VCCC  2024.05
VisualCamp Common C++ library
elements_view.hpp
Go to the documentation of this file.
1 //
2 // Created by yonggyulee on 2024/01/26.
3 //
4 
5 #ifndef VCCC_RANGES_VIEWS_ELEMENTS_VIEW_HPP
6 #define VCCC_RANGES_VIEWS_ELEMENTS_VIEW_HPP
7 
8 #include <cstddef>
9 #include <tuple>
10 #include <type_traits>
11 #include <utility>
12 
19 #include "vccc/__ranges/begin.hpp"
24 #include "vccc/__ranges/end.hpp"
30 #include "vccc/__ranges/size.hpp"
31 #include "vccc/__ranges/view.hpp"
44 
45 namespace vccc {
46 namespace ranges {
47 namespace detail {
48 
50 struct has_tuple_element : std::false_type {};
51 template<typename T, std::size_t N>
52 struct has_tuple_element<T, N, true> : bool_constant<(N < std::tuple_size<T>::value)> {};
53 
54 template<typename T, std::size_t N,
55  bool = std::is_reference<T>::value,
56  bool = has_typename_type<std::tuple_element<N, T>>::value>
57 struct returnable_element : std::false_type {};
58 template<typename T, std::size_t N, bool v>
59 struct returnable_element<T, N, true, v> : std::true_type {};
60 template<typename T, std::size_t N>
61 struct returnable_element<T, N, false, true>
62  : move_constructible<std::tuple_element_t<N, T>> {};
63 
64 // Not defined, if Base does not model forward_range
65 template<typename Base, std::size_t N, bool = forward_range<Base>::value /* false */>
66 struct elements_view_iterator_category {
67 #if __cplusplus < 202002L
68  using iterator_category = iterator_ignore;
69 #endif
70 };
71 
72 template<typename Base, std::size_t N>
73 struct elements_view_iterator_category<Base, N, true> {
74  private:
75  using C = typename cxx20_iterator_traits<iterator_t<Base>>::iterator_category;
76 
77  public:
78  using iterator_category =
79  std::conditional_t<
80  std::is_rvalue_reference<decltype(std::get<N>(*std::declval<iterator_t<Base>&>()))>::value, input_iterator_tag,
81  std::conditional_t<
82  derived_from<C, random_access_iterator_tag>::value, random_access_iterator_tag,
83  C
84  >>;
85 };
86 
87 } // namespace detail
88 
91 
92 template<typename V, std::size_t N>
93 class elements_view : public view_interface<elements_view<V, N>> {
94  public:
95  static_assert(input_range<V>::value, "Constraints not satisfied");
96  static_assert(view<V>::value, "Constraints not satisfied");
97  static_assert(detail::has_tuple_element<range_value_t<V>, N>::value, "Constraints not satisfied");
98  static_assert(detail::has_tuple_element<std::remove_reference_t<range_reference_t<V>>, N>::value, "Constraints not satisfied");
99  static_assert(detail::returnable_element<range_reference_t<V>, N>::value, "Constraints not satisfied");
100 
101  template<bool> class iterator;
102  template<bool> class sentinel;
103 
104  template<bool Const>
105  class iterator : public detail::elements_view_iterator_category<std::conditional_t<Const, const V, V>, N> {
106  using Base = maybe_const<Const, V>;
107  template<bool> friend class sentinel;
108 
109  template<typename Ref, bool = std::is_reference<Ref>::value /* true */>
110  struct iterator_reference {
111  using type = decltype(std::get<N>(*std::declval<iterator_t<Base>&>()));
112  };
113  template<typename Ref>
114  struct iterator_reference<Ref, false> {
115  using type = std::remove_cv_t<std::tuple_element_t<N, Ref>>;
116  };
117 
118  public:
119  using iterator_concept =
120  std::conditional_t<
121  random_access_range<Base>::value, random_access_iterator_tag,
122  std::conditional_t<
123  bidirectional_range<Base>::value, bidirectional_iterator_tag,
124  std::conditional_t<
125  forward_range<Base>::value, forward_iterator_tag,
126  input_iterator_tag
127  >>>;
128  using value_type = remove_cvref_t<std::tuple_element_t<N, range_value_t<Base>>>;
129  using difference_type = range_difference_t<Base>;
130 #if __cplusplus < 202002L
131  using pointer = void;
132  using reference = typename iterator_reference<range_reference_t<Base>>::type;
133 #endif
134 
135  iterator() = default;
136 
137  constexpr explicit iterator(iterator_t<Base> current)
138  : current_(std::move(current)) {}
139 
140  template<bool AntiConst, std::enable_if_t<conjunction<
141  bool_constant<((Const != AntiConst) && Const)>,
142  convertible_to<iterator_t<V>, iterator_t<Base>>
143  >::value, int> = 0>
144  constexpr iterator(iterator<AntiConst> i)
145  : current_(std::move(i.current_)) {}
146 
147  constexpr const iterator_t<Base>& base() const& noexcept {
148  return current_;
149  }
150 
151  constexpr iterator_t<Base> base() && {
152  return std::move(current_);
153  }
154 
155  constexpr decltype(auto) operator*() const {
156  return get_element(this->base(), std::is_reference<range_reference_t<Base>>{});
157  }
158 
159  template<typename B = Base, std::enable_if_t<random_access_range<B>::value, int> = 0>
160  constexpr decltype(auto) operator[](difference_type n) const {
161  return get_element(this->base() + n, std::is_reference<range_reference_t<Base>>{});
162  }
163 
164  constexpr iterator& operator++() {
165  ++current_;
166  return *this;
167  }
168 
169  template<typename B = Base, std::enable_if_t<forward_range<B>::value == false, int> = 0>
170  constexpr void operator++(int) {
171  ++current_;
172  }
173 
174  template<typename B = Base, std::enable_if_t<forward_range<B>::value, int> = 0>
175  constexpr iterator operator++(int) {
176  auto tmp = *this;
177  ++*this;
178  return tmp;
179  }
180 
181  template<typename B = Base, std::enable_if_t<bidirectional_range<B>::value, int> = 0>
182  constexpr iterator& operator--() {
183  --current_;
184  return *this;
185  }
186 
187  template<typename B = Base, std::enable_if_t<bidirectional_range<B>::value, int> = 0>
188  constexpr iterator operator--(int) {
189  auto tmp = *this;
190  --*this;
191  return tmp;
192  }
193 
194  template<typename B = Base, std::enable_if_t<random_access_range<B>::value, int> = 0>
195  constexpr iterator& operator+=(difference_type n) {
196  current_ += n;
197  return *this;
198  }
199 
200  template<typename B = Base, std::enable_if_t<random_access_range<B>::value, int> = 0>
201  constexpr iterator& operator-=(difference_type n) {
202  current_ -= n;
203  return *this;
204  }
205 
206  template<typename B = Base, std::enable_if_t<equality_comparable<iterator_t<B>>::value, int> = 0>
207  friend constexpr bool operator==(const iterator& x, const iterator& y) {
208  return x.current_ == y.current_;
209  }
210 
211  template<typename B = Base, std::enable_if_t<equality_comparable<iterator_t<B>>::value, int> = 0>
212  friend constexpr bool operator!=(const iterator& x, const iterator& y) {
213  return !(x == y);
214  }
215 
216  template<typename B = Base, std::enable_if_t<random_access_range<B>::value, int> = 0>
217  friend constexpr bool operator<(const iterator& x, const iterator& y) {
218  return x.current_ < y.current_;
219  }
220 
221  template<typename B = Base, std::enable_if_t<random_access_range<B>::value, int> = 0>
222  friend constexpr bool operator>(const iterator& x, const iterator& y) {
223  return y < x;
224  }
225 
226  template<typename B = Base, std::enable_if_t<random_access_range<B>::value, int> = 0>
227  friend constexpr bool operator<=(const iterator& x, const iterator& y) {
228  return !(y < x);
229  }
230 
231  template<typename B = Base, std::enable_if_t<random_access_range<B>::value, int> = 0>
232  friend constexpr bool operator>=(const iterator& x, const iterator& y) {
233  return !(x < y);
234  }
235 
236  template<typename B = Base, std::enable_if_t<random_access_range<B>::value, int> = 0>
237  friend constexpr iterator operator+(iterator i, difference_type n) {
238  return [&](){ auto j = i; j += n; return j; }();
239  }
240 
241  template<typename B = Base, std::enable_if_t<random_access_range<B>::value, int> = 0>
242  friend constexpr iterator operator+(difference_type n, iterator i) {
243  return [&](){ auto j = i; j += n; return j; }();
244  }
245 
246  template<typename B = Base, std::enable_if_t<random_access_range<B>::value, int> = 0>
247  friend constexpr iterator operator-(iterator i, difference_type n) {
248  return [&](){ auto j = i; j -= n; return j; }();
249  }
250 
251  template<typename B = Base, std::enable_if_t<sized_sentinel_for<iterator_t<B>, iterator_t<B>>::value, int> = 0>
252  friend constexpr difference_type operator-(const iterator& x, const iterator& y) {
253  return x.current_ - y.current_;
254  }
255 
256  private:
257  template<typename T>
258  constexpr decltype(auto) get_element(T&& e, std::true_type /* reference */) const {
259  return std::get<N>(*std::forward<T>(e));
260  }
261 
262  template<typename T>
263  constexpr decltype(auto) get_element(T&& e, std::false_type /* reference */) const {
264  using E = std::remove_cv_t<std::tuple_element_t<N, range_reference_t<Base>>>;
265  return static_cast<E>(std::get<N>(*std::forward<T>(e)));
266  }
267 
268  iterator_t<Base> current_;
269  };
270 
271  template<bool Const>
272  class sentinel {
273  using Base = maybe_const<Const, V>;
274 
275  public:
276  sentinel() = default;
277 
278  constexpr explicit sentinel(sentinel_t<Base> end)
279  : end_(std::move(end)) {}
280 
281  template<bool AntiConst, std::enable_if_t<conjunction<
282  bool_constant<((Const != AntiConst) && Const)>,
283  convertible_to<sentinel_t<V>, sentinel_t<Base>>
284  >::value, int> = 0>
285  constexpr sentinel(sentinel<AntiConst> i)
286  : end_(std::move(i.end_)) {}
287 
288  constexpr sentinel_t<Base> base() const {
289  return end_;
290  }
291 
292  template<bool OtherConst, std::enable_if_t<
293  sentinel_for<
294  sentinel_t<Base>,
295  iterator_t<maybe_const<OtherConst, V>>
296  >::value, int> = 0>
297  friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y) {
298  using namespace vccc::rel_ops;
299  return x.base() == y.end_;
300  }
301 
302  template<bool OtherConst, std::enable_if_t<
303  sentinel_for<
304  sentinel_t<Base>,
305  iterator_t<maybe_const<OtherConst, V>>
306  >::value, int> = 0>
307  friend constexpr bool operator!=(const iterator<OtherConst>& x, const sentinel& y) {
308  return !(x == y);
309  }
310 
311  template<bool OtherConst, std::enable_if_t<
312  sentinel_for<
313  sentinel_t<Base>,
314  iterator_t<maybe_const<OtherConst, V>>
315  >::value, int> = 0>
316  friend constexpr bool operator==(const sentinel& y, const iterator<OtherConst>& x) {
317  return x == y;
318  }
319 
320  template<bool OtherConst, std::enable_if_t<
321  sentinel_for<
322  sentinel_t<Base>,
323  iterator_t<maybe_const<OtherConst, V>>
324  >::value, int> = 0>
325  friend constexpr bool operator!=(const sentinel& y, const iterator<OtherConst>& x) {
326  return !(x == y);
327  }
328 
329  template<bool OtherConst, std::enable_if_t<
330  sized_sentinel_for<
331  sentinel_t<Base>,
332  iterator_t<maybe_const<OtherConst, V>>
333  >::value, int> = 0>
334  friend constexpr range_difference_t<maybe_const<OtherConst, V>>
335  operator-(const iterator<OtherConst>& x, const sentinel& y) {
336  return x.base() - y.end_;
337  }
338 
339  template<bool OtherConst, std::enable_if_t<
340  sized_sentinel_for<
341  sentinel_t<Base>,
342  iterator_t<maybe_const<OtherConst, V>>
343  >::value, int> = 0>
344  friend constexpr range_difference_t<maybe_const<OtherConst, V>>
345  operator-(const sentinel& y, const iterator<OtherConst>& x) {
346  return y.end_ - x.base();
347  }
348 
349 
350  private:
351  sentinel_t<Base> end_;
352  };
353 
354  elements_view() = default;
355 
356  constexpr explicit elements_view(V base)
357  : base_(std::move(base)) {}
358 
359  template<typename V2 = V, std::enable_if_t<copy_constructible<V2>::value, int> = 0>
360  constexpr V base() const& {
361  return base_;
362  }
363 
364  constexpr V base() && {
365  return std::move(base_);
366  }
367 
368  template<typename V2 = V, std::enable_if_t<simple_view<V2>::value == false, int> = 0>
369  constexpr auto begin() {
370  return iterator<false>{ranges::begin(base_)};
371  }
372 
373  template<typename V2 = V, std::enable_if_t<range<const V2>::value, int> = 0>
374  constexpr auto begin() const {
375  return iterator<true>{ranges::begin(base_)};
376  }
377 
378  template<typename V2 = V, std::enable_if_t<conjunction<
379  negation< simple_view<V2> >,
380  negation< common_range<V2> >
381  >::value, int> = 0>
382  constexpr auto end() {
383  return sentinel<false>{ranges::end(base_)};
384  }
385 
386  template<typename V2 = V, std::enable_if_t<conjunction<
387  negation< simple_view<V2> >,
388  common_range<V2>
389  >::value, int> = 0>
390  constexpr auto end() {
391  return iterator<false>{ranges::end(base_)};
392  }
393 
394  template<typename V2 = V, std::enable_if_t<conjunction<
395  range<const V2>,
396  negation< common_range<const V2> >
397  >::value, int> = 0>
398  constexpr auto end() const {
399  return sentinel<true>{ranges::end(base_)};
400  }
401 
402  template<typename V2 = V, std::enable_if_t<conjunction<
403  common_range<const V2>
404  >::value, int> = 0>
405  constexpr auto end() const {
406  return iterator<true>{ranges::end(base_)};
407  }
408 
409  template<typename V2 = V, std::enable_if_t<sized_range<V2>::value, int> = 0>
410  constexpr auto size() {
411  return ranges::size(base_);
412  }
413 
414  template<typename V2 = V, std::enable_if_t<sized_range<const V2>::value, int> = 0>
415  constexpr auto size() const {
416  return ranges::size(base_);
417  }
418 
419  private:
420  V base_;
421 };
422 
423 template<typename V, std::size_t N>
424 struct enable_borrowed_range<elements_view<V, N>> : enable_borrowed_range<V> {};
425 
427 
428 } // namespace ranges
429 } // namespace vccc
430 
431 #endif // VCCC_RANGES_VIEWS_ELEMENTS_VIEW_HPP
std::integral_constant< bool, v > bool_constant
Definition: bool_constant.hpp:19
Definition: directory.h:12
constexpr VCCC_INLINE_OR_STATIC detail::element_niebloid< 1 > value
Definition: key_value.hpp:35