VCCC  2024.05
VisualCamp Common C++ library
concat_view.hpp
Go to the documentation of this file.
1 //
2 // Created by YongGyu Lee on 2/13/24.
3 //
4 
5 #ifndef CONCAT_VIEW_HPP
6 #define CONCAT_VIEW_HPP
7 
8 #include <functional>
9 #include <tuple>
10 #include <type_traits>
11 #include <utility>
12 
14 #include "vccc/__iterator/next.hpp"
18 #include "vccc/__ranges/end.hpp"
30 #include "vccc/variant.hpp"
31 
32 namespace vccc {
33 namespace ranges {
34 namespace detail {
35 
36 template<typename... Rngs>
37 using concat_compatible = conjunction<
38  has_typename_type<common_type<range_value_t<Rngs>...>>,
39  has_typename_type<common_reference<range_reference_t<Rngs>...>>,
40  has_typename_type<common_reference<range_rvalue_reference_t<Rngs>...>>
41 >;
42 
43 } // namespace detail
44 
47 
48 // Modified from ranges-v3 library
49 template<typename... Rngs>
50 struct concat_view : view_interface<concat_view<Rngs...>> {
51  static_assert(sizeof...(Rngs) != 0, "Constraints not satisfied");
52  static_assert(conjunction<input_range<Rngs>...>::value, "Constraints not satisfied");
53  static_assert(detail::concat_compatible<Rngs...>::value, "Constraints not satisfied");
54 
55  private:
56  using difference_type_ = common_type_t<range_difference_t<Rngs>...>;
57  using BackBase = typename type_sequence<Rngs...>::back;
58 
59  static constexpr std::size_t cranges = sizeof...(Rngs);
60  std::tuple<Rngs...> bases_{};
61 
62  public:
63  template<bool IsConst>
64  struct iterator;
65 
66  template<bool Const>
67  struct sentinel {
68  private:
69  friend struct sentinel<!Const>;
70  friend struct iterator<Const>;
71  friend struct concat_view;
72 
73  using Parent = maybe_const<Const, concat_view>;
74  using Base = maybe_const<Const, BackBase>;
75  sentinel_t<Base> end_{};
76 
77  constexpr sentinel(Parent& parent)
78  : end_(ranges::end(std::get<cranges - 1>(parent.bases_))) {}
79 
80  public:
81  sentinel() = default;
82 
83  template<bool AntiConst, std::enable_if_t<conjunction<
84  bool_constant<((Const != AntiConst) && Const)>,
86  >::value, int> = 0>
87  constexpr sentinel(sentinel<AntiConst> that)
88  : end_(std::move(that.end_)) {}
89  };
90 
91  template<bool IsConst>
92  struct iterator {
95  std::conditional_t<
97  std::conditional_t<
99  std::conditional_t<
102  >>>;
106  using pointer = void;
107 
108  private:
109  friend struct iterator<!IsConst>;
110  using Parent = maybe_const<IsConst, concat_view>;
111  Parent* parent_;
113 
114  template<std::size_t N, std::enable_if_t<(N < cranges - 1), int> = 0>
115  void satisfy(std::integral_constant<std::size_t, N>) {
116  if (std::get<N>(its_) == ranges::end(std::get<N>(parent_->bases_))) {
117  its_.template emplace<N + 1>(ranges::begin(std::get<N + 1>(parent_->bases_)));
118  this->satisfy(std::integral_constant<size_t, N + 1>{});
119  }
120  }
121 
122  template<std::size_t N, std::enable_if_t<(N >= cranges - 1), int> = 0>
123  void satisfy(std::integral_constant<std::size_t, N>) { /* no op */ }
124 
125  struct next_raw_visitor {
127 
128  template<typename I, std::size_t N>
130  ++it;
131  pos->satisfy(std::integral_constant<size_t, N>{});
132  }
133 
134  template<typename U> void operator()(U&, in_place_index_t<variant_npos>) { /* no op */ }
135  };
136 
137  struct prev_raw_visitor {
139 
140  template<typename I>
142  --it;
143  }
144 
145  template<typename I, std::size_t N, std::enable_if_t<conjunction<
146  bool_constant<(N != 0)>,
148  >::value, int> = 0>
149  void operator()(I& it, in_place_index_t<N>) {
150  if (it == ranges::begin(std::get<N>(pos->parent_->bases_))) {
151  auto&& rng = std::get<N - 1>(pos->parent_->bases_);
152 
153  pos->its_.template emplace<N - 1>(ranges::next(ranges::begin(rng), ranges::end(rng)));
154  vccc::detail::variant_raw_visit(pos->its_.index(), pos->its_._base().storage(), *this);
155  } else {
156  --it;
157  }
158  }
159 
160  template<typename U> void operator()(U&, in_place_index_t<variant_npos>) { /* no op */ }
161  };
162 
163  struct advance_fwd_raw_visitor {
166 
169  ranges::advance(it, n);
170  }
171 
174  auto last = ranges::end(std::get<N>(pos->parent_->bases_));
175  // BUGBUG If distance(it, last) > n, then using bounded advance
176  // is O(n) when it need not be since the last iterator position
177  // is actually not interesting. Only the "rest" is needed, which
178  // can sometimes be O(1).
179  auto rest = ranges::advance(it, n, std::move(last));
180  pos->satisfy(std::integral_constant<size_t, N>{});
181  if (rest != 0) {
182  vccc::detail::variant_raw_visit(
183  pos->its_.index(), pos->its_._base().storage(), advance_fwd_raw_visitor{pos, rest});
184  }
185  }
186 
187  template<typename U> void operator()(U&, in_place_index_t<variant_npos>) { /* no op */ }
188  };
189 
190  struct advance_rev_raw_visitor {
193 
196  ranges::advance(it, n);
197  }
198 
201  auto first = ranges::begin(std::get<N>(pos->parent_->bases_));
202  if (it == first) {
203  auto&& rng = std::get<N - 1>(pos->parent_->bases_);
204  pos->its_.template emplace<N - 1>(ranges::next(ranges::begin(rng), ranges::end(rng)));
205  vccc::detail::variant_raw_visit(pos->its_.index(), pos->its_._base().storage(), *this);
206  } else {
207  auto rest = ranges::advance(it, n, std::move(first));
208  if (rest != 0) {
209  vccc::detail::variant_raw_visit(
210  pos->its_.index(), pos->its_._base().storage(), advance_rev_raw_visitor{pos, rest});
211  }
212  }
213  }
214 
215  template<typename U> void operator()(U&, in_place_index_t<variant_npos>) { /* no op */ }
216  };
217 
218  static difference_type distance_to_(std::integral_constant<size_t, cranges>, iterator const &, iterator const &) {
219  // unreachable
220  return -1;
221  }
222 
223  template<std::size_t N>
224  static difference_type distance_to_(std::integral_constant<size_t, N>, const iterator& from, const iterator& to) {
225  if (from.its_.index() > N)
226  return iterator::distance_to_(std::integral_constant<size_t, N + 1>{}, from, to);
227 
228  if (from.its_.index() == N) {
229  if (to.its_.index() == N)
230  return ranges::distance(vccc::detail::variant_raw_get(from.its_._base().storage(), in_place_index<N>),
231  vccc::detail::variant_raw_get(to.its_._base().storage(), in_place_index<N>));
232  return ranges::distance(vccc::detail::variant_raw_get(from.its_._base().storage(), in_place_index<N>),
233  ranges::end(std::get<N>(from.parent_->bases_)))
234  + iterator::distance_to_(std::integral_constant<size_t, N + 1>{}, from, to);
235  }
236 
237  if (from.its_.index() < N && to.its_.index() > N)
238  return ranges::distance(std::get<N>(from.parent_->bases_))
239  + iterator::distance_to_(std::integral_constant<size_t, N + 1>{}, from, to);
240 
241  return ranges::distance(ranges::begin(std::get<N>(from.parent_->bases_)),
242  vccc::detail::variant_raw_get(to.its_._base().storage(), in_place_index<N>));
243  }
244 
245  public:
246  iterator() = default;
247 
248  template<std::size_t I, typename It>
249  constexpr iterator(Parent* parent, in_place_index_t<I>, It&& it)
250  : parent_(parent)
251  , its_{in_place_index<I>, std::forward<It>(it)} // ranges::begin(std::get<0>(parent->bases_))
252  {
253  this->satisfy(std::integral_constant<size_t, I>{});
254  }
255 
256  // iterator(Parent* parent, end_tag)
257  // : parent_(parent)
258  // , its_{in_place_index<cranges - 1>, ranges::end(std::get<cranges - 1>(parent->bases_))} {}
259 
260 
261  template<bool Other, std::enable_if_t<conjunction<
262  bool_constant<(Other != IsConst && IsConst)>
263  >::value, int> = 0>
264  constexpr iterator(iterator<Other> that)
265  : parent_(that.parent_)
266  , its_(std::move(that.its_)) {}
267 
268  constexpr decltype(auto) operator*() const {
269  return its_.visit([](auto&& it) -> iterator::reference { return *it; });
270  }
271 
272  template<typename V = variant<iterator_t<maybe_const<IsConst, Rngs>>...>, std::enable_if_t<
273  equality_comparable<V>
274  ::value, int> = 0>
275  friend constexpr bool operator==(const iterator& x, const iterator& y) {
276  return x.its_ == y.its_;
277  }
278 
279  template<typename V = variant<iterator_t<maybe_const<IsConst, Rngs>>...>, std::enable_if_t<
280  equality_comparable<V>
281  ::value, int> = 0>
282  friend constexpr bool operator!=(const iterator& x, const iterator& y) {
283  return !(x == y);
284  }
285 
286  friend constexpr bool operator==(const iterator& x, const sentinel<IsConst>& y) {
287  return x.equal(y);
288  }
289 
290  friend constexpr bool operator!=(const iterator& x, const sentinel<IsConst>& y) {
291  return !(x == y);
292  }
293 
294  friend constexpr bool operator==(const sentinel<IsConst>& y, const iterator& x) {
295  return x == y;
296  }
297 
298  friend constexpr bool operator!=(const sentinel<IsConst>& y, const iterator& x) {
299  return !(x == y);
300  }
301 
302  constexpr bool equal(const sentinel<IsConst>& pos) const {
303  return its_.index() == cranges - 1 && std::get<cranges - 1>(its_) == pos.end_;
304  }
305 
306  constexpr iterator& operator++() {
307  vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), next_raw_visitor{this});
308  return *this;
309  }
310 
311  template<typename Dummy = void, std::enable_if_t<conjunction<
312  std::is_void<Dummy>,
314  >::value, int> = 0>
315  constexpr void operator++(int) {
316  ++*this;
317  }
318 
319  template<typename Dummy = void, std::enable_if_t<conjunction<
320  std::is_void<Dummy>,
322  >::value, int> = 0>
323  constexpr iterator operator++(int) {
324  auto tmp = *this;
325  ++*this;
326  return tmp;
327  }
328 
329  template<typename Dummy = void, std::enable_if_t<conjunction<
330  std::is_void<Dummy>,
332  >::value, int> = 0>
333  constexpr iterator& operator--() {
334  vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), prev_raw_visitor{this});
335  return *this;
336  }
337 
338  template<typename Dummy = void, std::enable_if_t<conjunction<
339  std::is_void<Dummy>,
341  >::value, int> = 0>
342  constexpr iterator& operator--(int) {
343  auto tmp = *this;
344  --*this;
345  return tmp;
346  }
347 
348  template<typename Dummy = void, std::enable_if_t<conjunction<
349  std::is_void<Dummy>,
351  >::value, int> = 0>
353  if (n > 0) {
354  vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), advance_fwd_raw_visitor{this, n});
355  } else if (n < 0) {
356  vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), advance_rev_raw_visitor{this, n});
357  }
358  return *this;
359  }
360 
361  template<typename Dummy = void, std::enable_if_t<conjunction<
362  std::is_void<Dummy>,
364  >::value, int> = 0>
366  *this += -n;
367  return *this;
368  }
369 
370  template<typename Dummy = void, std::enable_if_t<conjunction<
371  std::is_void<Dummy>,
373  >::value, int> = 0>
374  friend constexpr difference_type operator-(const iterator& x, const iterator& y) {
375  if (x.its_.index() <= y.its_.index())
376  return -iterator::distance_to_(std::integral_constant<std::size_t, 0>{}, x, y);
377  return iterator::distance_to_(std::integral_constant<std::size_t, 0>{}, y, x);
378  }
379 
380  };
381 
382 
383  concat_view() = default;
384 
385  explicit concat_view(Rngs... rngs)
386  : bases_{std::move(rngs)...} {}
387 
388  constexpr auto begin() {
389  using Const = conjunction<simple_view<Rngs>...>;
390  return iterator<Const::value>{this, in_place_index<0>, ranges::begin(std::get<0>(bases_))};
391  }
392 
393  template<typename Dummy = void, std::enable_if_t<conjunction<
394  std::is_void<Dummy>,
396  >::value, int> = 0>
397  constexpr iterator<true> begin() const {
398  return iterator<true>{this, in_place_index<0>, ranges::begin(std::get<0>(bases_))};
399  }
400 
401  template<typename Dummy = void, std::enable_if_t<conjunction<
402  std::is_void<Dummy>,
404  >::value, int> = 0>
405  constexpr auto end() {
406  using Const = conjunction<simple_view<Rngs>...>;
407  return iterator<Const::value>{this, in_place_index<cranges - 1>, ranges::end(std::get<cranges - 1>(bases_))};
408  }
409 
410  template<typename Dummy = void, std::enable_if_t<conjunction<
411  std::is_void<Dummy>,
413  >::value, int> = 0>
414  constexpr auto end() {
415  using Const = conjunction<simple_view<Rngs>...>;
416  return sentinel<Const::value>{*this};
417  }
418 
419  template<typename Dummy = void, std::enable_if_t<conjunction<
420  std::is_void<Dummy>,
422  >::value, int> = 0>
423  constexpr auto end() const {
424  return end_impl(conjunction<common_range<const Rngs>...>{});
425  }
426 
427  template<typename Dummy = void, std::enable_if_t<conjunction<
428  std::is_void<Dummy>,
430  >::value, int> = 0>
431  constexpr auto size() {
432  return vccc::tuple_fold_left(
433  vccc::tuple_transform(bases_, [](auto&& r) { return r.size(); }),
434  std::size_t{0},
435  std::plus<>{}
436  );
437  }
438 
439  template<typename Dummy = void, std::enable_if_t<conjunction<
440  std::is_void<Dummy>,
442  >::value, int> = 0>
443  constexpr auto size() const {
444  return vccc::tuple_fold_left(
445  vccc::tuple_transform(bases_, [](auto&& r) { return r.size(); }),
446  std::size_t{0},
447  std::plus<>{}
448  );
449  }
450 
451  private:
452  constexpr iterator<true> end_impl(std::true_type /* common_range */) const {
453  return iterator<true>{this, in_place_index<cranges - 1>, ranges::end(std::get<cranges - 1>(bases_))};
454  }
455 
456  constexpr sentinel<true> end_impl(std::false_type /* common_range */) const {
457  return sentinel<true>{*this};
458  }
459 };
460 
461 #if __cplusplus >= 201703L
462 
463 template<typename... Rng>
464 concat_view(Rng &&...) //
466 
467 #endif
468 
469 namespace views {
470 namespace detail {
471 
473  template<typename... R, std::enable_if_t<conjunction<
475  input_range<R>...
476  >::value, int> = 0>
477  constexpr auto operator()(R&&... rs) const {
478  return concat_view<all_t<R>...>{views::all(std::forward<R>(rs))...};
479  }
480 };
481 
482 } // namespace detail
483 
486 
488 
489 } // namespace views
490 
491 } // namespace ranges
492 } // namespace vccc
493 
494 #endif //CONCAT_VIEW_HPP
helper class template for defining a view, using the curiously recurring template pattern
Definition: view_interface.hpp:78
constexpr decltype(auto) back()
Definition: view_interface.hpp:255
a type-safe discriminated union
Definition: variant.hpp:589
constexpr std::size_t index() const noexcept
Definition: variant.hpp:662
constexpr decltype(auto) visit(Visitor &&vis) &
Definition: variant.hpp:707
constexpr VCCC_INLINE_OR_STATIC detail::advance_niebloid advance
Definition: advance.hpp:158
constexpr VCCC_INLINE_OR_STATIC detail::next_niebloid next
Definition: next.hpp:65
std::forward_iterator_tag forward_iterator_tag
Definition: iterator_tag.hpp:17
std::random_access_iterator_tag random_access_iterator_tag
Definition: iterator_tag.hpp:19
std::input_iterator_tag input_iterator_tag
Definition: iterator_tag.hpp:15
std::bidirectional_iterator_tag bidirectional_iterator_tag
Definition: iterator_tag.hpp:18
constexpr std::enable_if_t<(detail::ranges_to_1_tag< C, R, Args... >::value > 0), C > to(R &&r, Args &&... args)
Constructs an object of type C from the elements of r
Definition: to.hpp:446
constexpr iterator & operator--()
Definition: concat_view.hpp:333
constexpr iterator(Parent *parent, in_place_index_t< I >, It &&it)
Definition: concat_view.hpp:249
common_type_t< range_difference_t< Rngs >... > difference_type
Definition: concat_view.hpp:104
constexpr iterator & operator--(int)
Definition: concat_view.hpp:342
std::conditional_t< conjunction< random_access_range< Rngs >... >::value, random_access_iterator_tag, std::conditional_t< conjunction< bidirectional_range< Rngs >... >::value, bidirectional_iterator_tag, std::conditional_t< conjunction< forward_range< Rngs >... >::value, forward_iterator_tag, input_iterator_tag > >> iterator_concept
Definition: concat_view.hpp:102
void pointer
Definition: concat_view.hpp:106
constexpr friend bool operator==(const sentinel< IsConst > &y, const iterator &x)
Definition: concat_view.hpp:294
constexpr auto get(const subrange< I, S, K > &r)
Definition: subrange.hpp:371
constexpr auto size() const
Definition: concat_view.hpp:443
constexpr auto size()
Definition: concat_view.hpp:431
common_reference_t< range_reference_t< maybe_const< IsConst, Rngs > >... > reference
Definition: concat_view.hpp:105
constexpr friend difference_type operator-(const iterator &x, const iterator &y)
Definition: concat_view.hpp:374
constexpr void operator++(int)
Definition: concat_view.hpp:315
constexpr auto begin()
Definition: concat_view.hpp:388
typename sentinel< R >::type sentinel_t
Definition: sentinel_t.hpp:29
typename ranges::iterator< T >::type iterator_t
Definition: iterator_t.hpp:32
iterator * pos
Definition: concat_view.hpp:126
difference_type n
Definition: concat_view.hpp:165
constexpr VCCC_INLINE_OR_STATIC detail::begin_niebloid begin
returns an iterator to the beginning of a range
Definition: begin.hpp:116
constexpr friend bool operator==(const iterator &x, const iterator &y)
Definition: concat_view.hpp:275
void operator()(I &it, in_place_index_t< 0 >)
Definition: concat_view.hpp:195
constexpr VCCC_INLINE_OR_STATIC detail::distance_niebloid distance
Definition: distance.hpp:72
common_type_t< range_value_t< maybe_const< IsConst, Rngs > >... > value_type
Definition: concat_view.hpp:103
constexpr friend bool operator!=(const iterator &x, const iterator &y)
Definition: concat_view.hpp:282
constexpr auto end()
Definition: concat_view.hpp:405
void operator()(I &it, in_place_index_t< 0 >)
Definition: concat_view.hpp:141
constexpr iterator & operator-=(difference_type n)
Definition: concat_view.hpp:365
constexpr friend bool operator==(const iterator &x, const sentinel< IsConst > &y)
Definition: concat_view.hpp:286
constexpr auto end() const
Definition: concat_view.hpp:423
void operator()(I &it, in_place_index_t< N >)
Definition: concat_view.hpp:173
constexpr friend bool operator!=(const sentinel< IsConst > &y, const iterator &x)
Definition: concat_view.hpp:298
constexpr iterator & operator+=(difference_type n)
Definition: concat_view.hpp:352
input_iterator_tag iterator_category
Definition: concat_view.hpp:93
constexpr iterator< true > begin() const
Definition: concat_view.hpp:397
void operator()(I &it, in_place_index_t< N >)
Definition: concat_view.hpp:129
constexpr VCCC_INLINE_OR_STATIC detail::end_niebloid end
returns a sentinel indicating the end of a range
Definition: end.hpp:120
void operator()(U &, in_place_index_t< variant_npos >)
Definition: concat_view.hpp:134
concat_view(Rngs... rngs)
Definition: concat_view.hpp:385
constexpr iterator(iterator< Other > that)
Definition: concat_view.hpp:264
constexpr bool equal(const sentinel< IsConst > &pos) const
Definition: concat_view.hpp:302
constexpr friend bool operator!=(const iterator &x, const sentinel< IsConst > &y)
Definition: concat_view.hpp:290
constexpr VCCC_INLINE_OR_STATIC detail::concat_niebloid concat
concatenate ranges
Definition: concat_view.hpp:485
constexpr iterator & operator++()
Definition: concat_view.hpp:306
constexpr VCCC_INLINE_OR_STATIC detail::all_adaptor_closure all
a view that includes all elements of a range
Definition: all.hpp:82
void operator()(I &it, in_place_index_t< cranges - 1 >)
Definition: concat_view.hpp:168
constexpr auto tuple_fold_left(Tuple &&tuple, T &&init, F &&f)
Left fold operation for each tuple elements.
Definition: tuple_fold.hpp:52
constexpr auto tuple_transform(Tuple &&t, F &&f) noexcept(noexcept(detail::tuple_transform_impl(std::forward< Tuple >(t), std::forward< F >(f), std::make_index_sequence< std::tuple_size< remove_cvref_t< Tuple >>::value >{})))
Constructs a new tuple with each elements transformed.
Definition: tuple_transform.hpp:36
std::integral_constant< bool, v > bool_constant
Definition: bool_constant.hpp:19
typename common_reference< T... >::type common_reference_t
Definition: common_reference.hpp:54
typename common_type< T... >::type common_type_t
Definition: common_type.hpp:229
std::conditional_t< Const, const V, V > maybe_const
Definition: maybe_const.hpp:16
constexpr VCCC_INLINE_OR_STATIC in_place_index_t< I > in_place_index
Definition: in_place.hpp:53
#define VCCC_INLINE_OR_STATIC
Definition: inline_or_static.hpp:9
Definition: matrix.hpp:495
constexpr std::enable_if_t<(I< m *n), typename vccc::Matrix< T, m, n >::value_type & > get(vccc::Matrix< T, m, n > &matrix)
Definition: matrix.hpp:499
Definition: directory.h:12
constexpr VCCC_INLINE_OR_STATIC detail::element_niebloid< 0 > first
Definition: key_value.hpp:34
constexpr VCCC_INLINE_OR_STATIC detail::element_niebloid< 1 > value
Definition: key_value.hpp:35
specifies that a forward_iterator is a bidirectional iterator, supporting movement backwards
Definition: bidirectional_iterator.hpp:58
Definition: conjunction.hpp:22
Models std::convertible_to
Definition: convertible_to.hpp:38
Definition: in_place.hpp:35
Definition: negation.hpp:23
specifies a range whose iterator type satisfies bidirectional_iterator
Definition: bidirectional_range.hpp:49
Definition: common_range.hpp:41
Definition: concat_view.hpp:92
constexpr iterator operator++(int)
Definition: concat_view.hpp:323
Definition: concat_view.hpp:67
Definition: concat_view.hpp:50
constexpr auto end()
Definition: concat_view.hpp:414
specifies a range whose iterator type satisfies forward_iterator
Definition: forward_range.hpp:47
specifies a range whose iterator type satisfies input_iterator
Definition: input_range.hpp:46
specifies a range whose iterator type satisfies random_access_iterator
Definition: random_access_range.hpp:48
specifies that a type is a range, that is, it provides a begin iterator and an end sentinel
Definition: range.hpp:53
specifies that a range knows its size in constant time
Definition: sized_range.hpp:38
specifies the requirements for a range to be safely convertible to a view
Definition: viewable_range.hpp:59
Definition: concat_view.hpp:472
constexpr auto operator()(R &&... rs) const
Definition: concat_view.hpp:477
specifies that the - operator can be applied to an iterator and a sentinel to calculate their differe...
Definition: sized_sentinel_for.hpp:75
Definition: type_sequence.hpp:110