init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
allhaileris
2026-02-16 15:50:16 +03:00
commit afb81b8278
13816 changed files with 3689732 additions and 0 deletions

View File

@@ -0,0 +1,575 @@
/// \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>
#include <range/v3/detail/prologue.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 always_<int, decltype(Adapt::read(std::declval<BaseIter const &>(),
adaptor_base_current_mem_fn{}))> //
which_adaptor_value_(priority_tag<1>)
{
return 1;
}
template<typename BaseIter, typename Adapt>
constexpr always_<int, typename Adapt::value_type> //
which_adaptor_value_(priority_tag<2>)
{
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 indirectly_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)(
requires equality_comparable<I>)
static bool equal(I const & it0, I const & it1)
{
return it0 == it1;
}
template(typename I)(
requires input_or_output_iterator<I>)
static iter_reference_t<I> read(I const & it,
detail::adaptor_base_current_mem_fn = {})
noexcept(noexcept(iter_reference_t<I>(*it)))
{
return *it;
}
template(typename I)(
requires input_or_output_iterator<I>)
static void next(I & it)
{
++it;
}
template(typename I)(
requires bidirectional_iterator<I>)
static void prev(I & it)
{
--it;
}
template(typename I)(
requires random_access_iterator<I>)
static void advance(I & it, iter_difference_t<I> n)
{
it += n;
}
template(typename I)(
requires sized_sentinel_for<I, I>)
static iter_difference_t<I> distance_to(I const & it0, I const & it1)
{
return it1 - it0;
}
template(typename I, typename S)(
requires sentinel_for<S, I>)
static constexpr bool empty(I const & it, S const & last)
{
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;
#ifndef _MSC_VER
using basic_mixin<adaptor_cursor>::basic_mixin;
#else
constexpr explicit basic_adaptor_mixin(adaptor_cursor && cur)
: basic_mixin<adaptor_cursor>(static_cast<adaptor_cursor &&>(cur))
{}
constexpr explicit basic_adaptor_mixin(adaptor_cursor const & cur)
: basic_mixin<adaptor_cursor>(cur)
{}
#endif
// 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)(
requires //
(!same_as<adaptor_cursor<OtherIter, OtherAdapt>, adaptor_cursor>) AND
convertible_to<OtherIter, BaseIter> AND
convertible_to<OtherAdapt, Adapt>)
adaptor_cursor(adaptor_cursor<OtherIter, OtherAdapt> that)
: 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)(
requires same_as<D, Derived>)
constexpr auto begin_cursor() noexcept(
noexcept(view_adaptor::begin_cursor_(std::declval<D &>())))
-> decltype(view_adaptor::begin_cursor_(std::declval<D &>()))
{
return view_adaptor::begin_cursor_(derived());
}
template(typename D = Derived)(
requires same_as<D, Derived> AND range<base_range_t const>)
constexpr auto begin_cursor() const
noexcept(noexcept(view_adaptor::begin_cursor_(std::declval<D const &>())))
-> decltype(view_adaptor::begin_cursor_(std::declval<D 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)(
requires same_as<D, Derived>)
constexpr auto end_cursor() noexcept(
noexcept(view_adaptor::end_cursor_(std::declval<D &>())))
-> decltype(view_adaptor::end_cursor_(std::declval<D &>()))
{
return view_adaptor::end_cursor_(derived());
}
template(typename D = Derived)(
requires same_as<D, Derived> AND range<base_range_t const>)
constexpr auto end_cursor() const noexcept(
noexcept(view_adaptor::end_cursor_(std::declval<D const &>())))
-> decltype(view_adaptor::end_cursor_(std::declval<D 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;
constexpr explicit 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
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,65 @@
/// \file
// Range v3 library
//
// Copyright Andrey Diduh 2019
//
// 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_ADDRESSOF_HPP
#define RANGES_V3_VIEW_ADDRESSOF_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/utility/addressof.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
namespace views
{
struct addressof_fn
{
private:
struct take_address
{
template<typename V>
constexpr V * operator()(V & value) const noexcept
{
return detail::addressof(value);
}
};
public:
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng> AND
std::is_lvalue_reference<range_reference_t<Rng>>::value) //
constexpr auto CPP_auto_fun(operator())(Rng && rng)(const) //
(
return transform(all(static_cast<Rng &&>(rng)), take_address{}) //
)
};
/// \relates addressof_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<addressof_fn>, addressof)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_VIEW_ADDRESSOF_HPP

View File

@@ -0,0 +1,189 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_ADJACENT_FILTER_HPP
#define RANGES_V3_VIEW_ADJACENT_FILTER_HPP
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/algorithm/adjacent_find.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
// clang-format off
/// \concept adjacent_filter_constraints_
/// \brief The \c adjacent_filter_constraints_ concept
template(typename Rng, typename Pred)(
concept (adjacent_filter_constraints_)(Rng, Pred),
indirect_binary_predicate_<Pred, iterator_t<Rng>, iterator_t<Rng>>
);
/// \concept adjacent_filter_constraints
/// \brief The \c adjacent_filter_constraints concept
template<typename Rng, typename Pred>
CPP_concept adjacent_filter_constraints =
viewable_range<Rng> && forward_range<Rng> &&
CPP_concept_ref(detail::adjacent_filter_constraints_, Rng, Pred);
// clang-format on
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
template<typename Rng, typename Pred>
struct RANGES_EMPTY_BASES adjacent_filter_view
: view_adaptor<adjacent_filter_view<Rng, Pred>, Rng,
is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
, private box<semiregular_box_t<Pred>, adjacent_filter_view<Rng, Pred>>
{
private:
friend range_access;
template<bool Const>
struct adaptor : adaptor_base
{
private:
friend struct adaptor<!Const>;
using CRng = meta::const_if_c<Const, Rng>;
using Parent = meta::const_if_c<Const, adjacent_filter_view>;
Parent * rng_;
public:
adaptor() = default;
constexpr adaptor(Parent * rng) noexcept
: rng_(rng)
{}
template(bool Other)(
requires Const && CPP_NOT(Other)) //
constexpr adaptor(adaptor<Other> that)
: rng_(that.rng_)
{}
constexpr void next(iterator_t<CRng> & it) const
{
auto const last = ranges::end(rng_->base());
auto & pred = rng_->adjacent_filter_view::box::get();
RANGES_EXPECT(it != last);
for(auto tmp = it; ++it != last; tmp = it)
if(invoke(pred, *tmp, *it))
break;
}
CPP_member
constexpr auto prev(iterator_t<CRng> & it) const //
-> CPP_ret(void)(
requires bidirectional_range<CRng>)
{
auto const first = ranges::begin(rng_->base());
auto & pred = rng_->adjacent_filter_view::box::get();
RANGES_EXPECT(it != first);
--it;
while(it != first)
{
auto tmp = it;
if(invoke(pred, *--tmp, *it))
break;
it = tmp;
}
}
void distance_to() = delete;
};
constexpr adaptor<false> begin_adaptor() noexcept
{
return {this};
}
CPP_member
constexpr auto begin_adaptor() const noexcept //
-> CPP_ret(adaptor<true>)(
requires detail::adjacent_filter_constraints<Rng const, Pred const>)
{
return {this};
}
constexpr adaptor<false> end_adaptor() noexcept
{
return {this};
}
CPP_member
constexpr auto end_adaptor() const noexcept //
-> CPP_ret(adaptor<true>)(
requires detail::adjacent_filter_constraints<Rng const, Pred const>)
{
return {this};
}
public:
adjacent_filter_view() = default;
constexpr adjacent_filter_view(Rng rng, Pred pred)
: adjacent_filter_view::view_adaptor{detail::move(rng)}
, adjacent_filter_view::box(detail::move(pred))
{}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename Fun)(
requires copy_constructible<Rng>)
adjacent_filter_view(Rng &&, Fun)
->adjacent_filter_view<views::all_t<Rng>, Fun>;
#endif
namespace views
{
struct adjacent_filter_base_fn
{
template(typename Rng, typename Pred)(
requires detail::adjacent_filter_constraints<Rng, Pred>)
constexpr adjacent_filter_view<all_t<Rng>, Pred> //
operator()(Rng && rng, Pred pred) const
{
return {all(static_cast<Rng &&>(rng)), std::move(pred)};
}
};
struct adjacent_filter_fn : adjacent_filter_base_fn
{
using adjacent_filter_base_fn::operator();
template<typename Pred>
constexpr auto operator()(Pred pred) const
{
return make_view_closure(
bind_back(adjacent_filter_base_fn{}, std::move(pred)));
}
};
/// \relates adjacent_filter_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(adjacent_filter_fn, adjacent_filter)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::adjacent_filter_view)
#endif

View File

@@ -0,0 +1,186 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_ADJACENT_REMOVE_IF_HPP
#define RANGES_V3_VIEW_ADJACENT_REMOVE_IF_HPP
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/utility/box.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng, typename Pred>
struct RANGES_EMPTY_BASES adjacent_remove_if_view
: view_adaptor<adjacent_remove_if_view<Rng, Pred>, Rng,
is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
, private box<semiregular_box_t<Pred>, adjacent_remove_if_view<Rng, Pred>>
{
adjacent_remove_if_view() = default;
constexpr adjacent_remove_if_view(Rng rng, Pred pred)
: adjacent_remove_if_view::view_adaptor{detail::move(rng)}
, adjacent_remove_if_view::box(detail::move(pred))
{}
private:
friend range_access;
struct adaptor : adaptor_base
{
private:
adjacent_remove_if_view * rng_;
public:
adaptor() = default;
constexpr adaptor(adjacent_remove_if_view * rng) noexcept
: rng_(rng)
{}
static constexpr iterator_t<Rng> begin(adjacent_remove_if_view & rng)
{
return *rng.begin_;
}
constexpr void next(iterator_t<Rng> & it) const
{
RANGES_ASSERT(it != ranges::end(rng_->base()));
rng_->satisfy_forward(++it);
}
CPP_member
constexpr auto prev(iterator_t<Rng> & it) const //
-> CPP_ret(void)(
requires bidirectional_range<Rng>)
{
rng_->satisfy_reverse(it);
}
void advance() = delete;
void distance_to() = delete;
};
constexpr adaptor begin_adaptor()
{
cache_begin();
return {this};
}
CPP_member
constexpr auto end_adaptor() //
-> CPP_ret(adaptor)(
requires common_range<Rng>)
{
if(bidirectional_range<Rng>)
cache_begin();
return {this};
}
CPP_member
constexpr auto end_adaptor() noexcept //
-> CPP_ret(adaptor_base)(
requires (!common_range<Rng>))
{
return {};
}
constexpr void satisfy_forward(iterator_t<Rng> & it)
{
auto const last = ranges::end(this->base());
if(it == last)
return;
auto & pred = this->adjacent_remove_if_view::box::get();
for(auto nxt = it; ++nxt != last && invoke(pred, *it, *nxt); it = nxt)
;
}
constexpr void satisfy_reverse(iterator_t<Rng> & it)
{
auto const & first = *begin_;
RANGES_ASSERT(it != first);
(void)first;
auto prv = it;
--it;
if(prv == ranges::end(this->base()))
{
return;
}
auto & pred = this->adjacent_remove_if_view::box::get();
for(; invoke(pred, *it, *prv); prv = it, --it)
RANGES_ASSERT(it != first);
}
void cache_begin()
{
if(begin_)
return;
auto it = ranges::begin(this->base());
satisfy_forward(it);
begin_.emplace(std::move(it));
}
detail::non_propagating_cache<iterator_t<Rng>> begin_;
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename Fun)(
requires copy_constructible<Rng>)
adjacent_remove_if_view(Rng &&, Fun)
-> adjacent_remove_if_view<views::all_t<Rng>, Fun>;
#endif
namespace views
{
struct adjacent_remove_if_base_fn
{
template(typename Rng, typename Pred)(
requires viewable_range<Rng> AND forward_range<Rng> AND
indirect_binary_predicate_<Pred, iterator_t<Rng>, iterator_t<Rng>>)
constexpr adjacent_remove_if_view<all_t<Rng>, Pred> //
operator()(Rng && rng, Pred pred) const
{
return {all(static_cast<Rng &&>(rng)), std::move(pred)};
}
};
struct adjacent_remove_if_fn : adjacent_remove_if_base_fn
{
using adjacent_remove_if_base_fn::operator();
template<typename Pred>
constexpr auto operator()(Pred pred) const
{
return make_view_closure(
bind_back(adjacent_remove_if_base_fn{}, std::move(pred)));
}
};
/// \relates adjacent_remove_if_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(adjacent_remove_if_fn, adjacent_remove_if)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::adjacent_remove_if_view)
#endif

View File

@@ -0,0 +1,126 @@
/// \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_ALL_HPP
#define RANGES_V3_VIEW_ALL_HPP
#include <type_traits>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/ref.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
namespace views
{
struct all_fn
{
private:
/// If it's a view already, pass it though.
template<typename T>
static constexpr auto from_range_(T && t, std::true_type, detail::ignore_t,
detail::ignore_t)
{
return static_cast<T &&>(t);
}
/// If it is container-like, turn it into a view, being careful
/// to preserve the Sized-ness of the range.
template<typename T>
static constexpr auto from_range_(T && t, std::false_type, std::true_type,
detail::ignore_t)
{
return ranges::views::ref(t);
}
/// Not a view and not an lvalue? If it's a borrowed_range, then
/// return a subrange holding the range's begin/end.
template<typename T>
static constexpr auto from_range_(T && t, std::false_type, std::false_type,
std::true_type)
{
return make_subrange(static_cast<T &&>(t));
}
public:
template(typename T)(
requires range<T &> AND viewable_range<T>)
constexpr auto operator()(T && t) const
{
return all_fn::from_range_(static_cast<T &&>(t),
meta::bool_<view_<uncvref_t<T>>>{},
std::is_lvalue_reference<T>{},
meta::bool_<borrowed_range<T>>{});
}
template<typename T>
RANGES_DEPRECATED("Passing a reference_wrapper to views::all is deprecated.")
constexpr ref_view<T> operator()(std::reference_wrapper<T> r) const
{
return ranges::views::ref(r.get());
}
};
/// \relates all_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<all_fn>, all)
template<typename Rng>
using all_t = decltype(all(std::declval<Rng>()));
} // namespace views
template<typename Rng>
struct identity_adaptor : Rng
{
CPP_assert(view_<Rng>);
identity_adaptor() = default;
constexpr explicit identity_adaptor(Rng const & rng)
: Rng(rng)
{}
constexpr explicit identity_adaptor(Rng && rng)
: Rng(detail::move(rng))
{}
};
namespace cpp20
{
namespace views
{
using ranges::views::all;
using ranges::views::all_t;
}
template(typename Rng)(
requires viewable_range<Rng>)
using all_view RANGES_DEPRECATED(
"Please use ranges::cpp20::views::all_t instead.") =
ranges::views::all_t<Rng>;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,692 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2014-present
// Copyright Casey Carter 2017
//
// 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_ANY_VIEW_HPP
#define RANGES_V3_VIEW_ANY_VIEW_HPP
#include <type_traits>
#include <typeinfo>
#include <utility>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/addressof.hpp>
#include <range/v3/utility/memory.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/detail/prologue.hpp>
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_INCONSISTENT_OVERRIDE
RANGES_DIAGNOSTIC_SUGGEST_OVERRIDE
namespace ranges
{
/// \brief An enum that denotes the supported subset of range concepts supported by a
/// range.
enum class category
{
none = 0, ///<\brief No concepts met.
input = 1, ///<\brief satisfies ranges::concepts::input_range
forward = 3, ///<\brief satisfies ranges::concepts::forward_range
bidirectional = 7, ///<\brief satisfies ranges::concepts::bidirectional_range
random_access = 15, ///<\brief satisfies ranges::concepts::random_access_range
mask = random_access, ///<\brief Mask away any properties other than iterator
///< category
sized = 16, ///<\brief satisfies ranges::concepts::sized_range
};
/** \name Binary operators for ranges::category
* \relates ranges::category
* \{
*/
constexpr category operator&(category lhs, category rhs) noexcept
{
return static_cast<category>(
static_cast<meta::_t<std::underlying_type<category>>>(lhs) &
static_cast<meta::_t<std::underlying_type<category>>>(rhs));
}
constexpr category operator|(category lhs, category rhs) noexcept
{
return static_cast<category>(
static_cast<meta::_t<std::underlying_type<category>>>(lhs) |
static_cast<meta::_t<std::underlying_type<category>>>(rhs));
}
constexpr category operator^(category lhs, category rhs) noexcept
{
return static_cast<category>(
static_cast<meta::_t<std::underlying_type<category>>>(lhs) ^
static_cast<meta::_t<std::underlying_type<category>>>(rhs));
}
constexpr category operator~(category lhs) noexcept
{
return static_cast<category>(
~static_cast<meta::_t<std::underlying_type<category>>>(lhs));
}
constexpr category & operator&=(category & lhs, category rhs) noexcept
{
return (lhs = lhs & rhs);
}
constexpr category & operator|=(category & lhs, category rhs) noexcept
{
return (lhs = lhs | rhs);
}
constexpr category & operator^=(category & lhs, category rhs) noexcept
{
return (lhs = lhs ^ rhs);
}
//!\}
/// \brief For a given range, return a ranges::category enum with the satisfied
/// concepts.
template<typename Rng>
constexpr category get_categories() noexcept
{
return (input_range<Rng> ? category::input : category::none) |
(forward_range<Rng> ? category::forward : category::none) |
(bidirectional_range<Rng> ? category::bidirectional : category::none) |
(random_access_range<Rng> ? category::random_access : category::none) |
(sized_range<Rng> ? category::sized : category::none);
}
/// \cond
namespace detail
{
// workaround the fact that typeid ignores cv-qualifiers
template<typename>
struct rtti_tag
{};
struct any_ref
{
any_ref() = default;
template<typename T>
constexpr any_ref(T & obj) noexcept
: obj_(detail::addressof(obj))
#ifndef NDEBUG
, info_(&typeid(rtti_tag<T>))
#endif
{}
template<typename T>
T & get() const noexcept
{
RANGES_ASSERT(obj_ && info_ && *info_ == typeid(rtti_tag<T>));
return *const_cast<T *>(static_cast<T const volatile *>(obj_));
}
private:
void const volatile * obj_ = nullptr;
#ifndef NDEBUG
std::type_info const * info_ = nullptr;
#endif
};
template<typename Base>
struct cloneable : Base
{
using Base::Base;
virtual ~cloneable() override = default;
cloneable() = default;
cloneable(cloneable const &) = delete;
cloneable & operator=(cloneable const &) = delete;
virtual std::unique_ptr<cloneable> clone() const = 0;
};
// clang-format off
/// \concept any_compatible_range_
/// \brief The \c any_compatible_range_ concept
template(typename Rng, typename Ref)(
concept (any_compatible_range_)(Rng, Ref),
convertible_to<range_reference_t<Rng>, Ref>
);
/// \concept any_compatible_range
/// \brief The \c any_compatible_range concept
template<typename Rng, typename Ref>
CPP_concept any_compatible_range =
CPP_concept_ref(detail::any_compatible_range_, Rng, Ref);
// clang-format on
template<typename Rng, typename = void>
struct any_view_sentinel_impl
: private box<sentinel_t<Rng>, any_view_sentinel_impl<Rng>>
{
private:
using box_t = typename any_view_sentinel_impl::box;
public:
any_view_sentinel_impl() = default;
any_view_sentinel_impl(Rng & rng)
: box_t(ranges::end(rng))
{}
void init(Rng & rng) noexcept
{
box_t::get() = ranges::end(rng);
}
sentinel_t<Rng> const & get(Rng &) const noexcept
{
return box_t::get();
}
};
template<typename Rng>
struct any_view_sentinel_impl<
Rng, meta::void_<decltype(ranges::end(std::declval<Rng const &>()))>>
{
any_view_sentinel_impl() = default;
any_view_sentinel_impl(Rng &) noexcept
{}
void init(Rng &) noexcept
{}
sentinel_t<Rng> get(Rng & rng) const noexcept
{
return ranges::end(rng);
}
};
template<typename Ref, bool Sized = false>
struct any_input_view_interface
{
virtual ~any_input_view_interface() = default;
virtual void init() = 0;
virtual bool done() = 0;
virtual Ref read() const = 0;
virtual void next() = 0;
};
template<typename Ref>
struct any_input_view_interface<Ref, true> : any_input_view_interface<Ref, false>
{
virtual std::size_t size() = 0;
};
template<typename Ref>
struct any_input_cursor
{
using single_pass = std::true_type;
any_input_cursor() = default;
constexpr any_input_cursor(any_input_view_interface<Ref> & view) noexcept
: view_{detail::addressof(view)}
{}
Ref read() const
{
return view_->read();
}
void next()
{
view_->next();
}
bool equal(any_input_cursor const &) const noexcept
{
return true;
}
bool equal(default_sentinel_t) const
{
return !view_ || view_->done();
}
private:
any_input_view_interface<Ref> * view_ = nullptr;
};
template<typename Rng, typename Ref, bool Sized = false>
struct RANGES_EMPTY_BASES any_input_view_impl
: any_input_view_interface<Ref, Sized>
, private any_view_sentinel_impl<Rng>
{
CPP_assert(any_compatible_range<Rng, Ref>);
CPP_assert(!Sized || (bool)sized_range<Rng>);
explicit any_input_view_impl(Rng rng)
: rng_{std::move(rng)}
{}
any_input_view_impl(any_input_view_impl const &) = delete;
any_input_view_impl & operator=(any_input_view_impl const &) = delete;
private:
using sentinel_box_t = any_view_sentinel_impl<Rng>;
virtual void init() override
{
sentinel_box_t::init(rng_);
current_ = ranges::begin(rng_);
}
virtual bool done() override
{
return current_ == sentinel_box_t::get(rng_);
}
virtual Ref read() const override
{
return *current_;
}
virtual void next() override
{
++current_;
}
std::size_t size() // override-ish
{
return static_cast<std::size_t>(ranges::size(rng_));
}
RANGES_NO_UNIQUE_ADDRESS Rng rng_;
RANGES_NO_UNIQUE_ADDRESS iterator_t<Rng> current_{};
};
template<typename Ref, category Cat = category::forward, typename enable = void>
struct any_cursor_interface;
template<typename Ref, category Cat>
struct any_cursor_interface<
Ref, Cat, meta::if_c<(Cat & category::mask) == category::forward>>
{
virtual ~any_cursor_interface() = default;
virtual any_ref iter()
const = 0; // returns a const ref to the cursor's wrapped iterator
virtual Ref read() const = 0;
virtual bool equal(any_cursor_interface const &) const = 0;
virtual void next() = 0;
};
template<typename Ref, category Cat>
struct any_cursor_interface<
Ref, Cat, meta::if_c<(Cat & category::mask) == category::bidirectional>>
: any_cursor_interface<Ref, (Cat & ~category::mask) | category::forward>
{
virtual void prev() = 0;
};
template<typename Ref, category Cat>
struct any_cursor_interface<
Ref, Cat, meta::if_c<(Cat & category::mask) == category::random_access>>
: any_cursor_interface<Ref, (Cat & ~category::mask) | category::bidirectional>
{
virtual void advance(std::ptrdiff_t) = 0;
virtual std::ptrdiff_t distance_to(any_cursor_interface const &) const = 0;
};
template<typename Ref, category Cat>
using any_cloneable_cursor_interface = cloneable<any_cursor_interface<Ref, Cat>>;
template<typename I, typename Ref, category Cat>
struct any_cursor_impl : any_cloneable_cursor_interface<Ref, Cat>
{
CPP_assert(convertible_to<iter_reference_t<I>, Ref>);
CPP_assert((Cat & category::forward) == category::forward);
any_cursor_impl() = default;
any_cursor_impl(I it)
: it_{std::move(it)}
{}
private:
using Forward =
any_cursor_interface<Ref, (Cat & ~category::mask) | category::forward>;
I it_;
any_ref iter() const override
{
return it_;
}
Ref read() const override
{
return *it_;
}
bool equal(Forward const & that_) const override
{
auto & that = polymorphic_downcast<any_cursor_impl const &>(that_);
return that.it_ == it_;
}
void next() override
{
++it_;
}
std::unique_ptr<any_cloneable_cursor_interface<Ref, Cat>> clone()
const override
{
return detail::make_unique<any_cursor_impl>(it_);
}
void prev() // override (sometimes; it's complicated)
{
--it_;
}
void advance(std::ptrdiff_t n) // override-ish
{
it_ += n;
}
std::ptrdiff_t distance_to(
any_cursor_interface<Ref, Cat> const & that_) const // override-ish
{
auto & that = polymorphic_downcast<any_cursor_impl const &>(that_);
return static_cast<std::ptrdiff_t>(that.it_ - it_);
}
};
struct fully_erased_view
{
virtual bool at_end(
any_ref) = 0; // any_ref is a const ref to a wrapped iterator
// to be compared to the erased view's last sentinel
protected:
~fully_erased_view() = default;
};
struct any_sentinel
{
any_sentinel() = default;
constexpr explicit any_sentinel(fully_erased_view & view) noexcept
: view_{&view}
{}
private:
template<typename, category>
friend struct any_cursor;
fully_erased_view * view_ = nullptr;
};
template<typename Ref, category Cat>
struct any_cursor
{
private:
CPP_assert((Cat & category::forward) == category::forward);
std::unique_ptr<any_cloneable_cursor_interface<Ref, Cat>> ptr_;
template<typename Rng>
using impl_t = any_cursor_impl<iterator_t<Rng>, Ref, Cat>;
public:
any_cursor() = default;
template(typename Rng)(
requires (!same_as<detail::decay_t<Rng>, any_cursor>) AND
forward_range<Rng> AND
any_compatible_range<Rng, Ref>)
explicit any_cursor(Rng && rng)
: ptr_{detail::make_unique<impl_t<Rng>>(begin(rng))}
{}
any_cursor(any_cursor &&) = default;
any_cursor(any_cursor const & that)
: ptr_{that.ptr_ ? that.ptr_->clone() : nullptr}
{}
any_cursor & operator=(any_cursor &&) = default;
any_cursor & operator=(any_cursor const & that)
{
ptr_ = (that.ptr_ ? that.ptr_->clone() : nullptr);
return *this;
}
Ref read() const
{
RANGES_EXPECT(ptr_);
return ptr_->read();
}
bool equal(any_cursor const & that) const
{
RANGES_EXPECT(!ptr_ == !that.ptr_);
return !ptr_ || ptr_->equal(*that.ptr_);
}
bool equal(any_sentinel const & that) const
{
RANGES_EXPECT(!ptr_ == !that.view_);
return !ptr_ || that.view_->at_end(ptr_->iter());
}
void next()
{
RANGES_EXPECT(ptr_);
ptr_->next();
}
CPP_member
auto prev() //
-> CPP_ret(void)(
requires (category::bidirectional == (Cat & category::bidirectional)))
{
RANGES_EXPECT(ptr_);
ptr_->prev();
}
CPP_member
auto advance(std::ptrdiff_t n) //
-> CPP_ret(void)(
requires (category::random_access == (Cat & category::random_access)))
{
RANGES_EXPECT(ptr_);
ptr_->advance(n);
}
CPP_member
auto distance_to(any_cursor const & that) const //
-> CPP_ret(std::ptrdiff_t)(
requires (category::random_access == (Cat & category::random_access)))
{
RANGES_EXPECT(!ptr_ == !that.ptr_);
return !ptr_ ? 0 : ptr_->distance_to(*that.ptr_);
}
};
template<typename Ref, category Cat,
bool = (Cat & category::sized) == category::sized>
struct any_view_interface : fully_erased_view
{
CPP_assert((Cat & category::forward) == category::forward);
virtual ~any_view_interface() = default;
virtual any_cursor<Ref, Cat> begin_cursor() = 0;
};
template<typename Ref, category Cat>
struct any_view_interface<Ref, Cat, true> : any_view_interface<Ref, Cat, false>
{
virtual std::size_t size() = 0;
};
template<typename Ref, category Cat>
using any_cloneable_view_interface = cloneable<any_view_interface<Ref, Cat>>;
template<typename Rng, typename Ref, category Cat>
struct RANGES_EMPTY_BASES any_view_impl
: any_cloneable_view_interface<Ref, Cat>
, private box<Rng, any_view_impl<Rng, Ref, Cat>>
, private any_view_sentinel_impl<Rng>
{
CPP_assert((Cat & category::forward) == category::forward);
CPP_assert(any_compatible_range<Rng, Ref>);
CPP_assert((Cat & category::sized) == category::none ||
(bool)sized_range<Rng>);
any_view_impl() = default;
any_view_impl(Rng rng)
: range_box_t{std::move(rng)}
, sentinel_box_t{range_box_t::get()}
// NB: initialization order dependence
{}
private:
using range_box_t = box<Rng, any_view_impl>;
using sentinel_box_t = any_view_sentinel_impl<Rng>;
any_cursor<Ref, Cat> begin_cursor() override
{
return any_cursor<Ref, Cat>{range_box_t::get()};
}
bool at_end(any_ref it_) override
{
auto & it = it_.get<iterator_t<Rng> const>();
return it == sentinel_box_t::get(range_box_t::get());
}
std::unique_ptr<any_cloneable_view_interface<Ref, Cat>> clone() const override
{
return detail::make_unique<any_view_impl>(range_box_t::get());
}
std::size_t size() // override-ish
{
return static_cast<std::size_t>(ranges::size(range_box_t::get()));
}
};
} // namespace detail
/// \endcond
/// \brief A type-erased view
/// \ingroup group-views
template<typename Ref, category Cat = category::input, typename enable = void>
struct any_view
: view_facade<any_view<Ref, Cat>,
(Cat & category::sized) == category::sized ? finite : unknown>
{
friend range_access;
CPP_assert((Cat & category::forward) == category::forward);
any_view() = default;
template(typename Rng)(
requires //
(!same_as<detail::decay_t<Rng>, any_view>) AND
input_range<Rng> AND
detail::any_compatible_range<Rng, Ref>)
any_view(Rng && rng)
: any_view(static_cast<Rng &&>(rng),
meta::bool_<(get_categories<Rng>() & Cat) == Cat>{})
{}
any_view(any_view &&) = default;
any_view(any_view const & that)
: ptr_{that.ptr_ ? that.ptr_->clone() : nullptr}
{}
any_view & operator=(any_view &&) = default;
any_view & operator=(any_view const & that)
{
ptr_ = (that.ptr_ ? that.ptr_->clone() : nullptr);
return *this;
}
CPP_member
auto size() //
-> CPP_ret(std::size_t)(
requires (category::sized == (Cat & category::sized)))
{
return ptr_ ? ptr_->size() : 0;
}
private:
template<typename Rng>
using impl_t = detail::any_view_impl<views::all_t<Rng>, Ref, Cat>;
template<typename Rng>
any_view(Rng && rng, std::true_type)
: ptr_{detail::make_unique<impl_t<Rng>>(views::all(static_cast<Rng &&>(rng)))}
{}
template<typename Rng>
any_view(Rng &&, std::false_type)
{
static_assert(
(get_categories<Rng>() & Cat) == Cat,
"The range passed to any_view() does not model the requested category");
}
detail::any_cursor<Ref, Cat> begin_cursor()
{
return ptr_ ? ptr_->begin_cursor() : detail::value_init{};
}
detail::any_sentinel end_cursor() noexcept
{
return detail::any_sentinel{*ptr_};
}
std::unique_ptr<detail::any_cloneable_view_interface<Ref, Cat>> ptr_;
};
// input and not forward
template<typename Ref, category Cat>
struct any_view<Ref, Cat, meta::if_c<(Cat & category::forward) == category::input>>
: view_facade<any_view<Ref, Cat, void>,
(Cat & category::sized) == category::sized ? finite : unknown>
{
friend range_access;
any_view() = default;
template(typename Rng)(
requires //
(!same_as<detail::decay_t<Rng>, any_view>) AND
input_range<Rng> AND
detail::any_compatible_range<Rng, Ref>)
any_view(Rng && rng)
: ptr_{std::make_shared<impl_t<Rng>>(views::all(static_cast<Rng &&>(rng)))}
{}
CPP_member
auto size() //
-> CPP_ret(std::size_t)(
requires (category::sized == (Cat & category::sized)))
{
return ptr_ ? ptr_->size() : 0;
}
private:
template<typename Rng>
using impl_t =
detail::any_input_view_impl<views::all_t<Rng>, Ref,
(Cat & category::sized) == category::sized>;
detail::any_input_cursor<Ref> begin_cursor()
{
if(!ptr_)
return {};
ptr_->init();
return detail::any_input_cursor<Ref>{*ptr_};
}
std::shared_ptr<detail::any_input_view_interface<Ref, (Cat & category::sized) ==
category::sized>>
ptr_;
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng)(
requires view_<Rng>)
any_view(Rng &&)
->any_view<range_reference_t<Rng>, get_categories<Rng>()>;
#endif
template<typename Ref>
using any_input_view RANGES_DEPRECATED(
"Use any_view<Ref, category::input> instead.") = any_view<Ref, category::input>;
template<typename Ref>
using any_forward_view RANGES_DEPRECATED(
"Use any_view<Ref, category::forward> instead.") =
any_view<Ref, category::forward>;
template<typename Ref>
using any_bidirectional_view RANGES_DEPRECATED(
"Use any_view<Ref, category::bidirectional> instead.") =
any_view<Ref, category::bidirectional>;
template<typename Ref>
using any_random_access_view RANGES_DEPRECATED(
"Use any_view<Ref, category::random_access> instead.") =
any_view<Ref, category::random_access>;
} // namespace ranges
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::any_view)
RANGES_DIAGNOSTIC_POP
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,22 @@
/// \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_BOUNDED_HPP
#define RANGES_V3_VIEW_BOUNDED_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
"This header is deprecated. Please #include <range/v3/view/common.hpp> instead.")
#include <range/v3/view/common.hpp>
#endif

View File

@@ -0,0 +1,94 @@
/// \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_C_STR_HPP
#define RANGES_V3_VIEW_C_STR_HPP
#include <type_traits>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/unreachable_sentinel.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/delimit.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
template<typename T>
struct is_char_type_ : std::false_type
{};
template<>
struct is_char_type_<char> : std::true_type
{};
template<>
struct is_char_type_<wchar_t> : std::true_type
{};
template<>
struct is_char_type_<char16_t> : std::true_type
{};
template<>
struct is_char_type_<char32_t> : std::true_type
{};
template<typename T>
using is_char_type = is_char_type_<meta::_t<std::remove_cv<T>>>;
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
namespace views
{
/// View a `\0`-terminated C string (e.g. from a const char*) as a
/// range.
struct c_str_fn
{
// Fixed-length
template(typename Char, std::size_t N)(
requires detail::is_char_type<Char>::value) //
ranges::subrange<Char *> operator()(Char (&sz)[N]) const
{
return {&sz[0], &sz[N - 1]};
}
// Null-terminated
template(typename Char)(
requires detail::is_char_type<Char>::value) //
ranges::delimit_view<
ranges::subrange<Char *, ranges::unreachable_sentinel_t>,
meta::_t<std::remove_cv<Char>>> //
operator()(Char * sz) const volatile
{
using ch_t = meta::_t<std::remove_cv<Char>>;
return ranges::views::delimit(sz, ch_t(0));
}
};
/// \relates c_str_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(c_str_fn, c_str)
} // namespace views
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,202 @@
/// \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_CACHE1_HPP
#define RANGES_V3_VIEW_CACHE1_HPP
#include <range/v3/range_fwd.hpp>
#include <range/v3/detail/range_access.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng>
struct cache1_view : view_facade<cache1_view<Rng>, range_cardinality<Rng>::value>
{
private:
CPP_assert(view_<Rng>);
CPP_assert(input_range<Rng>);
CPP_assert(constructible_from<range_value_t<Rng>, range_reference_t<Rng>>);
friend range_access;
Rng rng_;
bool dirty_ = true;
detail::non_propagating_cache<range_value_t<Rng>> cache_;
CPP_member
auto update_(range_reference_t<Rng> && val) //
-> CPP_ret(void)(
requires assignable_from<range_value_t<Rng> &, range_reference_t<Rng>>)
{
if(!cache_)
cache_.emplace(static_cast<range_reference_t<Rng> &&>(val));
else
*cache_ = static_cast<range_reference_t<Rng> &&>(val);
}
CPP_member
auto update_(range_reference_t<Rng> && val) //
-> CPP_ret(void)(
requires (!assignable_from<range_value_t<Rng> &, range_reference_t<Rng>>))
{
cache_.emplace(static_cast<range_reference_t<Rng> &&>(val));
}
struct cursor;
struct sentinel
{
private:
friend cursor;
sentinel_t<Rng> last_;
public:
sentinel() = default;
constexpr explicit sentinel(sentinel_t<Rng> last)
: last_(std::move(last))
{}
};
struct cursor
{
private:
cache1_view * parent_;
iterator_t<Rng> current_;
public:
using value_type = range_value_t<Rng>;
using single_pass = std::true_type;
using difference_type = range_difference_t<Rng>;
cursor() = default;
constexpr explicit cursor(cache1_view * parent, iterator_t<Rng> current)
: parent_(parent)
, current_(std::move(current))
{}
range_value_t<Rng> && read() const
{
if(parent_->dirty_)
{
parent_->update_(*current_);
parent_->dirty_ = false;
}
return std::move(*parent_->cache_);
}
void next()
{
++current_;
parent_->dirty_ = true;
}
bool equal(cursor const & that) const
{
return current_ == that.current_;
}
bool equal(sentinel const & that) const
{
return current_ == that.last_;
}
CPP_member
auto distance_to(cursor const & that) const //
-> CPP_ret(difference_type)(
requires sized_sentinel_for<iterator_t<Rng>, iterator_t<Rng>>)
{
return that.current_ - current_;
}
CPP_member
auto distance_to(sentinel const & that) const //
-> CPP_ret(difference_type)(
requires sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>>)
{
return that.last_ - current_;
}
};
cursor begin_cursor()
{
dirty_ = true;
return cursor{this, ranges::begin(rng_)};
}
cursor end_cursor_impl(std::true_type)
{
return cursor{this, ranges::end(rng_)};
}
sentinel end_cursor_impl(std::false_type)
{
return sentinel{ranges::end(rng_)};
}
auto end_cursor()
{
return end_cursor_impl(meta::bool_<(bool)common_range<Rng>>{});
}
public:
cache1_view() = default;
constexpr explicit cache1_view(Rng rng)
: rng_{std::move(rng)}
{}
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return ranges::size(rng_);
}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
cache1_view(Rng &&) //
-> cache1_view<views::all_t<Rng>>;
#endif
namespace views
{
struct cache1_fn
{
/// \brief Caches the most recent element within the view so that
/// dereferencing the view's iterator multiple times doesn't incur any
/// recomputation. This can be useful in adaptor pipelines that include
/// combinations of \c view::filter and \c view::transform, for instance.
/// \note \c views::cache1 is always single-pass.
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng> AND
constructible_from<range_value_t<Rng>, range_reference_t<Rng>>)
constexpr cache1_view<all_t<Rng>> operator()(Rng && rng) const //
{
return cache1_view<all_t<Rng>>{all(static_cast<Rng &&>(rng))};
}
};
/// \relates cache1_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<cache1_fn>, cache1)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::cache1_view)
#endif

View File

@@ -0,0 +1,508 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-2014.
// Copyright Casey Carter 2017.
//
// 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_CARTESIAN_PRODUCT_HPP
#define RANGES_V3_VIEW_CARTESIAN_PRODUCT_HPP
#include <cstdint>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/utility/tuple_algorithm.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/empty.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/view/view.hpp> // for dereference_fn
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
template<typename State, typename Value>
using product_cardinality = std::integral_constant<
cardinality,
State::value == 0 || Value::value == 0
? static_cast<cardinality>(0)
: State::value == unknown || Value::value == unknown
? unknown
: State::value == infinite || Value::value == infinite
? infinite
: State::value == finite || Value::value == finite
? finite
: static_cast<cardinality>(
State::value * Value::value)>;
struct cartesian_size_fn
{
template(typename Size, typename Rng)(
requires integer_like_<Size> AND sized_range<Rng> AND
common_with<Size, range_size_t<Rng>>)
common_type_t<Size, range_size_t<Rng>> operator()(Size s, Rng && rng) const
{
using S = common_type_t<Size, range_size_t<Rng>>;
return static_cast<S>(s) * static_cast<S>(ranges::size(rng));
}
};
template<typename... Views>
using cartesian_product_cardinality =
meta::fold<meta::list<range_cardinality<Views>...>,
std::integral_constant<cardinality, static_cast<cardinality>(
(sizeof...(Views) > 0))>,
meta::quote<detail::product_cardinality>>;
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
// clang-format off
/// \concept cartesian_produce_view_can_const
/// \brief The \c cartesian_produce_view_can_const concept
template<typename...Views>
CPP_concept cartesian_produce_view_can_const =
and_v<range<Views const>...>;
/// \concept cartesian_produce_view_can_size_
/// \brief The \c cartesian_produce_view_can_size_ concept
template(typename IsConst, typename... Views)(
concept (cartesian_produce_view_can_size_)(IsConst, Views...),
and_v<common_with<std::uintmax_t, range_size_t<meta::const_if<IsConst, Views>>>...>
);
/// \concept cartesian_produce_view_can_size
/// \brief The \c cartesian_produce_view_can_size concept
template<typename IsConst, typename...Views>
CPP_concept cartesian_produce_view_can_size =
and_v<sized_range<meta::const_if<IsConst, Views>>...> &&
CPP_concept_ref(ranges::cartesian_produce_view_can_size_, IsConst, Views...);
/// \concept cartesian_produce_view_can_distance_
/// \brief The \c cartesian_produce_view_can_distance_ concept
template(typename IsConst, typename... Views)(
concept (cartesian_produce_view_can_distance_)(IsConst, Views...),
and_v<sized_sentinel_for<
iterator_t<meta::const_if<IsConst, Views>>,
iterator_t<meta::const_if<IsConst, Views>>>...>
);
/// \concept cartesian_produce_view_can_distance
/// \brief The \c cartesian_produce_view_can_distance concept
template<typename IsConst, typename...Views>
CPP_concept cartesian_produce_view_can_distance =
cartesian_produce_view_can_size<IsConst, Views...> &&
CPP_concept_ref(ranges::cartesian_produce_view_can_distance_, IsConst, Views...);
/// \concept cartesian_produce_view_can_random_
/// \brief The \c cartesian_produce_view_can_random_ concept
template(typename IsConst, typename... Views)(
concept (cartesian_produce_view_can_random_)(IsConst, Views...),
and_v<random_access_iterator<iterator_t<meta::const_if<IsConst, Views>>>...>
);
/// \concept cartesian_produce_view_can_random
/// \brief The \c cartesian_produce_view_can_random concept
template<typename IsConst, typename...Views>
CPP_concept cartesian_produce_view_can_random =
cartesian_produce_view_can_distance<IsConst, Views...> &&
CPP_concept_ref(ranges::cartesian_produce_view_can_random_, IsConst, Views...);
/// \concept cartesian_produce_view_can_bidi_
/// \brief The \c cartesian_produce_view_can_bidi_ concept
template(typename IsConst, typename... Views)(
concept (cartesian_produce_view_can_bidi_)(IsConst, Views...),
and_v<common_range<meta::const_if<IsConst, Views>>...,
bidirectional_iterator<iterator_t<meta::const_if<IsConst, Views>>>...>
);
/// \concept cartesian_produce_view_can_bidi
/// \brief The \c cartesian_produce_view_can_bidi concept
template<typename IsConst, typename...Views>
CPP_concept cartesian_produce_view_can_bidi =
cartesian_produce_view_can_random<IsConst, Views...> ||
CPP_concept_ref(ranges::cartesian_produce_view_can_bidi_, IsConst, Views...);
// clang-format on
template<typename... Views>
struct cartesian_product_view
: view_facade<cartesian_product_view<Views...>,
detail::cartesian_product_cardinality<Views...>::value>
{
private:
friend range_access;
CPP_assert(and_v<(forward_range<Views> && view_<Views>)...>);
CPP_assert(sizeof...(Views) != 0);
static constexpr auto my_cardinality =
detail::cartesian_product_cardinality<Views...>::value;
std::tuple<Views...> views_;
template<bool IsConst_>
struct cursor
{
private:
using IsConst = meta::bool_<IsConst_>;
friend cursor<true>;
template<typename T>
using constify_if = meta::const_if_c<IsConst_, T>;
using difference_type =
common_type_t<std::intmax_t, range_difference_t<Views>...>;
constify_if<cartesian_product_view> * view_;
std::tuple<iterator_t<constify_if<Views>>...> its_;
void next_(meta::size_t<1>)
{
auto & v = std::get<0>(view_->views_);
auto & i = std::get<0>(its_);
auto const last = ranges::end(v);
RANGES_EXPECT(i != last);
++i;
}
template<std::size_t N>
void next_(meta::size_t<N>)
{
auto & v = std::get<N - 1>(view_->views_);
auto & i = std::get<N - 1>(its_);
auto const last = ranges::end(v);
RANGES_EXPECT(i != last);
if(++i == last)
{
i = ranges::begin(v);
next_(meta::size_t<N - 1>{});
}
}
void prev_(meta::size_t<0>)
{
RANGES_EXPECT(false);
}
template<std::size_t N>
void prev_(meta::size_t<N>)
{
auto & v = std::get<N - 1>(view_->views_);
auto & i = std::get<N - 1>(its_);
if(i == ranges::begin(v))
{
CPP_assert(cartesian_produce_view_can_bidi<IsConst, Views...>);
// cartesian_produce_view_can_bidi<IsConst, Views...> implies this
// advance call is O(1)
ranges::advance(i, ranges::end(v));
prev_(meta::size_t<N - 1>{});
}
--i;
}
bool equal_(cursor const &, meta::size_t<0>) const
{
return true;
}
template<std::size_t N>
bool equal_(cursor const & that, meta::size_t<N>) const
{
return std::get<N - 1>(its_) == std::get<N - 1>(that.its_) &&
equal_(that, meta::size_t<N - 1>{});
}
difference_type distance_(cursor const & that, meta::size_t<1>) const
{
return difference_type{std::get<0>(that.its_) - std::get<0>(its_)};
}
template<std::size_t N>
difference_type distance_(cursor const & that, meta::size_t<N>) const
{
difference_type const d = distance_(that, meta::size_t<N - 1>{});
auto const scale = ranges::distance(std::get<N - 1>(view_->views_));
auto const increment = std::get<N - 1>(that.its_) - std::get<N - 1>(its_);
return difference_type{d * scale + increment};
}
void advance_(meta::size_t<0>, difference_type)
{
RANGES_EXPECT(false);
}
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_DIVIDE_BY_ZERO
template<std::size_t N>
void advance_(meta::size_t<N>, difference_type n)
{
if(n == 0)
return;
auto & i = std::get<N - 1>(its_);
auto const my_size = static_cast<difference_type>(
ranges::size(std::get<N - 1>(view_->views_)));
auto const first = ranges::begin(std::get<N - 1>(view_->views_));
auto const idx = static_cast<difference_type>(i - first);
RANGES_EXPECT(0 <= idx);
RANGES_EXPECT(idx < my_size || (N == 1 && idx == my_size && n < 0));
RANGES_EXPECT(n < INTMAX_MAX - idx);
n += idx;
auto n_div = n / my_size;
auto n_mod = n % my_size;
if(RANGES_CONSTEXPR_IF(N != 1))
{
if(n_mod < 0)
{
n_mod += my_size;
--n_div;
}
advance_(meta::size_t<N - 1>{}, n_div);
}
RANGES_EXPECT(0 <= n_mod && n_mod < my_size);
if(RANGES_CONSTEXPR_IF(N == 1))
{
if(n_div > 0)
{
RANGES_EXPECT(n_div == 1);
RANGES_EXPECT(n_mod == 0);
n_mod = my_size;
}
else if(n_div < 0)
{
RANGES_EXPECT(n_div == -1);
RANGES_EXPECT(n_mod == 0);
}
}
using D = iter_difference_t<decltype(first)>;
i = first + static_cast<D>(n_mod);
}
RANGES_DIAGNOSTIC_POP
void check_at_end_(meta::size_t<1>, bool at_end = false)
{
if(at_end)
ranges::advance(std::get<0>(its_),
ranges::end(std::get<0>(view_->views_)));
}
template<std::size_t N>
void check_at_end_(meta::size_t<N>, bool at_end = false)
{
return check_at_end_(
meta::size_t<N - 1>{},
at_end || bool(std::get<N - 1>(its_) ==
ranges::end(std::get<N - 1>(view_->views_))));
}
cursor(end_tag, constify_if<cartesian_product_view> * view,
std::true_type) // common_with
: cursor(begin_tag{}, view)
{
CPP_assert(
common_range<meta::at_c<meta::list<constify_if<Views>...>, 0>>);
std::get<0>(its_) = ranges::end(std::get<0>(view->views_));
}
cursor(end_tag, constify_if<cartesian_product_view> * view,
std::false_type) // !common_with
: cursor(begin_tag{}, view)
{
using View0 = meta::at_c<meta::list<constify_if<Views>...>, 0>;
CPP_assert(!common_range<View0> && random_access_range<View0> &&
sized_range<View0>);
std::get<0>(its_) += ranges::distance(std::get<0>(view->views_));
}
public:
using value_type = std::tuple<range_value_t<Views>...>;
cursor() = default;
explicit cursor(begin_tag, constify_if<cartesian_product_view> * view)
: view_(view)
, its_(tuple_transform(view->views_, ranges::begin))
{
// If any of the constituent views is empty, the cartesian_product is
// empty and this "begin" iterator needs to become an "end" iterator.
check_at_end_(meta::size_t<sizeof...(Views)>{});
}
explicit cursor(end_tag, constify_if<cartesian_product_view> * view)
: cursor(
end_tag{}, view,
meta::bool_<
common_range<meta::at_c<meta::list<constify_if<Views>...>, 0>>>{})
{}
template(bool Other)(
requires IsConst_ AND CPP_NOT(Other)) //
cursor(cursor<Other> that)
: view_(that.view_)
, its_(std::move(that.its_))
{}
common_tuple<range_reference_t<constify_if<Views>>...> read() const
{
return tuple_transform(its_, detail::dereference_fn{});
}
void next()
{
next_(meta::size_t<sizeof...(Views)>{});
}
bool equal(default_sentinel_t) const
{
return std::get<0>(its_) == ranges::end(std::get<0>(view_->views_));
}
bool equal(cursor const & that) const
{
return equal_(that, meta::size_t<sizeof...(Views)>{});
}
CPP_member
auto prev() -> CPP_ret(void)(
requires cartesian_produce_view_can_bidi<IsConst, Views...>)
{
prev_(meta::size_t<sizeof...(Views)>{});
}
CPP_auto_member
auto CPP_fun(distance_to)(cursor const & that)(
const requires cartesian_produce_view_can_distance<IsConst, Views...>)
{
return distance_(that, meta::size_t<sizeof...(Views)>{});
}
CPP_member
auto advance(difference_type n) //
-> CPP_ret(void)(
requires cartesian_produce_view_can_random<IsConst, Views...>)
{
advance_(meta::size_t<sizeof...(Views)>{}, n);
}
};
cursor<false> begin_cursor()
{
return cursor<false>{begin_tag{}, this};
}
CPP_member
auto begin_cursor() const //
-> CPP_ret(cursor<true>)(
requires cartesian_produce_view_can_const<Views...>)
{
return cursor<true>{begin_tag{}, this};
}
CPP_member
auto end_cursor() //
-> CPP_ret(cursor<false>)(
requires cartesian_produce_view_can_bidi<std::false_type, Views...>)
{
return cursor<false>{end_tag{}, this};
}
CPP_member
auto end_cursor() const //
-> CPP_ret(cursor<true>)(
requires cartesian_produce_view_can_bidi<std::true_type, Views...>)
{
return cursor<true>{end_tag{}, this};
}
CPP_member
auto end_cursor() const //
-> CPP_ret(default_sentinel_t)(
requires (!cartesian_produce_view_can_bidi<std::true_type, Views...>))
{
return {};
}
public:
cartesian_product_view() = default;
constexpr explicit cartesian_product_view(Views... views)
: views_{detail::move(views)...}
{}
template(typename...)(
requires (my_cardinality >= 0)) //
static constexpr std::size_t size() noexcept
{
return std::size_t{my_cardinality};
}
CPP_auto_member
auto CPP_fun(size)()(const //
requires (my_cardinality < 0) &&
cartesian_produce_view_can_size<std::true_type, Views...>)
{
return tuple_foldl(views_, std::uintmax_t{1}, detail::cartesian_size_fn{});
}
CPP_auto_member
auto CPP_fun(size)()(
requires (my_cardinality < 0) &&
cartesian_produce_view_can_size<std::false_type, Views...>)
{
return tuple_foldl(views_, std::uintmax_t{1}, detail::cartesian_size_fn{});
}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename... Rng>
cartesian_product_view(Rng &&...) //
-> cartesian_product_view<views::all_t<Rng>...>;
#endif
namespace views
{
struct cartesian_product_fn
{
constexpr empty_view<std::tuple<>> operator()() const noexcept
{
return {};
}
template(typename... Rngs)(
requires (sizeof...(Rngs) != 0) AND
concepts::and_v<(forward_range<Rngs> && viewable_range<Rngs>)...>)
constexpr cartesian_product_view<all_t<Rngs>...> operator()(Rngs &&... rngs)
const
{
return cartesian_product_view<all_t<Rngs>...>{
all(static_cast<Rngs &&>(rngs))...};
}
#if defined(_MSC_VER)
template(typename Rng0)(
requires forward_range<Rng0> AND viewable_range<Rng0>)
constexpr cartesian_product_view<all_t<Rng0>> operator()(Rng0 && rng0) const
{
return cartesian_product_view<all_t<Rng0>>{
all(static_cast<Rng0 &&>(rng0))};
}
template(typename Rng0, typename Rng1)(
requires forward_range<Rng0> AND viewable_range<Rng0> AND
forward_range<Rng1> AND viewable_range<Rng1>)
constexpr cartesian_product_view<all_t<Rng0>, all_t<Rng1>> //
operator()(Rng0 && rng0, Rng1 && rng1) const
{
return cartesian_product_view<all_t<Rng0>, all_t<Rng1>>{
all(static_cast<Rng0 &&>(rng0)), //
all(static_cast<Rng1 &&>(rng1))};
}
template(typename Rng0, typename Rng1, typename Rng2)(
requires forward_range<Rng0> AND viewable_range<Rng0> AND
forward_range<Rng1> AND viewable_range<Rng1> AND
forward_range<Rng2> AND viewable_range<Rng2>)
constexpr cartesian_product_view<all_t<Rng0>, all_t<Rng1>, all_t<Rng2>> //
operator()(Rng0 && rng0, Rng1 && rng1, Rng2 && rng2) const
{
return cartesian_product_view<all_t<Rng0>, all_t<Rng1>, all_t<Rng2>>{
all(static_cast<Rng0 &&>(rng0)), //
all(static_cast<Rng1 &&>(rng1)), //
all(static_cast<Rng2 &&>(rng2))};
}
#endif
};
RANGES_INLINE_VARIABLE(cartesian_product_fn, cartesian_product)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,463 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_CHUNK_HPP
#define RANGES_V3_VIEW_CHUNK_HPP
#include <limits>
#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/iterator/operations.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/box.hpp>
#include <range/v3/utility/optional.hpp> // for non_propagating_cache
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/view/take.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
template<typename Rng, bool Const>
constexpr bool can_sized_sentinel_() noexcept
{
using I = iterator_t<meta::const_if_c<Const, Rng>>;
return (bool)sized_sentinel_for<I, I>;
}
template<typename T>
struct zero
{
zero() = default;
constexpr explicit zero(T const &) noexcept
{}
constexpr zero & operator=(T const &) noexcept
{
return *this;
}
constexpr zero const & operator=(T const &) const noexcept
{
return *this;
}
constexpr operator T() const
{
return T(0);
}
constexpr T exchange(T const &) const
{
return T(0);
}
};
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
template<typename Rng, bool IsForwardRange>
struct chunk_view_
: view_adaptor<chunk_view_<Rng, IsForwardRange>, Rng,
is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
{
private:
friend range_access;
CPP_assert(forward_range<Rng>);
template<bool Const>
using offset_t =
meta::if_c<bidirectional_range<meta::const_if_c<Const, Rng>> ||
detail::can_sized_sentinel_<Rng, Const>(),
range_difference_t<Rng>, detail::zero<range_difference_t<Rng>>>;
range_difference_t<Rng> n_ = 0;
template<bool Const>
struct RANGES_EMPTY_BASES adaptor
: adaptor_base
, private box<offset_t<Const>>
{
private:
friend adaptor<!Const>;
using CRng = meta::const_if_c<Const, Rng>;
range_difference_t<CRng> n_;
sentinel_t<CRng> end_;
constexpr offset_t<Const> const & offset() const
{
offset_t<Const> const & result = this->box<offset_t<Const>>::get();
RANGES_EXPECT(0 <= result && result < n_);
return result;
}
constexpr offset_t<Const> & offset()
{
return const_cast<offset_t<Const> &>(
const_cast<adaptor const &>(*this).offset());
}
public:
adaptor() = default;
constexpr adaptor(meta::const_if_c<Const, chunk_view_> * cv)
: box<offset_t<Const>>{0}
, n_((RANGES_EXPECT(0 < cv->n_), cv->n_))
, end_(ranges::end(cv->base()))
{}
template(bool Other)(
requires Const AND CPP_NOT(Other)) //
constexpr adaptor(adaptor<Other> that)
: box<offset_t<Const>>(that.offset())
, n_(that.n_)
, end_(that.end_)
{}
constexpr auto read(iterator_t<CRng> const & it) const
-> decltype(views::take(make_subrange(it, end_), n_))
{
RANGES_EXPECT(it != end_);
RANGES_EXPECT(0 == offset());
return views::take(make_subrange(it, end_), n_);
}
constexpr void next(iterator_t<CRng> & it)
{
RANGES_EXPECT(it != end_);
RANGES_EXPECT(0 == offset());
offset() = ranges::advance(it, n_, end_);
}
CPP_member
constexpr auto prev(iterator_t<CRng> & it) //
-> CPP_ret(void)(
requires bidirectional_range<CRng>)
{
ranges::advance(it, -n_ + offset());
offset() = 0;
}
CPP_member
constexpr auto distance_to(iterator_t<CRng> const & here,
iterator_t<CRng> const & there,
adaptor const & that) const
-> CPP_ret(range_difference_t<Rng>)(
requires (detail::can_sized_sentinel_<Rng, Const>()))
{
auto const delta = (there - here) + (that.offset() - offset());
// This can fail for cyclic base ranges when the chunk size does not
// divide the cycle length. Such iterator pairs are NOT in the domain of
// -.
RANGES_ENSURE(0 == delta % n_);
return delta / n_;
}
CPP_member
constexpr auto advance(iterator_t<CRng> & it, range_difference_t<Rng> n) //
-> CPP_ret(void)(
requires random_access_range<CRng>)
{
using Limits = std::numeric_limits<range_difference_t<CRng>>;
if(0 < n)
{
RANGES_EXPECT(0 == offset());
RANGES_EXPECT(n <= Limits::max() / n_);
auto const remainder = ranges::advance(it, n * n_, end_) % n_;
RANGES_EXPECT(0 <= remainder && remainder < n_);
offset() = remainder;
}
else if(0 > n)
{
RANGES_EXPECT(n >= Limits::min() / n_);
ranges::advance(it, n * n_ + offset());
offset() = 0;
}
}
};
constexpr adaptor<simple_view<Rng>()> begin_adaptor()
{
return adaptor<simple_view<Rng>()>{this};
}
CPP_member
constexpr auto begin_adaptor() const //
-> CPP_ret(adaptor<true>)(
requires forward_range<Rng const>)
{
return adaptor<true>{this};
}
template<typename Size>
constexpr Size size_(Size base_size) const
{
auto const n = static_cast<Size>(n_);
return base_size / n + (0 != (base_size % n));
}
public:
chunk_view_() = default;
constexpr chunk_view_(Rng rng, range_difference_t<Rng> n)
: chunk_view_::view_adaptor(detail::move(rng))
, n_((RANGES_EXPECT(0 < n), n))
{}
CPP_auto_member
constexpr auto CPP_fun(size)()(const
requires sized_range<Rng const>)
{
return size_(ranges::size(this->base()));
}
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return size_(ranges::size(this->base()));
}
};
template<typename Rng>
struct chunk_view_<Rng, false>
: view_facade<chunk_view_<Rng, false>,
is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
{
private:
friend range_access;
CPP_assert(input_range<Rng> && !forward_range<Rng>);
using iter_cache_t = detail::non_propagating_cache<iterator_t<Rng>>;
Rng base_;
range_difference_t<Rng> n_;
range_difference_t<Rng> remainder_;
mutable iter_cache_t it_cache_;
constexpr iterator_t<Rng> & it() noexcept
{
return *it_cache_;
}
constexpr iterator_t<Rng> const & it() const noexcept
{
return *it_cache_;
}
struct outer_cursor
{
private:
struct inner_view : view_facade<inner_view, finite>
{
private:
friend range_access;
using value_type = range_value_t<Rng>;
chunk_view_ * rng_ = nullptr;
constexpr bool done() const noexcept
{
RANGES_EXPECT(rng_);
return rng_->remainder_ == 0;
}
constexpr bool equal(default_sentinel_t) const noexcept
{
return done();
}
constexpr iter_reference_t<iterator_t<Rng>> read() const
{
RANGES_EXPECT(!done());
return *rng_->it();
}
constexpr iter_rvalue_reference_t<iterator_t<Rng>> move() const
{
RANGES_EXPECT(!done());
return ranges::iter_move(rng_->it());
}
constexpr void next()
{
RANGES_EXPECT(!done());
++rng_->it();
--rng_->remainder_;
if(rng_->remainder_ != 0 && rng_->it() == ranges::end(rng_->base_))
rng_->remainder_ = 0;
}
CPP_member
constexpr auto distance_to(default_sentinel_t) const
-> CPP_ret(range_difference_t<Rng>)(
requires sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>>)
{
RANGES_EXPECT(rng_);
auto const d = ranges::end(rng_->base_) - rng_->it();
return ranges::min(d, rng_->remainder_);
}
public:
inner_view() = default;
constexpr explicit inner_view(chunk_view_ * view) noexcept
: rng_{view}
{}
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>>)
{
using size_type = detail::iter_size_t<iterator_t<Rng>>;
return static_cast<size_type>(distance_to(default_sentinel_t{}));
}
};
chunk_view_ * rng_ = nullptr;
public:
using value_type = inner_view;
outer_cursor() = default;
constexpr explicit outer_cursor(chunk_view_ * view) noexcept
: rng_{view}
{}
constexpr inner_view read() const
{
RANGES_EXPECT(!done());
return inner_view{rng_};
}
constexpr bool done() const
{
RANGES_EXPECT(rng_);
return rng_->it() == ranges::end(rng_->base_) && rng_->remainder_ != 0;
}
constexpr bool equal(default_sentinel_t) const
{
return done();
}
constexpr void next()
{
RANGES_EXPECT(!done());
ranges::advance(rng_->it(), rng_->remainder_, ranges::end(rng_->base_));
rng_->remainder_ = rng_->n_;
}
CPP_member
constexpr auto distance_to(default_sentinel_t) const
-> CPP_ret(range_difference_t<Rng>)(
requires sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>>)
{
RANGES_EXPECT(rng_);
auto d = ranges::end(rng_->base_) - rng_->it();
if(d < rng_->remainder_)
return 1;
d -= rng_->remainder_;
d = (d + rng_->n_ - 1) / rng_->n_;
d += (rng_->remainder_ != 0);
return d;
}
};
constexpr outer_cursor begin_cursor() noexcept
{
it_cache_ = ranges::begin(base_);
return outer_cursor{this};
}
template<typename Size>
constexpr Size size_(Size base_size) const
{
auto const n = static_cast<Size>(this->n_);
return base_size / n + (0 != base_size % n);
}
public:
chunk_view_() = default;
constexpr chunk_view_(Rng rng, range_difference_t<Rng> n)
: base_(detail::move(rng))
, n_((RANGES_EXPECT(0 < n), n))
, remainder_(n)
, it_cache_{nullopt}
{}
CPP_auto_member
constexpr auto CPP_fun(size)()(const
requires sized_range<Rng const>)
{
return size_(ranges::size(base_));
}
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return size_(ranges::size(base_));
}
Rng base() const
{
return base_;
}
};
template<typename Rng>
struct chunk_view : chunk_view_<Rng, (bool)forward_range<Rng>>
{
chunk_view() = default;
constexpr chunk_view(Rng rng, range_difference_t<Rng> n)
: chunk_view_<Rng, (bool)forward_range<Rng>>(static_cast<Rng &&>(rng), n)
{}
};
// Need to keep extra state for input_range, but forward_range is transparent
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<chunk_view<Rng>> =
enable_borrowed_range<Rng> && forward_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
chunk_view(Rng &&, range_difference_t<Rng>)
-> chunk_view<views::all_t<Rng>>;
#endif
namespace views
{
// In: range<T>
// Out: range<range<T>>, where each inner range has $n$ elements.
// The last range may have fewer.
struct chunk_base_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng>)
constexpr chunk_view<all_t<Rng>> //
operator()(Rng && rng, range_difference_t<Rng> n) const
{
return {all(static_cast<Rng &&>(rng)), n};
}
};
struct chunk_fn : chunk_base_fn
{
using chunk_base_fn::operator();
template(typename Int)(
requires detail::integer_like_<Int>)
constexpr auto operator()(Int n) const
{
return make_view_closure(bind_back(chunk_base_fn{}, n));
}
};
/// \relates chunk_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(chunk_fn, chunk)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::chunk_view)
#endif

View File

@@ -0,0 +1,170 @@
/// \file
// Range v3 library
//
// Copyright Hui Xie 2021
//
// 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_CHUNK_BY_HPP
#define RANGES_V3_VIEW_CHUNK_BY_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/algorithm/adjacent_find.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/not_fn.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng, typename Fun>
struct chunk_by_view
: view_facade<chunk_by_view<Rng, Fun>,
is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
{
private:
friend range_access;
Rng rng_;
// cached version of the end of the first subrange / start of the second subrange
detail::non_propagating_cache<iterator_t<Rng>> second_;
semiregular_box_t<Fun> fun_;
struct cursor
{
private:
friend range_access;
friend chunk_by_view;
iterator_t<Rng> cur_;
iterator_t<Rng> next_cur_;
sentinel_t<Rng> last_;
semiregular_box_ref_or_val_t<Fun, false> fun_;
#ifdef _MSC_VER
template<typename I = iterator_t<Rng>>
subrange<I> read() const
{
return {cur_, next_cur_};
}
#else
subrange<iterator_t<Rng>> read() const
{
return {cur_, next_cur_};
}
#endif
void next()
{
cur_ = next_cur_;
auto partition_cur = adjacent_find(cur_, last_, not_fn(fun_));
next_cur_ =
partition_cur != last_ ? ranges::next(partition_cur) : partition_cur;
}
bool equal(default_sentinel_t) const
{
return cur_ == last_;
}
bool equal(cursor const & that) const
{
return cur_ == that.cur_;
}
cursor(semiregular_box_ref_or_val_t<Fun, false> fun, iterator_t<Rng> first,
iterator_t<Rng> next_cur, sentinel_t<Rng> last)
: cur_(first)
, next_cur_(next_cur)
, last_(last)
, fun_(fun)
{}
public:
cursor() = default;
};
cursor begin_cursor()
{
auto first = ranges::begin(rng_);
auto last = ranges::end(rng_);
if(!second_)
{
auto partition_cur = adjacent_find(first, last, not_fn(fun_));
second_ =
partition_cur != last ? ranges::next(partition_cur) : partition_cur;
}
return {fun_, first, *second_, last};
}
public:
chunk_by_view() = default;
constexpr chunk_by_view(Rng rng, Fun fun)
: rng_(std::move(rng))
, fun_(std::move(fun))
{}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename Fun)(
requires copy_constructible<Fun>) chunk_by_view(Rng &&, Fun)
->chunk_by_view<views::all_t<Rng>, Fun>;
#endif
namespace views
{
struct chunk_by_base_fn
{
template(typename Rng, typename Fun)(
requires viewable_range<Rng> AND forward_range<Rng> AND //
indirect_relation<Fun, iterator_t<Rng>>) //
constexpr chunk_by_view<all_t<Rng>, Fun>
operator()(Rng && rng, Fun fun) const
{
return {all(static_cast<Rng &&>(rng)), std::move(fun)};
}
};
struct chunk_by_fn : chunk_by_base_fn
{
using chunk_by_base_fn::operator();
template<typename Fun>
constexpr auto operator()(Fun fun) const
{
return make_view_closure(bind_back(chunk_by_base_fn{}, std::move(fun)));
}
};
/// \relates chunk_by_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(chunk_by_fn, chunk_by)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::chunk_by_view)
#endif

View File

@@ -0,0 +1,235 @@
/// \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_COMMON_HPP
#define RANGES_V3_VIEW_COMMON_HPP
#include <type_traits>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/common_iterator.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
/// \cond
namespace detail
{
// clang-format off
/// \concept random_access_and_sized_range
/// \brief The \c random_access_and_sized_range concept
template<typename R>
CPP_concept random_access_and_sized_range =
random_access_range<R> && sized_range<R>;
// clang-format on
template<typename R>
using common_view_iterator_t =
meta::if_c<random_access_and_sized_range<R>, iterator_t<R>,
common_iterator_t<iterator_t<R>, sentinel_t<R>>>;
template<typename Rng>
struct is_common_range : meta::bool_<common_range<Rng>>
{};
} // namespace detail
/// \endcond
template<typename Rng, bool = detail::is_common_range<Rng>::value>
struct common_view : view_interface<common_view<Rng>, range_cardinality<Rng>::value>
{
private:
CPP_assert(view_<Rng>);
CPP_assert(!(common_range<Rng> && view_<Rng>));
Rng rng_;
sentinel_t<Rng> end_(std::false_type)
{
return ranges::end(rng_);
}
iterator_t<Rng> end_(std::true_type)
{
return ranges::begin(rng_) + ranges::distance(rng_);
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng>>)
sentinel_t<meta::const_if_c<Const, Rng>> end_(std::false_type) const
{
return ranges::end(rng_);
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng>>)
iterator_t<meta::const_if_c<Const, Rng>> end_(std::true_type) const
{
return ranges::begin(rng_) + ranges::distance(rng_);
}
public:
common_view() = default;
explicit common_view(Rng rng)
: rng_(detail::move(rng))
{}
Rng base() const
{
return rng_;
}
detail::common_view_iterator_t<Rng> begin()
{
return detail::common_view_iterator_t<Rng>{ranges::begin(rng_)};
}
detail::common_view_iterator_t<Rng> end()
{
return detail::common_view_iterator_t<Rng>{
end_(meta::bool_<detail::random_access_and_sized_range<Rng>>{})};
}
CPP_auto_member
auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return ranges::size(rng_);
}
template(bool Const = true)(
requires range<meta::const_if_c<Const, Rng>>)
auto begin() const
-> detail::common_view_iterator_t<meta::const_if_c<Const, Rng>>
{
return detail::common_view_iterator_t<meta::const_if_c<Const, Rng>>{
ranges::begin(rng_)};
}
template(bool Const = true)(
requires range<meta::const_if_c<Const, Rng>>)
auto end() const
-> detail::common_view_iterator_t<meta::const_if_c<Const, Rng>>
{
return detail::common_view_iterator_t<meta::const_if_c<Const, Rng>>{
end_(meta::bool_<detail::random_access_and_sized_range<
meta::const_if_c<Const, Rng>>>{})};
}
CPP_auto_member
auto CPP_fun(size)()(const
requires sized_range<Rng const>)
{
return ranges::size(rng_);
}
};
template<typename Rng, bool B>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<common_view<Rng, B>> = //
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng)(
requires (!common_range<Rng>)) //
common_view(Rng &&)
->common_view<views::all_t<Rng>>;
#endif
template<typename Rng>
struct common_view<Rng, true> : identity_adaptor<Rng>
{
CPP_assert(common_range<Rng>);
using identity_adaptor<Rng>::identity_adaptor;
};
namespace views
{
struct cpp20_common_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND common_range<Rng>)
all_t<Rng> operator()(Rng && rng) const
{
return all(static_cast<Rng &&>(rng));
}
template(typename Rng)(
requires viewable_range<Rng> AND (!common_range<Rng>)) //
common_view<all_t<Rng>> operator()(Rng && rng) const
{
return common_view<all_t<Rng>>{all(static_cast<Rng &&>(rng))};
}
};
struct common_fn
{
template(typename Rng)(
requires viewable_range<Rng>)
common_view<all_t<Rng>> operator()(Rng && rng) const
{
return common_view<all_t<Rng>>{all(static_cast<Rng &&>(rng))};
}
};
/// \relates common_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<common_fn>, common)
} // namespace views
/// @}
/// \cond
template<typename Rng>
using bounded_view RANGES_DEPRECATED(
"The name bounded_view is deprecated. "
"Please use common_view instead.") = common_view<Rng>;
/// \endcond
namespace views
{
/// \cond
namespace
{
RANGES_DEPRECATED(
"The name views::bounded is deprecated. "
"Please use views::common instead.")
RANGES_INLINE_VAR constexpr auto & bounded = common;
} // namespace
template<typename Rng>
using bounded_t RANGES_DEPRECATED("The name views::bounded_t is deprecated.") =
decltype(common(std::declval<Rng>()));
/// \endcond
} // namespace views
namespace cpp20
{
namespace views
{
RANGES_INLINE_VARIABLE(
ranges::views::view_closure<ranges::views::cpp20_common_fn>, common)
}
template(typename Rng)(
requires view_<Rng> && (!common_range<Rng>)) //
using common_view = ranges::common_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::common_view)
#endif

View File

@@ -0,0 +1,452 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-2014.
//
// 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_CONCAT_HPP
#define RANGES_V3_VIEW_CONCAT_HPP
#include <tuple>
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/arithmetic.hpp>
#include <range/v3/functional/compose.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/utility/tuple_algorithm.hpp>
#include <range/v3/utility/variant.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
template<typename State, typename Value>
using concat_cardinality_ = std::integral_constant<
cardinality,
State::value == infinite || Value::value == infinite
? infinite
: State::value == unknown || Value::value == unknown
? unknown
: State::value == finite || Value::value == finite
? finite
: static_cast<cardinality>(State::value + Value::value)>;
template<typename... Rngs>
using concat_cardinality =
meta::fold<meta::list<range_cardinality<Rngs>...>,
std::integral_constant<cardinality, static_cast<cardinality>(0)>,
meta::quote<concat_cardinality_>>;
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
template<typename... Rngs>
struct concat_view
: view_facade<concat_view<Rngs...>, detail::concat_cardinality<Rngs...>::value>
{
private:
friend range_access;
using difference_type_ = common_type_t<range_difference_t<Rngs>...>;
static constexpr std::size_t cranges{sizeof...(Rngs)};
std::tuple<Rngs...> rngs_;
template<bool IsConst>
struct cursor;
template<bool IsConst>
struct sentinel
{
private:
friend struct sentinel<!IsConst>;
friend struct cursor<IsConst>;
template<typename T>
using constify_if = meta::const_if_c<IsConst, T>;
using concat_view_t = constify_if<concat_view>;
sentinel_t<constify_if<meta::back<meta::list<Rngs...>>>> end_;
public:
sentinel() = default;
sentinel(concat_view_t * rng, end_tag)
: end_(end(std::get<cranges - 1>(rng->rngs_)))
{}
template(bool Other)(
requires IsConst AND CPP_NOT(Other)) //
sentinel(sentinel<Other> that)
: end_(std::move(that.end_))
{}
};
template<bool IsConst>
struct cursor
{
using difference_type = common_type_t<range_difference_t<Rngs>...>;
private:
friend struct cursor<!IsConst>;
template<typename T>
using constify_if = meta::const_if_c<IsConst, T>;
using concat_view_t = constify_if<concat_view>;
concat_view_t * rng_;
variant<iterator_t<constify_if<Rngs>>...> its_;
template<std::size_t N>
void satisfy(meta::size_t<N>)
{
RANGES_EXPECT(its_.index() == N);
if(ranges::get<N>(its_) == end(std::get<N>(rng_->rngs_)))
{
ranges::emplace<N + 1>(its_, begin(std::get<N + 1>(rng_->rngs_)));
this->satisfy(meta::size_t<N + 1>{});
}
}
void satisfy(meta::size_t<cranges - 1>)
{
RANGES_EXPECT(its_.index() == cranges - 1);
}
struct next_fun
{
cursor * pos;
template(typename I, std::size_t N)(
requires input_iterator<I>)
void operator()(indexed_element<I, N> it) const
{
RANGES_ASSERT(it.get() != end(std::get<N>(pos->rng_->rngs_)));
++it.get();
pos->satisfy(meta::size_t<N>{});
}
};
struct prev_fun
{
cursor * pos;
template(typename I)(
requires bidirectional_iterator<I>)
void operator()(indexed_element<I, 0> it) const
{
RANGES_ASSERT(it.get() != begin(std::get<0>(pos->rng_->rngs_)));
--it.get();
}
template(typename I, std::size_t N)(
requires (N != 0) AND bidirectional_iterator<I>)
void operator()(indexed_element<I, N> it) const
{
if(it.get() == begin(std::get<N>(pos->rng_->rngs_)))
{
auto && rng = std::get<N - 1>(pos->rng_->rngs_);
ranges::emplace<N - 1>(
pos->its_,
ranges::next(ranges::begin(rng), ranges::end(rng)));
pos->its_.visit_i(*this);
}
else
--it.get();
}
};
struct advance_fwd_fun
{
cursor * pos;
difference_type n;
template(typename I)(
requires random_access_iterator<I>)
void operator()(indexed_element<I, cranges - 1> it) const
{
ranges::advance(it.get(), n);
}
template(typename I, std::size_t N)(
requires random_access_iterator<I>)
void operator()(indexed_element<I, N> it) const
{
auto last = ranges::end(std::get<N>(pos->rng_->rngs_));
// BUGBUG If distance(it, last) > n, then using bounded advance
// is O(n) when it need not be since the last iterator position
// is actually not interesting. Only the "rest" is needed, which
// can sometimes be O(1).
auto rest = ranges::advance(it.get(), n, std::move(last));
pos->satisfy(meta::size_t<N>{});
if(rest != 0)
pos->its_.visit_i(advance_fwd_fun{pos, rest});
}
};
struct advance_rev_fun
{
cursor * pos;
difference_type n;
template(typename I)(
requires random_access_iterator<I>)
void operator()(indexed_element<I, 0> it) const
{
ranges::advance(it.get(), n);
}
template(typename I, std::size_t N)(
requires random_access_iterator<I>)
void operator()(indexed_element<I, N> it) const
{
auto first = ranges::begin(std::get<N>(pos->rng_->rngs_));
if(it.get() == first)
{
auto && rng = std::get<N - 1>(pos->rng_->rngs_);
ranges::emplace<N - 1>(
pos->its_,
ranges::next(ranges::begin(rng), ranges::end(rng)));
pos->its_.visit_i(*this);
}
else
{
auto rest = ranges::advance(it.get(), n, std::move(first));
if(rest != 0)
pos->its_.visit_i(advance_rev_fun{pos, rest});
}
}
};
[[noreturn]] static difference_type distance_to_(meta::size_t<cranges>,
cursor const &,
cursor const &)
{
RANGES_EXPECT(false);
}
template<std::size_t N>
static difference_type distance_to_(meta::size_t<N>, cursor const & from,
cursor const & to)
{
if(from.its_.index() > N)
return cursor::distance_to_(meta::size_t<N + 1>{}, from, to);
if(from.its_.index() == N)
{
if(to.its_.index() == N)
return distance(ranges::get<N>(from.its_),
ranges::get<N>(to.its_));
return distance(ranges::get<N>(from.its_),
end(std::get<N>(from.rng_->rngs_))) +
cursor::distance_to_(meta::size_t<N + 1>{}, from, to);
}
if(from.its_.index() < N && to.its_.index() > N)
return distance(std::get<N>(from.rng_->rngs_)) +
cursor::distance_to_(meta::size_t<N + 1>{}, from, to);
RANGES_EXPECT(to.its_.index() == N);
return distance(begin(std::get<N>(from.rng_->rngs_)),
ranges::get<N>(to.its_));
}
public:
// BUGBUG what about rvalue_reference and common_reference?
using reference = common_reference_t<range_reference_t<constify_if<Rngs>>...>;
using single_pass = meta::or_c<single_pass_iterator_<iterator_t<Rngs>>...>;
cursor() = default;
cursor(concat_view_t * rng, begin_tag)
: rng_(rng)
, its_{emplaced_index<0>, begin(std::get<0>(rng->rngs_))}
{
this->satisfy(meta::size_t<0>{});
}
cursor(concat_view_t * rng, end_tag)
: rng_(rng)
, its_{emplaced_index<cranges - 1>, end(std::get<cranges - 1>(rng->rngs_))}
{}
template(bool Other)(
requires IsConst && CPP_NOT(Other)) //
cursor(cursor<Other> that)
: rng_(that.rng_)
, its_(std::move(that.its_))
{}
reference read() const
{
// Kind of a dumb implementation. Surely there's a better way.
return ranges::get<0>(unique_variant(its_.visit(
compose(convert_to<reference>{}, detail::dereference_fn{}))));
}
void next()
{
its_.visit_i(next_fun{this});
}
CPP_member
auto equal(cursor const & pos) const //
-> CPP_ret(bool)(
requires //
equality_comparable<variant<iterator_t<constify_if<Rngs>>...>>)
{
return its_ == pos.its_;
}
bool equal(sentinel<IsConst> const & pos) const
{
return its_.index() == cranges - 1 &&
ranges::get<cranges - 1>(its_) == pos.end_;
}
CPP_member
auto prev() //
-> CPP_ret(void)(
requires and_v<bidirectional_range<Rngs>...>)
{
its_.visit_i(prev_fun{this});
}
CPP_member
auto advance(difference_type n) //
-> CPP_ret(void)(
requires and_v<random_access_range<Rngs>...>)
{
if(n > 0)
its_.visit_i(advance_fwd_fun{this, n});
else if(n < 0)
its_.visit_i(advance_rev_fun{this, n});
}
CPP_member
auto distance_to(cursor const & that) const //
-> CPP_ret(difference_type)(
requires and_v<sized_sentinel_for<iterator_t<Rngs>,
iterator_t<Rngs>>...>)
{
if(its_.index() <= that.its_.index())
return cursor::distance_to_(meta::size_t<0>{}, *this, that);
return -cursor::distance_to_(meta::size_t<0>{}, that, *this);
}
};
cursor<meta::and_c<simple_view<Rngs>()...>::value> begin_cursor()
{
return {this, begin_tag{}};
}
meta::if_<meta::and_c<(bool)common_range<Rngs>...>,
cursor<meta::and_c<simple_view<Rngs>()...>::value>,
sentinel<meta::and_c<simple_view<Rngs>()...>::value>>
end_cursor()
{
return {this, end_tag{}};
}
CPP_member
auto begin_cursor() const //
-> CPP_ret(cursor<true>)(
requires and_v<range<Rngs const>...>)
{
return {this, begin_tag{}};
}
CPP_member
auto end_cursor() const //
-> CPP_ret(
meta::if_<meta::and_c<(bool)common_range<Rngs const>...>, //
cursor<true>, //
sentinel<true>>)(
requires and_v<range<Rngs const>...>)
{
return {this, end_tag{}};
}
public:
concat_view() = default;
explicit concat_view(Rngs... rngs)
: rngs_{std::move(rngs)...}
{}
CPP_member
constexpr auto size() const //
-> CPP_ret(std::size_t)(
requires (detail::concat_cardinality<Rngs...>::value >= 0))
{
return static_cast<std::size_t>(detail::concat_cardinality<Rngs...>::value);
}
CPP_auto_member
constexpr auto CPP_fun(size)()(const //
requires(detail::concat_cardinality<Rngs...>::value < 0) &&
and_v<sized_range<Rngs const>...>)
{
using size_type = common_type_t<range_size_t<Rngs const>...>;
return tuple_foldl(
tuple_transform(rngs_,
[](auto && r) -> size_type { return ranges::size(r); }),
size_type{0},
plus{});
}
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires (detail::concat_cardinality<Rngs...>::value < 0) &&
and_v<sized_range<Rngs>...>)
{
using size_type = common_type_t<range_size_t<Rngs>...>;
return tuple_foldl(
tuple_transform(rngs_,
[](auto && r) -> size_type { return ranges::size(r); }),
size_type{0},
plus{});
}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename... Rng>
concat_view(Rng &&...) //
-> concat_view<views::all_t<Rng>...>;
#endif
namespace views
{
struct concat_fn
{
template(typename... Rngs)(
requires and_v<(viewable_range<Rngs> && input_range<Rngs>)...>)
concat_view<all_t<Rngs>...> operator()(Rngs &&... rngs) const
{
return concat_view<all_t<Rngs>...>{all(static_cast<Rngs &&>(rngs))...};
}
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng>)
all_t<Rng> operator()(Rng && rng) const //
{
return all(static_cast<Rng &&>(rng));
}
// MSVC doesn't like variadics in operator() for some reason
#if defined(_MSC_VER)
template(typename Rng0, typename Rng1)(
requires viewable_range<Rng0> AND input_range<Rng0> AND
viewable_range<Rng1> AND input_range<Rng1>)
concat_view<all_t<Rng0>, all_t<Rng1>> operator()(Rng0 && rng0, Rng1 && rng1)
const
{
return concat_view<all_t<Rng0>, all_t<Rng1>>{
all(static_cast<Rng0 &&>(rng0)),
all(static_cast<Rng1 &&>(rng1))};
}
template(typename Rng0, typename Rng1, typename Rng2)(
requires viewable_range<Rng0> AND input_range<Rng0> AND
viewable_range<Rng1> AND input_range<Rng1> AND
viewable_range<Rng2> AND input_range<Rng2>)
concat_view<all_t<Rng0>, all_t<Rng1>, all_t<Rng2>> //
operator()(Rng0 && rng0, Rng1 && rng1, Rng2 && rng2) const
{
return concat_view<all_t<Rng0>, all_t<Rng1>, all_t<Rng2>>{
all(static_cast<Rng0 &&>(rng0)),
all(static_cast<Rng1 &&>(rng1)),
all(static_cast<Rng2 &&>(rng2))};
}
#endif
};
/// \relates concat_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(concat_fn, concat)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::concat_view)
#endif

View File

@@ -0,0 +1,142 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_CONST_HPP
#define RANGES_V3_VIEW_CONST_HPP
#include <type_traits>
#include <utility>
#include <range/v3/range_fwd.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/utility/common_type.hpp>
#include <range/v3/utility/move.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng>
struct const_view : view_adaptor<const_view<Rng>, Rng>
{
private:
friend range_access;
template<bool Const>
struct adaptor : adaptor_base
{
using CRng = meta::const_if_c<Const, Rng>;
using value_ = range_value_t<CRng>;
using reference_ =
common_reference_t<value_ const &&, range_reference_t<CRng>>;
using rvalue_reference_ =
common_reference_t<value_ const &&, range_rvalue_reference_t<CRng>>;
adaptor() = default;
template(bool Other)(
requires Const && CPP_NOT(Other)) //
constexpr adaptor(adaptor<Other>)
{}
reference_ read(iterator_t<CRng> const & it) const
{
return *it;
}
rvalue_reference_ iter_move(iterator_t<CRng> const & it) const
noexcept(noexcept(rvalue_reference_(ranges::iter_move(it))))
{
return ranges::iter_move(it);
}
};
adaptor<simple_view<Rng>()> begin_adaptor()
{
return {};
}
CPP_member
auto begin_adaptor() const //
-> CPP_ret(adaptor<true>)(
requires range<Rng const>)
{
return {};
}
adaptor<simple_view<Rng>()> end_adaptor()
{
return {};
}
CPP_member
auto end_adaptor() const //
-> CPP_ret(adaptor<true>)(
requires range<Rng const>)
{
return {};
}
public:
const_view() = default;
explicit const_view(Rng rng)
: const_view::view_adaptor{std::move(rng)}
{}
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return ranges::size(this->base());
}
CPP_auto_member
constexpr auto CPP_fun(size)()(const
requires sized_range<Rng const>)
{
return ranges::size(this->base());
}
};
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<const_view<Rng>> = //
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
const_view(Rng &&) //
-> const_view<views::all_t<Rng>>;
#endif
namespace views
{
struct const_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng>)
const_view<all_t<Rng>> operator()(Rng && rng) const
{
return const_view<all_t<Rng>>{all(static_cast<Rng &&>(rng))};
}
};
/// \relates const_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<const_fn>, const_)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::const_view)
#endif

View File

@@ -0,0 +1,127 @@
/// \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_COUNTED_HPP
#define RANGES_V3_VIEW_COUNTED_HPP
#include <utility>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/iterator/counted_iterator.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/iterator/traits.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename I>
struct counted_view : view_interface<counted_view<I>, finite>
{
private:
friend range_access;
I it_;
iter_difference_t<I> n_;
public:
counted_view() = default;
counted_view(I it, iter_difference_t<I> n)
: it_(it)
, n_(n)
{
RANGES_EXPECT(0 <= n_);
}
counted_iterator<I> begin() const
{
return make_counted_iterator(it_, n_);
}
default_sentinel_t end() const
{
return {};
}
auto size() const
{
return static_cast<detail::iter_size_t<I>>(n_);
}
};
template<typename I>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<counted_view<I>> = true;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename I>
counted_view(I, iter_difference_t<I>)
-> counted_view<I>;
#endif
namespace views
{
struct cpp20_counted_fn
{
template(typename I)(
requires input_or_output_iterator<I> AND (!random_access_iterator<I>)) //
subrange<counted_iterator<I>, default_sentinel_t> //
operator()(I it, iter_difference_t<I> n) const
{
return {make_counted_iterator(std::move(it), n), default_sentinel};
}
template(typename I)(
requires random_access_iterator<I>)
subrange<I> operator()(I it, iter_difference_t<I> n) const
{
return {it, it + n};
}
};
struct counted_fn
{
template(typename I)(
requires input_or_output_iterator<I> AND (!random_access_iterator<I>)) //
counted_view<I> operator()(I it, iter_difference_t<I> n) const
{
return {std::move(it), n};
}
template(typename I)(
requires random_access_iterator<I>)
subrange<I> operator()(I it, iter_difference_t<I> n) const
{
return {it, it + n};
}
};
/// \relates counted_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(counted_fn, counted)
} // namespace views
namespace cpp20
{
namespace views
{
RANGES_INLINE_VARIABLE(ranges::views::cpp20_counted_fn, counted)
}
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::counted_view)
#endif

View File

@@ -0,0 +1,245 @@
/// \file cycle.hpp
// Range v3 library
//
// Copyright Eric Niebler 2013-present
// Copyright Gonzalo Brito Gadeschi 2015
// Copyright Casey Carter 2015
//
// 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_CYCLE_HPP
#define RANGES_V3_VIEW_CYCLE_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/iterator/unreachable_sentinel.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/box.hpp>
#include <range/v3/utility/get.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng, bool /* = (bool) is_infinite<Rng>() */>
struct RANGES_EMPTY_BASES cycled_view
: view_facade<cycled_view<Rng>, infinite>
, private detail::non_propagating_cache<iterator_t<Rng>, cycled_view<Rng>,
!common_range<Rng>>
{
private:
CPP_assert(forward_range<Rng> && !is_infinite<Rng>::value);
friend range_access;
Rng rng_;
using cache_t = detail::non_propagating_cache<iterator_t<Rng>, cycled_view<Rng>,
!common_range<Rng>>;
template<bool IsConst>
struct cursor
{
private:
friend struct cursor<!IsConst>;
template<typename T>
using constify_if = meta::const_if_c<IsConst, T>;
using cycled_view_t = constify_if<cycled_view>;
using CRng = constify_if<Rng>;
using iterator = iterator_t<CRng>;
cycled_view_t * rng_{};
iterator it_{};
std::intmax_t n_ = 0;
iterator get_end_(std::true_type, bool = false) const
{
return ranges::end(rng_->rng_);
}
template<bool CanBeEmpty = false>
iterator get_end_(std::false_type, meta::bool_<CanBeEmpty> = {}) const
{
auto & end_ = static_cast<cache_t &>(*rng_);
RANGES_EXPECT(CanBeEmpty || end_);
if(CanBeEmpty && !end_)
end_ = ranges::next(it_, ranges::end(rng_->rng_));
return *end_;
}
void set_end_(std::true_type) const
{}
void set_end_(std::false_type) const
{
auto & end_ = static_cast<cache_t &>(*rng_);
if(!end_)
end_ = it_;
}
public:
cursor() = default;
cursor(cycled_view_t * rng)
: rng_(rng)
, it_(ranges::begin(rng->rng_))
{}
template(bool Other)(
requires IsConst AND CPP_NOT(Other)) //
cursor(cursor<Other> that)
: rng_(that.rng_)
, it_(std::move(that.it_))
{}
// clang-format off
auto CPP_auto_fun(read)()(const)
(
return *it_
)
// clang-format on
CPP_member
auto equal(cursor const & pos) const //
-> CPP_ret(bool)(
requires equality_comparable<iterator>)
{
RANGES_EXPECT(rng_ == pos.rng_);
return n_ == pos.n_ && it_ == pos.it_;
}
void next()
{
auto const last = ranges::end(rng_->rng_);
RANGES_EXPECT(it_ != last);
if(++it_ == last)
{
++n_;
this->set_end_(meta::bool_<(bool)common_range<CRng>>{});
it_ = ranges::begin(rng_->rng_);
}
}
CPP_member
auto prev() //
-> CPP_ret(void)(
requires bidirectional_range<CRng>)
{
if(it_ == ranges::begin(rng_->rng_))
{
RANGES_EXPECT(n_ > 0); // decrementing the begin iterator?!
--n_;
it_ = this->get_end_(meta::bool_<(bool)common_range<CRng>>{});
}
--it_;
}
template(typename Diff)(
requires random_access_range<CRng> AND
detail::integer_like_<Diff>)
void advance(Diff n)
{
auto const first = ranges::begin(rng_->rng_);
auto const last = this->get_end_(meta::bool_<(bool)common_range<CRng>>{},
meta::bool_<true>());
auto const dist = last - first;
auto const d = it_ - first;
auto const off = (d + n) % dist;
n_ += (d + n) / dist;
RANGES_EXPECT(n_ >= 0);
using D = range_difference_t<Rng>;
it_ = first + static_cast<D>(off < 0 ? off + dist : off);
}
CPP_auto_member
auto CPP_fun(distance_to)(cursor const & that)(const //
requires sized_sentinel_for<iterator, iterator>)
{
RANGES_EXPECT(that.rng_ == rng_);
auto const first = ranges::begin(rng_->rng_);
auto const last = this->get_end_(meta::bool_<(bool)common_range<Rng>>{},
meta::bool_<true>());
auto const dist = last - first;
return (that.n_ - n_) * dist + (that.it_ - it_);
}
};
CPP_member
auto begin_cursor() //
-> CPP_ret(cursor<false>)(
requires (!simple_view<Rng>() || !common_range<Rng const>))
{
return {this};
}
CPP_member
auto begin_cursor() const //
-> CPP_ret(cursor<true>)(
requires common_range<Rng const>)
{
return {this};
}
unreachable_sentinel_t end_cursor() const
{
return unreachable;
}
public:
cycled_view() = default;
/// \pre <tt>!empty(rng)</tt>
explicit cycled_view(Rng rng)
: rng_(std::move(rng))
{
RANGES_EXPECT(!ranges::empty(rng_));
}
};
template<typename Rng>
struct cycled_view<Rng, true> : identity_adaptor<Rng>
{
CPP_assert(is_infinite<Rng>::value);
using identity_adaptor<Rng>::identity_adaptor;
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
cycled_view(Rng &&) //
-> cycled_view<views::all_t<Rng>>;
#endif
namespace views
{
/// Returns an infinite range that endlessly repeats the source
/// range.
struct cycle_fn
{
/// \pre <tt>!empty(rng)</tt>
template(typename Rng)(
requires viewable_range<Rng> AND forward_range<Rng>)
cycled_view<all_t<Rng>> operator()(Rng && rng) const
{
return cycled_view<all_t<Rng>>{all(static_cast<Rng &&>(rng))};
}
};
/// \relates cycle_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<cycle_fn>, cycle)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::cycled_view)
#endif

View File

@@ -0,0 +1,132 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_DELIMIT_HPP
#define RANGES_V3_VIEW_DELIMIT_HPP
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/iterator/unreachable_sentinel.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng, typename Val>
struct delimit_view
: view_adaptor<delimit_view<Rng, Val>, Rng,
is_finite<Rng>::value ? finite : unknown>
{
private:
friend range_access;
Val value_;
struct sentinel_adaptor : adaptor_base
{
sentinel_adaptor() = default;
sentinel_adaptor(Val value)
: value_(std::move(value))
{}
template<class I, class S>
bool empty(I const & it, S const & last) const
{
return it == last || *it == value_;
}
Val value_;
};
sentinel_adaptor end_adaptor() const
{
return {value_};
}
public:
delimit_view() = default;
constexpr delimit_view(Rng rng, Val value)
: delimit_view::view_adaptor{std::move(rng)}
, value_(std::move(value))
{}
};
// the begin iterator will be an iterator into the underlying view (conditionally
// borrowed) and the end iterator owns the value to be compared against (borrowed)
template<typename Rng, typename Val>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<delimit_view<Rng, Val>> = //
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename Val)(
requires copy_constructible<Val>)
delimit_view(Rng &&, Val)
-> delimit_view<views::all_t<Rng>, Val>;
#endif
namespace views
{
struct delimit_base_fn
{
template(typename I_, typename Val, typename I = detail::decay_t<I_>)(
requires (!range<I_>) AND convertible_to<I_, I> AND input_iterator<I> AND
semiregular<Val> AND
equality_comparable_with<Val, iter_reference_t<I>>)
constexpr auto operator()(I_ && begin_, Val value) const
-> delimit_view<subrange<I, unreachable_sentinel_t>, Val>
{
return {{static_cast<I_ &&>(begin_), {}}, std::move(value)};
}
template(typename Rng, typename Val)(
requires viewable_range<Rng> AND input_range<Rng> AND semiregular<
Val> AND equality_comparable_with<Val, range_reference_t<Rng>>)
constexpr auto operator()(Rng && rng, Val value) const //
-> delimit_view<all_t<Rng>, Val>
{
return {all(static_cast<Rng &&>(rng)), std::move(value)};
}
};
struct delimit_fn : delimit_base_fn
{
using delimit_base_fn::operator();
template<typename Val>
constexpr auto operator()(Val value) const
{
return make_view_closure(bind_back(delimit_base_fn{}, std::move(value)));
}
};
/// \relates delimit_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(delimit_fn, delimit)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::delimit_view)
#endif

View File

@@ -0,0 +1,203 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_DROP_HPP
#define RANGES_V3_VIEW_DROP_HPP
#include <type_traits>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/algorithm/min.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/iterator/traits.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/box.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng>
struct RANGES_EMPTY_BASES drop_view
: view_interface<drop_view<Rng>,
is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
, private detail::non_propagating_cache<iterator_t<Rng>, drop_view<Rng>,
!random_access_range<Rng>>
{
private:
using difference_type_ = range_difference_t<Rng>;
Rng rng_;
difference_type_ n_;
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng>>)
iterator_t<meta::const_if_c<Const, Rng>> //
get_begin_(std::true_type, std::true_type) const
{
CPP_assert(random_access_range<meta::const_if_c<Const, Rng>>);
return next(ranges::begin(rng_), n_, ranges::end(rng_));
}
iterator_t<Rng> get_begin_(std::true_type, std::false_type)
{
CPP_assert(random_access_range<Rng>);
return next(ranges::begin(rng_), n_, ranges::end(rng_));
}
iterator_t<Rng> get_begin_(std::false_type, detail::ignore_t)
{
CPP_assert(!random_access_range<Rng>);
using cache_t =
detail::non_propagating_cache<iterator_t<Rng>, drop_view<Rng>>;
auto & begin_ = static_cast<cache_t &>(*this);
if(!begin_)
begin_ = next(ranges::begin(rng_), n_, ranges::end(rng_));
return *begin_;
}
public:
drop_view() = default;
drop_view(Rng rng, difference_type_ n)
: rng_(std::move(rng))
, n_(n)
{
RANGES_EXPECT(n >= 0);
}
iterator_t<Rng> begin()
{
return this->get_begin_(meta::bool_<random_access_range<Rng>>{},
std::false_type{});
}
sentinel_t<Rng> end()
{
return ranges::end(rng_);
}
template(bool Const = true)(
requires Const AND random_access_range<meta::const_if_c<Const, Rng>>)
iterator_t<meta::const_if_c<Const, Rng>> begin() const
{
return this->get_begin_(std::true_type{}, std::true_type{});
}
template(bool Const = true)(
requires Const AND random_access_range<meta::const_if_c<Const, Rng>>)
sentinel_t<meta::const_if_c<Const, Rng>> end() const
{
return ranges::end(rng_);
}
CPP_auto_member
auto CPP_fun(size)()(const //
requires sized_range<Rng const>)
{
auto const s = ranges::size(rng_);
auto const n = static_cast<range_size_t<Rng const>>(n_);
return s < n ? 0 : s - n;
}
CPP_auto_member
auto CPP_fun(size)()(
requires sized_range<Rng>)
{
auto const s = ranges::size(rng_);
auto const n = static_cast<range_size_t<Rng>>(n_);
return s < n ? 0 : s - n;
}
Rng base() const
{
return rng_;
}
};
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<drop_view<Rng>> = //
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
drop_view(Rng &&, range_difference_t<Rng>)
-> drop_view<views::all_t<Rng>>;
#endif
namespace views
{
struct drop_base_fn
{
private:
template<typename Rng>
static auto impl_(Rng && rng, range_difference_t<Rng> n, input_range_tag)
-> drop_view<all_t<Rng>>
{
return {all(static_cast<Rng &&>(rng)), n};
}
template(typename Rng)(
requires borrowed_range<Rng> AND sized_range<Rng>)
static subrange<iterator_t<Rng>, sentinel_t<Rng>> //
impl_(Rng && rng, range_difference_t<Rng> n, random_access_range_tag)
{
return {begin(rng) + ranges::min(n, distance(rng)), end(rng)};
}
public:
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng>)
auto operator()(Rng && rng, range_difference_t<Rng> n) const
{
return drop_base_fn::impl_(
static_cast<Rng &&>(rng), n, range_tag_of<Rng>{});
}
};
struct drop_fn : drop_base_fn
{
using drop_base_fn::operator();
template(typename Int)(
requires detail::integer_like_<Int>)
constexpr auto operator()(Int n) const
{
return make_view_closure(bind_back(drop_base_fn{}, n));
}
};
/// \relates drop_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(drop_fn, drop)
} // namespace views
namespace cpp20
{
namespace views
{
using ranges::views::drop;
}
template(typename Rng)(
requires view_<Rng>)
using drop_view = ranges::drop_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::drop_view)
#endif

View File

@@ -0,0 +1,184 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_DROP_EXACTLY_HPP
#define RANGES_V3_VIEW_DROP_EXACTLY_HPP
#include <type_traits>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/iterator/traits.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/box.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng>
struct RANGES_EMPTY_BASES drop_exactly_view
: view_interface<drop_exactly_view<Rng>,
is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
, private detail::non_propagating_cache<iterator_t<Rng>, drop_exactly_view<Rng>,
!random_access_range<Rng>>
{
private:
using difference_type_ = range_difference_t<Rng>;
Rng rng_;
difference_type_ n_;
// random_access_range == true
template(bool Const = true)(
requires Const AND random_access_range<meta::const_if_c<Const, Rng>>)
iterator_t<meta::const_if_c<Const, Rng>> get_begin_(std::true_type) const
{
return next(ranges::begin(rng_), n_);
}
iterator_t<Rng> get_begin_(std::true_type)
{
return next(ranges::begin(rng_), n_);
}
// random_access_range == false
iterator_t<Rng> get_begin_(std::false_type)
{
using cache_t =
detail::non_propagating_cache<iterator_t<Rng>, drop_exactly_view<Rng>>;
auto & begin_ = static_cast<cache_t &>(*this);
if(!begin_)
begin_ = next(ranges::begin(rng_), n_);
return *begin_;
}
public:
drop_exactly_view() = default;
drop_exactly_view(Rng rng, difference_type_ n)
: rng_(std::move(rng))
, n_(n)
{
RANGES_EXPECT(n >= 0);
}
iterator_t<Rng> begin()
{
return this->get_begin_(meta::bool_<random_access_range<Rng>>{});
}
sentinel_t<Rng> end()
{
return ranges::end(rng_);
}
template(bool Const = true)(
requires Const AND random_access_range<meta::const_if_c<Const, Rng>>)
iterator_t<meta::const_if_c<Const, Rng>> begin() const
{
return this->get_begin_(std::true_type{});
}
template(bool Const = true)(
requires Const AND random_access_range<meta::const_if_c<Const, Rng>>)
sentinel_t<meta::const_if_c<Const, Rng>> end() const
{
return ranges::end(rng_);
}
CPP_auto_member
auto CPP_fun(size)()(const
requires sized_range<Rng const>)
{
return ranges::size(rng_) - static_cast<range_size_t<Rng const>>(n_);
}
CPP_auto_member
auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return ranges::size(rng_) - static_cast<range_size_t<Rng>>(n_);
}
Rng base() const
{
return rng_;
}
};
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<drop_exactly_view<Rng>> = //
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
drop_exactly_view(Rng &&, range_difference_t<Rng>)
->drop_exactly_view<views::all_t<Rng>>;
#endif
namespace views
{
struct drop_exactly_base_fn
{
private:
template<typename Rng>
static auto impl_(Rng && rng, range_difference_t<Rng> n, input_range_tag)
-> drop_exactly_view<all_t<Rng>>
{
return {all(static_cast<Rng &&>(rng)), n};
}
template(typename Rng)(
requires borrowed_range<Rng>)
static subrange<iterator_t<Rng>, sentinel_t<Rng>> //
impl_(Rng && rng, range_difference_t<Rng> n, random_access_range_tag)
{
return {begin(rng) + n, end(rng)};
}
public:
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng>)
auto operator()(Rng && rng, range_difference_t<Rng> n) const
{
return drop_exactly_base_fn::impl_(
static_cast<Rng &&>(rng), n, range_tag_of<Rng>{});
}
};
struct drop_exactly_fn : drop_exactly_base_fn
{
using drop_exactly_base_fn::operator();
template(typename Int)(
requires detail::integer_like_<Int>)
constexpr auto operator()(Int n) const
{
return make_view_closure(bind_back(drop_exactly_base_fn{}, n));
}
};
/// \relates drop_exactly_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(drop_exactly_fn, drop_exactly)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::drop_exactly_view)
#endif

View File

@@ -0,0 +1,373 @@
/// \file
// Range v3 library
//
// Copyright Andrey Diduh 2019
//
// 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_DROP_LAST_HPP
#define RANGES_V3_VIEW_DROP_LAST_HPP
#include <type_traits>
#include <meta/meta.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/iterator/counted_iterator.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
/// \cond
namespace detail
{
namespace drop_last_view
{
template<typename Rng>
range_size_t<Rng> get_size(Rng & rng, range_difference_t<Rng> n_)
{
RANGES_EXPECT(n_ >= 0);
range_size_t<Rng> const initial_size = ranges::size(rng);
range_size_t<Rng> const n = static_cast<range_size_t<Rng>>(n_);
return initial_size > n ? initial_size - n : 0;
}
template(typename Rng)(
requires random_access_range<Rng> AND sized_range<Rng>)
iterator_t<Rng> get_end(Rng & rng, range_difference_t<Rng> n, int)
{
return begin(rng) + static_cast<range_difference_t<Rng>>(
drop_last_view::get_size(rng, n));
}
template(typename Rng)(
requires bidirectional_range<Rng> AND common_range<Rng>)
iterator_t<Rng> get_end(Rng & rng, range_difference_t<Rng> n, long)
{
return prev(end(rng), n, begin(rng));
}
enum class mode_enum
{
bidi,
forward,
sized,
invalid
};
template<mode_enum Mode>
using mode_t = std::integral_constant<mode_enum, Mode>;
using mode_bidi = mode_t<mode_enum::bidi>;
using mode_forward = mode_t<mode_enum::forward>;
using mode_sized = mode_t<mode_enum::sized>;
using mode_invalid = mode_t<mode_enum::invalid>;
template<typename Rng>
constexpr mode_enum get_mode() noexcept
{
// keep range bound
// Sized Bidi O(N)
return (random_access_range<Rng> && view_<Rng> && sized_range<Rng>) ||
(bidirectional_range<Rng> && view_<Rng> &&
common_range<Rng>)
? mode_enum::bidi //
: sized_range<Rng> && view_<Rng> //
? mode_enum::sized //
: forward_range<Rng> && view_<Rng> //
? mode_enum::forward //
: mode_enum::invalid; //
// max performance
// Sized Bidi O(1)
// Sized Bidi use mode::sized instead of mode::bidi - thus become unbound.
/*return (random_access_range<Rng> && view_<Rng> && sized_range<Rng> &&
view_<Rng>) || (bidirectional_range<Rng> && view_<Rng> &&
common_range<Rng> && view_<Rng>) ? mode::bidi : sized_range<Rng> &&
view_<Rng> ? mode::sized : bidirectional_range<Rng> && view_<Rng> &&
common_range<Rng> && view_<Rng> ? mode::bidi : forward_range<Rng> &&
view_<Rng> ? mode::forward : mode::invalid;*/
}
template<typename Rng>
using mode_of = mode_t<drop_last_view::get_mode<Rng>()>;
} // namespace drop_last_view
} // namespace detail
/// \endcond
template<typename Rng, typename = detail::drop_last_view::mode_of<Rng>>
struct drop_last_view
{};
template<typename Rng>
struct drop_last_view<Rng, detail::drop_last_view::mode_bidi>
: view_interface<drop_last_view<Rng, detail::drop_last_view::mode_bidi>,
is_finite<Rng>::value
? finite
: range_cardinality<Rng>::value> // finite at best
{
CPP_assert(
(random_access_range<Rng> && view_<Rng> && sized_range<Rng>) ||
(bidirectional_range<Rng> && view_<Rng> && common_range<Rng>));
private:
friend range_access;
using difference_t = range_difference_t<Rng>;
Rng rng_;
difference_t n_;
detail::non_propagating_cache<iterator_t<Rng>> end_;
public:
drop_last_view() = default;
constexpr drop_last_view(Rng rng, difference_t n)
: rng_(std::move(rng))
, n_(n)
{
RANGES_EXPECT(n >= 0);
}
iterator_t<Rng> begin()
{
return ranges::begin(rng_);
}
sentinel_t<Rng> end()
{
if(!end_)
end_ = detail::drop_last_view::get_end(rng_, n_, 0);
return *end_;
}
template(typename CRng = Rng const)(
requires random_access_range<CRng> AND sized_range<CRng>)
iterator_t<CRng> begin() const
{
return ranges::begin(rng_);
}
template(typename CRng = Rng const)(
requires random_access_range<CRng> AND sized_range<CRng>)
iterator_t<CRng> end() const
{
return detail::drop_last_view::get_end(rng_, n_, 0);
}
CPP_auto_member
auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return detail::drop_last_view::get_size(rng_, n_);
}
CPP_auto_member
auto CPP_fun(size)()(const //
requires sized_range<Rng const>)
{
return detail::drop_last_view::get_size(rng_, n_);
}
Rng & base()
{
return rng_;
}
Rng const & base() const
{
return rng_;
}
};
template<typename Rng>
struct drop_last_view<Rng, detail::drop_last_view::mode_forward>
: view_adaptor<drop_last_view<Rng, detail::drop_last_view::mode_forward>, Rng,
is_finite<Rng>::value
? finite
: range_cardinality<Rng>::value> // finite at best (but
// unknown is expected)
{
CPP_assert(forward_range<Rng> && view_<Rng>);
private:
friend range_access;
using difference_t = range_difference_t<Rng>;
difference_t n_;
detail::non_propagating_cache<iterator_t<Rng>> probe_begin;
struct adaptor : adaptor_base
{
iterator_t<Rng> probe_;
adaptor() = default;
adaptor(iterator_t<Rng> probe_first)
: probe_(std::move(probe_first))
{}
void next(iterator_t<Rng> & it)
{
++it;
++probe_;
}
};
struct sentinel_adaptor : adaptor_base
{
template<typename I, typename S>
bool empty(I const &, adaptor const & ia, S const & s) const
{
return ia.probe_ == s;
}
};
adaptor begin_adaptor()
{
if(!probe_begin)
probe_begin = next(begin(this->base()), n_, end(this->base()));
return {*probe_begin};
}
sentinel_adaptor end_adaptor()
{
return {};
}
public:
drop_last_view() = default;
constexpr drop_last_view(Rng rng, difference_t n)
: drop_last_view::view_adaptor(std::move(rng))
, n_(n)
{
RANGES_EXPECT(n >= 0);
}
CPP_auto_member
auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return detail::drop_last_view::get_size(this->base(), n_);
}
CPP_auto_member
auto CPP_fun(size)()(const //
requires sized_range<Rng const>)
{
return detail::drop_last_view::get_size(this->base(), n_);
}
};
template<typename Rng>
struct drop_last_view<Rng, detail::drop_last_view::mode_sized>
: view_interface<drop_last_view<Rng, detail::drop_last_view::mode_sized>, finite>
{
CPP_assert(sized_range<Rng> && view_<Rng>);
private:
friend range_access;
using difference_t = range_difference_t<Rng>;
Rng rng_;
difference_t n_;
public:
drop_last_view() = default;
constexpr drop_last_view(Rng rng, difference_t n)
: rng_(std::move(rng))
, n_(n)
{
RANGES_EXPECT(n >= 0);
}
counted_iterator<iterator_t<Rng>> begin()
{
return {ranges::begin(rng_), static_cast<difference_t>(size())};
}
template(typename CRng = Rng const)(
requires sized_range<CRng>)
counted_iterator<iterator_t<CRng>> begin() const
{
return {ranges::begin(rng_), static_cast<difference_t>(size())};
}
default_sentinel_t end() const
{
return {};
}
range_size_t<Rng> size()
{
return detail::drop_last_view::get_size(this->base(), n_);
}
CPP_auto_member
auto CPP_fun(size)()(const //
requires sized_range<Rng const>)
{
return detail::drop_last_view::get_size(this->base(), n_);
}
Rng & base()
{
return rng_;
}
Rng const & base() const
{
return rng_;
}
};
template<typename Rng, typename T>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<drop_last_view<Rng, T>> = //
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
drop_last_view(Rng &&, range_difference_t<Rng>)
-> drop_last_view<views::all_t<Rng>>;
#endif
namespace views
{
struct drop_last_base_fn
{
template(typename Rng)(
requires sized_range<Rng> || forward_range<Rng>)
constexpr auto operator()(Rng && rng, range_difference_t<Rng> n) const
-> drop_last_view<all_t<Rng>>
{
return {all(static_cast<Rng &&>(rng)), n};
}
};
struct drop_last_fn : drop_last_base_fn
{
using drop_last_base_fn::operator();
template(typename Int)(
requires detail::integer_like_<Int>)
constexpr auto operator()(Int n) const
{
return make_view_closure(bind_back(drop_last_base_fn{}, n));
}
};
RANGES_INLINE_VARIABLE(drop_last_fn, drop_last)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::drop_last_view)
#endif

View File

@@ -0,0 +1,165 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_DROP_WHILE_HPP
#define RANGES_V3_VIEW_DROP_WHILE_HPP
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/algorithm/find_if_not.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/compose.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng, typename Pred>
struct drop_while_view
: view_interface<drop_while_view<Rng, Pred>,
is_finite<Rng>::value ? finite : unknown>
{
private:
Rng rng_;
RANGES_NO_UNIQUE_ADDRESS semiregular_box_t<Pred> pred_;
detail::non_propagating_cache<iterator_t<Rng>> begin_;
iterator_t<Rng> get_begin_()
{
if(!begin_)
begin_ = find_if_not(rng_, std::ref(pred_));
return *begin_;
}
public:
drop_while_view() = default;
drop_while_view(Rng rng, Pred pred)
: rng_(std::move(rng))
, pred_(std::move(pred))
{}
iterator_t<Rng> begin()
{
return get_begin_();
}
sentinel_t<Rng> end()
{
return ranges::end(rng_);
}
Rng base() const
{
return rng_;
}
};
// unlike take_while_view, drop_while_view is transparently safe because we only
// need the predicate to find begin()
template<typename Rng, typename Pred>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<drop_while_view<Rng, Pred>> =
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename Fun)(
requires copy_constructible<Fun>)
drop_while_view(Rng &&, Fun)
-> drop_while_view<views::all_t<Rng>, Fun>;
#endif
template<typename Rng, typename Pred>
RANGES_INLINE_VAR constexpr bool disable_sized_range<drop_while_view<Rng, Pred>> =
true;
namespace views
{
struct drop_while_base_fn
{
template(typename Rng, typename Pred)(
requires viewable_range<Rng> AND input_range<Rng> AND
indirect_unary_predicate<Pred, iterator_t<Rng>>)
auto operator()(Rng && rng, Pred pred) const
-> drop_while_view<all_t<Rng>, Pred>
{
return {all(static_cast<Rng &&>(rng)), std::move(pred)};
}
template(typename Rng, typename Pred, typename Proj)(
requires viewable_range<Rng> AND input_range<Rng> AND
indirect_unary_predicate<composed<Pred, Proj>, iterator_t<Rng>>)
auto operator()(Rng && rng, Pred pred, Proj proj) const
-> drop_while_view<all_t<Rng>, composed<Pred, Proj>>
{
return {all(static_cast<Rng &&>(rng)),
compose(std::move(pred), std::move(proj))};
}
};
struct drop_while_bind_fn
{
template<typename Pred>
constexpr auto operator()(Pred pred) const // TODO: underconstrained
{
return make_view_closure(
bind_back(drop_while_base_fn{}, std::move(pred)));
}
template(typename Pred, typename Proj)(
requires (!range<Pred>)) // TODO: underconstrained
constexpr auto operator()(Pred && pred, Proj proj) const
{
return make_view_closure(bind_back(
drop_while_base_fn{}, static_cast<Pred &&>(pred), std::move(proj)));
}
};
struct RANGES_EMPTY_BASES drop_while_fn
: drop_while_base_fn, drop_while_bind_fn
{
using drop_while_base_fn::operator();
using drop_while_bind_fn::operator();
};
/// \relates drop_while_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(drop_while_fn, drop_while)
} // namespace views
namespace cpp20
{
namespace views
{
using ranges::views::drop_while;
}
template(typename Rng, typename Pred)(
requires viewable_range<Rng> AND input_range<Rng> AND
indirect_unary_predicate<Pred, iterator_t<Rng>>)
using drop_while_view = ranges::drop_while_view<Rng, Pred>;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::drop_while_view)
#endif

View File

@@ -0,0 +1,85 @@
/// \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_EMPTY_HPP
#define RANGES_V3_VIEW_EMPTY_HPP
#include <range/v3/range_fwd.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename T>
struct empty_view : view_interface<empty_view<T>, (cardinality)0>
{
static_assert(std::is_object<T>::value,
"The template parameter to empty_view must be an object type.");
empty_view() = default;
static constexpr T * begin() noexcept
{
return nullptr;
}
static constexpr T * end() noexcept
{
return nullptr;
}
static constexpr std::size_t size() noexcept
{
return 0u;
}
static constexpr T * data() noexcept
{
return nullptr;
}
RANGES_DEPRECATED(
"Replace views::empty<T>() with views::empty<T>. "
"It is now a variable template.")
empty_view operator()() const
{
return *this;
}
};
template<typename T>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<empty_view<T>> = true;
namespace views
{
template<typename T>
RANGES_INLINE_VAR constexpr empty_view<T> empty{};
}
namespace cpp20
{
namespace views
{
using ranges::views::empty;
}
template(typename T)(
requires std::is_object<T>::value) //
using empty_view = ranges::empty_view<T>;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::empty_view)
#endif

View File

@@ -0,0 +1,123 @@
/// \file
// Range v3 library
//
// Copyright Casey Carter 2018-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_ENUMERATE_HPP
#define RANGES_V3_VIEW_ENUMERATE_HPP
#include <range/v3/core.hpp>
#include <range/v3/iterator/unreachable_sentinel.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/view/zip.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
// Counts from zero up.
// See https://github.com/ericniebler/range-v3/issues/1141
// for why we don't just use iota_view.
template<typename Size, typename Diff>
struct index_view : view_facade<index_view<Size, Diff>, infinite>
{
private:
friend range_access;
struct cursor
{
using difference_type = Diff;
private:
friend range_access;
Size index_{0};
Size read() const
{
return index_;
}
void next()
{
++index_;
}
bool equal(cursor const & that) const
{
return that.index_ == index_;
}
void prev()
{
--index_;
}
void advance(Diff n)
{
index_ += static_cast<Size>(n);
}
Diff distance_to(cursor const & that) const
{
return static_cast<Diff>(static_cast<Diff>(that.index_) -
static_cast<Diff>(index_));
}
public:
cursor() = default;
};
cursor begin_cursor() const
{
return cursor{};
}
unreachable_sentinel_t end_cursor() const
{
return unreachable;
}
public:
index_view() = default;
};
} // namespace detail
template<typename Size, typename Diff>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<detail::index_view<Size, Diff>> =
true;
/// \endcond
/// \addtogroup group-views
/// @{
namespace views
{
/// Lazily pairs each element in a source range with
/// its corresponding index.
struct enumerate_fn
{
template(typename Rng)(
requires viewable_range<Rng>)
auto operator()(Rng && rng) const
{
using D = range_difference_t<Rng>;
using S = detail::iter_size_t<iterator_t<Rng>>;
return zip(detail::index_view<S, D>(), all(static_cast<Rng &&>(rng)));
}
};
/// \relates enumerate_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<enumerate_fn>, enumerate)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,197 @@
/// \file
// Range v3 library
//
// Copyright Mitsutaka Takeda 2018-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_EXCLUSIVE_SCAN_HPP
#define RANGES_V3_VIEW_EXCLUSIVE_SCAN_HPP
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/arithmetic.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
// clang-format off
/// \concept exclusive_scan_constraints_
/// \brief The \c exclusive_scan_constraints_ concept
template(typename Rng, typename T, typename Fun)(
concept (exclusive_scan_constraints_)(Rng, T, Fun),
invocable<Fun &, T, range_reference_t<Rng>> AND
assignable_from<T &, invoke_result_t<Fun &, T, range_reference_t<Rng>>>
);
/// \concept exclusive_scan_constraints
/// \brief The \c exclusive_scan_constraints concept
template<typename Rng, typename T, typename Fun>
CPP_concept exclusive_scan_constraints =
viewable_range<Rng> && input_range<Rng> &&
copy_constructible<T> &&
CPP_concept_ref(ranges::exclusive_scan_constraints_, Rng, T, Fun);
// clang-format on
/// \addtogroup group-views
/// @{
template<typename Rng, typename T, typename Fun>
struct exclusive_scan_view : view_adaptor<exclusive_scan_view<Rng, T, Fun>, Rng>
{
private:
friend range_access;
CPP_assert(exclusive_scan_constraints<Rng, T, Fun>);
semiregular_box_t<T> init_;
semiregular_box_t<Fun> fun_;
using single_pass = meta::bool_<single_pass_iterator_<iterator_t<Rng>>>;
using use_sentinel_t = meta::bool_<!common_range<Rng> || single_pass{}>;
template<bool IsConst>
struct adaptor : adaptor_base
{
private:
friend struct adaptor<!IsConst>;
using exclusive_scan_view_t = meta::const_if_c<IsConst, exclusive_scan_view>;
using CRng = meta::const_if_c<IsConst, Rng>;
semiregular_box_t<T> sum_;
exclusive_scan_view_t * rng_;
// clang-format off
auto CPP_auto_fun(move_or_copy_init)(std::false_type)
(
return (rng_->init_)
)
// If the base range is single-pass, we can move the init value.
auto CPP_auto_fun(move_or_copy_init)(std::true_type)
(
return std::move(rng_->init_)
)
// clang-format on
public : using single_pass = exclusive_scan_view::single_pass;
adaptor() = default;
adaptor(exclusive_scan_view_t * rng)
: rng_(rng)
{}
template(bool Other)(
requires IsConst AND CPP_NOT(Other)) //
adaptor(adaptor<Other> that)
: rng_(that.rng_)
{}
iterator_t<CRng> begin(exclusive_scan_view_t &)
{
sum_ = move_or_copy_init(single_pass{});
return ranges::begin(rng_->base());
}
T read(iterator_t<CRng> const &) const
{
return sum_;
}
void next(iterator_t<CRng> & it)
{
RANGES_EXPECT(it != ranges::end(rng_->base()));
sum_ = invoke(rng_->fun_, static_cast<T &&>(std::move(sum_)), *it);
++it;
}
void prev() = delete;
};
adaptor<false> begin_adaptor()
{
return {this};
}
meta::if_<use_sentinel_t, adaptor_base, adaptor<false>> end_adaptor()
{
return {this};
}
CPP_member
auto begin_adaptor() const //
-> CPP_ret(adaptor<true>)(
requires exclusive_scan_constraints<Rng const, T, Fun const>)
{
return {this};
}
CPP_member
auto end_adaptor() const
-> CPP_ret(meta::if_<use_sentinel_t, adaptor_base, adaptor<true>>)(
requires exclusive_scan_constraints<Rng const, T, Fun const>)
{
return {this};
}
public:
exclusive_scan_view() = default;
constexpr exclusive_scan_view(Rng rng, T init, Fun fun)
: exclusive_scan_view::view_adaptor{std::move(rng)}
, init_(std::move(init))
, fun_(std::move(fun))
{}
CPP_auto_member
auto CPP_fun(size)()(const
requires sized_range<Rng const>)
{
return ranges::size(this->base());
}
CPP_auto_member
auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return ranges::size(this->base());
}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename T, typename Fun)(
requires copy_constructible<T> AND copy_constructible<Fun>)
exclusive_scan_view(Rng &&, T, Fun) //
-> exclusive_scan_view<views::all_t<Rng>, T, Fun>;
#endif
namespace views
{
struct exclusive_scan_base_fn
{
template(typename Rng, typename T, typename Fun = plus)(
requires exclusive_scan_constraints<Rng, T, Fun>)
constexpr exclusive_scan_view<all_t<Rng>, T, Fun> //
operator()(Rng && rng, T init, Fun fun = Fun{}) const
{
return {all(static_cast<Rng &&>(rng)), std::move(init), std::move(fun)};
}
};
struct exclusive_scan_fn : exclusive_scan_base_fn
{
using exclusive_scan_base_fn::operator();
template<typename T, typename Fun = plus>
constexpr auto operator()(T init, Fun fun = {}) const
{
return make_view_closure(
bind_back(exclusive_scan_base_fn{}, std::move(init), std::move(fun)));
}
};
/// \relates exclusive_scan_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(exclusive_scan_fn, exclusive_scan)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_VIEW_EXCLUSIVE_SCAN_HPP

View File

@@ -0,0 +1,137 @@
/// \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_FACADE_HPP
#define RANGES_V3_VIEW_FACADE_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/basic_iterator.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/iterator/traits.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
template<typename Derived>
using begin_cursor_t = detail::decay_t<decltype(
range_access::begin_cursor(std::declval<Derived &>()))>;
template<typename Derived>
using end_cursor_t = detail::decay_t<decltype(
range_access::end_cursor(std::declval<Derived &>()))>;
template<typename Derived>
using facade_iterator_t = basic_iterator<begin_cursor_t<Derived>>;
template<typename Derived>
using facade_sentinel_t =
meta::if_c<same_as<begin_cursor_t<Derived>, end_cursor_t<Derived>>,
facade_iterator_t<Derived>, end_cursor_t<Derived>>;
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
/// \brief A utility for constructing a view from a (derived) type that
/// implements begin and end cursors.
/// \tparam Derived A type that derives from `view_facade` and implements
/// begin and end cursors. This type is permitted to be incomplete.
/// \tparam Cardinality The cardinality of this view: `finite`, `infinite`,
/// or `unknown`. See `ranges::cardinality`.
template<typename Derived, cardinality Cardinality>
struct view_facade : view_interface<Derived, Cardinality>
{
protected:
friend range_access;
struct view_as_cursor : Derived
{
view_as_cursor() = default;
explicit view_as_cursor(Derived const * derived)
: Derived(*derived)
{}
explicit operator bool() = delete;
explicit operator bool() const = delete;
};
// Default implementations
constexpr view_as_cursor begin_cursor() const
{
return view_as_cursor{static_cast<Derived const *>(this)};
}
constexpr default_sentinel_t end_cursor() const
{
return {};
}
public:
/// Let `d` be `static_cast<Derived &>(*this)`. Let `b` be
/// `std::as_const(d).begin_cursor()` if that expression is well-formed;
/// otherwise, let `b` be `d.begin_cursor()`. Let `B` be the type of
/// `b`.
/// \return `ranges::basic_iterator<B>(b)`
template(typename D = Derived)(
requires same_as<D, Derived>)
constexpr auto begin() -> detail::facade_iterator_t<D>
{
return detail::facade_iterator_t<D>{
range_access::begin_cursor(*static_cast<Derived *>(this))};
}
/// \overload
template(typename D = Derived)(
requires same_as<D, Derived>)
constexpr auto begin() const -> detail::facade_iterator_t<D const>
{
return detail::facade_iterator_t<D const>{
range_access::begin_cursor(*static_cast<Derived const *>(this))};
}
/// Let `d` be `static_cast<Derived &>(*this)`. Let `e` be
/// `std::as_const(d).end_cursor()` if that expression is well-formed;
/// otherwise, let `e` be `d.end_cursor()`. Let `E` be the type of
/// `e`.
/// \return `ranges::basic_iterator<E>(e)` if `E` is the same
/// as `B` computed above for `begin()`; otherwise, return `e`.
template(typename D = Derived)(
requires same_as<D, Derived>)
constexpr auto end() -> detail::facade_sentinel_t<D>
{
return static_cast<detail::facade_sentinel_t<D>>(
range_access::end_cursor(*static_cast<Derived *>(this)));
}
/// \overload
template(typename D = Derived)(
requires same_as<D, Derived>)
constexpr auto end() const -> detail::facade_sentinel_t<D const>
{
return static_cast<detail::facade_sentinel_t<D const>>(
range_access::end_cursor(*static_cast<Derived const *>(this)));
}
};
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,171 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_FILTER_HPP
#define RANGES_V3_VIEW_FILTER_HPP
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/compose.hpp>
#include <range/v3/functional/not_fn.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/remove_if.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng, typename Pred>
struct filter_view : remove_if_view<Rng, logical_negate<Pred>>
{
filter_view() = default;
constexpr filter_view(Rng rng, Pred pred)
: filter_view::remove_if_view{std::move(rng), not_fn(std::move(pred))}
{}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename Pred)(
requires input_range<Rng> AND indirect_unary_predicate<Pred, iterator_t<Rng>> AND
view_<Rng> AND std::is_object<Pred>::value) //
filter_view(Rng &&, Pred)
->filter_view<views::all_t<Rng>, Pred>;
#endif
namespace views
{
struct filter_fn;
/// Given a source range and a unary predicate,
/// present a view of the elements that satisfy the predicate.
struct cpp20_filter_base_fn
{
template(typename Rng, typename Pred)(
requires viewable_range<Rng> AND input_range<Rng> AND
indirect_unary_predicate<Pred, iterator_t<Rng>>)
constexpr filter_view<all_t<Rng>, Pred> operator()(Rng && rng, Pred pred) //
const
{
return filter_view<all_t<Rng>, Pred>{all(static_cast<Rng &&>(rng)),
std::move(pred)};
}
};
struct cpp20_filter_fn : cpp20_filter_base_fn
{
using cpp20_filter_base_fn::operator();
template<typename Pred>
constexpr auto operator()(Pred pred) const
{
return make_view_closure(
bind_back(cpp20_filter_base_fn{}, std::move(pred)));
}
};
/// Given a source range, unary predicate, and optional projection,
/// present a view of the elements that satisfy the predicate.
struct filter_base_fn : cpp20_filter_base_fn
{
using cpp20_filter_base_fn::operator();
template(typename Rng, typename Pred, typename Proj)(
requires viewable_range<Rng> AND input_range<Rng> AND
indirect_unary_predicate<Pred, projected<iterator_t<Rng>, Proj>>)
constexpr filter_view<all_t<Rng>, composed<Pred, Proj>> //
operator()(Rng && rng, Pred pred, Proj proj) const
{
return filter_view<all_t<Rng>, composed<Pred, Proj>>{
all(static_cast<Rng &&>(rng)),
compose(std::move(pred), std::move(proj))};
}
};
/// # ranges::views::filter
/// The filter view takes in a predicate function `T -> bool` and converts an
/// input range of `T` into an output range of `T` by keeping all elements for
/// which the predicate returns true.
///
/// ## Example
/// \snippet example/view/filter.cpp filter example
///
/// ### Output
/// \include example/view/filter_golden.txt
///
/// ## Syntax
/// ```cpp
/// auto output_range = input_range | ranges::views::filter(filter_func);
/// ```
///
/// ## Parameters
/// <pre><b>filter_func</b></pre>
/// - Called once for each element of the input range
/// - Returns true for elements that should present in the output range
///
/// <pre><b>input_range</b></pre>
/// - The range of elements to filter
/// - Reference type: `T`
///
/// <pre><b>output_range</b></pre>
/// - The range of filtered values
/// - Is either a `forward_range` or the concept satisfied by the input
/// - Is a `common_range` if the input is a `common_range`
/// - Is not a `sized_range` or `borrowed_range`
/// - Reference type: `T`
///
struct filter_fn : filter_base_fn
{
using filter_base_fn::operator();
template<typename Pred>
constexpr auto operator()(Pred pred) const
{
return make_view_closure(bind_back(filter_base_fn{}, std::move(pred)));
}
template(typename Pred, typename Proj)(
requires (!range<Pred>))
constexpr auto operator()(Pred pred, Proj proj) const
{
return make_view_closure(
bind_back(filter_base_fn{}, std::move(pred), std::move(proj)));
}
};
/// \relates filter_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(filter_fn, filter)
} // namespace views
namespace cpp20
{
namespace views
{
RANGES_INLINE_VARIABLE(ranges::views::cpp20_filter_fn, filter)
}
template(typename V, typename Pred)(
requires input_range<V> AND indirect_unary_predicate<Pred, iterator_t<V>> AND
view_<V> AND std::is_object<Pred>::value) //
using filter_view = ranges::filter_view<V, Pred>;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::filter_view)
#endif

View File

@@ -0,0 +1,138 @@
/// \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_FOR_EACH_HPP
#define RANGES_V3_VIEW_FOR_EACH_HPP
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/generate_n.hpp>
#include <range/v3/view/join.hpp>
#include <range/v3/view/repeat_n.hpp>
#include <range/v3/view/single.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
namespace views
{
/// Lazily applies an unary function to each element in the source
/// range that returns another range (possibly empty), flattening
/// the result.
struct for_each_base_fn
{
template(typename Rng, typename Fun)(
requires viewable_range<Rng> AND transformable_range<Rng, Fun> AND
joinable_range<transform_view<all_t<Rng>, Fun>>)
constexpr auto operator()(Rng && rng, Fun fun) const
{
return join(transform(static_cast<Rng &&>(rng), std::move(fun)));
}
};
struct for_each_fn : for_each_base_fn
{
using for_each_base_fn::operator();
template<typename Fun>
constexpr auto operator()(Fun fun) const
{
return make_view_closure(bind_back(for_each_base_fn{}, std::move(fun)));
}
};
/// \relates for_each_fn
RANGES_INLINE_VARIABLE(for_each_fn, for_each)
} // namespace views
struct yield_fn
{
template(typename V)(
requires copy_constructible<V>)
single_view<V> operator()(V v) const
{
return views::single(std::move(v));
}
};
/// \relates yield_fn
RANGES_INLINE_VARIABLE(yield_fn, yield)
struct yield_from_fn
{
template(typename Rng)(
requires view_<Rng>)
Rng operator()(Rng rng) const
{
return rng;
}
};
/// \relates yield_from_fn
RANGES_INLINE_VARIABLE(yield_from_fn, yield_from)
struct yield_if_fn
{
template<typename V>
repeat_n_view<V> operator()(bool b, V v) const
{
return views::repeat_n(std::move(v), b ? 1 : 0);
}
};
/// \relates yield_if_fn
RANGES_INLINE_VARIABLE(yield_if_fn, yield_if)
struct lazy_yield_if_fn
{
template(typename F)(
requires invocable<F &>)
generate_n_view<F> operator()(bool b, F f) const
{
return views::generate_n(std::move(f), b ? 1 : 0);
}
};
/// \relates lazy_yield_if_fn
RANGES_INLINE_VARIABLE(lazy_yield_if_fn, lazy_yield_if)
/// @}
/// \cond
template(typename Rng, typename Fun)(
requires viewable_range<Rng> AND views::transformable_range<Rng, Fun> AND
input_range<invoke_result_t<Fun &, range_reference_t<Rng>>>)
auto
operator>>=(Rng && rng, Fun fun)
{
return views::for_each(static_cast<Rng &&>(rng), std::move(fun));
}
/// \endcond
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,120 @@
/// \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_GENERATE_HPP
#define RANGES_V3_VIEW_GENERATE_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/iterator/unreachable_sentinel.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename G>
struct generate_view : view_facade<generate_view<G>, infinite>
{
private:
friend range_access;
using result_t = invoke_result_t<G &>;
semiregular_box_t<G> gen_;
detail::non_propagating_cache<result_t> val_;
struct cursor
{
private:
generate_view * view_;
public:
cursor() = default;
explicit cursor(generate_view * view)
: view_(view)
{}
result_t && read() const
{
if(!view_->val_)
view_->val_.emplace(view_->gen_());
return static_cast<result_t &&>(static_cast<result_t &>(*view_->val_));
}
void next()
{
if(view_->val_)
view_->val_.reset();
else
static_cast<void>(view_->gen_());
}
};
cursor begin_cursor()
{
return cursor{this};
}
unreachable_sentinel_t end_cursor() const
{
return {};
}
public:
generate_view() = default;
explicit generate_view(G g)
: gen_(std::move(g))
{}
result_t & cached()
{
return *val_;
}
};
namespace views
{
struct generate_fn
{
template(typename G)(
requires invocable<G &> AND copy_constructible<G> AND
std::is_object<detail::decay_t<invoke_result_t<G &>>>::value AND
constructible_from<detail::decay_t<invoke_result_t<G &>>,
invoke_result_t<G &>> AND
assignable_from<detail::decay_t<invoke_result_t<G &>> &,
invoke_result_t<G &>>)
generate_view<G> operator()(G g) const
{
return generate_view<G>{std::move(g)};
}
};
/// \relates generate_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(generate_fn, generate)
} // namespace views
/// \@}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::generate_view)
#endif

View File

@@ -0,0 +1,127 @@
/// \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_GENERATE_N_HPP
#define RANGES_V3_VIEW_GENERATE_N_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/view/generate.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename G>
struct generate_n_view : view_facade<generate_n_view<G>, finite>
{
private:
friend range_access;
using result_t = invoke_result_t<G &>;
semiregular_box_t<G> gen_;
detail::non_propagating_cache<result_t> val_;
std::size_t n_;
struct cursor
{
private:
generate_n_view * rng_;
public:
cursor() = default;
explicit cursor(generate_n_view * rng)
: rng_(rng)
{}
bool equal(default_sentinel_t) const
{
return 0 == rng_->n_;
}
result_t && read() const
{
if(!rng_->val_)
rng_->val_.emplace(rng_->gen_());
return static_cast<result_t &&>(static_cast<result_t &>(*rng_->val_));
}
void next()
{
RANGES_EXPECT(0 != rng_->n_);
if(rng_->val_)
rng_->val_.reset();
else
static_cast<void>(rng_->gen_());
--rng_->n_;
}
};
cursor begin_cursor()
{
return cursor{this};
}
public:
generate_n_view() = default;
explicit generate_n_view(G g, std::size_t n)
: gen_(std::move(g))
, n_(n)
{}
result_t & cached()
{
return *val_;
}
std::size_t size() const
{
return n_;
}
};
namespace views
{
struct generate_n_fn
{
template(typename G)(
requires invocable<G &> AND copy_constructible<G> AND
std::is_object<detail::decay_t<invoke_result_t<G &>>>::value AND
constructible_from<detail::decay_t<invoke_result_t<G &>>,
invoke_result_t<G &>> AND
assignable_from<detail::decay_t<invoke_result_t<G &>> &,
invoke_result_t<G &>>)
generate_n_view<G> operator()(G g, std::size_t n) const
{
return generate_n_view<G>{std::move(g), n};
}
};
/// \relates generate_n_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(generate_n_fn, generate_n)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::generate_n_view)
#endif

View File

@@ -0,0 +1,112 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_GETLINES_HPP
#define RANGES_V3_VIEW_GETLINES_HPP
#include <istream>
#include <string>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
struct getlines_view : view_facade<getlines_view, unknown>
{
private:
friend range_access;
std::istream * sin_;
std::string str_;
char delim_;
struct cursor
{
private:
friend range_access;
using single_pass = std::true_type;
getlines_view * rng_ = nullptr;
public:
cursor() = default;
explicit cursor(getlines_view * rng)
: rng_(rng)
{}
void next()
{
rng_->next();
}
std::string & read() const noexcept
{
return rng_->str_;
}
bool equal(default_sentinel_t) const
{
return !rng_->sin_;
}
bool equal(cursor that) const
{
return !rng_->sin_ == !that.rng_->sin_;
}
};
void next()
{
if(!std::getline(*sin_, str_, delim_))
sin_ = nullptr;
}
cursor begin_cursor()
{
return cursor{this};
}
public:
getlines_view() = default;
getlines_view(std::istream & sin, char delim = '\n')
: sin_(&sin)
, str_{}
, delim_(delim)
{
this->next(); // prime the pump
}
std::string & cached() noexcept
{
return str_;
}
};
/// \cond
using getlines_range RANGES_DEPRECATED(
"getlines_range has been renamed getlines_view") = getlines_view;
/// \endcond
struct getlines_fn
{
getlines_view operator()(std::istream & sin, char delim = '\n') const
{
return getlines_view{sin, delim};
}
};
RANGES_INLINE_VARIABLE(getlines_fn, getlines)
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,213 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_GROUP_BY_HPP
#define RANGES_V3_VIEW_GROUP_BY_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/algorithm/find_if_not.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/view/take_while.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/config.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
// TODO group_by could support Input ranges by keeping mutable state in
// the range itself. The group_by view would then be mutable-only and
// Input.
/// \addtogroup group-views
/// @{
template<typename Rng, typename Fun>
struct group_by_view
: view_facade<group_by_view<Rng, Fun>,
is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
{
private:
friend range_access;
Rng rng_;
// cached version of the end of the first subrange / start of the second subrange
detail::non_propagating_cache<iterator_t<Rng>> second_;
semiregular_box_t<Fun> fun_;
struct pred
{
iterator_t<Rng> first_;
semiregular_box_ref_or_val_t<Fun, false> fun_;
bool operator()(range_reference_t<Rng> r) const
{
return invoke(fun_, *first_, r);
}
};
struct cursor
{
private:
friend range_access;
friend group_by_view;
iterator_t<Rng> cur_;
iterator_t<Rng> next_cur_;
sentinel_t<Rng> last_;
semiregular_box_ref_or_val_t<Fun, false> fun_;
struct mixin : basic_mixin<cursor>
{
mixin() = default;
#ifndef _MSC_VER
using basic_mixin<cursor>::basic_mixin;
#else
constexpr explicit mixin(cursor && cur)
: basic_mixin<cursor>(static_cast<cursor &&>(cur))
{}
constexpr explicit mixin(cursor const & cur)
: basic_mixin<cursor>(cur)
{}
#endif
iterator_t<Rng> base() const
{
return this->get().cur_;
}
};
#ifdef _MSC_VER
template<typename I = iterator_t<Rng>>
subrange<I> read() const
{
return {cur_, next_cur_};
}
#else
subrange<iterator_t<Rng>> read() const
{
return {cur_, next_cur_};
}
#endif
void next()
{
cur_ = next_cur_;
next_cur_ = cur_ != last_
? find_if_not(ranges::next(cur_), last_, pred{cur_, fun_})
: cur_;
}
bool equal(default_sentinel_t) const
{
return cur_ == last_;
}
bool equal(cursor const & that) const
{
return cur_ == that.cur_;
}
cursor(semiregular_box_ref_or_val_t<Fun, false> fun, iterator_t<Rng> first,
iterator_t<Rng> next_cur, sentinel_t<Rng> last)
: cur_(first)
, next_cur_(next_cur)
, last_(last)
, fun_(fun)
{}
public:
cursor() = default;
};
cursor begin_cursor()
{
auto b = ranges::begin(rng_);
auto e = ranges::end(rng_);
if(!second_)
{
second_ = b != e ? find_if_not(ranges::next(b), e, pred{b, fun_}) : b;
}
return {fun_, b, *second_, e};
}
public:
group_by_view() = default;
constexpr group_by_view(Rng rng, Fun fun)
: rng_(std::move(rng))
, fun_(std::move(fun))
{}
Rng base() const
{
return rng_;
}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename Fun)(
requires copy_constructible<Fun>)
group_by_view(Rng &&, Fun)
->group_by_view<views::all_t<Rng>, Fun>;
#endif
namespace views
{
struct group_by_base_fn
{
template(typename Rng, typename Fun)(
requires viewable_range<Rng> AND forward_range<Rng> AND
indirect_relation<Fun, iterator_t<Rng>>)
RANGES_DEPRECATED(
"views::group_by is deprecated. Please use views::chunk_by instead. "
"Note that views::chunk_by evaluates the predicate between adjacent "
"elements.")
constexpr group_by_view<all_t<Rng>, Fun> operator()(Rng && rng, Fun fun) const
{
return {all(static_cast<Rng &&>(rng)), std::move(fun)};
}
};
struct group_by_fn : group_by_base_fn
{
using group_by_base_fn::operator();
template<typename Fun>
RANGES_DEPRECATED(
"views::group_by is deprecated. Please use views::chunk_by instead. "
"Note that views::chunk_by evaluates the predicate between adjacent "
"elements.")
constexpr auto operator()(Fun fun) const
{
return make_view_closure(bind_back(group_by_base_fn{}, std::move(fun)));
}
};
/// \relates group_by_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(group_by_fn, group_by)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::group_by_view)
#endif

View File

@@ -0,0 +1,80 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-present
// Copyright Gonzalo Brito Gadeschi
//
// 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_INDICES_HPP
#define RANGES_V3_VIEW_INDICES_HPP
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/iota.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
namespace views
{
/// Half-open range of indices: [from, to).
struct indices_fn : iota_view<std::size_t>
{
indices_fn() = default;
template(typename Val)(
requires integral<Val>)
iota_view<Val, Val> operator()(Val to) const
{
return {Val(), to};
}
template(typename Val)(
requires integral<Val>)
iota_view<Val, Val> operator()(Val from, Val to) const
{
return {from, to};
}
};
/// Inclusive range of indices: [from, to].
struct closed_indices_fn
{
template(typename Val)(
requires integral<Val>)
closed_iota_view<Val> operator()(Val to) const
{
return {Val(), to};
}
template(typename Val)(
requires integral<Val>)
closed_iota_view<Val> operator()(Val from, Val to) const
{
return {from, to};
}
};
/// \relates indices_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(indices_fn, indices)
/// \relates closed_indices_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(closed_indices_fn, closed_indices)
} // namespace views
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_VIEW_INDICES_HPP

View File

@@ -0,0 +1,156 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_INDIRECT_HPP
#define RANGES_V3_VIEW_INDIRECT_HPP
#include <iterator>
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/move.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng>
struct indirect_view : view_adaptor<indirect_view<Rng>, Rng>
{
private:
friend range_access;
template<bool IsConst>
struct adaptor : adaptor_base
{
friend adaptor<!IsConst>;
using CRng = meta::const_if_c<IsConst, Rng>;
adaptor() = default;
template(bool Other)(
requires IsConst && CPP_NOT(Other)) //
constexpr adaptor(adaptor<Other>) noexcept
{}
// clang-format off
constexpr auto CPP_auto_fun(read)(iterator_t<CRng> const &it)(const)
(
return **it
)
constexpr auto CPP_auto_fun(iter_move)(iterator_t<CRng> const &it)(const)
(
return ranges::iter_move(*it)
)
// clang-format on
};
CPP_member
constexpr auto begin_adaptor() noexcept //
-> CPP_ret(adaptor<false>)(
requires (!simple_view<Rng>()))
{
return {};
}
CPP_member
constexpr auto begin_adaptor() const noexcept //
-> CPP_ret(adaptor<true>)(
requires range<Rng const>)
{
return {};
}
CPP_member
constexpr auto end_adaptor() noexcept //
-> CPP_ret(adaptor<false>)(
requires (!simple_view<Rng>()))
{
return {};
}
CPP_member
constexpr auto end_adaptor() const noexcept //
-> CPP_ret(adaptor<true>)(
requires range<Rng const>)
{
return {};
}
public:
indirect_view() = default;
constexpr explicit indirect_view(Rng rng)
: indirect_view::view_adaptor{detail::move(rng)}
{}
CPP_auto_member
constexpr auto CPP_fun(size)()(const //
requires sized_range<Rng const>)
{
return ranges::size(this->base());
}
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return ranges::size(this->base());
}
};
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<indirect_view<Rng>> = //
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
indirect_view(Rng &&) //
-> indirect_view<views::all_t<Rng>>;
#endif
namespace views
{
struct indirect_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng> AND
// We shouldn't need to strip references to test if something
// is readable. https://github.com/ericniebler/stl2/issues/594
// indirectly_readable<range_reference_t<Rng>>)
((bool)indirectly_readable<range_value_t<Rng>>)) // Cast to bool needed
// for GCC (???))
constexpr auto operator()(Rng && rng) const
{
return indirect_view<all_t<Rng>>{all(static_cast<Rng &&>(rng))};
}
};
/// \relates indirect_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<indirect_fn>, indirect)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::indirect_view)
#endif

View File

@@ -0,0 +1,515 @@
/// \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_INTERFACE_HPP
#define RANGES_V3_VIEW_INTERFACE_HPP
#include <iosfwd>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/common_iterator.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/detail/prologue.hpp>
#if defined(RANGES_WORKAROUND_GCC_91525)
#define CPP_template_gcc_workaround CPP_template_sfinae
#else
#define CPP_template_gcc_workaround template
#endif
namespace ranges
{
/// \cond
namespace detail
{
template<typename From, typename To = From>
struct slice_bounds
{
From from;
To to;
template(typename F, typename T)(
requires convertible_to<F, From> AND convertible_to<T, To>)
constexpr slice_bounds(F f, T t)
: from(static_cast<From>(f))
, to(static_cast<To>(t))
{}
};
template<typename Int>
struct from_end_
{
Int dist_;
constexpr explicit from_end_(Int dist)
: dist_(dist)
{}
template(typename Other)(
requires integer_like_<Other> AND explicitly_convertible_to<Other, Int>)
constexpr operator from_end_<Other>() const
{
return from_end_<Other>{static_cast<Other>(dist_)};
}
};
template<typename Rng>
using from_end_of_t = from_end_<range_difference_t<Rng>>;
// clang-format off
/// \concept _can_empty_
/// \brief The \c _can_empty_ concept
template<typename Rng>
CPP_requires(_can_empty_,
requires(Rng & rng) //
(
ranges::empty(rng)
));
/// \concept can_empty_
/// \brief The \c can_empty_ concept
template<typename Rng>
CPP_concept can_empty_ = //
CPP_requires_ref(detail::_can_empty_, Rng);
// clang-format on
template<cardinality C>
RANGES_INLINE_VAR constexpr bool has_fixed_size_ = (C >= 0 || C == infinite);
template<bool>
struct dependent_
{
template<typename T>
using invoke = T;
};
template<typename Stream, typename Rng>
Stream & print_rng_(Stream & sout, Rng & rng)
{
sout << '[';
auto it = ranges::begin(rng);
auto const e = ranges::end(rng);
if(it != e)
{
for(;;)
{
sout << *it;
if(++it == e)
break;
sout << ',';
}
}
sout << ']';
return sout;
}
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
template<typename Derived, cardinality Cardinality /* = finite*/>
struct view_interface : basic_view<Cardinality>
{
protected:
template<bool B>
using D = meta::invoke<detail::dependent_<B>, Derived>;
constexpr Derived & derived() noexcept
{
CPP_assert(derived_from<Derived, view_interface>);
return static_cast<Derived &>(*this);
}
/// \overload
constexpr Derived const & derived() const noexcept
{
CPP_assert(derived_from<Derived, view_interface>);
return static_cast<Derived const &>(*this);
}
public:
view_interface() = default;
view_interface(view_interface &&) = default;
view_interface(view_interface const &) = default;
view_interface & operator=(view_interface &&) = default;
view_interface & operator=(view_interface const &) = default;
/// \brief Test whether a range can be empty:
CPP_member
constexpr auto empty() const noexcept //
-> CPP_ret(bool)(
requires (detail::has_fixed_size_<Cardinality>))
{
return Cardinality == 0;
}
/// \overload
template(bool True = true)(
requires True AND (Cardinality < 0) AND (Cardinality != infinite) AND
(!forward_range<D<True>>) AND sized_range<D<True>>)
constexpr bool empty() //
noexcept(noexcept(bool(ranges::size(std::declval<D<True> &>()) == 0)))
{
return ranges::size(derived()) == 0;
}
/// \overload
template(bool True = true)(
requires True AND (Cardinality < 0) AND (Cardinality != infinite) AND
(!forward_range<D<True> const>) AND sized_range<D<True> const>)
constexpr bool empty() const //
noexcept(noexcept(bool(ranges::size(std::declval<D<True> const &>()) == 0)))
{
return ranges::size(derived()) == 0;
}
/// \overload
template(bool True = true)(
requires True AND (!detail::has_fixed_size_<Cardinality>) AND
forward_range<D<True>>)
constexpr bool empty() noexcept(
noexcept(bool(ranges::begin(std::declval<D<True> &>()) ==
ranges::end(std::declval<D<True> &>()))))
{
return bool(ranges::begin(derived()) == ranges::end(derived()));
}
/// \overload
template(bool True = true)(
requires True AND (!detail::has_fixed_size_<Cardinality>) AND
forward_range<D<True> const>)
constexpr bool empty() const
noexcept(noexcept(bool(ranges::begin(std::declval<D<True> const &>()) ==
ranges::end(std::declval<D<True> const &>()))))
{
return bool(ranges::begin(derived()) == ranges::end(derived()));
}
CPP_template_gcc_workaround(bool True = true)(
requires True && detail::can_empty_<D<True>>) // clang-format off
constexpr explicit operator bool()
noexcept(noexcept(ranges::empty(std::declval<D<True> &>())))
{
return !ranges::empty(derived());
}
// clang-format on
/// \overload
CPP_template_gcc_workaround(bool True = true)(
requires True && detail::can_empty_<D<True> const>) // clang-format off
constexpr explicit operator bool() const
noexcept(noexcept(ranges::empty(std::declval<D<True> const &>())))
{
return !ranges::empty(derived());
}
// clang-format on
/// If the size of the range is known at compile-time and finite,
/// return it.
template(bool True = true, int = 42)(
requires True AND (Cardinality >= 0)) //
static constexpr std::size_t size() noexcept
{
return static_cast<std::size_t>(Cardinality);
}
/// If `sized_sentinel_for<sentinel_t<Derived>, iterator_t<Derived>>` is
/// satisfied, and if `Derived` is a `forward_range`, then return
/// `end - begin` cast to an unsigned integer.
template(bool True = true)(
requires True AND (Cardinality < 0) AND
sized_sentinel_for<sentinel_t<D<True>>, iterator_t<D<True>>> AND
forward_range<D<True>>)
constexpr detail::iter_size_t<iterator_t<D<True>>> size()
{
using size_type = detail::iter_size_t<iterator_t<D<True>>>;
return static_cast<size_type>(derived().end() - derived().begin());
}
/// \overload
template(bool True = true)(
requires True AND (Cardinality < 0) AND
sized_sentinel_for<sentinel_t<D<True> const>,
iterator_t<D<True> const>> AND
forward_range<D<True> const>)
constexpr detail::iter_size_t<iterator_t<D<True>>> size() const //
{
using size_type = detail::iter_size_t<iterator_t<D<True>>>;
return static_cast<size_type>(derived().end() - derived().begin());
}
/// Access the first element in a range:
template(bool True = true)(
requires True AND forward_range<D<True>>)
constexpr range_reference_t<D<True>> front()
{
return *derived().begin();
}
/// \overload
template(bool True = true)(
requires True AND forward_range<D<True> const>)
constexpr range_reference_t<D<True> const> front() const
{
return *derived().begin();
}
/// Access the last element in a range:
template(bool True = true)(
requires True AND common_range<D<True>> AND bidirectional_range<D<True>>)
constexpr range_reference_t<D<True>> back()
{
return *prev(derived().end());
}
/// \overload
template(bool True = true)(
requires True AND common_range<D<True> const> AND
bidirectional_range<D<True> const>)
constexpr range_reference_t<D<True> const> back() const
{
return *prev(derived().end());
}
/// Simple indexing:
template(bool True = true)(
requires True AND random_access_range<D<True>>)
constexpr range_reference_t<D<True>> operator[](range_difference_t<D<True>> n)
{
return derived().begin()[n];
}
/// \overload
template(bool True = true)(
requires True AND random_access_range<D<True> const>)
constexpr range_reference_t<D<True> const> //
operator[](range_difference_t<D<True>> n) const
{
return derived().begin()[n];
}
/// Returns a pointer to the block of memory
/// containing the elements of a contiguous range:
template(bool True = true)(
requires True AND contiguous_iterator<iterator_t<D<True>>>)
constexpr std::add_pointer_t<range_reference_t<D<True>>> data() //
{
return std::addressof(*ranges::begin(derived()));
}
/// \overload
template(bool True = true)(
requires True AND contiguous_iterator<iterator_t<D<True> const>>)
constexpr std::add_pointer_t<range_reference_t<D<True> const>> data() const //
{
return std::addressof(*ranges::begin(derived()));
}
/// Returns a reference to the element at specified location pos, with bounds
/// checking.
template(bool True = true)(
requires True AND random_access_range<D<True>> AND sized_range<D<True>>)
constexpr range_reference_t<D<True>> at(range_difference_t<D<True>> n)
{
using size_type = range_size_t<Derived>;
if(n < 0 || size_type(n) >= ranges::size(derived()))
{
throw std::out_of_range("view_interface::at");
}
return derived().begin()[n];
}
/// \overload
template(bool True = true)(
requires True AND random_access_range<D<True> const> AND
sized_range<D<True> const>)
constexpr range_reference_t<D<True> const> at(range_difference_t<D<True>> n) const
{
using size_type = range_size_t<Derived const>;
if(n < 0 || size_type(n) >= ranges::size(derived()))
{
throw std::out_of_range("view_interface::at");
}
return derived().begin()[n];
}
/// Python-ic slicing:
// rng[{4,6}]
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND input_range<D<True> &>)
constexpr auto
operator[](detail::slice_bounds<range_difference_t<D<True>>> offs) &
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND input_range<D<True> const &>)
constexpr auto
operator[](detail::slice_bounds<range_difference_t<D<True>>> offs) const &
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND input_range<D<True>>)
constexpr auto
operator[](detail::slice_bounds<range_difference_t<D<True>>> offs) &&
{
return Slice{}(detail::move(derived()), offs.from, offs.to);
}
// rng[{4,end-2}]
/// \overload
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND input_range<D<True> &> AND sized_range<D<True> &>)
constexpr auto //
operator[](detail::slice_bounds<range_difference_t<D<True>>,
detail::from_end_of_t<D<True>>> offs) &
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND input_range<D<True> const &> AND
sized_range<D<True> const &>)
constexpr auto //
operator[](detail::slice_bounds<range_difference_t<D<True>>,
detail::from_end_of_t<D<True>>> offs) const &
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND input_range<D<True>> AND sized_range<D<True>>)
constexpr auto //
operator[](detail::slice_bounds<range_difference_t<D<True>>,
detail::from_end_of_t<D<True>>> offs) &&
{
return Slice{}(detail::move(derived()), offs.from, offs.to);
}
// rng[{end-4,end-2}]
/// \overload
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND (forward_range<D<True> &> ||
(input_range<D<True> &> && sized_range<D<True> &>))) //
constexpr auto //
operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>,
detail::from_end_of_t<D<True>>> offs) &
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND
(forward_range<D<True> const &> ||
(input_range<D<True> const &> && sized_range<D<True> const &>))) //
constexpr auto //
operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>,
detail::from_end_of_t<D<True>>> offs) const &
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND
(forward_range<D<True>> ||
(input_range<D<True>> && sized_range<D<True>>))) //
constexpr auto //
operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>,
detail::from_end_of_t<D<True>>> offs) &&
{
return Slice{}(detail::move(derived()), offs.from, offs.to);
}
// rng[{4,end}]
/// \overload
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND input_range<D<True> &>)
constexpr auto //
operator[](detail::slice_bounds<range_difference_t<D<True>>, end_fn> offs) &
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND input_range<D<True> const &>)
constexpr auto //
operator[](detail::slice_bounds<range_difference_t<D<True>>, end_fn> offs) const &
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND input_range<D<True>>)
constexpr auto //
operator[](detail::slice_bounds<range_difference_t<D<True>>, end_fn> offs) &&
{
return Slice{}(detail::move(derived()), offs.from, offs.to);
}
// rng[{end-4,end}]
/// \overload
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND
(forward_range<D<True> &> ||
(input_range<D<True> &> && sized_range<D<True> &>))) //
constexpr auto //
operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>, end_fn> offs) &
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND
(forward_range<D<True> const &> ||
(input_range<D<True> const &> && sized_range<D<True> const &>))) //
constexpr auto //
operator[](
detail::slice_bounds<detail::from_end_of_t<D<True>>, end_fn> offs) const &
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template(bool True = true, typename Slice = views::slice_fn)(
requires True AND
(forward_range<D<True>> ||
(input_range<D<True>> && sized_range<D<True>>))) //
constexpr auto //
operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>, end_fn> offs) &&
{
return Slice{}(detail::move(derived()), offs.from, offs.to);
}
private:
#ifndef RANGES_V3_DISABLE_IO
/// \brief Print a range to an ostream
template<bool True = true>
friend auto operator<<(std::ostream & sout, Derived const & rng)
-> CPP_broken_friend_ret(std::ostream &)(
requires True && input_range<D<True> const>)
{
return detail::print_rng_(sout, rng);
}
/// \overload
template<bool True = true>
friend auto operator<<(std::ostream & sout, Derived & rng)
-> CPP_broken_friend_ret(std::ostream &)(
requires True && (!range<D<True> const>) && input_range<D<True>>)
{
return detail::print_rng_(sout, rng);
}
/// \overload
template<bool True = true>
friend auto operator<<(std::ostream & sout, Derived && rng)
-> CPP_broken_friend_ret(std::ostream &)(
requires True && (!range<D<True> const>) && input_range<D<True>>)
{
return detail::print_rng_(sout, rng);
}
#endif
};
namespace cpp20
{
template(typename Derived)(
requires std::is_class<Derived>::value AND
same_as<Derived, meta::_t<std::remove_cv<Derived>>>)
using view_interface = ranges::view_interface<Derived, ranges::unknown>;
}
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,254 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_INTERSPERSE_HPP
#define RANGES_V3_VIEW_INTERSPERSE_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/operations.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng>
struct intersperse_view
: view_adaptor<intersperse_view<Rng>, Rng,
(range_cardinality<Rng>::value > 0)
? static_cast<cardinality>(range_cardinality<Rng>::value * 2 - 1)
: range_cardinality<Rng>::value>
{
intersperse_view() = default;
constexpr intersperse_view(Rng rng, range_value_t<Rng> val)
: intersperse_view::view_adaptor{detail::move(rng)}
, val_(detail::move(val))
{}
CPP_auto_member
constexpr auto CPP_fun(size)()(const //
requires sized_range<Rng const>)
{
auto const n = ranges::size(this->base());
return n ? n * 2 - 1 : 0;
}
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires sized_range<Rng>)
{
auto const n = ranges::size(this->base());
return n ? n * 2 - 1 : 0;
}
private:
friend range_access;
template<bool Const>
struct cursor_adaptor : adaptor_base
{
private:
friend struct cursor_adaptor<!Const>;
using CRng = meta::const_if_c<Const, Rng>;
bool toggle_ = false;
range_value_t<Rng> val_;
public:
cursor_adaptor() = default;
constexpr explicit cursor_adaptor(range_value_t<Rng> const & val)
: val_{val}
{}
template(bool Other)(
requires Const AND CPP_NOT(Other)) //
cursor_adaptor(cursor_adaptor<Other> that)
: toggle_(that.toggle_)
, val_(std::move(that.val_))
{}
template<typename View>
constexpr iterator_t<CRng> begin(View & view)
{
auto first = ranges::begin(view.base());
toggle_ = first != ranges::end(view.base());
return first;
}
constexpr range_value_t<Rng> read(iterator_t<CRng> const & it) const
{
return toggle_ ? *it : val_;
}
CPP_member
constexpr auto equal(iterator_t<CRng> const & it0,
iterator_t<CRng> const & it1,
cursor_adaptor const & other) const //
-> CPP_ret(bool)(
requires sentinel_for<iterator_t<CRng>, iterator_t<CRng>>)
{
return it0 == it1 && toggle_ == other.toggle_;
}
constexpr void next(iterator_t<CRng> & it)
{
if(toggle_)
++it;
toggle_ = !toggle_;
}
CPP_member
constexpr auto prev(iterator_t<CRng> & it) //
-> CPP_ret(void)(
requires bidirectional_range<CRng>)
{
toggle_ = !toggle_;
if(toggle_)
--it;
}
CPP_member
constexpr auto distance_to(iterator_t<CRng> const & it,
iterator_t<CRng> const & other_it,
cursor_adaptor const & other) const
-> CPP_ret(range_difference_t<Rng>)(
requires sized_sentinel_for<iterator_t<CRng>, iterator_t<CRng>>)
{
return (other_it - it) * 2 + (other.toggle_ - toggle_);
}
CPP_member
constexpr auto advance(iterator_t<CRng> & it, range_difference_t<CRng> n) //
-> CPP_ret(void)(
requires random_access_range<CRng>)
{
ranges::advance(it, n >= 0 ? (n + toggle_) / 2 : (n - !toggle_) / 2);
if(n % 2 != 0)
toggle_ = !toggle_;
}
};
template<bool Const>
struct sentinel_adaptor : adaptor_base
{
private:
using CRng = meta::const_if_c<Const, Rng>;
public:
sentinel_adaptor() = default;
template(bool Other)(
requires Const AND CPP_NOT(Other)) //
sentinel_adaptor(sentinel_adaptor<Other>)
{}
static constexpr bool empty(iterator_t<CRng> const & it,
cursor_adaptor<Const> const &,
sentinel_t<CRng> const & sent)
{
return it == sent;
}
};
constexpr cursor_adaptor<false> begin_adaptor()
{
return cursor_adaptor<false>{val_};
}
CPP_member
constexpr auto begin_adaptor() const //
-> CPP_ret(cursor_adaptor<true>)(
requires range<Rng const>)
{
return cursor_adaptor<true>{val_};
}
CPP_member
constexpr auto end_adaptor() //
-> CPP_ret(cursor_adaptor<false>)(
requires common_range<Rng> && (!single_pass_iterator_<iterator_t<Rng>>))
{
return cursor_adaptor<false>{val_};
}
CPP_member
constexpr auto end_adaptor() noexcept //
-> CPP_ret(sentinel_adaptor<false>)(
requires (!common_range<Rng>) || single_pass_iterator_<iterator_t<Rng>>)
{
return {};
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng>> AND
common_range<meta::const_if_c<Const, Rng>> AND
(!single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng>>>)) //
constexpr cursor_adaptor<Const> end_adaptor() const
{
return cursor_adaptor<true>{val_};
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng>> AND
(!common_range<meta::const_if_c<Const, Rng>> ||
single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng>>>)) //
constexpr sentinel_adaptor<Const> end_adaptor() const noexcept
{
return {};
}
range_value_t<Rng> val_;
};
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<intersperse_view<Rng>> = //
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
intersperse_view(Rng &&, range_value_t<Rng>)
-> intersperse_view<views::all_t<Rng>>;
#endif
namespace views
{
struct intersperse_base_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng> AND
convertible_to<range_reference_t<Rng>, range_value_t<Rng>> AND
semiregular<range_value_t<Rng>>)
constexpr intersperse_view<all_t<Rng>> //
operator()(Rng && rng, range_value_t<Rng> val) const
{
return {all(static_cast<Rng &&>(rng)), std::move(val)};
}
};
struct intersperse_fn : intersperse_base_fn
{
using intersperse_base_fn::operator();
template(typename T)(
requires copyable<T>)
constexpr auto operator()(T t) const
{
return make_view_closure(bind_back(intersperse_base_fn{}, std::move(t)));
}
};
/// \relates intersperse_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(intersperse_fn, intersperse)
} // namespace views
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::intersperse_view)
#endif

View File

@@ -0,0 +1,591 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_IOTA_HPP
#define RANGES_V3_VIEW_IOTA_HPP
#include <climits>
#include <cstdint>
#include <limits>
#include <type_traits>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/iterator/diffmax_t.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/delimit.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/detail/prologue.hpp>
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_UNSIGNED_MATH
RANGES_DIAGNOSTIC_IGNORE_TRUNCATION
namespace ranges
{
/// \cond
namespace detail
{
template<std::size_t N, typename = void>
struct promote_as_signed_
{
// This shouldn't cause us to LOSE precision, but maybe it doesn't
// net us any either.
static_assert(sizeof(std::intmax_t) * CHAR_BIT >= N,
"Possible extended integral type?");
using difference_type = diffmax_t;
};
template<std::size_t N>
struct promote_as_signed_<N, enable_if_t<(N < 16)>>
{
using difference_type = std::int_fast16_t;
};
template<std::size_t N>
struct promote_as_signed_<N, enable_if_t<(N >= 16 && N < 32)>>
{
using difference_type = std::int_fast32_t;
};
template<std::size_t N>
struct promote_as_signed_<N, enable_if_t<(N >= 32 && N < 64)>>
{
using difference_type = std::int_fast64_t;
};
template<typename I>
using iota_difference_t = typename meta::conditional_t<
std::is_integral<I>::value && sizeof(I) == sizeof(iter_difference_t<I>),
promote_as_signed_<sizeof(iter_difference_t<I>) * CHAR_BIT>,
with_difference_type_<iter_difference_t<I>>>::difference_type;
// clang-format off
/// \concept _decrementable_
/// \brief The \c _decrementable_ concept
template<typename I>
CPP_requires(_decrementable_,
requires(I i) //
(
--i,
i--,
concepts::requires_<same_as<I&, decltype(--i)>>,
concepts::requires_<same_as<I, decltype(i--)>>
));
/// \concept decrementable_
/// \brief The \c decrementable_ concept
template<typename I>
CPP_concept decrementable_ =
incrementable<I> &&
CPP_requires_ref(detail::_decrementable_, I);
/// \concept _advanceable_
/// \brief The \c _advanceable_ concept
template<typename I>
CPP_requires(_advanceable_,
requires(I i, I const j, iota_difference_t<I> const n) //
(
j - j,
i += n,
i -= n,
static_cast<I>(j - n),
static_cast<I>(j + n),
static_cast<I>(n + j),
// NOT TO SPEC:
// Unsigned integers are advanceable, but subtracting them results in
// an unsigned integral, which is not the same as the difference type,
// which is signed.
concepts::requires_<convertible_to<decltype(j - j), iota_difference_t<I>>>,
concepts::requires_<same_as<I&, decltype(i += n)>>,
concepts::requires_<same_as<I&, decltype(i -= n)>> //,
// concepts::requires_<convertible_to<decltype(i - n), I>>,
// concepts::requires_<convertible_to<decltype(i + n), I>>,
// concepts::requires_<convertible_to<decltype(n + i), I>>
));
/// \concept advanceable_
/// \brief The \c advanceable_ concept
template<typename I>
CPP_concept advanceable_ =
decrementable_<I> && totally_ordered<I> &&
CPP_requires_ref(detail::_advanceable_, I);
// clang-format on
template(typename I)(
requires (!unsigned_integral<I>)) //
void iota_advance_(I & i, iota_difference_t<I> n)
{
// TODO: bounds-check this
i += n;
}
template(typename Int)(
requires unsigned_integral<Int>)
void iota_advance_(Int & i, iota_difference_t<Int> n)
{
// TODO: bounds-check this
if(n >= 0)
i += static_cast<Int>(n);
else
i -= static_cast<Int>(-n);
}
template(typename I)(
requires advanceable_<I> AND (!integral<I>)) //
iota_difference_t<I> iota_distance_(I const & i, I const & s)
{
return static_cast<iota_difference_t<I>>(s - i);
}
template(typename Int)(
requires signed_integral<Int>)
iota_difference_t<Int> iota_distance_(Int i0, Int i1)
{
// TODO: bounds-check this
return static_cast<iota_difference_t<Int>>(
static_cast<iota_difference_t<Int>>(i1) -
static_cast<iota_difference_t<Int>>(i0));
}
template(typename Int)(
requires unsigned_integral<Int>)
iota_difference_t<Int> iota_distance_(Int i0, Int i1)
{
// TODO: bounds-check this
return (i0 > i1) ? static_cast<iota_difference_t<Int>>(
-static_cast<iota_difference_t<Int>>(i0 - i1))
: static_cast<iota_difference_t<Int>>(i1 - i0);
}
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
/// An iota view in a closed range
template<typename From, typename To /* = From */>
struct RANGES_EMPTY_BASES closed_iota_view
: view_facade<closed_iota_view<From, To>, finite>
{
private:
friend range_access;
From from_ = From();
RANGES_NO_UNIQUE_ADDRESS To to_ = To();
struct cursor
{
using difference_type = detail::iota_difference_t<From>;
private:
friend range_access;
From from_ = From();
RANGES_NO_UNIQUE_ADDRESS To to_ = To();
bool done_ = false;
From read() const
{
RANGES_EXPECT(!done_);
return from_;
}
void next()
{
RANGES_EXPECT(!done_);
if(from_ == to_)
done_ = true;
else
++from_;
}
bool equal(default_sentinel_t) const
{
return done_;
}
CPP_member
auto equal(cursor const & that) const //
-> CPP_ret(bool)(
requires equality_comparable<From>)
{
return that.from_ == from_ && that.done_ == done_;
}
CPP_member
auto prev() //
-> CPP_ret(void)(
requires detail::decrementable_<From>)
{
if(done_)
done_ = false;
else
--from_;
}
CPP_member
auto advance(difference_type n) //
-> CPP_ret(void)(
requires detail::advanceable_<From>)
{
if(n > 0)
{
RANGES_ENSURE(detail::iota_distance_(from_, to_) >= n - !done_);
detail::iota_advance_(
from_,
n - (done_ = (detail::iota_distance_(from_, to_) <= n - !done_)));
}
else if(n < 0)
detail::iota_advance_(from_, n + std::exchange(done_, false));
}
CPP_member
auto distance_to(cursor const & that) const //
-> CPP_ret(difference_type)(
requires detail::advanceable_<From>)
{
using D = difference_type;
return static_cast<D>(detail::iota_distance_(from_, that.from_)) +
((D)that.done_ - (D)done_);
}
CPP_member
auto distance_to(default_sentinel_t) const //
-> CPP_ret(difference_type)(
requires sized_sentinel_for<To, From>)
{
return difference_type(to_ - from_) + !done_;
}
public:
cursor() = default;
constexpr cursor(From from, To to, bool done = false)
: from_(std::move(from))
, to_(std::move(to))
, done_(done)
{}
};
cursor begin_cursor() const
{
return {from_, to_};
}
CPP_member
auto end_cursor() const //
-> CPP_ret(cursor)(
requires same_as<From, To>)
{
return {to_, to_, true};
}
CPP_member
auto end_cursor() const //
-> CPP_ret(default_sentinel_t)(
requires (!same_as<From, To>))
{
return {};
}
constexpr void check_bounds_(std::true_type)
{
RANGES_EXPECT(from_ <= to_);
}
constexpr void check_bounds_(std::false_type)
{}
public:
closed_iota_view() = default;
constexpr closed_iota_view(meta::id_t<From> from, meta::id_t<To> to)
: from_(std::move(from))
, to_(std::move(to))
{
check_bounds_(meta::bool_<totally_ordered_with<From, To>>{});
}
};
template<typename From, typename To>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<closed_iota_view<From, To>> =
true;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename From, typename To)(
requires weakly_incrementable<From> AND semiregular<To> AND
(!integral<From> || !integral<To> ||
std::is_signed<From>::value == std::is_signed<To>::value)) //
closed_iota_view(From, To)
->closed_iota_view<From, To>;
#endif
template<typename From, typename To /* = unreachable_sentinel_t*/>
struct RANGES_EMPTY_BASES iota_view
: view_facade<iota_view<From, To>,
same_as<To, unreachable_sentinel_t>
? infinite
: std::is_integral<From>::value && std::is_integral<To>::value
? finite
: unknown>
{
private:
friend range_access;
From from_ = From();
RANGES_NO_UNIQUE_ADDRESS To to_ = To();
struct cursor;
struct sentinel
{
private:
friend struct cursor;
RANGES_NO_UNIQUE_ADDRESS To to_;
public:
sentinel() = default;
constexpr explicit sentinel(To to)
: to_(std::move(to))
{}
};
struct cursor
{
using difference_type = detail::iota_difference_t<From>;
private:
friend range_access;
From from_;
From read() const
{
return from_;
}
void next()
{
++from_;
}
bool equal(sentinel const & that) const
{
return from_ == that.to_;
}
CPP_member
auto equal(cursor const & that) const //
-> CPP_ret(bool)(
requires equality_comparable<From>)
{
return that.from_ == from_;
}
CPP_member
auto prev() //
-> CPP_ret(void)(
requires detail::decrementable_<From>)
{
--from_;
}
CPP_member
auto advance(difference_type n) //
-> CPP_ret(void)(
requires detail::advanceable_<From>)
{
detail::iota_advance_(from_, n);
}
// Not to spec: TODO the relational operators will effectively be constrained
// with Advanceable, but they should be constrained with totally_ordered.
// Reimplement iota_view without view_facade or basic_iterator.
CPP_member
auto distance_to(cursor const & that) const //
-> CPP_ret(difference_type)(
requires detail::advanceable_<From>)
{
return detail::iota_distance_(from_, that.from_);
}
// Extension: see https://github.com/ericniebler/stl2/issues/613
CPP_member
auto distance_to(sentinel const & that) const //
-> CPP_ret(difference_type)(
requires sized_sentinel_for<To, From>)
{
return that.to_ - from_;
}
public:
cursor() = default;
constexpr explicit cursor(From from)
: from_(std::move(from))
{}
};
cursor begin_cursor() const
{
return cursor{from_};
}
CPP_auto_member
auto CPP_fun(end_cursor)()(const //
requires(same_as<To, unreachable_sentinel_t>))
{
return unreachable;
}
CPP_auto_member
auto CPP_fun(end_cursor)()(const //
requires(!same_as<To, unreachable_sentinel_t>))
{
return meta::conditional_t<same_as<From, To>, cursor, sentinel>{to_};
}
constexpr void check_bounds_(std::true_type)
{
RANGES_EXPECT(from_ <= to_);
}
constexpr void check_bounds_(std::false_type)
{}
public:
#ifdef RANGES_WORKAROUND_MSVC_934264
constexpr
#endif // RANGES_WORKAROUND_MSVC_934264
iota_view() = default;
constexpr explicit iota_view(From from)
: from_(std::move(from))
{}
constexpr iota_view(meta::id_t<From> from, meta::id_t<To> to)
: from_(std::move(from))
, to_(std::move(to))
{
check_bounds_(meta::bool_<totally_ordered_with<From, To>>{});
}
};
template<typename From, typename To>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<iota_view<From, To>> = true;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename From, typename To)(
requires weakly_incrementable<From> AND semiregular<To> AND
(!integral<From> || !integral<To> ||
std::is_signed<From>::value == std::is_signed<To>::value)) //
iota_view(From, To)
->iota_view<From, To>;
#endif
namespace views
{
struct iota_fn
{
template(typename From)(
requires weakly_incrementable<From>)
iota_view<From> operator()(From value) const
{
return iota_view<From>{std::move(value)};
}
template(typename From, typename To)(
requires weakly_incrementable<From> AND semiregular<To> AND
detail::weakly_equality_comparable_with_<From, To> AND
(!integral<From> || !integral<To> ||
std::is_signed<From>::value == std::is_signed<To>::value)) //
iota_view<From, To> operator()(From from, To to) const
{
return {std::move(from), std::move(to)};
}
};
struct closed_iota_fn
{
template(typename From, typename To)(
requires weakly_incrementable<From> AND semiregular<To> AND
detail::weakly_equality_comparable_with_<From, To> AND
(!integral<From> || !integral<To> ||
std::is_signed<From>::value == std::is_signed<To>::value)) //
closed_iota_view<From, To> operator()(From from, To to) const
{
return {std::move(from), std::move(to)};
}
};
/// \relates iota_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(iota_fn, iota)
/// \relates closed_iota_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(closed_iota_fn, closed_iota)
/// # ranges::views::ints
/// The ints view returns a range of monotonically increasing ints.
///
/// ## Example
/// \snippet example/view/ints.cpp ints example
///
/// ### Output
/// \include example/view/ints_golden.txt
///
/// ## Syntax
/// ```cpp
/// auto output_range = ranges::views::ints(lower_bound, upper_bound);
/// ```
///
/// ## Parameters
/// <pre><b>lower_bound</b></pre>
/// - Optional lower bound
///
/// <pre><b>upper_bound</b></pre>
/// - Exclusive upper bound
/// - Required when `lower_bound` is specified
/// - To create an infinite range with a `lower_bound`, use
/// `ranges::unreachable` as the `upper_bound`
///
/// <pre><b>output_range</b></pre>
/// - Range of monotonically increasing ints
/// - When an `upper_bound` is not specified, the range is quasi-infinite
///
struct ints_fn : iota_view<int>
{
ints_fn() = default;
template(typename Val)(
requires integral<Val>)
RANGES_DEPRECATED(
"This potentially confusing API is deprecated. Prefer to "
"explicitly specify the upper bound as with ranges::unreachable, as in "
"views::ints( n, unreachable )")
constexpr iota_view<Val> operator()(Val value) const //
{
return iota_view<Val>{value};
}
template(typename Val)(
requires integral<Val>)
constexpr iota_view<Val> operator()(Val value, unreachable_sentinel_t) const
{
return iota_view<Val>{value};
}
template(typename Val)(
requires integral<Val>)
constexpr iota_view<Val, Val> operator()(Val from, Val to) const
{
return {from, to};
}
};
/// \relates ints_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(ints_fn, ints)
} // namespace views
namespace cpp20
{
namespace views
{
using ranges::views::iota;
}
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::closed_iota_view)
RANGES_SATISFY_BOOST_RANGE(::ranges::iota_view)
RANGES_DIAGNOSTIC_POP
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,123 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_ISTREAM_HPP
#define RANGES_V3_VIEW_ISTREAM_HPP
#include <istream>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Val>
struct istream_view : view_facade<istream_view<Val>, unknown>
{
private:
friend range_access;
std::istream * sin_;
semiregular_box_t<Val> obj_;
struct cursor
{
private:
friend range_access;
using single_pass = std::true_type;
istream_view * rng_ = nullptr;
public:
cursor() = default;
explicit cursor(istream_view * rng)
: rng_(rng)
{}
void next()
{
rng_->next();
}
Val & read() const noexcept
{
return rng_->cached();
}
bool equal(default_sentinel_t) const
{
return !rng_->sin_;
}
bool equal(cursor that) const
{
return !rng_->sin_ == !that.rng_->sin_;
}
};
void next()
{
if(!(*sin_ >> cached()))
sin_ = nullptr;
}
cursor begin_cursor()
{
return cursor{this};
}
public:
istream_view() = default;
explicit istream_view(std::istream & sin)
: sin_(&sin)
, obj_{}
{
next(); // prime the pump
}
Val & cached() noexcept
{
return obj_;
}
};
/// \cond
template<typename Val>
using istream_range RANGES_DEPRECATED(
"istream_range<T> has been renamed to istream_view<T>") = istream_view<Val>;
/// \endcond
/// \cond
namespace _istream_
{
/// \endcond
template(typename Val)(
requires copy_constructible<Val> AND default_constructible<Val>)
inline istream_view<Val> istream(std::istream & sin)
{
return istream_view<Val>{sin};
}
/// \cond
} // namespace _istream_
using namespace _istream_;
/// \endcond
namespace cpp20
{
template<typename Val>
using basic_istream_view = ::ranges::istream_view<Val>;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,649 @@
/// \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

View File

@@ -0,0 +1,123 @@
/// \file
// Range v3 library
//
// Copyright Casey Carter 2017
// Copyright Gonzalo Brito Gadeschi 2017
//
// 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_LINEAR_DISTRIBUTE_HPP
#define RANGES_V3_VIEW_LINEAR_DISTRIBUTE_HPP
#include <type_traits>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
namespace views
{
/// \addtogroup group-views
/// @{
template<typename T>
struct linear_distribute_view : view_facade<linear_distribute_view<T>, finite>
{
CPP_assert(std::is_arithmetic<T>());
private:
friend range_access;
using Calc = meta::conditional_t<std::is_floating_point<T>::value, T, double>;
T from_, to_;
Calc delta_;
std::ptrdiff_t n_;
constexpr T read() const noexcept
{
return from_;
}
constexpr bool equal(default_sentinel_t) const noexcept
{
return n_ == 0;
}
constexpr bool equal(linear_distribute_view const & other) const noexcept
{
bool const eq = n_ == other.n_;
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_FLOAT_EQUAL
RANGES_EXPECT(to_ == other.to_);
RANGES_EXPECT(!eq || from_ == other.from_);
RANGES_DIAGNOSTIC_POP
return eq;
}
constexpr void next() noexcept
{
RANGES_EXPECT(n_ > 0);
--n_;
if(n_ == 0)
{
from_ = to_;
}
else
{
from_ = T(to_ - (delta_ * Calc(n_ - 1)));
}
}
public:
constexpr linear_distribute_view() = default;
constexpr linear_distribute_view(T from, T to, std::ptrdiff_t n) noexcept
: from_(from)
, to_(to)
, delta_(n > 1 ? (to - from) / Calc(n - 1) : 0)
, n_(n)
{
RANGES_EXPECT(n_ > 0);
RANGES_EXPECT(to_ >= from_);
}
constexpr std::size_t size() const noexcept
{
return static_cast<std::size_t>(n_);
}
};
/// Distributes `n` values linearly in the closed interval [`from`, `to`].
///
/// \pre `from <= to && n > 0`
///
/// If `from == to`, returns n-times `to`.
/// If `n == 1` returns `to`.
struct linear_distribute_fn
{
template(typename T)(
requires std::is_arithmetic<T>::value)
constexpr auto operator()(T from, T to, std::ptrdiff_t n) const
{
return linear_distribute_view<T>{from, to, n};
}
};
/// \relates linear_distribute_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(linear_distribute_fn, linear_distribute)
} // namespace views
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,150 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_MAP_HPP
#define RANGES_V3_VIEW_MAP_HPP
#include <utility>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
// TODO: Reuse subrange's pair_like concept here and have get_first and get_second
// dispatch through get<>()
namespace ranges
{
/// \cond
namespace detail
{
template<typename T>
constexpr T & get_first_second_helper(T & t, std::true_type) noexcept
{
return t;
}
template(typename T)(
requires move_constructible<T>)
constexpr T get_first_second_helper(T & t, std::false_type) //
noexcept(std::is_nothrow_move_constructible<T>::value)
{
return std::move(t);
}
template<typename P, typename E>
using get_first_second_tag = meta::bool_<std::is_lvalue_reference<P>::value ||
std::is_lvalue_reference<E>::value>;
struct get_first
{
// clang-format off
template<typename Pair>
constexpr auto CPP_auto_fun(operator())(Pair &&p)(const)
(
return get_first_second_helper(
p.first,
get_first_second_tag<Pair, decltype(p.first)>{})
)
// clang-format on
};
struct get_second
{
// clang-format off
template<typename Pair>
constexpr auto CPP_auto_fun(operator())(Pair &&p)(const)
(
return get_first_second_helper(
p.second,
get_first_second_tag<Pair, decltype(p.second)>{})
)
// clang-format on
};
// clang-format off
/// \concept kv_pair_like_
/// \brief The \c kv_pair_like_ concept
template<typename T>
CPP_concept kv_pair_like_ =
invocable<get_first const &, T> &&
invocable<get_second const &, T>;
// clang-format on
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
namespace views
{
struct keys_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng> AND
detail::kv_pair_like_<range_reference_t<Rng>>)
keys_range_view<all_t<Rng>> operator()(Rng && rng) const
{
return {all(static_cast<Rng &&>(rng)), detail::get_first{}};
}
};
struct values_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng> AND
detail::kv_pair_like_<range_reference_t<Rng>>)
values_view<all_t<Rng>> operator()(Rng && rng) const
{
return {all(static_cast<Rng &&>(rng)), detail::get_second{}};
}
};
/// \relates keys_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<keys_fn>, keys)
/// \relates values_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<values_fn>, values)
} // namespace views
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<keys_range_view<Rng>> =
enable_borrowed_range<Rng>;
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<values_view<Rng>> =
enable_borrowed_range<Rng>;
namespace cpp20
{
namespace views
{
using ranges::views::keys;
using ranges::views::values;
} // namespace views
// TODO(@cjdb): provide implementation for elements_view
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,136 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_MOVE_HPP
#define RANGES_V3_VIEW_MOVE_HPP
#include <type_traits>
#include <utility>
#include <range/v3/range_fwd.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng>
struct move_view : view_adaptor<move_view<Rng>, Rng>
{
private:
friend range_access;
template<bool Const>
struct adaptor : adaptor_base
{
adaptor() = default;
template(bool Other)(
requires Const AND CPP_NOT(Other)) //
constexpr adaptor(adaptor<Other>)
{}
using CRng = meta::const_if_c<Const, Rng>;
using value_type = range_value_t<Rng>;
range_rvalue_reference_t<CRng> read(iterator_t<CRng> const & it) const
{
return ranges::iter_move(it);
}
range_rvalue_reference_t<CRng> iter_move(iterator_t<CRng> const & it) const
{
return ranges::iter_move(it);
}
};
adaptor<simple_view<Rng>()> begin_adaptor()
{
return {};
}
adaptor<simple_view<Rng>()> end_adaptor()
{
return {};
}
CPP_member
auto begin_adaptor() const //
-> CPP_ret(adaptor<true>)(
requires input_range<Rng const>)
{
return {};
}
CPP_member
auto end_adaptor() const //
-> CPP_ret(adaptor<true>)(
requires input_range<Rng const>)
{
return {};
}
public:
move_view() = default;
explicit move_view(Rng rng)
: move_view::view_adaptor{std::move(rng)}
{}
CPP_auto_member
auto CPP_fun(size)()(const //
requires sized_range<Rng const>)
{
return ranges::size(this->base());
}
CPP_auto_member
auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return ranges::size(this->base());
}
};
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<move_view<Rng>> =
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
move_view(Rng &&) //
-> move_view<views::all_t<Rng>>;
#endif
namespace views
{
struct move_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng>)
move_view<all_t<Rng>> operator()(Rng && rng) const
{
return move_view<all_t<Rng>>{all(static_cast<Rng &&>(rng))};
}
};
/// \relates move_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<move_fn>, move)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::move_view)
#endif

View File

@@ -0,0 +1,233 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_PARTIAL_SUM_HPP
#define RANGES_V3_VIEW_PARTIAL_SUM_HPP
#include <iterator>
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/arithmetic.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/addressof.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
// clang-format off
/// \concept partial_sum_view_constraints_
/// \brief The \c partial_sum_view_constraints_ concept
template(typename Rng, typename Fun)(
concept (partial_sum_view_constraints_)(Rng, Fun),
copy_constructible<range_value_t<Rng>> AND
constructible_from<range_value_t<Rng>, range_reference_t<Rng>> AND
assignable_from<range_value_t<Rng> &, range_reference_t<Rng>> AND
indirectly_binary_invocable_<Fun &, iterator_t<Rng>, iterator_t<Rng>> AND
assignable_from<
range_value_t<Rng> &,
indirect_result_t<Fun &, iterator_t<Rng>, iterator_t<Rng>>>
);
/// \concept partial_sum_view_constraints
/// \brief The \c partial_sum_view_constraints concept
template<typename Rng, typename Fun>
CPP_concept partial_sum_view_constraints =
input_range<Rng> &&
copy_constructible<Fun> &&
CPP_concept_ref(detail::partial_sum_view_constraints_, Rng, Fun);
// clang-format on
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
template<typename Rng, typename Fun>
struct partial_sum_view
: view_facade<partial_sum_view<Rng, Fun>, range_cardinality<Rng>::value>
{
private:
friend range_access;
CPP_assert(view_<Rng>);
CPP_assert(detail::partial_sum_view_constraints<Rng, Fun>);
RANGES_NO_UNIQUE_ADDRESS Rng base_{};
RANGES_NO_UNIQUE_ADDRESS semiregular_box_t<Fun> fun_;
template<bool IsConst>
struct cursor
{
private:
friend cursor<true>;
using Parent = meta::const_if_c<IsConst, partial_sum_view>;
using Base = meta::const_if_c<IsConst, Rng>;
Parent * parent_ = nullptr;
RANGES_NO_UNIQUE_ADDRESS iterator_t<Base> current_{};
RANGES_NO_UNIQUE_ADDRESS semiregular_box_t<range_value_t<Rng>> sum_;
public:
using single_pass = meta::bool_<single_pass_iterator_<iterator_t<Base>>>;
cursor() = default;
constexpr explicit cursor(Parent * rng)
: parent_{rng}
, current_(ranges::begin(rng->base_))
{
if(current_ != ranges::end(rng->base_))
sum_ = *current_;
}
template(bool Other)(
requires IsConst AND CPP_NOT(Other) AND
convertible_to<iterator_t<Rng> const &,
iterator_t<Base>>)
constexpr cursor(cursor<Other> const & that)
: parent_{that.parent_}
, current_(that.current_)
, sum_(that.sum_)
{}
constexpr range_value_t<Rng> read() const
{
RANGES_EXPECT(current_ != ranges::end(parent_->base_));
return sum_;
}
constexpr void next()
{
auto last = ranges::end(parent_->base_);
RANGES_EXPECT(current_ != last);
if(++current_ != last)
{
auto & sum = static_cast<range_value_t<Rng> &>(sum_);
using F = meta::const_if_c<IsConst, Fun>;
auto & f = static_cast<F &>(parent_->fun_);
sum = invoke(f, sum, *current_);
}
}
constexpr bool equal(default_sentinel_t) const
{
return current_ == ranges::end(parent_->base_);
}
CPP_auto_member
constexpr bool CPP_fun(equal)(cursor const & that)(const //
requires equality_comparable<iterator_t<Base>>)
{
RANGES_EXPECT(parent_ == that.parent_);
return current_ == that.current_;
}
};
constexpr cursor<false> begin_cursor()
{
return cursor<false>{this};
}
template(typename CRng = Rng const)(
requires detail::partial_sum_view_constraints<CRng, Fun const>)
constexpr cursor<true> begin_cursor() const
{
return cursor<true>{this};
}
public:
partial_sum_view() = default;
constexpr partial_sum_view(Rng rng, Fun fun) noexcept(
std::is_nothrow_move_constructible<Rng>::value &&
std::is_nothrow_move_constructible<Fun>::value)
: base_(std::move(rng))
, fun_(std::move(fun))
{}
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return ranges::size(base_);
}
CPP_auto_member
constexpr auto CPP_fun(size)()(const //
requires sized_range<Rng const>)
{
return ranges::size(base_);
}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename Fun)(
requires copy_constructible<Fun>)
partial_sum_view(Rng &&, Fun)
-> partial_sum_view<views::all_t<Rng>, Fun>;
#endif
namespace views
{
struct partial_sum_base_fn
{
template(typename Rng, typename Fun = plus)(
requires detail::partial_sum_view_constraints<all_t<Rng>, Fun>)
constexpr partial_sum_view<all_t<Rng>, Fun> //
operator()(Rng && rng, Fun fun = {}) const
{
return {all(static_cast<Rng &&>(rng)), std::move(fun)};
}
};
struct partial_sum_fn : partial_sum_base_fn
{
using partial_sum_base_fn::operator();
template(typename Fun)(
requires (!range<Fun>))
constexpr auto operator()(Fun && fun) const
{
return make_view_closure(
bind_back(partial_sum_base_fn{}, static_cast<Fun &&>(fun)));
}
template<typename Fun = plus>
RANGES_DEPRECATED(
"Use \"ranges::views::partial_sum\" instead of "
"\"ranges::views::partial_sum()\".")
constexpr auto
operator()() const
{
return make_view_closure(bind_back(partial_sum_base_fn{}, Fun{}));
}
};
/// \relates partial_sum_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<partial_sum_fn>, partial_sum)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::partial_sum_view)
#endif

View File

@@ -0,0 +1,125 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_REF_HPP
#define RANGES_V3_VIEW_REF_HPP
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/addressof.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
template<typename Rng>
struct ref_view;
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<ref_view<Rng>> = true;
/// \addtogroup group-views
/// @{
template<typename Rng>
struct ref_view : view_interface<ref_view<Rng>, range_cardinality<Rng>::value>
{
private:
CPP_assert(range<Rng>);
static_assert(std::is_object<Rng>::value, "");
Rng * rng_ = nullptr; // exposition only
public:
constexpr ref_view() noexcept = default;
constexpr ref_view(Rng & rng) noexcept
: rng_(detail::addressof(rng))
{}
constexpr Rng & base() const noexcept
{
return *rng_;
}
constexpr iterator_t<Rng> begin() const noexcept(noexcept(ranges::begin(*rng_)))
{
return ranges::begin(*rng_);
}
constexpr sentinel_t<Rng> end() const noexcept(noexcept(ranges::end(*rng_)))
{
return ranges::end(*rng_);
}
CPP_member
constexpr auto empty() const noexcept(noexcept(ranges::empty(*rng_)))
-> CPP_ret(bool)(
requires detail::can_empty_<Rng>)
{
return ranges::empty(*rng_);
}
CPP_auto_member
constexpr auto CPP_fun(size)()(const //
noexcept(noexcept(ranges::size(*rng_))) //
requires sized_range<Rng>)
{
return ranges::size(*rng_);
}
CPP_auto_member
constexpr auto CPP_fun(data)()(const //
noexcept(noexcept(ranges::data(*rng_))) //
requires contiguous_range<Rng>)
{
return ranges::data(*rng_);
}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename R)(
requires range<R>)
ref_view(R &) //
-> ref_view<R>;
#endif
namespace views
{
struct ref_fn
{
template(typename Rng)(
requires range<Rng>)
constexpr ref_view<Rng> operator()(Rng & rng) const noexcept
{
return ref_view<Rng>(rng);
}
template<typename Rng>
void operator()(Rng const && rng) const = delete;
};
/// \relates const_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(ref_fn, ref)
} // namespace views
namespace cpp20
{
template(typename Rng)(
requires std::is_object<Rng>::value) //
using ref_view = ranges::ref_view<Rng>;
}
} // namespace ranges
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::ref_view)
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,109 @@
/// \file
// Range v3 library
//
// Copyright Andrey Diduh 2019
//
// 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_REMOVE_HPP
#define RANGES_V3_VIEW_REMOVE_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/comparisons.hpp>
#include <range/v3/view/remove_if.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
namespace views
{
struct remove_base_fn
{
private:
template<typename Value>
struct pred_
{
Value value_;
template(typename T)(
requires equality_comparable_with<T, Value const &>)
bool operator()(T && other) const
{
return static_cast<T &&>(other) == value_;
}
};
public:
template(typename Rng, typename Value)(
requires move_constructible<Value> AND viewable_range<Rng> AND
input_range<Rng> AND
indirectly_comparable<iterator_t<Rng>, Value const *, equal_to>)
constexpr auto operator()(Rng && rng, Value value) const
{
return remove_if(static_cast<Rng &&>(rng),
pred_<Value>{std::move(value)});
}
template(typename Rng, typename Value, typename Proj)(
requires move_constructible<Value> AND viewable_range<Rng> AND
input_range<Rng> AND
indirectly_comparable<iterator_t<Rng>, Value const *, equal_to, Proj>)
constexpr auto operator()(Rng && rng, Value value, Proj proj) const
{
return remove_if(static_cast<Rng &&>(rng),
pred_<Value>{std::move(value)},
std::move(proj));
}
};
struct remove_bind_fn
{
template<typename Value>
constexpr auto operator()(Value value) const // TODO: underconstrained
{
return make_view_closure(bind_back(remove_base_fn{}, std::move(value)));
}
template(typename Value, typename Proj)(
requires (!range<Value>)) // TODO: underconstrained
constexpr auto operator()(Value && value, Proj proj) const
{
return make_view_closure(bind_back(
remove_base_fn{}, static_cast<Value &&>(value), std::move(proj)));
}
};
struct RANGES_EMPTY_BASES remove_fn
: remove_base_fn, remove_bind_fn
{
using remove_base_fn::operator();
using remove_bind_fn::operator();
};
/// \relates remove_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(remove_fn, remove)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_VIEW_REMOVE_HPP

View File

@@ -0,0 +1,209 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_REMOVE_IF_HPP
#define RANGES_V3_VIEW_REMOVE_IF_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/functional/compose.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/box.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng, typename Pred>
struct RANGES_EMPTY_BASES remove_if_view
: view_adaptor<remove_if_view<Rng, Pred>, Rng,
is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
, private box<semiregular_box_t<Pred>>
{
remove_if_view() = default;
constexpr remove_if_view(Rng rng, Pred pred)
: remove_if_view::view_adaptor{detail::move(rng)}
, remove_if_view::box(detail::move(pred))
{}
private:
friend range_access;
struct adaptor : adaptor_base
{
adaptor() = default;
constexpr adaptor(remove_if_view * rng) noexcept
: rng_(rng)
{}
static constexpr iterator_t<Rng> begin(remove_if_view & rng)
{
return *rng.begin_;
}
constexpr void next(iterator_t<Rng> & it) const
{
RANGES_ASSERT(it != ranges::end(rng_->base()));
rng_->satisfy_forward(++it);
}
CPP_member
constexpr auto prev(iterator_t<Rng> & it) const //
-> CPP_ret(void)(
requires bidirectional_range<Rng>)
{
rng_->satisfy_reverse(it);
}
void advance() = delete;
void distance_to() = delete;
private:
remove_if_view * rng_;
};
constexpr adaptor begin_adaptor()
{
cache_begin();
return {this};
}
CPP_member
constexpr auto end_adaptor() const noexcept //
-> CPP_ret(adaptor_base)(
requires (!common_range<Rng>))
{
return {};
}
CPP_member
constexpr auto end_adaptor() //
-> CPP_ret(adaptor)(
requires common_range<Rng>)
{
if(bidirectional_range<Rng>)
cache_begin();
return {this};
}
constexpr void satisfy_forward(iterator_t<Rng> & it)
{
auto const last = ranges::end(this->base());
auto & pred = this->remove_if_view::box::get();
while(it != last && invoke(pred, *it))
++it;
}
constexpr void satisfy_reverse(iterator_t<Rng> & it)
{
RANGES_ASSERT(begin_);
auto const & first = *begin_;
auto & pred = this->remove_if_view::box::get();
do
{
RANGES_ASSERT(it != first);
(void)first;
--it;
} while(invoke(pred, *it));
}
constexpr void cache_begin()
{
if(begin_)
return;
auto it = ranges::begin(this->base());
satisfy_forward(it);
begin_.emplace(std::move(it));
}
detail::non_propagating_cache<iterator_t<Rng>> begin_;
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename Pred)(
requires copy_constructible<Pred>)
remove_if_view(Rng &&, Pred)
-> remove_if_view<views::all_t<Rng>, Pred>;
#endif
namespace views
{
/// Given a source range, unary predicate, and optional projection,
/// present a view of the elements that do not satisfy the predicate.
struct remove_if_base_fn
{
template(typename Rng, typename Pred)(
requires viewable_range<Rng> AND input_range<Rng> AND
indirect_unary_predicate<Pred, iterator_t<Rng>>)
constexpr remove_if_view<all_t<Rng>, Pred> operator()(Rng && rng, Pred pred)
const
{
return remove_if_view<all_t<Rng>, Pred>{all(static_cast<Rng &&>(rng)),
std::move(pred)};
}
template(typename Rng, typename Pred, typename Proj)(
requires viewable_range<Rng> AND input_range<Rng> AND
indirect_unary_predicate<Pred, projected<iterator_t<Rng>, Proj>>)
constexpr remove_if_view<all_t<Rng>, composed<Pred, Proj>> //
operator()(Rng && rng, Pred pred, Proj proj) const
{
return remove_if_view<all_t<Rng>, composed<Pred, Proj>>{
all(static_cast<Rng &&>(rng)),
compose(std::move(pred), std::move(proj))};
}
};
struct remove_if_bind_fn
{
template<typename Pred>
constexpr auto operator()(Pred pred) const // TODO: underconstrained
{
return make_view_closure(bind_back(remove_if_base_fn{}, std::move(pred)));
}
template(typename Pred, typename Proj)(
requires (!range<Pred>)) // TODO: underconstrained
constexpr auto operator()(Pred && pred, Proj proj) const
{
return make_view_closure(bind_back(
remove_if_base_fn{}, static_cast<Pred &&>(pred), std::move(proj)));
}
};
struct RANGES_EMPTY_BASES remove_if_fn
: remove_if_base_fn, remove_if_bind_fn
{
using remove_if_base_fn::operator();
using remove_if_bind_fn::operator();
};
/// \relates remove_if_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(remove_if_fn, remove_if)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::remove_if_view)
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,123 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_REPEAT_HPP
#define RANGES_V3_VIEW_REPEAT_HPP
#include <utility>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/unreachable_sentinel.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
// Ordinarily, a view shouldn't contain its elements. This is so that copying
// and assigning ranges is O(1), and also so that in the event of element
// mutation, all the copies of the range see the mutation the same way. The
// repeat_view *does* own its lone element, though. This is OK because:
// - O(N) copying is fine when N==1 as it is in this case, and
// - The element is immutable, so there is no potential for incorrect
// semantics.
template<typename Val>
struct repeat_view : view_facade<repeat_view<Val>, infinite>
{
private:
semiregular_box_t<Val> value_;
friend range_access;
struct cursor
{
private:
Val const * value_;
std::ptrdiff_t n_ = 0;
public:
cursor() = default;
explicit cursor(Val const & value)
: value_(std::addressof(value))
{}
Val const & read() const noexcept
{
return *value_;
}
bool equal(cursor const & that) const
{
return n_ == that.n_;
}
void next()
{
++n_;
}
void prev()
{
--n_;
}
void advance(std::ptrdiff_t d)
{
n_ += d;
}
std::ptrdiff_t distance_to(cursor const & that) const
{
return that.n_ - n_;
}
};
cursor begin_cursor() const
{
return cursor{value_};
}
unreachable_sentinel_t end_cursor() const
{
return unreachable;
}
public:
repeat_view() = default;
constexpr explicit repeat_view(Val value)
: value_(detail::move(value))
{}
};
namespace views
{
struct repeat_fn
{
template(typename Val)(
requires copy_constructible<Val>)
repeat_view<Val> operator()(Val value) const
{
return repeat_view<Val>{std::move(value)};
}
};
/// \relates repeat_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(repeat_fn, repeat)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::repeat_view)
#endif

View File

@@ -0,0 +1,131 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_REPEAT_N_HPP
#define RANGES_V3_VIEW_REPEAT_N_HPP
#include <utility>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
// Ordinarily, a view shouldn't contain its elements. This is so that copying
// and assigning ranges is O(1), and also so that in the event of element
// mutation, all the copies of the range see the mutation the same way. The
// repeat_n_view *does* own its lone element, though. This is OK because:
// - O(N) copying is fine when N==1 as it is in this case, and
// - The element is immutable, so there is no potential for incorrect
// semantics.
template<typename Val>
struct repeat_n_view : view_facade<repeat_n_view<Val>, finite>
{
private:
friend range_access;
semiregular_box_t<Val> value_;
std::ptrdiff_t n_;
struct cursor
{
private:
Val const * value_;
std::ptrdiff_t n_;
public:
cursor() = default;
cursor(Val const & value, std::ptrdiff_t n)
: value_(std::addressof(value))
, n_(n)
{}
Val const & read() const
{
return *value_;
}
constexpr bool equal(default_sentinel_t) const
{
return 0 == n_;
}
bool equal(cursor const & that) const
{
return n_ == that.n_;
}
void next()
{
RANGES_EXPECT(0 != n_);
--n_;
}
void prev()
{
++n_;
}
void advance(std::ptrdiff_t n)
{
n_ -= n;
}
std::ptrdiff_t distance_to(cursor const & that) const
{
return n_ - that.n_;
}
};
cursor begin_cursor() const
{
return {value_, n_};
}
public:
repeat_n_view() = default;
constexpr repeat_n_view(Val value, std::ptrdiff_t n)
: value_(detail::move(value))
, n_((RANGES_EXPECT(0 <= n), n))
{}
constexpr std::size_t size() const
{
return static_cast<std::size_t>(n_);
}
};
namespace views
{
struct repeat_n_fn
{
template(typename Val)(
requires copy_constructible<Val>)
repeat_n_view<Val> operator()(Val value, std::ptrdiff_t n) const
{
return repeat_n_view<Val>{std::move(value), n};
}
};
/// \relates repeat_n_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(repeat_n_fn, repeat_n)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::repeat_n_view)
#endif

View File

@@ -0,0 +1,142 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_REPLACE_HPP
#define RANGES_V3_VIEW_REPLACE_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
template<typename Val1, typename Val2>
struct replacer_fn
{
private:
Val1 old_value_;
Val2 new_value_;
public:
replacer_fn() = default;
constexpr replacer_fn(Val1 old_value, Val2 new_value)
: old_value_(std::move(old_value))
, new_value_(std::move(new_value))
{}
template<typename I>
[[noreturn]] common_type_t<decay_t<unwrap_reference_t<Val2 const &>>,
iter_value_t<I>> &
operator()(copy_tag, I const &) const
{
RANGES_EXPECT(false);
}
template<typename I>
common_reference_t<unwrap_reference_t<Val2 const &>, iter_reference_t<I>>
operator()(I const & i) const
{
auto && x = *i;
if(x == unwrap_reference(old_value_))
return unwrap_reference(new_value_);
return ((decltype(x) &&)x);
}
template<typename I>
common_reference_t<unwrap_reference_t<Val2 const &>,
iter_rvalue_reference_t<I>>
operator()(move_tag, I const & i) const
{
auto && x = iter_move(i);
if(x == unwrap_reference(old_value_))
return unwrap_reference(new_value_);
return ((decltype(x) &&)x);
}
};
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
namespace views
{
struct replace_base_fn
{
template(typename Rng, typename Val1, typename Val2)(
requires viewable_range<Rng> AND input_range<Rng> AND
same_as<
detail::decay_t<unwrap_reference_t<Val1>>,
detail::decay_t<unwrap_reference_t<Val2>>> AND
equality_comparable_with<
detail::decay_t<unwrap_reference_t<Val1>>,
range_value_t<Rng>> AND
common_with<detail::decay_t<unwrap_reference_t<Val2 const &>>,
range_value_t<Rng>> AND
common_reference_with<unwrap_reference_t<Val2 const &>,
range_reference_t<Rng>> AND
common_reference_with<
unwrap_reference_t<Val2 const &>,
range_rvalue_reference_t<Rng>>)
constexpr replace_view< //
all_t<Rng>, //
detail::decay_t<Val1>, //
detail::decay_t<Val2>> //
operator()(Rng && rng, Val1 && old_value,
Val2 && new_value) const //
{
return {
all(static_cast<Rng &&>(rng)),
{static_cast<Val1 &&>(old_value), static_cast<Val2 &&>(new_value)}};
}
};
struct replace_fn : replace_base_fn
{
using replace_base_fn::operator();
template(typename Val1, typename Val2)(
requires same_as<detail::decay_t<unwrap_reference_t<Val1>>,
detail::decay_t<unwrap_reference_t<Val2>>>)
constexpr auto operator()(Val1 old_value, Val2 new_value) const
{
return make_view_closure(bind_back(
replace_base_fn{}, std::move(old_value), std::move(new_value)));
}
};
/// \relates replace_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(replace_fn, replace)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,157 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_REPLACE_IF_HPP
#define RANGES_V3_VIEW_REPLACE_IF_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/utility/compressed_pair.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
template<typename Pred, typename Val>
struct replacer_if_fn : compressed_pair<semiregular_box_t<Pred>, Val>
{
private:
using base_t = compressed_pair<semiregular_box_t<Pred>, Val>;
using base_t::first;
using base_t::second;
public:
replacer_if_fn() = default;
constexpr replacer_if_fn(Pred pred, Val new_value)
: base_t{std::move(pred), std::move(new_value)}
{}
template<typename I>
[[noreturn]] common_type_t<decay_t<unwrap_reference_t<Val const &>>,
iter_value_t<I>> &
operator()(copy_tag, I const &) const
{
RANGES_EXPECT(false);
}
template(typename I)(
requires (!invocable<Pred const &, iter_reference_t<I>>))
common_reference_t<unwrap_reference_t<Val const &>, iter_reference_t<I>> //
operator()(I const & i)
{
auto && x = *i;
if(invoke(first(), (decltype(x) &&)x)) //
return unwrap_reference(second());
return (decltype(x) &&)x;
}
template(typename I)(
requires invocable<Pred const &, iter_reference_t<I>>)
common_reference_t<unwrap_reference_t<Val const &>, iter_reference_t<I>> //
operator()(I const & i) const
{
auto && x = *i;
if(invoke(first(), (decltype(x) &&)x)) //
return unwrap_reference(second());
return (decltype(x) &&)x;
}
template(typename I)(
requires (!invocable<Pred const &, iter_rvalue_reference_t<I>>))
common_reference_t<
unwrap_reference_t<Val const &>, //
iter_rvalue_reference_t<I>> //
operator()(move_tag, I const & i)
{
auto && x = iter_move(i);
if(invoke(first(), (decltype(x) &&)x)) //
return unwrap_reference(second());
return (decltype(x) &&)x;
}
template(typename I)(
requires invocable<Pred const &, iter_rvalue_reference_t<I>>)
common_reference_t< //
unwrap_reference_t<Val const &>, //
iter_rvalue_reference_t<I>> //
operator()(move_tag, I const & i) const
{
auto && x = iter_move(i);
if(invoke(first(), (decltype(x) &&)x)) //
return unwrap_reference(second());
return (decltype(x) &&)x;
}
};
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
namespace views
{
struct replace_if_base_fn
{
template(typename Rng, typename Pred, typename Val)(
requires viewable_range<Rng> AND input_range<Rng> AND
indirect_unary_predicate<Pred, iterator_t<Rng>> AND
common_with<detail::decay_t<unwrap_reference_t<Val const &>>,
range_value_t<Rng>> AND
common_reference_with<unwrap_reference_t<Val const &>,
range_reference_t<Rng>> AND
common_reference_with<unwrap_reference_t<Val const &>,
range_rvalue_reference_t<Rng>>)
constexpr replace_if_view<all_t<Rng>, Pred, Val> //
operator()(Rng && rng, Pred pred, Val new_value) const
{
return {all(static_cast<Rng &&>(rng)),
{std::move(pred), std::move(new_value)}};
}
};
struct replace_if_fn : replace_if_base_fn
{
using replace_if_base_fn::operator();
template<typename Pred, typename Val>
constexpr auto operator()(Pred pred, Val new_value) const
{
return make_view_closure(bind_back(
replace_if_base_fn{}, std::move(pred), std::move(new_value)));
}
};
/// \relates replace_if_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(replace_if_fn, replace_if)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,186 @@
/// \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_REVERSE_HPP
#define RANGES_V3_VIEW_REVERSE_HPP
#include <iterator>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/iterator/reverse_iterator.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/box.hpp>
#include <range/v3/utility/get.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng>
struct RANGES_EMPTY_BASES reverse_view
: view_interface<reverse_view<Rng>, range_cardinality<Rng>::value>
, private detail::non_propagating_cache<iterator_t<Rng>, reverse_view<Rng>,
!common_range<Rng>>
{
private:
CPP_assert(bidirectional_range<Rng>);
Rng rng_;
constexpr reverse_iterator<iterator_t<Rng>> begin_(std::true_type)
{
return make_reverse_iterator(ranges::end(rng_));
}
constexpr reverse_iterator<iterator_t<Rng>> begin_(std::false_type)
{
using cache_t =
detail::non_propagating_cache<iterator_t<Rng>, reverse_view<Rng>>;
auto & end_ = static_cast<cache_t &>(*this);
if(!end_)
{
#if defined(_MSC_VER)
auto tmp = ranges::begin(rng_);
auto e = ranges::end(rng_);
while(tmp != e)
++tmp;
#else
auto tmp = ranges::next(ranges::begin(rng_), ranges::end(rng_));
#endif
end_ = std::move(tmp);
}
return make_reverse_iterator(*end_);
}
public:
reverse_view() = default;
constexpr explicit reverse_view(Rng rng)
: rng_(detail::move(rng))
{}
Rng base() const
{
return rng_;
}
constexpr reverse_iterator<iterator_t<Rng>> begin()
{
return begin_(meta::bool_<(bool)common_range<Rng>>{});
}
template(bool Const = true)(
requires Const AND common_range<meta::const_if_c<Const, Rng>>)
constexpr reverse_iterator<iterator_t<meta::const_if_c<Const, Rng>>> begin() const
{
return make_reverse_iterator(ranges::end(rng_));
}
constexpr reverse_iterator<iterator_t<Rng>> end()
{
return make_reverse_iterator(ranges::begin(rng_));
}
template(bool Const = true)(
requires Const AND common_range<meta::const_if_c<Const, Rng>>)
constexpr reverse_iterator<iterator_t<meta::const_if_c<Const, Rng>>> end() const
{
return make_reverse_iterator(ranges::begin(rng_));
}
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return ranges::size(rng_);
}
CPP_auto_member
constexpr auto CPP_fun(size)()(const //
requires sized_range<Rng const>)
{
return ranges::size(rng_);
}
};
template<typename Rng>
struct reverse_view<reverse_view<Rng>> : Rng
{
CPP_assert(bidirectional_range<Rng>);
CPP_assert(
same_as<detail::decay_t<decltype(std::declval<reverse_view<Rng>>().base())>,
Rng>);
reverse_view() = default;
constexpr explicit reverse_view(reverse_view<Rng> rng)
: Rng(rng.base())
{}
constexpr reverse_view<Rng> base() const
{
return reverse_view<Rng>{*this};
}
};
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<reverse_view<Rng>> =
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
reverse_view(Rng &&) //
-> reverse_view<views::all_t<Rng>>;
template<typename Rng>
reverse_view(reverse_view<Rng>)
-> reverse_view<reverse_view<Rng>>;
#endif
namespace views
{
struct reverse_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND bidirectional_range<Rng>)
constexpr reverse_view<all_t<Rng>> operator()(Rng && rng) const
{
return reverse_view<all_t<Rng>>{all(static_cast<Rng &&>(rng))};
}
};
/// \relates reverse_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<reverse_fn>, reverse)
} // namespace views
namespace cpp20
{
namespace views
{
using ranges::views::reverse;
}
template(typename Rng)(
requires view_<Rng> AND bidirectional_range<Rng>)
using reverse_view = ranges::reverse_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::reverse_view)
#endif

View File

@@ -0,0 +1,267 @@
/// \file
// Range v3 library
//
// Copyright Casey Carter 2016
//
// 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_SAMPLE_HPP
#define RANGES_V3_VIEW_SAMPLE_HPP
#include <meta/meta.hpp>
#include <range/v3/algorithm/shuffle.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
template<typename Rng,
bool = (bool)sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>>>
class size_tracker
{
range_difference_t<Rng> size_;
public:
CPP_assert(forward_range<Rng> || sized_range<Rng>);
size_tracker() = default;
size_tracker(Rng & rng)
: size_(ranges::distance(rng))
{}
void decrement()
{
--size_;
}
range_difference_t<Rng> get(Rng &, iterator_t<Rng> &) const
{
return size_;
}
};
// Impl for sized_sentinel_for (no need to store anything)
template<typename Rng>
class size_tracker<Rng, true>
{
public:
size_tracker() = default;
size_tracker(Rng &)
{}
void decrement()
{}
range_difference_t<Rng> get(Rng & rng, iterator_t<Rng> const & it) const
{
return ranges::end(rng) - it;
}
};
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
// Take a random sampling from another view
template<typename Rng, typename URNG>
class sample_view : public view_facade<sample_view<Rng, URNG>, finite>
{
friend range_access;
using D = range_difference_t<Rng>;
Rng rng_;
// Mutable is OK here because sample_view is an Input view.
mutable range_difference_t<Rng> size_;
URNG * engine_;
template<bool IsConst>
class cursor
{
friend cursor<!IsConst>;
using Base = meta::const_if_c<IsConst, Rng>;
meta::const_if_c<IsConst, sample_view> * parent_;
iterator_t<Base> current_;
RANGES_NO_UNIQUE_ADDRESS detail::size_tracker<Base> size_;
D pop_size()
{
return size_.get(parent_->rng_, current_);
}
void advance()
{
if(parent_->size_ > 0)
{
using Dist = std::uniform_int_distribution<D>;
Dist dist{};
URNG & engine = *parent_->engine_;
for(;; ++current_, size_.decrement())
{
RANGES_ASSERT(current_ != ranges::end(parent_->rng_));
auto n = pop_size();
RANGES_EXPECT(n > 0);
typename Dist::param_type const interval{0, n - 1};
if(dist(engine, interval) < parent_->size_)
break;
}
}
}
public:
using value_type = range_value_t<Rng>;
using difference_type = D;
cursor() = default;
explicit cursor(meta::const_if_c<IsConst, sample_view> * rng)
: parent_(rng)
, current_(ranges::begin(rng->rng_))
, size_{rng->rng_}
{
auto n = pop_size();
if(rng->size_ > n)
rng->size_ = n;
advance();
}
template(bool Other)(
requires IsConst AND CPP_NOT(Other)) //
cursor(cursor<Other> that)
: parent_(that.parent_)
, current_(std::move(that.current_))
, size_(that.size_)
{}
range_reference_t<Rng> read() const
{
return *current_;
}
bool equal(default_sentinel_t) const
{
RANGES_EXPECT(parent_);
return parent_->size_ <= 0;
}
void next()
{
RANGES_EXPECT(parent_);
RANGES_EXPECT(parent_->size_ > 0);
--parent_->size_;
RANGES_ASSERT(current_ != ranges::end(parent_->rng_));
++current_;
size_.decrement();
advance();
}
};
cursor<false> begin_cursor()
{
return cursor<false>{this};
}
template(bool Const = true)(
requires Const AND
(sized_range<meta::const_if_c<Const, Rng>> ||
sized_sentinel_for<sentinel_t<meta::const_if_c<Const, Rng>>,
iterator_t<meta::const_if_c<Const, Rng>>> ||
forward_range<meta::const_if_c<Const, Rng>>)) //
cursor<Const> begin_cursor() const
{
return cursor<true>{this};
}
public:
sample_view() = default;
explicit sample_view(Rng rng, D sample_size, URNG & generator)
: rng_(std::move(rng))
, size_(sample_size)
, engine_(std::addressof(generator))
{
RANGES_EXPECT(sample_size >= 0);
}
Rng base() const
{
return rng_;
}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng, typename URNG>
sample_view(Rng &&, range_difference_t<Rng>, URNG &)
->sample_view<views::all_t<Rng>, URNG>;
#endif
namespace views
{
/// Returns a random sample of a range of length `size(range)`.
struct sample_base_fn
{
template(typename Rng, typename URNG = detail::default_random_engine)(
requires viewable_range<Rng> AND input_range<Rng> AND
uniform_random_bit_generator<URNG> AND
convertible_to<invoke_result_t<URNG &>, range_difference_t<Rng>> AND
(sized_range<Rng> ||
sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>> ||
forward_range<Rng>)) //
sample_view<all_t<Rng>, URNG> operator()(
Rng && rng,
range_difference_t<Rng> sample_size,
URNG & generator = detail::get_random_engine()) const
{
return sample_view<all_t<Rng>, URNG>{
all(static_cast<Rng &&>(rng)), sample_size, generator};
}
/// \cond
template<typename Rng, typename URNG>
invoke_result_t<sample_base_fn, Rng, range_difference_t<Rng>, URNG &> //
operator()(
Rng && rng,
range_difference_t<Rng> sample_size,
detail::reference_wrapper_<URNG> r) const
{
return (*this)(static_cast<Rng &&>(rng), sample_size, r.get());
}
/// \endcond
};
struct sample_fn : sample_base_fn
{
using sample_base_fn::operator();
template(typename Size, typename URNG = detail::default_random_engine)(
requires integral<Size> AND uniform_random_bit_generator<URNG>)
constexpr auto operator()(
Size n,
URNG & urng = detail::get_random_engine()) const //
{
return make_view_closure(bind_back(
sample_base_fn{}, n, detail::reference_wrapper_<URNG>(urng)));
}
};
/// \relates sample_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(sample_fn, sample)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::sample_view)
#endif

View File

@@ -0,0 +1,890 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-present
// Copyright Tomislav Ivek 2015-2016
//
// 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_SET_ALGORITHM_HPP
#define RANGES_V3_VIEW_SET_ALGORITHM_HPP
#include <algorithm>
#include <iterator>
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/comparisons.hpp>
#include <range/v3/functional/identity.hpp>
#include <range/v3/functional/invoke.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/utility/move.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
/// \cond
namespace detail
{
template<typename Rng1, typename Rng2, typename C, typename P1, typename P2,
template<bool, typename...> class Cursor, cardinality Cardinality>
struct set_algorithm_view
: view_facade<set_algorithm_view<Rng1, Rng2, C, P1, P2, Cursor, Cardinality>,
Cardinality>
{
private:
friend range_access;
semiregular_box_t<C> pred_;
semiregular_box_t<P1> proj1_;
semiregular_box_t<P2> proj2_;
Rng1 rng1_;
Rng2 rng2_;
template<bool IsConst>
using cursor = Cursor<IsConst, Rng1, Rng2, C, P1, P2>;
cursor<simple_view<Rng1>() && simple_view<Rng2>()> begin_cursor()
{
return {pred_,
proj1_,
proj2_,
ranges::begin(rng1_),
ranges::end(rng1_),
ranges::begin(rng2_),
ranges::end(rng2_)};
}
CPP_member
auto begin_cursor() const //
-> CPP_ret(cursor<true>)(
requires range<Rng1 const> && range<Rng2 const>)
{
return {pred_,
proj1_,
proj2_,
ranges::begin(rng1_),
ranges::end(rng1_),
ranges::begin(rng2_),
ranges::end(rng2_)};
}
public:
set_algorithm_view() = default;
set_algorithm_view(Rng1 rng1, Rng2 rng2, C pred, P1 proj1, P2 proj2)
: pred_(std::move(pred))
, proj1_(std::move(proj1))
, proj2_(std::move(proj2))
, rng1_(std::move(rng1))
, rng2_(std::move(rng2))
{}
};
template<bool IsConst, typename Rng1, typename Rng2, typename C, typename P1,
typename P2>
struct set_difference_cursor
{
private:
friend struct set_difference_cursor<!IsConst, Rng1, Rng2, C, P1, P2>;
using pred_ref_ = semiregular_box_ref_or_val_t<C, IsConst>;
using proj1_ref_ = semiregular_box_ref_or_val_t<P1, IsConst>;
using proj2_ref_ = semiregular_box_ref_or_val_t<P2, IsConst>;
pred_ref_ pred_;
proj1_ref_ proj1_;
proj2_ref_ proj2_;
template<typename T>
using constify_if = meta::const_if_c<IsConst, T>;
using R1 = constify_if<Rng1>;
using R2 = constify_if<Rng2>;
iterator_t<R1> it1_;
sentinel_t<R1> end1_;
iterator_t<R2> it2_;
sentinel_t<R2> end2_;
void satisfy()
{
while(it1_ != end1_)
{
if(it2_ == end2_)
return;
if(invoke(pred_, invoke(proj1_, *it1_), invoke(proj2_, *it2_)))
return;
if(!invoke(pred_, invoke(proj2_, *it2_), invoke(proj1_, *it1_)))
++it1_;
++it2_;
}
}
public:
using value_type = range_value_t<constify_if<Rng1>>;
using single_pass = meta::or_c<single_pass_iterator_<iterator_t<R1>>,
single_pass_iterator_<iterator_t<R2>>>;
set_difference_cursor() = default;
set_difference_cursor(pred_ref_ pred, proj1_ref_ proj1, proj2_ref_ proj2,
iterator_t<R1> it1, sentinel_t<R1> end1,
iterator_t<R2> it2, sentinel_t<R2> end2)
: pred_(std::move(pred))
, proj1_(std::move(proj1))
, proj2_(std::move(proj2))
, it1_(std::move(it1))
, end1_(std::move(end1))
, it2_(std::move(it2))
, end2_(std::move(end2))
{
satisfy();
}
template(bool Other)(
requires IsConst && CPP_NOT(Other)) //
set_difference_cursor(
set_difference_cursor<Other, Rng1, Rng2, C, P1, P2> that)
: pred_(std::move(that.pred_))
, proj1_(std::move(that.proj1_))
, proj2_(std::move(that.proj2_))
, it1_(std::move(that.it1_))
, end1_(std::move(that.end1_))
, it2_(std::move(that.it2_))
, end2_(std::move(that.end2_))
{}
// clang-format off
auto CPP_auto_fun(read)()(const)
(
return *it1_
)
// clang-format on
void next()
{
++it1_;
satisfy();
}
CPP_member
auto equal(set_difference_cursor const & that) const //
-> CPP_ret(bool)(
requires forward_range<Rng1>)
{
// does not support comparing iterators from different ranges
return it1_ == that.it1_;
}
bool equal(default_sentinel_t) const
{
return it1_ == end1_;
}
// clang-format off
auto CPP_auto_fun(move)()(const)
(
return iter_move(it1_)
)
// clang-format on
};
constexpr cardinality set_difference_cardinality(cardinality c1, cardinality c2)
{
return (c1 == unknown)
? unknown
: (c1 >= 0) || (c1 == finite) ? finite : // else, c1 == infinite
(c2 >= 0) || (c2 == finite) ? infinite : unknown;
}
} // namespace detail
/// \endcond
template<typename Rng1, typename Rng2, typename C, typename P1, typename P2>
using set_difference_view =
detail::set_algorithm_view<Rng1, Rng2, C, P1, P2, detail::set_difference_cursor,
detail::set_difference_cardinality(
range_cardinality<Rng1>::value,
range_cardinality<Rng2>::value)>;
namespace views
{
struct set_difference_base_fn
{
template(typename Rng1, typename Rng2, typename C = less,
typename P1 = identity, typename P2 = identity)(
requires //
viewable_range<Rng1> AND input_range<Rng1> AND
viewable_range<Rng2> AND input_range<Rng2> AND
indirect_relation<C,
projected<iterator_t<Rng1>, P1>,
projected<iterator_t<Rng2>, P2>>)
set_difference_view<all_t<Rng1>, all_t<Rng2>, C, P1, P2> //
operator()(Rng1 && rng1,
Rng2 && rng2,
C pred = C{},
P1 proj1 = P1{},
P2 proj2 = P2{}) const
{
return {all(static_cast<Rng1 &&>(rng1)),
all(static_cast<Rng2 &&>(rng2)),
std::move(pred),
std::move(proj1),
std::move(proj2)};
}
};
struct set_difference_fn : set_difference_base_fn
{
using set_difference_base_fn::operator();
template(typename Rng2, typename C = less, typename P1 = identity,
typename P2 = identity)(
requires viewable_range<Rng2> AND input_range<Rng2> AND (!range<C>))
constexpr auto operator()(Rng2 && rng2,
C && pred = C{},
P1 proj1 = P1{},
P2 proj2 = P2{}) const
{
return make_view_closure(bind_back(set_difference_base_fn{},
all(rng2),
static_cast<C &&>(pred),
std::move(proj1),
std::move(proj2)));
}
};
/// \relates set_difference_fn
RANGES_INLINE_VARIABLE(set_difference_fn, set_difference)
} // namespace views
/// \cond
namespace detail
{
template<bool IsConst, typename Rng1, typename Rng2, typename C, typename P1,
typename P2>
struct set_intersection_cursor
{
private:
friend struct set_intersection_cursor<!IsConst, Rng1, Rng2, C, P1, P2>;
using pred_ref_ = semiregular_box_ref_or_val_t<C, IsConst>;
using proj1_ref_ = semiregular_box_ref_or_val_t<P1, IsConst>;
using proj2_ref_ = semiregular_box_ref_or_val_t<P2, IsConst>;
pred_ref_ pred_;
proj1_ref_ proj1_;
proj2_ref_ proj2_;
template<typename T>
using constify_if = meta::const_if_c<IsConst, T>;
using R1 = constify_if<Rng1>;
using R2 = constify_if<Rng2>;
iterator_t<R1> it1_;
sentinel_t<R1> end1_;
iterator_t<R2> it2_;
sentinel_t<R2> end2_;
void satisfy()
{
while(it1_ != end1_ && it2_ != end2_)
{
if(invoke(pred_, invoke(proj1_, *it1_), invoke(proj2_, *it2_)))
++it1_;
else
{
if(!invoke(pred_, invoke(proj2_, *it2_), invoke(proj1_, *it1_)))
return;
++it2_;
}
}
}
public:
using value_type = range_value_t<R1>;
using single_pass = meta::or_c<single_pass_iterator_<iterator_t<R1>>,
single_pass_iterator_<iterator_t<R2>>>;
set_intersection_cursor() = default;
set_intersection_cursor(pred_ref_ pred, proj1_ref_ proj1, proj2_ref_ proj2,
iterator_t<R1> it1, sentinel_t<R1> end1,
iterator_t<R2> it2, sentinel_t<R2> end2)
: pred_(std::move(pred))
, proj1_(std::move(proj1))
, proj2_(std::move(proj2))
, it1_(std::move(it1))
, end1_(std::move(end1))
, it2_(std::move(it2))
, end2_(std::move(end2))
{
satisfy();
}
template(bool Other)(
requires IsConst && CPP_NOT(Other)) //
set_intersection_cursor(
set_intersection_cursor<Other, Rng1, Rng2, C, P1, P2> that)
: pred_(std::move(that.pred_))
, proj1_(std::move(that.proj1_))
, proj2_(std::move(that.proj2_))
, it1_(std::move(that.it1_))
, end1_(std::move(that.end1_))
, it2_(std::move(that.it2_))
, end2_(std::move(that.end2_))
{}
// clang-format off
auto CPP_auto_fun(read)()(const)
(
return *it1_
)
// clang-format on
void next()
{
++it1_;
++it2_;
satisfy();
}
CPP_member
auto equal(set_intersection_cursor const & that) const //
-> CPP_ret(bool)(
requires forward_range<Rng1>)
{
// does not support comparing iterators from different ranges
return it1_ == that.it1_;
}
bool equal(default_sentinel_t) const
{
return (it1_ == end1_) || (it2_ == end2_);
}
// clang-format off
auto CPP_auto_fun(move)()(const)
(
return iter_move(it1_)
)
// clang-format on
};
constexpr cardinality set_intersection_cardinality(cardinality c1, cardinality c2)
{
return (c1 == unknown) || (c2 == unknown)
? unknown
: (c1 >= 0 || c1 == finite) || (c2 >= 0 || c2 == finite) ? finite
: unknown;
}
} // namespace detail
/// \endcond
template<typename Rng1, typename Rng2, typename C, typename P1, typename P2>
using set_intersection_view =
detail::set_algorithm_view<Rng1, Rng2, C, P1, P2, detail::set_intersection_cursor,
detail::set_intersection_cardinality(
range_cardinality<Rng1>::value,
range_cardinality<Rng2>::value)>;
namespace views
{
struct set_intersection_base_fn
{
template(typename Rng1, typename Rng2, typename C = less,
typename P1 = identity, typename P2 = identity)(
requires viewable_range<Rng1> AND input_range<Rng1> AND
viewable_range<Rng2> AND input_range<Rng2> AND
indirect_relation<
C,
projected<iterator_t<Rng1>, P1>,
projected<iterator_t<Rng2>, P2>>)
set_intersection_view<all_t<Rng1>, all_t<Rng2>, C, P1, P2>
operator()(Rng1 && rng1,
Rng2 && rng2,
C pred = C{},
P1 proj1 = P1{},
P2 proj2 = P2{}) const
{
return {all(static_cast<Rng1 &&>(rng1)),
all(static_cast<Rng2 &&>(rng2)),
std::move(pred),
std::move(proj1),
std::move(proj2)};
}
};
struct set_intersection_fn : set_intersection_base_fn
{
using set_intersection_base_fn::operator();
template(typename Rng2, typename C = less, typename P1 = identity,
typename P2 = identity)(
requires viewable_range<Rng2> AND input_range<Rng2> AND (!range<C>))
constexpr auto operator()(Rng2 && rng2,
C && pred = C{},
P1 proj1 = P1{},
P2 proj2 = P2{}) const
{
return make_view_closure(bind_back(set_intersection_base_fn{},
all(rng2),
static_cast<C &&>(pred),
std::move(proj1),
std::move(proj2)));
}
};
/// \relates set_intersection_fn
RANGES_INLINE_VARIABLE(set_intersection_fn, set_intersection)
} // namespace views
/// \cond
namespace detail
{
template<bool IsConst, typename Rng1, typename Rng2, typename C, typename P1,
typename P2>
struct set_union_cursor
{
private:
friend struct set_union_cursor<!IsConst, Rng1, Rng2, C, P1, P2>;
using pred_ref_ = semiregular_box_ref_or_val_t<C, IsConst>;
using proj1_ref_ = semiregular_box_ref_or_val_t<P1, IsConst>;
using proj2_ref_ = semiregular_box_ref_or_val_t<P2, IsConst>;
pred_ref_ pred_;
proj1_ref_ proj1_;
proj2_ref_ proj2_;
template<typename T>
using constify_if = meta::const_if_c<IsConst, T>;
using R1 = constify_if<Rng1>;
using R2 = constify_if<Rng2>;
iterator_t<R1> it1_;
sentinel_t<R1> end1_;
iterator_t<R2> it2_;
sentinel_t<R2> end2_;
enum class state_t
{
FIRST,
SECOND
} state;
void satisfy()
{
if(it1_ == end1_)
{
state = state_t::SECOND;
return;
}
if(it2_ == end2_)
{
state = state_t::FIRST;
return;
}
if(invoke(pred_, invoke(proj2_, *it2_), invoke(proj1_, *it1_)))
{
state = state_t::SECOND;
return;
}
if(!invoke(pred_, invoke(proj1_, *it1_), invoke(proj2_, *it2_)))
++it2_;
state = state_t::FIRST;
}
public:
using value_type = common_type_t<range_value_t<R1>, range_value_t<R2>>;
using reference_type =
common_reference_t<range_reference_t<R1>, range_reference_t<R2>>;
using rvalue_reference_type =
common_reference_t<range_rvalue_reference_t<R1>,
range_rvalue_reference_t<R2>>;
using single_pass = meta::or_c<single_pass_iterator_<iterator_t<R1>>,
single_pass_iterator_<iterator_t<R2>>>;
set_union_cursor() = default;
set_union_cursor(pred_ref_ pred, proj1_ref_ proj1, proj2_ref_ proj2,
iterator_t<R1> it1, sentinel_t<R1> end1, iterator_t<R2> it2,
sentinel_t<R2> end2)
: pred_(std::move(pred))
, proj1_(std::move(proj1))
, proj2_(std::move(proj2))
, it1_(std::move(it1))
, end1_(std::move(end1))
, it2_(std::move(it2))
, end2_(std::move(end2))
{
satisfy();
}
template(bool Other)(
requires IsConst AND CPP_NOT(Other))
set_union_cursor(set_union_cursor<Other, Rng1, Rng2, C, P1, P2> that)
: pred_(std::move(that.pred_))
, proj1_(std::move(that.proj1_))
, proj2_(std::move(that.proj2_))
, it1_(std::move(that.it1_))
, end1_(std::move(that.end1_))
, it2_(std::move(that.it2_))
, end2_(std::move(that.end2_))
{}
reference_type read() const noexcept(noexcept(*it1_) && noexcept(*it2_))
{
if(state == state_t::SECOND)
return *it2_;
else
return *it1_;
}
void next()
{
if(state == state_t::FIRST)
++it1_;
else
++it2_;
satisfy();
}
CPP_member
auto equal(set_union_cursor const & that) const //
-> CPP_ret(bool)(
requires forward_range<Rng1> && forward_range<Rng2>)
{
// does not support comparing iterators from different ranges
return (it1_ == that.it1_) && (it2_ == that.it2_);
}
bool equal(default_sentinel_t) const
{
return (it1_ == end1_) && (it2_ == end2_);
}
rvalue_reference_type move() const
noexcept(noexcept(iter_move(it1_)) && noexcept(iter_move(it2_)))
{
if(state == state_t::SECOND)
return iter_move(it2_);
else
return iter_move(it1_);
}
};
constexpr cardinality set_union_cardinality(cardinality c1, cardinality c2)
{
return (c1 == infinite) || (c2 == infinite)
? infinite
: (c1 == unknown) || (c2 == unknown) ? unknown : finite;
}
} // namespace detail
/// \endcond
template<typename Rng1, typename Rng2, typename C, typename P1, typename P2>
using set_union_view =
detail::set_algorithm_view<Rng1, Rng2, C, P1, P2, detail::set_union_cursor,
detail::set_union_cardinality(
range_cardinality<Rng1>::value,
range_cardinality<Rng2>::value)>;
namespace views
{
struct set_union_base_fn
{
public:
template(typename Rng1, typename Rng2, typename C = less,
typename P1 = identity, typename P2 = identity)(
requires //
viewable_range<Rng1> AND input_range<Rng1> AND
viewable_range<Rng2> AND input_range<Rng2> AND
common_with<range_value_t<Rng1>, range_value_t<Rng2>> AND
common_reference_with<range_reference_t<Rng1>,
range_reference_t<Rng2>> AND
common_reference_with<range_rvalue_reference_t<Rng1>,
range_rvalue_reference_t<Rng2>> AND
indirect_relation<C,
projected<iterator_t<Rng1>, P1>,
projected<iterator_t<Rng2>, P2>>)
set_union_view<all_t<Rng1>, all_t<Rng2>, C, P1, P2> //
operator()(Rng1 && rng1,
Rng2 && rng2,
C pred = C{},
P1 proj1 = P1{},
P2 proj2 = P2{}) const
{
return {all(static_cast<Rng1 &&>(rng1)),
all(static_cast<Rng2 &&>(rng2)),
std::move(pred),
std::move(proj1),
std::move(proj2)};
}
};
struct set_union_fn : set_union_base_fn
{
using set_union_base_fn::operator();
template(typename Rng2, typename C = less, typename P1 = identity,
typename P2 = identity)(
requires viewable_range<Rng2> AND input_range<Rng2> AND (!range<C>))
constexpr auto operator()(Rng2 && rng2,
C && pred = C{},
P1 proj1 = P1{},
P2 proj2 = P2{}) const
{
return make_view_closure(bind_back(set_union_base_fn{},
all(rng2),
static_cast<C &&>(pred),
std::move(proj1),
std::move(proj2)));
}
};
/// \relates set_union_fn
RANGES_INLINE_VARIABLE(set_union_fn, set_union)
} // namespace views
/// \cond
namespace detail
{
template<bool IsConst, typename Rng1, typename Rng2, typename C, typename P1,
typename P2>
struct set_symmetric_difference_cursor
{
private:
friend struct set_symmetric_difference_cursor<!IsConst, Rng1, Rng2, C, P1,
P2>;
using pred_ref_ = semiregular_box_ref_or_val_t<C, IsConst>;
using proj1_ref_ = semiregular_box_ref_or_val_t<P1, IsConst>;
using proj2_ref_ = semiregular_box_ref_or_val_t<P2, IsConst>;
pred_ref_ pred_;
proj1_ref_ proj1_;
proj2_ref_ proj2_;
template<typename T>
using constify_if = meta::const_if_c<IsConst, T>;
using R1 = constify_if<Rng1>;
using R2 = constify_if<Rng2>;
iterator_t<R1> it1_;
sentinel_t<R1> end1_;
iterator_t<R2> it2_;
sentinel_t<R2> end2_;
enum class state_t
{
FIRST,
SECOND,
ONLY_FIRST,
ONLY_SECOND
} state;
void satisfy()
{
while(it1_ != end1_)
{
if(it2_ == end2_)
{
state = state_t::ONLY_FIRST;
return;
}
if(invoke(pred_, invoke(proj1_, *it1_), invoke(proj2_, *it2_)))
{
state = state_t::FIRST;
return;
}
else
{
if(invoke(pred_, invoke(proj2_, *it2_), invoke(proj1_, *it1_)))
{
state = state_t::SECOND;
return;
}
else
{
++it1_;
++it2_;
}
}
}
state = state_t::ONLY_SECOND;
}
public:
using value_type = common_type_t<range_value_t<R1>, range_value_t<R2>>;
using reference_type =
common_reference_t<range_reference_t<R1>, range_reference_t<R2>>;
using rvalue_reference_type =
common_reference_t<range_rvalue_reference_t<R1>,
range_rvalue_reference_t<R2>>;
using single_pass = meta::or_c<single_pass_iterator_<iterator_t<R1>>,
single_pass_iterator_<iterator_t<R2>>>;
set_symmetric_difference_cursor() = default;
set_symmetric_difference_cursor(pred_ref_ pred, proj1_ref_ proj1,
proj2_ref_ proj2, iterator_t<R1> it1,
sentinel_t<R1> end1, iterator_t<R2> it2,
sentinel_t<R2> end2)
: pred_(std::move(pred))
, proj1_(std::move(proj1))
, proj2_(std::move(proj2))
, it1_(std::move(it1))
, end1_(std::move(end1))
, it2_(std::move(it2))
, end2_(std::move(end2))
, state()
{
satisfy();
}
template(bool Other)(
requires IsConst && CPP_NOT(Other)) //
set_symmetric_difference_cursor(
set_symmetric_difference_cursor<Other, Rng1, Rng2, C, P1, P2> that)
: pred_(std::move(that.pred_))
, proj1_(std::move(that.proj1_))
, proj2_(std::move(that.proj2_))
, it1_(std::move(that.it1_))
, end1_(std::move(that.end1_))
, it2_(std::move(that.it2_))
, end2_(std::move(that.end2_))
, state(that.state)
{}
reference_type read() const noexcept(noexcept(*it1_) && noexcept(*it2_))
{
if(state == state_t::SECOND || state == state_t::ONLY_SECOND)
return *it2_;
else
return *it1_;
}
void next()
{
switch(state)
{
case state_t::FIRST:
++it1_;
satisfy();
break;
case state_t::ONLY_FIRST:
++it1_;
break;
case state_t::SECOND:
++it2_;
satisfy();
break;
case state_t::ONLY_SECOND:
++it2_;
break;
}
}
CPP_member
auto equal(set_symmetric_difference_cursor const & that) const
-> CPP_ret(bool)(
requires forward_range<R1> && forward_range<R2>)
{
// does not support comparing iterators from different ranges:
return (it1_ == that.it1_) && (it2_ == that.it2_);
}
bool equal(default_sentinel_t) const
{
return (it1_ == end1_) && (it2_ == end2_);
}
rvalue_reference_type move() const
noexcept(noexcept(iter_move(it1_)) && noexcept(iter_move(it2_)))
{
if(state == state_t::SECOND || state == state_t::ONLY_SECOND)
return iter_move(it2_);
else
return iter_move(it1_);
}
};
constexpr cardinality set_symmetric_difference_cardinality(cardinality c1,
cardinality c2)
{
return (c1 == unknown) || (c2 == unknown)
? unknown
: (c1 == infinite) != (c2 == infinite)
? infinite
: (c1 == infinite) && (c2 == infinite) ? unknown : finite;
}
} // namespace detail
/// \endcond
template<typename Rng1, typename Rng2, typename C, typename P1, typename P2>
using set_symmetric_difference_view = detail::set_algorithm_view<
Rng1, Rng2, C, P1, P2, detail::set_symmetric_difference_cursor,
detail::set_symmetric_difference_cardinality(range_cardinality<Rng1>::value,
range_cardinality<Rng2>::value)>;
namespace views
{
struct set_symmetric_difference_base_fn
{
template(typename Rng1, typename Rng2, typename C = less,
typename P1 = identity, typename P2 = identity)(
requires //
viewable_range<Rng1> AND input_range<Rng1> AND
viewable_range<Rng2> AND input_range<Rng2> AND
common_with<range_value_t<Rng1>, range_value_t<Rng2>> AND
common_reference_with<range_reference_t<Rng1>,
range_reference_t<Rng2>> AND
common_reference_with<range_rvalue_reference_t<Rng1>,
range_rvalue_reference_t<Rng2>> AND
indirect_relation<C,
projected<iterator_t<Rng1>, P1>,
projected<iterator_t<Rng2>, P2>>)
set_symmetric_difference_view<all_t<Rng1>, all_t<Rng2>, C, P1, P2>
operator()(Rng1 && rng1,
Rng2 && rng2,
C pred = C{},
P1 proj1 = P1{},
P2 proj2 = P2{}) const
{
return {all(static_cast<Rng1 &&>(rng1)),
all(static_cast<Rng2 &&>(rng2)),
std::move(pred),
std::move(proj1),
std::move(proj2)};
}
};
struct set_symmetric_difference_fn : set_symmetric_difference_base_fn
{
using set_symmetric_difference_base_fn::operator();
template(typename Rng2, typename C = less, typename P1 = identity,
typename P2 = identity)(
requires viewable_range<Rng2> AND input_range<Rng2> AND (!range<C>))
constexpr auto operator()(Rng2 && rng2,
C && pred = C{},
P1 proj1 = P1{},
P2 proj2 = P2{}) const
{
return make_view_closure(bind_back(set_symmetric_difference_base_fn{},
all(rng2),
static_cast<C &&>(pred),
std::move(proj1),
std::move(proj2)));
}
};
/// \relates set_symmetric_difference_fn
RANGES_INLINE_VARIABLE(set_symmetric_difference_fn, set_symmetric_difference)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,141 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_SINGLE_HPP
#define RANGES_V3_VIEW_SINGLE_HPP
#include <type_traits>
#include <utility>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/iterator/traits.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/addressof.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename T>
struct single_view : view_interface<single_view<T>, (cardinality)1>
{
private:
CPP_assert(copy_constructible<T>);
static_assert(std::is_object<T>::value,
"The template parameter of single_view must be an object type");
semiregular_box_t<T> value_;
template<typename... Args>
constexpr single_view(in_place_t, std::true_type, Args &&... args)
: value_{static_cast<Args &&>(args)...}
{}
template<typename... Args>
constexpr single_view(in_place_t, std::false_type, Args &&... args)
: value_{in_place, static_cast<Args &&>(args)...}
{}
public:
single_view() = default;
constexpr explicit single_view(T const & t)
: value_(t)
{}
constexpr explicit single_view(T && t)
: value_(std::move(t))
{}
template(class... Args)(
requires constructible_from<T, Args...>)
constexpr single_view(in_place_t, Args &&... args)
: single_view{in_place,
meta::bool_<(bool)semiregular<T>>{},
static_cast<Args &&>(args)...}
{}
constexpr T * begin() noexcept
{
return data();
}
constexpr T const * begin() const noexcept
{
return data();
}
constexpr T * end() noexcept
{
return data() + 1;
}
constexpr T const * end() const noexcept
{
return data() + 1;
}
static constexpr std::size_t size() noexcept
{
return 1u;
}
constexpr T * data() noexcept
{
return detail::addressof(static_cast<T &>(value_));
}
constexpr T const * data() const noexcept
{
return detail::addressof(static_cast<T const &>(value_));
}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<class T>
explicit single_view(T &&) //
-> single_view<detail::decay_t<T>>;
#endif
namespace views
{
struct single_fn
{
template(typename Val)(
requires copy_constructible<Val>)
single_view<Val> operator()(Val value) const
{
return single_view<Val>{std::move(value)};
}
};
/// \relates single_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(single_fn, single)
} // namespace views
namespace cpp20
{
namespace views
{
using ranges::views::single;
}
template(typename T)(
requires std::is_object<T>::value) //
using single_view = ranges::single_view<T>;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::single_view)
#endif

View File

@@ -0,0 +1,341 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_SLICE_HPP
#define RANGES_V3_VIEW_SLICE_HPP
#include <type_traits>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/iterator/counted_iterator.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/iterator/traits.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/drop_exactly.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
template<typename Rng, typename Int>
iterator_t<Rng> pos_at_(Rng && rng, Int i, input_range_tag, std::true_type)
{
RANGES_EXPECT(0 <= i);
return next(ranges::begin(rng), i);
}
template<typename Rng, typename Int>
iterator_t<Rng> pos_at_(Rng && rng, Int i, bidirectional_range_tag,
std::false_type)
{
if(0 > i)
{
// If it's not common and we know the size, faster to count from the front
if(RANGES_CONSTEXPR_IF(sized_range<Rng> && !common_range<Rng>))
return next(ranges::begin(rng), distance(rng) + i);
// Otherwise, probably faster to count from the back.
return next(ranges::next(ranges::begin(rng), ranges::end(rng)), i);
}
return next(ranges::begin(rng), i);
}
template<typename Rng, typename Int>
iterator_t<Rng> pos_at_(Rng && rng, Int i, input_range_tag, std::false_type)
{
RANGES_EXPECT(i >= 0 || (bool)sized_range<Rng> || (bool)forward_range<Rng>);
if(0 > i)
return next(ranges::begin(rng), distance(rng) + i);
return next(ranges::begin(rng), i);
}
template<typename Rng, bool IsRandomAccess>
struct slice_view_ : view_facade<slice_view<Rng>, finite>
{
private:
friend range_access;
Rng rng_;
range_difference_t<Rng> from_, count_;
detail::non_propagating_cache<iterator_t<Rng>> begin_;
iterator_t<Rng> get_begin_()
{
if(!begin_)
begin_ = detail::pos_at_(
rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{});
return *begin_;
}
public:
slice_view_() = default;
constexpr slice_view_(Rng rng, range_difference_t<Rng> from,
range_difference_t<Rng> count)
: rng_(std::move(rng))
, from_(from)
, count_(count)
{}
counted_iterator<iterator_t<Rng>> begin()
{
return make_counted_iterator(get_begin_(), count_);
}
default_sentinel_t end()
{
return {};
}
auto size() const
{
return static_cast<detail::iter_size_t<iterator_t<Rng>>>(count_);
}
Rng base() const
{
return rng_;
}
};
template<typename Rng>
struct slice_view_<Rng, true> : view_interface<slice_view<Rng>, finite>
{
private:
Rng rng_;
range_difference_t<Rng> from_, count_;
public:
slice_view_() = default;
constexpr slice_view_(Rng rng, range_difference_t<Rng> from,
range_difference_t<Rng> count)
: rng_(std::move(rng))
, from_(from)
, count_(count)
{
RANGES_EXPECT(0 <= count_);
}
iterator_t<Rng> begin()
{
return detail::pos_at_(
rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{});
}
iterator_t<Rng> end()
{
return detail::pos_at_(
rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{}) +
count_;
}
template(typename BaseRng = Rng)(
requires range<BaseRng const>)
iterator_t<BaseRng const> begin() const
{
return detail::pos_at_(
rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{});
}
template(typename BaseRng = Rng)(
requires range<BaseRng const>)
iterator_t<BaseRng const> end() const
{
return detail::pos_at_(
rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{}) +
count_;
}
auto size() const
{
return static_cast<detail::iter_size_t<iterator_t<Rng>>>(count_);
}
Rng base() const
{
return rng_;
}
};
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
template<typename Rng>
struct slice_view : detail::slice_view_<Rng, (bool)random_access_range<Rng>>
{
using detail::slice_view_<Rng, (bool)random_access_range<Rng>>::slice_view_;
};
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<slice_view<Rng>> = //
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
slice_view(Rng &&, range_difference_t<Rng>, range_difference_t<Rng>)
->slice_view<views::all_t<Rng>>;
#endif
namespace views
{
struct slice_base_fn
{
private:
template<typename Rng>
static constexpr slice_view<all_t<Rng>> impl_(Rng && rng,
range_difference_t<Rng> from,
range_difference_t<Rng> count,
input_range_tag, range_tag = {})
{
return {all(static_cast<Rng &&>(rng)), from, count};
}
template(typename Rng)(
requires borrowed_range<Rng>)
static subrange<iterator_t<Rng>> impl_(Rng && rng,
range_difference_t<Rng> from,
range_difference_t<Rng> count,
random_access_range_tag,
common_range_tag = {})
{
auto it =
detail::pos_at_(rng, from, range_tag_of<Rng>{}, is_infinite<Rng>{});
return {it, it + count};
}
public:
// slice(rng, 2, 4)
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng>)
constexpr auto operator()(Rng && rng,
range_difference_t<Rng> from,
range_difference_t<Rng> to) const
{
RANGES_EXPECT(0 <= from && from <= to);
return slice_base_fn::impl_(
static_cast<Rng &&>(rng), from, to - from, range_tag_of<Rng>{});
}
// slice(rng, 4, end-2)
// TODO Support Forward, non-Sized ranges by returning a range that
// doesn't know it's size?
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng> AND sized_range<Rng>)
auto operator()(Rng && rng,
range_difference_t<Rng> from,
detail::from_end_of_t<Rng> to) const
{
static_assert(!is_infinite<Rng>::value,
"Can't index from the end of an infinite range!");
RANGES_EXPECT(0 <= from);
RANGES_ASSERT(from <= distance(rng) + to.dist_);
return slice_base_fn::impl_(static_cast<Rng &&>(rng),
from,
distance(rng) + to.dist_ - from,
range_tag_of<Rng>{});
}
// slice(rng, end-4, end-2)
template(typename Rng)(
requires viewable_range<Rng> AND
(forward_range<Rng> || (input_range<Rng> && sized_range<Rng>)))
auto operator()(Rng && rng,
detail::from_end_of_t<Rng> from,
detail::from_end_of_t<Rng> to) const
{
static_assert(!is_infinite<Rng>::value,
"Can't index from the end of an infinite range!");
RANGES_EXPECT(from.dist_ <= to.dist_);
return slice_base_fn::impl_(static_cast<Rng &&>(rng),
from.dist_,
to.dist_ - from.dist_,
range_tag_of<Rng>{},
common_range_tag_of<Rng>{});
}
// slice(rng, 4, end)
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng>)
auto operator()(Rng && rng, range_difference_t<Rng> from, end_fn) const
{
RANGES_EXPECT(0 <= from);
return ranges::views::drop_exactly(static_cast<Rng &&>(rng), from);
}
// slice(rng, end-4, end)
template(typename Rng)(
requires viewable_range<Rng> AND
(forward_range<Rng> || (input_range<Rng> && sized_range<Rng>)))
auto operator()(Rng && rng,
detail::from_end_of_t<Rng> from,
end_fn) const
{
static_assert(!is_infinite<Rng>::value,
"Can't index from the end of an infinite range!");
return slice_base_fn::impl_(static_cast<Rng &&>(rng),
from.dist_,
-from.dist_,
range_tag_of<Rng>{},
common_range_tag_of<Rng>{});
}
};
struct slice_fn : slice_base_fn
{
using slice_base_fn::operator();
// Overloads for the pipe syntax: rng | views::slice(from,to)
template(typename Int)(
requires detail::integer_like_<Int>)
constexpr auto operator()(Int from, Int to) const
{
return make_view_closure(bind_back(slice_base_fn{}, from, to));
}
template(typename Int)(
requires detail::integer_like_<Int>)
constexpr auto operator()(Int from, detail::from_end_<Int> to) const
{
return make_view_closure(bind_back(slice_base_fn{}, from, to));
}
template(typename Int)(
requires detail::integer_like_<Int>)
constexpr auto operator()(detail::from_end_<Int> from,
detail::from_end_<Int> to) const
{
return make_view_closure(bind_back(slice_base_fn{}, from, to));
}
template(typename Int)(
requires detail::integer_like_<Int>)
constexpr auto operator()(Int from, end_fn) const
{
return make_view_closure(
bind_back(ranges::views::drop_exactly_base_fn{}, from));
}
template(typename Int)(
requires detail::integer_like_<Int>)
constexpr auto operator()(detail::from_end_<Int> from, end_fn to) const
{
return make_view_closure(bind_back(slice_base_fn{}, from, to));
}
};
/// \relates _slice_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(slice_fn, slice)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::slice_view)
#endif

View File

@@ -0,0 +1,407 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-present
// Copyright Tobias Mayer 2016
// Copyright Casey Carter 2016
//
// 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_SLIDING_HPP
#define RANGES_V3_VIEW_SLIDING_HPP
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/counted.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace sliding_view_detail
{
enum class cache
{
none,
first,
last
};
template<typename Rng>
using caching = std::integral_constant<
cache, random_access_range<Rng> && sized_range<Rng>
? cache::none
: bidirectional_range<Rng> && common_range<Rng> ? cache::last
: cache::first>;
} // namespace sliding_view_detail
/// \endcond
template<typename Rng,
sliding_view_detail::cache = sliding_view_detail::caching<Rng>::value>
struct sliding_view;
/// \cond
namespace sliding_view_detail
{
template<typename Rng>
using uncounted_t =
decltype(ranges::uncounted(std::declval<iterator_t<Rng> &>()));
template<typename Rng, bool = (bool)random_access_range<Rng>>
struct trailing
{
trailing() = default;
constexpr trailing(Rng & rng)
: it_{uncounted(ranges::begin(rng))}
{}
constexpr uncounted_t<Rng> get(iterator_t<Rng> const &,
range_difference_t<Rng>) const
{
return it_;
}
void next()
{
++it_;
}
CPP_member
auto prev() //
-> CPP_ret(void)(
requires bidirectional_range<Rng>)
{
--it_;
}
private:
uncounted_t<Rng> it_;
};
template<typename Rng>
struct trailing<Rng, true>
{
trailing() = default;
constexpr trailing(Rng &) noexcept
{}
constexpr uncounted_t<Rng> get(iterator_t<Rng> const & it,
range_difference_t<Rng> n) const
{
return uncounted(it - (n - 1));
}
void next()
{}
void prev()
{}
};
template<typename Rng>
struct RANGES_EMPTY_BASES sv_base
: view_adaptor<sliding_view<Rng>, Rng,
is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
, private detail::non_propagating_cache<iterator_t<Rng>, sv_base<Rng>,
caching<Rng>::value != cache::none>
{
CPP_assert(forward_range<Rng>);
sv_base() = default;
sv_base(Rng rng, range_difference_t<Rng> n)
: sv_base::view_adaptor(std::move(rng))
, n_(n)
{
RANGES_ASSERT(0 < n_);
}
CPP_auto_member
auto CPP_fun(size)()(const //
requires sized_range<Rng const>)
{
auto const count = ranges::size(this->base());
auto const n = static_cast<range_size_t<Rng const>>(n_);
return count < n ? 0 : count - n + 1;
}
CPP_auto_member
auto CPP_fun(size)()(
requires sized_range<Rng>)
{
auto const count = ranges::size(this->base());
auto const n = static_cast<range_size_t<Rng>>(n_);
return count < n ? 0 : count - n + 1;
}
protected:
range_difference_t<Rng> n_;
optional<iterator_t<Rng>> & cache() &
{
return static_cast<cache_t &>(*this);
}
optional<iterator_t<Rng>> const & cache() const &
{
return static_cast<cache_t const &>(*this);
}
private:
using cache_t = detail::non_propagating_cache<iterator_t<Rng>, sv_base<Rng>>;
};
} // namespace sliding_view_detail
/// \endcond
/// \addtogroup group-views
/// @{
template<typename Rng>
struct sliding_view<Rng, sliding_view_detail::cache::first>
: sliding_view_detail::sv_base<Rng>
{
private:
friend range_access;
iterator_t<Rng> get_first()
{
auto & first = this->cache();
if(!first)
{
first = ranges::next(
ranges::begin(this->base()), this->n_ - 1, ranges::end(this->base()));
}
return *first;
}
struct RANGES_EMPTY_BASES adaptor
: adaptor_base
, sliding_view_detail::trailing<Rng>
{
private:
using base_t = sliding_view_detail::trailing<Rng>;
range_difference_t<Rng> n_ = {};
public:
adaptor() = default;
adaptor(sliding_view * v)
: base_t{v->base()}
, n_{v->n_}
{}
iterator_t<Rng> begin(sliding_view & v)
{
return v.get_first();
}
auto read(iterator_t<Rng> const & it) const
-> decltype(views::counted(uncounted(it), n_))
{
return views::counted(base_t::get(it, n_), n_);
}
void next(iterator_t<Rng> & it)
{
++it;
base_t::next();
}
CPP_member
auto prev(iterator_t<Rng> & it) //
-> CPP_ret(void)(
requires bidirectional_range<Rng>)
{
base_t::prev();
--it;
}
CPP_member
auto advance(iterator_t<Rng> & it, range_difference_t<Rng> n)
-> CPP_ret(void)(
requires random_access_range<Rng>)
{
it += n;
}
};
adaptor begin_adaptor()
{
return {this};
}
meta::if_c<common_range<Rng>, adaptor, adaptor_base> end_adaptor()
{
return {this};
}
public:
using sliding_view::sv_base::sv_base;
};
template<typename Rng>
struct sliding_view<Rng, sliding_view_detail::cache::last>
: sliding_view_detail::sv_base<Rng>
{
private:
friend range_access;
iterator_t<Rng> get_last()
{
auto & last = this->cache();
if(!last)
{
last = ranges::prev(
ranges::end(this->base()), this->n_ - 1, ranges::begin(this->base()));
}
return *last;
}
struct adaptor : adaptor_base
{
private:
range_difference_t<Rng> n_ = {};
public:
adaptor() = default;
adaptor(sliding_view * v)
: n_{v->n_}
{}
iterator_t<Rng> end(sliding_view & v)
{
return v.get_last();
}
auto read(iterator_t<Rng> const & it) const
-> decltype(views::counted(uncounted(it), n_))
{
return views::counted(uncounted(it), n_);
}
};
adaptor begin_adaptor()
{
return {this};
}
adaptor end_adaptor()
{
return {this};
}
public:
using sliding_view::sv_base::sv_base;
};
template<typename Rng>
struct sliding_view<Rng, sliding_view_detail::cache::none>
: sliding_view_detail::sv_base<Rng>
{
private:
friend range_access;
template<bool Const>
struct adaptor : adaptor_base
{
private:
friend adaptor<!Const>;
using CRng = meta::const_if_c<Const, Rng>;
range_difference_t<Rng> n_ = 0;
public:
adaptor() = default;
adaptor(range_difference_t<Rng> n)
: n_(n)
{}
template(bool Other)(
requires Const AND CPP_NOT(Other)) //
adaptor(adaptor<Other> that)
: n_(that.n_)
{}
iterator_t<CRng> end(meta::const_if_c<Const, sliding_view> & v) const
{
auto const sz = ranges::distance(v.base());
auto const offset = n_ - 1 < sz ? n_ - 1 : sz;
return ranges::begin(v.base()) + (sz - offset);
}
auto read(iterator_t<CRng> const & it) const
-> decltype(views::counted(uncounted(it), n_))
{
return views::counted(uncounted(it), n_);
}
};
adaptor<simple_view<Rng>()> begin_adaptor()
{
return {this->n_};
}
CPP_member
auto begin_adaptor() const //
-> CPP_ret(adaptor<true>)(
requires range<Rng const>)
{
return {this->n_};
}
adaptor<simple_view<Rng>()> end_adaptor()
{
return {this->n_};
}
CPP_member
auto end_adaptor() const //
-> CPP_ret(adaptor<true>)(
requires range<Rng const>)
{
return {this->n_};
}
public:
using sliding_view::sv_base::sv_base;
};
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<sliding_view<Rng>> = //
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
sliding_view(Rng &&, range_difference_t<Rng>)
-> sliding_view<views::all_t<Rng>>;
#endif
namespace views
{
// In: range<T>
// Out: range<range<T>>, where each inner range has $n$ elements.
struct sliding_base_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND forward_range<Rng>)
constexpr sliding_view<all_t<Rng>> //
operator()(Rng && rng, range_difference_t<Rng> n) const
{
return {all(static_cast<Rng &&>(rng)), n};
}
};
struct sliding_fn : sliding_base_fn
{
using sliding_base_fn::operator();
template<typename Int>
constexpr auto CPP_fun(operator())(Int n)(const //
requires detail::integer_like_<Int>)
{
return make_view_closure(bind_back(sliding_base_fn{}, n));
}
};
/// \relates sliding_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(sliding_fn, sliding)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,426 @@
/// \file
// Range v3 library
//
// Copyright Casey Carter 2016-2017
//
// 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_SPAN_HPP
#define RANGES_V3_VIEW_SPAN_HPP
#include <cstddef>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/algorithm/equal.hpp>
#include <range/v3/algorithm/lexicographical_compare.hpp>
#include <range/v3/iterator/reverse_iterator.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
/// \cond
namespace detail
{
using span_index_t = std::ptrdiff_t;
} // namespace detail
/// \endcond
constexpr detail::span_index_t dynamic_extent = -1;
/// \cond
namespace detail
{
template(typename To, typename From)(
requires integral<To> AND integral<From>)
constexpr To narrow_cast(From from) noexcept
{
using C = common_type_t<To, From>;
return RANGES_EXPECT((from > 0) == (static_cast<To>(from) > 0)),
RANGES_EXPECT(static_cast<C>(from) ==
static_cast<C>(static_cast<To>(from))),
static_cast<To>(from);
}
template<typename T>
constexpr span_index_t byte_size(span_index_t n) noexcept
{
return n == dynamic_extent ? dynamic_extent
: (RANGES_EXPECT(n >= 0),
RANGES_EXPECT(narrow_cast<std::size_t>(n) <=
PTRDIFF_MAX / sizeof(T)),
n * narrow_cast<span_index_t>(sizeof(T)));
}
template<span_index_t N>
struct span_extent
{
CPP_assert(N >= 0);
constexpr span_extent() noexcept = default;
constexpr span_extent(span_index_t size) noexcept
// this constructor does nothing, the delegation exists only
// to provide a place for the contract check expression.
: span_extent{(RANGES_EXPECT(size == N), tag{})}
{}
constexpr span_index_t size() const noexcept
{
return N;
}
private:
struct tag
{};
constexpr span_extent(tag) noexcept
{}
};
template<>
struct span_extent<dynamic_extent>
{
span_extent() = default;
constexpr span_extent(span_index_t size) noexcept
: size_{((void)RANGES_EXPECT(size >= 0), size)}
{}
constexpr span_index_t size() const noexcept
{
return size_;
}
private:
span_index_t size_ = 0;
};
constexpr span_index_t subspan_extent(span_index_t Extent, span_index_t Offset,
span_index_t Count) noexcept
{
return Count == dynamic_extent && Extent != dynamic_extent ? Extent - Offset
: Count;
}
} // namespace detail
// clang-format off
/// \concept span_compatible_range_
/// \brief The \c span_compatible_range_ concept
template(typename Rng, typename T)(
concept (span_compatible_range_)(Rng, T),
detail::is_convertible<detail::element_t<Rng>(*)[], T(*)[]>::value
);
/// \concept span_compatible_range
/// \brief The \c span_compatible_range concept
template<typename Rng, typename T>
CPP_concept span_compatible_range =
sized_range<Rng> && contiguous_range<Rng> &&
CPP_concept_ref(ranges::span_compatible_range_, Rng, T);
/// \concept span_dynamic_conversion
/// \brief The \c span_dynamic_conversion concept
template<typename Rng, detail::span_index_t N>
CPP_concept span_dynamic_conversion =
N == dynamic_extent ||
range_cardinality<Rng>::value < cardinality();
/// \concept span_static_conversion
/// \brief The \c span_static_conversion concept
template<typename Rng, detail::span_index_t N>
CPP_concept span_static_conversion =
N != dynamic_extent && range_cardinality<Rng>::value == N;
// clang-format on
/// \endcond
template<typename T, detail::span_index_t N = dynamic_extent>
struct RANGES_EMPTY_BASES span
: public view_interface<
span<T, N>, (N == dynamic_extent ? finite : static_cast<cardinality>(N))>
, public detail::span_extent<N>
{
CPP_assert(std::is_object<T>::value);
using element_type = T;
using value_type = meta::_t<std::remove_cv<T>>;
using index_type = detail::span_index_t;
using difference_type = index_type;
using pointer = T *;
using reference = T &;
using iterator = T *;
using reverse_iterator = ranges::reverse_iterator<iterator>;
static constexpr index_type extent = N;
constexpr span() noexcept = default;
constexpr span(pointer ptr, index_type cnt) noexcept
: detail::span_extent<N>{(RANGES_EXPECT(cnt >= 0), cnt)}
, data_{(RANGES_EXPECT(0 == cnt || ptr != nullptr), ptr)}
{}
template<typename = void> // Artificially templatize so that the other
// constructor is preferred for {ptr, 0}
constexpr span(pointer first, pointer last) noexcept
: span{first, last - first}
{}
template(typename Rng)(
requires (!same_as<span, uncvref_t<Rng>>) AND
span_compatible_range<Rng, T> AND
span_dynamic_conversion<Rng, N>)
constexpr span(Rng && rng) noexcept(noexcept(ranges::data(rng),
ranges::size(rng)))
: span{ranges::data(rng), detail::narrow_cast<index_type>(ranges::size(rng))}
{}
template(typename Rng)(
requires (!same_as<span, uncvref_t<Rng>>) AND
span_compatible_range<Rng, T> AND
span_static_conversion<Rng, N>)
constexpr span(Rng && rng) noexcept(noexcept(ranges::data(rng)))
: span{ranges::data(rng), N}
{}
template<index_type Count>
constexpr span<T, Count> first() const noexcept
{
static_assert(Count >= 0, "Count of elements to extract cannot be negative.");
static_assert(
N == dynamic_extent || Count <= N,
"Count of elements to extract must be less than the static span extent.");
return RANGES_EXPECT(Count <= size()),
RANGES_EXPECT(Count == 0 || data_ != nullptr),
span<T, Count>{data_, Count};
}
constexpr span<T> first(index_type cnt) const noexcept
{
return RANGES_EXPECT(cnt >= 0 && cnt <= size()),
RANGES_EXPECT(cnt == 0 || data_ != nullptr), span<T>{data_, cnt};
}
template<index_type Count>
constexpr span<T, Count> last() const noexcept
{
static_assert(Count >= 0, "Count of elements to extract cannot be negative.");
static_assert(
N == dynamic_extent || Count <= N,
"Count of elements to extract must be less than the static span extent.");
return RANGES_EXPECT(Count <= size()),
RANGES_EXPECT((Count == 0 && size() == 0) || data_ != nullptr),
span<T, Count>{data_ + size() - Count, Count};
}
constexpr span<T> last(index_type cnt) const noexcept
{
return RANGES_EXPECT(cnt >= 0 && cnt <= size()),
RANGES_EXPECT((cnt == 0 && size() == 0) || data_ != nullptr),
span<T>{data_ + size() - cnt, cnt};
}
template<index_type Offset, index_type Count>
constexpr span<T, detail::subspan_extent(N, Offset, Count)> subspan() const
noexcept
{
static_assert(Offset >= 0,
"Offset of first element to extract cannot be negative.");
static_assert(Count >= dynamic_extent,
"Count of elements to extract cannot be negative.");
static_assert(
N == dynamic_extent ||
N >= Offset + (Count == dynamic_extent ? 0 : Count),
"Sequence of elements to extract must be within the static span extent.");
return RANGES_EXPECT(size() >=
Offset + (Count == dynamic_extent ? 0 : Count)),
RANGES_EXPECT((Offset == 0 && Count <= 0) || data_ != nullptr),
span<T, detail::subspan_extent(N, Offset, Count)>{
data_ + Offset, Count == dynamic_extent ? size() - Offset : Count};
}
template<index_type Offset>
constexpr span<T, (N >= Offset ? N - Offset : dynamic_extent)> subspan() const
noexcept
{
static_assert(Offset >= 0,
"Offset of first element to extract cannot be negative.");
static_assert(N == dynamic_extent || N >= Offset,
"Offset of first element to extract must be within the static "
"span extent.");
return RANGES_EXPECT(size() >= Offset),
RANGES_EXPECT((Offset == 0 && size() == 0) || data_ != nullptr),
span < T,
N >= Offset ? N - Offset
: dynamic_extent > {data_ + Offset, size() - Offset};
}
constexpr span<T, dynamic_extent> subspan(index_type offset) const noexcept
{
return RANGES_EXPECT(offset >= 0), RANGES_EXPECT(size() >= offset),
RANGES_EXPECT((offset == 0 && size() == 0) || data_ != nullptr),
span<T, dynamic_extent>{data_ + offset, size() - offset};
}
constexpr span<T, dynamic_extent> subspan(index_type offset, index_type cnt) const
noexcept
{
return RANGES_EXPECT(offset >= 0), RANGES_EXPECT(cnt >= 0),
RANGES_EXPECT(size() >= offset + cnt),
RANGES_EXPECT((offset == 0 && cnt == 0) || data_ != nullptr),
span<T, dynamic_extent>{data_ + offset, cnt};
}
constexpr pointer data() const noexcept
{
return data_;
}
using detail::span_extent<N>::size;
constexpr index_type size_bytes() const noexcept
{
return detail::byte_size<T>(size());
}
constexpr bool empty() const noexcept
{
return size() == 0;
}
constexpr reference operator[](index_type idx) const noexcept
{
return RANGES_EXPECT(idx >= 0), RANGES_EXPECT(idx < size()),
RANGES_EXPECT(data_), data_[idx];
}
constexpr iterator begin() const noexcept
{
return RANGES_EXPECT(!size() || data_), data_;
}
constexpr iterator end() const noexcept
{
return RANGES_EXPECT(!size() || data_), data_ + size();
}
constexpr reverse_iterator rbegin() const noexcept
{
return reverse_iterator{end()};
}
constexpr reverse_iterator rend() const noexcept
{
return reverse_iterator{begin()};
}
template(typename U, index_type M)(
requires equality_comparable_with<T, U>)
bool operator==(span<U, M> const & that) const
{
RANGES_EXPECT(!size() || data());
RANGES_EXPECT(!that.size() || that.data());
return ranges::equal(*this, that);
}
template(typename U, index_type M)(
requires equality_comparable_with<T, U>)
bool operator!=(span<U, M> const & that) const
{
return !(*this == that);
}
template(typename U, index_type M)(
requires totally_ordered_with<T, U>)
bool operator<(span<U, M> const & that) const
{
RANGES_EXPECT(!size() || data());
RANGES_EXPECT(!that.size() || that.data());
return ranges::lexicographical_compare(*this, that);
}
template(typename U, index_type M)(
requires totally_ordered_with<T, U>)
bool operator>(span<U, M> const & that) const
{
return that < *this;
}
template(typename U, index_type M)(
requires totally_ordered_with<T, U>)
bool operator<=(span<U, M> const & that) const
{
return !(that < *this);
}
template(typename U, index_type M)(
requires totally_ordered_with<T, U>)
bool operator>=(span<U, M> const & that) const
{
return !(*this < that);
}
private:
T * data_ = nullptr;
};
template<typename T, detail::span_index_t N>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<span<T, N>> = true;
template<typename T, detail::span_index_t N>
constexpr detail::span_index_t span<T, N>::extent;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng)(
requires contiguous_range<Rng>)
span(Rng && rng)
->span<detail::element_t<Rng>, (range_cardinality<Rng>::value < cardinality()
? dynamic_extent
: static_cast<detail::span_index_t>(
range_cardinality<Rng>::value))>;
#endif
template<typename T, detail::span_index_t N>
span<unsigned char const, detail::byte_size<T>(N)> as_bytes(span<T, N> s) noexcept
{
return {reinterpret_cast<unsigned char const *>(s.data()), s.size_bytes()};
}
template<typename T, detail::span_index_t N>
span<unsigned char, detail::byte_size<T>(N)> as_writeable_bytes(span<T, N> s) noexcept
{
return {reinterpret_cast<unsigned char *>(s.data()), s.size_bytes()};
}
template<typename ElementType>
constexpr span<ElementType> make_span(ElementType * ptr,
detail::span_index_t cnt) noexcept
{
return span<ElementType>{ptr, cnt};
}
template<typename ElementType>
constexpr span<ElementType> make_span(ElementType * first,
ElementType * last) noexcept
{
return span<ElementType>{first, last};
}
template(typename Rng)(
requires contiguous_range<Rng> AND
(range_cardinality<Rng>::value < cardinality())) //
constexpr span<detail::element_t<Rng>> make_span(Rng && rng) noexcept(
noexcept(ranges::data(rng), ranges::size(rng)))
{
return {ranges::data(rng),
detail::narrow_cast<detail::span_index_t>(ranges::size(rng))};
}
template(typename Rng)(
requires contiguous_range<Rng> AND
(range_cardinality<Rng>::value >= cardinality())) //
constexpr span<
detail::element_t<Rng>,
static_cast<detail::span_index_t>(
range_cardinality<Rng>::
value)> make_span(Rng && rng) noexcept(noexcept(ranges::data(rng)))
{
return {ranges::data(rng), range_cardinality<Rng>::value};
}
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_VIEW_SPAN_HPP

View File

@@ -0,0 +1,706 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_SPLIT_HPP
#define RANGES_V3_VIEW_SPLIT_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/algorithm/mismatch.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/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/view/single.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
/// \cond
namespace detail
{
// clang-format off
#if defined(_MSC_VER) && !defined(__clang__) && \
RANGES_CXX_VER <= RANGES_CXX_STD_17
template<typename R, std::size_t Sz = static_cast<std::size_t>(R::size())>
constexpr bool _is_tiny_range_(R const *) noexcept
{
return R::size() <= 1u;
}
constexpr bool _is_tiny_range_(void const*) noexcept
{
return false;
}
/// \concept tiny_range
/// \brief The \c tiny_range concept
template<typename R>
CPP_concept tiny_range =
sized_range<R> &&
detail::_is_tiny_range_(static_cast<std::add_pointer_t<R>>(nullptr));
#else // ^^^^ workaround / no workaround vvvv
/// \concept tiny_range_
/// \brief The \c tiny_range_ concept
template(typename R)(
concept (tiny_range_)(R),
ranges::type<
std::integral_constant<decltype(R::size()), R::size()>> AND
(R::size() <= 1)
);
/// \concept tiny_range
/// \brief The \c tiny_range concept
template<typename R>
CPP_concept tiny_range =
sized_range<R> &&
CPP_concept_ref(detail::tiny_range_, std::remove_reference_t<R>);
#endif
// clang-format on
} // namespace detail
template<typename V, typename Pattern>
#if CPP_CXX_CONCEPTS
requires input_range<V> && forward_range<Pattern> && view_<V> && view_<
Pattern> && indirectly_comparable<iterator_t<V>, iterator_t<Pattern>,
ranges::equal_to> &&
(forward_range<V> || detail::tiny_range<Pattern>)
#endif
struct split_view;
namespace detail
{
struct there
{
template<typename T>
static decltype(auto) current_(T & t) noexcept
{
return (t.curr_);
}
};
template<typename It>
struct here
{
It curr_ = It();
It & current_(ignore_t) noexcept
{
return curr_;
}
It const & current_(ignore_t) const noexcept
{
return curr_;
}
};
template<bool>
struct here_or_there_
{
template<typename>
using invoke = there;
};
template<>
struct here_or_there_<true>
{
template<typename It>
using invoke = here<It>;
};
template<typename It>
using split_view_base = meta::invoke<here_or_there_<!forward_iterator<It>>, It>;
template<typename JoinView, bool Const>
struct split_outer_iterator;
template<typename JoinView, bool Const>
struct split_inner_iterator;
template<typename V, typename Pattern, bool Const>
struct split_inner_iterator<split_view<V, Pattern>, Const>
{
private:
using Outer = split_outer_iterator<split_view<V, Pattern>, Const>;
using Base = meta::const_if_c<Const, V>;
using BaseIterCategory =
typename std::iterator_traits<iterator_t<Base>>::iterator_category;
Outer i_ = Outer();
bool incremented_ = false;
constexpr decltype(auto) current_() noexcept
{
return i_.current_();
}
constexpr decltype(auto) current_() const noexcept
{
return i_.current_();
}
constexpr bool done_() const
{
auto cur = current_();
auto last = ranges::end(i_.parent_->base_);
if(cur == last)
return true;
auto pcur = ranges::begin(i_.parent_->pattern_);
auto pend = ranges::end(i_.parent_->pattern_);
if(pcur == pend)
return incremented_;
do
{
if(*cur != *pcur)
return false;
if(++pcur == pend)
return true;
} while(++cur != last);
return false;
}
#if RANGES_CXX_IF_CONSTEXPR < RANGES_CXX_IF_CONSTEXPR_17
constexpr void pre_inc(std::true_type) // Forward
{
++current_();
}
constexpr void pre_inc(std::false_type) // Input
{
if(Pattern::size() != 0)
++current_();
}
constexpr split_inner_iterator post_inc(std::true_type) // Forward
{
auto tmp = *this;
pre_inc(std::true_type{});
return tmp;
}
constexpr void post_inc(std::false_type) // Input
{
pre_inc(std::false_type{});
}
#endif
public:
using iterator_concept = typename Outer::iterator_concept;
using iterator_category =
meta::conditional_t<
derived_from<BaseIterCategory, std::forward_iterator_tag>,
std::forward_iterator_tag,
std::input_iterator_tag>;
using value_type = range_value_t<Base>;
using difference_type = range_difference_t<Base>;
using reference = range_reference_t<Base>; // Not to spec
using pointer = iter_pointer_t<iterator_t<Base>>; // Not to spec
split_inner_iterator() = default;
constexpr explicit split_inner_iterator(Outer i)
: i_(std::move(i))
{}
constexpr decltype(auto) operator*() const
{
return *current_();
}
constexpr split_inner_iterator & operator++()
{
incremented_ = true;
#if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
if constexpr(!forward_range<Base>)
if constexpr(Pattern::size() == 0)
return *this;
++current_();
#else
pre_inc(meta::bool_<forward_range<Base>>{});
#endif
return *this;
}
constexpr decltype(auto) operator++(int)
{
#if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
if constexpr(forward_range<V>)
{
auto tmp = *this;
++*this;
return tmp;
}
else
++*this;
#else
return post_inc(meta::bool_<forward_range<V>>{});
#endif
}
CPP_broken_friend_member
friend constexpr auto operator==(split_inner_iterator const & x,
split_inner_iterator const & y)
-> CPP_broken_friend_ret(bool)(
requires forward_range<Base>)
{
return x.i_.curr_ == y.i_.curr_;
}
CPP_broken_friend_member
friend constexpr auto operator!=(split_inner_iterator const & x,
split_inner_iterator const & y)
-> CPP_broken_friend_ret(bool)(
requires forward_range<Base>)
{
return x.i_.curr_ != y.i_.curr_;
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#endif // RANGES_WORKAROUND_MSVC_756601
friend constexpr bool operator==(split_inner_iterator const & x,
default_sentinel_t)
{
return x.done_();
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#endif // RANGES_WORKAROUND_MSVC_756601
friend constexpr bool operator==(default_sentinel_t,
split_inner_iterator const & x)
{
return x.done_();
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#endif // RANGES_WORKAROUND_MSVC_756601
friend constexpr bool operator!=(split_inner_iterator const & x,
default_sentinel_t)
{
return !x.done_();
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#endif // RANGES_WORKAROUND_MSVC_756601
friend constexpr bool operator!=(default_sentinel_t,
split_inner_iterator const & x)
{
return !x.done_();
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#endif // RANGES_WORKAROUND_MSVC_756601
friend constexpr decltype(auto) iter_move(
split_inner_iterator const &
i) noexcept(noexcept(ranges::iter_move(i.current_())))
{
return ranges::iter_move(i.current_());
}
CPP_broken_friend_member
friend constexpr auto iter_swap(
split_inner_iterator const & x,
split_inner_iterator const &
y) noexcept(noexcept(ranges::iter_swap(x.current_(), y.current_())))
-> CPP_broken_friend_ret(void)(
requires indirectly_swappable<iterator_t<Base>>)
{
ranges::iter_swap(x.current_(), y.current_());
}
};
template<typename It>
using split_outer_iterator_base =
meta::invoke<here_or_there_<forward_iterator<It>>, It>;
template<typename JoinView, bool Const>
struct split_outer_iterator;
template<typename V, typename Pattern, bool Const>
struct split_outer_iterator<split_view<V, Pattern>, Const>
: split_outer_iterator_base<iterator_t<meta::const_if_c<Const, V>>>
{
private:
friend struct split_inner_iterator<split_view<V, Pattern>, Const>;
using Parent = meta::const_if_c<Const, split_view<V, Pattern>>;
using Base = meta::const_if_c<Const, V>;
using Current = split_outer_iterator_base<iterator_t<Base>>;
Parent * parent_ = nullptr;
constexpr decltype(auto) current_() noexcept
{
return parent_->current_(*this);
}
constexpr decltype(auto) current_() const noexcept
{
return parent_->current_(*this);
}
constexpr decltype(auto) base_() const noexcept
{
return (parent_->base_);
}
#if RANGES_CXX_IF_CONSTEXPR < RANGES_CXX_IF_CONSTEXPR_17
constexpr split_outer_iterator post_inc(std::true_type) // Forward
{
auto tmp = *this;
++*this;
return tmp;
}
constexpr void post_inc(std::false_type) // Input
{
++*this;
}
#endif
public:
using iterator_concept =
meta::conditional_t<forward_range<Base>, std::forward_iterator_tag,
std::input_iterator_tag>;
using iterator_category = std::input_iterator_tag;
struct value_type : view_interface<value_type>
{
private:
split_outer_iterator i_ = split_outer_iterator();
public:
value_type() = default;
constexpr explicit value_type(split_outer_iterator i)
: i_(std::move(i))
{}
constexpr split_inner_iterator<split_view<V, Pattern>, Const> begin()
const
{
return split_inner_iterator<split_view<V, Pattern>, Const>(i_);
}
constexpr default_sentinel_t end() const
{
return default_sentinel;
}
};
using difference_type = range_difference_t<Base>;
using reference = value_type; // Not to spec
using pointer = value_type *; // Not to spec
split_outer_iterator() = default;
CPP_member
constexpr explicit CPP_ctor(split_outer_iterator)(Parent * parent)(
requires (!forward_range<Base>))
: parent_(parent)
{}
CPP_member
constexpr CPP_ctor(split_outer_iterator)(Parent * parent,
iterator_t<Base> current)(
requires forward_range<Base>)
: Current{std::move(current)}
, parent_(parent)
{}
template(bool Other)(
requires Const AND CPP_NOT(Other) AND
convertible_to<iterator_t<V>, iterator_t<Base>>)
constexpr split_outer_iterator(
split_outer_iterator<split_view<V, Pattern>, Other> i)
: Current{std::move(i.curr_)}
, parent_(i.parent_)
{}
constexpr value_type operator*() const
{
return value_type{*this};
}
constexpr split_outer_iterator & operator++()
{
auto & current = current_();
const auto last = ranges::end(base_());
if(current == last)
return *this;
auto const pbegin = ranges::begin(parent_->pattern_);
auto const pend = ranges::end(parent_->pattern_);
if(pbegin == pend)
++current;
else
do
{
const auto ret = ranges::mismatch(current, last, pbegin, pend);
if(ret.in2 == pend)
{
current = ret.in1; // The pattern matched; skip it
break;
}
} while(++current != last);
return *this;
}
constexpr decltype(auto) operator++(int)
{
#if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
if constexpr(forward_range<Base>)
{
auto tmp = *this;
++*this;
return tmp;
}
else
++*this;
#else
return post_inc(meta::bool_<forward_range<Base>>{});
#endif
}
CPP_broken_friend_member
friend constexpr auto operator==(split_outer_iterator const & x,
split_outer_iterator const & y)
-> CPP_broken_friend_ret(bool)(
requires forward_range<Base>)
{
return x.curr_ == y.curr_;
}
CPP_broken_friend_member
friend constexpr auto operator!=(split_outer_iterator const & x,
split_outer_iterator const & y)
-> CPP_broken_friend_ret(bool)(
requires forward_range<Base>)
{
return x.curr_ != y.curr_;
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#endif // RANGES_WORKAROUND_MSVC_756601
friend constexpr bool operator==(split_outer_iterator const & x,
default_sentinel_t)
{
return x.current_() == ranges::end(x.base_());
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#endif // RANGES_WORKAROUND_MSVC_756601
friend constexpr bool operator==(default_sentinel_t,
split_outer_iterator const & x)
{
return x.current_() == ranges::end(x.base_());
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#endif // RANGES_WORKAROUND_MSVC_756601
friend constexpr bool operator!=(split_outer_iterator const & x,
default_sentinel_t)
{
return x.current_() != ranges::end(x.base_());
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#endif // RANGES_WORKAROUND_MSVC_756601
friend constexpr bool operator!=(default_sentinel_t,
split_outer_iterator const & x)
{
return x.current_() != ranges::end(x.base_());
}
};
} // namespace detail
/// \endcond
template<typename V, typename Pattern>
#if CPP_CXX_CONCEPTS
requires input_range<V> && forward_range<Pattern> && view_<V> && view_<
Pattern> && indirectly_comparable<iterator_t<V>, iterator_t<Pattern>,
ranges::equal_to> &&
(forward_range<V> || detail::tiny_range<Pattern>)
#endif
struct RANGES_EMPTY_BASES split_view
: view_interface<split_view<V, Pattern>, is_finite<V>::value ? finite : unknown>
, private detail::split_view_base<iterator_t<V>>
{
private:
template<typename, bool>
friend struct detail::split_outer_iterator;
template<typename, bool>
friend struct detail::split_inner_iterator;
V base_ = V();
Pattern pattern_ = Pattern();
template<bool Const>
using outer_iterator = detail::split_outer_iterator<split_view, Const>;
#if RANGES_CXX_IF_CONSTEXPR < RANGES_CXX_IF_CONSTEXPR_17
outer_iterator<simple_view<V>()> begin_(std::true_type)
{
return outer_iterator<simple_view<V>()>{this, ranges::begin(base_)};
}
outer_iterator<false> begin_(std::false_type)
{
this->curr_ = ranges::begin(base_);
return outer_iterator<false>{this};
}
outer_iterator<simple_view<V>()> end_(std::true_type) const
{
return outer_iterator<true>{this, ranges::end(base_)};
}
default_sentinel_t end_(std::false_type) const
{
return default_sentinel;
}
#endif
public:
split_view() = default;
constexpr split_view(V base, Pattern pattern)
: base_((V &&) base)
, pattern_((Pattern &&) pattern)
{}
CPP_member
constexpr CPP_ctor(split_view)(V base, range_value_t<V> e)(
requires constructible_from<Pattern, range_value_t<V>>)
: base_(std::move(base))
, pattern_(e)
{}
constexpr V base() const
{
return base_;
}
constexpr outer_iterator<forward_range<V> && simple_view<V>()> begin()
{
#if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
if constexpr(forward_range<V>)
return outer_iterator<simple_view<V>()>{this, ranges::begin(base_)};
else
{
this->curr_ = ranges::begin(base_);
return outer_iterator<false>{this};
}
#else
return begin_(meta::bool_<forward_range<V>>{});
#endif
}
CPP_member
constexpr auto begin() const //
-> CPP_ret(outer_iterator<true>)(
requires forward_range<V> && forward_range<const V>)
{
return {this, ranges::begin(base_)};
}
CPP_member
constexpr auto end() //
-> CPP_ret(outer_iterator<simple_view<V>()>)(
requires forward_range<V> && common_range<V>)
{
return outer_iterator<simple_view<V>()>{this, ranges::end(base_)};
}
constexpr auto end() const
{
#if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
if constexpr(forward_range<V> && forward_range<const V> &&
common_range<const V>)
return outer_iterator<true>{this, ranges::end(base_)};
else
return default_sentinel;
#else
return end_(meta::bool_ < forward_range<V> && forward_range<const V> &&
common_range<const V> > {});
#endif
}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename R, typename P)(
requires input_range<R> AND forward_range<P> AND viewable_range<R> AND
viewable_range<P> AND
indirectly_comparable<iterator_t<R>, iterator_t<P>, ranges::equal_to> AND
(forward_range<R> || detail::tiny_range<P>)) //
split_view(R &&, P &&)
->split_view<views::all_t<R>, views::all_t<P>>;
template(typename R)(
requires input_range<R>)
split_view(R &&, range_value_t<R>)
->split_view<views::all_t<R>, single_view<range_value_t<R>>>;
#endif
namespace views
{
struct split_base_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng> AND
indirectly_comparable<iterator_t<Rng>,
range_value_t<Rng> const *,
ranges::equal_to>)
constexpr split_view<all_t<Rng>, single_view<range_value_t<Rng>>> //
operator()(Rng && rng, range_value_t<Rng> val) const
{
return {all(static_cast<Rng &&>(rng)), single(std::move(val))};
}
template(typename Rng, typename Pattern)(
requires viewable_range<Rng> AND input_range<Rng> AND
viewable_range<Pattern> AND forward_range<Pattern> AND
indirectly_comparable<
iterator_t<Rng>,
iterator_t<Pattern>,
ranges::equal_to> AND
(forward_range<Rng> || detail::tiny_range<Pattern>)) //
constexpr split_view<all_t<Rng>, all_t<Pattern>> //
operator()(Rng && rng, Pattern && pattern) const
{
return {all((Rng &&) rng), all((Pattern &&) pattern)};
}
};
struct split_fn : split_base_fn
{
using split_base_fn::operator();
template<typename T>
constexpr auto operator()(T t) const
{
return make_view_closure(bind_back(split_base_fn{}, std::move(t)));
}
};
/// \relates split_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(split_fn, split)
} // namespace views
namespace cpp20
{
namespace views
{
using ranges::views::split;
}
template(typename Rng, typename Pattern)(
requires input_range<Rng> AND forward_range<Pattern> AND view_<Rng> AND
view_<Pattern> AND
indirectly_comparable<
iterator_t<Rng>,
iterator_t<Pattern>,
ranges::equal_to> AND
(forward_range<Rng> || ranges::detail::tiny_range<Pattern>)) //
using split_view =
ranges::split_view<Rng, Pattern>;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::split_view)
#endif

View File

@@ -0,0 +1,230 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_SPLIT_WHEN_HPP
#define RANGES_V3_VIEW_SPLIT_WHEN_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/algorithm/find_if_not.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/view/indirect.hpp>
#include <range/v3/view/iota.hpp>
#include <range/v3/view/take_while.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng, typename Fun>
struct split_when_view
: view_facade<split_when_view<Rng, Fun>,
is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
{
private:
friend range_access;
Rng rng_;
semiregular_box_t<Fun> fun_;
template<bool IsConst>
struct cursor
{
private:
friend range_access;
friend split_when_view;
friend struct cursor<!IsConst>;
bool zero_;
using CRng = meta::const_if_c<IsConst, Rng>;
iterator_t<CRng> cur_;
sentinel_t<CRng> last_;
using fun_ref_t = semiregular_box_ref_or_val_t<Fun, IsConst>;
fun_ref_t fun_;
struct search_pred
{
bool zero_;
iterator_t<CRng> first_;
sentinel_t<CRng> last_;
fun_ref_t fun_;
bool operator()(iterator_t<CRng> cur) const
{
return (zero_ && cur == first_) ||
(cur != last_ && !invoke(fun_, cur, last_).first);
}
};
using reference_ =
indirect_view<take_while_view<iota_view<iterator_t<CRng>>, search_pred>>;
reference_ read() const
{
return reference_{{views::iota(cur_), {zero_, cur_, last_, fun_}}};
}
void next()
{
RANGES_EXPECT(cur_ != last_);
// If the last match consumed zero elements, bump the position.
if(zero_)
{
zero_ = false;
++cur_;
}
for(; cur_ != last_; ++cur_)
{
auto p = invoke(fun_, cur_, last_);
if(p.first)
{
zero_ = (cur_ == p.second);
cur_ = p.second;
return;
}
}
}
bool equal(default_sentinel_t) const
{
return cur_ == last_;
}
bool equal(cursor const & that) const
{
return cur_ == that.cur_;
}
cursor(fun_ref_t fun, iterator_t<CRng> first, sentinel_t<CRng> last)
: cur_(first)
, last_(last)
, fun_(fun)
{
// For skipping an initial zero-length match
auto p = invoke(fun, first, last);
zero_ = p.first && first == p.second;
}
public:
cursor() = default;
template(bool Other)(
requires IsConst AND CPP_NOT(Other)) //
cursor(cursor<Other> that)
: cursor{std::move(that.cur_), std::move(that.last_), std::move(that.fun_)}
{}
};
cursor<false> begin_cursor()
{
return {fun_, ranges::begin(rng_), ranges::end(rng_)};
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng>> AND
invocable<Fun const &, iterator_t<meta::const_if_c<Const, Rng>>,
sentinel_t<meta::const_if_c<Const, Rng>>>)
cursor<Const> begin_cursor() const
{
return {fun_, ranges::begin(rng_), ranges::end(rng_)};
}
public:
split_when_view() = default;
split_when_view(Rng rng, Fun fun)
: rng_(std::move(rng))
, fun_(std::move(fun))
{}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename Fun)(
requires copy_constructible<Fun>)
split_when_view(Rng &&, Fun)
-> split_when_view<views::all_t<Rng>, Fun>;
#endif
namespace views
{
struct split_when_base_fn
{
private:
template<typename Pred>
struct predicate_pred_
{
semiregular_box_t<Pred> pred_;
template(typename I, typename S)(
requires sentinel_for<S, I>)
std::pair<bool, I> operator()(I cur, S last) const
{
auto where = ranges::find_if_not(cur, last, std::ref(pred_));
return {cur != where, where};
}
};
public:
template(typename Rng, typename Fun)(
requires viewable_range<Rng> AND forward_range<Rng> AND
invocable<Fun &, iterator_t<Rng>, sentinel_t<Rng>> AND
invocable<Fun &, iterator_t<Rng>, iterator_t<Rng>> AND
copy_constructible<Fun> AND
convertible_to<
invoke_result_t<Fun &, iterator_t<Rng>, sentinel_t<Rng>>,
std::pair<bool, iterator_t<Rng>>>)
split_when_view<all_t<Rng>, Fun> operator()(Rng && rng, Fun fun) const //
{
return {all(static_cast<Rng &&>(rng)), std::move(fun)};
}
template(typename Rng, typename Fun)(
requires viewable_range<Rng> AND forward_range<Rng> AND
predicate<Fun const &, range_reference_t<Rng>> AND
copy_constructible<Fun>)
split_when_view<all_t<Rng>, predicate_pred_<Fun>> //
operator()(Rng && rng, Fun fun) const
{
return {all(static_cast<Rng &&>(rng)),
predicate_pred_<Fun>{std::move(fun)}};
}
};
struct split_when_fn : split_when_base_fn
{
using split_when_base_fn::operator();
template<typename T>
constexpr auto operator()(T && t) const
{
return make_view_closure(
bind_back(split_when_base_fn{}, static_cast<T &&>(t)));
}
};
/// \relates split_when_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(split_when_fn, split_when)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::split_when_view)
#endif

View File

@@ -0,0 +1,341 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-present
// Copyright Casey Carter 2017
//
// 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_STRIDE_HPP
#define RANGES_V3_VIEW_STRIDE_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/operations.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
template<typename Rng>
struct stride_view;
namespace detail
{
template<typename Rng>
using stride_view_adaptor =
view_adaptor<stride_view<Rng>, Rng,
is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>;
// Bidirectional stride views need to remember the distance between
// the penultimate iterator and the last iterator - which may be less
// than the stride - so that decrementing an last iterator properly
// produces the penultimate iterator. stride_view_base specializes on
// that distinction so that only Bidirectional stride views have the
// data member "offset_".
template<typename Rng, bool BidiRange>
struct stride_view_base_;
template<typename Rng>
using stride_view_base = stride_view_base_<Rng, (bool)bidirectional_range<Rng>>;
template<typename Rng, bool /*= bidirectional_range<Rng>*/>
struct stride_view_base_ : stride_view_adaptor<Rng>
{
stride_view_base_() = default;
constexpr stride_view_base_(Rng && rng, range_difference_t<Rng> const stride)
: stride_view_adaptor<Rng>{std::move(rng)}
, stride_{(RANGES_EXPECT(0 < stride), stride)}
, offset_{calc_offset(meta::bool_<sized_range<Rng>>{})}
{}
protected:
constexpr void set_offset(range_difference_t<Rng> const delta) noexcept
{
RANGES_EXPECT(0 <= delta && delta < stride_);
if(0 > offset_)
offset_ = delta;
else
RANGES_EXPECT(offset_ == delta);
}
constexpr void set_offset(range_difference_t<Rng> const) const noexcept
{}
constexpr range_difference_t<Rng> get_offset(bool check = true) const noexcept
{
RANGES_EXPECT(!check || 0 <= offset_);
return offset_;
}
range_difference_t<Rng> stride_;
range_difference_t<Rng> offset_ = -1;
private:
constexpr range_difference_t<Rng> calc_offset(std::true_type)
{
if(auto const rem = ranges::distance(this->base()) % stride_)
return stride_ - rem;
else
return 0;
}
constexpr range_difference_t<Rng> calc_offset(std::false_type) const noexcept
{
return -1;
}
};
template<typename Rng>
struct stride_view_base_<Rng, false> : stride_view_adaptor<Rng>
{
stride_view_base_() = default;
constexpr stride_view_base_(Rng && rng, range_difference_t<Rng> const stride)
: stride_view_adaptor<Rng>{std::move(rng)}
, stride_{(RANGES_EXPECT(0 < stride), stride)}
{}
protected:
constexpr void set_offset(range_difference_t<Rng> const) const noexcept
{}
constexpr range_difference_t<Rng> get_offset(bool = true) const noexcept
{
return 0;
}
range_difference_t<Rng> stride_;
};
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
template<typename Rng>
struct stride_view : detail::stride_view_base<Rng>
{
private:
friend range_access;
// stride_view const models Range if Rng const models Range, and
// either (1) Rng is sized, so we can pre-calculate offset_, or (2)
// Rng is !Bidirectional, so it does not need offset_.
static constexpr bool const_iterable() noexcept
{
return range<Rng const> &&
(sized_range<Rng const> || !bidirectional_range<Rng const>);
}
// If the underlying range doesn't model common_range, then we can't
// decrement the last and there's no reason to adapt the sentinel. Strictly
// speaking, we don't have to adapt the last iterator of input and forward
// ranges, but in the interests of making the resulting stride view model
// common_range, adapt it anyway.
template<bool Const>
static constexpr bool can_bound() noexcept
{
using CRng = meta::const_if_c<Const, Rng>;
return common_range<CRng> &&
(sized_range<CRng> || !bidirectional_range<CRng>);
}
template<bool Const>
struct adaptor : adaptor_base
{
private:
friend struct adaptor<!Const>;
using CRng = meta::const_if_c<Const, Rng>;
using stride_view_t = meta::const_if_c<Const, stride_view>;
stride_view_t * rng_;
public:
adaptor() = default;
constexpr adaptor(stride_view_t * rng) noexcept
: rng_(rng)
{}
template(bool Other)(
requires Const AND CPP_NOT(Other)) //
adaptor(adaptor<Other> that)
: rng_(that.rng_)
{}
constexpr void next(iterator_t<CRng> & it)
{
auto const last = ranges::end(rng_->base());
RANGES_EXPECT(it != last);
auto const delta = ranges::advance(it, rng_->stride_, last);
if(it == last)
{
rng_->set_offset(delta);
}
}
CPP_member
constexpr auto prev(iterator_t<CRng> & it) //
-> CPP_ret(void)(
requires bidirectional_range<CRng>)
{
RANGES_EXPECT(it != ranges::begin(rng_->base()));
auto delta = -rng_->stride_;
if(it == ranges::end(rng_->base()))
{
RANGES_EXPECT(rng_->get_offset() >= 0);
delta += rng_->get_offset();
}
ranges::advance(it, delta);
}
template(typename Other)(
requires sized_sentinel_for<Other, iterator_t<CRng>>)
constexpr range_difference_t<Rng> distance_to(iterator_t<CRng> const & here,
Other const & there) const
{
range_difference_t<Rng> delta = there - here;
if(delta < 0)
delta -= rng_->stride_ - 1;
else
delta += rng_->stride_ - 1;
return delta / rng_->stride_;
}
CPP_member
constexpr auto advance(iterator_t<CRng> & it, range_difference_t<Rng> n) //
-> CPP_ret(void)(
requires random_access_range<CRng>)
{
if(0 == n)
return;
n *= rng_->stride_;
auto const last = ranges::end(rng_->base());
if(it == last)
{
RANGES_EXPECT(n < 0);
RANGES_EXPECT(rng_->get_offset() >= 0);
n += rng_->get_offset();
}
if(0 < n)
{
auto delta = ranges::advance(it, n, last);
if(it == last)
{
// advance hit the last of the base range.
rng_->set_offset(delta % rng_->stride_);
}
}
else if(0 > n)
{
#ifdef NDEBUG
ranges::advance(it, n);
#else
auto const first = ranges::begin(rng_->base());
auto const delta = ranges::advance(it, n, first);
RANGES_EXPECT(delta == 0);
#endif
}
}
};
constexpr adaptor<false> begin_adaptor() noexcept
{
return adaptor<false>{this};
}
CPP_member
constexpr auto begin_adaptor() const noexcept
-> CPP_ret(adaptor<true>)(
requires(const_iterable()))
{
return adaptor<true>{this};
}
constexpr meta::if_c<can_bound<false>(), adaptor<false>, adaptor_base> //
end_adaptor() noexcept
{
return {this};
}
CPP_member
constexpr auto end_adaptor() const noexcept //
-> CPP_ret(meta::if_c<can_bound<true>(), adaptor<true>, adaptor_base>)(
requires (const_iterable()))
{
return {this};
}
public:
stride_view() = default;
constexpr stride_view(Rng rng, range_difference_t<Rng> const stride)
: detail::stride_view_base<Rng>{std::move(rng), stride}
{}
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires sized_range<Rng>)
{
using size_type = range_size_t<Rng>;
auto const n = ranges::size(this->base());
return (n + static_cast<size_type>(this->stride_) - 1) /
static_cast<size_type>(this->stride_);
}
CPP_auto_member
constexpr auto CPP_fun(size)()(const //
requires sized_range<Rng const>)
{
using size_type = range_size_t<Rng const>;
auto const n = ranges::size(this->base());
return (n + static_cast<size_type>(this->stride_) - 1) /
static_cast<size_type>(this->stride_);
}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
stride_view(Rng &&, range_difference_t<Rng>)
-> stride_view<views::all_t<Rng>>;
#endif
namespace views
{
struct stride_base_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng>)
constexpr stride_view<all_t<Rng>> //
operator()(Rng && rng, range_difference_t<Rng> step) const
{
return stride_view<all_t<Rng>>{all(static_cast<Rng &&>(rng)), step};
}
};
struct stride_fn : stride_base_fn
{
using stride_base_fn::operator();
template(typename Difference)(
requires detail::integer_like_<Difference>)
constexpr auto operator()(Difference step) const
{
return make_view_closure(bind_back(stride_base_fn{}, step));
}
};
/// \relates stride_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(stride_fn, stride)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::stride_view)
#endif

View File

@@ -0,0 +1,485 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-present
// Copyright Casey Carter 2017
//
// 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_SUBRANGE_HPP
#define RANGES_V3_VIEW_SUBRANGE_HPP
#include <tuple>
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/iterator/unreachable_sentinel.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/dangling.hpp>
#include <range/v3/utility/get.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
enum class subrange_kind : bool
{
unsized,
sized
};
/// \cond
namespace detail
{
// clang-format off
/// \concept convertible_to_not_slicing_
/// \brief The \c convertible_to_not_slicing_ concept
template<typename From, typename To>
CPP_concept convertible_to_not_slicing_ =
convertible_to<From, To> &&
// A conversion is a slicing conversion if the source and the destination
// are both pointers, and if the pointed-to types differ after removing
// cv qualifiers.
(!(std::is_pointer<decay_t<From>>::value &&
std::is_pointer<decay_t<To>>::value &&
not_same_as_<std::remove_pointer_t<decay_t<From>>,
std::remove_pointer_t<decay_t<To>>>));
template<std::size_t N, typename T>
using tuple_element_fun_t = void (*)(meta::_t<std::tuple_element<N, T>> const &);
/// \concept pair_like_impl_
/// \brief The \c pair_like_impl_ concept
template<typename T>
CPP_requires(pair_like_impl_, //
requires(T t, tuple_element_fun_t<0, T> p0, tuple_element_fun_t<1, T> p1) //
(
p0( get<0>(t) ),
p1( get<1>(t) )
));
/// \concept pair_like_impl_
/// \brief The \c pair_like_impl_ concept
template<typename T>
CPP_concept pair_like_impl_ = CPP_requires_ref(detail::pair_like_impl_, T);
/// \concept is_complete_
/// \brief The \c is_complete_ concept
template(typename T)(
concept (is_complete_)(T),
0 != sizeof(T));
/// \concept is_complete_
/// \brief The \c is_complete_ concept
template<typename T>
CPP_concept is_complete_ = //
CPP_concept_ref(is_complete_, T);
template(typename T)( //
concept (pair_like_)(T), //
is_complete_<std::tuple_size<T>> AND
derived_from<std::tuple_size<T>, meta::size_t<2>> AND
detail::pair_like_impl_<T>);
/// \concept pair_like
/// \brief The \c pair_like concept
template<typename T>
CPP_concept pair_like = //
CPP_concept_ref(detail::pair_like_, T);
// clang-format off
template(typename T, typename U, typename V)( //
concept (pair_like_convertible_from_helper_)(T, U, V), //
convertible_to_not_slicing_<U, meta::_t<std::tuple_element<0, T>>> AND
convertible_to<V, meta::_t<std::tuple_element<1, T>>>);
/// \concept pair_like_convertible_from_helper_
/// \brief The \c pair_like_convertible_from_helper_ concept
template<typename T, typename U, typename V>
CPP_concept pair_like_convertible_from_helper_ = //
CPP_concept_ref(pair_like_convertible_from_helper_, T, U, V);
template(typename T, typename U, typename V)( //
concept (pair_like_convertible_from_impl_)(T, U, V),
(!range<T>) AND
constructible_from<T, U, V> AND
pair_like<uncvref_t<T>> AND
pair_like_convertible_from_helper_<T, U, V>);
/// \concept pair_like_convertible_from_
/// \brief The \c pair_like_convertible_from_ concept
template<typename T, typename U, typename V>
CPP_concept pair_like_convertible_from_ =
CPP_concept_ref(detail::pair_like_convertible_from_impl_, T, U, V);
/// \concept range_convertible_to_impl_
/// \brief The \c range_convertible_to_impl_ concept
template(typename R, typename I, typename S)(
concept (range_convertible_to_impl_)(R, I, S),
convertible_to_not_slicing_<iterator_t<R>, I> AND
convertible_to<sentinel_t<R>, S>);
/// \concept range_convertible_to_
/// \brief The \c range_convertible_to_ concept
template<typename R, typename I, typename S>
CPP_concept range_convertible_to_ =
borrowed_range<R> &&
CPP_concept_ref(detail::range_convertible_to_impl_, R, I, S);
// clang-format on
template(typename S, typename I)(
requires sentinel_for<S, I>)
constexpr bool is_sized_sentinel_() noexcept
{
return (bool)sized_sentinel_for<S, I>;
}
template<subrange_kind K, typename S, typename I>
constexpr bool store_size_() noexcept
{
return K == subrange_kind::sized && !(bool)sized_sentinel_for<S, I>;
}
} // namespace detail
/// \endcond
template< //
typename I, //
typename S = I, //
subrange_kind K = static_cast<subrange_kind>(detail::is_sized_sentinel_<S, I>())>
struct subrange;
template<typename I, typename S, subrange_kind K>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<subrange<I, S, K>> = true;
/// \cond
namespace _subrange_
{
struct adl_hook
{};
template(std::size_t N, typename I, typename S, subrange_kind K)(
requires (N == 0)) //
constexpr I get(subrange<I, S, K> const & r)
{
return r.begin();
}
template(std::size_t N, typename I, typename S, subrange_kind K)(
requires (N == 1)) //
constexpr S get(subrange<I, S, K> const & r)
{
return r.end();
}
} // namespace _subrange_
/// \endcond
template<typename I, typename S, subrange_kind K>
struct subrange
: view_interface<subrange<I, S, K>,
same_as<S, unreachable_sentinel_t>
? infinite
: K == subrange_kind::sized ? finite : unknown>
, private _subrange_::adl_hook
{
CPP_assert(input_or_output_iterator<I>);
CPP_assert(sentinel_for<S, I>);
CPP_assert(K == subrange_kind::sized || !sized_sentinel_for<S, I>);
CPP_assert(K != subrange_kind::sized || !same_as<S, unreachable_sentinel_t>);
using size_type = detail::iter_size_t<I>;
using iterator = I;
using sentinel = S;
subrange() = default;
template(typename I2)(
requires detail::convertible_to_not_slicing_<I2, I> AND
(!detail::store_size_<K, S, I>())) //
constexpr subrange(I2 && i, S s)
: data_{static_cast<I2 &&>(i), std::move(s)}
{}
template(typename I2)(
requires detail::convertible_to_not_slicing_<I2, I> AND
(detail::store_size_<K, S, I>())) //
constexpr subrange(I2 && i, S s, size_type n)
: data_{static_cast<I2 &&>(i), std::move(s), n}
{
if(RANGES_CONSTEXPR_IF((bool)random_access_iterator<I>))
{
using D = iter_difference_t<I>;
RANGES_EXPECT(n <= (size_type)std::numeric_limits<D>::max());
RANGES_EXPECT(ranges::next(first_(), (D)n) == last_());
}
}
template(typename I2)(
requires detail::convertible_to_not_slicing_<I2, I> AND
sized_sentinel_for<S, I>)
constexpr subrange(I2 && i, S s, size_type n)
: data_{static_cast<I2 &&>(i), std::move(s)}
{
RANGES_EXPECT(static_cast<size_type>(last_() - first_()) == n);
}
template(typename R)(
requires (!same_as<detail::decay_t<R>, subrange>) AND
detail::range_convertible_to_<R, I, S> AND
(!detail::store_size_<K, S, I>()))
constexpr subrange(R && r)
: subrange{ranges::begin(r), ranges::end(r)}
{}
template(typename R)(
requires (!same_as<detail::decay_t<R>, subrange>) AND
detail::range_convertible_to_<R, I, S> AND
(detail::store_size_<K, S, I>()) AND
sized_range<R>)
constexpr subrange(R && r)
: subrange{ranges::begin(r), ranges::end(r), ranges::size(r)}
{}
template(typename R)(
requires (K == subrange_kind::sized) AND
detail::range_convertible_to_<R, I, S>)
constexpr subrange(R && r, size_type n) //
: subrange{ranges::begin(r), ranges::end(r), n}
{
if(RANGES_CONSTEXPR_IF((bool)sized_range<R>))
{
RANGES_EXPECT(n == ranges::size(r));
}
}
template(typename PairLike)(
requires (!same_as<PairLike, subrange>) AND
detail::pair_like_convertible_from_<PairLike, I const &, S const &>)
constexpr operator PairLike() const
{
return PairLike(first_(), last_());
}
constexpr I begin() const noexcept(std::is_nothrow_copy_constructible<I>::value)
{
return first_();
}
constexpr S end() const noexcept(std::is_nothrow_copy_constructible<S>::value)
{
return last_();
}
constexpr bool empty() const
{
return first_() == last_();
}
CPP_member
constexpr auto size() const //
-> CPP_ret(size_type)(
requires (K == subrange_kind::sized))
{
return get_size_();
}
RANGES_NODISCARD
constexpr subrange next(iter_difference_t<I> n = 1) const
{
auto tmp = *this;
tmp.advance(n);
return tmp;
}
CPP_member
RANGES_NODISCARD constexpr auto prev(iter_difference_t<I> n = 1) const
-> CPP_ret(subrange)(
requires bidirectional_iterator<I>)
{
auto tmp = *this;
tmp.advance(-n);
return tmp;
}
constexpr subrange & advance(iter_difference_t<I> n)
{
set_size_(get_size_() -
static_cast<size_type>(n - ranges::advance(first_(), n, last_())));
return *this;
}
private:
using data_t =
meta::conditional_t< //
detail::store_size_<K, S, I>(), //
std::tuple<I, S, size_type>, //
std::tuple<I, S>>;
data_t data_;
constexpr I & first_() noexcept
{
return std::get<0>(data_);
}
constexpr const I & first_() const noexcept
{
return std::get<0>(data_);
}
constexpr S & last_() noexcept
{
return std::get<1>(data_);
}
constexpr const S & last_() const noexcept
{
return std::get<1>(data_);
}
CPP_member
constexpr auto get_size_() const //
-> CPP_ret(size_type)(
requires sized_sentinel_for<S, I>)
{
return static_cast<size_type>(last_() - first_());
}
CPP_member
constexpr auto get_size_() const noexcept //
-> CPP_ret(size_type)(
requires (detail::store_size_<K, S, I>()))
{
return std::get<2>(data_);
}
static constexpr void set_size_(...) noexcept
{}
CPP_member
constexpr auto set_size_(size_type n) noexcept //
-> CPP_ret(void)(
requires (detail::store_size_<K, S, I>()))
{
std::get<2>(data_) = n;
}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename I, typename S>
subrange(I, S) //
-> subrange<I, S>;
template(typename I, typename S)(
requires input_or_output_iterator<I> AND sentinel_for<S, I>)
subrange(I, S, detail::iter_size_t<I>)
-> subrange<I, S, subrange_kind::sized>;
template(typename R)(
requires borrowed_range<R>)
subrange(R &&) //
-> subrange<iterator_t<R>, sentinel_t<R>,
(sized_range<R> ||
sized_sentinel_for<sentinel_t<R>, iterator_t<R>>)
? subrange_kind::sized
: subrange_kind::unsized>;
template(typename R)(
requires borrowed_range<R>)
subrange(R &&, detail::iter_size_t<iterator_t<R>>)
-> subrange<iterator_t<R>, sentinel_t<R>, subrange_kind::sized>;
#endif
// in lieu of deduction guides, use make_subrange
struct make_subrange_fn
{
template<typename I, typename S>
constexpr subrange<I, S> operator()(I i, S s) const
{
return {i, s};
}
template(typename I, typename S)(
requires input_or_output_iterator<I> AND sentinel_for<S, I>)
constexpr subrange<I, S, subrange_kind::sized> //
operator()(I i, S s, detail::iter_size_t<I> n) const
{
return {i, s, n};
}
template(typename R)(
requires borrowed_range<R>)
constexpr auto operator()(R && r) const
-> subrange<iterator_t<R>, sentinel_t<R>,
(sized_range<R> || sized_sentinel_for<sentinel_t<R>, iterator_t<R>>)
? subrange_kind::sized
: subrange_kind::unsized>
{
return {(R &&) r};
}
template(typename R)(
requires borrowed_range<R>)
constexpr subrange<iterator_t<R>, sentinel_t<R>, subrange_kind::sized> //
operator()(R && r, detail::iter_size_t<iterator_t<R>> n) const
{
return {(R &&) r, n};
}
};
/// \relates make_subrange_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(make_subrange_fn, make_subrange)
template<typename R>
using borrowed_subrange_t = detail::maybe_dangling_<R, subrange<iterator_t<R>>>;
template<typename R>
using safe_subrange_t RANGES_DEPRECATED("Use borrowed_subrange_t instead.") =
borrowed_subrange_t<R>;
namespace cpp20
{
using ranges::subrange_kind;
template(typename I, //
typename S = I, //
subrange_kind K = //
static_cast<subrange_kind>( //
detail::is_sized_sentinel_<S, I>()))(
requires input_or_output_iterator<I> AND sentinel_for<S, I> AND
(K == subrange_kind::sized || !sized_sentinel_for<S, I>)) //
using subrange = ranges::subrange<I, S, K>;
using ranges::borrowed_subrange_t;
template<typename R>
using safe_subrange_t RANGES_DEPRECATED("Use borrowed_subrange_t instead.") =
borrowed_subrange_t<R>;
} // namespace cpp20
/// @}
} // namespace ranges
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
namespace std
{
template<typename I, typename S, ::ranges::subrange_kind K>
struct tuple_size<::ranges::subrange<I, S, K>> : std::integral_constant<size_t, 2>
{};
template<typename I, typename S, ::ranges::subrange_kind K>
struct tuple_element<0, ::ranges::subrange<I, S, K>>
{
using type = I;
};
template<typename I, typename S, ::ranges::subrange_kind K>
struct tuple_element<1, ::ranges::subrange<I, S, K>>
{
using type = S;
};
} // namespace std
RANGES_DIAGNOSTIC_POP
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,146 @@
/// \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_TAIL_HPP
#define RANGES_V3_VIEW_TAIL_HPP
#include <type_traits>
#include <utility>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
namespace detail
{
template<typename T>
constexpr T prev_or_zero_(T n)
{
return n == 0 ? T(0) : T(n - 1);
}
} // namespace detail
/// \addtogroup group-views
/// @{
template<typename Rng>
struct tail_view
: view_interface<tail_view<Rng>,
(range_cardinality<Rng>::value >= 0)
? detail::prev_or_zero_(range_cardinality<Rng>::value)
: range_cardinality<Rng>::value>
{
private:
Rng rng_;
public:
tail_view() = default;
tail_view(Rng rng)
: rng_(static_cast<Rng &&>(rng))
{
CPP_assert(input_range<Rng>);
}
iterator_t<Rng> begin()
{
return next(ranges::begin(rng_), 1, ranges::end(rng_));
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng>>)
iterator_t<meta::const_if_c<Const, Rng>> begin() const
{
return next(ranges::begin(rng_), 1, ranges::end(rng_));
}
sentinel_t<Rng> end()
{
return ranges::end(rng_);
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng>>)
sentinel_t<meta::const_if_c<Const, Rng>> end() const
{
return ranges::end(rng_);
}
// Strange cast to bool in the requires clause is to work around gcc bug.
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires(bool(sized_range<Rng>)))
{
using size_type = range_size_t<Rng>;
return range_cardinality<Rng>::value >= 0
? detail::prev_or_zero_((size_type)range_cardinality<Rng>::value)
: detail::prev_or_zero_(ranges::size(rng_));
}
CPP_auto_member
constexpr auto CPP_fun(size)()(const //
requires(bool(sized_range<Rng const>)))
{
using size_type = range_size_t<Rng>;
return range_cardinality<Rng>::value >= 0
? detail::prev_or_zero_((size_type)range_cardinality<Rng>::value)
: detail::prev_or_zero_(ranges::size(rng_));
}
Rng base() const
{
return rng_;
}
};
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<tail_view<Rng>> = //
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng)(
requires viewable_range<Rng>)
tail_view(Rng &&)
->tail_view<views::all_t<Rng>>;
#endif
namespace views
{
struct tail_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng>)
meta::if_c<range_cardinality<Rng>::value == 0,
all_t<Rng>,
tail_view<all_t<Rng>>> //
operator()(Rng && rng) const
{
return all(static_cast<Rng &&>(rng));
}
};
/// \relates tail_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<tail_fn>, tail)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::tail_view)
#endif

View File

@@ -0,0 +1,327 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_TAKE_HPP
#define RANGES_V3_VIEW_TAKE_HPP
#include <type_traits>
#include <range/v3/range_fwd.hpp>
#include <range/v3/algorithm/min.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/iterator/counted_iterator.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng>
struct take_view : view_interface<take_view<Rng>, finite>
{
private:
CPP_assert(view_<Rng>);
Rng base_ = Rng();
range_difference_t<Rng> count_ = 0;
template<bool Const>
struct sentinel
{
private:
using Base = meta::conditional_t<Const, Rng const, Rng>;
using CI = counted_iterator<iterator_t<Base>>;
sentinel_t<Base> end_ = sentinel_t<Base>();
public:
sentinel() = default;
constexpr explicit sentinel(sentinel_t<Base> last)
: end_(std::move(last))
{}
template(bool Other)(
requires Const AND CPP_NOT(Other) AND
convertible_to<sentinel_t<Rng>,
sentinel_t<Base>>)
constexpr sentinel(sentinel<Other> that)
: end_(std::move(that.end_))
{}
constexpr sentinel_t<Base> base() const
{
return end_;
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#endif // RANGES_WORKAROUND_MSVC_756601
friend constexpr bool operator==(sentinel const & x, CI const & y)
{
return y.count() == 0 || y.base() == x.end_;
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#endif // RANGES_WORKAROUND_MSVC_756601
friend constexpr bool operator==(CI const & y, sentinel const & x)
{
return y.count() == 0 || y.base() == x.end_;
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#endif // RANGES_WORKAROUND_MSVC_756601
friend constexpr bool operator!=(sentinel const & x, CI const & y)
{
return y.count() != 0 && y.base() != x.end_;
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#endif // RANGES_WORKAROUND_MSVC_756601
friend constexpr bool operator!=(CI const & y, sentinel const & x)
{
return y.count() != 0 && y.base() != x.end_;
}
};
#if RANGES_CXX_IF_CONSTEXPR < RANGES_CXX_IF_CONSTEXPR_17
template<typename Take>
static auto begin_random_access_(Take & take, std::true_type)
{
return ranges::begin(take.base_);
}
template<typename Take>
static auto begin_random_access_(Take & take, std::false_type)
{
auto s = static_cast<range_difference_t<Rng>>(take.size());
return make_counted_iterator(ranges::begin(take.base_), s);
}
template<typename Take>
static auto begin_sized_(Take & take, std::true_type)
{
return begin_random_access_(
take, meta::bool_<random_access_range<decltype((take.base_))>>{});
}
template<typename Take>
static auto begin_sized_(Take & take, std::false_type)
{
return make_counted_iterator(ranges::begin(take.base_), take.count_);
}
template<typename Take>
static auto end_random_access_(Take & take, std::true_type)
{
return ranges::begin(take.base_) +
static_cast<range_difference_t<Rng>>(take.size());
}
static auto end_random_access_(detail::ignore_t, std::false_type)
{
return default_sentinel;
}
template<typename Take>
static auto end_sized_(Take & take, std::true_type, std::false_type) // sized
{
return end_random_access_(
take, meta::bool_<random_access_range<decltype((take.base_))>>{});
}
static auto end_sized_(detail::ignore_t, std::false_type,
std::true_type) // infinite
{
return default_sentinel;
}
static auto end_sized_(take_view & take, std::false_type, std::false_type)
{
return sentinel<false>{ranges::end(take.base_)};
}
static auto end_sized_(take_view const & take, std::false_type, std::false_type)
{
return sentinel<true>{ranges::end(take.base_)};
}
#endif
public:
take_view() = default;
constexpr take_view(Rng base, range_difference_t<Rng> cnt)
: base_(std::move(base))
, count_(cnt)
{}
constexpr Rng base() const
{
return base_;
}
CPP_auto_member
constexpr auto CPP_fun(begin)()(
requires(!simple_view<Rng>()))
{
#if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
if constexpr(sized_range<Rng>)
if constexpr(random_access_range<Rng>)
return ranges::begin(base_);
else
{
// cannot always delegate to size() member on GCC with ConceptsTS
#if defined(__cpp_concepts) && __cpp_concepts <= 201507
auto s = ranges::min(
static_cast<range_difference_t<Rng>>(count_),
static_cast<range_difference_t<Rng>>(ranges::size(base_)));
#else
auto s = static_cast<range_difference_t<Rng>>(size());
#endif
return make_counted_iterator(ranges::begin(base_), s);
}
else
return make_counted_iterator(ranges::begin(base_), count_);
#else
return begin_sized_(*this, meta::bool_<sized_range<Rng>>{});
#endif
}
CPP_auto_member
constexpr auto CPP_fun(begin)()(const //
requires range<Rng const>)
{
#if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
if constexpr(sized_range<Rng const>)
if constexpr(random_access_range<Rng const>)
return ranges::begin(base_);
else
{
auto s = static_cast<range_difference_t<Rng>>(size());
return make_counted_iterator(ranges::begin(base_), s);
}
else
return make_counted_iterator(ranges::begin(base_), count_);
#else
return begin_sized_(*this, meta::bool_<sized_range<Rng const>>{});
#endif
}
CPP_auto_member
constexpr auto CPP_fun(end)()(
requires(!simple_view<Rng>()))
{
#if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
if constexpr(sized_range<Rng>)
if constexpr(random_access_range<Rng>)
return ranges::begin(base_) +
static_cast<range_difference_t<Rng>>(size());
else
return default_sentinel;
// Not to spec: Infinite ranges:
else if constexpr(is_infinite<Rng>::value)
return default_sentinel;
else
return sentinel<false>{ranges::end(base_)};
#else
return end_sized_(*this, meta::bool_<sized_range<Rng>>{}, is_infinite<Rng>{});
#endif
}
CPP_auto_member
constexpr auto CPP_fun(end)()(const //
requires range<Rng const>)
{
#if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
if constexpr(sized_range<Rng const>)
if constexpr(random_access_range<Rng const>)
return ranges::begin(base_) +
static_cast<range_difference_t<Rng>>(size());
else
return default_sentinel;
// Not to spec: Infinite ranges:
else if constexpr(is_infinite<Rng const>::value)
return default_sentinel;
else
return sentinel<true>{ranges::end(base_)};
#else
return end_sized_(
*this, meta::bool_<sized_range<Rng const>>{}, is_infinite<Rng const>{});
#endif
}
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires sized_range<Rng>)
{
auto n = ranges::size(base_);
return ranges::min(n, static_cast<decltype(n)>(count_));
}
CPP_auto_member
constexpr auto CPP_fun(size)()(const //
requires sized_range<Rng const>)
{
auto n = ranges::size(base_);
return ranges::min(n, static_cast<decltype(n)>(count_));
}
};
template<typename Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<take_view<Rng>> = //
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng>
take_view(Rng &&, range_difference_t<Rng>)
-> take_view<views::all_t<Rng>>;
#endif
namespace views
{
struct take_base_fn
{
template(typename Rng)(
requires viewable_range<Rng>)
take_view<all_t<Rng>> operator()(Rng && rng, range_difference_t<Rng> n) const
{
return {all(static_cast<Rng &&>(rng)), n};
}
};
struct take_fn : take_base_fn
{
using take_base_fn::operator();
template(typename Int)(
requires detail::integer_like_<Int>)
constexpr auto operator()(Int n) const
{
return make_view_closure(bind_back(take_base_fn{}, n));
}
};
/// \relates take_fn
RANGES_INLINE_VARIABLE(take_fn, take)
} // namespace views
namespace cpp20
{
namespace views
{
using ranges::views::take;
}
template(typename Rng)(
requires view_<Rng>)
using take_view = ranges::take_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::take_view)
#endif

View File

@@ -0,0 +1,203 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_TAKE_EXACTLY_HPP
#define RANGES_V3_VIEW_TAKE_EXACTLY_HPP
#include <type_traits>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/iterator/counted_iterator.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/iterator/traits.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/counted.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
template<typename Rng>
struct is_random_access_common_
: meta::bool_<(bool)random_access_range<Rng> && (bool)common_range<Rng>>
{};
// BUGBUG Per the discussion in https://github.com/ericniebler/stl2/issues/63,
// it's unclear if we can infer anything from random_access_range<Rng> &&
// common_range<Rng>
template<typename Rng,
bool IsRandomAccessCommon /*= is_random_access_common_<Rng>::value*/>
struct take_exactly_view_
: view_interface<take_exactly_view_<Rng, IsRandomAccessCommon>, finite>
{
private:
Rng rng_;
range_difference_t<Rng> n_;
public:
take_exactly_view_() = default;
take_exactly_view_(Rng rng, range_difference_t<Rng> n)
: rng_(std::move(rng))
, n_(n)
{
RANGES_EXPECT(n >= 0);
}
counted_iterator<iterator_t<Rng>> begin()
{
return {ranges::begin(rng_), n_};
}
template(typename BaseRng = Rng)(
requires range<BaseRng const>)
counted_iterator<iterator_t<BaseRng const>> begin() const
{
return {ranges::begin(rng_), n_};
}
default_sentinel_t end() const
{
return {};
}
auto size() const
{
return static_cast<detail::iter_size_t<iterator_t<Rng>>>(n_);
}
Rng base() const
{
return rng_;
}
};
template<typename Rng>
struct take_exactly_view_<Rng, true>
: view_interface<take_exactly_view_<Rng, true>, finite>
{
private:
Rng rng_;
range_difference_t<Rng> n_;
public:
take_exactly_view_() = default;
take_exactly_view_(Rng rng, range_difference_t<Rng> n)
: rng_(std::move(rng))
, n_(n)
{
RANGES_EXPECT(n >= 0);
RANGES_EXPECT(!(bool)sized_range<Rng> || n <= ranges::distance(rng_));
}
iterator_t<Rng> begin()
{
return ranges::begin(rng_);
}
iterator_t<Rng> end()
{
return ranges::begin(rng_) + n_;
}
CPP_auto_member
auto CPP_fun(begin)()(const //
requires range<Rng const>)
{
return ranges::begin(rng_);
}
CPP_auto_member
auto CPP_fun(end)()(const //
requires range<Rng const>)
{
return ranges::begin(rng_) + n_;
}
detail::iter_size_t<iterator_t<Rng>> size() const
{
return static_cast<detail::iter_size_t<iterator_t<Rng>>>(n_);
}
Rng base() const
{
return rng_;
}
};
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
template<typename Rng>
using take_exactly_view = detail::take_exactly_view_<Rng>;
template<typename Rng, bool B>
RANGES_INLINE_VAR constexpr bool //
enable_borrowed_range<detail::take_exactly_view_<Rng, B>> = //
enable_borrowed_range<Rng>;
namespace views
{
struct take_exactly_base_fn
{
private:
template<typename Rng>
static constexpr take_exactly_view<all_t<Rng>> impl_(
Rng && rng, range_difference_t<Rng> n, input_range_tag)
{
return {all(static_cast<Rng &&>(rng)), n};
}
template(typename Rng)(
requires borrowed_range<Rng>)
static constexpr subrange<iterator_t<Rng>> impl_(Rng && rng,
range_difference_t<Rng> n,
random_access_range_tag)
{
return {begin(rng), next(begin(rng), n)};
}
public:
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng>)
constexpr auto operator()(Rng && rng, range_difference_t<Rng> n) const
{
return take_exactly_base_fn::impl_(
static_cast<Rng &&>(rng), n, range_tag_of<Rng>{});
}
};
struct take_exactly_fn : take_exactly_base_fn
{
using take_exactly_base_fn::operator();
template(typename Int)(
requires detail::integer_like_<Int>)
constexpr auto operator()(Int n) const
{
return make_view_closure(bind_back(take_exactly_base_fn{}, n));
}
};
/// \relates take_exactly_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(take_exactly_fn, take_exactly)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::detail::take_exactly_view_)
#endif

View File

@@ -0,0 +1,66 @@
/// \file
// Range v3 library
//
// Copyright Barry Revzin 2019-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_TAKE_LAST_HPP
#define RANGES_V3_VIEW_TAKE_LAST_HPP
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/operations.hpp>
#include <range/v3/view/drop_exactly.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
namespace views
{
struct take_last_base_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND sized_range<Rng>)
auto operator()(Rng && rng, range_difference_t<Rng> n) const
{
auto sz = ranges::distance(rng);
return drop_exactly(static_cast<Rng &&>(rng), sz > n ? sz - n : 0);
}
};
struct take_last_fn : take_last_base_fn
{
using take_last_base_fn::operator();
template(typename Int)(
requires detail::integer_like_<Int>)
constexpr auto operator()(Int n) const
{
return make_view_closure(bind_back(take_last_base_fn{}, n));
}
};
/// \relates take_last_fn
RANGES_INLINE_VARIABLE(take_last_fn, take_last)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,210 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_TAKE_WHILE_HPP
#define RANGES_V3_VIEW_TAKE_WHILE_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/functional/compose.hpp>
#include <range/v3/functional/indirect.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng, typename Pred>
struct iter_take_while_view
: view_adaptor<iter_take_while_view<Rng, Pred>, Rng,
is_finite<Rng>::value ? finite : unknown>
{
private:
friend range_access;
RANGES_NO_UNIQUE_ADDRESS semiregular_box_t<Pred> pred_;
template<bool IsConst>
struct sentinel_adaptor : adaptor_base
{
private:
friend struct sentinel_adaptor<!IsConst>;
using CRng = meta::const_if_c<IsConst, Rng>;
RANGES_NO_UNIQUE_ADDRESS semiregular_box_ref_or_val_t<Pred, IsConst> pred_;
public:
sentinel_adaptor() = default;
sentinel_adaptor(semiregular_box_ref_or_val_t<Pred, IsConst> pred)
: pred_(std::move(pred))
{}
template(bool Other)(
requires IsConst AND CPP_NOT(Other)) //
sentinel_adaptor(sentinel_adaptor<Other> that)
: pred_(std::move(that.pred_))
{}
bool empty(iterator_t<CRng> const & it, sentinel_t<CRng> const & last) const
{
return it == last || !invoke(pred_, it);
}
};
sentinel_adaptor<false> end_adaptor()
{
return {pred_};
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng>> AND
invocable<Pred const &, iterator_t<meta::const_if_c<Const, Rng>>>)
sentinel_adaptor<Const> end_adaptor() const
{
return {pred_};
}
public:
iter_take_while_view() = default;
constexpr iter_take_while_view(Rng rng, Pred pred)
: iter_take_while_view::view_adaptor{std::move(rng)}
, pred_(std::move(pred))
{}
};
template<typename Rng, typename Pred>
struct take_while_view : iter_take_while_view<Rng, indirected<Pred>>
{
take_while_view() = default;
constexpr take_while_view(Rng rng, Pred pred)
: iter_take_while_view<Rng, indirected<Pred>>{std::move(rng),
indirect(std::move(pred))}
{}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename Fun)(
requires copy_constructible<Fun>)
take_while_view(Rng &&, Fun)
-> take_while_view<views::all_t<Rng>, Fun>;
#endif
namespace views
{
struct iter_take_while_base_fn
{
template(typename Rng, typename Pred)(
requires viewable_range<Rng> AND input_range<Rng> AND
predicate<Pred &, iterator_t<Rng>> AND copy_constructible<Pred>)
constexpr iter_take_while_view<all_t<Rng>, Pred> //
operator()(Rng && rng, Pred pred) const
{
return {all(static_cast<Rng &&>(rng)), std::move(pred)};
}
};
struct iter_take_while_fn : iter_take_while_base_fn
{
using iter_take_while_base_fn::operator();
template<typename Pred>
constexpr auto operator()(Pred pred) const
{
return make_view_closure(
bind_back(iter_take_while_base_fn{}, std::move(pred)));
}
};
struct take_while_base_fn
{
template(typename Rng, typename Pred)(
requires viewable_range<Rng> AND input_range<Rng> AND
indirect_unary_predicate<Pred &, iterator_t<Rng>>)
constexpr take_while_view<all_t<Rng>, Pred> //
operator()(Rng && rng, Pred pred) const
{
return {all(static_cast<Rng &&>(rng)), std::move(pred)};
}
template(typename Rng, typename Pred, typename Proj)(
requires viewable_range<Rng> AND input_range<Rng> AND
indirect_unary_predicate<composed<Pred, Proj> &, iterator_t<Rng>>)
constexpr take_while_view<all_t<Rng>, composed<Pred, Proj>> //
operator()(Rng && rng, Pred pred, Proj proj) const
{
return {all(static_cast<Rng &&>(rng)),
compose(std::move(pred), std::move(proj))};
}
};
struct take_while_bind_fn
{
template<typename Pred>
constexpr auto operator()(Pred pred) const // TODO: underconstrained
{
return make_view_closure(
bind_back(take_while_base_fn{}, std::move(pred)));
}
template(typename Pred, typename Proj)(
requires (!range<Pred>)) // TODO: underconstrained
constexpr auto operator()(Pred && pred, Proj proj) const
{
return make_view_closure(bind_back(
take_while_base_fn{}, static_cast<Pred &&>(pred), std::move(proj)));
}
};
struct RANGES_EMPTY_BASES take_while_fn
: take_while_base_fn, take_while_bind_fn
{
using take_while_base_fn::operator();
using take_while_bind_fn::operator();
};
/// \relates iter_take_while_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(iter_take_while_fn, iter_take_while)
/// \relates take_while_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(take_while_fn, take_while)
} // namespace views
namespace cpp20
{
namespace views
{
using ranges::views::take_while;
}
template(typename Rng, typename Pred)(
requires viewable_range<Rng> AND input_range<Rng> AND
predicate<Pred &, iterator_t<Rng>> AND copy_constructible<Pred>)
using take_while_view = ranges::take_while_view<Rng, Pred>;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::iter_take_while_view)
RANGES_SATISFY_BOOST_RANGE(::ranges::take_while_view)
#endif

View File

@@ -0,0 +1,207 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_TOKENIZE_HPP
#define RANGES_V3_VIEW_TOKENIZE_HPP
#include <initializer_list>
#include <regex>
#include <type_traits>
#include <utility>
#include <vector>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng, typename Regex, typename SubMatchRange>
struct tokenize_view
: view_interface<tokenize_view<Rng, Regex, SubMatchRange>,
is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
{
private:
CPP_assert(bidirectional_range<Rng> && view_<Rng> && common_range<Rng>);
CPP_assert(semiregular<Regex>);
CPP_assert(semiregular<SubMatchRange>);
Rng rng_;
Regex rex_;
SubMatchRange subs_;
std::regex_constants::match_flag_type flags_;
template<bool Const>
using iterator_t =
std::regex_token_iterator<iterator_t<meta::const_if_c<Const, Rng>>>;
public:
tokenize_view() = default;
tokenize_view(Rng rng, Regex rex, SubMatchRange subs,
std::regex_constants::match_flag_type flags)
: rng_(std::move(rng))
, rex_(std::move(rex))
, subs_(std::move(subs))
, flags_(flags)
{}
iterator_t<simple_view<Rng>()> begin()
{
meta::const_if_c<simple_view<Rng>(), Rng> & rng = rng_;
return {ranges::begin(rng), ranges::end(rng), rex_, subs_, flags_};
}
template(bool Const = true)(
requires range<Rng const>)
iterator_t<Const> begin() const
{
return {ranges::begin(rng_), ranges::end(rng_), rex_, subs_, flags_};
}
iterator_t<simple_view<Rng>()> end()
{
return {};
}
template(bool Const = true)(
requires range<Rng const>)
iterator_t<Const> end() const
{
return {};
}
Rng base() const
{
return rng_;
}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename Regex, typename SubMatchRange)(
requires copy_constructible<Regex> AND copy_constructible<SubMatchRange>)
tokenize_view(Rng &&, Regex, SubMatchRange)
->tokenize_view<views::all_t<Rng>, Regex, SubMatchRange>;
#endif
namespace views
{
struct tokenize_base_fn
{
template(typename Rng, typename Regex)(
requires bidirectional_range<Rng> AND common_range<Rng> AND
same_as< //
range_value_t<Rng>, //
typename detail::decay_t<Regex>::value_type>)
tokenize_view<all_t<Rng>, detail::decay_t<Regex>, int> //
operator()(Rng && rng,
Regex && rex,
int sub = 0,
std::regex_constants::match_flag_type flags =
std::regex_constants::match_default) const //
{
return {all(static_cast<Rng &&>(rng)),
static_cast<Regex &&>(rex),
sub,
flags};
}
template(typename Rng, typename Regex)(
requires bidirectional_range<Rng> AND common_range<Rng> AND
same_as<range_value_t<Rng>,
typename detail::decay_t<Regex>::value_type>)
tokenize_view<all_t<Rng>, detail::decay_t<Regex>, std::vector<int>> //
operator()(Rng && rng,
Regex && rex,
std::vector<int> subs,
std::regex_constants::match_flag_type flags =
std::regex_constants::match_default) const //
{
return {all(static_cast<Rng &&>(rng)),
static_cast<Regex &&>(rex),
std::move(subs),
flags};
}
template(typename Rng, typename Regex)(
requires bidirectional_range<Rng> AND common_range<Rng> AND
same_as<range_value_t<Rng>,
typename detail::decay_t<Regex>::value_type>)
tokenize_view<all_t<Rng>,
detail::decay_t<Regex>,
std::initializer_list<int>> //
operator()(Rng && rng,
Regex && rex,
std::initializer_list<int> subs,
std::regex_constants::match_flag_type flags =
std::regex_constants::match_default) const //
{
return {all(static_cast<Rng &&>(rng)),
static_cast<Regex &&>(rex),
std::move(subs),
flags};
}
};
struct tokenize_fn : tokenize_base_fn
{
using tokenize_base_fn::operator();
template<typename Regex>
constexpr auto operator()(Regex && rex,
int sub = 0,
std::regex_constants::match_flag_type flags =
std::regex_constants::match_default) const
{
return make_view_closure(bind_back(
tokenize_base_fn{}, static_cast<Regex &&>(rex), sub, flags));
}
template<typename Regex>
auto operator()(Regex && rex,
std::vector<int> subs,
std::regex_constants::match_flag_type flags =
std::regex_constants::match_default) const
{
return bind_back(tokenize_base_fn{},
static_cast<Regex &&>(rex),
std::move(subs),
flags);
}
template<typename Regex>
constexpr auto operator()(Regex && rex,
std::initializer_list<int> subs,
std::regex_constants::match_flag_type flags =
std::regex_constants::match_default) const
{
return make_view_closure(bind_back(
tokenize_base_fn{}, static_cast<Regex &&>(rex), subs, flags));
}
};
/// \relates tokenize_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(tokenize_fn, tokenize)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::tokenize_view)
#endif

View File

@@ -0,0 +1,618 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_TRANSFORM_HPP
#define RANGES_V3_VIEW_TRANSFORM_HPP
#include <iterator>
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/algorithm/max.hpp>
#include <range/v3/algorithm/min.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/indirect.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/move.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
constexpr cardinality transform2_cardinality(cardinality c1, cardinality c2)
{
return c1 >= 0 || c2 >= 0
? (c1 >= 0 && c2 >= 0 ? (c1 < c2 ? c1 : c2) : finite)
: c1 == finite || c2 == finite
? finite
: c1 == unknown || c2 == unknown ? unknown : infinite;
}
// clang-format off
/// \concept iter_transform_1_readable_
/// \brief The \c iter_transform_1_readable_ concept
template(typename Fun, typename Rng)(
concept (iter_transform_1_readable_)(Fun, Rng),
regular_invocable<Fun &, iterator_t<Rng>> AND
regular_invocable<Fun &, copy_tag, iterator_t<Rng>> AND
regular_invocable<Fun &, move_tag, iterator_t<Rng>> AND
common_reference_with<
invoke_result_t<Fun &, iterator_t<Rng>> &&,
invoke_result_t<Fun &, copy_tag, iterator_t<Rng>> &> AND
common_reference_with<
invoke_result_t<Fun &, iterator_t<Rng>> &&,
invoke_result_t<Fun &, move_tag, iterator_t<Rng>> &&> AND
common_reference_with<
invoke_result_t<Fun &, move_tag, iterator_t<Rng>> &&,
invoke_result_t<Fun &, copy_tag, iterator_t<Rng>> const &>
);
/// \concept iter_transform_1_readable
/// \brief The \c iter_transform_1_readable concept
template<typename Fun, typename Rng>
CPP_concept iter_transform_1_readable =
CPP_concept_ref(detail::iter_transform_1_readable_, Fun, Rng);
/// \concept iter_transform_2_readable_
/// \brief The \c iter_transform_2_readable_ concept
template(typename Fun, typename Rng1, typename Rng2)(
concept (iter_transform_2_readable_)(Fun, Rng1, Rng2),
regular_invocable<Fun &, iterator_t<Rng1>, iterator_t<Rng2>> AND
regular_invocable<Fun &, copy_tag, iterator_t<Rng1>, iterator_t<Rng2>> AND
regular_invocable<Fun &, move_tag, iterator_t<Rng1>, iterator_t<Rng2>> AND
common_reference_with<
invoke_result_t<Fun &, iterator_t<Rng1>, iterator_t<Rng2>> &&,
invoke_result_t<Fun &, copy_tag, iterator_t<Rng1>, iterator_t<Rng2>> &> AND
common_reference_with<
invoke_result_t<Fun &, iterator_t<Rng1>, iterator_t<Rng2>> &&,
invoke_result_t<Fun &, move_tag, iterator_t<Rng1>, iterator_t<Rng2>> &&> AND
common_reference_with<
invoke_result_t<Fun &, move_tag, iterator_t<Rng1>, iterator_t<Rng2>> &&,
invoke_result_t<Fun &, copy_tag, iterator_t<Rng1>, iterator_t<Rng2>> const &>
);
/// \concept iter_transform_2_readable
/// \brief The \c iter_transform_2_readable concept
template<typename Fun, typename Rng1, typename Rng2>
CPP_concept iter_transform_2_readable =
CPP_concept_ref(detail::iter_transform_2_readable_, Fun, Rng1, Rng2);
// clang-format on
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
template<typename Rng, typename Fun>
struct iter_transform_view : view_adaptor<iter_transform_view<Rng, Fun>, Rng>
{
private:
friend range_access;
RANGES_NO_UNIQUE_ADDRESS semiregular_box_t<Fun> fun_;
template<bool Const>
using use_sentinel_t =
meta::bool_<!common_range<meta::const_if_c<Const, Rng>> ||
single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng>>>>;
template<bool IsConst>
struct adaptor : adaptor_base
{
private:
friend struct adaptor<!IsConst>;
using CRng = meta::const_if_c<IsConst, Rng>;
using fun_ref_ = semiregular_box_ref_or_val_t<Fun, IsConst>;
RANGES_NO_UNIQUE_ADDRESS fun_ref_ fun_;
public:
using value_type =
detail::decay_t<invoke_result_t<Fun &, copy_tag, iterator_t<CRng>>>;
adaptor() = default;
adaptor(fun_ref_ fun)
: fun_(std::move(fun))
{}
template(bool Other)(
requires IsConst AND CPP_NOT(Other)) //
adaptor(adaptor<Other> that)
: fun_(std::move(that.fun_))
{}
// clang-format off
auto CPP_auto_fun(read)(iterator_t<CRng> it)(const)
(
return invoke(fun_, it)
)
auto CPP_auto_fun(iter_move)(iterator_t<CRng> it)(const)
(
return invoke(fun_, move_tag{}, it)
)
// clang-format on
};
adaptor<false> begin_adaptor()
{
return {fun_};
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng>> AND
detail::iter_transform_1_readable<Fun const,
meta::const_if_c<Const, Rng>>)
adaptor<Const> begin_adaptor() const
{
return {fun_};
}
meta::if_<use_sentinel_t<false>, adaptor_base, adaptor<false>> end_adaptor()
{
return {fun_};
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng>> AND
detail::iter_transform_1_readable<Fun const,
meta::const_if_c<Const, Rng>>)
meta::if_<use_sentinel_t<Const>, adaptor_base, adaptor<Const>> end_adaptor() const
{
return {fun_};
}
public:
iter_transform_view() = default;
iter_transform_view(Rng rng, Fun fun)
: iter_transform_view::view_adaptor{std::move(rng)}
, fun_(std::move(fun))
{}
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return ranges::size(this->base());
}
CPP_auto_member
constexpr auto CPP_fun(size)()(const //
requires sized_range<Rng const>)
{
return ranges::size(this->base());
}
};
template<typename Rng, typename Fun>
struct transform_view : iter_transform_view<Rng, indirected<Fun>>
{
transform_view() = default;
transform_view(Rng rng, Fun fun)
: iter_transform_view<Rng, indirected<Fun>>{std::move(rng),
indirect(std::move(fun))}
{}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename Fun)(
requires copy_constructible<Fun>)
transform_view(Rng &&, Fun)
-> transform_view<views::all_t<Rng>, Fun>;
#endif
template<typename Rng1, typename Rng2, typename Fun>
struct iter_transform2_view
: view_facade<iter_transform2_view<Rng1, Rng2, Fun>,
detail::transform2_cardinality(range_cardinality<Rng1>::value,
range_cardinality<Rng2>::value)>
{
private:
friend range_access;
RANGES_NO_UNIQUE_ADDRESS semiregular_box_t<Fun> fun_;
Rng1 rng1_;
Rng2 rng2_;
using difference_type_ =
common_type_t<range_difference_t<Rng1>, range_difference_t<Rng2>>;
static constexpr cardinality my_cardinality = detail::transform2_cardinality(
range_cardinality<Rng1>::value, range_cardinality<Rng2>::value);
template<bool>
struct cursor;
template<bool Const>
struct sentinel
{
private:
friend struct cursor<Const>;
sentinel_t<meta::const_if_c<Const, Rng1>> end1_;
sentinel_t<meta::const_if_c<Const, Rng2>> end2_;
public:
sentinel() = default;
sentinel(meta::const_if_c<Const, iter_transform2_view> * parent,
decltype(ranges::end))
: end1_(end(parent->rng1_))
, end2_(end(parent->rng2_))
{}
template(bool Other)(
requires Const AND CPP_NOT(Other)) //
sentinel(sentinel<Other> that)
: end1_(std::move(that.end1_))
, end2_(std::move(that.end2_))
{}
};
template<bool Const>
struct cursor
{
private:
using fun_ref_ = semiregular_box_ref_or_val_t<Fun, Const>;
using R1 = meta::const_if_c<Const, Rng1>;
using R2 = meta::const_if_c<Const, Rng2>;
fun_ref_ fun_;
iterator_t<R1> it1_;
iterator_t<R2> it2_;
public:
using difference_type = difference_type_;
using single_pass = meta::or_c<(bool)single_pass_iterator_<iterator_t<R1>>,
(bool)single_pass_iterator_<iterator_t<R2>>>;
using value_type =
detail::decay_t<invoke_result_t<meta::const_if_c<Const, Fun> &, copy_tag,
iterator_t<R1>, iterator_t<R2>>>;
cursor() = default;
template<typename BeginEndFn>
cursor(meta::const_if_c<Const, iter_transform2_view> * parent,
BeginEndFn begin_end)
: fun_(parent->fun_)
, it1_(begin_end(parent->rng1_))
, it2_(begin_end(parent->rng2_))
{}
template(bool Other)(
requires Const AND CPP_NOT(Other)) //
cursor(cursor<Other> that)
: fun_(std::move(that.fun_))
, it1_(std::move(that.end1_))
, it2_(std::move(that.end2_))
{}
// clang-format off
auto CPP_auto_fun(read)()(const)
(
return invoke(fun_, it1_, it2_)
)
// clang-format on
void next()
{
++it1_;
++it2_;
}
CPP_member
auto equal(cursor const & that) const //
-> CPP_ret(bool)(
requires forward_range<Rng1> && forward_range<Rng2>)
{
// By returning true if *any* of the iterators are equal, we allow
// transformed ranges to be of different lengths, stopping when the first
// one reaches the last.
return it1_ == that.it1_ || it2_ == that.it2_;
}
bool equal(sentinel<Const> const & s) const
{
// By returning true if *any* of the iterators are equal, we allow
// transformed ranges to be of different lengths, stopping when the first
// one reaches the last.
return it1_ == s.end1_ || it2_ == s.end2_;
}
CPP_member
auto prev() //
-> CPP_ret(void)(
requires bidirectional_range<R1> && bidirectional_range<R2>)
{
--it1_;
--it2_;
}
CPP_member
auto advance(difference_type n) -> CPP_ret(void)(
requires random_access_range<R1> && random_access_range<R2>)
{
ranges::advance(it1_, n);
ranges::advance(it2_, n);
}
CPP_member
auto distance_to(cursor const & that) const //
-> CPP_ret(difference_type)(
requires sized_sentinel_for<iterator_t<R1>, iterator_t<R1>> &&
sized_sentinel_for<iterator_t<R2>, iterator_t<R2>>)
{
// Return the smallest distance (in magnitude) of any of the iterator
// pairs. This is to accommodate zippers of sequences of different length.
difference_type d1 = that.it1_ - it1_, d2 = that.it2_ - it2_;
return 0 < d1 ? ranges::min(d1, d2) : ranges::max(d1, d2);
}
// clang-format off
auto CPP_auto_fun(move)()(const)
(
return invoke(fun_, move_tag{}, it1_, it2_)
)
// clang-format on
};
template<bool Const>
using end_cursor_t = meta::if_c<
common_range<meta::const_if_c<Const, Rng1>> &&
common_range<meta::const_if_c<Const, Rng2>> &&
!single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng1>>> &&
!single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng2>>>,
cursor<Const>, sentinel<Const>>;
cursor<simple_view<Rng1>() && simple_view<Rng2>()> begin_cursor()
{
return {this, ranges::begin};
}
end_cursor_t<simple_view<Rng1>() && simple_view<Rng2>()> end_cursor()
{
return {this, ranges::end};
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng1>> AND
range<meta::const_if_c<Const, Rng2>> AND
detail::iter_transform_2_readable< //
Fun const, //
meta::const_if_c<Const, Rng1>, //
meta::const_if_c<Const, Rng2>>)
cursor<true> begin_cursor() const
{
return {this, ranges::begin};
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng1>> AND
range<meta::const_if_c<Const, Rng2>> AND
detail::iter_transform_2_readable< //
Fun const, //
meta::const_if_c<Const, Rng1>, //
meta::const_if_c<Const, Rng2>>)
end_cursor_t<Const> end_cursor() const
{
return {this, ranges::end};
}
template<typename Self>
static constexpr auto size_(Self & self)
{
using size_type = common_type_t<range_size_t<Rng1>, range_size_t<Rng2>>;
return ranges::min(static_cast<size_type>(ranges::size(self.rng1_)),
static_cast<size_type>(ranges::size(self.rng2_)));
}
template<bool B>
using R1 = meta::invoke<detail::dependent_<B>, Rng1>;
template<bool B>
using R2 = meta::invoke<detail::dependent_<B>, Rng2>;
public:
iter_transform2_view() = default;
constexpr iter_transform2_view(Rng1 rng1, Rng2 rng2, Fun fun)
: fun_(std::move(fun))
, rng1_(std::move(rng1))
, rng2_(std::move(rng2))
{}
CPP_member
static constexpr auto size() //
-> CPP_ret(std::size_t)(
requires (my_cardinality >= 0))
{
return static_cast<std::size_t>(my_cardinality);
}
template(bool True = true)(
requires (my_cardinality < 0) AND sized_range<Rng1 const> AND
sized_range<Rng2 const> AND
common_with<range_size_t<R1<True>>, range_size_t<R2<True>>>)
constexpr auto size() const
{
return size_(*this);
}
template(bool True = true)(
requires (my_cardinality < 0) AND sized_range<Rng1> AND sized_range<Rng2> AND
common_with<range_size_t<R1<True>>, range_size_t<R2<True>>>)
constexpr auto size()
{
return size_(*this);
}
};
template<typename Rng1, typename Rng2, typename Fun>
struct transform2_view : iter_transform2_view<Rng1, Rng2, indirected<Fun>>
{
transform2_view() = default;
constexpr transform2_view(Rng1 rng1, Rng2 rng2, Fun fun)
: iter_transform2_view<Rng1, Rng2, indirected<Fun>>{std::move(rng1),
std::move(rng2),
indirect(std::move(fun))}
{}
};
namespace views
{
struct iter_transform_base_fn
{
template(typename Rng, typename Fun)(
requires viewable_range<Rng> AND input_range<Rng> AND
copy_constructible<Fun> AND
detail::iter_transform_1_readable<Fun, Rng>)
constexpr iter_transform_view<all_t<Rng>, Fun> //
operator()(Rng && rng, Fun fun) const
{
return {all(static_cast<Rng &&>(rng)), std::move(fun)};
}
template(typename Rng1, typename Rng2, typename Fun)(
requires viewable_range<Rng1> AND input_range<Rng1> AND
viewable_range<Rng2> AND input_range<Rng2> AND
copy_constructible<Fun> AND
common_with<range_difference_t<Rng1>, range_difference_t<Rng1>> AND
detail::iter_transform_2_readable<Fun, Rng1, Rng2>)
constexpr iter_transform2_view<all_t<Rng1>, all_t<Rng2>, Fun> //
operator()(Rng1 && rng1, Rng2 && rng2, Fun fun) const
{
return {all(static_cast<Rng1 &&>(rng1)),
all(static_cast<Rng2 &&>(rng2)),
std::move(fun)};
}
};
struct iter_transform_fn : iter_transform_base_fn
{
using iter_transform_base_fn::operator();
template<typename Fun>
constexpr auto operator()(Fun fun) const
{
return make_view_closure(
bind_back(iter_transform_base_fn{}, std::move(fun)));
}
};
/// \relates iter_transform_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(iter_transform_fn, iter_transform)
// Don't forget to update views::for_each whenever this set
// of concepts changes
// clang-format off
/// \concept transformable_range_
/// \brief The \c transformable_range_ concept
template(typename Rng, typename Fun)(
concept (transformable_range_)(Rng, Fun),
regular_invocable<Fun &, range_reference_t<Rng>> AND
(!std::is_void<indirect_result_t<Fun &, iterator_t<Rng>>>::value)
);
/// \concept transformable_range
/// \brief The \c transformable_range concept
template<typename Rng, typename Fun>
CPP_concept transformable_range =
viewable_range<Rng> && input_range<Rng> &&
copy_constructible<Fun> &&
CPP_concept_ref(views::transformable_range_, Rng, Fun);
/// \concept transformable_ranges_
/// \brief The \c transformable_ranges_ concept
template(typename Rng1, typename Rng2, typename Fun)(
concept (transformable_ranges_)(Rng1, Rng2, Fun),
regular_invocable<Fun &, range_reference_t<Rng1>, range_reference_t<Rng2>> AND
(!std::is_void<
indirect_result_t<Fun &, iterator_t<Rng1>, iterator_t<Rng2>>>::value)
);
/// \concept transformable_ranges
/// \brief The \c transformable_ranges concept
template<typename Rng1, typename Rng2, typename Fun>
CPP_concept transformable_ranges =
viewable_range<Rng1> && input_range<Rng1> &&
viewable_range<Rng2> && input_range<Rng2> &&
copy_constructible<Fun> &&
CPP_concept_ref(views::transformable_ranges_, Rng1, Rng2, Fun);
// clang-format on
struct transform_base_fn
{
template(typename Rng, typename Fun)(
requires transformable_range<Rng, Fun>)
constexpr transform_view<all_t<Rng>, Fun> operator()(Rng && rng, Fun fun)
const
{
return {all(static_cast<Rng &&>(rng)), std::move(fun)};
}
template(typename Rng1, typename Rng2, typename Fun)(
requires transformable_ranges<Rng1, Rng2, Fun>)
constexpr transform2_view<all_t<Rng1>, all_t<Rng2>, Fun> //
operator()(Rng1 && rng1, Rng2 && rng2, Fun fun) const
{
return {all(static_cast<Rng1 &&>(rng1)),
all(static_cast<Rng2 &&>(rng2)),
std::move(fun)};
}
};
/// # ranges::views::transform
/// The transform view takes in a function `T -> U` and converts an input
/// range of `T` into an output range of `U` by calling the function on every
/// element of the input range.
///
/// ## Example
/// \snippet example/view/transform.cpp transform example
///
/// ### Output
/// \include example/view/transform_golden.txt
///
/// ## Syntax
/// ```cpp
/// auto output_range = input_range | ranges::views::transform(transform_func);
/// ```
///
/// ## Parameters
/// <pre><b>transform_func</b></pre>
/// - Maps an input value to an output value (`transform_func(T) -> U`)
///
/// <pre><b>input_range</b></pre>
/// - The range of elements to transform
/// - Reference type: `T`
///
/// <pre><b>output_range</b></pre>
/// - The range of output values
/// - Reference type: `U`
/// - Value type: `decay_t<U>`
/// - This range will have the same category as the input range (excluding
/// contiguous ranges). Contiguous ranges are reduced to random access ranges.
///
struct transform_fn : transform_base_fn
{
using transform_base_fn::operator();
template<typename Fun>
constexpr auto operator()(Fun fun) const
{
return make_view_closure(bind_back(transform_base_fn{}, std::move(fun)));
}
};
/// \relates transform_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(transform_fn, transform)
} // namespace views
namespace cpp20
{
namespace views
{
using ranges::views::transform;
}
template(typename Rng, typename F)(
requires input_range<Rng> AND copy_constructible<F> AND view_<Rng> AND
std::is_object<F>::value AND
regular_invocable<F &, iter_reference_t<iterator_t<Rng>>>)
using transform_view = ranges::transform_view<Rng, F>;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::iter_transform_view)
RANGES_SATISFY_BOOST_RANGE(::ranges::transform_view)
#endif

View File

@@ -0,0 +1,162 @@
/// \file
// Range v3 library
//
// Copyright Johel Guerrero 2019
//
// 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_TRIM_HPP
#define RANGES_V3_VIEW_TRIM_HPP
#include <utility>
#include <concepts/concepts.hpp>
#include <range/v3/algorithm/find_if_not.hpp>
#include <range/v3/detail/config.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/compose.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/utility/optional.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename Rng, typename Pred>
struct trim_view : view_interface<trim_view<Rng, Pred>>
{
private:
Rng rng_;
semiregular_box_t<Pred> pred_;
detail::non_propagating_cache<iterator_t<Rng>> begin_;
detail::non_propagating_cache<iterator_t<Rng>> end_;
public:
CPP_assert(bidirectional_range<Rng> && view_<Rng> && indirect_unary_predicate<
Pred, iterator_t<Rng>> && common_range<Rng>);
trim_view() = default;
constexpr trim_view(Rng rng, Pred pred)
: rng_(std::move(rng))
, pred_(std::move(pred))
{}
iterator_t<Rng> begin()
{
if(!begin_)
begin_ = find_if_not(rng_, std::ref(pred_));
return *begin_;
}
iterator_t<Rng> end()
{
if(!end_)
{
const auto first = begin();
auto last = ranges::end(rng_);
while(last != first)
if(!invoke(pred_, *--last))
{
++last;
break;
}
end_ = std::move(last);
}
return *end_;
}
Rng base() const
{
return rng_;
}
};
template<typename Rng, typename Pred>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<trim_view<Rng, Pred>> = //
enable_borrowed_range<Rng>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename Rng, typename Pred>
trim_view(Rng &&, Pred) //
-> trim_view<views::all_t<Rng>, Pred>;
#endif
template<typename Rng, typename Pred>
RANGES_INLINE_VAR constexpr bool disable_sized_range<trim_view<Rng, Pred>> = true;
namespace views
{
struct trim_base_fn
{
template(typename Rng, typename Pred)(
requires viewable_range<Rng> AND bidirectional_range<Rng> AND
indirect_unary_predicate<Pred, iterator_t<Rng>> AND
common_range<Rng>)
constexpr trim_view<all_t<Rng>, Pred> //
operator()(Rng && rng, Pred pred) const //
{
return {all(static_cast<Rng &&>(rng)), std::move(pred)};
}
template(typename Rng, typename Pred, typename Proj)(
requires viewable_range<Rng> AND bidirectional_range<Rng> AND
indirect_unary_predicate<composed<Pred, Proj>, iterator_t<Rng>> AND
common_range<Rng>)
constexpr trim_view<all_t<Rng>, composed<Pred, Proj>> //
operator()(Rng && rng, Pred pred, Proj proj) const
{
return {all(static_cast<Rng &&>(rng)),
compose(std::move(pred), std::move(proj))};
}
};
struct trim_bind_fn
{
template<typename Pred>
constexpr auto operator()(Pred pred) const // TODO: underconstrained
{
return make_view_closure(bind_back(trim_base_fn{}, std::move(pred)));
}
template(typename Pred, typename Proj)(
requires (!range<Pred>)) // TODO: underconstrained
constexpr auto operator()(Pred && pred, Proj proj) const
{
return make_view_closure(bind_back(
trim_base_fn{}, static_cast<Pred &&>(pred), std::move(proj)));
}
};
struct RANGES_EMPTY_BASES trim_fn
: trim_base_fn, trim_bind_fn
{
using trim_base_fn::operator();
using trim_bind_fn::operator();
};
/// \relates trim_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(trim_fn, trim)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::trim_view)
#endif // RANGES_V3_VIEW_TRIM_HPP

View File

@@ -0,0 +1,74 @@
//
// 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_UNBOUNDED_HPP
#define RANGES_V3_VIEW_UNBOUNDED_HPP
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/unreachable_sentinel.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
template<typename I>
struct unbounded_view : view_interface<unbounded_view<I>, infinite>
{
private:
I it_;
public:
unbounded_view() = default;
constexpr explicit unbounded_view(I it)
: it_(detail::move(it))
{}
constexpr I begin() const
{
return it_;
}
constexpr unreachable_sentinel_t end() const
{
return {};
}
};
template<typename I>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<unbounded_view<I>> = true;
namespace views
{
struct unbounded_fn
{
template(typename I)(
requires input_iterator<I>)
constexpr unbounded_view<I> operator()(I it) const
{
return unbounded_view<I>{detail::move(it)};
}
};
/// \relates unbounded_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(unbounded_fn, unbounded)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::unbounded_view)
#endif

View File

@@ -0,0 +1,72 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_UNIQUE_HPP
#define RANGES_V3_VIEW_UNIQUE_HPP
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/not_fn.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adjacent_filter.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
namespace views
{
struct unique_base_fn
{
template(typename Rng, typename C = equal_to)(
requires viewable_range<Rng> AND forward_range<Rng> AND
indirect_relation<C, iterator_t<Rng>>)
constexpr adjacent_filter_view<all_t<Rng>, logical_negate<C>> //
operator()(Rng && rng, C pred = {}) const
{
return {all(static_cast<Rng &&>(rng)), not_fn(pred)};
}
};
struct unique_fn : unique_base_fn
{
using unique_base_fn::operator();
template(typename C)(
requires (!range<C>))
constexpr auto operator()(C && pred) const
{
return make_view_closure(
bind_back(unique_base_fn{}, static_cast<C &&>(pred)));
}
};
/// \relates unique_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<unique_fn>, unique)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,289 @@
/// \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_VIEW_HPP
#define RANGES_V3_VIEW_VIEW_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/compose.hpp>
#include <range/v3/functional/concepts.hpp>
#include <range/v3/functional/pipeable.hpp>
#include <range/v3/functional/reference_wrapper.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-views
/// @{
/// \cond
namespace detail
{
struct dereference_fn
{
// clang-format off
template<typename I>
constexpr auto CPP_auto_fun(operator())(I &&i) (const)
(
return *(I &&) i
)
// clang-format on
};
struct view_closure_base_
{};
} // namespace detail
/// \endcond
// clang-format off
/// \concept simple_view_impl_
/// \brief The \c simple_view_impl_ concept
template(typename Rng)(
concept (simple_view_impl_)(Rng),
same_as<iterator_t<Rng>, iterator_t<Rng const>> AND
same_as<sentinel_t<Rng>, sentinel_t<Rng const>>);
/// \concept simple_view_
/// \brief The \c simple_view_ concept
template<typename Rng>
CPP_concept simple_view_ =
view_<Rng> &&
range<Rng const> &&
CPP_concept_ref(ranges::simple_view_impl_, Rng);
/// \concept invocable_view_closure_
/// \brief The \c invocable_view_closure_ concept
template(typename ViewFn, typename Rng)(
concept (invocable_view_closure_)(ViewFn, Rng),
!derived_from<invoke_result_t<ViewFn, Rng>, detail::view_closure_base_>);
/// \concept invocable_view_closure
/// \brief The \c invocable_view_closure concept
template<typename ViewFn, typename Rng>
CPP_concept invocable_view_closure =
invocable<ViewFn, Rng> &&
CPP_concept_ref(ranges::invocable_view_closure_, ViewFn, Rng);
// clang-format on
template<typename Rng>
constexpr bool simple_view() noexcept
{
return (bool)simple_view_<Rng>;
}
struct make_view_closure_fn
{
template<typename Fun>
constexpr views::view_closure<Fun> operator()(Fun fun) const
{
return views::view_closure<Fun>{static_cast<Fun &&>(fun)};
}
};
/// \ingroup group-views
/// \sa make_view_closure_fn
RANGES_INLINE_VARIABLE(make_view_closure_fn, make_view_closure)
namespace views
{
struct RANGES_STRUCT_WITH_ADL_BARRIER(view_closure_base)
: detail::view_closure_base_
{
// Piping requires viewable_ranges. Pipeing a value into a closure
// should not yield another closure.
template(typename Rng, typename ViewFn)(
requires viewable_range<Rng> AND
invocable_view_closure<ViewFn, Rng>)
friend constexpr auto operator|(Rng && rng, view_closure<ViewFn> vw)
{
return static_cast<ViewFn &&>(vw)(static_cast<Rng &&>(rng));
}
#ifndef RANGES_WORKAROUND_CLANG_43400
// This overload is deleted because when piping a range into an
// view, it must be moved in.
template<typename Rng, typename ViewFn> // **************************
friend constexpr auto // **************************
operator|(Rng &&, view_closure<ViewFn> const &) // ******* READ THIS ********
// **** IF YOUR COMPILE *****
-> CPP_broken_friend_ret(Rng)( // ****** BREAKS HERE *******
requires range<Rng> && // **************************
(!viewable_range<Rng>)) = delete; // **************************
// **************************************************************************
// * When piping a range into an adaptor, the range must satisfy the *
// * "viewable_range" concept. A range is viewable when either or both *
// * of these things are true: *
// * - The range is an lvalue (not a temporary object), OR *
// * - The range is a view (not a container). *
// **************************************************************************
#endif
template<typename ViewFn, typename Pipeable>
friend constexpr auto operator|(view_closure<ViewFn> vw, Pipeable pipe)
-> CPP_broken_friend_ret(view_closure<composed<Pipeable, ViewFn>>)(
requires (is_pipeable_v<Pipeable>))
{
return make_view_closure(
compose(static_cast<Pipeable &&>(pipe), static_cast<ViewFn &&>(vw)));
}
};
#ifdef RANGES_WORKAROUND_CLANG_43400
namespace RANGES_ADL_BARRIER_FOR(view_closure_base)
{
// This overload is deleted because when piping a range into an
// view, it must be moved in.
template(typename Rng, typename ViewFn)( // ************************
requires range<Rng> AND (!viewable_range<Rng>))// ************************
constexpr Rng // ************************
operator|(Rng &&, view_closure<ViewFn> const &) // ****** READ THIS *******
= delete; // *** IF YOUR COMPILE ****
// ***** BREAKS HERE ******
// ************************
// ************************
// ***************************************************************************
// * When piping a range into an adaptor, the range must satisfy the *
// * "viewable_range" concept. A range is viewable when either or both *
// * of these things are true: *
// * - The range is an lvalue (not a temporary object), OR *
// * - The range is a view (not a container). *
// ***************************************************************************
} // namespace )
#endif // RANGES_WORKAROUND_CLANG_43400
template<typename ViewFn>
struct RANGES_EMPTY_BASES view_closure
: view_closure_base
, ViewFn
{
view_closure() = default;
constexpr explicit view_closure(ViewFn fn)
: ViewFn(static_cast<ViewFn &&>(fn))
{}
};
/// \cond
/// DEPRECATED STUFF
struct view_access_
{
template<typename ViewFn>
struct impl
{
// clang-format off
template<typename... Ts, typename V = ViewFn>
static constexpr auto CPP_auto_fun(bind)(Ts &&... ts)
(
return V::bind(static_cast<Ts &&>(ts)...)
)
// clang-format on
};
};
using view_access RANGES_DEPRECATED(
"view_access and views::view<> are deprecated. Please "
"replace view<> with view_closure<> and discontinue use of view_access.") =
view_access_;
template<typename>
struct old_view_;
struct make_view_fn_
{
template<typename Fun>
constexpr old_view_<Fun> operator()(Fun fun) const
{
return old_view_<Fun>{static_cast<Fun &&>(fun)};
}
};
using make_view_fn RANGES_DEPRECATED(
"make_view_fn is deprecated. Please use "
"make_view_closure instead.") = make_view_fn_;
namespace
{
RANGES_DEPRECATED(
"make_view and views::view<> has been deprecated. Please switch to "
"make_view_closure and views::view_closure.")
RANGES_INLINE_VAR constexpr auto & make_view =
static_const<make_view_fn_>::value;
} // namespace
template<typename ViewFn>
struct old_view_ : pipeable_base
{
private:
ViewFn vw_;
friend pipeable_access;
// Piping requires range arguments or lvalue containers.
template(typename Rng, typename Vw)(
requires viewable_range<Rng> AND invocable<ViewFn &, Rng>)
static constexpr auto pipe(Rng && rng, Vw && v)
{
return v.vw_(static_cast<Rng &&>(rng));
}
public:
old_view_() = default;
constexpr explicit old_view_(ViewFn a) noexcept(
std::is_nothrow_move_constructible<ViewFn>::value)
: vw_(std::move(a))
{}
// Calling directly requires a viewable_range.
template(typename Rng, typename... Rest)(
requires viewable_range<Rng> AND invocable<ViewFn const &, Rng, Rest...>)
constexpr invoke_result_t<ViewFn const &, Rng, Rest...> //
operator()(Rng && rng, Rest &&... rest) const
{
return vw_(static_cast<Rng &&>(rng), static_cast<Rest &&>(rest)...);
}
// Currying overload.
// clang-format off
template<typename... Ts, typename V = ViewFn>
constexpr auto CPP_auto_fun(operator())(Ts &&... ts)(const)
(
return make_view_fn_{}(
view_access_::impl<V>::bind(vw_, static_cast<Ts &&>(ts)...))
)
// clang-format on
};
template<typename ViewFn>
using view RANGES_DEPRECATED(
"The views::view<> template is deprecated. Please switch to view_closure") =
old_view_<ViewFn>;
/// \endcond
} // namespace views
template<typename ViewFn>
RANGES_INLINE_VAR constexpr bool is_pipeable_v<views::view_closure<ViewFn>> = true;
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,189 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_ZIP_HPP
#define RANGES_V3_VIEW_ZIP_HPP
#include <tuple>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/iterator/traits.hpp>
#include <range/v3/utility/common_tuple.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/empty.hpp>
#include <range/v3/view/zip_with.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
struct indirect_zip_fn_
{
// tuple value
template(typename... Its)(
requires (sizeof...(Its) != 2) AND and_v<indirectly_readable<Its>...>)
std::tuple<iter_value_t<Its>...> operator()(copy_tag, Its...) const
{
RANGES_EXPECT(false);
}
// tuple reference
template(typename... Its)(
requires (sizeof...(Its) != 2) AND and_v<indirectly_readable<Its>...>)
common_tuple<iter_reference_t<Its>...>
operator()(Its const &... its) const //
noexcept(meta::and_c<noexcept(iter_reference_t<Its>(*its))...>::value)
{
return common_tuple<iter_reference_t<Its>...>{*its...};
}
// tuple rvalue reference
template(typename... Its)(
requires (sizeof...(Its) != 2) AND and_v<indirectly_readable<Its>...>)
common_tuple<iter_rvalue_reference_t<Its>...> //
operator()(move_tag, Its const &... its) const //
noexcept(meta::and_c<noexcept(
iter_rvalue_reference_t<Its>(iter_move(its)))...>::value)
{
return common_tuple<iter_rvalue_reference_t<Its>...>{iter_move(its)...};
}
// pair value
template(typename It1, typename It2)(
requires indirectly_readable<It1> AND indirectly_readable<It2>)
std::pair<iter_value_t<It1>, iter_value_t<It2>> //
operator()(copy_tag, It1, It2) const
{
RANGES_EXPECT(false);
}
// pair reference
template(typename It1, typename It2)(
requires indirectly_readable<It1> AND indirectly_readable<It2>)
common_pair<iter_reference_t<It1>, iter_reference_t<It2>>
operator()(It1 const & it1, It2 const & it2) const //
noexcept( //
noexcept(iter_reference_t<It1>(*it1)) && //
noexcept(iter_reference_t<It2>(*it2)))
{
return {*it1, *it2};
}
// pair rvalue reference
template(typename It1, typename It2)(
requires indirectly_readable<It1> AND indirectly_readable<It2>)
common_pair<iter_rvalue_reference_t<It1>, iter_rvalue_reference_t<It2>>
operator()(move_tag, It1 const & it1, It2 const & it2) const
noexcept(noexcept(iter_rvalue_reference_t<It1>(iter_move(it1))) &&
noexcept(iter_rvalue_reference_t<It2>(iter_move(it2))))
{
return {iter_move(it1), iter_move(it2)};
}
};
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
template<typename... Rngs>
struct zip_view : iter_zip_with_view<detail::indirect_zip_fn_, Rngs...>
{
CPP_assert(sizeof...(Rngs) != 0);
zip_view() = default;
explicit zip_view(Rngs... rngs)
: iter_zip_with_view<detail::indirect_zip_fn_, Rngs...>{
detail::indirect_zip_fn_{},
std::move(rngs)...}
{}
};
template<typename... Rng>
RANGES_INLINE_VAR constexpr bool enable_borrowed_range<zip_view<Rng...>> =
and_v<enable_borrowed_range<Rng>...>;
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<typename... Rng>
zip_view(Rng &&...) //
-> zip_view<views::all_t<Rng>...>;
#endif
namespace views
{
struct zip_fn
{
constexpr empty_view<std::tuple<>> operator()() const noexcept
{
return {};
}
template(typename... Rngs)(
requires and_v<viewable_range<Rngs>...> AND
and_v<input_range<Rngs>...> AND
(sizeof...(Rngs) != 0)) //
zip_view<all_t<Rngs>...> operator()(Rngs &&... rngs) const
{
return zip_view<all_t<Rngs>...>{all(static_cast<Rngs &&>(rngs))...};
}
#if defined(_MSC_VER)
template(typename Rng0)(
requires input_range<Rng0> AND viewable_range<Rng0>)
constexpr zip_view<all_t<Rng0>> operator()(Rng0 && rng0) const
{
return zip_view<all_t<Rng0>>{all(static_cast<Rng0 &&>(rng0))};
}
template(typename Rng0, typename Rng1)(
requires input_range<Rng0> AND viewable_range<Rng0> AND
input_range<Rng1> AND viewable_range<Rng1>)
constexpr zip_view<all_t<Rng0>, all_t<Rng1>> //
operator()(Rng0 && rng0, Rng1 && rng1) const
{
return zip_view<all_t<Rng0>, all_t<Rng1>>{ //
all(static_cast<Rng0 &&>(rng0)), //
all(static_cast<Rng1 &&>(rng1))};
}
template(typename Rng0, typename Rng1, typename Rng2)(
requires input_range<Rng0> AND viewable_range<Rng0> AND
input_range<Rng1> AND viewable_range<Rng1> AND
input_range<Rng2> AND viewable_range<Rng2>)
constexpr zip_view<all_t<Rng0>, all_t<Rng1>, all_t<Rng2>> //
operator()(Rng0 && rng0, Rng1 && rng1, Rng2 && rng2) const
{
return zip_view<all_t<Rng0>, all_t<Rng1>, all_t<Rng2>>{ //
all(static_cast<Rng0 &&>(rng0)), //
all(static_cast<Rng1 &&>(rng1)), //
all(static_cast<Rng2 &&>(rng2))};
}
#endif
};
/// \relates zip_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(zip_fn, zip)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::zip_view)
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,452 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-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_ZIP_WITH_HPP
#define RANGES_V3_VIEW_ZIP_WITH_HPP
#include <limits>
#include <tuple>
#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/functional/indirect.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/common_type.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/utility/tuple_algorithm.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/empty.hpp>
#include <range/v3/view/facade.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
struct equal_to_
{
template<typename T, typename U>
bool operator()(T const & t, U const & u) const
{
return static_cast<bool>(t == u);
}
};
RANGES_INLINE_VARIABLE(equal_to_, equal_to)
struct dec_
{
template<typename T>
void operator()(T & t) const
{
--t;
}
};
RANGES_INLINE_VARIABLE(dec_, dec)
struct inc_
{
template<typename T>
void operator()(T & t) const
{
++t;
}
};
RANGES_INLINE_VARIABLE(inc_, inc)
struct _advance_
{
template(typename I, typename Diff)(
requires input_or_output_iterator<I> AND integer_like_<Diff>)
void operator()(I & i, Diff n) const
{
advance(i, static_cast<iter_difference_t<I>>(n));
}
};
RANGES_INLINE_VARIABLE(_advance_, advance_)
struct distance_to_
{
template<typename T>
constexpr auto operator()(T const & t, T const & u) const -> decltype(u - t)
{
return u - t;
}
};
RANGES_INLINE_VARIABLE(distance_to_, distance_to)
struct _min_
{
template<typename T, typename U>
constexpr auto operator()(T const & t, U const & u) const
-> decltype(true ? t : u)
{
return u < t ? u : t;
}
};
RANGES_INLINE_VARIABLE(_min_, min_)
struct _max_
{
template<typename T, typename U>
constexpr auto operator()(T const & t, U const & u) const
-> decltype(true ? u : t)
{
return u < t ? t : u;
}
};
RANGES_INLINE_VARIABLE(_max_, max_)
template<typename State, typename Value>
using zip_cardinality = std::integral_constant<
cardinality,
State::value >= 0 && Value::value >= 0
? min_(State::value, Value::value)
: State::value >=0 && Value::value == infinite
? State::value
: State::value == infinite && Value::value >= 0
? Value::value
: State::value == finite || Value::value == finite
? finite
: State::value == unknown || Value::value == unknown
? unknown
: infinite>;
} // namespace detail
/// \endcond
namespace views
{
// clang-format off
/// \concept zippable_with_
/// \brief The \c zippable_with_ concept
template(typename Fun, typename... Rngs)(
concept (zippable_with_)(Fun, Rngs...),
invocable<Fun&, iterator_t<Rngs>...> AND
invocable<Fun&, copy_tag, iterator_t<Rngs>...> AND
invocable<Fun&, move_tag, iterator_t<Rngs>...>
);
/// \concept zippable_with
/// \brief The \c zippable_with concept
template<typename Fun, typename ...Rngs>
CPP_concept zippable_with =
and_v<input_range<Rngs>...> &&
copy_constructible<Fun> &&
CPP_concept_ref(views::zippable_with_, Fun, Rngs...);
// clang-format on
} // namespace views
/// \addtogroup group-views
/// @{
template<typename Fun, typename... Rngs>
struct iter_zip_with_view
: view_facade<iter_zip_with_view<Fun, Rngs...>,
meta::fold<meta::list<range_cardinality<Rngs>...>,
std::integral_constant<cardinality, cardinality::infinite>,
meta::quote<detail::zip_cardinality>>::value>
{
private:
CPP_assert(sizeof...(Rngs) != 0);
friend range_access;
semiregular_box_t<Fun> fun_;
std::tuple<Rngs...> rngs_;
using difference_type_ = common_type_t<range_difference_t<Rngs>...>;
template<bool Const>
struct cursor;
template<bool Const>
struct sentinel
{
private:
friend struct cursor<Const>;
friend struct sentinel<!Const>;
std::tuple<sentinel_t<meta::const_if_c<Const, Rngs>>...> ends_;
public:
sentinel() = default;
sentinel(detail::ignore_t,
std::tuple<sentinel_t<meta::const_if_c<Const, Rngs>>...> ends)
: ends_(std::move(ends))
{}
template(bool Other)(
requires Const AND CPP_NOT(Other)) //
sentinel(sentinel<Other> that)
: ends_(std::move(that.ends_))
{}
};
template<bool Const>
struct cursor
{
private:
friend struct cursor<!Const>;
using fun_ref_ = semiregular_box_ref_or_val_t<Fun, Const>;
fun_ref_ fun_;
std::tuple<iterator_t<meta::const_if_c<Const, Rngs>>...> its_;
public:
using difference_type =
common_type_t<range_difference_t<meta::const_if_c<Const, Rngs>>...>;
using single_pass = meta::or_c<(
bool)single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rngs>>>...>;
using value_type = detail::decay_t<invoke_result_t<
fun_ref_ &, copy_tag, iterator_t<meta::const_if_c<Const, Rngs>>...>>;
cursor() = default;
cursor(fun_ref_ fun,
std::tuple<iterator_t<meta::const_if_c<Const, Rngs>>...> its)
: fun_(std::move(fun))
, its_(std::move(its))
{}
template(bool Other)(
requires Const AND CPP_NOT(Other)) //
cursor(cursor<Other> that)
: fun_(std::move(that.fun_))
, its_(std::move(that.its_))
{}
// clang-format off
auto CPP_auto_fun(read)()(const)
(
return tuple_apply(fun_, its_)
)
// clang-format on
void next()
{
tuple_for_each(its_, detail::inc);
}
CPP_member
auto equal(cursor const & that) const //
-> CPP_ret(bool)(
requires and_v<
sentinel_for<iterator_t<meta::const_if_c<Const, Rngs>>,
iterator_t<meta::const_if_c<Const, Rngs>>>...>)
{
// By returning true if *any* of the iterators are equal, we allow
// zipped ranges to be of different lengths, stopping when the first
// one reaches the last.
return tuple_foldl(tuple_transform(its_, that.its_, detail::equal_to),
false,
[](bool a, bool b) { return a || b; });
}
bool equal(sentinel<Const> const & s) const
{
// By returning true if *any* of the iterators are equal, we allow
// zipped ranges to be of different lengths, stopping when the first
// one reaches the last.
return tuple_foldl(tuple_transform(its_, s.ends_, detail::equal_to),
false,
[](bool a, bool b) { return a || b; });
}
CPP_member
auto prev() //
-> CPP_ret(void)(
requires and_v<bidirectional_range<meta::const_if_c<Const, Rngs>>...>)
{
tuple_for_each(its_, detail::dec);
}
CPP_member
auto advance(difference_type n) //
-> CPP_ret(void)(
requires and_v<random_access_range<meta::const_if_c<Const, Rngs>>...>)
{
tuple_for_each(its_, bind_back(detail::advance_, n));
}
CPP_member
auto distance_to(cursor const & that) const //
-> CPP_ret(difference_type)(
requires and_v<
sized_sentinel_for<iterator_t<meta::const_if_c<Const, Rngs>>,
iterator_t<meta::const_if_c<Const, Rngs>>>...>)
{
// Return the smallest distance (in magnitude) of any of the iterator
// pairs. This is to accommodate zippers of sequences of different length.
if(0 < std::get<0>(that.its_) - std::get<0>(its_))
return tuple_foldl(
tuple_transform(its_, that.its_, detail::distance_to),
(std::numeric_limits<difference_type>::max)(),
detail::min_);
else
return tuple_foldl(
tuple_transform(its_, that.its_, detail::distance_to),
(std::numeric_limits<difference_type>::min)(),
detail::max_);
}
// clang-format off
template<std::size_t... Is>
auto CPP_auto_fun(move_)(meta::index_sequence<Is...>)(const)
(
return invoke(fun_, move_tag{}, std::get<Is>(its_)...)
)
// clang-format on
auto move() const noexcept(noexcept(std::declval<cursor const &>().move_(
meta::make_index_sequence<sizeof...(Rngs)>{})))
-> decltype(std::declval<cursor const &>().move_(
meta::make_index_sequence<sizeof...(Rngs)>{}))
{
return move_(meta::make_index_sequence<sizeof...(Rngs)>{});
}
};
template<bool Const>
using end_cursor_t =
meta::if_c<concepts::and_v<(bool)common_range<Rngs>...,
!(bool)single_pass_iterator_<iterator_t<Rngs>>...>,
cursor<Const>, sentinel<Const>>;
cursor<false> begin_cursor()
{
return {fun_, tuple_transform(rngs_, ranges::begin)};
}
end_cursor_t<false> end_cursor()
{
return {fun_, tuple_transform(rngs_, ranges::end)};
}
template(bool Const = true)(
requires Const AND and_v<range<Rngs const>...> AND
views::zippable_with<Fun, meta::if_c<Const, Rngs const>...>)
cursor<Const> begin_cursor() const
{
return {fun_, tuple_transform(rngs_, ranges::begin)};
}
template(bool Const = true)(
requires Const AND and_v<range<Rngs const>...> AND
views::zippable_with<Fun, meta::if_c<Const, Rngs const>...>)
end_cursor_t<Const> end_cursor() const
{
return {fun_, tuple_transform(rngs_, ranges::end)};
}
public:
iter_zip_with_view() = default;
explicit iter_zip_with_view(Rngs... rngs)
: fun_(Fun{})
, rngs_{std::move(rngs)...}
{}
explicit iter_zip_with_view(Fun fun, Rngs... rngs)
: fun_(std::move(fun))
, rngs_{std::move(rngs)...}
{}
CPP_auto_member
constexpr auto CPP_fun(size)()(const //
requires and_v<sized_range<Rngs const>...>)
{
using size_type = common_type_t<range_size_t<Rngs const>...>;
return range_cardinality<iter_zip_with_view>::value >= 0
? size_type{(
std::size_t)range_cardinality<iter_zip_with_view>::value}
: tuple_foldl(tuple_transform(rngs_,
[](auto && r) -> size_type {
return ranges::size(r);
}),
(std::numeric_limits<size_type>::max)(),
detail::min_);
}
};
template<typename Fun, typename... Rngs>
struct zip_with_view : iter_zip_with_view<indirected<Fun>, Rngs...>
{
CPP_assert(sizeof...(Rngs) != 0);
zip_with_view() = default;
explicit zip_with_view(Rngs... rngs)
: iter_zip_with_view<indirected<Fun>, Rngs...>{{Fun{}}, std::move(rngs)...}
{}
explicit zip_with_view(Fun fun, Rngs... rngs)
: iter_zip_with_view<indirected<Fun>, Rngs...>{{std::move(fun)},
std::move(rngs)...}
{}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Fun, typename... Rng)(
requires copy_constructible<Fun>)
zip_with_view(Fun, Rng &&...)
-> zip_with_view<Fun, views::all_t<Rng>...>;
#endif
namespace views
{
struct iter_zip_with_fn
{
template(typename... Rngs, typename Fun)(
requires and_v<viewable_range<Rngs>...> AND
zippable_with<Fun, Rngs...> AND (sizeof...(Rngs) != 0)) //
iter_zip_with_view<Fun, all_t<Rngs>...> //
operator()(Fun fun, Rngs &&... rngs) const
{
return iter_zip_with_view<Fun, all_t<Rngs>...>{
std::move(fun), all(static_cast<Rngs &&>(rngs))...};
}
template(typename Fun)(
requires zippable_with<Fun>) //
constexpr empty_view<detail::decay_t<invoke_result_t<Fun &>>>
operator()(Fun) const noexcept
{
return {};
}
};
/// \relates iter_zip_with_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(iter_zip_with_fn, iter_zip_with)
struct zip_with_fn
{
template(typename... Rngs, typename Fun)(
requires and_v<viewable_range<Rngs>...> AND
and_v<input_range<Rngs>...> AND copy_constructible<Fun> AND
invocable<Fun &, range_reference_t<Rngs>...> AND
(sizeof...(Rngs) != 0)) //
zip_with_view<Fun, all_t<Rngs>...> operator()(Fun fun, Rngs &&... rngs) const
{
return zip_with_view<Fun, all_t<Rngs>...>{
std::move(fun), all(static_cast<Rngs &&>(rngs))...};
}
template(typename Fun)(
requires copy_constructible<Fun> AND invocable<Fun &>) //
constexpr empty_view<detail::decay_t<invoke_result_t<Fun &>>>
operator()(Fun) const noexcept
{
return {};
}
};
/// \relates zip_with_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(zip_with_fn, zip_with)
} // namespace views
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::iter_zip_with_view)
RANGES_SATISFY_BOOST_RANGE(::ranges::zip_with_view)
#endif