axmol/thirdparty/range-v3/include/range/v3/view/join.hpp

650 lines
23 KiB
C++

/// \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_JOIN_HPP
#define RANGES_V3_VIEW_JOIN_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/range_for.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/utility/variant.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/view/single.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
// Compute the cardinality of a joined range
constexpr cardinality join_cardinality_(
cardinality Outer, cardinality Inner,
cardinality Joiner = static_cast<cardinality>(0)) noexcept
{
return Outer == infinite || Inner == infinite ||
(Joiner == infinite && Outer != 0 && Outer != 1)
? infinite
: Outer == unknown || Inner == unknown ||
(Joiner == unknown && Outer != 0 && Outer != 1)
? unknown
: Outer == finite || Inner == finite ||
(Joiner == finite && Outer != 0 && Outer != 1)
? finite
: static_cast<cardinality>(
Outer * Inner +
(Outer == 0 ? 0 : (Outer - 1) * Joiner));
}
template<typename Range>
constexpr cardinality join_cardinality() noexcept
{
return detail::join_cardinality_(
range_cardinality<Range>::value,
range_cardinality<range_reference_t<Range>>::value);
}
template<typename Range, typename JoinRange>
constexpr cardinality join_cardinality() noexcept
{
return detail::join_cardinality_(
range_cardinality<Range>::value,
range_cardinality<range_reference_t<Range>>::value,
range_cardinality<JoinRange>::value);
}
template<typename Inner>
struct store_inner_
{
non_propagating_cache<std::remove_cv_t<Inner>> inner_ = {};
template<typename OuterIt>
constexpr auto && update_inner_(OuterIt && it)
{
return inner_.emplace_deref(it);
}
constexpr Inner & get_inner_(ignore_t) noexcept
{
return *inner_;
}
};
struct pass_thru_inner_
{
// Intentionally promote xvalues to lvalues here:
template<typename OuterIt>
static constexpr auto && update_inner_(OuterIt && it) noexcept
{
return *it;
}
template<typename OuterIt>
static constexpr decltype(auto) get_inner_(OuterIt && outer_it)
{
return *outer_it;
}
};
template<typename Rng>
using join_view_inner =
meta::conditional_t<!std::is_reference<range_reference_t<Rng>>::value,
store_inner_<range_reference_t<Rng>>, pass_thru_inner_>;
// clang-format off
/// \concept has_member_arrow_
/// \brief The \c has_member_arrow_ concept
template<typename I>
CPP_requires(has_member_arrow_,
requires(I i) //
(
i.operator->()
));
/// \concept has_arrow_
/// \brief The \c has_arrow_ concept
template<typename I>
CPP_concept has_arrow_ =
input_iterator<I> &&
(std::is_pointer<I>::value || CPP_requires_ref(detail::has_member_arrow_, I));
// clang-format on
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
// Join a range of ranges
template<typename Rng>
struct RANGES_EMPTY_BASES join_view
: view_facade<join_view<Rng>, detail::join_cardinality<Rng>()>
, private detail::join_view_inner<Rng>
{
CPP_assert(input_range<Rng> && view_<Rng>);
CPP_assert(input_range<range_reference_t<Rng>>);
join_view() = default;
explicit join_view(Rng rng)
: outer_(views::all(std::move(rng)))
{}
// Not to spec
CPP_member
static constexpr auto size() //
-> CPP_ret(std::size_t)(
requires (detail::join_cardinality<Rng>() >= 0))
{
return static_cast<std::size_t>(detail::join_cardinality<Rng>());
}
// Not to spec
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires(detail::join_cardinality<Rng>() < 0) &&
(range_cardinality<Rng>::value >= 0) &&
forward_range<Rng> &&
sized_range<range_reference_t<Rng>>)
{
range_size_t<range_reference_t<Rng>> n = 0;
RANGES_FOR(auto && inner, outer_)
n += ranges::size(inner);
return n;
}
// // ericniebler/stl2#605
constexpr Rng base() const
{
return outer_;
}
private:
friend range_access;
Rng outer_{};
template<bool Const>
struct cursor
{
private:
using Parent = meta::conditional_t<Const, join_view const, join_view>;
using COuter = meta::conditional_t<Const, Rng const, Rng>;
using CInner = range_reference_t<COuter>;
using ref_is_glvalue = std::is_reference<CInner>;
Parent * rng_ = nullptr;
iterator_t<COuter> outer_it_{};
iterator_t<CInner> inner_it_{};
void satisfy()
{
for(; outer_it_ != ranges::end(rng_->outer_); ++outer_it_)
{
auto && inner = rng_->update_inner_(outer_it_);
inner_it_ = ranges::begin(inner);
if(inner_it_ != ranges::end(inner))
return;
}
if(RANGES_CONSTEXPR_IF(ref_is_glvalue::value))
inner_it_ = iterator_t<CInner>();
}
public:
using single_pass = meta::bool_<single_pass_iterator_<iterator_t<COuter>> ||
single_pass_iterator_<iterator_t<CInner>> ||
!ref_is_glvalue::value>;
cursor() = default;
template<typename BeginOrEnd>
constexpr cursor(Parent * rng, BeginOrEnd begin_or_end)
: rng_{rng}
, outer_it_(begin_or_end(rng->outer_))
{
satisfy();
}
template(bool Other)(
requires Const AND CPP_NOT(Other) AND
convertible_to<iterator_t<Rng>, iterator_t<COuter>> AND
convertible_to<iterator_t<range_reference_t<Rng>>,
iterator_t<CInner>>)
constexpr cursor(cursor<Other> that)
: rng_(that.rng_)
, outer_it_(std::move(that.outer_it_))
, inner_it_(std::move(that.inner_it_))
{}
CPP_member
constexpr auto arrow() //
-> CPP_ret(iterator_t<CInner>)(
requires detail::has_arrow_<iterator_t<CInner>>)
{
return inner_it_;
}
constexpr bool equal(default_sentinel_t) const
{
return outer_it_ == ranges::end(rng_->outer_);
}
CPP_member
constexpr auto equal(cursor const & that) const //
-> CPP_ret(bool)(
requires ref_is_glvalue::value && //
equality_comparable<iterator_t<COuter>> && //
equality_comparable<iterator_t<CInner>>)
{
return outer_it_ == that.outer_it_ && inner_it_ == that.inner_it_;
}
constexpr void next()
{
auto && inner_rng = rng_->get_inner_(outer_it_);
if(++inner_it_ == ranges::end(inner_rng))
{
++outer_it_;
satisfy();
}
}
CPP_member
constexpr auto prev() //
-> CPP_ret(void)(
requires ref_is_glvalue::value && //
bidirectional_range<COuter> && //
bidirectional_range<CInner> && //
common_range<CInner>) // ericniebler/stl2#606
{
if(outer_it_ == ranges::end(rng_->outer_))
inner_it_ = ranges::end(*--outer_it_);
while(inner_it_ == ranges::begin(*outer_it_))
inner_it_ = ranges::end(*--outer_it_);
--inner_it_;
}
// clang-format off
constexpr auto CPP_auto_fun(read)()(const)
(
return *inner_it_
)
constexpr auto CPP_auto_fun(move)()(const)
(
return iter_move(inner_it_)
)
// clang-format on
};
static constexpr bool use_const_always() noexcept
{
return simple_view<Rng>() && std::is_reference<range_reference_t<Rng>>::value;
}
struct end_cursor_fn
{
constexpr auto operator()(join_view * this_, std::true_type) const
{
return cursor<use_const_always()>{this_, ranges::end};
}
constexpr auto operator()(join_view *, std::false_type) const
{
return default_sentinel_t{};
}
};
struct cend_cursor_fn
{
constexpr auto operator()(join_view const * this_, std::true_type) const
{
return cursor<true>{this_, ranges::end};
}
constexpr auto operator()(join_view const *, std::false_type) const
{
return default_sentinel_t{};
}
};
constexpr cursor<use_const_always()> begin_cursor()
{
return {this, ranges::begin};
}
template(bool Const = true)(
requires Const AND input_range<meta::const_if_c<Const, Rng>> AND
std::is_reference<range_reference_t<meta::const_if_c<Const, Rng>>>::value)
constexpr cursor<Const> begin_cursor() const
{
return {this, ranges::begin};
}
constexpr auto end_cursor()
{
using cond =
meta::bool_<std::is_reference<range_reference_t<Rng>>::value &&
forward_range<Rng> && forward_range<range_reference_t<Rng>> &&
common_range<Rng> && common_range<range_reference_t<Rng>>>;
return end_cursor_fn{}(this, cond{});
}
template(bool Const = true)(
requires Const AND input_range<meta::const_if_c<Const, Rng>> AND
std::is_reference<range_reference_t<meta::const_if_c<Const, Rng>>>::value)
constexpr auto end_cursor() const
{
using CRng = meta::const_if_c<Const, Rng>;
using cond =
meta::bool_<std::is_reference<range_reference_t<CRng>>::value &&
forward_range<CRng> &&
forward_range<range_reference_t<CRng>> &&
common_range<CRng> && common_range<range_reference_t<CRng>>>;
return cend_cursor_fn{}(this, cond{});
}
};
// Join a range of ranges, inserting a range of values between them.
// TODO: Support const iteration when range_reference_t<Rng> is a true reference.
template<typename Rng, typename ValRng>
struct join_with_view
: view_facade<join_with_view<Rng, ValRng>, detail::join_cardinality<Rng, ValRng>()>
, private detail::join_view_inner<Rng>
{
CPP_assert(input_range<Rng>);
CPP_assert(input_range<range_reference_t<Rng>>);
CPP_assert(forward_range<ValRng>);
CPP_assert(
common_with<range_value_t<range_reference_t<Rng>>, range_value_t<ValRng>>);
CPP_assert(semiregular<common_type_t<range_value_t<range_reference_t<Rng>>,
range_value_t<ValRng>>>);
join_with_view() = default;
join_with_view(Rng rng, ValRng val)
: outer_(views::all(std::move(rng)))
, val_(views::all(std::move(val)))
{}
CPP_member
static constexpr auto size() //
-> CPP_ret(std::size_t)(
requires (detail::join_cardinality<Rng, ValRng>() >= 0))
{
return static_cast<std::size_t>(detail::join_cardinality<Rng, ValRng>());
}
CPP_auto_member
auto CPP_fun(size)()(const //
requires(detail::join_cardinality<Rng, ValRng>() < 0) &&
(range_cardinality<Rng>::value >= 0) && forward_range<Rng> &&
sized_range<range_reference_t<Rng>> && sized_range<ValRng>)
{
range_size_t<range_reference_t<Rng>> n = 0;
RANGES_FOR(auto && inner, outer_)
n += ranges::size(inner);
return n + (range_cardinality<Rng>::value == 0
? 0
: ranges::size(val_) * (range_cardinality<Rng>::value - 1));
}
private:
friend range_access;
using Outer = views::all_t<Rng>;
// Intentionally promote xvalues to lvalues here:
using Inner = views::all_t<range_reference_t<Outer> &>;
Outer outer_{};
views::all_t<ValRng> val_{};
class cursor
{
join_with_view * rng_ = nullptr;
iterator_t<Outer> outer_it_{};
variant<iterator_t<ValRng>, iterator_t<Inner>> cur_{};
void satisfy()
{
while(true)
{
if(cur_.index() == 0)
{
if(ranges::get<0>(cur_) != ranges::end(rng_->val_))
break;
// Intentionally promote xvalues to lvalues here:
auto && inner = rng_->update_inner_(outer_it_);
ranges::emplace<1>(cur_, ranges::begin(inner));
}
else
{
auto && inner = rng_->get_inner_(outer_it_);
if(ranges::get<1>(cur_) != ranges::end(inner))
break;
if(++outer_it_ == ranges::end(rng_->outer_))
break;
ranges::emplace<0>(cur_, ranges::begin(rng_->val_));
}
}
}
public:
using value_type = common_type_t<range_value_t<Inner>, range_value_t<ValRng>>;
using reference =
common_reference_t<range_reference_t<Inner>, range_reference_t<ValRng>>;
using rvalue_reference = common_reference_t<range_rvalue_reference_t<Inner>,
range_rvalue_reference_t<ValRng>>;
using single_pass = std::true_type;
cursor() = default;
cursor(join_with_view * rng)
: rng_{rng}
, outer_it_(ranges::begin(rng->outer_))
{
if(outer_it_ != ranges::end(rng->outer_))
{
auto && inner = rng_->update_inner_(outer_it_);
ranges::emplace<1>(cur_, ranges::begin(inner));
satisfy();
}
}
bool equal(default_sentinel_t) const
{
return outer_it_ == ranges::end(rng_->outer_);
}
void next()
{
// visit(cur_, [](auto& it){ ++it; });
if(cur_.index() == 0)
{
auto & it = ranges::get<0>(cur_);
RANGES_ASSERT(it != ranges::end(rng_->val_));
++it;
}
else
{
auto & it = ranges::get<1>(cur_);
#ifndef NDEBUG
auto && inner = rng_->get_inner_(outer_it_);
RANGES_ASSERT(it != ranges::end(inner));
#endif
++it;
}
satisfy();
}
reference read() const
{
// return visit(cur_, [](auto& it) -> reference { return *it; });
if(cur_.index() == 0)
return *ranges::get<0>(cur_);
else
return *ranges::get<1>(cur_);
}
rvalue_reference move() const
{
// return visit(cur_, [](auto& it) -> rvalue_reference { return
// iter_move(it); });
if(cur_.index() == 0)
return iter_move(ranges::get<0>(cur_));
else
return iter_move(ranges::get<1>(cur_));
}
};
cursor begin_cursor()
{
return {this};
}
};
namespace views
{
/// \cond
// Don't forget to update views::for_each whenever this set
// of concepts changes
// clang-format off
/// \concept joinable_range_
/// \brief The \c joinable_range_ concept
template(typename Rng)(
concept (joinable_range_)(Rng),
input_range<range_reference_t<Rng>>
);
/// \concept joinable_range
/// \brief The \c joinable_range concept
template<typename Rng>
CPP_concept joinable_range =
viewable_range<Rng> && input_range<Rng> &&
CPP_concept_ref(views::joinable_range_, Rng);
/// \concept joinable_with_range_
/// \brief The \c joinable_with_range_ concept
template(typename Rng, typename ValRng)(
concept (joinable_with_range_)(Rng, ValRng),
common_with<
range_value_t<ValRng>,
range_value_t<range_reference_t<Rng>>> AND
semiregular<
common_type_t<
range_value_t<ValRng>,
range_value_t<range_reference_t<Rng>>>> AND
common_reference_with<
range_reference_t<ValRng>,
range_reference_t<range_reference_t<Rng>>> AND
common_reference_with<
range_rvalue_reference_t<ValRng>,
range_rvalue_reference_t<range_reference_t<Rng>>>
);
/// \concept joinable_with_range
/// \brief The \c joinable_with_range concept
template<typename Rng, typename ValRng>
CPP_concept joinable_with_range =
joinable_range<Rng> &&
viewable_range<ValRng> && forward_range<ValRng> &&
CPP_concept_ref(views::joinable_with_range_, Rng, ValRng);
// clang-format on
/// \endcond
struct cpp20_join_fn
{
template(typename Rng)(
requires joinable_range<Rng>)
join_view<all_t<Rng>> operator()(Rng && rng) const
{
return join_view<all_t<Rng>>{all(static_cast<Rng &&>(rng))};
}
};
struct join_base_fn : cpp20_join_fn
{
private:
template<typename Rng>
using inner_value_t = range_value_t<range_reference_t<Rng>>;
public:
using cpp20_join_fn::operator();
template(typename Rng)(
requires joinable_with_range<Rng, single_view<inner_value_t<Rng>>>)
join_with_view<all_t<Rng>, single_view<inner_value_t<Rng>>> //
operator()(Rng && rng, inner_value_t<Rng> v) const
{
return {all(static_cast<Rng &&>(rng)), single(std::move(v))};
}
template(typename Rng, typename ValRng)(
requires joinable_with_range<Rng, ValRng>)
join_with_view<all_t<Rng>, all_t<ValRng>> //
operator()(Rng && rng, ValRng && val) const
{
return {all(static_cast<Rng &&>(rng)), all(static_cast<ValRng &&>(val))};
}
/// \cond
template<typename Rng, typename T>
invoke_result_t<join_base_fn, Rng, T &> //
operator()(Rng && rng, detail::reference_wrapper_<T> r) const
{
return (*this)(static_cast<Rng &&>(rng), r.get());
}
/// \endcond
};
struct join_bind_fn
{
template(typename T)(
requires (!joinable_range<T>)) // TODO: underconstrained
constexpr auto operator()(T && t)const
{
return make_view_closure(bind_back(join_base_fn{}, static_cast<T &&>(t)));
}
template(typename T)(
requires (!joinable_range<T &>) AND range<T &>)
constexpr auto operator()(T & t) const
{
return make_view_closure(bind_back(join_base_fn{},
detail::reference_wrapper_<T>(t)));
}
};
struct RANGES_EMPTY_BASES join_fn
: join_base_fn, join_bind_fn
{
using join_base_fn::operator();
using join_bind_fn::operator();
};
/// \relates join_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<join_fn>, join)
} // namespace views
/// @}
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng)(
requires views::joinable_range<Rng>)
explicit join_view(Rng &&)
->join_view<views::all_t<Rng>>;
template(typename Rng, typename ValRng)(
requires views::joinable_with_range<Rng, ValRng>)
explicit join_with_view(Rng &&, ValRng &&)
->join_with_view<views::all_t<Rng>, views::all_t<ValRng>>;
#endif
namespace cpp20
{
namespace views
{
RANGES_INLINE_VARIABLE(
ranges::views::view_closure<ranges::views::cpp20_join_fn>, join)
}
template(typename Rng)(
requires input_range<Rng> AND view_<Rng> AND
input_range<iter_reference_t<iterator_t<Rng>>>) //
using join_view = ranges::join_view<Rng>;
} // namespace cpp20
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::join_view)
RANGES_SATISFY_BOOST_RANGE(::ranges::join_with_view)
#endif