3030
3131#pragma once
3232
33+ #include " core/templates/tuple.h"
34+ #include " core/typedefs.h"
35+
36+ // Like std::begin, but without an expensive include.
37+ template <class T , size_t SIZE>
38+ T *std_begin (T (&array)[SIZE]) {
39+ return array;
40+ }
41+
42+ template <class T , size_t SIZE>
43+ T *std_end (T (&array)[SIZE]) {
44+ return array + SIZE;
45+ }
46+
47+ template <class T , size_t SIZE>
48+ const T *std_begin (const T (&array)[SIZE]) {
49+ return array;
50+ }
51+
52+ template <class T , size_t SIZE>
53+ const T *std_end (const T (&array)[SIZE]) {
54+ return array + SIZE;
55+ }
56+
57+ template <class T >
58+ auto std_begin (T &t) -> decltype(t.begin()) {
59+ return t.begin ();
60+ }
61+
62+ template <class T >
63+ auto std_end (T &t) -> decltype(t.end()) {
64+ return t.end ();
65+ }
66+
67+ template <class T >
68+ auto std_begin (const T &t) -> decltype(t.begin()) {
69+ return t.begin ();
70+ }
71+
72+ template <class T >
73+ auto std_end (const T &t) -> decltype(t.end()) {
74+ return t.end ();
75+ }
76+
77+ // / Can be returned from a function and directly iterated.
78+ // / Example usage:
79+ // / for (int i : object.get_iterable()) { ... }
3380template <typename I>
3481class Iterable {
3582 I _begin;
@@ -44,3 +91,92 @@ class Iterable {
4491 Iterable (const I &begin, const I &end) :
4592 _begin (begin), _end(end) {}
4693};
94+
95+ template <typename T>
96+ struct IteratorType {
97+ using type = decltype (std_begin(std::declval<T>()));
98+ };
99+
100+ template <typename T>
101+ using IteratorTypeT = typename IteratorType<T>::type;
102+
103+ template <typename T, typename ... Rest>
104+ bool _tuple_any_elements_equal (const Tuple<T, Rest...> &p_lhs, const Tuple<T, Rest...> &p_rhs) {
105+ if constexpr (sizeof ...(Rest) == 0 ) {
106+ return p_lhs.value == p_rhs.value ;
107+ } else {
108+ return p_lhs.value == p_rhs.value || _tuple_any_elements_equal (static_cast <const Tuple<Rest...> &>(p_lhs), static_cast <const Tuple<Rest...> &>(p_rhs));
109+ }
110+ }
111+
112+ template <typename T, typename ... Rest>
113+ void _tuple_increment (Tuple<T, Rest...> &p_tuple) {
114+ p_tuple.value ++;
115+ if constexpr (sizeof ...(Rest) > 0 ) {
116+ _tuple_increment<Rest...>(p_tuple);
117+ }
118+ }
119+
120+ template <typename ... T, typename ... T1, size_t ... Is>
121+ Tuple<T...> _tuple_dereference_impl (Tuple<T1...> &p_tuple, IndexSequence<Is...>) {
122+ return Tuple<T...>{ *p_tuple.template get <Is>()... };
123+ }
124+
125+ template <typename TUPLE, typename ... T>
126+ struct ZipShortestIterator {
127+ TUPLE iterators;
128+
129+ Tuple<T...> operator *() {
130+ return _tuple_dereference_impl<T...>(iterators, BuildIndexSequence<sizeof ...(T)>{});
131+ }
132+ ZipShortestIterator &operator ++() {
133+ _tuple_increment (iterators);
134+ return *this ;
135+ }
136+ bool operator !=(const ZipShortestIterator &iter) const {
137+ return !_tuple_any_elements_equal (iterators, iter.iterators );
138+ }
139+ };
140+
141+ // / Can be used to iterate multiple iterables together.
142+ // / The iteration stops with the shortest iterator.
143+ // / Example usage:
144+ // / for (auto [ai, bi, ci] : zip_shortest<A, B, C>(a, b, c)) { ... }
145+ template <typename ... T, typename ... ITER>
146+ Iterable<ZipShortestIterator<Tuple<IteratorTypeT<ITER>...>, T...>> zip_shortest (ITER &&...t) {
147+ static_assert (sizeof ...(T) == sizeof ...(ITER));
148+ using TUPLE = Tuple<IteratorTypeT<ITER>...>;
149+ return Iterable<ZipShortestIterator<TUPLE, T...>>{
150+ ZipShortestIterator<TUPLE, T...>{ TUPLE{ std_begin (t)... } },
151+ ZipShortestIterator<TUPLE, T...>{ TUPLE{ std_end (t)... } }
152+ };
153+ }
154+
155+ template <typename IDX, typename VALUE, typename T>
156+ struct EnumerateIterator {
157+ size_t index;
158+ T iterator;
159+
160+ Tuple<IDX, VALUE> operator *() {
161+ return { index, *iterator };
162+ }
163+ EnumerateIterator &operator ++() {
164+ index++;
165+ iterator++;
166+ return *this ;
167+ }
168+ bool operator !=(const EnumerateIterator &iter) {
169+ return iterator != iter.iterator ;
170+ }
171+ };
172+
173+ // / Can be used to count an index with an iterable.
174+ // / Example usage:
175+ // / for (auto [index, ai] : enumerate<size_t, A>(a)) { ... }
176+ template <typename IDX, typename VALUE, typename ITER>
177+ Iterable<EnumerateIterator<IDX, VALUE, IteratorTypeT<ITER>>> enumerate(ITER &&t) {
178+ return Iterable{
179+ EnumerateIterator<IDX, VALUE, IteratorTypeT<ITER>>{ 0 , std_begin (t) },
180+ EnumerateIterator<IDX, VALUE, IteratorTypeT<ITER>>{ 0 , std_end (t) }
181+ };
182+ }
0 commit comments