Iros
 
Loading...
Searching...
No Matches
concat_view.h
Go to the documentation of this file.
1#pragma once
2
11#include "di/function/minus.h"
12#include "di/meta/constexpr.h"
13#include "di/meta/util.h"
16
17// Implementation of views::concat as described in p2542r2:
18// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2542r2.html.
19namespace di::container {
20namespace detail {
21 template<typename... Cons>
23
24 template<typename... Cons>
26
27 template<typename... Cons>
29
30 template<typename Ref, typename RRef, typename It>
31 concept ConcatIndirectlyReadableImpl = requires(It const it) {
32 static_cast<Ref>(*it);
33 static_cast<RRef>(container::iterator_move(it));
34 };
35
36 template<typename... Cons>
40 concepts::CommonReferenceWith<ConcatRValue<Cons...>&&, ConcatValue<Cons...> const&> &&
42 ...);
43
44 template<typename... Cons>
45 concept Concatable = requires {
46 typename ConcatReference<Cons...>;
47 typename ConcatValue<Cons...>;
48 typename ConcatRValue<Cons...>;
49 } && ConcatIndirectlyReadable<Cons...>;
50
51 template<typename... Cons>
53
59
60 template<typename... Cons>
63}
64
65template<concepts::InputContainer... Views>
66requires(sizeof...(Views) > 0 && (concepts::View<Views> && ...) && detail::Concatable<Views...>)
67class ConcatView : public ViewInterface<ConcatView<Views...>> {
68private:
69 template<bool is_const>
70 class Iterator
71 : public IteratorBase<
72 Iterator<is_const>,
73 meta::Conditional<
74 detail::ConcatRandomAccess<meta::MaybeConst<is_const, Views>...>, RandomAccessIteratorTag,
75 meta::Conditional<
76 detail::ConcatBidirectional<meta::MaybeConst<is_const, Views>...>, BidirectionalIteratorTag,
77 meta::Conditional<(concepts::ForwardContainer<meta::MaybeConst<is_const, Views>> && ...),
78 ForwardIteratorTag, InputIteratorTag>>>,
79 detail::ConcatValue<meta::MaybeConst<is_const, Views>...>,
80 meta::CommonType<meta::ContainerSSizeType<meta::MaybeConst<is_const, Views>>...>> {
81 private:
86
87 template<bool>
88 friend class Iterator;
89 friend class ConcatView;
90
91 template<size_t N>
92 constexpr void satisfy() {
93 if constexpr (N != sizeof...(Views) - 1) {
94 if (util::get<N>(m_base) == container::end(util::get<N>(m_parent->m_views))) {
95 m_base.template emplace<N + 1>(container::begin(util::get<N + 1>(m_parent->m_views)));
96 satisfy<N + 1>();
97 }
98 }
99 }
100
101 template<size_t N>
102 constexpr void prev() {
103 if constexpr (N == 0) {
104 --util::get<0>(m_base);
105 } else {
106 if (util::get<N>(m_base) == container::begin(util::get<N>(m_parent->m_views))) {
107 using PrevView = meta::MaybeConst<is_const, meta::At<meta::List<Views...>, N - 1>>;
109 m_base.template emplace<N - 1>(container::end(util::get<N - 1>(m_parent->m_views)));
110 } else {
111 m_base.template emplace<N - 1>(
113 container::size(util::get<N - 1>(m_parent->m_views))));
114 }
115 prev<N - 1>();
116 } else {
117 --util::get<N>(m_base);
118 }
119 }
120 }
121
122 template<size_t N>
123 constexpr void advance_fwd(SSizeType offset, SSizeType steps) {
124 if constexpr (N == sizeof...(Views) - 1) {
125 util::get<N>(m_base) += steps;
126 } else {
127 auto n_size = container::size(util::get<N>(m_parent->m_views));
128 if (offset + steps < static_cast<SSizeType>(n_size)) {
129 util::get<N>(m_base) += steps;
130 } else {
131 m_base.template emplace<N + 1>(container::begin(util::get<N + 1>(m_parent->m_views)));
132 advance_fwd<N + 1>(0, offset + steps - n_size);
133 }
134 }
135 }
136
137 template<size_t N>
138 constexpr void advance_bwd(SSizeType offset, SSizeType steps) {
139 if constexpr (N == 0) {
140 util::get<N>(m_base) -= steps;
141 } else {
142 if (offset >= steps) {
143 util::get<N>(m_base) -= steps;
144 } else {
145 m_base.template emplace<N - 1>(container::begin(util::get<N - 1>(m_parent->m_views)) +
146 container::size(util::get<N - 1>(m_parent->m_views)));
147 advance_bwd<N - 1>(static_cast<SSizeType>(container::size(util::get<N - 1>(m_parent->m_views))),
148 steps - offset);
149 }
150 }
151 }
152
153 template<typename... Args>
154 requires(concepts::ConstructibleFrom<BaseIter, Args...>)
155 constexpr explicit Iterator(meta::MaybeConst<is_const, ConcatView>* parent, Args&&... args)
156 : m_parent(parent), m_base(util::forward<Args>(args)...) {}
157
158 public:
159 constexpr Iterator()
161 = default;
162
163 constexpr Iterator(Iterator<!is_const> other)
164 requires(is_const &&
166 : m_parent(other.m_parent), m_base(util::move(other.m_base)) {}
167
168 constexpr auto operator*() const -> decltype(auto) {
169 return visit(
170 [](auto&& it) -> Reference {
171 return *it;
172 },
173 m_base);
174 }
175
176 constexpr void advance_one() {
177 function::index_dispatch<void, sizeof...(Views)>(m_base.index(), [&]<size_t i>(Constexpr<i>) {
178 ++util::get<i>(m_base);
179 this->template satisfy<i>();
180 });
181 }
182
183 constexpr void back_one()
185 {
186 function::index_dispatch<void, sizeof...(Views)>(m_base.index(), [&]<size_t i>(Constexpr<i>) {
187 this->template prev<i>();
188 });
189 }
190
191 constexpr void advance_n(SSizeType n)
193 {
194 function::index_dispatch<void, sizeof...(Views)>(m_base.index(), [&]<size_t i>(Constexpr<i>) {
195 if (n > 0) {
196 this->template advance_fwd<i>(
197 util::get<i>(m_base) - container::begin(util::get<i>(m_parent->m_views)), n);
198 } else if (n < 0) {
199 this->template advance_bwd<i>(
200 util::get<i>(m_base) - container::begin(util::get<i>(m_parent->m_views)), -n);
201 }
202 });
203 }
204
205 private:
206 constexpr friend auto operator==(Iterator const& a, Iterator const& b) -> bool
208 {
209 return a.m_base == b.m_base;
210 }
211
212 constexpr auto at_end() const -> bool {
213 constexpr auto last_index = sizeof...(Views) - 1;
214 return m_base.index() == last_index &&
215 util::get<last_index>(m_base) == container::end(util::get<last_index>(m_parent->m_views));
216 }
217
218 constexpr friend auto operator==(Iterator const& a, DefaultSentinel) -> bool { return a.at_end(); }
219
220 constexpr friend auto operator<=>(Iterator const& a, Iterator const& b)
222 {
223 return a.m_base <=> b.m_base;
224 }
225
226 constexpr auto distance_from(Iterator const& b) const -> SSizeType {
227 auto ai = this->m_base.index();
228 auto bi = b.m_base.index();
229
230 if (ai > bi) {
231 auto sizes = apply(
232 [](auto const&... views) {
233 return Array { static_cast<SSizeType>(container::size(views))... };
234 },
235 m_parent->m_views);
236
237 auto b_to_a = container::sum(sizes | view::drop(bi + 1) | view::take(ai - bi - 1));
238 auto b_to_its_end =
239 function::index_dispatch<SSizeType, sizeof...(Views)>(bi, [&]<size_t index>(Constexpr<index>) {
240 return sizes[index] -
241 (util::get<index>(b.m_base) - container::begin(util::get<index>(m_parent->m_views)));
242 });
243 auto a_to_its_start =
244 function::index_dispatch<SSizeType, sizeof...(Views)>(ai, [&]<size_t index>(Constexpr<index>) {
245 return util::get<index>(this->m_base) - container::begin(util::get<index>(m_parent->m_views));
246 });
247
248 return b_to_its_end + b_to_a + a_to_its_start;
249 }
250 if (ai < bi) {
251 return b.distance_from(*this);
252 }
253 return function::index_dispatch<SSizeType, sizeof...(Views)>(ai, [&]<size_t index>(Constexpr<index>) {
254 return util::get<index>(this->m_base) - util::get<index>(b.m_base);
255 });
256 }
257
258 constexpr auto distance_from_end() const -> SSizeType {
259 auto sizes = apply(
260 [](auto const&... views) {
261 return Array { static_cast<SSizeType>(container::size(views))... };
262 },
263 m_parent->m_views);
264
265 auto index = m_base.index();
266 auto rest_to_end = container::sum(sizes | view::drop(index + 1));
267 auto current_to_its_end =
268 function::index_dispatch<SSizeType, sizeof...(Views)>(index, [&]<size_t index>(Constexpr<index>) {
269 return sizes[index] -
270 (util::get<index>(m_base) - container::begin(util::get<index>(m_parent->m_views)));
271 });
272
273 return -(rest_to_end + current_to_its_end);
274 }
275
276 constexpr friend auto operator-(Iterator const& a, Iterator const& b) -> SSizeType
278 {
279 return a.distance_from(b);
280 }
281
282 constexpr friend auto operator-(Iterator const& a, DefaultSentinel) -> SSizeType
284 {
285 return a.distance_from_end();
286 }
287
288 constexpr friend auto operator-(DefaultSentinel, Iterator const& a) -> SSizeType
290 {
291 return -a.distance_from_end();
292 }
293
294 constexpr friend auto tag_invoke(Iterator const& a) -> decltype(auto) {
295 return visit<RValue>(iterator_move, a.m_base);
296 }
297
298 template<typename = void>
299 constexpr friend void tag_invoke(Iterator const& a, Iterator const& b)
300 requires(requires { visit(iterator_swap, a.m_base, b.m_base); })
301 {
302 visit(iterator_swap, a.m_base, b.m_base);
303 }
304
305 meta::MaybeConst<is_const, ConcatView>* m_parent { nullptr };
306 BaseIter m_base;
307 };
308
309public:
310 ConcatView() = default;
311
314 = delete;
315
316 constexpr explicit ConcatView(Views... views) : m_views(util::move(views)...) {}
317
318 constexpr auto begin()
319 requires(!concepts::SimpleView<Views> || ...)
320 {
321 auto it = Iterator<false>(this, c_<0ZU>, container::begin(util::get<0>(m_views)));
322 it.template satisfy<0>();
323 return it;
324 }
325
326 constexpr auto begin() const
327 requires((concepts::Container<Views const> && detail::Concatable<Views const>) && ...)
328 {
329 auto it = Iterator<true>(this, c_<0ZU>, container::begin(util::get<0>(m_views)));
330 it.template satisfy<0>();
331 return it;
332 }
333
334 constexpr auto end()
335 requires(!concepts::SimpleView<Views> || ...)
336 {
339 constexpr auto N = sizeof...(Views);
340 return Iterator<false>(this, c_<N - 1>, container::end(util::get<N - 1>(m_views)));
341 } else {
342 return default_sentinel;
343 }
344 }
345
346 constexpr auto end() const
347 requires((concepts::Container<Views const> && detail::Concatable<Views const>) && ...)
348 {
351 constexpr auto N = sizeof...(Views);
352 return Iterator<true>(this, c_<N - 1>, container::end(util::get<N - 1>(m_views)));
353 } else {
354 return default_sentinel;
355 }
356 }
357
358 constexpr auto size()
359 requires(concepts::SizedContainer<Views> && ...)
360 {
361 return apply(
362 [](auto... sizes) {
363 using CT = meta::MakeUnsigned<meta::CommonType<decltype(sizes)...>>;
364 return (CT { 0 } + ... + CT { sizes });
365 },
367 }
368
369 constexpr auto size() const
370 requires(concepts::SizedContainer<Views const> && ...)
371 {
372 return apply(
373 [](auto... sizes) {
374 using CT = meta::MakeUnsigned<meta::CommonType<decltype(sizes)...>>;
375 return (CT { 0 } + ... + CT { sizes });
376 },
378 }
379
380private:
381 [[no_unique_address]] Tuple<Views...> m_views;
382};
383
384template<typename... Cons>
386}
Definition concat_view.h:67
constexpr auto size() const
Definition concat_view.h:369
constexpr ConcatView(Views... views)
Definition concat_view.h:316
constexpr auto size()
Definition concat_view.h:358
constexpr auto end()
Definition concat_view.h:334
constexpr auto end() const
Definition concat_view.h:346
constexpr auto begin() const
Definition concat_view.h:326
constexpr auto begin()
Definition concat_view.h:318
Definition view_interface.h:26
Definition tuple_forward_declaration.h:5
Definition variant_forward_declaration.h:6
constexpr auto index() const -> size_t
Definition variant.h:173
Definition bidirectional_container.h:8
Definition common_container.h:10
Definition common.h:203
Definition operations.h:11
Definition operations.h:99
Definition operations.h:24
Definition operations.h:27
Definition compare.h:82
Definition input_container.h:8
Definition random_access_container.h:8
Definition operations.h:117
Definition simple_view.h:11
Definition sized_container.h:8
Definition compare.h:91
Definition view.h:10
Definition concat_view.h:45
Definition any_storable.h:9
Definition sequence.h:13
meta::CommonReference< meta::ContainerRValue< Cons >... > ConcatRValue
Definition concat_view.h:28
meta::CommonReference< meta::ContainerReference< Cons >... > ConcatReference
Definition concat_view.h:22
meta::CommonType< meta::ContainerValue< Cons >... > ConcatValue
Definition concat_view.h:25
concept Cons
Definition zip_transform.h:12
constexpr auto drop
Definition drop.h:36
constexpr auto take
Definition take.h:35
Definition sequence.h:12
constexpr auto prev
Definition prev.h:28
constexpr auto next
Definition next.h:35
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 size
Definition size.h:54
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 sum
Definition sum.h:26
constexpr auto begin
Definition begin.h:44
constexpr auto index_dispatch
Definition index_dispatch.h:41
typename T::template At< index > At
Definition list.h:110
constexpr bool All
Definition algorithm.h:20
detail::CommonTypeHelper< Types... >::Type CommonType
Definition common.h:62
detail::CommonReferenceHelper< Types... >::Type CommonReference
Definition common.h:198
T::Back Back
Definition list.h:103
detail::MakeUnsignedHelper< RemoveCV< T > >::Type MakeUnsigned
Definition language.h:362
Conditional< is_const, T const, T > MaybeConst
Definition util.h:9
Type< detail::PopBackHelper< L > > PopBack
Definition algorithm.h:111
decltype(container::begin(util::declval< T & >())) ContainerIterator
Definition container_iterator.h:8
Definition vocab.h:96
constexpr auto get(T &&value) -> decltype(auto)
Definition get.h:8
constexpr tag_invoke_detail::TagInvokeFn tag_invoke
Definition tag_invoke.h:22
constexpr auto tuple_transform(F &&function, Tup &&tuple)
Definition tuple_transform.h:22
constexpr auto apply(F &&f, Tup &&tuple) -> decltype(detail::apply_impl(meta::MakeIndexSequence< meta::TupleSize< Tup > > {}, util::forward< F >(f), util::forward< Tup >(tuple)))
Definition apply.h:22
constexpr auto visit(Vis &&visitor, Vars &&... variants) -> R
Definition visit.h:39
constexpr auto c_
A value of type Constexpr<val>.
Definition constexpr.h:252
Definition default_sentinel.h:4
Definition iterator_base.h:14
Constexpr<(concepts::BidirectionalContainer< Con > &&concepts::CommonContainer< Con >)||(concepts::SizedContainer< Con > &&concepts::RandomAccessContainer< Con >)> Invoke
Definition concat_view.h:56
A wrapper for a constexpr value.
Definition core.h:77
Definition core.h:5
Definition span_fixed_size.h:37