VCCC  2024.05
VisualCamp Common C++ library
subrange.hpp
Go to the documentation of this file.
1 //
2 // Created by yonggyulee on 2024/01/04.
3 //
4 
5 #ifndef VCCC_RANGES_SUBRANGE_HPP
6 #define VCCC_RANGES_SUBRANGE_HPP
7 
8 #include <cstddef>
9 #include <tuple>
10 #include <type_traits>
11 #include <utility>
12 
25 #include "vccc/__ranges/begin.hpp"
27 #include "vccc/__ranges/end.hpp"
29 #include "vccc/__ranges/range.hpp"
31 #include "vccc/__ranges/size.hpp"
44 
45 namespace vccc {
46 namespace ranges {
47 namespace detail {
48 
49 template<typename From, typename To>
50 struct convertible_to_non_slicing
51  : conjunction<
52  convertible_to<From, To>,
53  disjunction<
54  disjunction<
55  negation< std::is_pointer<From> >,
56  negation< std::is_pointer<To> >
57  >,
58  std::is_convertible<std::remove_pointer_t<From>(*)[], std::remove_pointer_t<To>(*)[]>
59  >
60  > {};
61 
62 template<typename T, typename U>
63 struct different_from : negation<same_as<std::decay_t<T>, std::decay_t<U>>> {};
64 
66 struct make_unsigned_like {};
67 template<typename T>
68 struct make_unsigned_like<T, true> {
69  using type = std::make_unsigned_t<T>;
70 };
71 template<typename T>
72 using make_unsigned_like_t = typename make_unsigned_like<T>::type;
73 
75 struct pair_like_convertible_from
76  : conjunction<
77  negation< range<T> >,
78  negation< std::is_reference<T> >,
79  constructible_from<T, U, V>,
80  convertible_to_non_slicing<U, std::tuple_element_t<0, T>>,
81  convertible_to<V, std::tuple_element_t<1, T>>
82  > {};
83 
84 template<typename T, typename U, typename V>
85 struct pair_like_convertible_from<T, U, V, false> : std::false_type {};
86 
88 struct borrowed_range_difference {
89  using type = range_difference_t<R>;
90 };
91 template<typename R>
92 struct borrowed_range_difference<R, false> {};
93 template<typename R>
94 using borrowed_range_difference_t = typename borrowed_range_difference<R>::type;
95 
96 template<
97  typename I,
98  typename S = I,
100 >
101 struct is_subrange_constructible
102  : conjunction<
103  input_or_output_iterator<I>,
104  sentinel_for<S, I>,
105  disjunction<
106  bool_constant<(K == subrange_kind::sized)>,
107  negation< sized_sentinel_for<S, I> >
108  >
109  > {};
110 
111 template<typename I, typename S, bool Store /* false */>
112 struct subrange_size {
113  constexpr subrange_size() = default;
114  template<typename U>
115  constexpr subrange_size(in_place_t, U) noexcept {}
116 };
117 
118 template<typename I, typename S>
119 struct subrange_size<I, S, true> {
120  constexpr subrange_size() = default;
121  template<typename U>
122  constexpr subrange_size(in_place_t, U n) : size_(n) {}
123 
124  std::make_unsigned_t<iter_difference_t<I>> size_ = 0;
125 };
126 
128 struct subrange_ctor_range
129  : conjunction<
130  convertible_to_non_slicing<iterator_t<R>, I>,
131  convertible_to<sentinel_t<R>, S>
132  > {};
133 
134 template<typename I, typename S, typename R>
135 struct subrange_ctor_range<I, S, R, false> : std::false_type {};
136 
137 
138 }
139 
142 
143 template<
144  typename I,
145  typename S = I,
147 >
148 class subrange
149  : public view_interface<subrange<I, S, K>>
150  , detail::subrange_size<I, S, (K == subrange_kind::sized && sized_sentinel_for<S, I>::value == false)>
151 {
152  using store_size = bool_constant<(K == subrange_kind::sized && sized_sentinel_for<S, I>::value == false)>;
153  using size_base = detail::subrange_size<I, S, store_size::value>;
154  public:
155  static_assert(input_or_output_iterator<I>::value, "Constraints not satisfied");
156  static_assert(sentinel_for<S, I>::value, "Constraints not satisfied");
157  static_assert(K == subrange_kind::sized || !sized_sentinel_for<S, I>::value, "Constraints not satisfied");
158 
159  subrange() = default;
160 
161  template<typename I2, std::enable_if_t<conjunction<
162  detail::convertible_to_non_slicing<I2, I>,
164  >::value, int> = 0>
165  constexpr subrange(I2 i, S s)
166  : iterator_(std::move(i)), sentinel_(std::move(s)) {}
167 
168  template<typename I2, std::enable_if_t<conjunction<
169  detail::convertible_to_non_slicing<I2, I>,
171  >::value, int> = 0>
172  constexpr subrange(I2 i, S s, detail::make_unsigned_like_t<iter_difference_t<I>> n)
173  : size_base(in_place, n), iterator_(std::move(i)), sentinel_(std::move(s)) {}
174 
175  template<typename R, std::enable_if_t<conjunction<
176  detail::different_from<subrange, R>,
177  detail::subrange_ctor_range<I, S, R>,
178  disjunction<
181  >
182  >::value, int> = 0>
183  constexpr subrange(R&& r)
184  : subrange(r, static_cast<detail::make_unsigned_like_t<iter_difference_t<I>>>(ranges::size(r))) {}
185 
186  template<typename R, std::enable_if_t<conjunction<
187  detail::subrange_ctor_range<I, S, R>,
189  >::value, int> = 0>
190  constexpr subrange(R&& r, detail::make_unsigned_like_t<iter_difference_t<I>> n)
191  : subrange(ranges::begin(r), ranges::end(r), n) {}
192 
193 
194  template<typename PairLike, std::enable_if_t<conjunction<
196  detail::pair_like_convertible_from<PairLike, const I&, const S&>
197  >::value, int> = 0>
198  constexpr operator PairLike() const {
199  return PairLike(iterator_, sentinel_);
200  }
201 
202 
204  constexpr I begin() const {
205  return iterator_;
206  }
207 
209  VCCC_NODISCARD constexpr I begin() {
210  return std::move(iterator_);
211  }
212 
213  constexpr S end() const {
214  return sentinel_;
215  }
216 
217  constexpr bool empty() const {
218  using namespace vccc::rel_ops;
219  return iterator_ == sentinel_;
220  }
221 
222  template<subrange_kind K2 = K, std::enable_if_t<conjunction<
225  >::value, int> = 0>
226  constexpr detail::make_unsigned_like_t<iter_difference_t<I>> size() const {
227  return static_cast<detail::make_unsigned_like_t<iter_difference_t<I>>>(sentinel_ - iterator_);
228  }
229 
230  template<subrange_kind K2 = K, std::enable_if_t<conjunction<
233  >::value, int> = 0>
234  constexpr detail::make_unsigned_like_t<iter_difference_t<I>> size() const {
235  return size_base::size_;
236  }
237 
239  ranges::advance(iterator_, n, sentinel_);
240  return *this;
241  }
242 
245  auto tmp = *this;
246  tmp.advance(-n);
247  return tmp;
248  }
249 
252  auto tmp = *this;
253  tmp.advance(n);
254  return tmp;
255  }
256 
259  advance(n);
260  return std::move(*this);
261  }
262 
263  private:
264  I iterator_;
265  S sentinel_;
266 };
267 
268 // make-function for C++14
269 
270 template<typename I, typename S, std::enable_if_t<conjunction<
273 >::value, int> = 0>
274 constexpr subrange<I, S>
275 make_subrange(I i, S s) {
276  return subrange<I, S>(std::move(i), std::move(s));
277 }
278 
279 template<typename I, typename S, std::enable_if_t<conjunction<
282 >::value, int> = 0>
283 constexpr subrange<I, S, subrange_kind::sized>
284 make_subrange(I i, S s, detail::make_unsigned_like_t<iter_difference_t<I>> n) {
285  return subrange<I, S, subrange_kind::sized>(std::move(i), std::move(s), n);
286 }
287 
289 constexpr subrange<iterator_t<R>, sentinel_t<R>,
291  sized_sentinel_for<sentinel_t<R>, iterator_t<R>>::value) ?
294  return {std::forward<R>(r)};
295 }
296 
298 constexpr subrange<iterator_t<R>, sentinel_t<R>, subrange_kind::sized>
299 make_subrange(R&& r, detail::make_unsigned_like_t<range_difference_t<R>> n) {
300  return {std::forward<R>(r), n};
301 }
302 
303 
304 #if __cplusplus >= 201703L
305 
306 // template<typename R>
307 // subrange(R&&, detail::make_unsigned_like_t<range_difference_t<R>>) ->
308 // subrange<ranges::iterator_t<R>, ranges::sentinel_t<R>, ranges::subrange_kind::sized>;
309 //
310 // template<typename I, typename S> subrange(I, S) -> subrange<I, S>;
311 //
312 // ^^^^^^^^^^ These two are ambiguous without constraints
313 
314 
315 template<typename I, typename S>
316 subrange(I, S, detail::make_unsigned_like_t<iter_difference_t<I>>) ->
317  subrange<I, S, ranges::subrange_kind::sized>;
318 
319 template<typename R>
320 subrange(R&&) ->
321  subrange<ranges::iterator_t<R>, ranges::sentinel_t<R>,
325 
326 #endif
327 
328 namespace detail {
329 
330 template<typename R>
331 struct is_size_storing_subrange;
332 
333 template<typename I, typename S, subrange_kind K>
334 struct is_size_storing_subrange<subrange<I, S, K>>
335  : bool_constant<(K == subrange_kind::sized && sized_sentinel_for<S, I>::value == false)> {};
336 
337 template<std::size_t N>
338 struct get_subrange;
339 
340 template<> struct get_subrange<0> {
341  template<typename I, typename S, subrange_kind K>
342  static constexpr auto get(const subrange<I, S, K>& r) {
343  return r.begin();
344  }
345  template<typename I, typename S, subrange_kind K>
346  static constexpr auto get(subrange<I, S, K>&& r) {
347  return std::move(r.begin());
348  }
349 };
350 
351 template<> struct get_subrange<1> {
352  template<typename I, typename S, subrange_kind K>
353  auto get(const subrange<I, S, K>& r) {
354  return r.end();
355  }
356  template<typename I, typename S, subrange_kind K>
357  auto get(subrange<I, S, K>&& r) {
358  return std::move(r.end());
359  }
360 };
361 
362 template<typename T>
363 struct is_subrange : std::false_type {};
364 template<typename I, typename S, subrange_kind K>
365 struct is_subrange<subrange<I, S, K>> : std::true_type {};
366 
367 } // namespace detail
368 
369 template<std::size_t N, typename I, typename S, subrange_kind K,
370  std::enable_if_t<((N == 0 && copyable<I>::value) || N == 1), int> = 0>
371 constexpr auto get(const subrange<I, S, K>& r) {
373 }
374 
375 template<std::size_t N, typename I, typename S, subrange_kind K,
376  std::enable_if_t<(N < 2), int> = 0>
377 constexpr auto get(subrange<I, S, K>&& r) {
378  return detail::get_subrange<N>::get(std::move(r));
379 }
380 
381 template<typename I, typename S, subrange_kind K>
382 struct enable_borrowed_range<subrange<I, S, K>> : std::true_type {};
383 
385 
386 } // namespace ranges
387 
388 namespace internal {
389 
390 template<typename I, typename S, ranges::subrange_kind K>
391 struct tuple_like_uncvref<ranges::subrange<I, S, K>> : std::true_type {};
392 
393 } // namespace internal
394 
395 } // namespace vccc
396 
397 template<typename I, typename S, vccc::ranges::subrange_kind K>
398 struct std::tuple_size<vccc::ranges::subrange<I, S, K>> : std::integral_constant<std::size_t, 2> {};
399 
400 namespace std {
401 
403 
404 template<typename I, typename S, vccc::ranges::subrange_kind K>
405 struct tuple_element<0, vccc::ranges::subrange<I, S, K>> { using type = I; };
406 template<typename I, typename S, vccc::ranges::subrange_kind K>
407 struct tuple_element<0, const vccc::ranges::subrange<I, S, K>> { using type = I; };
408 template<typename I, typename S, vccc::ranges::subrange_kind K>
409 struct tuple_element<1, vccc::ranges::subrange<I, S, K>> { using type = S; };
410 template<typename I, typename S, vccc::ranges::subrange_kind K>
411 struct tuple_element<1, const vccc::ranges::subrange<I, S, K>> { using type = S; };
412 
413 } // namespace std
414 
415 #endif // VCCC_RANGES_SUBRANGE_HPP
Definition: subrange.hpp:151
constexpr VCCC_NODISCARD subrange_kind next(iter_difference_t< I > n=1) const &
Definition: subrange.hpp:251
constexpr subrange(R &&r)
Definition: subrange.hpp:183
constexpr S end() const
Definition: subrange.hpp:213
constexpr VCCC_NODISCARD subrange_kind prev(iter_difference_t< I > n=1) const
Definition: subrange.hpp:244
constexpr subrange(R &&r, detail::make_unsigned_like_t< iter_difference_t< I >> n)
Definition: subrange.hpp:190
constexpr subrange(I2 i, S s, detail::make_unsigned_like_t< iter_difference_t< I >> n)
Definition: subrange.hpp:172
constexpr VCCC_NODISCARD I begin()
Definition: subrange.hpp:209
constexpr I begin() const
Definition: subrange.hpp:204
constexpr subrange & advance(iter_difference_t< I > n)
Definition: subrange.hpp:238
constexpr detail::make_unsigned_like_t< iter_difference_t< I > > size() const
Definition: subrange.hpp:226
constexpr bool empty() const
Definition: subrange.hpp:217
constexpr VCCC_NODISCARD subrange_kind next(iter_difference_t< I > n=1) &&
Definition: subrange.hpp:258
constexpr subrange(I2 i, S s)
Definition: subrange.hpp:165
helper class template for defining a view, using the curiously recurring template pattern
Definition: view_interface.hpp:78
constexpr VCCC_INLINE_OR_STATIC detail::advance_niebloid advance
Definition: advance.hpp:158
typename iter_difference< T >::type iter_difference_t
Computes the difference type of T
Definition: iter_difference_t.hpp:49
constexpr auto get(subrange< I, S, K > &&r)
Definition: subrange.hpp:377
constexpr auto get(const subrange< I, S, K > &r)
Definition: subrange.hpp:371
subrange_kind
Definition: subrange_kind.hpp:18
typename sentinel< R >::type sentinel_t
Definition: sentinel_t.hpp:29
typename ranges::iterator< T >::type iterator_t
Definition: iterator_t.hpp:32
constexpr subrange< I, S > make_subrange(I i, S s)
Definition: subrange.hpp:275
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
std::integral_constant< bool, v > bool_constant
Definition: bool_constant.hpp:19
constexpr VCCC_INLINE_OR_STATIC in_place_t in_place
Definition: in_place.hpp:47
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
#define VCCC_NODISCARD
Definition: nodiscard.hpp:14
Definition: conjunction.hpp:22
Definition: disjunction.hpp:22
specifies that objects of a type can be incremented and dereferenced
Definition: input_or_output_iterator.hpp:43
Definition: negation.hpp:23
Definition: enable_borrowed_range.hpp:17
specifies that a range knows its size in constant time
Definition: sized_range.hpp:38
Definition: sentinel_for.hpp:24
specifies that the - operator can be applied to an iterator and a sentinel to calculate their differe...
Definition: sized_sentinel_for.hpp:75