VCCC  2024.05
VisualCamp Common C++ library
cartesian_product_view.hpp
Go to the documentation of this file.
1 //
2 // Created by yonggyulee on 2024/01/27.
3 //
4 
5 #ifndef VCCC_RANGES_VIEWS_CARTESIAN_PRODUCT_VIEW_HPP
6 #define VCCC_RANGES_VIEWS_CARTESIAN_PRODUCT_VIEW_HPP
7 
8 #include <limits>
9 #include <memory>
10 #include <tuple>
11 #include <utility>
12 
21 #include "vccc/__ranges/begin.hpp"
26 #include "vccc/__ranges/end.hpp"
33 #include "vccc/__ranges/view.hpp"
41 
42 namespace vccc {
43 namespace ranges {
44 namespace detail {
45 
46 template<bool Const, typename First, typename... Vs>
47 struct cartesian_product_is_random_access
48  : conjunction<
49  random_access_range<maybe_const<Const, First>>,
50  random_access_range<maybe_const<Const, Vs>>...,
51  sized_range<maybe_const<Const, Vs>>...
52  > {};
53 
54 template<typename R>
55 struct cartesian_product_common_arg
56  : disjunction<
57  common_range<R>,
58  conjunction< sized_range<R>, random_access_range<R> >
59  > {};
60 
61 template<bool Const, typename First, typename... Vs>
62 struct cartesian_product_is_bidirectional
63  : conjunction<
64  bidirectional_range<maybe_const<Const, First>>,
65  bidirectional_range<maybe_const<Const, Vs>>...,
66  cartesian_product_common_arg<maybe_const<Const, Vs>>...
67  > {};
68 
69 template<typename First, typename... Vs>
70 struct cartesian_product_is_common : cartesian_product_common_arg<First> {};
71 
72 template<typename... Vs>
73 struct cartesian_product_is_sized : conjunction<sized_range<Vs>...> {};
74 
75 template< bool Const, template<typename> class FirstSent, typename First, typename... Vs>
76 struct cartesian_is_sized_sentinel
77  : conjunction<
78  sized_sentinel_for<
79  FirstSent<maybe_const<Const, First>>,
80  iterator_t<maybe_const<Const, First>>>,
81  sized_range<maybe_const<Const, Vs>>...,
82  sized_sentinel_for<
83  iterator_t<maybe_const<Const, Vs>>,
84  iterator_t<maybe_const<Const, Vs>>>...
85  > {};
86 
87 template<typename R>
88 constexpr auto cartesian_common_arg_end_impl(R& r, std::true_type /* common_range */) {
89  return ranges::end(r);
90 }
91 template<typename R>
92 constexpr auto cartesian_common_arg_end_impl(R& r, std::false_type /* common_range */) {
93  return ranges::begin(r) + ranges::distance(r);
94 }
95 
97 constexpr auto cartesian_common_arg_end(R& r) {
98  return vccc::ranges::detail::cartesian_common_arg_end_impl(r, common_range<R>{});
99 }
100 
101 template<typename R, typename F, typename Tuple, std::size_t... I>
102 constexpr R cartesian_tuple_transform_impl(F func, Tuple&& t, std::index_sequence<I...>)
103  noexcept(
104  conjunction<bool_constant<
105  noexcept(func(std::get<I>( std::forward<Tuple>(t) )))
106  >...>::value
107  )
108 {
109  return R(func(std::get<I>( std::forward<Tuple>(t) ))...);
110 }
111 
112 template<typename R, typename F, typename Tuple>
113 constexpr R cartesian_tuple_transform(F func, Tuple&& t)
114  noexcept(noexcept(
115  cartesian_tuple_transform_impl<R>(
116  func,
117  std::forward<Tuple>(t),
118  std::make_index_sequence<std::tuple_size<remove_cvref_t<Tuple>>::value>{})
119  ))
120 {
121  return cartesian_tuple_transform_impl<R>(
122  func,
123  std::forward<Tuple>(t),
124  std::make_index_sequence<std::tuple_size<remove_cvref_t<Tuple>>::value>{});
125 }
126 
127 template<typename F, typename Tuple, std::size_t... I>
128 constexpr auto cartesian_tuple_transform_impl(F func, Tuple&& t, std::index_sequence<I...>) {
129  return std::make_tuple(
130  func(
131  std::get<I>( std::forward<Tuple>(t) )
132  )...
133  );
134 }
135 
136 template<typename F, typename Tuple>
137 constexpr auto cartesian_tuple_transform(F func, Tuple&& t) {
138  return cartesian_tuple_transform_impl(
139  func,
140  std::forward<Tuple>(t),
141  std::make_index_sequence<std::tuple_size<remove_cvref_t<Tuple>>::value>{});
142 }
143 
144 template<typename Tuple, typename Indices>
145 struct cartesian_product_is_empty_impl;
146 
147 template<typename Tuple, std::size_t... I>
148 struct cartesian_product_is_empty_impl<Tuple, std::index_sequence<0, I...>>
149  : disjunction<
150 
151  > {};
152 
154 struct cartesian_product_is_empty : cartesian_product_is_empty_impl<Tuple, std::make_index_sequence<N>> {};
155 
156 template<typename Tuple> struct cartesian_product_is_empty<Tuple, 1> : std::false_type {};
157 template<typename Tuple> struct cartesian_product_is_empty<Tuple, 0>; // unreachable
158 
159 template<typename F, typename Tuple, std::size_t... I>
160 constexpr auto cartesian_tuple_transform_end(F func, const Tuple& t, std::index_sequence<0, I...>) {
161  return std::make_tuple(func(std::get<I>(t))...);
162 }
163 
164 } // namespace detail
165 
168 
169 template<typename First, typename... Vs>
170 class cartesian_product_view : public view_interface<cartesian_product_view<First, Vs...>> {
171  std::tuple<First, Vs...> bases_;
172  template<bool Const>
173  using iterator_current = std::tuple<
176 
177  public:
178  static_assert(input_range<First>::value, "Constraints not satisfied");
179  static_assert(conjunction<forward_range<Vs>...>::value, "Constraints not satisfied");
180  static_assert(view<First>::value, "Constraints not satisfied");
181  static_assert(conjunction<view<Vs>...>::value, "Constraints not satisfied");
182 
183  template<bool Const> class iterator;
184  template<bool Const> friend class iterator;
185 
186  template<bool Const>
187  class iterator {
190 
191  public:
194  std::conditional_t<
195  detail::cartesian_product_is_random_access<Const, First, Vs...>::value, random_access_iterator_tag,
196  std::conditional_t<
197  detail::cartesian_product_is_bidirectional<Const, First, Vs...>::value, bidirectional_iterator_tag,
198  std::conditional_t<
201  >>>;
202  using value_type = std::tuple<
205  using reference = std::tuple<
208  using difference_type = int;
209 #if __cplusplus < 202002L
210  using pointer = void;
211 #endif
212 
213  iterator() = default;
214 
215  template<bool AntiConst, std::enable_if_t<conjunction<
216  bool_constant<((Const != AntiConst) && Const)>,
219  >::value, int> = 0>
221  : parent_(i.parent_), current_(std::move(i.current_)) {}
222 
223  constexpr auto operator*() const {
224  return detail::cartesian_tuple_transform(
225  [](auto& i) -> decltype(auto) { return *i; }, current_);
226  }
227 
228  template<typename First2 = First, std::enable_if_t<
229  detail::cartesian_product_is_random_access<Const, First2, Vs...>::value, int> = 0>
230  constexpr reference operator[](difference_type n) const {
231  return *((*this) + n);
232  }
233 
234  template<std::size_t N = sizeof...(Vs)>
235  constexpr void next() {
236  auto& it = std::get<N>(current_);
237  ++it;
238  next(it, std::integral_constant<std::size_t, N>{});
239  }
240 
241  template<std::size_t N = sizeof...(Vs)>
242  constexpr void prev() {
243  auto& it = std::get<N>(current_);
244  prev(it, std::integral_constant<std::size_t, N>{});
245  --it;
246  }
247 
248  template<typename Tuple>
249  constexpr difference_type distance_from(const Tuple& t) const {
250  return scaled_sum(t);
251  }
252 
253  constexpr iterator& operator++() {
254  next();
255  return *this;
256  }
257 
258  template<typename First2 = First, std::enable_if_t<
260  constexpr void operator++(int) {
261  ++*this;
262  }
263 
264  template<typename First2 = First, std::enable_if_t<
266  constexpr iterator operator++(int) {
267  auto tmp = *this;
268  ++*this;
269  return tmp;
270  }
271 
272  template<typename First2 = First, std::enable_if_t<
273  detail::cartesian_product_is_bidirectional<Const, First2, Vs...>::value, int> = 0>
274  constexpr iterator& operator--() {
275  prev();
276  return *this;
277  }
278 
279  template<typename First2 = First, std::enable_if_t<
280  detail::cartesian_product_is_bidirectional<Const, First2, Vs...>::value, int> = 0>
281  constexpr iterator operator--(int) {
282  auto tmp = *this;
283  --*this;
284  return tmp;
285  }
286 
287  template<typename First2 = First, std::enable_if_t<
288  detail::cartesian_product_is_random_access<Const, First2, Vs...>::value, int> = 0>
290  if (n > 0) {
291  while (n) {
292  next();
293  --n;
294  }
295  } else if (n < 0) {
296  while (n < 0) {
297  prev();
298  ++n;
299  }
300  }
301  return *this;
302  }
303 
304  template<typename First2 = First, std::enable_if_t<
305  detail::cartesian_product_is_random_access<Const, First2, Vs...>::value, int> = 0>
307  *this += -n;
308  return *this;
309  }
310 
311  template<typename First2 = First, std::enable_if_t<
313  friend constexpr bool operator==(const iterator& x, const iterator& y) {
314  return x.current_ == y.current_;
315  }
316 
317  template<typename First2 = First, std::enable_if_t<
319  friend constexpr bool operator!=(const iterator& x, const iterator& y) {
320  return !(x == y);
321  }
322 
323  template<typename First2 = First, std::enable_if_t<
325  friend constexpr bool operator==(const iterator& x, default_sentinel_t) {
326  return x.compare_with_default();
327  }
328 
329  template<typename First2 = First, std::enable_if_t<
331  friend constexpr bool operator!=(const iterator& x, default_sentinel_t) {
332  return !x.compare_with_default();
333  }
334 
335  template<typename First2 = First, std::enable_if_t<
337  friend constexpr bool operator==(default_sentinel_t, const iterator& x) {
338  return x.compare_with_default();
339  }
340 
341  template<typename First2 = First, std::enable_if_t<
343  friend constexpr bool operator!=(default_sentinel_t, const iterator& x) {
344  return !x.compare_with_default();
345  }
346 
347  template<typename First2 = First, std::enable_if_t<
348  detail::cartesian_product_is_random_access<Const, First2, Vs...>::value, int> = 0>
349  friend constexpr iterator operator+(const iterator& i, difference_type n) {
350  return iterator(i) += n;
351  }
352 
353  template<typename First2 = First, std::enable_if_t<
354  detail::cartesian_product_is_random_access<Const, First2, Vs...>::value, int> = 0>
355  friend constexpr iterator operator+(difference_type n, const iterator& i) {
356  return i + n;
357  }
358 
359  template<typename First2 = First, std::enable_if_t<
360  detail::cartesian_product_is_random_access<Const, First2, Vs...>::value, int> = 0>
361  friend constexpr iterator operator-(const iterator& i, difference_type n) {
362  return iterator(i) -= n;
363  }
364 
365  template<typename First2 = First, std::enable_if_t<
366  detail::cartesian_is_sized_sentinel<Const, iterator_t, First2, Vs...>::value, int> = 0>
367  friend constexpr difference_type operator-(const iterator& i, const iterator& j) {
368  return i.distance_from(j.current_);
369  }
370 
371  template<typename First2 = First, std::enable_if_t<
372  detail::cartesian_is_sized_sentinel<Const, sentinel_t, First2, Vs...>::value, int> = 0>
373  friend constexpr difference_type operator-(const iterator& i, default_sentinel_t) {
374  return i.distance_from_default();
375  }
376 
377  template<typename First2 = First, std::enable_if_t<
378  detail::cartesian_is_sized_sentinel<Const, sentinel_t, First2, Vs...>::value, int> = 0>
379  friend constexpr difference_type operator-(default_sentinel_t s, const iterator& i) {
380  return -(i - s);
381  }
382 
383  friend constexpr auto iter_move(const iterator& i)
384  noexcept(
385  noexcept(vccc::tuple_transform(i.current_, ranges::iter_move)) &&
386  conjunction<
387  std::is_nothrow_move_constructible<range_rvalue_reference_t< maybe_const<Const, First> >>,
388  std::is_nothrow_move_constructible<range_rvalue_reference_t< maybe_const<Const, Vs> >>...
389  >::value
390  )
391  {
392  return vccc::tuple_transform(i.current_, ranges::iter_move);
393  }
394 
395  template<typename Dummy = void, std::enable_if_t<conjunction<std::is_void<Dummy>,
396  indirectly_swappable< iterator_t<maybe_const<Const, First>> >,
397  indirectly_swappable< iterator_t<maybe_const<Const, Vs>> >...
398  >::value, int> = 0>
399  friend constexpr void iter_swap(const iterator& x, const iterator& y)
400  noexcept(noexcept(x.iter_swap_impl(y)))
401  {
402  x.iter_swap_impl(y);
403  }
404 
405  private:
406  template<typename It>
407  constexpr void next(It&, std::integral_constant<std::size_t, 0>) {}
408  template<typename It, std::size_t N>
409  constexpr void next(It& it, std::integral_constant<std::size_t, N>) {
410  if (it == ranges::end(std::get<N>(parent_->bases_))) {
411  it = ranges::begin(std::get<N>(parent_->bases_));
412  next<N - 1>();
413  }
414  }
415 
416  template<typename It>
417  constexpr void prev(It&, std::integral_constant<std::size_t, 0>) {}
418  template<typename It, std::size_t N>
419  constexpr void prev(It& it, std::integral_constant<std::size_t, N>) {
420  if (it == ranges::begin(std::get<N>(parent_->bases_))) {
421  it = detail::cartesian_common_arg_end(std::get<N>(parent_->bases_));
422  prev<N - 1>();
423  }
424  }
425 
426  template<typename Tuple>
427  constexpr difference_type scaled_size(const Tuple& t, std::integral_constant<std::size_t, 0>) const {
428  // f = 0
429  return static_cast<difference_type>(std::get<0>(current_) - std::get<0>(t));
430  }
431  template<typename Tuple, std::size_t N>
432  constexpr difference_type scaled_size(const Tuple& t, std::integral_constant<std::size_t, N>) const {
433  auto f = static_cast<difference_type>(ranges::size(std::get<N>(parent_->bases_)));
434  auto g = static_cast<difference_type>(std::get<N>(current_) - std::get<N>(t));
435  return g + f * scaled_size(t, std::integral_constant<std::size_t, N - 1>{});
436  }
437 
438  template<typename Tuple>
439  constexpr difference_type scaled_sum(const Tuple& t) const {
440  return scaled_size(t, std::integral_constant<std::size_t, sizeof...(Vs)>{});
441  }
442 
443  template<std::size_t... I>
444  constexpr difference_type distance_from_default_impl(std::index_sequence<0, I...>) const {
445  return distance_from(std::make_tuple(
446  ranges::end(std::get<0>(parent_->bases_)),
447  ranges::begin(std::get<I>(parent_->bases_))...));
448  }
449 
450  constexpr difference_type distance_from_default() const {
451  return distance_from_default_impl(std::index_sequence_for<Vs...>{});
452  }
453 
454  constexpr bool compare_with_default_impl(std::integral_constant<std::size_t, 0>) const {
455  return std::get<0>(current_) == ranges::end(std::get<0>(parent_->bases_));
456  }
457 
458  template<std::size_t I>
459  constexpr bool compare_with_default_impl(std::integral_constant<std::size_t, I>) const {
460  return std::get<I>(current_) == ranges::end(std::get<I>(parent_->bases_))
461  ? true
462  : compare_with_default(std::integral_constant<std::size_t, I - 1>{});
463  }
464 
465  constexpr bool compare_with_default() const {
466  return compare_with_default_impl(std::index_sequence_for<Vs...>{});
467  }
468 
469  template<std::size_t... I>
470  constexpr void iter_swap_impl(const iterator& other, std::index_sequence<I...>) const
471  noexcept(
472  conjunction<bool_constant<
473  noexcept(ranges::iter_swap(std::get<I>(this->current_), std::get<I>(other.current_)))
474  >...>::value
475  )
476  {
477  int dummy[] = {
478  (ranges::iter_swap(std::get<I>(current_), std::get<I>(other.current_)), 0)...
479  };
480  (void)dummy;
481  }
482 
483  constexpr iterator(Parent& parent, iterator_current<Const> current)
484  : parent_(vccc::addressof(parent)), current_(std::move(current)) {}
485 
486  Parent* parent_ = nullptr;
487  iterator_current<Const> current_;
488  };
489 
490  constexpr cartesian_product_view() = default;
491 
492  constexpr cartesian_product_view(First first, Vs... bases)
493  : bases_(std::move(first), std::move(bases)...) {}
494 
495  template<typename First2 = First, std::enable_if_t<disjunction<
498  >::value, int> = 0>
499  constexpr iterator<false> begin() {
500  return iterator<false>(
501  *this, detail::cartesian_tuple_transform<iterator_current<true>>(ranges::begin, bases_));
502  }
503 
504  template<typename First2 = First, std::enable_if_t<conjunction<
506  range<const Vs>...
507  >::value, int> = 0>
508  constexpr iterator<true> begin() const {
509  return iterator<true>(
510  *this, detail::cartesian_tuple_transform<iterator_current<true>>(ranges::begin, bases_));
511  }
512 
513  template<typename First2 = First, std::enable_if_t<conjunction<
514  disjunction<
517  detail::cartesian_product_is_common<First, Vs...>
518  >::value, int> = 0>
519  constexpr iterator<false> end() {
520  return iterator<false>(*this, tuple_transform_end<false>(bases_));
521  }
522 
523  template<typename First2 = First, std::enable_if_t<
524  detail::cartesian_product_is_common<const First2, const Vs...>::value, int> = 0>
525  constexpr iterator<true> end() const {
526  return iterator<true>(*this, tuple_transform_end<true>(bases_));
527  }
528 
529  template<typename First2 = First, std::enable_if_t<
530  detail::cartesian_product_is_common<const First2, const Vs...>::value == false, int> = 0>
531  constexpr default_sentinel_t end() const {
532  return default_sentinel;
533  }
534 
535  template<typename First2 = First, std::enable_if_t<
536  detail::cartesian_product_is_sized<First2, Vs...>::value, int> = 0>
537  constexpr std::size_t size() {
538  return size_impl(std::index_sequence_for<First, Vs...>{});
539  }
540 
541  template<typename First2 = First, std::enable_if_t<
542  detail::cartesian_product_is_sized<const First2, const Vs...>::value, int> = 0>
543  constexpr std::size_t size() const {
544  return size_impl(std::index_sequence_for<First, Vs...>{});
545  }
546 
547  private:
548  template<std::size_t N>
549  constexpr bool is_empty_impl(std::integral_constant<std::size_t, N>) const {
550  return ranges::empty(std::get<N>(bases_)) ? true : is_empty_impl(std::integral_constant<std::size_t, N - 1>{});
551  }
552  constexpr bool is_empty_impl(std::integral_constant<std::size_t, 0>) const {
553  return false;
554  }
555  constexpr bool is_empty() const {
556  return is_empty_impl(std::integral_constant<std::size_t, sizeof...(Vs)>{});
557  }
558 
559  template<bool Const, typename Tuple, std::size_t... I>
560  constexpr iterator_current<Const> tuple_transform_end_impl(Tuple&& t, std::index_sequence<0, I...>) {
561  return iterator_current<Const>(
562  is_empty() ?
563  ranges::begin( std::get<0>(std::forward<Tuple>(t)) ) :
564  detail::cartesian_common_arg_end( std::get<0>(std::forward<Tuple>(t)) ),
565  ranges::begin(std::get<I>(std::forward<Tuple>(t)))...
566  );
567  }
568 
569  template<bool Const, typename Tuple>
570  constexpr iterator_current<Const> tuple_transform_end(Tuple&& t) {
571  return tuple_transform_end_impl<Const>(
572  std::forward<Tuple>(t),
573  std::make_index_sequence<std::tuple_size<remove_cvref_t<Tuple>>::value>{});
574  }
575 
576  template<bool Const, typename Tuple, std::size_t... I>
577  constexpr iterator_current<Const> tuple_transform_end_impl(Tuple&& t, std::index_sequence<0, I...>) const {
578  return iterator_current<Const>(
579  is_empty() ?
580  ranges::begin( std::get<0>(std::forward<Tuple>(t)) ) :
581  detail::cartesian_common_arg_end( std::get<0>(std::forward<Tuple>(t)) ),
582  ranges::begin(std::get<I>(std::forward<Tuple>(t)))...
583  );
584  }
585 
586  template<bool Const, typename Tuple>
587  constexpr iterator_current<Const> tuple_transform_end(Tuple&& t) const {
588  return tuple_transform_end_impl<Const>(
589  std::forward<Tuple>(t),
590  std::make_index_sequence<std::tuple_size<remove_cvref_t<Tuple>>::value>{});
591  }
592 
593  template<std::size_t... I>
594  constexpr std::size_t size_impl(std::index_sequence<I...>) {
595  std::size_t prod = 1;
596  int dummy[] = {
597  ((void)(prod *= static_cast<std::size_t>(ranges::size(std::get<I>(bases_)))), 0)...
598  };
599  (void)dummy;
600  return prod;
601  }
602 
603  template<std::size_t... I>
604  constexpr std::size_t size_impl(std::index_sequence<I...>) const {
605  std::size_t prod = 1;
606  int dummy[] = {
607  ((void)(prod *= static_cast<std::size_t>(ranges::size(std::get<I>(bases_)))), 0)...
608  };
609  (void)dummy;
610  return prod;
611  }
612 };
613 
614 #if __cplusplus >= 201703L
615 
616 template<typename... Rs>
617 cartesian_product_view(Rs&&...) -> cartesian_product_view<views::all_t<Rs>...>;
618 
619 #endif
620 
622 
623 } // namespace ranges
624 } // namespace vccc
625 
626 #endif // VCCC_RANGES_VIEWS_CARTESIAN_PRODUCT_VIEW_HPP
Definition: cartesian_product_view.hpp:187
constexpr friend auto iter_move(const iterator &i) noexcept(noexcept(vccc::tuple_transform(i.current_, ranges::iter_move)) &&conjunction< std::is_nothrow_move_constructible< range_rvalue_reference_t< maybe_const< Const, First > >>, std::is_nothrow_move_constructible< range_rvalue_reference_t< maybe_const< Const, Vs > >>... >::value)
Definition: cartesian_product_view.hpp:383
constexpr iterator & operator--()
Definition: cartesian_product_view.hpp:274
int difference_type
Definition: cartesian_product_view.hpp:208
constexpr friend iterator operator+(const iterator &i, difference_type n)
Definition: cartesian_product_view.hpp:349
constexpr friend iterator operator-(const iterator &i, difference_type n)
Definition: cartesian_product_view.hpp:361
void pointer
Definition: cartesian_product_view.hpp:210
constexpr friend bool operator==(const iterator &x, default_sentinel_t)
Definition: cartesian_product_view.hpp:325
constexpr difference_type distance_from(const Tuple &t) const
Definition: cartesian_product_view.hpp:249
constexpr void operator++(int)
Definition: cartesian_product_view.hpp:260
constexpr iterator(iterator< AntiConst > i)
Definition: cartesian_product_view.hpp:220
constexpr void prev()
Definition: cartesian_product_view.hpp:242
std::tuple< range_reference_t< maybe_const< Const, First > >, range_reference_t< maybe_const< Const, Vs > >... > reference
Definition: cartesian_product_view.hpp:207
constexpr friend bool operator==(const iterator &x, const iterator &y)
Definition: cartesian_product_view.hpp:313
constexpr friend bool operator==(default_sentinel_t, const iterator &x)
Definition: cartesian_product_view.hpp:337
constexpr friend bool operator!=(const iterator &x, const iterator &y)
Definition: cartesian_product_view.hpp:319
constexpr auto operator*() const
Definition: cartesian_product_view.hpp:223
constexpr iterator & operator-=(difference_type n)
Definition: cartesian_product_view.hpp:306
constexpr friend difference_type operator-(default_sentinel_t s, const iterator &i)
Definition: cartesian_product_view.hpp:379
constexpr iterator & operator+=(difference_type n)
Definition: cartesian_product_view.hpp:289
input_iterator_tag iterator_category
Definition: cartesian_product_view.hpp:192
constexpr iterator operator--(int)
Definition: cartesian_product_view.hpp:281
constexpr void next()
Definition: cartesian_product_view.hpp:235
constexpr friend iterator operator+(difference_type n, const iterator &i)
Definition: cartesian_product_view.hpp:355
constexpr friend bool operator!=(default_sentinel_t, const iterator &x)
Definition: cartesian_product_view.hpp:343
constexpr reference operator[](difference_type n) const
Definition: cartesian_product_view.hpp:230
constexpr friend difference_type operator-(const iterator &i, default_sentinel_t)
Definition: cartesian_product_view.hpp:373
constexpr iterator operator++(int)
Definition: cartesian_product_view.hpp:266
constexpr friend bool operator!=(const iterator &x, default_sentinel_t)
Definition: cartesian_product_view.hpp:331
constexpr friend difference_type operator-(const iterator &i, const iterator &j)
Definition: cartesian_product_view.hpp:367
constexpr friend void iter_swap(const iterator &x, const iterator &y) noexcept(noexcept(x.iter_swap_impl(y)))
Definition: cartesian_product_view.hpp:399
constexpr iterator & operator++()
Definition: cartesian_product_view.hpp:253
std::tuple< range_value_t< maybe_const< Const, First > >, range_value_t< maybe_const< Const, Vs > >... > value_type
Definition: cartesian_product_view.hpp:204
std::conditional_t< detail::cartesian_product_is_random_access< Const, First, Vs... >::value, random_access_iterator_tag, std::conditional_t< detail::cartesian_product_is_bidirectional< Const, First, Vs... >::value, bidirectional_iterator_tag, std::conditional_t< forward_range< maybe_const< Const, First > >::value, forward_iterator_tag, input_iterator_tag > >> iterator_concept
Definition: cartesian_product_view.hpp:201
Definition: cartesian_product_view.hpp:170
constexpr default_sentinel_t end() const
Definition: cartesian_product_view.hpp:531
constexpr cartesian_product_view()=default
constexpr cartesian_product_view(First first, Vs... bases)
Definition: cartesian_product_view.hpp:492
constexpr std::size_t size() const
Definition: cartesian_product_view.hpp:543
constexpr std::size_t size()
Definition: cartesian_product_view.hpp:537
constexpr iterator< false > end()
Definition: cartesian_product_view.hpp:519
constexpr iterator< true > begin() const
Definition: cartesian_product_view.hpp:508
constexpr iterator< true > end() const
Definition: cartesian_product_view.hpp:525
constexpr iterator< false > begin()
Definition: cartesian_product_view.hpp:499
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::random_access_iterator_tag random_access_iterator_tag
Definition: iterator_tag.hpp:19
constexpr VCCC_INLINE_OR_STATIC default_sentinel_t default_sentinel
Definition: default_sentinel_t.hpp:25
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
constexpr VCCC_INLINE_OR_STATIC detail::empty_niebloid empty
checks whether a range is empty
Definition: empty.hpp:116
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
typename range_rvalue_reference< R >::type range_rvalue_reference_t
Used to obtain the rvalue reference type of the iterator type of range type R.
Definition: range_rvalue_reference_t.hpp:38
constexpr VCCC_INLINE_OR_STATIC detail::distance_niebloid distance
Definition: distance.hpp:72
constexpr VCCC_INLINE_OR_STATIC detail::size_niebloid size
returns the size of a container or array
Definition: size.hpp:145
constexpr VCCC_INLINE_OR_STATIC detail::end_niebloid end
returns a sentinel indicating the end of a range
Definition: end.hpp:120
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
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
std::conditional_t< Const, const V, V > maybe_const
Definition: maybe_const.hpp:16
Definition: matrix.hpp:495
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
Definition: conjunction.hpp:22
Models std::convertible_to
Definition: convertible_to.hpp:38
Definition: default_sentinel_t.hpp:23
Definition: disjunction.hpp:22
specifies that operator == is an equivalence relation
Definition: equality_comparable.hpp:30
Definition: negation.hpp:23
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 type is a range, that is, it provides a begin iterator and an end sentinel
Definition: range.hpp:53
specifies that a range is a view, that is, it has constant time copy/move/assignment
Definition: view.hpp:31