Skip to content

Commit ac6fa74

Browse files
committed
Separate overridable from non-overridable methods in IteratorImpl
1 parent f0d68e5 commit ac6fa74

File tree

6 files changed

+62
-46
lines changed

6 files changed

+62
-46
lines changed

subdoc/lib/database.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ struct Database {
647647

648648
// Namespace path goes from the outside in to the global, we want the
649649
// inverse, and then to skip the global namespace.
650-
auto it = iter_namespace_path(decl).collect_vec().into_iter().reverse();
650+
auto it = iter_namespace_path(decl).collect_vec().into_iter().rev();
651651
it.next(); // TODO: Use Iterator::skip().
652652
for (const Namespace& n : it) {
653653
switch (n) {
@@ -686,7 +686,7 @@ struct Database {
686686
for (std::string_view name : iter_record_path(containing_record_decl)
687687
.collect_vec()
688688
.into_iter()
689-
.reverse()) {
689+
.rev()) {
690690
if (first) {
691691
auto r_it = ns_cursor->records.find(RecordId(name));
692692
if (r_it == ns_cursor->records.end()) {

subdoc/lib/gen/files.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ inline std::filesystem::path construct_html_file_path(
4545
std::filesystem::path p = sus::move(root);
4646

4747
std::ostringstream fname;
48-
for (const Namespace& n : namespace_path.iter().reverse()) {
48+
for (const Namespace& n : namespace_path.iter().rev()) {
4949
switch (n) {
5050
case Namespace::Tag::Global: break;
5151
case Namespace::Tag::Anonymous:
@@ -58,7 +58,7 @@ inline std::filesystem::path construct_html_file_path(
5858
break;
5959
}
6060
}
61-
for (std::string_view n : record_path.iter().reverse()) {
61+
for (std::string_view n : record_path.iter().rev()) {
6262
fname << n << "-";
6363
}
6464
fname << name;

subdoc/lib/gen/generate_record.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void generate_record_overview(HtmlWriter::OpenDiv& record_div,
5050
{
5151
// TODO: This code gets duplicated a lot, share it.
5252

53-
for (const Namespace &n : element.namespace_path.iter().reverse()) {
53+
for (const Namespace &n : element.namespace_path.iter().rev()) {
5454
switch (n) {
5555
case Namespace::Tag::Global: break;
5656
case Namespace::Tag::Anonymous: {
@@ -68,7 +68,7 @@ void generate_record_overview(HtmlWriter::OpenDiv& record_div,
6868
break;
6969
}
7070
}
71-
for (std::string_view record_name: element.record_path.iter().reverse()) {
71+
for (std::string_view record_name: element.record_path.iter().rev()) {
7272
{
7373
auto record_anchor = full_type_span.open_a();
7474
record_anchor.write_text(record_name);
@@ -228,7 +228,7 @@ void generate_record(const RecordElement& element,
228228

229229
{
230230
std::ostringstream title;
231-
for (const Namespace& n: element.namespace_path.iter().reverse()) {
231+
for (const Namespace& n: element.namespace_path.iter().rev()) {
232232
switch (n) {
233233
case Namespace::Tag::Global: break;
234234
case Namespace::Tag::Anonymous:
@@ -241,7 +241,7 @@ void generate_record(const RecordElement& element,
241241
break;
242242
}
243243
}
244-
for (std::string_view record_name: element.record_path.iter().reverse()) {
244+
for (std::string_view record_name: element.record_path.iter().rev()) {
245245
title << record_name;
246246
title << "::";
247247
}

subdoc/lib/path.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ inline std::string namespace_with_path_to_string(
4343
std::ostringstream s;
4444
bool add_colons = false;
4545

46-
for (const Namespace& n : path.iter().reverse()) {
46+
for (const Namespace& n : path.iter().rev()) {
4747
if (add_colons) s << "::";
4848
switch (n) {
4949
case Namespace::Tag::Global: break;

subspace/iter/iterator_defn.h

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,17 @@ class IteratorImpl {
6363
"methods must know the complete type.");
6464
}
6565

66+
inline const Iter& as_subclass() const {
67+
return static_cast<const Iter&>(*this);
68+
}
69+
inline Iter& as_subclass_mut() { return static_cast<Iter&>(*this); }
70+
6671
public:
6772
using Item = ItemT;
6873

6974
/// Adaptor for use in ranged for loops.
7075
auto begin() & noexcept {
71-
return __private::IteratorLoop<Iter&>(static_cast<Iter&>(*this));
76+
return __private::IteratorLoop<Iter&>(as_subclass_mut());
7277
}
7378
/// Adaptor for use in ranged for loops.
7479
auto end() & noexcept { return __private::IteratorEnd(); }
@@ -78,7 +83,7 @@ class IteratorImpl {
7883
/// sus::iter::IntoIterator trait implementation.
7984
Iter&& into_iter() && noexcept { return static_cast<Iter&&>(*this); }
8085

81-
// Provided methods.
86+
// Provided overridable methods.
8287

8388
/// Returns the bounds on the remaining length of the iterator.
8489
///
@@ -104,9 +109,7 @@ class IteratorImpl {
104109
///
105110
/// The default implementation returns `lower = 0` and `upper = None` which is
106111
/// correct for any iterator.
107-
virtual SizeHint size_hint() const noexcept {
108-
return SizeHint(0_usize, ::sus::Option<::sus::num::usize>::none());
109-
}
112+
virtual SizeHint size_hint() const noexcept;
110113

111114
/// Tests whether all elements of the iterator match a predicate.
112115
///
@@ -116,7 +119,7 @@ class IteratorImpl {
116119
/// from the predicate.
117120
///
118121
/// Returns `true` if the iterator is empty.
119-
bool all(::sus::fn::FnMut<bool(Item)> f) noexcept;
122+
virtual bool all(::sus::fn::FnMut<bool(Item)> f) noexcept;
120123

121124
/// Tests whether any elements of the iterator match a predicate.
122125
///
@@ -126,7 +129,21 @@ class IteratorImpl {
126129
/// the predicate.
127130
///
128131
/// Returns `false` if the iterator is empty.
129-
bool any(::sus::fn::FnMut<bool(Item)> f) noexcept;
132+
virtual bool any(::sus::fn::FnMut<bool(Item)> f) noexcept;
133+
134+
/// Consumes the iterator, and returns the number of elements that were in
135+
/// it.
136+
///
137+
/// The function walks the iterator until it sees an Option holding #None.
138+
///
139+
/// # Safety
140+
///
141+
/// If the `usize` type does not have trapping arithmetic enabled, and the
142+
/// iterator has more than `usize::MAX` elements in it, the value will wrap
143+
/// and be incorrect. Otherwise, `usize` will catch overflow and panic.
144+
virtual ::sus::num::usize count() noexcept;
145+
146+
// Provided final methods.
130147

131148
/// Wraps the iterator in a new iterator that is trivially relocatable.
132149
///
@@ -145,18 +162,6 @@ class IteratorImpl {
145162
auto box() && noexcept
146163
requires(!::sus::mem::relocate_by_memcpy<Iter>);
147164

148-
/// Consumes the iterator, and returns the number of elements that were in
149-
/// it.
150-
///
151-
/// The function walks the iterator until it sees an Option holding #None.
152-
///
153-
/// # Safety
154-
///
155-
/// If the `usize` type does not have trapping arithmetic enabled, and the
156-
/// iterator has more than `usize::MAX` elements in it, the value will wrap
157-
/// and be incorrect. Otherwise, `usize` will catch overflow and panic.
158-
::sus::num::usize count() noexcept;
159-
160165
/// Creates an iterator which uses a closure to map each element to another
161166
/// type.
162167
///
@@ -176,8 +181,16 @@ class IteratorImpl {
176181
pred) && noexcept
177182
requires(::sus::mem::relocate_by_memcpy<Iter>);
178183

179-
auto reverse() && noexcept
180-
requires(::sus::mem::relocate_by_memcpy<Iter>);
184+
/// Reverses an iterator's direction.
185+
///
186+
/// Usually, iterators iterate from front to back. After using `rev()`, an
187+
/// iterator will instead iterate from back to front.
188+
///
189+
/// This is only possible if the iterator has an end, so `rev()` only works on
190+
/// `DoubleEndedIterator`s.
191+
auto rev() && noexcept
192+
requires(::sus::mem::relocate_by_memcpy<Iter> &&
193+
::sus::iter::DoubleEndedIterator<Iter, Item>);
181194

182195
/// Transforms an iterator into a collection.
183196
///
@@ -219,11 +232,15 @@ class IteratorImpl {
219232
// TODO: cloned().
220233
};
221234

235+
template <class Iter, class Item>
236+
SizeHint IteratorImpl<Iter, Item>::size_hint() const noexcept {
237+
return SizeHint(0_usize, ::sus::Option<::sus::num::usize>::none());
238+
}
239+
222240
template <class Iter, class Item>
223241
bool IteratorImpl<Iter, Item>::all(::sus::fn::FnMut<bool(Item)> f) noexcept {
224-
// TODO: If constexpr(I::all() exists) then call that instead.
225242
while (true) {
226-
Option<Item> item = static_cast<Iter&>(*this).next();
243+
Option<Item> item = as_subclass_mut().next();
227244
if (item.is_none()) return true;
228245
// SAFETY: `item` was checked to hold Some already.
229246
if (!f(item.take().unwrap_unchecked(::sus::marker::unsafe_fn)))
@@ -233,23 +250,14 @@ bool IteratorImpl<Iter, Item>::all(::sus::fn::FnMut<bool(Item)> f) noexcept {
233250

234251
template <class Iter, class Item>
235252
bool IteratorImpl<Iter, Item>::any(::sus::fn::FnMut<bool(Item)> f) noexcept {
236-
// TODO: If constexpr(I::any() exists) then call that instead.
237253
while (true) {
238-
Option<Item> item = static_cast<Iter&>(*this).next();
254+
Option<Item> item = as_subclass_mut().next();
239255
if (item.is_none()) return false;
240256
// SAFETY: `item` was checked to hold Some already.
241257
if (f(item.take().unwrap_unchecked(::sus::marker::unsafe_fn))) return true;
242258
}
243259
}
244260

245-
template <class Iter, class Item>
246-
::sus::num::usize IteratorImpl<Iter, Item>::count() noexcept {
247-
// TODO: If constexpr(I::count() exists) then call that instead.
248-
auto c = 0_usize;
249-
while (static_cast<Iter&>(*this).next().is_some()) c += 1_usize;
250-
return c;
251-
}
252-
253261
template <class Iter, class Item>
254262
auto IteratorImpl<Iter, Item>::box() && noexcept
255263
requires(!::sus::mem::relocate_by_memcpy<Iter>)
@@ -260,6 +268,13 @@ auto IteratorImpl<Iter, Item>::box() && noexcept
260268
return BoxedIterator::with(static_cast<Iter&&>(*this));
261269
}
262270

271+
template <class Iter, class Item>
272+
::sus::num::usize IteratorImpl<Iter, Item>::count() noexcept {
273+
auto c = 0_usize;
274+
while (as_subclass_mut().next().is_some()) c += 1_usize;
275+
return c;
276+
}
277+
263278
template <class Iter, class Item>
264279
template <class MapFn, int&..., class R, class MapFnMut>
265280
requires(::sus::construct::Into<MapFn, MapFnMut> && !std::is_void_v<R>)
@@ -285,8 +300,9 @@ auto IteratorImpl<Iter, Item>::filter(
285300
}
286301

287302
template <class Iter, class Item>
288-
auto IteratorImpl<Iter, Item>::reverse() && noexcept
289-
requires(::sus::mem::relocate_by_memcpy<Iter>)
303+
auto IteratorImpl<Iter, Item>::rev() && noexcept
304+
requires(::sus::mem::relocate_by_memcpy<Iter> &&
305+
::sus::iter::DoubleEndedIterator<Iter, Item>)
290306
{
291307
using Sized = SizedIteratorType<Iter>::type;
292308
using Reverse = Reverse<Sized>;

subspace/iter/iterator_unittest.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,10 +374,10 @@ TEST(Iterator, CollectVec) {
374374
EXPECT_EQ(collected[4u], 5);
375375
}
376376

377-
TEST(Iterator, Reverse) {
377+
TEST(Iterator, Rev) {
378378
i32 nums[5] = {1, 2, 3, 4, 5};
379379

380-
auto it = ArrayIterator<i32, 5>::with_array(nums).reverse();
380+
auto it = ArrayIterator<i32, 5>::with_array(nums).rev();
381381
static_assert(sus::iter::Iterator<decltype(it), i32>);
382382
static_assert(sus::iter::DoubleEndedIterator<decltype(it), i32>);
383383
EXPECT_EQ(it.next(), sus::some(5).construct());

0 commit comments

Comments
 (0)