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