/// \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 #include #include #include #include #include #include #include #include #include RANGES_DEPRECATED_HEADER( "This header is deprecated. Please switch to subrange in " ".") 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 constexpr I begin(iterator_range && r) noexcept( std::is_nothrow_copy_constructible::value) { return r.begin(); } template constexpr I begin(iterator_range const && r) noexcept( std::is_nothrow_copy_constructible::value) { return r.begin(); } template constexpr S end(iterator_range && r) noexcept( std::is_nothrow_copy_constructible::value) { return r.end(); } template constexpr S end(iterator_range const && r) noexcept( std::is_nothrow_copy_constructible::value) { return r.end(); } // A temporary sized_iterator_range can be safely passed to ranges::begin and // ranges::end. template constexpr I begin(sized_iterator_range && r) noexcept( std::is_nothrow_copy_constructible::value) { return r.begin(); } template constexpr I begin(sized_iterator_range const && r) noexcept( std::is_nothrow_copy_constructible::value) { return r.begin(); } template constexpr S end(sized_iterator_range && r) noexcept( std::is_nothrow_copy_constructible::value) { return r.end(); } template constexpr S end(sized_iterator_range const && r) noexcept( std::is_nothrow_copy_constructible::value) { return r.end(); } } // namespace _iterator_range_ /// \endcond template struct RANGES_EMPTY_BASES iterator_range : view_interface, same_as ? infinite : unknown> , compressed_pair , _iterator_range_::adl_hook_ { private: template friend struct iterator_range; template friend struct sized_iterator_range; compressed_pair & base() noexcept { return *this; } compressed_pair const & base() const noexcept { return *this; } using compressed_pair::first; using compressed_pair::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{detail::move(first), detail::move(last)} {} template constexpr CPP_ctor(iterator_range)(iterator_range rng)( // requires constructible_from && constructible_from) : compressed_pair{detail::move(rng.begin()), detail::move(rng.end())} {} template explicit constexpr CPP_ctor(iterator_range)(std::pair rng)( // requires constructible_from && constructible_from) : compressed_pair{detail::move(rng.first), detail::move(rng.second)} {} template auto operator=(iterator_range rng) -> CPP_ret(iterator_range &)( // requires assignable_from && assignable_from) { 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 && convertible_to) // constexpr operator std::pair() 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 struct sized_iterator_range : view_interface, finite> , _iterator_range_::adl_hook_ { using size_type = detail::iter_size_t; 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 friend struct sized_iterator_range; iterator_range 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 || static_cast(ranges::distance(rng_)) == size_); #endif } template RANGES_NDEBUG_CONSTEXPR CPP_ctor(sized_iterator_range)(std::pair rng, size_type size)( // requires constructible_from && constructible_from) : sized_iterator_range{detail::move(rng).first, detail::move(rng).second, size} {} template RANGES_NDEBUG_CONSTEXPR CPP_ctor(sized_iterator_range)(iterator_range rng, size_type size)( // requires constructible_from && constructible_from) : sized_iterator_range{detail::move(rng).first(), detail::move(rng).second, size} {} template RANGES_NDEBUG_CONSTEXPR CPP_ctor(sized_iterator_range)( sized_iterator_range rng)( // requires constructible_from && constructible_from) : sized_iterator_range{detail::move(rng).rng_.first(), detail::move(rng).rng_.second, rng.size_} {} template auto operator=(sized_iterator_range rng) -> CPP_ret(sized_iterator_range &)( // requires assignable_from && assignable_from) { 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 && convertible_to) // constexpr operator std::pair() const { return rng_; } CPP_template(typename X, typename Y)( // requires convertible_to && convertible_to) // constexpr operator iterator_range() const { return rng_; } constexpr operator iterator_range 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(p.rng_) return ranges::get(p.*&sized_iterator_range::rng_) // makes clang happy ) // clang-format on /// \overload template 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 constexpr auto operator()(I first, S last) const -> CPP_ret(iterator_range)( // requires sentinel_for) { return {detail::move(first), detail::move(last)}; } /// \return `{first, last, size}` template constexpr auto operator()(I first, S last, detail::iter_size_t sz) const -> CPP_ret(sized_iterator_range)( // requires sentinel_for) { 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 struct tuple_size<::ranges::iterator_range> : std::integral_constant {}; template struct tuple_element<0, ::ranges::iterator_range> { using type = I; }; template struct tuple_element<1, ::ranges::iterator_range> { using type = S; }; template struct tuple_size<::ranges::sized_iterator_range> : std::integral_constant {}; template struct tuple_element<0, ::ranges::sized_iterator_range> { using type = I; }; template struct tuple_element<1, ::ranges::sized_iterator_range> { using type = S; }; template struct tuple_element<2, ::ranges::sized_iterator_range> { using type = typename ::ranges::sized_iterator_range::size_type; }; } // namespace std /// \endcond RANGES_DIAGNOSTIC_POP #endif