VCCC  2024.05
VisualCamp Common C++ library
advance.hpp
Go to the documentation of this file.
1 //
2 // Created by cosge on 2023-12-25.
3 //
4 
5 #ifndef VCCC_ITERATOR_ADVANCE_HPP_
6 #define VCCC_ITERATOR_ADVANCE_HPP_
7 
8 #include <type_traits>
9 
10 #include "vccc/core.hpp"
21 
22 namespace vccc {
23 namespace ranges {
24 namespace detail {
25 
26 struct advance_niebloid;
27 using vccc::detail::conditional_tag;
28 using vccc::detail::tag_1;
29 using vccc::detail::tag_2;
30 using vccc::detail::tag_3;
31 using vccc::detail::tag_else;
32 
33 template<typename I>
34 using advance_n_tag = conditional_tag<random_access_iterator<I>, bidirectional_iterator<I>>;
35 
36 template<typename I>
37 constexpr void advance_n(I& i, iter_difference_t<I> n, tag_1 /* random_access_iterator */) {
38  i += n;
39 }
40 
41 template<typename I>
42 constexpr void advance_n(I& i, iter_difference_t<I> n, tag_2 /* bidirectional_iterator */) {
43  while (n > 0) {
44  --n;
45  ++i;
46  }
47 
48  while (n < 0) {
49  ++n;
50  --i;
51  }
52 }
53 
54 template<typename I>
55 constexpr void advance_n(I& i, iter_difference_t<I> n, tag_else) {
56  while (n > 0) {
57  --n;
58  ++i;
59  }
60 }
61 
62 template<typename I, typename S>
63 struct advance_bound_check_impl : conjunction<input_or_output_iterator<I>, sentinel_for<S, I>> {};
64 
65 template<typename I, typename S, bool = has_typename_type<iter_difference<I>>::value /* true */>
66 struct advance_bound_check : conjunction< negation<std::is_same<iter_difference_t<I>, S>>,
67  advance_bound_check_impl<I, S> > {};
68 template<typename I, typename S>
69 struct advance_bound_check<I, S, false> : advance_bound_check_impl<I, S> {};
70 
71 template<typename I, typename S>
72 using advance_bound_tag = conditional_tag<assignable_from<I&, S>, sized_sentinel_for<S, I>>;
73 
74 template<typename I, typename S>
75 constexpr void advance_bound(I& i, S bound, tag_1 /* assignable_from */) {
76  i = std::move(bound);
77 }
78 
79 template<typename I, typename S>
80 constexpr void advance_bound(I& i, S bound, tag_2 /* sized_sentinel_for */);
81 
82 template<typename I, typename S>
83 constexpr void advance_bound(I& i, S bound, tag_else) {
84  while (i != bound)
85  ++i;
86 }
87 
88 
89 template<typename I, typename S>
90 using advance_mixed_tag = conditional_tag<sized_sentinel_for<S, I>, bidirectional_iterator<I>>;
91 
92 template<typename I, typename S>
93 constexpr iter_difference_t<I>
94 advance_mixed(I& i, iter_difference_t<I> n, S bound, tag_1 /* sized_sentinel_for */);
95 
96 template<typename I, typename S>
97 constexpr iter_difference_t<I>
98 advance_mixed(I& i, iter_difference_t<I> n, S bound, tag_2 /* bidirectional_iterator */) {
99  while (n > 0 && i != bound) {
100  --n;
101  ++i;
102  }
103 
104  while (n < 0 && i != bound) {
105  ++n;
106  --i;
107  }
108 
109  return n;
110 }
111 
112 template<typename I, typename S>
113 constexpr iter_difference_t<I>
114 advance_mixed(I& i, iter_difference_t<I> n, S bound, tag_else) {
115  while (n > 0 && i != bound) {
116  --n;
117  ++i;
118  }
119 
120  return n;
121 }
122 
123 struct advance_niebloid {
124  template<typename I>
126  operator()(I& i, iter_difference_t<I> n) const {
127  advance_n(i, n, advance_n_tag<I>{});
128  }
129 
130 
131  // Subsumes above
132  template<typename I, typename S>
134  operator()(I& i, S bound) const {
135  advance_bound(i, bound, advance_bound_tag<I, S>{});
136  }
137 
138 
139  template<typename I, typename S, std::enable_if_t<conjunction<
140  input_or_output_iterator<I>,
141  sentinel_for<S, I>
142  >::value, int> = 0>
143  constexpr iter_difference_t<I>
144  operator()(I& i, iter_difference_t<I> n, S bound) const {
145  return advance_mixed(i, n, bound, advance_mixed_tag<I, S>{});
146  }
147 };
148 } // namespace detail
149 
150 namespace niebloid {
151 
157 
158 VCCC_INLINE_OR_STATIC constexpr detail::advance_niebloid advance{};
159 
162 
163 } // namespace niebloid
164 using namespace niebloid;
165 
166 namespace detail {
167 
168 template<typename I, typename S>
169 constexpr void advance_bound(I& i, S bound, tag_2 /* sized_sentinel_for */) {
170  ranges::advance(i, bound - i);
171 }
172 
173 template<typename I, typename S>
174 constexpr iter_difference_t<I>
175 advance_mixed(I& i, iter_difference_t<I> n, S bound, tag_1 /* sized_sentinel_for */) {
176  const iter_difference_t<I> d = bound - i;
177  if ((n < 0 && n <= d) || (n > 0 && n >= d)) {
178  ranges::advance(i, d);
179  return n - d;
180  }
181 
182  ranges::advance(i, n);
183  return 0;
184 }
185 
186 } // namespace detail
187 } // namespace ranges
188 } // namespace vccc
189 
190 #endif // VCCC_ITERATOR_ADVANCE_HPP_
constexpr VCCC_INLINE_OR_STATIC detail::advance_niebloid advance
Definition: advance.hpp:158
#define VCCC_INLINE_OR_STATIC
Definition: inline_or_static.hpp:9
Definition: directory.h:12
constexpr VCCC_INLINE_OR_STATIC detail::element_niebloid< 1 > value
Definition: key_value.hpp:35