VCCC  2024.05
VisualCamp Common C++ library
join_view.hpp
Go to the documentation of this file.
1 //
2 // Created by yonggyulee on 1/31/24.
3 //
4 
5 #ifndef VCCC_RANGES_VIEWS_JOIN_VIEW_HPP_
6 #define VCCC_RANGES_VIEWS_JOIN_VIEW_HPP_
7 
8 #include <type_traits>
9 #include <utility>
10 
30 #include "vccc/__ranges/view.hpp"
39 
40 namespace vccc {
41 namespace ranges {
42 namespace detail {
43 
44 template<typename Base>
45 using join_view_iterator_concept =
46  std::conditional_t<
47  conjunction<
48  std::is_reference<range_reference_t<Base>>,
49  bidirectional_range<Base>,
50  bidirectional_range<range_reference_t<Base>>
51  >::value,
53  std::conditional_t<
54  conjunction<
55  std::is_reference<range_reference_t<Base>>,
56  forward_range<Base>,
57  forward_range<range_reference_t<Base>>
58  >::value,
61  >>;
62 
63 // Defined only if IteratorConcept models forward_iterator_tag
64 template<typename Base, typename IteratorConcept = join_view_iterator_concept<Base>>
65 struct join_view_iterator_category {
66 #if __cplusplus < 202002L
67  using iterator_category = iterator_ignore;
68 #endif
69 };
70 
71 template<typename Base>
72 struct join_view_iterator_category<Base, forward_iterator_tag> {
73  private:
74  using OuterC = typename cxx20_iterator_traits<iterator_t<Base>>::iterator_category;
75  using InnerC = typename cxx20_iterator_traits<iterator_t<range_reference_t<Base>>>::iterator_category;
76 
77  public:
78  using iterator_category =
79  std::conditional_t<
80  conjunction<
81  derived_from<OuterC, bidirectional_iterator_tag>,
82  derived_from<InnerC, bidirectional_iterator_tag>
83  >::value,
85  std::conditional_t<
86  conjunction<
87  derived_from<OuterC, forward_iterator_tag>,
88  derived_from<InnerC, forward_iterator_tag>
89  >::value,
92  >>;
93 };
94 
95 } // namespace detail
96 
99 
100 template<typename V>
101 class join_view : public view_interface<join_view<V>> {
102  public:
103  static_assert(input_range<V>::value, "Constraints not satisfied");
104  static_assert(view<V>::value, "Constraints not satisfied");
105  static_assert(input_range<range_reference_t<V>>::value, "Constraints not satisfied");
106 
107  private:
108  template <bool Const>
109  using InnerRng = range_reference_t<maybe_const<Const, V>>;
110 
111  public:
112  template<bool Const> class iterator;
113  template<bool Const> friend class iterator;
114  template<bool Const> class sentinel;
115 
116  template<bool Const>
117  class iterator : detail::join_view_iterator_category<maybe_const<Const, V>> {
118  using Parent = maybe_const<Const, join_view>;
119  using Base = maybe_const<Const, V>;
120  using OuterIter = iterator_t<Base>;
121  using InnerIter = iterator_t<range_reference_t<Base>>;
122  static constexpr bool ref_is_glvalue = std::is_reference<range_reference_t<Base>>::value;
123 
124  friend class join_view;
125  template<bool> friend class sentinel;
126 
127  public:
128  using iterator_concept = detail::join_view_iterator_concept<Base>;
129 
132 #if __cplusplus < 202002L
133  using pointer = void;
134  using reference = decltype(**std::declval<movable_box<InnerIter>&>());
135 #endif
136 
137  template<typename O = OuterIter, std::enable_if_t<conjunction<
140  >::value, int> = 0>
142  : outer_(), inner_(), parent_(nullptr) {}
143 
144  constexpr iterator(Parent& parent, OuterIter outer)
145  : outer_(std::move(outer)), parent_(vccc::addressof(parent))
146  {
147  satisfy();
148  }
149 
150  template<bool AntiConst, std::enable_if_t<conjunction<
151  bool_constant<((Const != AntiConst) && Const)>,
152  convertible_to<iterator_t<V>, OuterIter>,
154  >::value, int> = 0>
156  : outer_(std::move(i.outer_)), inner_(std::move(i.inner_)), parent_(i.parent_) {}
157 
158  constexpr decltype(auto) operator*() const {
159  return **inner_;
160  }
161 
162  template<typename II = InnerIter, std::enable_if_t<conjunction<
165  >::value, int> = 0>
166  constexpr decltype(auto) operator->() const {
167  return *inner_;
168  }
169 
170  template<bool B = ref_is_glvalue, std::enable_if_t<B, int> = 0>
171  constexpr iterator& operator++() {
172  auto&& inner_rng = *outer_;
173  if (++*inner_ == ranges::end(inner_rng)) {
174  ++outer_;
175  satisfy();
176  }
177  return *this;
178  }
179 
180  template<bool B = ref_is_glvalue, std::enable_if_t<B == false, int> = 0>
181  constexpr iterator& operator++() {
182  auto&& inner_rng = *parent_->inner_;
183  if (++*inner_ == ranges::end(inner_rng)) {
184  ++outer_;
185  satisfy();
186  }
187  return *this;
188  }
189 
190  template<bool B = ref_is_glvalue, std::enable_if_t<conjunction<
194  >::value == false, int> = 0>
195  constexpr void operator++(int) {
196  ++*this;
197  }
198 
199  template<bool B = ref_is_glvalue, std::enable_if_t<conjunction<
203  >::value, int> = 0>
204  constexpr iterator operator++(int) {
205  auto tmp = *this;
206  ++*this;
207  return tmp;
208  }
209 
210  template<bool B = ref_is_glvalue, std::enable_if_t<conjunction<
215  >::value, int> = 0>
216  constexpr iterator& operator--() {
217  if (outer_ == ranges::end(parent_->base_))
218  inner_ = ranges::end(*--outer_);
219  while (*inner_ == ranges::begin(*outer_))
220  inner_ = ranges::end(*--outer_);
221  --*inner_;
222  return *this;
223  }
224 
225  template<bool B = ref_is_glvalue, std::enable_if_t<conjunction<
230  >::value, int> = 0>
231  constexpr iterator operator--(int) {
232  auto tmp = *this;
233  --*this;
234  return tmp;
235  }
236 
237  constexpr void satisfy() {
238  satisfy_impl(bool_constant<ref_is_glvalue>{});
239  }
240 
241  template<bool B = ref_is_glvalue, std::enable_if_t<conjunction<
245  >::value, int> = 0>
246  friend constexpr bool operator==(const iterator& x, const iterator& y) {
247  return (x.outer_ == y.outer_) && (*x.inner_ == *y.inner_);
248  }
249 
250  template<bool B = ref_is_glvalue, std::enable_if_t<conjunction<
254  >::value, int> = 0>
255  friend constexpr bool operator!=(const iterator& x, const iterator& y) {
256  return !(x == y);
257  }
258 
259  friend constexpr decltype(auto) iter_move(const iterator& i)
260  noexcept(noexcept(ranges::iter_move(*i.inner_)))
261  {
262  return ranges::iter_move(*i.inner_);
263  }
264 
266  friend constexpr void iter_swap(const iterator& x, const iterator& y)
267  noexcept(noexcept(ranges::iter_swap(*x.inner_, *y.inner_)))
268  {
269  ranges::iter_swap(x.inner_, y.inner_);
270  }
271 
272  private:
273  constexpr OuterIter& get_outer() noexcept {
274  return get_outer(forward_range<Base>{});
275  }
276  constexpr const OuterIter& get_outer() const noexcept {
277  return get_outer(forward_range<Base>{});
278  }
279  constexpr OuterIter& get_outer_impl(std::true_type /* forward_range */) noexcept {
280  return outer_;
281  }
282  constexpr OuterIter& get_outer_impl(std::false_type /* forward_range */) noexcept {
283  return *parent_->outer_;
284  }
285  constexpr OuterIter& get_outer_impl(std::true_type /* forward_range */) const noexcept {
286  return outer_;
287  }
288  constexpr OuterIter& get_outer_impl(std::false_type /* forward_range */) const noexcept {
289  return *parent_->outer_;
290  }
291 
292  constexpr decltype(auto) update_inner_impl(const iterator_t<Base>& x, std::true_type /* ref_is_glvalue */) {
293  return *x;
294  }
295  constexpr decltype(auto) update_inner_impl(const iterator_t<Base>& x, std::false_type /* ref_is_glvalue */) {
296  return parent_->inner_.emplace(x);
297  }
298 
299  constexpr decltype(auto) update_inner(const iterator_t<Base>& x) {
300  return update_inner_impl(x, bool_constant<ref_is_glvalue>{});
301  }
302 
303  constexpr void satisfy_impl(std::true_type /* ref_is_glvalue */) {
304  for (; outer_ != ranges::end(parent_->base_); ++outer_) {
305  auto&& inner = update_inner(outer_);
306  inner_ = ranges::begin(inner);
307  if (*inner_ != ranges::end(inner))
308  return;
309  }
310 
311  inner_ = InnerIter();
312  }
313  constexpr void satisfy_impl(std::false_type /* ref_is_glvalue */) {
314  for (; outer_ != ranges::end(parent_->base_); ++outer_) {
315  auto&& inner = update_inner(outer_);;
316  inner_ = ranges::begin(inner);
317  if (inner_ != ranges::end(inner))
318  return;
319  }
320  }
321 
322  OuterIter outer_;
323  movable_box<InnerIter> inner_;
324  Parent* parent_;
325  };
326 
327  template<bool Const>
328  class sentinel {
329  using Parent = maybe_const<Const, join_view>;
330  using Base = maybe_const<Const, V>;
331 
332  public:
333  sentinel() = default;
334 
335  constexpr explicit sentinel(Parent& parent)
336  : end_(ranges::end(parent.base_)) {}
337 
338  template<bool AntiConst, std::enable_if_t<conjunction<
339  bool_constant<((Const != AntiConst) && Const)>,
341  >::value, int> = 0>
343  : end_(std::move(s.end_)) {}
344 
345  friend constexpr bool operator==(const iterator<Const>& x, const sentinel& y) {
346  using namespace vccc::rel_ops;
347  return x.get_outer() == y.end_;
348  }
349 
350  friend constexpr bool operator==(const sentinel& y, const iterator<Const>& x) {
351  return x == y;
352  }
353 
354  friend constexpr bool operator!=(const iterator<Const>& x, const sentinel& y) {
355  return !(x == y);
356  }
357 
358  friend constexpr bool operator!=(const sentinel& y, const iterator<Const>& x) {
359  return !(x == y);
360  }
361 
362  private:
363  sentinel_t<Base> end_;
364  };
365 
367  join_view() : base_(V()) {}
368 
369  constexpr explicit join_view(V base) : base_(std::move(base)) {}
370 
372  constexpr V base() const& {
373  return base_;
374  }
375 
376  constexpr V base() && {
377  return std::move(base_);
378  }
379 
380  constexpr auto begin() {
381  using B = conjunction<simple_view<V>, std::is_reference<range_reference_t<V>>>;
382  return iterator<B::value>{*this, ranges::begin(base_)};
383  }
384 
385  template<typename V2 = V, std::enable_if_t<conjunction<
387  std::is_reference<range_reference_t<const V2>>
388  >::value, int> = 0>
389  constexpr auto begin() const {
390  return iterator<true>{*this, ranges::begin(base_)};
391  }
392 
393  constexpr auto end() {
394  return end_impl(conjunction<
396  std::is_reference<range_reference_t<V>>,
400  >{});
401  }
402 
403  template<typename V2 = V, std::enable_if_t<conjunction<
405  std::is_reference<range_reference_t<const V2>>
406  >::value, int> = 0>
407  constexpr auto end() const {
408  return end_impl(conjunction<
410  std::is_reference<range_reference_t<const V>>,
414  >{});
415  }
416 
417  private:
418  constexpr auto end_impl(std::true_type) {
419  return iterator<simple_view<V>::value>{*this, ranges::end(base_)};
420  }
421  constexpr auto end_impl(std::false_type) {
422  return sentinel<simple_view<V>::value>{*this};
423  }
424 
425  constexpr auto end_impl(std::true_type) const {
426  return iterator<true>{*this, ranges::end(base_)};
427  }
428  constexpr auto end_impl(std::false_type) const {
429  return sentinel<true>{*this};
430  }
431 
432  V base_;
433 };
434 
435 #if __cplusplus >= 201703L
436 
437 template<typename R>
438 explicit join_view(R&&) -> join_view<views::all_t<R>>;
439 
440 #endif
441 
443 
444 } // namespace ranges
445 } // namespace vccc
446 
447 #endif // VCCC_RANGES_VIEWS_JOIN_VIEW_HPP_
Definition: join_view.hpp:117
constexpr iterator & operator--()
Definition: join_view.hpp:216
void pointer
Definition: join_view.hpp:133
iterator()
Definition: join_view.hpp:141
common_type_t< range_difference_t< Base >, range_difference_t< range_reference_t< Base > >> difference_type
Definition: join_view.hpp:131
constexpr void operator++(int)
Definition: join_view.hpp:195
constexpr iterator(iterator< AntiConst > i)
Definition: join_view.hpp:155
constexpr friend bool operator==(const iterator &x, const iterator &y)
Definition: join_view.hpp:246
detail::join_view_iterator_concept< Base > iterator_concept
Definition: join_view.hpp:128
constexpr decltype(auto) friend iter_move(const iterator &i) noexcept(noexcept(ranges::iter_move(*i.inner_)))
Definition: join_view.hpp:259
constexpr friend bool operator!=(const iterator &x, const iterator &y)
Definition: join_view.hpp:255
constexpr friend void iter_swap(const iterator &x, const iterator &y) noexcept(noexcept(ranges::iter_swap(*x.inner_, *y.inner_)))
Definition: join_view.hpp:266
constexpr iterator operator--(int)
Definition: join_view.hpp:231
constexpr iterator operator++(int)
Definition: join_view.hpp:204
constexpr void satisfy()
Definition: join_view.hpp:237
constexpr iterator & operator++()
Definition: join_view.hpp:171
decltype(**std::declval< movable_box< InnerIter > & >()) reference
Definition: join_view.hpp:134
constexpr iterator(Parent &parent, OuterIter outer)
Definition: join_view.hpp:144
range_value_t< range_reference_t< Base > > value_type
Definition: join_view.hpp:130
Definition: join_view.hpp:328
constexpr sentinel(Parent &parent)
Definition: join_view.hpp:335
constexpr friend bool operator==(const sentinel &y, const iterator< Const > &x)
Definition: join_view.hpp:350
constexpr friend bool operator==(const iterator< Const > &x, const sentinel &y)
Definition: join_view.hpp:345
constexpr sentinel(sentinel< AntiConst > s)
Definition: join_view.hpp:342
constexpr friend bool operator!=(const iterator< Const > &x, const sentinel &y)
Definition: join_view.hpp:354
constexpr friend bool operator!=(const sentinel &y, const iterator< Const > &x)
Definition: join_view.hpp:358
Definition: join_view.hpp:101
constexpr V base() const &
Definition: join_view.hpp:372
constexpr auto begin()
Definition: join_view.hpp:380
join_view()
Definition: join_view.hpp:367
constexpr V base() &&
Definition: join_view.hpp:376
constexpr auto end()
Definition: join_view.hpp:393
constexpr auto end() const
Definition: join_view.hpp:407
constexpr auto begin() const
Definition: join_view.hpp:389
constexpr join_view(V base)
Definition: join_view.hpp:369
helper class template for defining a view, using the curiously recurring template pattern
Definition: view_interface.hpp:78
constexpr VCCC_INLINE_OR_STATIC detail_iter_move::iter_move_niebloid iter_move
Definition: iter_move.hpp:92
constexpr VCCC_INLINE_OR_STATIC detail_iter_swap::iter_swap_niebloid iter_swap
Definition: iter_swap.hpp:90
std::forward_iterator_tag forward_iterator_tag
Definition: iterator_tag.hpp:17
std::input_iterator_tag input_iterator_tag
Definition: iterator_tag.hpp:15
std::bidirectional_iterator_tag bidirectional_iterator_tag
Definition: iterator_tag.hpp:18
std::enable_if_t< std::is_object< T >::value, T * > addressof(T &t) noexcept
Definition: addressof.hpp:33
typename sentinel< R >::type sentinel_t
Definition: sentinel_t.hpp:29
typename ranges::iterator< T >::type iterator_t
Definition: iterator_t.hpp:32
constexpr VCCC_INLINE_OR_STATIC detail::begin_niebloid begin
returns an iterator to the beginning of a range
Definition: begin.hpp:116
constexpr VCCC_INLINE_OR_STATIC detail::end_niebloid end
returns a sentinel indicating the end of a range
Definition: end.hpp:120
typename range_difference< R >::type range_difference_t
Used to obtain the difference type of the iterator type of range type R.
Definition: range_difference_t.hpp:41
typename range_reference< R >::type range_reference_t
Used to obtain the reference type of the iterator type of range type R.
Definition: range_reference_t.hpp:42
typename range_value< R >::type range_value_t
Used to obtain the value type of the iterator type of range type R.
Definition: range_value_t.hpp:42
std::integral_constant< bool, v > bool_constant
Definition: bool_constant.hpp:19
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
Definition: matrix.hpp:495
Definition: cxx20_rel_ops.hpp:17
Definition: directory.h:12
constexpr VCCC_INLINE_OR_STATIC detail::element_niebloid< 1 > value
Definition: key_value.hpp:35
Definition: conjunction.hpp:22
Models std::convertible_to
Definition: convertible_to.hpp:38
specifies that an object of a type can be copied, moved, and swapped
Definition: copyable.hpp:59
specifies that an object of a type can be default constructed
Definition: default_initializable.hpp:62
specifies that operator == is an equivalence relation
Definition: equality_comparable.hpp:30
Definition: has_operator_arrow.hpp:18
specifies a range whose iterator type satisfies bidirectional_iterator
Definition: bidirectional_range.hpp:49
Definition: common_range.hpp:41
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 that a range is a view, that is, it has constant time copy/move/assignment
Definition: view.hpp:31