File indexing completed on 2025-01-18 10:09:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef RANGES_V3_VIEW_SUBRANGE_HPP
0016 #define RANGES_V3_VIEW_SUBRANGE_HPP
0017
0018 #include <tuple>
0019 #include <type_traits>
0020 #include <utility>
0021
0022 #include <meta/meta.hpp>
0023
0024 #include <concepts/concepts.hpp>
0025
0026 #include <range/v3/iterator/operations.hpp>
0027 #include <range/v3/iterator/unreachable_sentinel.hpp>
0028 #include <range/v3/range/access.hpp>
0029 #include <range/v3/range/concepts.hpp>
0030 #include <range/v3/range/dangling.hpp>
0031 #include <range/v3/utility/get.hpp>
0032 #include <range/v3/view/interface.hpp>
0033
0034 #include <range/v3/detail/prologue.hpp>
0035
0036 namespace ranges
0037 {
0038
0039
0040 enum class subrange_kind : bool
0041 {
0042 unsized,
0043 sized
0044 };
0045
0046
0047 namespace detail
0048 {
0049
0050
0051
0052 template<typename From, typename To>
0053 CPP_concept convertible_to_not_slicing_ =
0054 convertible_to<From, To> &&
0055
0056
0057
0058 (!(std::is_pointer<decay_t<From>>::value &&
0059 std::is_pointer<decay_t<To>>::value &&
0060 not_same_as_<std::remove_pointer_t<decay_t<From>>,
0061 std::remove_pointer_t<decay_t<To>>>));
0062
0063 template<std::size_t N, typename T>
0064 using tuple_element_fun_t = void (*)(meta::_t<std::tuple_element<N, T>> const &);
0065
0066
0067
0068 template<typename T>
0069 CPP_requires(pair_like_impl_,
0070 requires(T t, tuple_element_fun_t<0, T> p0, tuple_element_fun_t<1, T> p1)
0071 (
0072 p0( get<0>(t) ),
0073 p1( get<1>(t) )
0074 ));
0075
0076
0077 template<typename T>
0078 CPP_concept pair_like_impl_ = CPP_requires_ref(detail::pair_like_impl_, T);
0079
0080
0081
0082 template(typename T)(
0083 concept (is_complete_)(T),
0084 0 != sizeof(T));
0085
0086
0087
0088 template<typename T>
0089 CPP_concept is_complete_ =
0090 CPP_concept_ref(is_complete_, T);
0091
0092 template(typename T)(
0093 concept (pair_like_)(T),
0094 is_complete_<std::tuple_size<T>> AND
0095 derived_from<std::tuple_size<T>, meta::size_t<2>> AND
0096 detail::pair_like_impl_<T>);
0097
0098
0099
0100 template<typename T>
0101 CPP_concept pair_like =
0102 CPP_concept_ref(detail::pair_like_, T);
0103
0104
0105 template(typename T, typename U, typename V)(
0106 concept (pair_like_convertible_from_helper_)(T, U, V),
0107 convertible_to_not_slicing_<U, meta::_t<std::tuple_element<0, T>>> AND
0108 convertible_to<V, meta::_t<std::tuple_element<1, T>>>);
0109
0110
0111
0112 template<typename T, typename U, typename V>
0113 CPP_concept pair_like_convertible_from_helper_ =
0114 CPP_concept_ref(pair_like_convertible_from_helper_, T, U, V);
0115
0116 template(typename T, typename U, typename V)(
0117 concept (pair_like_convertible_from_impl_)(T, U, V),
0118 (!range<T>) AND
0119 constructible_from<T, U, V> AND
0120 pair_like<uncvref_t<T>> AND
0121 pair_like_convertible_from_helper_<T, U, V>);
0122
0123
0124
0125 template<typename T, typename U, typename V>
0126 CPP_concept pair_like_convertible_from_ =
0127 CPP_concept_ref(detail::pair_like_convertible_from_impl_, T, U, V);
0128
0129
0130
0131 template(typename R, typename I, typename S)(
0132 concept (range_convertible_to_impl_)(R, I, S),
0133 convertible_to_not_slicing_<iterator_t<R>, I> AND
0134 convertible_to<sentinel_t<R>, S>);
0135
0136
0137
0138 template<typename R, typename I, typename S>
0139 CPP_concept range_convertible_to_ =
0140 borrowed_range<R> &&
0141 CPP_concept_ref(detail::range_convertible_to_impl_, R, I, S);
0142
0143
0144 template(typename S, typename I)(
0145 requires sentinel_for<S, I>)
0146 constexpr bool is_sized_sentinel_() noexcept
0147 {
0148 return (bool)sized_sentinel_for<S, I>;
0149 }
0150
0151 template<subrange_kind K, typename S, typename I>
0152 constexpr bool store_size_() noexcept
0153 {
0154 return K == subrange_kind::sized && !(bool)sized_sentinel_for<S, I>;
0155 }
0156 }
0157
0158
0159 template<
0160 typename I,
0161 typename S = I,
0162 subrange_kind K = static_cast<subrange_kind>(detail::is_sized_sentinel_<S, I>())>
0163 struct subrange;
0164
0165 template<typename I, typename S, subrange_kind K>
0166 RANGES_INLINE_VAR constexpr bool enable_borrowed_range<subrange<I, S, K>> = true;
0167
0168
0169 namespace _subrange_
0170 {
0171 struct adl_hook
0172 {};
0173
0174 template(std::size_t N, typename I, typename S, subrange_kind K)(
0175 requires (N == 0))
0176 constexpr I get(subrange<I, S, K> const & r)
0177 {
0178 return r.begin();
0179 }
0180 template(std::size_t N, typename I, typename S, subrange_kind K)(
0181 requires (N == 1))
0182 constexpr S get(subrange<I, S, K> const & r)
0183 {
0184 return r.end();
0185 }
0186 }
0187
0188
0189 template<typename I, typename S, subrange_kind K>
0190 struct subrange
0191 : view_interface<subrange<I, S, K>,
0192 same_as<S, unreachable_sentinel_t>
0193 ? infinite
0194 : K == subrange_kind::sized ? finite : unknown>
0195 , private _subrange_::adl_hook
0196 {
0197 CPP_assert(input_or_output_iterator<I>);
0198 CPP_assert(sentinel_for<S, I>);
0199 CPP_assert(K == subrange_kind::sized || !sized_sentinel_for<S, I>);
0200 CPP_assert(K != subrange_kind::sized || !same_as<S, unreachable_sentinel_t>);
0201
0202 using size_type = detail::iter_size_t<I>;
0203 using iterator = I;
0204 using sentinel = S;
0205
0206 subrange() = default;
0207
0208 template(typename I2)(
0209 requires detail::convertible_to_not_slicing_<I2, I> AND
0210 (!detail::store_size_<K, S, I>()))
0211 constexpr subrange(I2 && i, S s)
0212 : data_{static_cast<I2 &&>(i), std::move(s)}
0213 {}
0214
0215 template(typename I2)(
0216 requires detail::convertible_to_not_slicing_<I2, I> AND
0217 (detail::store_size_<K, S, I>()))
0218 constexpr subrange(I2 && i, S s, size_type n)
0219 : data_{static_cast<I2 &&>(i), std::move(s), n}
0220 {
0221 if(RANGES_CONSTEXPR_IF((bool)random_access_iterator<I>))
0222 {
0223 using D = iter_difference_t<I>;
0224 RANGES_EXPECT(n <= (size_type)std::numeric_limits<D>::max());
0225 RANGES_EXPECT(ranges::next(first_(), (D)n) == last_());
0226 }
0227 }
0228 template(typename I2)(
0229 requires detail::convertible_to_not_slicing_<I2, I> AND
0230 sized_sentinel_for<S, I>)
0231 constexpr subrange(I2 && i, S s, size_type n)
0232 : data_{static_cast<I2 &&>(i), std::move(s)}
0233 {
0234 RANGES_EXPECT(static_cast<size_type>(last_() - first_()) == n);
0235 }
0236
0237 template(typename R)(
0238 requires (!same_as<detail::decay_t<R>, subrange>) AND
0239 detail::range_convertible_to_<R, I, S> AND
0240 (!detail::store_size_<K, S, I>()))
0241 constexpr subrange(R && r)
0242 : subrange{ranges::begin(r), ranges::end(r)}
0243 {}
0244
0245 template(typename R)(
0246 requires (!same_as<detail::decay_t<R>, subrange>) AND
0247 detail::range_convertible_to_<R, I, S> AND
0248 (detail::store_size_<K, S, I>()) AND
0249 sized_range<R>)
0250 constexpr subrange(R && r)
0251 : subrange{ranges::begin(r), ranges::end(r), ranges::size(r)}
0252 {}
0253
0254 template(typename R)(
0255 requires (K == subrange_kind::sized) AND
0256 detail::range_convertible_to_<R, I, S>)
0257 constexpr subrange(R && r, size_type n)
0258 : subrange{ranges::begin(r), ranges::end(r), n}
0259 {
0260 if(RANGES_CONSTEXPR_IF((bool)sized_range<R>))
0261 {
0262 RANGES_EXPECT(n == ranges::size(r));
0263 }
0264 }
0265
0266 template(typename PairLike)(
0267 requires (!same_as<PairLike, subrange>) AND
0268 detail::pair_like_convertible_from_<PairLike, I const &, S const &>)
0269 constexpr operator PairLike() const
0270 {
0271 return PairLike(first_(), last_());
0272 }
0273
0274 constexpr I begin() const noexcept(std::is_nothrow_copy_constructible<I>::value)
0275 {
0276 return first_();
0277 }
0278 constexpr S end() const noexcept(std::is_nothrow_copy_constructible<S>::value)
0279 {
0280 return last_();
0281 }
0282 constexpr bool empty() const
0283 {
0284 return first_() == last_();
0285 }
0286
0287 CPP_member
0288 constexpr auto size() const
0289 -> CPP_ret(size_type)(
0290 requires (K == subrange_kind::sized))
0291 {
0292 return get_size_();
0293 }
0294
0295 RANGES_NODISCARD
0296 constexpr subrange next(iter_difference_t<I> n = 1) const
0297 {
0298 auto tmp = *this;
0299 tmp.advance(n);
0300 return tmp;
0301 }
0302
0303 CPP_member
0304 RANGES_NODISCARD constexpr auto prev(iter_difference_t<I> n = 1) const
0305 -> CPP_ret(subrange)(
0306 requires bidirectional_iterator<I>)
0307 {
0308 auto tmp = *this;
0309 tmp.advance(-n);
0310 return tmp;
0311 }
0312
0313 constexpr subrange & advance(iter_difference_t<I> n)
0314 {
0315 set_size_(get_size_() -
0316 static_cast<size_type>(n - ranges::advance(first_(), n, last_())));
0317 return *this;
0318 }
0319
0320 private:
0321 using data_t =
0322 meta::conditional_t<
0323 detail::store_size_<K, S, I>(),
0324 std::tuple<I, S, size_type>,
0325 std::tuple<I, S>>;
0326 data_t data_;
0327
0328 constexpr I & first_() noexcept
0329 {
0330 return std::get<0>(data_);
0331 }
0332 constexpr const I & first_() const noexcept
0333 {
0334 return std::get<0>(data_);
0335 }
0336 constexpr S & last_() noexcept
0337 {
0338 return std::get<1>(data_);
0339 }
0340 constexpr const S & last_() const noexcept
0341 {
0342 return std::get<1>(data_);
0343 }
0344 CPP_member
0345 constexpr auto get_size_() const
0346 -> CPP_ret(size_type)(
0347 requires sized_sentinel_for<S, I>)
0348 {
0349 return static_cast<size_type>(last_() - first_());
0350 }
0351 CPP_member
0352 constexpr auto get_size_() const noexcept
0353 -> CPP_ret(size_type)(
0354 requires (detail::store_size_<K, S, I>()))
0355 {
0356 return std::get<2>(data_);
0357 }
0358 static constexpr void set_size_(...) noexcept
0359 {}
0360 CPP_member
0361 constexpr auto set_size_(size_type n) noexcept
0362 -> CPP_ret(void)(
0363 requires (detail::store_size_<K, S, I>()))
0364 {
0365 std::get<2>(data_) = n;
0366 }
0367 };
0368
0369 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
0370 template<typename I, typename S>
0371 subrange(I, S)
0372 -> subrange<I, S>;
0373
0374 template(typename I, typename S)(
0375 requires input_or_output_iterator<I> AND sentinel_for<S, I>)
0376 subrange(I, S, detail::iter_size_t<I>)
0377 -> subrange<I, S, subrange_kind::sized>;
0378
0379 template(typename R)(
0380 requires borrowed_range<R>)
0381 subrange(R &&)
0382 -> subrange<iterator_t<R>, sentinel_t<R>,
0383 (sized_range<R> ||
0384 sized_sentinel_for<sentinel_t<R>, iterator_t<R>>)
0385 ? subrange_kind::sized
0386 : subrange_kind::unsized>;
0387
0388 template(typename R)(
0389 requires borrowed_range<R>)
0390 subrange(R &&, detail::iter_size_t<iterator_t<R>>)
0391 -> subrange<iterator_t<R>, sentinel_t<R>, subrange_kind::sized>;
0392 #endif
0393
0394
0395 struct make_subrange_fn
0396 {
0397 template<typename I, typename S>
0398 constexpr subrange<I, S> operator()(I i, S s) const
0399 {
0400 return {i, s};
0401 }
0402 template(typename I, typename S)(
0403 requires input_or_output_iterator<I> AND sentinel_for<S, I>)
0404 constexpr subrange<I, S, subrange_kind::sized>
0405 operator()(I i, S s, detail::iter_size_t<I> n) const
0406 {
0407 return {i, s, n};
0408 }
0409 template(typename R)(
0410 requires borrowed_range<R>)
0411 constexpr auto operator()(R && r) const
0412 -> subrange<iterator_t<R>, sentinel_t<R>,
0413 (sized_range<R> || sized_sentinel_for<sentinel_t<R>, iterator_t<R>>)
0414 ? subrange_kind::sized
0415 : subrange_kind::unsized>
0416 {
0417 return {(R &&) r};
0418 }
0419 template(typename R)(
0420 requires borrowed_range<R>)
0421 constexpr subrange<iterator_t<R>, sentinel_t<R>, subrange_kind::sized>
0422 operator()(R && r, detail::iter_size_t<iterator_t<R>> n) const
0423 {
0424 return {(R &&) r, n};
0425 }
0426 };
0427
0428
0429
0430 RANGES_INLINE_VARIABLE(make_subrange_fn, make_subrange)
0431
0432 template<typename R>
0433 using borrowed_subrange_t = detail::maybe_dangling_<R, subrange<iterator_t<R>>>;
0434
0435 template<typename R>
0436 using safe_subrange_t RANGES_DEPRECATED("Use borrowed_subrange_t instead.") =
0437 borrowed_subrange_t<R>;
0438
0439 namespace cpp20
0440 {
0441 using ranges::subrange_kind;
0442
0443 template(typename I,
0444 typename S = I,
0445 subrange_kind K =
0446 static_cast<subrange_kind>(
0447 detail::is_sized_sentinel_<S, I>()))(
0448 requires input_or_output_iterator<I> AND sentinel_for<S, I> AND
0449 (K == subrange_kind::sized || !sized_sentinel_for<S, I>))
0450 using subrange = ranges::subrange<I, S, K>;
0451
0452 using ranges::borrowed_subrange_t;
0453
0454 template<typename R>
0455 using safe_subrange_t RANGES_DEPRECATED("Use borrowed_subrange_t instead.") =
0456 borrowed_subrange_t<R>;
0457 }
0458
0459 }
0460
0461 RANGES_DIAGNOSTIC_PUSH
0462 RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
0463
0464 namespace std
0465 {
0466 template<typename I, typename S, ::ranges::subrange_kind K>
0467 struct tuple_size<::ranges::subrange<I, S, K>> : std::integral_constant<size_t, 2>
0468 {};
0469 template<typename I, typename S, ::ranges::subrange_kind K>
0470 struct tuple_element<0, ::ranges::subrange<I, S, K>>
0471 {
0472 using type = I;
0473 };
0474 template<typename I, typename S, ::ranges::subrange_kind K>
0475 struct tuple_element<1, ::ranges::subrange<I, S, K>>
0476 {
0477 using type = S;
0478 };
0479 }
0480
0481 RANGES_DIAGNOSTIC_POP
0482
0483 #include <range/v3/detail/epilogue.hpp>
0484
0485 #endif