/// \file // Range v3 library // // Copyright Eric Niebler 2013-present // Copyright Casey Carter 2017 // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/range-v3 // #ifndef RANGES_V3_VIEW_SUBRANGE_HPP #define RANGES_V3_VIEW_SUBRANGE_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \addtogroup group-views /// @{ enum class subrange_kind : bool { unsized, sized }; /// \cond namespace detail { // clang-format off /// \concept convertible_to_not_slicing_ /// \brief The \c convertible_to_not_slicing_ concept template CPP_concept convertible_to_not_slicing_ = convertible_to && // A conversion is a slicing conversion if the source and the destination // are both pointers, and if the pointed-to types differ after removing // cv qualifiers. (!(std::is_pointer>::value && std::is_pointer>::value && not_same_as_>, std::remove_pointer_t>>)); template using tuple_element_fun_t = void (*)(meta::_t> const &); /// \concept pair_like_impl_ /// \brief The \c pair_like_impl_ concept template CPP_requires(pair_like_impl_, // requires(T t, tuple_element_fun_t<0, T> p0, tuple_element_fun_t<1, T> p1) // ( p0( get<0>(t) ), p1( get<1>(t) ) )); /// \concept pair_like_impl_ /// \brief The \c pair_like_impl_ concept template CPP_concept pair_like_impl_ = CPP_requires_ref(detail::pair_like_impl_, T); /// \concept is_complete_ /// \brief The \c is_complete_ concept template(typename T)( concept (is_complete_)(T), 0 != sizeof(T)); /// \concept is_complete_ /// \brief The \c is_complete_ concept template CPP_concept is_complete_ = // CPP_concept_ref(is_complete_, T); template(typename T)( // concept (pair_like_)(T), // is_complete_> AND derived_from, meta::size_t<2>> AND detail::pair_like_impl_); /// \concept pair_like /// \brief The \c pair_like concept template CPP_concept pair_like = // CPP_concept_ref(detail::pair_like_, T); // clang-format off template(typename T, typename U, typename V)( // concept (pair_like_convertible_from_helper_)(T, U, V), // convertible_to_not_slicing_>> AND convertible_to>>); /// \concept pair_like_convertible_from_helper_ /// \brief The \c pair_like_convertible_from_helper_ concept template CPP_concept pair_like_convertible_from_helper_ = // CPP_concept_ref(pair_like_convertible_from_helper_, T, U, V); template(typename T, typename U, typename V)( // concept (pair_like_convertible_from_impl_)(T, U, V), (!range) AND constructible_from AND pair_like> AND pair_like_convertible_from_helper_); /// \concept pair_like_convertible_from_ /// \brief The \c pair_like_convertible_from_ concept template CPP_concept pair_like_convertible_from_ = CPP_concept_ref(detail::pair_like_convertible_from_impl_, T, U, V); /// \concept range_convertible_to_impl_ /// \brief The \c range_convertible_to_impl_ concept template(typename R, typename I, typename S)( concept (range_convertible_to_impl_)(R, I, S), convertible_to_not_slicing_, I> AND convertible_to, S>); /// \concept range_convertible_to_ /// \brief The \c range_convertible_to_ concept template CPP_concept range_convertible_to_ = borrowed_range && CPP_concept_ref(detail::range_convertible_to_impl_, R, I, S); // clang-format on template(typename S, typename I)( requires sentinel_for) constexpr bool is_sized_sentinel_() noexcept { return (bool)sized_sentinel_for; } template constexpr bool store_size_() noexcept { return K == subrange_kind::sized && !(bool)sized_sentinel_for; } } // namespace detail /// \endcond template< // typename I, // typename S = I, // subrange_kind K = static_cast(detail::is_sized_sentinel_())> struct subrange; template RANGES_INLINE_VAR constexpr bool enable_borrowed_range> = true; /// \cond namespace _subrange_ { struct adl_hook {}; template(std::size_t N, typename I, typename S, subrange_kind K)( requires (N == 0)) // constexpr I get(subrange const & r) { return r.begin(); } template(std::size_t N, typename I, typename S, subrange_kind K)( requires (N == 1)) // constexpr S get(subrange const & r) { return r.end(); } } // namespace _subrange_ /// \endcond template struct subrange : view_interface, same_as ? infinite : K == subrange_kind::sized ? finite : unknown> , private _subrange_::adl_hook { CPP_assert(input_or_output_iterator); CPP_assert(sentinel_for); CPP_assert(K == subrange_kind::sized || !sized_sentinel_for); CPP_assert(K != subrange_kind::sized || !same_as); using size_type = detail::iter_size_t; using iterator = I; using sentinel = S; subrange() = default; template(typename I2)( requires detail::convertible_to_not_slicing_ AND (!detail::store_size_())) // constexpr subrange(I2 && i, S s) : data_{static_cast(i), std::move(s)} {} template(typename I2)( requires detail::convertible_to_not_slicing_ AND (detail::store_size_())) // constexpr subrange(I2 && i, S s, size_type n) : data_{static_cast(i), std::move(s), n} { if(RANGES_CONSTEXPR_IF((bool)random_access_iterator)) { using D = iter_difference_t; RANGES_EXPECT(n <= (size_type)std::numeric_limits::max()); RANGES_EXPECT(ranges::next(first_(), (D)n) == last_()); } } template(typename I2)( requires detail::convertible_to_not_slicing_ AND sized_sentinel_for) constexpr subrange(I2 && i, S s, size_type n) : data_{static_cast(i), std::move(s)} { RANGES_EXPECT(static_cast(last_() - first_()) == n); } template(typename R)( requires (!same_as, subrange>) AND detail::range_convertible_to_ AND (!detail::store_size_())) constexpr subrange(R && r) : subrange{ranges::begin(r), ranges::end(r)} {} template(typename R)( requires (!same_as, subrange>) AND detail::range_convertible_to_ AND (detail::store_size_()) AND sized_range) constexpr subrange(R && r) : subrange{ranges::begin(r), ranges::end(r), ranges::size(r)} {} template(typename R)( requires (K == subrange_kind::sized) AND detail::range_convertible_to_) constexpr subrange(R && r, size_type n) // : subrange{ranges::begin(r), ranges::end(r), n} { if(RANGES_CONSTEXPR_IF((bool)sized_range)) { RANGES_EXPECT(n == ranges::size(r)); } } template(typename PairLike)( requires (!same_as) AND detail::pair_like_convertible_from_) constexpr operator PairLike() const { return PairLike(first_(), last_()); } constexpr I begin() const noexcept(std::is_nothrow_copy_constructible::value) { return first_(); } constexpr S end() const noexcept(std::is_nothrow_copy_constructible::value) { return last_(); } constexpr bool empty() const { return first_() == last_(); } CPP_member constexpr auto size() const // -> CPP_ret(size_type)( requires (K == subrange_kind::sized)) { return get_size_(); } RANGES_NODISCARD constexpr subrange next(iter_difference_t n = 1) const { auto tmp = *this; tmp.advance(n); return tmp; } CPP_member RANGES_NODISCARD constexpr auto prev(iter_difference_t n = 1) const -> CPP_ret(subrange)( requires bidirectional_iterator) { auto tmp = *this; tmp.advance(-n); return tmp; } constexpr subrange & advance(iter_difference_t n) { set_size_(get_size_() - static_cast(n - ranges::advance(first_(), n, last_()))); return *this; } private: using data_t = meta::conditional_t< // detail::store_size_(), // std::tuple, // std::tuple>; data_t data_; constexpr I & first_() noexcept { return std::get<0>(data_); } constexpr const I & first_() const noexcept { return std::get<0>(data_); } constexpr S & last_() noexcept { return std::get<1>(data_); } constexpr const S & last_() const noexcept { return std::get<1>(data_); } CPP_member constexpr auto get_size_() const // -> CPP_ret(size_type)( requires sized_sentinel_for) { return static_cast(last_() - first_()); } CPP_member constexpr auto get_size_() const noexcept // -> CPP_ret(size_type)( requires (detail::store_size_())) { return std::get<2>(data_); } static constexpr void set_size_(...) noexcept {} CPP_member constexpr auto set_size_(size_type n) noexcept // -> CPP_ret(void)( requires (detail::store_size_())) { std::get<2>(data_) = n; } }; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 template subrange(I, S) // -> subrange; template(typename I, typename S)( requires input_or_output_iterator AND sentinel_for) subrange(I, S, detail::iter_size_t) -> subrange; template(typename R)( requires borrowed_range) subrange(R &&) // -> subrange, sentinel_t, (sized_range || sized_sentinel_for, iterator_t>) ? subrange_kind::sized : subrange_kind::unsized>; template(typename R)( requires borrowed_range) subrange(R &&, detail::iter_size_t>) -> subrange, sentinel_t, subrange_kind::sized>; #endif // in lieu of deduction guides, use make_subrange struct make_subrange_fn { template constexpr subrange operator()(I i, S s) const { return {i, s}; } template(typename I, typename S)( requires input_or_output_iterator AND sentinel_for) constexpr subrange // operator()(I i, S s, detail::iter_size_t n) const { return {i, s, n}; } template(typename R)( requires borrowed_range) constexpr auto operator()(R && r) const -> subrange, sentinel_t, (sized_range || sized_sentinel_for, iterator_t>) ? subrange_kind::sized : subrange_kind::unsized> { return {(R &&) r}; } template(typename R)( requires borrowed_range) constexpr subrange, sentinel_t, subrange_kind::sized> // operator()(R && r, detail::iter_size_t> n) const { return {(R &&) r, n}; } }; /// \relates make_subrange_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(make_subrange_fn, make_subrange) template using borrowed_subrange_t = detail::maybe_dangling_>>; template using safe_subrange_t RANGES_DEPRECATED("Use borrowed_subrange_t instead.") = borrowed_subrange_t; namespace cpp20 { using ranges::subrange_kind; template(typename I, // typename S = I, // subrange_kind K = // static_cast( // detail::is_sized_sentinel_()))( requires input_or_output_iterator AND sentinel_for AND (K == subrange_kind::sized || !sized_sentinel_for)) // using subrange = ranges::subrange; using ranges::borrowed_subrange_t; template using safe_subrange_t RANGES_DEPRECATED("Use borrowed_subrange_t instead.") = borrowed_subrange_t; } // namespace cpp20 /// @} } // namespace ranges RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS namespace std { template struct tuple_size<::ranges::subrange> : std::integral_constant {}; template struct tuple_element<0, ::ranges::subrange> { using type = I; }; template struct tuple_element<1, ::ranges::subrange> { using type = S; }; } // namespace std RANGES_DIAGNOSTIC_POP #include #endif