/// \file // Range v3 library // // Copyright Eric Niebler 2013-present // // 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_ITERATOR_RANGE_HPP #define RANGES_V3_ITERATOR_RANGE_HPP #include <type_traits> #include <utility> #include <meta/meta.hpp> #include <concepts/concepts.hpp> #include <range/v3/range_fwd.hpp> #include <range/v3/iterator/concepts.hpp> #include <range/v3/iterator/operations.hpp> #include <range/v3/iterator/unreachable_sentinel.hpp> #include <range/v3/utility/static_const.hpp> #include <range/v3/view/interface.hpp> RANGES_DEPRECATED_HEADER( "This header is deprecated. Please switch to subrange in " "<range/v3/view/subrange.hpp>.") namespace ranges { /// \addtogroup group-views /// @{ /// \cond namespace _iterator_range_ { struct adl_hook_ {}; // A temporary iterator_range can be safely passed to ranges::begin and // ranges::end. template<class I, class S> constexpr I begin(iterator_range<I, S> && r) noexcept( std::is_nothrow_copy_constructible<I>::value) { return r.begin(); } template<class I, class S> constexpr I begin(iterator_range<I, S> const && r) noexcept( std::is_nothrow_copy_constructible<I>::value) { return r.begin(); } template<class I, class S> constexpr S end(iterator_range<I, S> && r) noexcept( std::is_nothrow_copy_constructible<S>::value) { return r.end(); } template<class I, class S> constexpr S end(iterator_range<I, S> const && r) noexcept( std::is_nothrow_copy_constructible<S>::value) { return r.end(); } // A temporary sized_iterator_range can be safely passed to ranges::begin and // ranges::end. template<class I, class S> constexpr I begin(sized_iterator_range<I, S> && r) noexcept( std::is_nothrow_copy_constructible<I>::value) { return r.begin(); } template<class I, class S> constexpr I begin(sized_iterator_range<I, S> const && r) noexcept( std::is_nothrow_copy_constructible<I>::value) { return r.begin(); } template<class I, class S> constexpr S end(sized_iterator_range<I, S> && r) noexcept( std::is_nothrow_copy_constructible<S>::value) { return r.end(); } template<class I, class S> constexpr S end(sized_iterator_range<I, S> const && r) noexcept( std::is_nothrow_copy_constructible<S>::value) { return r.end(); } } // namespace _iterator_range_ /// \endcond template<typename I, typename S /*= I*/> struct RANGES_EMPTY_BASES iterator_range : view_interface<iterator_range<I, S>, same_as<S, unreachable_sentinel_t> ? infinite : unknown> , compressed_pair<I, S> , _iterator_range_::adl_hook_ { private: template<typename, typename> friend struct iterator_range; template<typename, typename> friend struct sized_iterator_range; compressed_pair<I, S> & base() noexcept { return *this; } compressed_pair<I, S> const & base() const noexcept { return *this; } using compressed_pair<I, S>::first; using compressed_pair<I, S>::second; public: using iterator = I; using sentinel = S; /// \cond using const_iterator = I; // Mostly to avoid spurious errors in Boost.Range /// \endcond constexpr I & begin() & { return this->first(); } constexpr I const & begin() const & { return this->first(); } constexpr S & end() & { return this->second(); } constexpr S const & end() const & { return this->second(); } iterator_range() = default; constexpr iterator_range(I first, S last) : compressed_pair<I, S>{detail::move(first), detail::move(last)} {} template<typename X, typename Y> constexpr CPP_ctor(iterator_range)(iterator_range<X, Y> rng)( // requires constructible_from<I, X> && constructible_from<S, Y>) : compressed_pair<I, S>{detail::move(rng.begin()), detail::move(rng.end())} {} template<typename X, typename Y> explicit constexpr CPP_ctor(iterator_range)(std::pair<X, Y> rng)( // requires constructible_from<I, X> && constructible_from<S, Y>) : compressed_pair<I, S>{detail::move(rng.first), detail::move(rng.second)} {} template<typename X, typename Y> auto operator=(iterator_range<X, Y> rng) -> CPP_ret(iterator_range &)( // requires assignable_from<I &, X> && assignable_from<S &, Y>) { base().first() = std::move(rng.base()).first(); base().second() = std::move(rng.base()).second(); return *this; } CPP_template(typename X, typename Y)( // requires convertible_to<I, X> && convertible_to<S, Y>) // constexpr operator std::pair<X, Y>() const { return {base().first(), base().second()}; } constexpr bool empty() const { return base().first() == base().second(); } }; // Like iterator_range, but with a known size. The first and second members // are private to prevent inadvertent violations of the class invariant. // // Class invariant: // distance(begin(), end()) == size() // template<typename I, typename S /* = I */> struct sized_iterator_range : view_interface<sized_iterator_range<I, S>, finite> , _iterator_range_::adl_hook_ { using size_type = detail::iter_size_t<I>; using iterator = I; using sentinel = S; #ifndef RANGES_DOXYGEN_INVOKED using const_iterator = I; // Mostly to avoid spurious errors in Boost.Range #endif private: template<typename X, typename Y> friend struct sized_iterator_range; iterator_range<I, S> rng_; size_type size_; public: sized_iterator_range() = default; RANGES_NDEBUG_CONSTEXPR sized_iterator_range(I first, S last, size_type size) : rng_{detail::move(first), detail::move(last)} , size_(size) { #ifndef NDEBUG RANGES_ASSERT(!(bool)forward_iterator<I> || static_cast<size_type>(ranges::distance(rng_)) == size_); #endif } template<typename X, typename Y> RANGES_NDEBUG_CONSTEXPR CPP_ctor(sized_iterator_range)(std::pair<X, Y> rng, size_type size)( // requires constructible_from<I, X> && constructible_from<S, Y>) : sized_iterator_range{detail::move(rng).first, detail::move(rng).second, size} {} template<typename X, typename Y> RANGES_NDEBUG_CONSTEXPR CPP_ctor(sized_iterator_range)(iterator_range<X, Y> rng, size_type size)( // requires constructible_from<I, X> && constructible_from<S, Y>) : sized_iterator_range{detail::move(rng).first(), detail::move(rng).second, size} {} template<typename X, typename Y> RANGES_NDEBUG_CONSTEXPR CPP_ctor(sized_iterator_range)( sized_iterator_range<X, Y> rng)( // requires constructible_from<I, X> && constructible_from<S, Y>) : sized_iterator_range{detail::move(rng).rng_.first(), detail::move(rng).rng_.second, rng.size_} {} template<typename X, typename Y> auto operator=(sized_iterator_range<X, Y> rng) -> CPP_ret(sized_iterator_range &)( // requires assignable_from<I &, X> && assignable_from<S &, Y>) { rng_ = detail::move(rng).rng_; size_ = rng.size_; return *this; } I begin() const { return rng_.begin(); } S end() const { return rng_.end(); } size_type size() const noexcept { return size_; } CPP_template(typename X, typename Y)( // requires convertible_to<I, X> && convertible_to<S, Y>) // constexpr operator std::pair<X, Y>() const { return rng_; } CPP_template(typename X, typename Y)( // requires convertible_to<I, X> && convertible_to<S, Y>) // constexpr operator iterator_range<X, Y>() const { return rng_; } constexpr operator iterator_range<I, S> const &() const & noexcept { return rng_; } // clang-format off /// Tuple-like access for `sized_iterator_range` CPP_template(std::size_t N)( // requires (N < 2)) // friend constexpr auto CPP_auto_fun(get)(sized_iterator_range const &p) ( // return ranges::get<N>(p.rng_) return ranges::get<N>(p.*&sized_iterator_range::rng_) // makes clang happy ) // clang-format on /// \overload template<std::size_t N> friend constexpr auto get(sized_iterator_range const & p) noexcept -> CPP_ret(size_type)( // requires(N == 2)) { return p.size(); } }; struct make_iterator_range_fn { /// \return `{first, last}` template<typename I, typename S> constexpr auto operator()(I first, S last) const -> CPP_ret(iterator_range<I, S>)( // requires sentinel_for<S, I>) { return {detail::move(first), detail::move(last)}; } /// \return `{first, last, size}` template<typename I, typename S> constexpr auto operator()(I first, S last, detail::iter_size_t<I> sz) const -> CPP_ret(sized_iterator_range<I, S>)( // requires sentinel_for<S, I>) { return {detail::move(first), detail::move(last), sz}; } }; /// \sa `make_iterator_range_fn` RANGES_INLINE_VARIABLE(make_iterator_range_fn, make_iterator_range) // TODO add specialization of range_cardinality for when we can determine the range is // infinite /// @} } // namespace ranges // The standard is inconsistent about whether these are classes or structs RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS /// \cond namespace std { template<typename I, typename S> struct tuple_size<::ranges::iterator_range<I, S>> : std::integral_constant<size_t, 2> {}; template<typename I, typename S> struct tuple_element<0, ::ranges::iterator_range<I, S>> { using type = I; }; template<typename I, typename S> struct tuple_element<1, ::ranges::iterator_range<I, S>> { using type = S; }; template<typename I, typename S> struct tuple_size<::ranges::sized_iterator_range<I, S>> : std::integral_constant<size_t, 3> {}; template<typename I, typename S> struct tuple_element<0, ::ranges::sized_iterator_range<I, S>> { using type = I; }; template<typename I, typename S> struct tuple_element<1, ::ranges::sized_iterator_range<I, S>> { using type = S; }; template<typename I, typename S> struct tuple_element<2, ::ranges::sized_iterator_range<I, S>> { using type = typename ::ranges::sized_iterator_range<I, S>::size_type; }; } // namespace std /// \endcond RANGES_DIAGNOSTIC_POP #endif