|
- /// \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 <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/traits.hpp>
- #include <range/v3/range/primitives.hpp>
- #include <range/v3/range/traits.hpp>
- #include <range/v3/utility/compressed_pair.hpp>
- #include <range/v3/view/all.hpp>
- #include <range/v3/view/facade.hpp>
-
- namespace ranges
- {
- /// \cond
- namespace detail
- {
- template<typename Derived>
- using begin_adaptor_t = detail::decay_t<decltype(
- range_access::begin_adaptor(std::declval<Derived &>()))>;
-
- template<typename Derived>
- using end_adaptor_t = detail::decay_t<decltype(
- range_access::end_adaptor(std::declval<Derived &>()))>;
-
- template<typename Derived>
- using adapted_iterator_t = detail::decay_t<decltype(
- std::declval<begin_adaptor_t<Derived>>().begin(std::declval<Derived &>()))>;
-
- template<typename Derived>
- using adapted_sentinel_t = detail::decay_t<decltype(
- std::declval<end_adaptor_t<Derived>>().end(std::declval<Derived &>()))>;
-
- struct adaptor_base_current_mem_fn
- {};
-
- template<typename BaseIter, typename Adapt>
- constexpr int which_adaptor_value_(priority_tag<0>)
- {
- return 0;
- }
- template<typename BaseIter, typename Adapt>
- constexpr auto which_adaptor_value_(priority_tag<1>)
- -> always_<int, decltype(Adapt::read(std::declval<BaseIter const &>(),
- adaptor_base_current_mem_fn{}))>
- {
- return 1;
- }
- template<typename BaseIter, typename Adapt>
- constexpr auto which_adaptor_value_(priority_tag<2>)
- -> always_<int, typename Adapt::value_type>
- {
- return 2;
- }
-
- template<typename BaseIter, typename Adapt,
- int = detail::which_adaptor_value_<BaseIter, Adapt>(priority_tag<2>{})>
- struct adaptor_value_type_
- {
- compressed_pair<BaseIter, Adapt> data_;
- };
- template<typename BaseIter, typename Adapt>
- struct adaptor_value_type_<BaseIter, Adapt, 1>
- {
- using value_type = iter_value_t<BaseIter>;
- compressed_pair<BaseIter, Adapt> data_;
- };
- template<typename BaseIter, typename Adapt>
- struct adaptor_value_type_<BaseIter, Adapt, 2>
- {
- #ifdef RANGES_WORKAROUND_MSVC_688606
- using value_type = typename readable_traits<Adapt>::value_type;
- #else // ^^^ workaround ^^^ / vvv no workaround vvv
- using value_type = typename Adapt::value_type;
- #endif // RANGES_WORKAROUND_MSVC_688606
- compressed_pair<BaseIter, Adapt> data_;
- };
- } // namespace detail
- /// \endcond
-
- /// \addtogroup group-views
- /// @{
- template<typename BaseIt, typename Adapt>
- struct adaptor_cursor;
-
- template<typename BaseSent, typename Adapt>
- 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<typename Rng>
- static constexpr auto CPP_auto_fun(begin)(Rng &rng)
- (
- return ranges::begin(rng.base())
- )
- template<typename Rng>
- static constexpr auto CPP_auto_fun(end)(Rng &rng)
- (
- return ranges::end(rng.base())
- )
- // clang-format on
- template<typename I>
- static auto equal(I const & it0, I const & it1) -> CPP_ret(bool)( //
- requires equality_comparable<I>)
- {
- return it0 == it1;
- }
- template<typename I>
- static auto read(I const & it, detail::adaptor_base_current_mem_fn = {}) noexcept(
- noexcept(iter_reference_t<I>(*it))) -> CPP_ret(iter_reference_t<I>)( //
- requires input_or_output_iterator<I>)
- {
- return *it;
- }
- template<typename I>
- static auto next(I & it) -> CPP_ret(void)( //
- requires input_or_output_iterator<I>)
- {
- ++it;
- }
- template<typename I>
- static auto prev(I & it) -> CPP_ret(void)( //
- requires bidirectional_iterator<I>)
- {
- --it;
- }
- template<typename I>
- static auto advance(I & it, iter_difference_t<I> n) -> CPP_ret(void)( //
- requires random_access_iterator<I>)
- {
- it += n;
- }
- template<typename I>
- static auto distance_to(I const & it0, I const & it1)
- -> CPP_ret(iter_difference_t<I>)( //
- requires sized_sentinel_for<I, I>)
- {
- return it1 - it0;
- }
- template<typename I, typename S>
- static constexpr auto empty(I const & it, S const & last) -> CPP_ret(bool)( //
- requires sentinel_for<S, I>)
- {
- return it == last;
- }
- };
-
- // Build a sentinel out of a sentinel into the adapted range, and an
- // adaptor that customizes behavior.
- template<typename BaseSent, typename Adapt>
- struct base_adaptor_sentinel
- {
- private:
- template<typename, typename>
- friend struct adaptor_cursor;
- RANGES_NO_UNIQUE_ADDRESS compressed_pair<BaseSent, Adapt> 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<typename BaseSent, typename Adapt>
- meta::id<base_adaptor_sentinel<BaseSent, Adapt>> base_adaptor_sentinel_2_(long);
-
- template<typename BaseSent, typename Adapt>
- meta::id<typename Adapt::template mixin<base_adaptor_sentinel<BaseSent, Adapt>>>
- base_adaptor_sentinel_2_(int);
-
- template<typename BaseSent, typename Adapt>
- struct base_adaptor_sentinel_
- : decltype(base_adaptor_sentinel_2_<BaseSent, Adapt>(42))
- {};
-
- template<typename BaseSent, typename Adapt>
- using adaptor_sentinel_ = meta::_t<base_adaptor_sentinel_<BaseSent, Adapt>>;
- } // namespace detail
- /// \endcond
-
- template<typename BaseSent, typename Adapt>
- struct adaptor_sentinel : detail::adaptor_sentinel_<BaseSent, Adapt>
- {
- using detail::adaptor_sentinel_<BaseSent, Adapt>::adaptor_sentinel_;
- };
-
- // Build a cursor out of an iterator into the adapted range, and an
- // adaptor that customizes behavior.
- template<typename BaseIter, typename Adapt>
- struct adaptor_cursor : private detail::adaptor_value_type_<BaseIter, Adapt>
- {
- private:
- friend range_access;
- template<typename, typename>
- friend struct adaptor_cursor;
- using base_t = detail::adaptor_value_type_<BaseIter, Adapt>;
- using single_pass = meta::bool_<(bool)range_access::single_pass_t<Adapt>() ||
- (bool)single_pass_iterator_<BaseIter>>;
-
- struct basic_adaptor_mixin : basic_mixin<adaptor_cursor>
- {
- basic_adaptor_mixin() = default;
- using basic_mixin<adaptor_cursor>::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<typename Adapt_>
- static meta::id<basic_adaptor_mixin> basic_adaptor_mixin_2_(long);
-
- template<typename Adapt_>
- static meta::id<typename Adapt_::template mixin<basic_adaptor_mixin>>
- basic_adaptor_mixin_2_(int);
-
- using mixin = meta::_t<decltype(basic_adaptor_mixin_2_<Adapt>(42))>;
-
- template<typename A = Adapt, typename R = decltype(std::declval<A const &>().read(
- std::declval<BaseIter const &>()))>
- R read() const noexcept(
- noexcept(std::declval<A const &>().read(std::declval<BaseIter const &>())))
- {
- using V = range_access::cursor_value_t<adaptor_cursor>;
- static_assert(common_reference_with<R &&, V &>,
- "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<typename A = Adapt, typename = decltype(std::declval<A &>().next(
- std::declval<BaseIter &>()))>
- void next()
- {
- this->data_.second().next(this->data_.first());
- }
- template<typename A = Adapt,
- typename = decltype(std::declval<A const &>().equal(
- std::declval<BaseIter const &>(), std::declval<BaseIter const &>(),
- std::declval<A const &>()))>
- bool equal_(adaptor_cursor const & that, int) const
- {
- return this->data_.second().equal(
- this->data_.first(), that.data_.first(), that.data_.second());
- }
- template<typename A = Adapt,
- typename = decltype(std::declval<A const &>().equal(
- std::declval<BaseIter const &>(), std::declval<BaseIter const &>()))>
- bool equal_(adaptor_cursor const & that, long) const
- {
- return this->data_.second().equal(this->data_.first(), that.data_.first());
- }
- template<typename C = adaptor_cursor>
- auto equal(adaptor_cursor const & that) const
- -> decltype(std::declval<C const &>().equal_(that, 42))
- {
- return this->equal_(that, 42);
- }
- template<typename S, typename A,
- typename = decltype(std::declval<A const &>().empty(
- std::declval<BaseIter const &>(), std::declval<Adapt const &>(),
- std::declval<S const &>()))>
- constexpr bool equal_(adaptor_sentinel<S, A> const & that, int) const
- {
- return that.data_.second().empty(
- this->data_.first(), this->data_.second(), that.data_.first());
- }
- template<typename S, typename A,
- typename = decltype(std::declval<A const &>().empty(
- std::declval<BaseIter const &>(), std::declval<S const &>()))>
- constexpr bool equal_(adaptor_sentinel<S, A> const & that, long) const
- {
- return that.data_.second().empty(this->data_.first(), that.data_.first());
- }
- template<typename S, typename A>
- constexpr auto equal(adaptor_sentinel<S, A> const & that) const
- -> decltype(std::declval<adaptor_cursor const &>().equal_(that, 42))
- {
- return this->equal_(that, 42);
- }
- template<typename A = Adapt, typename = decltype(std::declval<A &>().prev(
- std::declval<BaseIter &>()))>
- void prev()
- {
- this->data_.second().prev(this->data_.first());
- }
- template<typename A = Adapt, typename = decltype(std::declval<A &>().advance(
- std::declval<BaseIter &>(), 0))>
- void advance(iter_difference_t<BaseIter> n)
- {
- this->data_.second().advance(this->data_.first(), n);
- }
- template<typename A = Adapt,
- typename R = decltype(std::declval<A const &>().distance_to(
- std::declval<BaseIter const &>(), std::declval<BaseIter const &>(),
- std::declval<A const &>()))>
- 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<typename A = Adapt,
- typename R = decltype(std::declval<A const &>().distance_to(
- std::declval<BaseIter const &>(), std::declval<BaseIter const &>()))>
- R distance_to_(adaptor_cursor const & that, long) const
- {
- return this->data_.second().distance_to(this->data_.first(),
- that.data_.first());
- }
- template<typename C = adaptor_cursor>
- auto distance_to(adaptor_cursor const & that) const
- -> decltype(std::declval<C const &>().distance_to_(that, 42))
- {
- return this->distance_to_(that, 42);
- }
- // If the adaptor has an iter_move function, use it.
- template<typename A = Adapt,
- typename X = decltype(std::declval<A const &>().iter_move(
- std::declval<BaseIter const &>()))>
- X iter_move_(int) const noexcept(noexcept(
- std::declval<A const &>().iter_move(std::declval<BaseIter const &>())))
- {
- using V = range_access::cursor_value_t<adaptor_cursor>;
- using R = decltype(this->data_.second().read(this->data_.first()));
- static_assert(
- common_reference_with<X &&, V const &>,
- "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<R &&, X &&>,
- "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<typename A = Adapt,
- typename R = decltype(std::declval<A const &>().read(
- std::declval<BaseIter const &>(),
- detail::adaptor_base_current_mem_fn{})),
- typename X = iter_rvalue_reference_t<BaseIter>>
- X iter_move_(long) const
- noexcept(noexcept(X(ranges::iter_move(std::declval<BaseIter const &>()))))
- {
- 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<typename A = Adapt,
- typename R = decltype(
- std::declval<A const &>().read(std::declval<BaseIter const &>())),
- typename X = aux::move_t<R>>
- X iter_move_(detail::ignore_t) const noexcept(noexcept(X(static_cast<X &&>(
- std::declval<A const &>().read(std::declval<BaseIter const &>())))))
- {
- using V = range_access::cursor_value_t<adaptor_cursor>;
- static_assert(
- common_reference_with<X &&, V const &>,
- "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<X &&>(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<const adaptor_cursor &>().iter_move_(42)))
- -> decltype(std::declval<const adaptor_cursor &>().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<typename OtherIter, typename OtherAdapt>
- CPP_ctor(adaptor_cursor)(adaptor_cursor<OtherIter, OtherAdapt> that)(
- requires defer::not_same_as_<adaptor_cursor<OtherIter, OtherAdapt>, adaptor_cursor> &&
- defer::convertible_to<OtherIter, BaseIter> &&
- defer::convertible_to<OtherAdapt, Adapt>)
- : base_t{{std::move(that.data_.first()), std::move(that.data_.second())}}
- {}
- };
-
- template<typename D>
- using adaptor_cursor_t =
- adaptor_cursor<detail::adapted_iterator_t<D>, detail::begin_adaptor_t<D>>;
-
- template<typename D>
- using adaptor_sentinel_t = meta::if_c<
- same_as<detail::adapted_iterator_t<D>, detail::adapted_sentinel_t<D>> &&
- same_as<detail::begin_adaptor_t<D>, detail::end_adaptor_t<D>>,
- adaptor_cursor_t<D>,
- adaptor_sentinel<detail::adapted_sentinel_t<D>, detail::end_adaptor_t<D>>>;
-
- template<typename Derived, typename BaseRng,
- cardinality Cardinality /*= range_cardinality<BaseRng>::value*/>
- struct view_adaptor : view_facade<Derived, Cardinality>
- {
- private:
- friend Derived;
- friend range_access;
- friend adaptor_base;
- CPP_assert(viewable_range<BaseRng>);
- using base_range_t = views::all_t<BaseRng>;
- using view_facade<Derived, Cardinality>::derived;
-
- base_range_t rng_;
-
- constexpr adaptor_base begin_adaptor() const noexcept
- {
- return {};
- }
- constexpr adaptor_base end_adaptor() const noexcept
- {
- return {};
- }
-
- template<typename D>
- static constexpr adaptor_cursor_t<D> begin_cursor_(D & d) noexcept(noexcept(
- adaptor_cursor_t<D>{std::declval<detail::begin_adaptor_t<D> &>().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<typename D = Derived>
- constexpr auto begin_cursor() noexcept(
- noexcept(view_adaptor::begin_cursor_(std::declval<D &>())))
- -> CPP_ret(decltype(view_adaptor::begin_cursor_(std::declval<D &>())))( //
- requires same_as<D, Derived>)
- {
- return view_adaptor::begin_cursor_(derived());
- }
- template<typename D = Derived>
- constexpr auto begin_cursor() const
- noexcept(noexcept(view_adaptor::begin_cursor_(std::declval<D const &>())))
- -> CPP_ret(
- decltype(view_adaptor::begin_cursor_(std::declval<D const &>())))( //
- requires same_as<D, Derived> && range<base_range_t const>)
- {
- return view_adaptor::begin_cursor_(derived());
- }
-
- template<typename D>
- static constexpr adaptor_sentinel_t<D> end_cursor_(D & d) noexcept(noexcept(
- adaptor_sentinel_t<D>{std::declval<detail::end_adaptor_t<D> &>().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<typename D = Derived>
- constexpr auto end_cursor() noexcept(
- noexcept(view_adaptor::end_cursor_(std::declval<D &>())))
- -> CPP_ret(decltype(view_adaptor::end_cursor_(std::declval<D &>())))( //
- requires same_as<D, Derived>)
- {
- return view_adaptor::end_cursor_(derived());
- }
- template<typename D = Derived>
- constexpr auto end_cursor() const noexcept(
- noexcept(view_adaptor::end_cursor_(std::declval<D const &>())))
- -> CPP_ret(decltype(view_adaptor::end_cursor_(std::declval<D const &>())))( //
- requires same_as<D, Derived> && range<base_range_t const>)
- {
- 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<BaseRng &&>(rng)))
- {}
- constexpr base_range_t & base() noexcept
- {
- return rng_;
- }
- /// \overload
- constexpr base_range_t const & base() const noexcept
- {
- return rng_;
- }
- };
-
- /// @}
- } // namespace ranges
-
- #endif
|