Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:09:58

0001 /// \file
0002 // Range v3 library
0003 //
0004 //  Copyright Eric Niebler 2013-present
0005 //  Copyright Casey Carter 2017
0006 //
0007 //  Use, modification and distribution is subject to the
0008 //  Boost Software License, Version 1.0. (See accompanying
0009 //  file LICENSE_1_0.txt or copy at
0010 //  http://www.boost.org/LICENSE_1_0.txt)
0011 //
0012 // Project home: https://github.com/ericniebler/range-v3
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     /// \addtogroup group-views
0039     /// @{
0040     enum class subrange_kind : bool
0041     {
0042         unsized,
0043         sized
0044     };
0045 
0046     /// \cond
0047     namespace detail
0048     {
0049         // clang-format off
0050         /// \concept convertible_to_not_slicing_
0051         /// \brief The \c convertible_to_not_slicing_ concept
0052         template<typename From, typename To>
0053         CPP_concept convertible_to_not_slicing_ =
0054             convertible_to<From, To> &&
0055             // A conversion is a slicing conversion if the source and the destination
0056             // are both pointers, and if the pointed-to types differ after removing
0057             // cv qualifiers.
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         /// \concept pair_like_impl_
0067         /// \brief The \c pair_like_impl_ concept
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         /// \concept pair_like_impl_
0076         /// \brief The \c pair_like_impl_ concept
0077         template<typename T>
0078         CPP_concept pair_like_impl_ = CPP_requires_ref(detail::pair_like_impl_, T);
0079 
0080         /// \concept is_complete_
0081         /// \brief The \c is_complete_ concept
0082         template(typename T)(
0083         concept (is_complete_)(T),
0084             0 != sizeof(T));
0085 
0086         /// \concept is_complete_
0087         /// \brief The \c is_complete_ concept
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         /// \concept pair_like
0099         /// \brief The \c pair_like concept
0100         template<typename T>
0101         CPP_concept pair_like = //
0102             CPP_concept_ref(detail::pair_like_, T);
0103 
0104         // clang-format off
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         /// \concept pair_like_convertible_from_helper_
0111         /// \brief The \c pair_like_convertible_from_helper_ concept
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         /// \concept pair_like_convertible_from_
0124         /// \brief The \c pair_like_convertible_from_ concept
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         /// \concept range_convertible_to_impl_
0130         /// \brief The \c range_convertible_to_impl_ concept
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         /// \concept range_convertible_to_
0137         /// \brief The \c range_convertible_to_ concept
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         // clang-format on
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     } // namespace detail
0157     /// \endcond
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     /// \cond
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     } // namespace _subrange_
0187     /// \endcond
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     // in lieu of deduction guides, use make_subrange
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     /// \relates make_subrange_fn
0429     /// \ingroup group-views
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     } // namespace cpp20
0458     /// @}
0459 } // namespace ranges
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 } // namespace std
0480 
0481 RANGES_DIAGNOSTIC_POP
0482 
0483 #include <range/v3/detail/epilogue.hpp>
0484 
0485 #endif