/// \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 namespace ranges { /// \addtogroup group-views /// @{ enum class subrange_kind : bool { unsized, sized }; /// \cond namespace detail { template using tuple_element_fun_t = void (*)(meta::_t> const &); // clang-format off CPP_def ( template(typename From, typename To) 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_>>, meta::_t>>>)) ); CPP_def ( template(typename T) concept pair_like_gcc_bugs_3_, 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) ) ) ); CPP_def ( template(typename T) concept pair_like_gcc_bugs_2_, derived_from, meta::size_t<2>> && pair_like_gcc_bugs_3_ ); CPP_def ( template(typename T) concept pair_like_gcc_bugs_, ranges::defer::type>> && defer::pair_like_gcc_bugs_2_ ); CPP_def ( template(typename T) concept get_first_and_second_, requires(T &t) ( get<0>(t), get<1>(t) ) ); CPP_def ( template(typename T) concept pair_like_, (!std::is_reference::value) && (defer::get_first_and_second_ && defer::pair_like_gcc_bugs_) ); // clang-format on // Short-circuit the PairLike concept for things known to be pairs: template struct pair_like : meta::bool_> {}; template struct pair_like> : meta::bool_ {}; template struct pair_like> : meta::bool_ {}; // clang-format off CPP_def ( template(typename T, typename U, typename V) concept pair_like_convertible_from_gcc_bugs_, convertible_to_not_slicing_>> && convertible_to>> ); CPP_def ( template(typename T, typename U, typename V) concept pair_like_convertible_from_, (!range) && constructible_from && (ranges::defer::is_true>::value> && defer::pair_like_convertible_from_gcc_bugs_) ); CPP_def ( template(typename R, typename I, typename S) concept range_convertible_to_, forwarding_range_ && convertible_to_not_slicing_, I> && convertible_to, S> ); // clang-format on template constexpr auto is_sized_sentinel_() noexcept -> CPP_ret(bool)( // requires sentinel_for) { return (bool)sized_sentinel_for; } template constexpr bool store_size_() noexcept { return K == subrange_kind::sized && !(bool)sized_sentinel_for; } } // namespace detail /// \endcond template(detail::is_sized_sentinel_())> struct subrange; /// \cond namespace _subrange_ { struct adl_hook {}; // A temporary subrange can be safely passed to ranges::begin and ranges::end. template constexpr I begin(subrange && r) noexcept( std::is_nothrow_copy_constructible::value) { return r.begin(); } template constexpr I begin(subrange const && r) noexcept( std::is_nothrow_copy_constructible::value) { return r.begin(); } template constexpr S end(subrange && r) noexcept( std::is_nothrow_copy_constructible::value) { return r.end(); } template constexpr S end(subrange const && r) noexcept( std::is_nothrow_copy_constructible::value) { return r.end(); } template constexpr auto get(subrange const & r) -> CPP_ret(I)( // requires(N == 0)) { return r.begin(); } template constexpr auto get(subrange const & r) -> CPP_ret(S)( // requires(N == 1)) { 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 constexpr CPP_ctor(subrange)(I2 && i, S s)( // requires detail::convertible_to_not_slicing_ && (!detail::store_size_())) : data_{static_cast(i), std::move(s)} {} template constexpr CPP_ctor(subrange)(I2 && i, S s, size_type n)( // requires detail::convertible_to_not_slicing_ && (detail::store_size_())) : 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 constexpr CPP_ctor(subrange)(I2 && i, S s, size_type n)( // requires detail::convertible_to_not_slicing_ && sized_sentinel_for) : data_{static_cast(i), std::move(s)} { RANGES_EXPECT(static_cast(last_() - first_()) == n); } template constexpr CPP_ctor(subrange)(R && r)( requires defer::not_same_as_ && detail::defer::range_convertible_to_ && defer::is_true()>) : subrange{ranges::begin(r), ranges::end(r)} {} template constexpr CPP_ctor(subrange)(R && r)( requires defer::not_same_as_ && detail::defer::range_convertible_to_ && defer::is_true< detail::store_size_()> && defer::sized_range) : subrange{ranges::begin(r), ranges::end(r), ranges::size(r)} {} template constexpr CPP_ctor(subrange)(R && r, size_type n)( requires detail::range_convertible_to_ && (K == subrange_kind::sized)) : subrange{ranges::begin(r), ranges::end(r), n} { if(RANGES_CONSTEXPR_IF((bool)sized_range)) { RANGES_EXPECT(n == ranges::size(r)); } } /// Implicit conversion to something that looks like a container. CPP_template(typename Container)( // requires detail::convertible_to_container) // constexpr operator Container() const { return ranges::to(*this); } CPP_template(typename PairLike)( // requires defer::not_same_as_ && detail::defer::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: detail::if_then_t(), std::tuple, std::tuple> 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; CPP_template(typename I, typename S)( // requires input_or_output_iterator && sentinel_for) // subrange(I, S, detail::iter_size_t) ->subrange; CPP_template(typename R)( // requires forwarding_range_) // subrange(R &&) ->subrange, sentinel_t, (sized_range || sized_sentinel_for, iterator_t>) ? subrange_kind::sized : subrange_kind::unsized>; CPP_template(typename R)( // requires forwarding_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 auto operator()(I i, S s) const -> subrange { return {i, s}; } template constexpr auto operator()(I i, S s, detail::iter_size_t n) const -> CPP_ret(subrange)( // requires input_or_output_iterator && sentinel_for) { return {i, s, n}; } template constexpr auto operator()(R && r) const -> CPP_ret( subrange, sentinel_t, (sized_range || sized_sentinel_for, iterator_t>) ? subrange_kind::sized : subrange_kind::unsized>)( // requires forwarding_range_) { return {(R &&) r}; } template constexpr auto operator()(R && r, detail::iter_size_t> n) const -> CPP_ret(subrange, sentinel_t, subrange_kind::sized>)( // requires forwarding_range_) { return {(R &&) r, n}; } }; /// \relates make_subrange_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(make_subrange_fn, make_subrange) template using safe_subrange_t = detail::maybe_dangling_>>; namespace cpp20 { using ranges::subrange_kind; CPP_template(typename I, // typename S = I, // subrange_kind K = // static_cast( // detail::is_sized_sentinel_()))( // requires input_or_output_iterator && sentinel_for && // (K == subrange_kind::sized || !sized_sentinel_for)) // using subrange = ranges::subrange; using ranges::safe_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 #endif