/// \file // Range v3 library // // Copyright Eric Niebler 2014-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_VIEW_ADAPTOR_HPP #define RANGES_V3_VIEW_ADAPTOR_HPP #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \cond namespace detail { template using begin_adaptor_t = detail::decay_t()))>; template using end_adaptor_t = detail::decay_t()))>; template using adapted_iterator_t = detail::decay_t>().begin(std::declval()))>; template using adapted_sentinel_t = detail::decay_t>().end(std::declval()))>; struct adaptor_base_current_mem_fn {}; template constexpr int which_adaptor_value_(priority_tag<0>) { return 0; } template constexpr auto which_adaptor_value_(priority_tag<1>) -> always_(), adaptor_base_current_mem_fn{}))> { return 1; } template constexpr auto which_adaptor_value_(priority_tag<2>) -> always_ { return 2; } template(priority_tag<2>{})> struct adaptor_value_type_ { compressed_pair data_; }; template struct adaptor_value_type_ { using value_type = iter_value_t; compressed_pair data_; }; template struct adaptor_value_type_ { #ifdef RANGES_WORKAROUND_MSVC_688606 using value_type = typename readable_traits::value_type; #else // ^^^ workaround ^^^ / vvv no workaround vvv using value_type = typename Adapt::value_type; #endif // RANGES_WORKAROUND_MSVC_688606 compressed_pair data_; }; } // namespace detail /// \endcond /// \addtogroup group-views /// @{ template struct adaptor_cursor; template struct base_adaptor_sentinel; struct adaptor_base { adaptor_base() = default; adaptor_base(adaptor_base &&) = default; adaptor_base(adaptor_base const &) = default; adaptor_base & operator=(adaptor_base &&) = default; adaptor_base & operator=(adaptor_base const &) = default; adaptor_base(detail::ignore_t, detail::ignore_t = {}, detail::ignore_t = {}) {} // clang-format off template static constexpr auto CPP_auto_fun(begin)(Rng &rng) ( return ranges::begin(rng.base()) ) template static constexpr auto CPP_auto_fun(end)(Rng &rng) ( return ranges::end(rng.base()) ) // clang-format on template static auto equal(I const & it0, I const & it1) -> CPP_ret(bool)( // requires equality_comparable) { return it0 == it1; } template static auto read(I const & it, detail::adaptor_base_current_mem_fn = {}) noexcept( noexcept(iter_reference_t(*it))) -> CPP_ret(iter_reference_t)( // requires input_or_output_iterator) { return *it; } template static auto next(I & it) -> CPP_ret(void)( // requires input_or_output_iterator) { ++it; } template static auto prev(I & it) -> CPP_ret(void)( // requires bidirectional_iterator) { --it; } template static auto advance(I & it, iter_difference_t n) -> CPP_ret(void)( // requires random_access_iterator) { it += n; } template static auto distance_to(I const & it0, I const & it1) -> CPP_ret(iter_difference_t)( // requires sized_sentinel_for) { return it1 - it0; } template static constexpr auto empty(I const & it, S const & last) -> CPP_ret(bool)( // requires sentinel_for) { return it == last; } }; // Build a sentinel out of a sentinel into the adapted range, and an // adaptor that customizes behavior. template struct base_adaptor_sentinel { private: template friend struct adaptor_cursor; RANGES_NO_UNIQUE_ADDRESS compressed_pair data_; public: base_adaptor_sentinel() = default; base_adaptor_sentinel(BaseSent sent, Adapt adapt) : data_{std::move(sent), std::move(adapt)} {} // All sentinels into adapted ranges have a base() member for fetching // the underlying sentinel. BaseSent base() const { return data_.first(); } protected: // Adaptor accessor Adapt & get() { return data_.second(); } Adapt const & get() const { return data_.second(); } }; /// \cond namespace detail { template meta::id> base_adaptor_sentinel_2_(long); template meta::id>> base_adaptor_sentinel_2_(int); template struct base_adaptor_sentinel_ : decltype(base_adaptor_sentinel_2_(42)) {}; template using adaptor_sentinel_ = meta::_t>; } // namespace detail /// \endcond template struct adaptor_sentinel : detail::adaptor_sentinel_ { using detail::adaptor_sentinel_::adaptor_sentinel_; }; // Build a cursor out of an iterator into the adapted range, and an // adaptor that customizes behavior. template struct adaptor_cursor : private detail::adaptor_value_type_ { private: friend range_access; template friend struct adaptor_cursor; using base_t = detail::adaptor_value_type_; using single_pass = meta::bool_<(bool)range_access::single_pass_t() || (bool)single_pass_iterator_>; struct basic_adaptor_mixin : basic_mixin { basic_adaptor_mixin() = default; using basic_mixin::basic_mixin; // All iterators into adapted ranges have a base() member for fetching // the underlying iterator. BaseIter base() const { return basic_adaptor_mixin::basic_mixin::get().data_.first(); } protected: // Adaptor accessor Adapt & get() { return basic_adaptor_mixin::basic_mixin::get().data_.second(); } const Adapt & get() const { return basic_adaptor_mixin::basic_mixin::get().data_.second(); } }; template static meta::id basic_adaptor_mixin_2_(long); template static meta::id> basic_adaptor_mixin_2_(int); using mixin = meta::_t(42))>; template().read( std::declval()))> R read() const noexcept( noexcept(std::declval().read(std::declval()))) { using V = range_access::cursor_value_t; static_assert(common_reference_with, "In your adaptor, you've specified a value type that does not " "share a common reference type with the return type of read."); return this->data_.second().read(this->data_.first()); } template().next( std::declval()))> void next() { this->data_.second().next(this->data_.first()); } template().equal( std::declval(), std::declval(), std::declval()))> bool equal_(adaptor_cursor const & that, int) const { return this->data_.second().equal( this->data_.first(), that.data_.first(), that.data_.second()); } template().equal( std::declval(), std::declval()))> bool equal_(adaptor_cursor const & that, long) const { return this->data_.second().equal(this->data_.first(), that.data_.first()); } template auto equal(adaptor_cursor const & that) const -> decltype(std::declval().equal_(that, 42)) { return this->equal_(that, 42); } template().empty( std::declval(), std::declval(), std::declval()))> constexpr bool equal_(adaptor_sentinel const & that, int) const { return that.data_.second().empty( this->data_.first(), this->data_.second(), that.data_.first()); } template().empty( std::declval(), std::declval()))> constexpr bool equal_(adaptor_sentinel const & that, long) const { return that.data_.second().empty(this->data_.first(), that.data_.first()); } template constexpr auto equal(adaptor_sentinel const & that) const -> decltype(std::declval().equal_(that, 42)) { return this->equal_(that, 42); } template().prev( std::declval()))> void prev() { this->data_.second().prev(this->data_.first()); } template().advance( std::declval(), 0))> void advance(iter_difference_t n) { this->data_.second().advance(this->data_.first(), n); } template().distance_to( std::declval(), std::declval(), std::declval()))> R distance_to_(adaptor_cursor const & that, int) const { return this->data_.second().distance_to( this->data_.first(), that.data_.first(), that.data_.second()); } template().distance_to( std::declval(), std::declval()))> R distance_to_(adaptor_cursor const & that, long) const { return this->data_.second().distance_to(this->data_.first(), that.data_.first()); } template auto distance_to(adaptor_cursor const & that) const -> decltype(std::declval().distance_to_(that, 42)) { return this->distance_to_(that, 42); } // If the adaptor has an iter_move function, use it. template().iter_move( std::declval()))> X iter_move_(int) const noexcept(noexcept( std::declval().iter_move(std::declval()))) { using V = range_access::cursor_value_t; using R = decltype(this->data_.second().read(this->data_.first())); static_assert( common_reference_with, "In your adaptor, the result of your iter_move member function does " "not share a common reference with your value type."); static_assert( common_reference_with, "In your adaptor, the result of your iter_move member function does " "not share a common reference with the result of your read member " "function."); return this->data_.second().iter_move(this->data_.first()); } // If there is no iter_move member and the adaptor has not overridden the read // member function, then dispatch to the base iterator's iter_move function. template().read( std::declval(), detail::adaptor_base_current_mem_fn{})), typename X = iter_rvalue_reference_t> X iter_move_(long) const noexcept(noexcept(X(ranges::iter_move(std::declval())))) { return ranges::iter_move(this->data_.first()); } // If the adaptor does not have an iter_move function but overrides the read // member function, apply std::move to the result of calling read. template().read(std::declval())), typename X = aux::move_t> X iter_move_(detail::ignore_t) const noexcept(noexcept(X(static_cast( std::declval().read(std::declval()))))) { using V = range_access::cursor_value_t; static_assert( common_reference_with, "In your adaptor, you've specified a value type that does not share a " "common " "reference type with the result of moving the result of the read member " "function. Consider defining an iter_move function in your adaptor."); return static_cast(this->data_.second().read(this->data_.first())); } // Gives users a way to override the default iter_move function in their adaptors. auto move() const noexcept(noexcept(std::declval().iter_move_(42))) -> decltype(std::declval().iter_move_(42)) { return iter_move_(42); } public: adaptor_cursor() = default; adaptor_cursor(BaseIter iter, Adapt adapt) : base_t{{std::move(iter), std::move(adapt)}} {} template CPP_ctor(adaptor_cursor)(adaptor_cursor that)( requires defer::not_same_as_, adaptor_cursor> && defer::convertible_to && defer::convertible_to) : base_t{{std::move(that.data_.first()), std::move(that.data_.second())}} {} }; template using adaptor_cursor_t = adaptor_cursor, detail::begin_adaptor_t>; template using adaptor_sentinel_t = meta::if_c< same_as, detail::adapted_sentinel_t> && same_as, detail::end_adaptor_t>, adaptor_cursor_t, adaptor_sentinel, detail::end_adaptor_t>>; template::value*/> struct view_adaptor : view_facade { private: friend Derived; friend range_access; friend adaptor_base; CPP_assert(viewable_range); using base_range_t = views::all_t; using view_facade::derived; base_range_t rng_; constexpr adaptor_base begin_adaptor() const noexcept { return {}; } constexpr adaptor_base end_adaptor() const noexcept { return {}; } template static constexpr adaptor_cursor_t begin_cursor_(D & d) noexcept(noexcept( adaptor_cursor_t{std::declval &>().begin(d), range_access::begin_adaptor(d)})) { auto adapt = range_access::begin_adaptor(d); auto pos = adapt.begin(d); return {std::move(pos), std::move(adapt)}; } template constexpr auto begin_cursor() noexcept( noexcept(view_adaptor::begin_cursor_(std::declval()))) -> CPP_ret(decltype(view_adaptor::begin_cursor_(std::declval())))( // requires same_as) { return view_adaptor::begin_cursor_(derived()); } template constexpr auto begin_cursor() const noexcept(noexcept(view_adaptor::begin_cursor_(std::declval()))) -> CPP_ret( decltype(view_adaptor::begin_cursor_(std::declval())))( // requires same_as && range) { return view_adaptor::begin_cursor_(derived()); } template static constexpr adaptor_sentinel_t end_cursor_(D & d) noexcept(noexcept( adaptor_sentinel_t{std::declval &>().end(d), range_access::end_adaptor(d)})) { auto adapt = range_access::end_adaptor(d); auto pos = adapt.end(d); return {std::move(pos), std::move(adapt)}; } template constexpr auto end_cursor() noexcept( noexcept(view_adaptor::end_cursor_(std::declval()))) -> CPP_ret(decltype(view_adaptor::end_cursor_(std::declval())))( // requires same_as) { return view_adaptor::end_cursor_(derived()); } template constexpr auto end_cursor() const noexcept( noexcept(view_adaptor::end_cursor_(std::declval()))) -> CPP_ret(decltype(view_adaptor::end_cursor_(std::declval())))( // requires same_as && range) { return view_adaptor::end_cursor_(derived()); } protected: ~view_adaptor() = default; public: view_adaptor() = default; view_adaptor(view_adaptor &&) = default; view_adaptor(view_adaptor const &) = default; view_adaptor & operator=(view_adaptor &&) = default; view_adaptor & operator=(view_adaptor const &) = default; explicit constexpr view_adaptor(BaseRng && rng) : rng_(views::all(static_cast(rng))) {} constexpr base_range_t & base() noexcept { return rng_; } /// \overload constexpr base_range_t const & base() const noexcept { return rng_; } }; /// @} } // namespace ranges #endif