Iros
 
Loading...
Searching...
No Matches
cartesian_product_view.h
Go to the documentation of this file.
1#pragma once
2
8#include "di/meta/util.h"
10
11namespace di::container {
12namespace detail {
13 template<typename First, typename... Rest>
17
18 template<typename Con>
21
22 template<typename First, typename... Rest>
26
27 template<typename First, typename... Rest>
29
30 template<typename... Cons>
32
33 template<typename First, typename... Cons>
37
38 template<CartesianProductCommonArg Con>
39 constexpr auto cartiesian_common_arg_end(Con&& con) {
40 if constexpr (concepts::CommonContainer<Con>) {
41 return container::end(con);
42 } else {
43 return container::begin(con) + container::size(con);
44 }
45 }
46}
47
51private:
52 template<bool is_const>
53 struct Iterator
54 : public IteratorBase<
55 Iterator<is_const>,
56 meta::Conditional<
57 detail::CartesianProductIsRandomAccess<meta::MaybeConst<is_const, First>,
58 meta::MaybeConst<is_const, Rest>...>,
59 RandomAccessIteratorTag,
60 meta::Conditional<detail::CartesianProductIsBidirectional<meta::MaybeConst<is_const, First>,
61 meta::MaybeConst<is_const, Rest>...>,
62 RandomAccessIteratorTag,
63 meta::Conditional<concepts::ForwardContainer<meta::MaybeConst<is_const, First>>,
64 ForwardIteratorTag, InputIteratorTag>>>,
65 Tuple<meta::ContainerValue<First>, meta::ContainerValue<Rest>...>, ssize_t> {
66 private:
67 friend class CartesianProductView;
68
70
73
74 constexpr explicit Iterator(Parent& parent, Storage storage)
75 : m_parent(util::addressof(parent)), m_iterators(util::move(storage)) {}
76
77 public:
78 Iterator() = default;
79
80 constexpr Iterator(Iterator<!is_const> other)
81 requires(is_const &&
84 : m_parent(other.m_parent), m_iterators(util::move(other)) {}
85
86 constexpr auto operator*() const {
87 return tuple_transform(
88 [](auto& iterator) -> decltype(*iterator) {
89 return *iterator;
90 },
91 m_iterators);
92 }
93
94 constexpr void advance_one() { this->next(); }
95
96 constexpr void back_one()
99 {
100 this->prev();
101 }
102
103 constexpr void advance_n(ssize_t n)
106 {
107 if (n == 0) {
108 return;
109 }
110
111 if (*this == m_parent->end()) {
112 DI_ASSERT(n < 0);
113 *this = m_parent->begin();
114 advance_n(m_parent->size() + n);
115 } else {
116 this->advance(n);
117 }
118 }
119
120 private:
121 constexpr friend auto operator==(Iterator const& a, Iterator const& b) -> bool {
122 return a.m_iterators == b.m_iterators;
123 }
124
125 constexpr friend auto operator<=>(Iterator const& a, Iterator const& b)
128 {
129 return a.m_iterators <=> b.m_iterators;
130 }
131
132 constexpr friend auto operator-(Iterator const& a, Iterator const& b) -> ssize_t
137 ...))
138 {
139 return a.distance_from(b.m_iterators);
140 }
141
142 constexpr friend auto operator==(Iterator const& a, DefaultSentinel) -> bool { return a.at_end(); }
143
144 constexpr auto at_end() const -> bool {
145 return function::unpack<meta::MakeIndexSequence<1 + sizeof...(Rest)>>([&]<size_t... indices>(
147 return ((util::get<indices>(m_iterators) == container::end(util::get<indices>(m_parent->m_bases))) ||
148 ...);
149 });
150 }
151
152 constexpr friend auto operator-(Iterator const& a, DefaultSentinel)
153 requires(
155 {
156 return a.distance_to_end();
157 }
158
159 constexpr auto distance_to_end() const {
160 auto end_tuple = function::unpack<meta::MakeIndexSequence<1 + sizeof...(Rest)>>(
161 [&]<size_t... indices>(meta::ListV<indices...>) {
162 return make_tuple(container::end(util::get<indices>(m_parent->m_bases))...);
163 });
164 return distance_to(end_tuple);
165 }
166
167 constexpr friend auto operator-(DefaultSentinel, Iterator const& b)
168 requires(
170 {
171 return -(b - default_sentinel);
172 }
173
174 constexpr friend auto tag_invoke(types::Tag<iterator_move>, Iterator const& self) {
175 return tuple_transform(iterator_move, self.m_iterators);
176 }
177
178 constexpr friend void tag_invoke(types::Tag<iterator_swap>, Iterator const& a, Iterator const& b)
181 {
182 return function::unpack<meta::MakeIndexSequence<1 + sizeof...(Rest)>>(
183 [&]<size_t... indices>(meta::ListV<indices...>) {
184 (void) (iterator_swap(util::get<indices>(a.m_iterators), util::get<indices>(b.m_iterators)), ...);
185 });
186 }
187
188 template<size_t N = sizeof...(Rest)>
189 constexpr void next() {
190 auto& it = util::get<N>(m_iterators);
191 ++it;
192 if constexpr (N > 0) {
193 if (it == container::end(util::get<N>(m_parent->m_bases))) {
194 it = container::begin(util::get<N>(m_parent->m_bases));
195 this->next<N - 1>();
196 }
197 }
198 }
199
200 template<size_t N = sizeof...(Rest)>
201 constexpr void prev() {
202 auto& it = util::get<N>(m_iterators);
203 if (it == container::begin(util::get<N>(m_parent->m_bases))) {
204 it = detail::cartiesian_common_arg_end(util::get<N>(m_parent->m_bases));
205 if constexpr (N > 0) {
206 this->prev<N - 1>();
207 }
208 }
209 --it;
210 }
211
212 template<size_t N = sizeof...(Rest)>
213 constexpr void advance(ssize_t n) {
214 auto& it = util::get<N>(m_iterators);
215 auto position = container::distance(container::begin(util::get<N>(m_parent->m_bases)), it);
216 auto new_position = position + n;
217
218 if constexpr (N == 0) {
219 it += (new_position - position);
220 } else {
221 auto size = container::distance(util::get<N>(m_parent->m_bases));
222 if (new_position < 0) {
223 new_position = size - (-new_position % size);
224 }
225 new_position %= size;
226 it += (new_position - position);
227
228 advance<N - 1>(n / size);
229 }
230 }
231
232 template<size_t N = sizeof...(Rest), typename Tuple>
233 constexpr auto distance_from(Tuple const& a) const -> ssize_t {
234 auto distance = container::distance(util::get<N>(a), util::get<N>(m_iterators));
235 if constexpr (N == 0) {
236 return distance;
237 } else {
238 auto scale = container::distance(util::get<N>(m_parent->m_bases));
239 return distance + scale * this->distance_from<N - 1>(a);
240 }
241 }
242
243 Parent* m_parent { nullptr };
244 Storage m_iterators;
245 };
246
247public:
249
250 constexpr explicit CartesianProductView(First first, Rest... bases)
251 : m_bases(util::move(first), util::move(bases)...) {}
252
253 constexpr auto begin()
255 {
256 return Iterator<false>(*this, tuple_transform(container::begin, m_bases));
257 }
258
259 constexpr auto begin() const -> Iterator<true>
260 requires(concepts::Container<First> && (concepts::Container<Rest> && ...))
261 {
262 return Iterator<true>(*this, tuple_transform(container::begin, m_bases));
263 }
264
265 constexpr auto end()
267 detail::CartesianProductIsCommon<First, Rest...>)
268 {
269 auto it = Iterator<false>(*this, tuple_transform(container::begin, m_bases));
270 bool is_empty = false;
271 bool is_first = true;
273 [&](auto&& base) {
274 if (!is_first && container::empty(base)) {
275 is_empty = true;
276 }
277 is_first = false;
278 },
279 m_bases);
280 if (!is_empty) {
282 }
283 return it;
284 }
285
286 constexpr auto end() const
287 requires(detail::CartesianProductIsCommon<First const, Rest const...>)
288 {
289 auto it = Iterator<true>(*this, tuple_transform(container::begin, m_bases));
290 bool is_empty = false;
291 bool is_first = true;
293 [&](auto&& base) {
294 if (!is_first && container::empty(base)) {
295 is_empty = true;
296 }
297 is_first = false;
298 },
299 m_bases);
300 if (!is_empty) {
302 }
303 return it;
304 }
305
306 constexpr auto end() const
307 requires(!detail::CartesianProductIsCommon<First const, Rest const...>)
308 {
309 return default_sentinel;
310 }
311
312 constexpr auto size()
313 requires(detail::CartesianProductIsSized<First, Rest...>)
314 {
315 size_t size = 1;
317 [&](auto& view) {
319 },
320 m_bases);
321 return size;
322 }
323
324 constexpr auto size() const
325 requires(detail::CartesianProductIsSized<First const, Rest const...>)
326 {
327 size_t size = 1;
329 [&](auto& view) {
331 },
332 m_bases);
333 return size;
334 }
335
336private:
337 Tuple<First, Rest...> m_bases;
338};
339
340template<typename... Cons>
342}
#define DI_ASSERT(...)
Definition assert_bool.h:7
Definition cartesian_product_view.h:50
constexpr auto end() const
Definition cartesian_product_view.h:286
constexpr auto end()
Definition cartesian_product_view.h:265
constexpr CartesianProductView(First first, Rest... bases)
Definition cartesian_product_view.h:250
constexpr auto size() const
Definition cartesian_product_view.h:324
constexpr auto end() const
Definition cartesian_product_view.h:306
constexpr auto begin()
Definition cartesian_product_view.h:253
constexpr auto begin() const -> Iterator< true > requires(concepts::Container< First > &&(concepts::Container< Rest > &&...))
Definition cartesian_product_view.h:259
constexpr auto size()
Definition cartesian_product_view.h:312
Definition view_interface.h:26
Definition tuple_forward_declaration.h:5
Definition bidirectional_container.h:8
Definition common_container.h:10
Definition operations.h:99
Definition forward_container.h:8
Definition indirectly_swappable.h:7
Definition input_container.h:8
Definition random_access_container.h:8
Definition simple_view.h:11
Definition sized_container.h:8
Definition sized_sentinel_for.h:9
Definition compare.h:91
Definition view.h:10
Definition cartesian_product_view.h:19
Definition cartesian_product_view.h:23
Definition cartesian_product_view.h:28
Definition cartesian_product_view.h:14
Definition cartesian_product_view.h:31
Definition cartesian_product_view.h:34
Definition any_storable.h:9
Definition sequence.h:13
constexpr auto cartiesian_common_arg_end(Con &&con)
Definition cartesian_product_view.h:39
Definition adjacent.h:8
Definition sequence.h:12
constexpr auto prev
Definition prev.h:28
constexpr auto next
Definition next.h:35
constexpr auto empty
Definition empty.h:45
constexpr auto operator<=>(MoveIterator< Iter > const &a, MoveIterator< U > const &b)
Definition move_iterator.h:90
constexpr auto operator-(MoveIterator< Iter > const &a, MoveIterator< U > const &b) -> decltype(a.base() - b.base())
Definition move_iterator.h:95
constexpr auto iterator_move
Definition iterator_move.h:56
constexpr auto move
Definition move.h:38
constexpr auto operator==(MoveIterator< Iter > const &a, MoveIterator< U > const &b) -> bool
Definition move_iterator.h:85
constexpr auto distance
Definition distance.h:44
constexpr auto size
Definition size.h:54
CartesianProductView(Cons &&...) -> CartesianProductView< meta::AsView< Cons >... >
constexpr auto iterator_swap
Definition iterator_swap.h:49
constexpr auto default_sentinel
Definition default_sentinel.h:6
constexpr auto end
Definition end.h:47
constexpr auto advance
Definition advance.h:62
auto tag_invoke(types::Tag< util::deduce_create >, InPlaceTemplate< NodeHashMap >, Con &&) -> NodeHashMap< meta::TupleElement< T, 0 >, meta::TupleElement< T, 1 > >
constexpr auto begin
Definition begin.h:44
constexpr auto unpack
Definition unpack.h:24
MakeIntegerSequence< usize, count > MakeIndexSequence
Definition algorithm.h:285
Conditional< is_const, T const, T > MaybeConst
Definition util.h:9
decltype(container::begin(util::declval< T & >())) ContainerIterator
Definition container_iterator.h:8
ptrdiff_t ssize_t
Definition ssize_t.h:6
di::meta::Decay< decltype(T)> Tag
Definition tag_invoke.h:28
Definition vocab.h:96
constexpr auto get(T &&value) -> decltype(auto)
Definition get.h:8
constexpr auto tuple_transform(F &&function, Tup &&tuple)
Definition tuple_transform.h:22
constexpr auto make_tuple(Args &&... args)
Definition make_tuple.h:9
constexpr void tuple_for_each(F &&function, Tup &&tuple)
Definition tuple_for_each.h:22
Definition default_sentinel.h:4
Definition iterator_base.h:14
Definition core.h:8