/// \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