Skip to content

Commit e452392

Browse files
committed
Introduce the IntoIterator iterator_concept
Iterators are always also IntoIterator, returning a reference to themselves. This allows code to receive an iterator or a container, and is most useful when receiving an iterator over non-reference values.
1 parent e322329 commit e452392

File tree

4 files changed

+42
-6
lines changed

4 files changed

+42
-6
lines changed

subdoc/lib/gen/html_writer.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,6 @@ class HtmlWriter {
361361
}
362362
}
363363

364-
// TODO: Add an Iterator<T> concept and use that to know what Item is here.
365364
void write_open(
366365
std::string_view type,
367366
sus::iter::Iterator<const std::string&> auto classes_iter,

subspace/iter/iterator_concept.h

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,46 @@
1414

1515
#pragma once
1616

17+
#include <type_traits>
18+
1719
#include "subspace/convert/subclass.h"
20+
#include "subspace/mem/forward.h"
1821

1922
namespace sus::iter {
2023

2124
template <class Iter, class Item>
2225
class IteratorImpl;
2326

24-
/// A concept for dealing with iterators.
27+
/// A concept for all implementations of iterators.
2528
///
2629
/// Types that satisfy this concept can be used in for loops and provide
2730
/// all the methods of an iterator type, which are found in
2831
/// `sus::iter::IteratorImpl`.
2932
template <class T, class Item>
3033
concept Iterator = requires {
3134
// Has a T::Item typename.
32-
requires(!std::is_void_v<typename T::Item>);
35+
requires(!std::is_void_v<typename std::decay_t<T>::Item>);
3336
// The T::Item matches the concept input.
34-
requires(std::same_as<typename T::Item, Item>);
37+
requires(std::same_as<typename std::decay_t<T>::Item, Item>);
3538
// Subclasses from IteratorImpl<T, T::Item>.
36-
requires ::sus::convert::SameOrSubclassOf<T*, IteratorImpl<T, Item>*>;
39+
requires ::sus::convert::SameOrSubclassOf<
40+
std::decay_t<T>*, IteratorImpl<std::decay_t<T>, Item>*>;
41+
};
42+
43+
/// Conversion into an `Iterator`.
44+
///
45+
/// A more general trait than `Iterator` which will accept anything that can be
46+
/// iterated, including an `Iterator` (since all `Iterator`s also satisfy
47+
/// `IntoIterator`). This can be particularly useful when receiving an iterator
48+
/// over a set of non-reference values, allowing the caller to pass a container
49+
/// directly in place of an iterator.
50+
///
51+
/// Note that an `IntoIterator` type is not directly iterable in for loops, and
52+
/// requires calling `into_iter()` on it to convert it into an `Iterator`
53+
/// which is iterable in for loops.
54+
template <class T, class Item>
55+
concept IntoIterator = requires(T&& t) {
56+
{ ::sus::forward<T>(t).into_iter() } -> Iterator<Item>;
3757
};
3858

3959
} // namespace sus::iter

subspace/iter/iterator_defn.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ class [[nodiscard]] IteratorImpl : public IteratorBase<Item> {
128128
}
129129

130130
public:
131+
/// An Iterator also satisfies IntoIterator, which simply returns itself.
132+
///
133+
/// sus::iter::IntoIterator trait implementation.
134+
Iter&& into_iter() && noexcept { return ::sus::move(*this); }
135+
131136
// Provided methods.
132137

133138
/// Tests whether all elements of the iterator match a predicate.

subspace/iter/iterator_unittest.cc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ static_assert(
4242
static_assert(
4343
sus::iter::Iterator<sus::iter::Map<int, int, 8, 8>, int>);
4444
static_assert(
45-
::sus::iter::Iterator<sus::iter::Once<int>, int>);
45+
sus::iter::Iterator<sus::iter::Once<int>, int>);
4646
static_assert(
4747
sus::iter::Iterator<sus::containers::ArrayIntoIter<int, 1>, int>);
4848
static_assert(
@@ -51,6 +51,18 @@ static_assert(
5151
sus::iter::Iterator<sus::containers::SliceIter<const int&>, const int&>);
5252
static_assert(
5353
sus::iter::Iterator<sus::containers::SliceIterMut<int&>, int&>);
54+
55+
static_assert(
56+
sus::iter::IntoIterator<sus::containers::Array<int, 3u>, int>);
57+
static_assert(
58+
sus::iter::IntoIterator<sus::containers::Slice<const int>, const int&>);
59+
static_assert(
60+
sus::iter::IntoIterator<sus::containers::Slice<int>, int&>);
61+
static_assert(
62+
sus::iter::IntoIterator<sus::containers::Vec<int>, int>);
63+
64+
static_assert(
65+
sus::iter::IntoIterator<sus::iter::Once<int>, int>);
5466
// clang-format on
5567

5668
template <class Item, size_t N>

0 commit comments

Comments
 (0)