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,304 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-present
// 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_ITERATOR_ACCESS_HPP
#define RANGES_V3_ITERATOR_ACCESS_HPP
#include <iterator>
#include <type_traits>
#include <utility>
#include <std/detail/associated_types.hpp>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/utility/move.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/utility/swap.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator
/// @{
/// \cond
namespace detail
{
template<typename I,
#ifdef RANGES_WORKAROUND_MSVC_683388
typename R = meta::conditional_t<
std::is_pointer<uncvref_t<I>>::value &&
std::is_array<std::remove_pointer_t<uncvref_t<I>>>::value,
std::add_lvalue_reference_t<std::remove_pointer_t<uncvref_t<I>>>,
decltype(*std::declval<I &>())>,
#else
typename R = decltype(*std::declval<I &>()),
#endif
typename = R &>
using iter_reference_t_ = R;
#if defined(RANGES_DEEP_STL_INTEGRATION) && RANGES_DEEP_STL_INTEGRATION && \
!defined(RANGES_DOXYGEN_INVOKED)
template<typename T>
using iter_value_t_ =
typename meta::conditional_t<
is_std_iterator_traits_specialized_v<T>,
std::iterator_traits<T>,
indirectly_readable_traits<T>>::value_type;
#else
template<typename T>
using iter_value_t_ = typename indirectly_readable_traits<T>::value_type;
#endif
} // namespace detail
/// \endcond
template<typename R>
using iter_reference_t = detail::iter_reference_t_<R>;
template<typename R>
using iter_value_t = detail::iter_value_t_<uncvref_t<R>>;
/// \cond
namespace _iter_move_
{
#if RANGES_BROKEN_CPO_LOOKUP
void iter_move(); // unqualified name lookup block
#endif
template<typename T>
decltype(iter_move(std::declval<T>())) try_adl_iter_move_(int);
template<typename T>
void try_adl_iter_move_(long);
template<typename T>
RANGES_INLINE_VAR constexpr bool is_adl_indirectly_movable_v =
!RANGES_IS_SAME(void, decltype(_iter_move_::try_adl_iter_move_<T>(42)));
struct fn
{
// clang-format off
template<typename I,
typename = detail::enable_if_t<is_adl_indirectly_movable_v<I &>>>
#ifndef RANGES_WORKAROUND_CLANG_23135
constexpr
#endif // RANGES_WORKAROUND_CLANG_23135
auto CPP_auto_fun(operator())(I &&i)(const)
(
return iter_move(i)
)
template<
typename I,
typename = detail::enable_if_t<!is_adl_indirectly_movable_v<I &>>,
typename R = iter_reference_t<I>>
#ifndef RANGES_WORKAROUND_CLANG_23135
constexpr
#endif // RANGES_WORKAROUND_CLANG_23135
auto CPP_auto_fun(operator())(I &&i)(const)
(
return static_cast<aux::move_t<R>>(aux::move(*i))
)
// clang-format on
};
} // namespace _iter_move_
/// \endcond
RANGES_DEFINE_CPO(_iter_move_::fn, iter_move)
/// \cond
namespace detail
{
template<typename I, typename O>
auto is_indirectly_movable_(I & (*i)(), O & (*o)(), iter_value_t<I> * v = nullptr)
-> always_<std::true_type,
decltype(iter_value_t<I>(iter_move(i()))),
decltype(*v = iter_move(i())),
decltype(*o() = (iter_value_t<I> &&) * v),
decltype(*o() = iter_move(i()))>;
template<typename I, typename O>
auto is_indirectly_movable_(...) -> std::false_type;
template<typename I, typename O>
auto is_nothrow_indirectly_movable_(iter_value_t<I> * v) -> meta::bool_<
noexcept(iter_value_t<I>(iter_move(std::declval<I &>()))) &&
noexcept(*v = iter_move(std::declval<I &>())) &&
noexcept(*std::declval<O &>() = (iter_value_t<I> &&) * v) &&
noexcept(*std::declval<O &>() = iter_move(std::declval<I &>()))>;
template<typename I, typename O>
auto is_nothrow_indirectly_movable_(...) -> std::false_type;
} // namespace detail
/// \endcond
template<typename I, typename O>
RANGES_INLINE_VAR constexpr bool is_indirectly_movable_v =
decltype(detail::is_indirectly_movable_<I, O>(nullptr, nullptr))::value;
template<typename I, typename O>
RANGES_INLINE_VAR constexpr bool is_nothrow_indirectly_movable_v =
decltype(detail::is_nothrow_indirectly_movable_<I, O>(nullptr))::value;
template<typename I, typename O>
struct is_indirectly_movable : meta::bool_<is_indirectly_movable_v<I, O>>
{};
template<typename I, typename O>
struct is_nothrow_indirectly_movable
: meta::bool_<is_nothrow_indirectly_movable_v<I, O>>
{};
/// \cond
namespace _iter_swap_
{
struct nope
{};
// Q: Should std::reference_wrapper be considered a proxy wrt swapping rvalues?
// A: No. Its operator= is currently defined to reseat the references, so
// std::swap(ra, rb) already means something when ra and rb are (lvalue)
// reference_wrappers. That reseats the reference wrappers but leaves the
// referents unmodified. Treating rvalue reference_wrappers differently would
// be confusing.
// Q: Then why is it OK to "re"-define swap for pairs and tuples of references?
// A: Because as defined above, swapping an rvalue tuple of references has the
// same semantics as swapping an lvalue tuple of references. Rather than
// reseat the references, assignment happens *through* the references.
// Q: But I have an iterator whose operator* returns an rvalue
// std::reference_wrapper<T>. How do I make it model indirectly_swappable?
// A: With an overload of iter_swap.
// Intentionally create an ambiguity with std::iter_swap, which is
// unconstrained.
template<typename T, typename U>
nope iter_swap(T, U) = delete;
#ifdef RANGES_WORKAROUND_MSVC_895622
nope iter_swap();
#endif
template<typename T, typename U>
decltype(iter_swap(std::declval<T>(), std::declval<U>())) try_adl_iter_swap_(int);
template<typename T, typename U>
nope try_adl_iter_swap_(long);
// Test whether an overload of iter_swap for a T and a U can be found
// via ADL with the iter_swap overload above participating in the
// overload set. This depends on user-defined iter_swap overloads
// being a better match than the overload in namespace std.
template<typename T, typename U>
RANGES_INLINE_VAR constexpr bool is_adl_indirectly_swappable_v =
!RANGES_IS_SAME(nope, decltype(_iter_swap_::try_adl_iter_swap_<T, U>(42)));
struct fn
{
// *If* a user-defined iter_swap is found via ADL, call that:
template<typename T, typename U>
constexpr detail::enable_if_t<is_adl_indirectly_swappable_v<T, U>> operator()(
T && t, U && u) const noexcept(noexcept(iter_swap((T &&) t, (U &&) u)))
{
(void)iter_swap((T &&) t, (U &&) u);
}
// *Otherwise*, for readable types with swappable reference
// types, call ranges::swap(*a, *b)
template<typename I0, typename I1>
constexpr detail::enable_if_t<
!is_adl_indirectly_swappable_v<I0, I1> &&
is_swappable_with<iter_reference_t<I0>, iter_reference_t<I1>>::value>
operator()(I0 && a, I1 && b) const noexcept(noexcept(ranges::swap(*a, *b)))
{
ranges::swap(*a, *b);
}
// *Otherwise*, for readable types that are mutually
// indirectly_movable_storable, implement as:
// iter_value_t<T0> tmp = iter_move(a);
// *a = iter_move(b);
// *b = std::move(tmp);
template<typename I0, typename I1>
constexpr detail::enable_if_t<
!is_adl_indirectly_swappable_v<I0, I1> &&
!is_swappable_with<iter_reference_t<I0>, iter_reference_t<I1>>::value &&
is_indirectly_movable_v<I0, I1> && is_indirectly_movable_v<I1, I0>>
operator()(I0 && a, I1 && b) const
noexcept(is_nothrow_indirectly_movable_v<I0, I1> &&
is_nothrow_indirectly_movable_v<I1, I0>)
{
iter_value_t<I0> v0 = iter_move(a);
*a = iter_move(b);
*b = detail::move(v0);
}
};
} // namespace _iter_swap_
/// \endcond
/// \relates _iter_swap_::fn
RANGES_DEFINE_CPO(_iter_swap_::fn, iter_swap)
/// \cond
namespace detail
{
template<typename T, typename U>
auto is_indirectly_swappable_(T & (*t)(), U & (*u)())
-> detail::always_<std::true_type, decltype(iter_swap(t(), u()))>;
template<typename T, typename U>
auto is_indirectly_swappable_(...) -> std::false_type;
template<typename T, typename U>
auto is_nothrow_indirectly_swappable_(int)
-> meta::bool_<noexcept(iter_swap(std::declval<T &>(), std::declval<U &>()))>;
template<typename T, typename U>
auto is_nothrow_indirectly_swappable_(long) -> std::false_type;
} // namespace detail
/// \endcond
template<typename T, typename U>
RANGES_INLINE_VAR constexpr bool is_indirectly_swappable_v =
decltype(detail::is_indirectly_swappable_<T, U>(nullptr, nullptr))::value;
template<typename T, typename U>
RANGES_INLINE_VAR constexpr bool is_nothrow_indirectly_swappable_v =
decltype(detail::is_nothrow_indirectly_swappable_<T, U>(0))::value;
template<typename T, typename U>
struct is_indirectly_swappable : meta::bool_<is_indirectly_swappable_v<T, U>>
{};
template<typename T, typename U>
struct is_nothrow_indirectly_swappable
: meta::bool_<is_nothrow_indirectly_swappable_v<T, U>>
{};
namespace cpp20
{
using ranges::iter_move;
using ranges::iter_reference_t;
using ranges::iter_swap;
using ranges::iter_value_t;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_ITERATOR_ACCESS_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,462 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2014-present
// 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_ITERATOR_COMMON_ITERATOR_HPP
#define RANGES_V3_ITERATOR_COMMON_ITERATOR_HPP
#include <cstdint>
#include <iterator>
#include <type_traits>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/detail/variant.hpp>
#include <range/v3/iterator/basic_iterator.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/utility/common_tuple.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator
/// @{
/// \cond
namespace detail
{
template<typename I, typename S>
variant<I, S> & cidata(common_iterator<I, S> & that)
{
return that.data_;
}
template<typename I, typename S>
variant<I, S> const & cidata(common_iterator<I, S> const & that)
{
return that.data_;
}
} // namespace detail
#if RANGES_BROKEN_CPO_LOOKUP
namespace _common_iterator_
{
struct adl_hook
{};
} // namespace _common_iterator_
#endif
/// \endcond
template<typename I, typename S>
struct common_iterator
#if RANGES_BROKEN_CPO_LOOKUP
: private _common_iterator_::adl_hook
#endif
{
private:
CPP_assert(input_or_output_iterator<I>);
CPP_assert(sentinel_for<S, I>);
CPP_assert(!same_as<I, S>);
variant<I, S> data_;
friend variant<I, S> & detail::cidata<>(common_iterator<I, S> &);
friend variant<I, S> const & detail::cidata<>(common_iterator<I, S> const &);
struct emplace_fn
{
variant<I, S> * data_;
template<typename T, std::size_t N>
void operator()(indexed_element<T, N> t) const
{
ranges::emplace<N>(*data_, t.get());
}
};
struct arrow_proxy_
{
private:
friend common_iterator;
iter_value_t<I> keep_;
arrow_proxy_(iter_reference_t<I> && x)
: keep_(std::move(x))
{}
public:
const iter_value_t<I> * operator->() const noexcept
{
return std::addressof(keep_);
}
};
template<typename T>
static T * operator_arrow_(T * p, int) noexcept
{
return p;
}
template<typename J, typename = detail::iter_arrow_t<J const>>
static J operator_arrow_(J const & j, int) noexcept(noexcept(J(j)))
{
return j;
}
template(typename J, typename R = iter_reference_t<J>)(
requires std::is_reference<R>::value) //
static meta::_t<std::add_pointer<R>> operator_arrow_(J const & j, long) noexcept
{
auto && r = *j;
return std::addressof(r);
}
template(typename J, typename V = iter_value_t<J>)(
requires constructible_from<V, iter_reference_t<J>>)
static arrow_proxy_ operator_arrow_(J const & j, ...) noexcept(noexcept(V(V(*j))))
{
return arrow_proxy_(*j);
}
public:
using difference_type = iter_difference_t<I>;
common_iterator() = default;
common_iterator(I i)
: data_(emplaced_index<0>, std::move(i))
{}
common_iterator(S s)
: data_(emplaced_index<1>, std::move(s))
{}
template(typename I2, typename S2)(
requires convertible_to<I2, I> AND convertible_to<S2, S>)
common_iterator(common_iterator<I2, S2> const & that)
: data_(detail::variant_core_access::make_empty<I, S>())
{
detail::cidata(that).visit_i(emplace_fn{&data_});
}
template(typename I2, typename S2)(
requires convertible_to<I2, I> AND convertible_to<S2, S>)
common_iterator & operator=(common_iterator<I2, S2> const & that)
{
detail::cidata(that).visit_i(emplace_fn{&data_});
return *this;
}
iter_reference_t<I> operator*() //
noexcept(noexcept(iter_reference_t<I>(*std::declval<I &>())))
{
return *ranges::get<0>(data_);
}
CPP_member
auto operator*() const //
noexcept(noexcept(iter_reference_t<I>(*std::declval<I const &>())))
-> CPP_ret(iter_reference_t<I>)(
requires indirectly_readable<I const>)
{
return *ranges::get<0>(data_);
}
template(typename J = I)(
requires indirectly_readable<J>)
auto operator->() const //
noexcept(
noexcept(common_iterator::operator_arrow_(std::declval<I const &>(), 42)))
-> decltype(common_iterator::operator_arrow_(std::declval<J const &>(), 42))
{
return common_iterator::operator_arrow_(ranges::get<0>(data_), 42);
}
common_iterator & operator++()
{
++ranges::get<0>(data_);
return *this;
}
#ifdef RANGES_WORKAROUND_MSVC_677925
template(typename I2 = I)(
requires (!forward_iterator<I2>)) //
auto operator++(int) //
-> decltype(std::declval<I2 &>()++)
{
return ranges::get<0>(data_)++;
}
#else // ^^^ workaround ^^^ / vvv no workaround vvv
CPP_member
auto operator++(int) //
-> CPP_ret(decltype(std::declval<I &>()++))(
requires (!forward_iterator<I>))
{
return ranges::get<0>(data_)++;
}
#endif // RANGES_WORKAROUND_MSVC_677925
CPP_member
auto operator++(int) //
-> CPP_ret(common_iterator)(
requires forward_iterator<I>)
{
return common_iterator(ranges::get<0>(data_)++);
}
#if !RANGES_BROKEN_CPO_LOOKUP
template<typename I_ = I>
friend constexpr auto iter_move(common_iterator const & i) //
noexcept(detail::has_nothrow_iter_move_v<I>)
-> CPP_broken_friend_ret(iter_rvalue_reference_t<I>)(
requires input_iterator<I_>)
{
return ranges::iter_move(ranges::get<0>(detail::cidata(i)));
}
template<typename I2, typename S2>
friend auto iter_swap(
common_iterator const & x,
common_iterator<I2, S2> const &
y) noexcept(is_nothrow_indirectly_swappable<I, I2>::value)
-> CPP_broken_friend_ret(void)(
requires indirectly_swappable<I2, I>)
{
return ranges::iter_swap(ranges::get<0>(detail::cidata(x)),
ranges::get<0>(detail::cidata(y)));
}
#endif
};
/// \cond
#if RANGES_BROKEN_CPO_LOOKUP
namespace _common_iterator_
{
template<typename I, typename S>
constexpr auto iter_move(common_iterator<I, S> const & i) noexcept(
detail::has_nothrow_iter_move_v<I>)
-> CPP_broken_friend_ret(iter_rvalue_reference_t<I>)(
requires input_iterator<I>)
{
return ranges::iter_move(ranges::get<0>(detail::cidata(i)));
}
template<typename I1, typename S1, typename I2, typename S2>
auto iter_swap(common_iterator<I1, S1> const & x,
common_iterator<I2, S2> const & y) //
noexcept(is_nothrow_indirectly_swappable<I1, I2>::value)
-> CPP_broken_friend_ret(void)(
requires indirectly_swappable<I1, I2>)
{
return ranges::iter_swap(ranges::get<0>(detail::cidata(x)),
ranges::get<0>(detail::cidata(y)));
}
} // namespace _common_iterator_
#endif
/// \endcond
template(typename I1, typename I2, typename S1, typename S2)(
requires sentinel_for<S1, I2> AND sentinel_for<S2, I1> AND
(!equality_comparable_with<I1, I2>)) //
bool operator==(common_iterator<I1, S1> const & x, common_iterator<I2, S2> const & y)
{
return detail::cidata(x).index() == 1u ? (detail::cidata(y).index() == 1u ||
ranges::get<0>(detail::cidata(y)) ==
ranges::get<1>(detail::cidata(x)))
: (detail::cidata(y).index() != 1u ||
ranges::get<0>(detail::cidata(x)) ==
ranges::get<1>(detail::cidata(y)));
}
template(typename I1, typename I2, typename S1, typename S2)(
requires sentinel_for<S1, I2> AND sentinel_for<S2, I1> AND
equality_comparable_with<I1, I2>)
bool operator==(common_iterator<I1, S1> const & x, common_iterator<I2, S2> const & y)
{
return detail::cidata(x).index() == 1u
? (detail::cidata(y).index() == 1u ||
ranges::get<0>(detail::cidata(y)) ==
ranges::get<1>(detail::cidata(x)))
: (detail::cidata(y).index() == 1u
? ranges::get<0>(detail::cidata(x)) ==
ranges::get<1>(detail::cidata(y))
: ranges::get<0>(detail::cidata(x)) ==
ranges::get<0>(detail::cidata(y)));
}
template(typename I1, typename I2, typename S1, typename S2)(
requires sentinel_for<S1, I2> AND sentinel_for<S2, I1>)
bool operator!=(common_iterator<I1, S1> const & x, common_iterator<I2, S2> const & y)
{
return !(x == y);
}
template(typename I1, typename I2, typename S1, typename S2)(
requires sized_sentinel_for<I1, I2> AND sized_sentinel_for<S1, I2> AND
sized_sentinel_for<S2, I1>)
iter_difference_t<I2> operator-(common_iterator<I1, S1> const & x,
common_iterator<I2, S2> const & y)
{
return detail::cidata(x).index() == 1u
? (detail::cidata(y).index() == 1u
? 0
: ranges::get<1>(detail::cidata(x)) -
ranges::get<0>(detail::cidata(y)))
: (detail::cidata(y).index() == 1u
? ranges::get<0>(detail::cidata(x)) -
ranges::get<1>(detail::cidata(y))
: ranges::get<0>(detail::cidata(x)) -
ranges::get<0>(detail::cidata(y)));
}
template<typename I, typename S>
struct indirectly_readable_traits<common_iterator<I, S>>
: meta::if_c<
(bool)indirectly_readable<I>,
indirectly_readable_traits<I>,
meta::nil_>
{};
/// \cond
namespace detail
{
template<typename I>
auto demote_common_iter_cat(...) -> nil_;
template<typename I>
auto demote_common_iter_cat(long)
-> with_iterator_category<std::input_iterator_tag>;
template(typename I)(
requires derived_from<typename std::iterator_traits<I>::iterator_category,
std::forward_iterator_tag>)
auto demote_common_iter_cat(int)
-> with_iterator_category<std::forward_iterator_tag>;
template<typename I, bool = (bool)input_iterator<I>>
struct common_iterator_std_traits : decltype(detail::demote_common_iter_cat<I>(0))
{
using difference_type = iter_difference_t<I>;
using value_type = iter_value_t<I>;
using reference = iter_reference_t<I>;
using pointer = detail::iter_pointer_t<I>;
using iterator_concept =
meta::conditional_t<(bool)forward_iterator<I>, std::forward_iterator_tag,
std::input_iterator_tag>;
};
template<typename I>
struct common_iterator_std_traits<I, false>
{
using difference_type = iter_difference_t<I>;
using value_type = void;
using reference = void;
using pointer = void;
using iterator_category = std::output_iterator_tag;
};
// An iterator adaptor that demotes a user-defined difference_type to
// std::intmax_t, for use when constructing containers from such
// iterators.
template<typename I>
struct cpp17_iterator_cursor
{
private:
friend range_access;
I it_;
struct mixin : basic_mixin<cpp17_iterator_cursor>
{
mixin() = default;
#ifndef _MSC_VER
using basic_mixin<cpp17_iterator_cursor>::basic_mixin;
#else
constexpr explicit mixin(cpp17_iterator_cursor && cur)
: basic_mixin<cpp17_iterator_cursor>(
static_cast<cpp17_iterator_cursor &&>(cur))
{}
constexpr explicit mixin(cpp17_iterator_cursor const & cur)
: basic_mixin<cpp17_iterator_cursor>(cur)
{}
#endif
explicit mixin(I it)
: mixin{cpp17_iterator_cursor{std::move(it)}}
{}
I base() const
{
return this->get().it_;
}
};
public:
using single_pass = meta::bool_<!forward_iterator<I>>;
using difference_type = std::ptrdiff_t;
using value_type = iter_value_t<I>;
cpp17_iterator_cursor() = default;
constexpr explicit cpp17_iterator_cursor(I i)
: it_(static_cast<I &&>(i))
{}
I arrow() const
{
return it_;
}
decltype(auto) read()
{
return *it_;
}
decltype(auto) read() const
{
return *it_;
}
void next()
{
++it_;
}
bool equal(cpp17_iterator_cursor const & that) const
{
return it_ == that.it_;
}
CPP_member
auto prev() //
-> CPP_ret(void)(
requires bidirectional_iterator<I>)
{
--it_;
}
CPP_member
auto advance(std::ptrdiff_t n) //
-> CPP_ret(void)(
requires random_access_iterator<I>)
{
it_ += static_cast<iter_difference_t<I>>(n);
}
CPP_member
auto distance_to(cpp17_iterator_cursor const & that) //
-> CPP_ret(std::ptrdiff_t)(
requires random_access_iterator<I>)
{
auto d = that.it_ - it_;
RANGES_EXPECT(d <= PTRDIFF_MAX);
return static_cast<std::ptrdiff_t>(d);
}
};
} // namespace detail
/// \endcond
namespace cpp20
{
using ranges::common_iterator;
}
/// @}
} // namespace ranges
/// \cond
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
namespace std
{
template<typename I, typename S>
struct iterator_traits<::ranges::common_iterator<I, S>>
: ::ranges::detail::common_iterator_std_traits<I>
{};
} // namespace std
RANGES_DIAGNOSTIC_POP
/// \endcond
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,990 @@
/// \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_ITERATOR_CONCEPTS_HPP
#define RANGES_V3_ITERATOR_CONCEPTS_HPP
#include <iterator>
#include <type_traits>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/comparisons.hpp>
#include <range/v3/functional/concepts.hpp>
#include <range/v3/functional/identity.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/iterator/access.hpp>
#include <range/v3/iterator/traits.hpp>
#ifdef _GLIBCXX_DEBUG
#include <debug/safe_iterator.h>
#endif
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator-concepts
/// @{
/// \cond
namespace detail
{
template<typename I>
using iter_traits_t = meta::conditional_t<is_std_iterator_traits_specialized_v<I>,
std::iterator_traits<I>, I>;
#if defined(_GLIBCXX_DEBUG)
template(typename I, typename T, typename Seq)(
requires same_as<I, __gnu_debug::_Safe_iterator<T *, Seq>>)
auto iter_concept_(__gnu_debug::_Safe_iterator<T *, Seq>, priority_tag<3>)
-> ranges::contiguous_iterator_tag;
#endif
#if defined(__GLIBCXX__)
template(typename I, typename T, typename Seq)(
requires same_as<I, __gnu_cxx::__normal_iterator<T *, Seq>>)
auto iter_concept_(__gnu_cxx::__normal_iterator<T *, Seq>, priority_tag<3>)
-> ranges::contiguous_iterator_tag;
#endif
#if defined(_LIBCPP_VERSION)
template(typename I, typename T)(
requires same_as<I, std::__wrap_iter<T *>>)
auto iter_concept_(std::__wrap_iter<T *>, priority_tag<3>)
-> ranges::contiguous_iterator_tag;
#endif
#if defined(_MSVC_STL_VERSION) || defined(_IS_WRS)
template(typename I)(
requires same_as<I, class I::_Array_iterator>)
auto iter_concept_(I, priority_tag<3>)
-> ranges::contiguous_iterator_tag;
template(typename I)(
requires same_as<I, class I::_Array_const_iterator>)
auto iter_concept_(I, priority_tag<3>)
-> ranges::contiguous_iterator_tag;
template(typename I)(
requires same_as<I, class I::_Vector_iterator>)
auto iter_concept_(I, priority_tag<3>)
-> ranges::contiguous_iterator_tag;
template(typename I)(
requires same_as<I, class I::_Vector_const_iterator>)
auto iter_concept_(I, priority_tag<3>)
-> ranges::contiguous_iterator_tag;
template(typename I)(
requires same_as<I, class I::_String_iterator>)
auto iter_concept_(I, priority_tag<3>)
-> ranges::contiguous_iterator_tag;
template(typename I)(
requires same_as<I, class I::_String_const_iterator>)
auto iter_concept_(I, priority_tag<3>)
-> ranges::contiguous_iterator_tag;
template(typename I)(
requires same_as<I, class I::_String_view_iterator>)
auto iter_concept_(I, priority_tag<3>)
-> ranges::contiguous_iterator_tag;
#endif
template(typename I, typename T)(
requires same_as<I, T *>)
auto iter_concept_(T *, priority_tag<3>)
-> ranges::contiguous_iterator_tag;
template<typename I>
auto iter_concept_(I, priority_tag<2>) ->
typename iter_traits_t<I>::iterator_concept;
template<typename I>
auto iter_concept_(I, priority_tag<1>) ->
typename iter_traits_t<I>::iterator_category;
template<typename I>
auto iter_concept_(I, priority_tag<0>)
-> enable_if_t<!is_std_iterator_traits_specialized_v<I>,
std::random_access_iterator_tag>;
template<typename I>
using iter_concept_t =
decltype(iter_concept_<I>(std::declval<I>(), priority_tag<3>{}));
using ::concepts::detail::weakly_equality_comparable_with_;
template<typename I>
using readable_types_t =
meta::list<iter_value_t<I>, iter_reference_t<I>, iter_rvalue_reference_t<I>>;
} // namespace detail
/// \endcond
// clang-format off
/// \concept readable_
/// \brief The \c readable_ concept
template(typename I)(
concept (readable_)(I),
// requires (I const i)
// (
// { *i } -> same_as<iter_reference_t<I>>;
// { iter_move(i) } -> same_as<iter_rvalue_reference_t<I>>;
// ) &&
same_as<iter_reference_t<I const>, iter_reference_t<I>> AND
same_as<iter_rvalue_reference_t<I const>, iter_rvalue_reference_t<I>> AND
common_reference_with<iter_reference_t<I> &&, iter_value_t<I> &> AND
common_reference_with<iter_reference_t<I> &&,
iter_rvalue_reference_t<I> &&> AND
common_reference_with<iter_rvalue_reference_t<I> &&, iter_value_t<I> const &>
);
/// \concept indirectly_readable
/// \brief The \c indirectly_readable concept
template<typename I>
CPP_concept indirectly_readable = //
CPP_concept_ref(ranges::readable_, uncvref_t<I>);
template<typename I>
RANGES_DEPRECATED("Please use ranges::indirectly_readable instead")
RANGES_INLINE_VAR constexpr bool readable = //
indirectly_readable<I>;
/// \concept writable_
/// \brief The \c writable_ concept
template<typename O, typename T>
CPP_requires(writable_,
requires(O && o, T && t) //
(
*o = (T &&) t,
*(O &&) o = (T &&) t,
const_cast<iter_reference_t<O> const &&>(*o) = (T &&) t,
const_cast<iter_reference_t<O> const &&>(*(O &&) o) = (T &&) t
));
/// \concept indirectly_writable
/// \brief The \c indirectly_writable concept
template<typename O, typename T>
CPP_concept indirectly_writable = //
CPP_requires_ref(ranges::writable_, O, T);
template<typename O, typename T>
RANGES_DEPRECATED("Please use ranges::indirectly_writable instead")
RANGES_INLINE_VAR constexpr bool writable = //
indirectly_writable<O, T>;
// clang-format on
/// \cond
namespace detail
{
#if RANGES_CXX_INLINE_VARIABLES >= RANGES_CXX_INLINE_VARIABLES_17
template<typename D>
inline constexpr bool _is_integer_like_ = std::is_integral<D>::value;
#else
template<typename D, typename = void>
constexpr bool _is_integer_like_ = std::is_integral<D>::value;
#endif
// gcc10 uses for std::ranges::range_difference_t<
// std::ranges::iota_view<size_t, size_t>> == __int128
#if __SIZEOF_INT128__
__extension__ typedef __int128 int128_t;
#if RANGES_CXX_INLINE_VARIABLES >= RANGES_CXX_INLINE_VARIABLES_17
template<>
inline constexpr bool _is_integer_like_<int128_t> = true;
#else
template<typename Enable>
constexpr bool _is_integer_like_<int128_t, Enable> = true;
#endif
#endif // __SIZEOF_INT128__
// clang-format off
/// \concept integer_like_
/// \brief The \c integer_like_ concept
template<typename D>
CPP_concept integer_like_ = _is_integer_like_<D>;
// TODO additional syntactic and semantic requirements
#ifdef RANGES_WORKAROUND_MSVC_792338
template<typename D, bool Signed = (D(-1) < D(0))>
constexpr bool _is_signed_(D *)
{
return Signed;
}
constexpr bool _is_signed_(void *)
{
return false;
}
/// \concept signed_integer_like_
/// \brief The \c signed_integer_like_ concept
template<typename D>
CPP_concept signed_integer_like_ =
integer_like_<D> && detail::_is_signed_((D*) nullptr);
#else // ^^^ workaround / no workaround vvv
/// \concept signed_integer_like_impl_
/// \brief The \c signed_integer_like_impl_ concept
template(typename D)(
concept (signed_integer_like_impl_)(D),
integer_like_<D> AND
concepts::type<std::integral_constant<bool, (D(-1) < D(0))>> AND
std::integral_constant<bool, (D(-1) < D(0))>::value
);
/// \concept signed_integer_like_
/// \brief The \c signed_integer_like_ concept
template<typename D>
CPP_concept signed_integer_like_ =
integer_like_<D> &&
CPP_concept_ref(detail::signed_integer_like_impl_, D);
#endif // RANGES_WORKAROUND_MSVC_792338
// clang-format on
} // namespace detail
/// \endcond
// clang-format off
/// \concept weakly_incrementable_
/// \brief The \c weakly_incrementable_ concept
template<typename I>
CPP_requires(weakly_incrementable_,
requires(I i) //
(
++i,
i++,
concepts::requires_<same_as<I&, decltype(++i)>>
));
/// \concept weakly_incrementable_
/// \brief The \c weakly_incrementable_ concept
template(typename I)(
concept (weakly_incrementable_)(I),
concepts::type<iter_difference_t<I>> AND
detail::signed_integer_like_<iter_difference_t<I>>);
/// \concept weakly_incrementable
/// \brief The \c weakly_incrementable concept
template<typename I>
CPP_concept weakly_incrementable =
copyable<I> &&
CPP_requires_ref(ranges::weakly_incrementable_, I) &&
CPP_concept_ref(ranges::weakly_incrementable_, I);
/// \concept incrementable_
/// \brief The \c incrementable_ concept
template<typename I>
CPP_requires(incrementable_,
requires(I i) //
(
concepts::requires_<same_as<I, decltype(i++)>>
));
/// \concept incrementable
/// \brief The \c incrementable concept
template<typename I>
CPP_concept incrementable =
regular<I> &&
weakly_incrementable<I> &&
CPP_requires_ref(ranges::incrementable_, I);
/// \concept input_or_output_iterator_
/// \brief The \c input_or_output_iterator_ concept
template(typename I)(
concept (input_or_output_iterator_)(I),
detail::dereferenceable_<I&>
);
/// \concept input_or_output_iterator
/// \brief The \c input_or_output_iterator concept
template<typename I>
CPP_concept input_or_output_iterator =
weakly_incrementable<I> &&
CPP_concept_ref(ranges::input_or_output_iterator_, I);
/// \concept sentinel_for
/// \brief The \c sentinel_for concept
template<typename S, typename I>
CPP_concept sentinel_for =
semiregular<S> &&
input_or_output_iterator<I> &&
detail::weakly_equality_comparable_with_<S, I>;
/// \concept sized_sentinel_for_
/// \brief The \c sized_sentinel_for_ concept
template<typename S, typename I>
CPP_requires(sized_sentinel_for_,
requires(S const & s, I const & i) //
(
s - i,
i - s,
concepts::requires_<same_as<iter_difference_t<I>, decltype(s - i)>>,
concepts::requires_<same_as<iter_difference_t<I>, decltype(i - s)>>
));
/// \concept sized_sentinel_for_
/// \brief The \c sized_sentinel_for_ concept
template(typename S, typename I)(
concept (sized_sentinel_for_)(S, I),
(!disable_sized_sentinel<std::remove_cv_t<S>, std::remove_cv_t<I>>) AND
sentinel_for<S, I>);
/// \concept sized_sentinel_for
/// \brief The \c sized_sentinel_for concept
template<typename S, typename I>
CPP_concept sized_sentinel_for =
CPP_concept_ref(sized_sentinel_for_, S, I) &&
CPP_requires_ref(ranges::sized_sentinel_for_, S, I);
/// \concept output_iterator_
/// \brief The \c output_iterator_ concept
template<typename Out, typename T>
CPP_requires(output_iterator_,
requires(Out o, T && t) //
(
*o++ = (T &&) t
));
/// \concept output_iterator
/// \brief The \c output_iterator concept
template<typename Out, typename T>
CPP_concept output_iterator =
input_or_output_iterator<Out> &&
indirectly_writable<Out, T> &&
CPP_requires_ref(ranges::output_iterator_, Out, T);
/// \concept with_category_
/// \brief The \c with_category_ concept
template(typename I, typename Tag)(
concept (with_category_)(I, Tag),
derived_from<detail::iter_concept_t<I>, Tag>
);
/// \concept input_iterator
/// \brief The \c input_iterator concept
template<typename I>
CPP_concept input_iterator =
input_or_output_iterator<I> &&
indirectly_readable<I> &&
CPP_concept_ref(ranges::with_category_, I, std::input_iterator_tag);
/// \concept forward_iterator
/// \brief The \c forward_iterator concept
template<typename I>
CPP_concept forward_iterator =
input_iterator<I> &&
incrementable<I> &&
sentinel_for<I, I> &&
CPP_concept_ref(ranges::with_category_, I, std::forward_iterator_tag);
/// \concept bidirectional_iterator_
/// \brief The \c bidirectional_iterator_ concept
template<typename I>
CPP_requires(bidirectional_iterator_,
requires(I i) //
(
--i,
i--,
concepts::requires_<same_as<I&, decltype(--i)>>,
concepts::requires_<same_as<I, decltype(i--)>>
));
/// \concept bidirectional_iterator
/// \brief The \c bidirectional_iterator concept
template<typename I>
CPP_concept bidirectional_iterator =
forward_iterator<I> &&
CPP_requires_ref(ranges::bidirectional_iterator_, I) &&
CPP_concept_ref(ranges::with_category_, I, std::bidirectional_iterator_tag);
/// \concept random_access_iterator_
/// \brief The \c random_access_iterator_ concept
template<typename I>
CPP_requires(random_access_iterator_,
requires(I i, iter_difference_t<I> n)
(
i + n,
n + i,
i - n,
i += n,
i -= n,
concepts::requires_<same_as<decltype(i + n), I>>,
concepts::requires_<same_as<decltype(n + i), I>>,
concepts::requires_<same_as<decltype(i - n), I>>,
concepts::requires_<same_as<decltype(i += n), I&>>,
concepts::requires_<same_as<decltype(i -= n), I&>>,
concepts::requires_<same_as<decltype(i[n]), iter_reference_t<I>>>
));
/// \concept random_access_iterator
/// \brief The \c random_access_iterator concept
template<typename I>
CPP_concept random_access_iterator =
bidirectional_iterator<I> &&
totally_ordered<I> &&
sized_sentinel_for<I, I> &&
CPP_requires_ref(ranges::random_access_iterator_, I) &&
CPP_concept_ref(ranges::with_category_, I, std::random_access_iterator_tag);
/// \concept contiguous_iterator_
/// \brief The \c contiguous_iterator_ concept
template(typename I)(
concept (contiguous_iterator_)(I),
std::is_lvalue_reference<iter_reference_t<I>>::value AND
same_as<iter_value_t<I>, uncvref_t<iter_reference_t<I>>> AND
derived_from<detail::iter_concept_t<I>, ranges::contiguous_iterator_tag>
);
/// \concept contiguous_iterator
/// \brief The \c contiguous_iterator concept
template<typename I>
CPP_concept contiguous_iterator =
random_access_iterator<I> &&
CPP_concept_ref(ranges::contiguous_iterator_, I);
// clang-format on
/////////////////////////////////////////////////////////////////////////////////////
// iterator_tag_of
template<typename Rng>
using iterator_tag_of = //
std::enable_if_t< //
input_iterator<Rng>, //
meta::conditional_t< //
contiguous_iterator<Rng>, //
ranges::contiguous_iterator_tag, //
meta::conditional_t< //
random_access_iterator<Rng>, //
std::random_access_iterator_tag, //
meta::conditional_t< //
bidirectional_iterator<Rng>, //
std::bidirectional_iterator_tag, //
meta::conditional_t< //
forward_iterator<Rng>, //
std::forward_iterator_tag, //
std::input_iterator_tag>>>>>;
/// \cond
namespace detail
{
template<typename, bool>
struct iterator_category_
{};
template<typename I>
struct iterator_category_<I, true>
{
using type = iterator_tag_of<I>;
};
template<typename T, typename U = meta::_t<std::remove_const<T>>>
using iterator_category = iterator_category_<U, (bool)input_iterator<U>>;
} // namespace detail
/// \endcond
/// \cond
// Generally useful to know if an iterator is single-pass or not:
// clang-format off
/// \concept single_pass_iterator_
/// \brief The \c single_pass_iterator_ concept
template<typename I>
CPP_concept single_pass_iterator_ =
input_or_output_iterator<I> && !forward_iterator<I>;
// clang-format on
/// \endcond
//////////////////////////////////////////////////////////////////////////////////////
// indirect_result_t
template<typename Fun, typename... Is>
using indirect_result_t =
detail::enable_if_t<(bool)and_v<(bool)indirectly_readable<Is>...>,
invoke_result_t<Fun, iter_reference_t<Is>...>>;
/// \cond
namespace detail
{
// clang-format off
/// \concept common_reference_with_4_impl_
/// \brief The \c common_reference_with_4_impl_ concept
template(typename T1, typename T2, typename T3, typename T4)(
concept (common_reference_with_4_impl_)(T1, T2, T3, T4),
concepts::type<common_reference_t<T1, T2, T3, T4>> AND
convertible_to<T1, common_reference_t<T1, T2, T3, T4>> AND
convertible_to<T2, common_reference_t<T1, T2, T3, T4>> AND
convertible_to<T3, common_reference_t<T1, T2, T3, T4>> AND
convertible_to<T4, common_reference_t<T1, T2, T3, T4>>
);
/// \concept common_reference_with_4_
/// \brief The \c common_reference_with_4_ concept
template<typename T1, typename T2, typename T3, typename T4>
CPP_concept common_reference_with_4_ =
CPP_concept_ref(detail::common_reference_with_4_impl_, T1, T2, T3, T4);
// axiom: all permutations of T1,T2,T3,T4 have the same
// common reference type.
/// \concept indirectly_unary_invocable_impl_
/// \brief The \c indirectly_unary_invocable_impl_ concept
template(typename F, typename I)(
concept (indirectly_unary_invocable_impl_)(F, I),
invocable<F &, iter_value_t<I> &> AND
invocable<F &, iter_reference_t<I>> AND
invocable<F &, iter_common_reference_t<I>> AND
common_reference_with<
invoke_result_t<F &, iter_value_t<I> &>,
invoke_result_t<F &, iter_reference_t<I>>>
);
/// \concept indirectly_unary_invocable_
/// \brief The \c indirectly_unary_invocable_ concept
template<typename F, typename I>
CPP_concept indirectly_unary_invocable_ =
indirectly_readable<I> &&
CPP_concept_ref(detail::indirectly_unary_invocable_impl_, F, I);
// clang-format on
} // namespace detail
/// \endcond
// clang-format off
/// \concept indirectly_unary_invocable
/// \brief The \c indirectly_unary_invocable concept
template<typename F, typename I>
CPP_concept indirectly_unary_invocable =
detail::indirectly_unary_invocable_<F, I> &&
copy_constructible<F>;
/// \concept indirectly_regular_unary_invocable_
/// \brief The \c indirectly_regular_unary_invocable_ concept
template(typename F, typename I)(
concept (indirectly_regular_unary_invocable_)(F, I),
regular_invocable<F &, iter_value_t<I> &> AND
regular_invocable<F &, iter_reference_t<I>> AND
regular_invocable<F &, iter_common_reference_t<I>> AND
common_reference_with<
invoke_result_t<F &, iter_value_t<I> &>,
invoke_result_t<F &, iter_reference_t<I>>>
);
/// \concept indirectly_regular_unary_invocable
/// \brief The \c indirectly_regular_unary_invocable concept
template<typename F, typename I>
CPP_concept indirectly_regular_unary_invocable =
indirectly_readable<I> &&
copy_constructible<F> &&
CPP_concept_ref(ranges::indirectly_regular_unary_invocable_, F, I);
/// \cond
// Non-standard indirect invocable concepts
/// \concept indirectly_binary_invocable_impl_
/// \brief The \c indirectly_binary_invocable_impl_ concept
template(typename F, typename I1, typename I2)(
concept (indirectly_binary_invocable_impl_)(F, I1, I2),
invocable<F &, iter_value_t<I1> &, iter_value_t<I2> &> AND
invocable<F &, iter_value_t<I1> &, iter_reference_t<I2>> AND
invocable<F &, iter_reference_t<I1>, iter_value_t<I2> &> AND
invocable<F &, iter_reference_t<I1>, iter_reference_t<I2>> AND
invocable<F &, iter_common_reference_t<I1>, iter_common_reference_t<I2>> AND
detail::common_reference_with_4_<
invoke_result_t<F &, iter_value_t<I1> &, iter_value_t<I2> &>,
invoke_result_t<F &, iter_value_t<I1> &, iter_reference_t<I2>>,
invoke_result_t<F &, iter_reference_t<I1>, iter_value_t<I2> &>,
invoke_result_t<F &, iter_reference_t<I1>, iter_reference_t<I2>>>
);
/// \concept indirectly_binary_invocable_
/// \brief The \c indirectly_binary_invocable_ concept
template<typename F, typename I1, typename I2>
CPP_concept indirectly_binary_invocable_ =
indirectly_readable<I1> && indirectly_readable<I2> &&
copy_constructible<F> &&
CPP_concept_ref(ranges::indirectly_binary_invocable_impl_, F, I1, I2);
/// \concept indirectly_regular_binary_invocable_impl_
/// \brief The \c indirectly_regular_binary_invocable_impl_ concept
template(typename F, typename I1, typename I2)(
concept (indirectly_regular_binary_invocable_impl_)(F, I1, I2),
regular_invocable<F &, iter_value_t<I1> &, iter_value_t<I2> &> AND
regular_invocable<F &, iter_value_t<I1> &, iter_reference_t<I2>> AND
regular_invocable<F &, iter_reference_t<I1>, iter_value_t<I2> &> AND
regular_invocable<F &, iter_reference_t<I1>, iter_reference_t<I2>> AND
regular_invocable<F &, iter_common_reference_t<I1>, iter_common_reference_t<I2>> AND
detail::common_reference_with_4_<
invoke_result_t<F &, iter_value_t<I1> &, iter_value_t<I2> &>,
invoke_result_t<F &, iter_value_t<I1> &, iter_reference_t<I2>>,
invoke_result_t<F &, iter_reference_t<I1>, iter_value_t<I2> &>,
invoke_result_t<F &, iter_reference_t<I1>, iter_reference_t<I2>>>
);
/// \concept indirectly_regular_binary_invocable_
/// \brief The \c indirectly_regular_binary_invocable_ concept
template<typename F, typename I1, typename I2>
CPP_concept indirectly_regular_binary_invocable_ =
indirectly_readable<I1> && indirectly_readable<I2> &&
copy_constructible<F> &&
CPP_concept_ref(ranges::indirectly_regular_binary_invocable_impl_, F, I1, I2);
/// \endcond
/// \concept indirect_unary_predicate_
/// \brief The \c indirect_unary_predicate_ concept
template(typename F, typename I)(
concept (indirect_unary_predicate_)(F, I),
predicate<F &, iter_value_t<I> &> AND
predicate<F &, iter_reference_t<I>> AND
predicate<F &, iter_common_reference_t<I>>
);
/// \concept indirect_unary_predicate
/// \brief The \c indirect_unary_predicate concept
template<typename F, typename I>
CPP_concept indirect_unary_predicate =
indirectly_readable<I> &&
copy_constructible<F> &&
CPP_concept_ref(ranges::indirect_unary_predicate_, F, I);
/// \concept indirect_binary_predicate_impl_
/// \brief The \c indirect_binary_predicate_impl_ concept
template(typename F, typename I1, typename I2)(
concept (indirect_binary_predicate_impl_)(F, I1, I2),
predicate<F &, iter_value_t<I1> &, iter_value_t<I2> &> AND
predicate<F &, iter_value_t<I1> &, iter_reference_t<I2>> AND
predicate<F &, iter_reference_t<I1>, iter_value_t<I2> &> AND
predicate<F &, iter_reference_t<I1>, iter_reference_t<I2>> AND
predicate<F &, iter_common_reference_t<I1>, iter_common_reference_t<I2>>
);
/// \concept indirect_binary_predicate_
/// \brief The \c indirect_binary_predicate_ concept
template<typename F, typename I1, typename I2>
CPP_concept indirect_binary_predicate_ =
indirectly_readable<I1> && indirectly_readable<I2> &&
copy_constructible<F> &&
CPP_concept_ref(ranges::indirect_binary_predicate_impl_, F, I1, I2);
/// \concept indirect_relation_
/// \brief The \c indirect_relation_ concept
template(typename F, typename I1, typename I2)(
concept (indirect_relation_)(F, I1, I2),
relation<F &, iter_value_t<I1> &, iter_value_t<I2> &> AND
relation<F &, iter_value_t<I1> &, iter_reference_t<I2>> AND
relation<F &, iter_reference_t<I1>, iter_value_t<I2> &> AND
relation<F &, iter_reference_t<I1>, iter_reference_t<I2>> AND
relation<F &, iter_common_reference_t<I1>, iter_common_reference_t<I2>>
);
/// \concept indirect_relation
/// \brief The \c indirect_relation concept
template<typename F, typename I1, typename I2 = I1>
CPP_concept indirect_relation =
indirectly_readable<I1> && indirectly_readable<I2> &&
copy_constructible<F> &&
CPP_concept_ref(ranges::indirect_relation_, F, I1, I2);
/// \concept indirect_strict_weak_order_
/// \brief The \c indirect_strict_weak_order_ concept
template(typename F, typename I1, typename I2)(
concept (indirect_strict_weak_order_)(F, I1, I2),
strict_weak_order<F &, iter_value_t<I1> &, iter_value_t<I2> &> AND
strict_weak_order<F &, iter_value_t<I1> &, iter_reference_t<I2>> AND
strict_weak_order<F &, iter_reference_t<I1>, iter_value_t<I2> &> AND
strict_weak_order<F &, iter_reference_t<I1>, iter_reference_t<I2>> AND
strict_weak_order<F &, iter_common_reference_t<I1>, iter_common_reference_t<I2>>
);
/// \concept indirect_strict_weak_order
/// \brief The \c indirect_strict_weak_order concept
template<typename F, typename I1, typename I2 = I1>
CPP_concept indirect_strict_weak_order =
indirectly_readable<I1> && indirectly_readable<I2> &&
copy_constructible<F> &&
CPP_concept_ref(ranges::indirect_strict_weak_order_, F, I1, I2);
// clang-format on
//////////////////////////////////////////////////////////////////////////////////////
// projected struct, for "projecting" a readable with a unary callable
/// \cond
namespace detail
{
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_UNDEFINED_INTERNAL
template<typename I, typename Proj>
struct projected_
{
struct type
{
using reference = indirect_result_t<Proj &, I>;
using value_type = uncvref_t<reference>;
reference operator*() const;
};
};
RANGES_DIAGNOSTIC_POP
template<typename Proj>
struct select_projected_
{
template<typename I>
using apply =
meta::_t<
detail::enable_if_t<
(bool)indirectly_regular_unary_invocable<Proj, I>,
detail::projected_<I, Proj>>>;
};
template<>
struct select_projected_<identity>
{
template<typename I>
using apply = detail::enable_if_t<(bool)indirectly_readable<I>, I>;
};
} // namespace detail
/// \endcond
template<typename I, typename Proj>
using projected = typename detail::select_projected_<Proj>::template apply<I>;
template<typename I, typename Proj>
struct incrementable_traits<detail::projected_<I, Proj>> : incrementable_traits<I>
{};
// clang-format off
/// \concept indirectly_movable_
/// \brief The \c indirectly_movable_ concept
template(typename I, typename O)(
concept (indirectly_movable_)(I, O),
indirectly_writable<O, iter_rvalue_reference_t<I>>
);
/// \concept indirectly_movable
/// \brief The \c indirectly_movable concept
template<typename I, typename O>
CPP_concept indirectly_movable =
indirectly_readable<I> && CPP_concept_ref(ranges::indirectly_movable_, I, O);
/// \concept indirectly_movable_storable_
/// \brief The \c indirectly_movable_storable_ concept
template(typename I, typename O)(
concept (indirectly_movable_storable_)(I, O),
indirectly_writable<O, iter_value_t<I>> AND
movable<iter_value_t<I>> AND
constructible_from<iter_value_t<I>, iter_rvalue_reference_t<I>> AND
assignable_from<iter_value_t<I> &, iter_rvalue_reference_t<I>>
);
/// \concept indirectly_movable_storable
/// \brief The \c indirectly_movable_storable concept
template<typename I, typename O>
CPP_concept indirectly_movable_storable =
indirectly_movable<I, O> &&
CPP_concept_ref(ranges::indirectly_movable_storable_, I, O);
/// \concept indirectly_copyable_
/// \brief The \c indirectly_copyable_ concept
template(typename I, typename O)(
concept (indirectly_copyable_)(I, O),
indirectly_writable<O, iter_reference_t<I>>
);
/// \concept indirectly_copyable
/// \brief The \c indirectly_copyable concept
template<typename I, typename O>
CPP_concept indirectly_copyable =
indirectly_readable<I> && CPP_concept_ref(ranges::indirectly_copyable_, I, O);
/// \concept indirectly_copyable_storable_
/// \brief The \c indirectly_copyable_storable_ concept
template(typename I, typename O)(
concept (indirectly_copyable_storable_)(I, O),
indirectly_writable<O, iter_value_t<I> const &> AND
copyable<iter_value_t<I>> AND
constructible_from<iter_value_t<I>, iter_reference_t<I>> AND
assignable_from<iter_value_t<I> &, iter_reference_t<I>>
);
/// \concept indirectly_copyable_storable
/// \brief The \c indirectly_copyable_storable concept
template<typename I, typename O>
CPP_concept indirectly_copyable_storable =
indirectly_copyable<I, O> &&
CPP_concept_ref(ranges::indirectly_copyable_storable_, I, O);
/// \concept indirectly_swappable_
/// \brief The \c indirectly_swappable_ concept
template<typename I1, typename I2>
CPP_requires(indirectly_swappable_,
requires(I1 const i1, I2 const i2) //
(
ranges::iter_swap(i1, i2),
ranges::iter_swap(i1, i1),
ranges::iter_swap(i2, i2),
ranges::iter_swap(i2, i1)
));
/// \concept indirectly_swappable
/// \brief The \c indirectly_swappable concept
template<typename I1, typename I2 = I1>
CPP_concept indirectly_swappable =
indirectly_readable<I1> && //
indirectly_readable<I2> && //
CPP_requires_ref(ranges::indirectly_swappable_, I1, I2);
/// \concept projected_indirect_relation_
/// \brief The \c projected_indirect_relation_ concept
template(typename C, typename I1, typename P1, typename I2, typename P2)(
concept (projected_indirect_relation_)(C, I1, P1, I2, P2),
indirect_relation<C, projected<I1, P1>, projected<I2, P2>>
);
/// \concept indirectly_comparable
/// \brief The \c indirectly_comparable concept
template<typename I1, typename I2, typename C, typename P1 = identity,
typename P2 = identity>
CPP_concept indirectly_comparable =
CPP_concept_ref(ranges::projected_indirect_relation_, C, I1, P1, I2, P2);
//////////////////////////////////////////////////////////////////////////////////////
// Composite concepts for use defining algorithms:
/// \concept permutable
/// \brief The \c permutable concept
template<typename I>
CPP_concept permutable =
forward_iterator<I> &&
indirectly_swappable<I, I> &&
indirectly_movable_storable<I, I>;
/// \concept projected_indirect_strict_weak_order_
/// \brief The \c projected_indirect_strict_weak_order_ concept
template(typename C, typename I1, typename P1, typename I2, typename P2)(
concept (projected_indirect_strict_weak_order_)(C, I1, P1, I2, P2),
indirect_strict_weak_order<C, projected<I1, P1>, projected<I2, P2>>
);
template<typename I1, typename I2, typename Out, typename C = less,
typename P1 = identity, typename P2 = identity>
CPP_concept mergeable =
input_iterator<I1> &&
input_iterator<I2> &&
weakly_incrementable<Out> &&
indirectly_copyable<I1, Out> &&
indirectly_copyable<I2, Out> &&
CPP_concept_ref(ranges::projected_indirect_strict_weak_order_, C, I1, P1, I2, P2);
/// \concept sortable
/// \brief The \c sortable concept
template<typename I, typename C = less, typename P = identity>
CPP_concept sortable =
permutable<I> &&
CPP_concept_ref(ranges::projected_indirect_strict_weak_order_, C, I, P, I, P);
// clang-format on
struct sentinel_tag
{};
struct sized_sentinel_tag : sentinel_tag
{};
template<typename S, typename I>
using sentinel_tag_of = //
std::enable_if_t< //
sentinel_for<S, I>, //
meta::conditional_t< //
sized_sentinel_for<S, I>, //
sized_sentinel_tag, //
sentinel_tag>>;
// Deprecated things:
/// \cond
template<typename I>
using iterator_category RANGES_DEPRECATED(
"iterator_category is deprecated. Use the iterator concepts instead") =
detail::iterator_category<I>;
template<typename I>
using iterator_category_t RANGES_DEPRECATED(
"iterator_category_t is deprecated. Use the iterator concepts instead") =
meta::_t<detail::iterator_category<I>>;
template<typename Fun, typename... Is>
using indirect_invoke_result_t RANGES_DEPRECATED(
"Please switch to indirect_result_t") = indirect_result_t<Fun, Is...>;
template<typename Fun, typename... Is>
struct RANGES_DEPRECATED("Please switch to indirect_result_t") indirect_invoke_result
: meta::defer<indirect_result_t, Fun, Is...>
{};
template<typename Sig>
struct indirect_result_of
{};
template<typename Fun, typename... Is>
struct RANGES_DEPRECATED("Please switch to indirect_result_t")
indirect_result_of<Fun(Is...)> : meta::defer<indirect_result_t, Fun, Is...>
{};
template<typename Sig>
using indirect_result_of_t RANGES_DEPRECATED("Please switch to indirect_result_t") =
meta::_t<indirect_result_of<Sig>>;
/// \endcond
namespace cpp20
{
using ranges::bidirectional_iterator;
using ranges::contiguous_iterator;
using ranges::forward_iterator;
using ranges::incrementable;
using ranges::indirect_relation;
using ranges::indirect_result_t;
using ranges::indirect_strict_weak_order;
using ranges::indirect_unary_predicate;
using ranges::indirectly_comparable;
using ranges::indirectly_copyable;
using ranges::indirectly_copyable_storable;
using ranges::indirectly_movable;
using ranges::indirectly_movable_storable;
using ranges::indirectly_readable;
using ranges::indirectly_regular_unary_invocable;
using ranges::indirectly_swappable;
using ranges::indirectly_unary_invocable;
using ranges::indirectly_writable;
using ranges::input_iterator;
using ranges::input_or_output_iterator;
using ranges::mergeable;
using ranges::output_iterator;
using ranges::permutable;
using ranges::projected;
using ranges::random_access_iterator;
using ranges::sentinel_for;
using ranges::sized_sentinel_for;
using ranges::sortable;
using ranges::weakly_incrementable;
} // namespace cpp20
/// @}
} // namespace ranges
#ifdef _GLIBCXX_DEBUG
// HACKHACK: workaround underconstrained operator- for libstdc++ debug iterator wrapper
// by intentionally creating an ambiguity when the wrapped types don't support the
// necessary operation.
namespace __gnu_debug
{
template(typename I1, typename I2, typename Seq)(
requires (!::ranges::sized_sentinel_for<I1, I2>)) //
void operator-(_Safe_iterator<I1, Seq> const &, _Safe_iterator<I2, Seq> const &) =
delete;
template(typename I1, typename Seq)(
requires (!::ranges::sized_sentinel_for<I1, I1>)) //
void operator-(_Safe_iterator<I1, Seq> const &, _Safe_iterator<I1, Seq> const &) =
delete;
} // namespace __gnu_debug
#endif
#if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 3900)
// HACKHACK: workaround libc++ (https://llvm.org/bugs/show_bug.cgi?id=28421)
// and libstdc++ (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71771)
// underconstrained operator- for reverse_iterator by disabling sized_sentinel_for
// when the base iterators do not model sized_sentinel_for.
namespace ranges
{
template<typename S, typename I>
/*inline*/ constexpr bool
disable_sized_sentinel<std::reverse_iterator<S>, std::reverse_iterator<I>> =
!static_cast<bool>(sized_sentinel_for<I, S>);
} // namespace ranges
#endif // defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 3900)
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_ITERATOR_CONCEPTS_HPP

View File

@@ -0,0 +1,472 @@
/// \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_ITERATOR_COUNTED_ITERATOR_HPP
#define RANGES_V3_ITERATOR_COUNTED_ITERATOR_HPP
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/iterator/traits.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator
/// @{
/// \cond
namespace _counted_iterator_
{
struct access
{
template<typename I>
static constexpr iter_difference_t<counted_iterator<I>> & count(
counted_iterator<I> & ci) noexcept
{
return ci.cnt_;
}
template<typename I>
static constexpr I & current(counted_iterator<I> & ci) noexcept
{
return ci.current_;
}
template<typename I>
static constexpr I const & current(counted_iterator<I> const & ci) noexcept
{
return ci.current_;
}
};
template<bool>
struct contiguous_iterator_concept_base
{};
template<>
struct contiguous_iterator_concept_base<true>
{
using iterator_concept = ranges::contiguous_iterator_tag;
};
} // namespace _counted_iterator_
/// \endcond
template<typename I>
// requires input_or_output_iterator<I>
struct counted_iterator
: _counted_iterator_::contiguous_iterator_concept_base<(bool)contiguous_iterator<I>>
{
private:
friend advance_fn;
CPP_assert(input_or_output_iterator<I>);
friend _counted_iterator_::access;
I current_{};
iter_difference_t<I> cnt_{0};
constexpr void post_increment_(std::true_type)
{
CPP_assert(std::is_void<decltype(current_++)>());
++current_;
--cnt_;
}
constexpr auto post_increment_(std::false_type) -> decltype(current_++)
{
CPP_assert(!std::is_void<decltype(current_++)>());
auto && tmp = current_++;
--cnt_;
return static_cast<decltype(tmp) &&>(tmp);
}
public:
using iterator_type = I;
using difference_type = iter_difference_t<I>;
counted_iterator() = default;
constexpr counted_iterator(I x, iter_difference_t<I> n)
: current_(std::move(x))
, cnt_(n)
{
RANGES_EXPECT(n >= 0);
}
template(typename I2)(
requires convertible_to<I2, I>)
constexpr counted_iterator(counted_iterator<I2> const & i)
: current_(_counted_iterator_::access::current(i))
, cnt_(i.count())
{}
template(typename I2)(
requires convertible_to<I2, I>)
constexpr counted_iterator & operator=(counted_iterator<I2> const & i)
{
current_ = _counted_iterator_::access::current(i);
cnt_ = i.count();
}
constexpr I base() const
{
return current_;
}
constexpr iter_difference_t<I> count() const
{
return cnt_;
}
constexpr iter_reference_t<I> operator*() noexcept(
noexcept(iter_reference_t<I>(*current_)))
{
RANGES_EXPECT(cnt_ > 0);
return *current_;
}
template(typename I2 = I)(
requires indirectly_readable<I2 const>)
constexpr iter_reference_t<I2> operator*() const //
noexcept(noexcept(iter_reference_t<I>(*current_)))
{
RANGES_EXPECT(cnt_ > 0);
return *current_;
}
constexpr counted_iterator & operator++()
{
RANGES_EXPECT(cnt_ > 0);
++current_;
--cnt_;
return *this;
}
#ifdef RANGES_WORKAROUND_MSVC_677925
template(typename I2 = I)(
requires (!forward_iterator<I2>)) //
constexpr auto operator++(int) -> decltype(std::declval<I2 &>()++)
#else // ^^^ workaround ^^^ / vvv no workaround vvv
CPP_member
constexpr auto operator++(int) //
-> CPP_ret(decltype(std::declval<I &>()++))(
requires (!forward_iterator<I>))
#endif // RANGES_WORKAROUND_MSVC_677925
{
RANGES_EXPECT(cnt_ > 0);
return post_increment_(std::is_void<decltype(current_++)>());
}
CPP_member
constexpr auto operator++(int) //
-> CPP_ret(counted_iterator)(
requires forward_iterator<I>)
{
auto tmp(*this);
++*this;
return tmp;
}
CPP_member
constexpr auto operator--() //
-> CPP_ret(counted_iterator &)(
requires bidirectional_iterator<I>)
{
--current_;
++cnt_;
return *this;
}
CPP_member
constexpr auto operator--(int) //
-> CPP_ret(counted_iterator)(
requires bidirectional_iterator<I>)
{
auto tmp(*this);
--*this;
return tmp;
}
CPP_member
constexpr auto operator+=(difference_type n) //
-> CPP_ret(counted_iterator &)(
requires random_access_iterator<I>)
{
RANGES_EXPECT(cnt_ >= n);
current_ += n;
cnt_ -= n;
return *this;
}
CPP_member
constexpr auto operator+(difference_type n) const //
-> CPP_ret(counted_iterator)(
requires random_access_iterator<I>)
{
auto tmp(*this);
tmp += n;
return tmp;
}
CPP_member
constexpr auto operator-=(difference_type n) //
-> CPP_ret(counted_iterator &)(
requires random_access_iterator<I>)
{
RANGES_EXPECT(cnt_ >= -n);
current_ -= n;
cnt_ += n;
return *this;
}
CPP_member
constexpr auto operator-(difference_type n) const //
-> CPP_ret(counted_iterator)(
requires random_access_iterator<I>)
{
auto tmp(*this);
tmp -= n;
return tmp;
}
CPP_member
constexpr auto operator[](difference_type n) const //
-> CPP_ret(iter_reference_t<I>)(
requires random_access_iterator<I>)
{
RANGES_EXPECT(cnt_ >= n);
return current_[n];
}
#if !RANGES_BROKEN_CPO_LOOKUP
CPP_broken_friend_member
friend constexpr auto iter_move(counted_iterator const & i) //
noexcept(detail::has_nothrow_iter_move_v<I>)
-> CPP_broken_friend_ret(iter_rvalue_reference_t<I>)(
requires input_iterator<I>)
{
return ranges::iter_move(i.current_);
}
template<typename I2, typename S2>
friend constexpr auto iter_swap(counted_iterator const & x,
counted_iterator<I2> const & y) //
noexcept(is_nothrow_indirectly_swappable<I, I2>::value)
-> CPP_broken_friend_ret(void)(
requires indirectly_swappable<I2, I>)
{
return ranges::iter_swap(x.current_, _counted_iterator_::access::current(y));
}
#endif
};
/// \cond
#if RANGES_BROKEN_CPO_LOOKUP
namespace _counted_iterator_
{
template<typename I>
constexpr auto iter_move(counted_iterator<I> const & i) noexcept(
detail::has_nothrow_iter_move_v<I>)
-> CPP_broken_friend_ret(iter_rvalue_reference_t<I>)(
requires input_iterator<I>)
{
return ranges::iter_move(_counted_iterator_::access::current(i));
}
template<typename I1, typename I2>
constexpr auto iter_swap(
counted_iterator<I1> const & x,
counted_iterator<I2> const &
y) noexcept(is_nothrow_indirectly_swappable<I1, I2>::value)
-> CPP_broken_friend_ret(void)(
requires indirectly_swappable<I2, I1>)
{
return ranges::iter_swap(_counted_iterator_::access::current(x),
_counted_iterator_::access::current(y));
}
} // namespace _counted_iterator_
#endif
/// endcond
template(typename I1, typename I2)(
requires common_with<I1, I2>)
constexpr bool operator==(counted_iterator<I1> const & x,
counted_iterator<I2> const & y)
{
return x.count() == y.count();
}
template<typename I>
constexpr bool operator==(counted_iterator<I> const & x, default_sentinel_t)
{
return x.count() == 0;
}
template<typename I>
constexpr bool operator==(default_sentinel_t, counted_iterator<I> const & x)
{
return x.count() == 0;
}
template(typename I1, typename I2)(
requires common_with<I1, I2>)
constexpr bool operator!=(counted_iterator<I1> const & x,
counted_iterator<I2> const & y)
{
return !(x == y);
}
template<typename I>
constexpr bool operator!=(counted_iterator<I> const & x, default_sentinel_t y)
{
return !(x == y);
}
template<typename I>
constexpr bool operator!=(default_sentinel_t x, counted_iterator<I> const & y)
{
return !(x == y);
}
template(typename I1, typename I2)(
requires common_with<I1, I2>)
constexpr bool operator<(counted_iterator<I1> const & x,
counted_iterator<I2> const & y)
{
return y.count() < x.count();
}
template(typename I1, typename I2)(
requires common_with<I1, I2>)
constexpr bool operator<=(counted_iterator<I1> const & x,
counted_iterator<I2> const & y)
{
return !(y < x);
}
template(typename I1, typename I2)(
requires common_with<I1, I2>)
constexpr bool operator>(counted_iterator<I1> const & x,
counted_iterator<I2> const & y)
{
return y < x;
}
template(typename I1, typename I2)(
requires common_with<I1, I2>)
constexpr bool operator>=(counted_iterator<I1> const & x,
counted_iterator<I2> const & y)
{
return !(x < y);
}
template(typename I1, typename I2)(
requires common_with<I1, I2>)
constexpr iter_difference_t<I2> operator-(counted_iterator<I1> const & x,
counted_iterator<I2> const & y)
{
return y.count() - x.count();
}
template<typename I>
constexpr iter_difference_t<I> operator-(counted_iterator<I> const & x,
default_sentinel_t)
{
return -x.count();
}
template<typename I>
constexpr iter_difference_t<I> operator-(default_sentinel_t,
counted_iterator<I> const & y)
{
return y.count();
}
template(typename I)(
requires random_access_iterator<I>)
constexpr counted_iterator<I> operator+(iter_difference_t<I> n,
counted_iterator<I> const & x)
{
return x + n;
}
template(typename I)(
requires input_or_output_iterator<I>)
constexpr counted_iterator<I> make_counted_iterator(I i, iter_difference_t<I> n)
{
return {std::move(i), n};
}
template<typename I>
struct indirectly_readable_traits<counted_iterator<I>>
: meta::conditional_t<
(bool)indirectly_readable<I>,
indirectly_readable_traits<I>,
meta::nil_>
{};
CPP_template_def(typename I)(
requires input_or_output_iterator<I>)
constexpr void advance_fn::operator()(counted_iterator<I> & i,
iter_difference_t<I> n) const
{
RANGES_EXPECT(n <= i.cnt_);
advance(i.current_, n);
i.cnt_ -= n;
}
namespace cpp20
{
using ranges::counted_iterator;
}
/// @}
} // namespace ranges
/// \cond
namespace ranges
{
namespace _counted_iterator_
{
template<typename I, typename = void>
struct iterator_traits_
{
using difference_type = iter_difference_t<I>;
using value_type = void;
using reference = void;
using pointer = void;
using iterator_category = std::output_iterator_tag;
};
template<typename I>
struct iterator_traits_<I, meta::if_c<input_iterator<I>>>
: std::iterator_traits<I>
{
using pointer = void;
};
} // namespace _counted_iterator_
} // namespace ranges
namespace std
{
template<typename I>
struct iterator_traits<::ranges::counted_iterator<I>>
: ::ranges::_counted_iterator_::iterator_traits_<I>
{};
} // namespace std
/// \endcond
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,41 @@
/// \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_ITERATOR_DEFAULT_SENTINEL_HPP
#define RANGES_V3_ITERATOR_DEFAULT_SENTINEL_HPP
#include <range/v3/detail/config.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator
/// @{
struct default_sentinel_t
{};
// Default sentinel
RANGES_INLINE_VARIABLE(default_sentinel_t, default_sentinel)
namespace cpp20
{
using ranges::default_sentinel;
using ranges::default_sentinel_t;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,470 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 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_ITERATOR_DIFFMAX_T_HPP
#define RANGES_V3_ITERATOR_DIFFMAX_T_HPP
#include <cstdint>
#include <iosfwd>
#include <limits>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/detail/prologue.hpp>
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_UNSIGNED_MATH
namespace ranges
{
/// \cond
namespace detail
{
struct diffmax_t
{
private:
bool neg_;
std::uintmax_t val_;
struct tag
{};
constexpr diffmax_t(tag, bool neg, std::uintmax_t val)
: neg_(val && neg)
, val_(val)
{}
/// \cond
constexpr void _check()
{
RANGES_ENSURE(!neg_ || val_);
}
static constexpr diffmax_t _normalize(bool neg, std::uintmax_t val)
{
return diffmax_t{tag{}, val && neg, val};
}
/// \endcond
public:
diffmax_t() = default;
template(typename T)(
requires integral<T>)
constexpr diffmax_t(T val) noexcept
: neg_(0 > val)
, val_(0 > val ? static_cast<std::uintmax_t>(-val)
: static_cast<std::uintmax_t>(val))
{}
friend constexpr bool operator<(diffmax_t a, diffmax_t b) noexcept
{
a._check();
b._check();
return a.neg_ ? (b.neg_ ? a.val_ > b.val_ : true)
: (b.neg_ ? false : a.val_ < b.val_);
}
friend constexpr bool operator>(diffmax_t a, diffmax_t b) noexcept
{
return b < a;
}
friend constexpr bool operator<=(diffmax_t a, diffmax_t b) noexcept
{
return !(b < a);
}
friend constexpr bool operator>=(diffmax_t a, diffmax_t b) noexcept
{
return !(a < b);
}
friend constexpr bool operator==(diffmax_t a, diffmax_t b) noexcept
{
a._check();
b._check();
return a.val_ == b.val_ && a.neg_ == b.neg_;
}
friend constexpr bool operator!=(diffmax_t a, diffmax_t b) noexcept
{
return !(a == b);
}
friend constexpr diffmax_t operator+(diffmax_t a) noexcept
{
return a;
}
friend constexpr diffmax_t operator-(diffmax_t a) noexcept
{
return _normalize(!a.neg_, a.val_);
}
friend constexpr diffmax_t operator+(diffmax_t a, diffmax_t b) noexcept
{
return a.neg_ == b.neg_
? diffmax_t{tag{}, a.neg_, a.val_ + b.val_}
: (a.neg_ ? (a.val_ > b.val_
? diffmax_t{tag{}, true, a.val_ - b.val_}
: diffmax_t{tag{}, false, b.val_ - a.val_})
: (b.val_ > a.val_
? diffmax_t{tag{}, true, b.val_ - a.val_}
: diffmax_t{tag{}, false, a.val_ - b.val_}));
}
friend constexpr diffmax_t operator-(diffmax_t a, diffmax_t b) noexcept
{
return a + -b;
}
friend constexpr diffmax_t operator*(diffmax_t a, diffmax_t b) noexcept
{
return _normalize(a.neg_ ^ b.neg_, a.val_ * b.val_);
}
friend constexpr diffmax_t operator/(diffmax_t a, diffmax_t b) noexcept
{
return _normalize(a.neg_ ^ b.neg_, a.val_ / b.val_);
}
friend constexpr diffmax_t operator%(diffmax_t a, diffmax_t b) noexcept
{
return _normalize(a.neg_, a.val_ % b.val_);
}
static constexpr std::uintmax_t compl_if(bool neg,
std::uintmax_t val) noexcept
{
return neg ? ~val + 1 : val;
}
friend constexpr diffmax_t operator&(diffmax_t a, diffmax_t b) noexcept
{
return _normalize(
a.neg_ && b.neg_,
compl_if(a.neg_ && b.neg_,
compl_if(a.neg_, a.val_) & compl_if(b.neg_, b.val_)));
}
friend constexpr diffmax_t operator|(diffmax_t a, diffmax_t b) noexcept
{
return _normalize(
a.neg_ || b.neg_,
compl_if(a.neg_ || b.neg_,
compl_if(a.neg_, a.val_) | compl_if(b.neg_, b.val_)));
}
friend constexpr diffmax_t operator^(diffmax_t a, diffmax_t b) noexcept
{
return _normalize(
bool(a.neg_ ^ b.neg_),
compl_if(bool(a.neg_ ^ b.neg_),
compl_if(a.neg_, a.val_) ^ compl_if(b.neg_, b.val_)));
}
friend constexpr diffmax_t operator<<(diffmax_t a, diffmax_t b) noexcept
{
RANGES_ENSURE(!a.neg_);
return b.neg_ ? diffmax_t{tag{}, false, a.val_ >> b.val_}
: diffmax_t{tag{}, false, a.val_ << b.val_};
}
friend constexpr diffmax_t operator>>(diffmax_t a, diffmax_t b) noexcept
{
return b.neg_ ? diffmax_t{tag{}, a.neg_, a.val_ << b.val_}
: diffmax_t{tag{}, a.neg_, a.val_ >> b.val_};
}
friend constexpr diffmax_t & operator+=(diffmax_t & a, diffmax_t b) noexcept
{
return (a = a + b);
}
friend constexpr diffmax_t & operator-=(diffmax_t & a, diffmax_t b) noexcept
{
return (a = a - b);
}
friend constexpr diffmax_t & operator*=(diffmax_t & a, diffmax_t b) noexcept
{
return (a = a * b);
}
friend constexpr diffmax_t & operator/=(diffmax_t & a, diffmax_t b) noexcept
{
return (a = a / b);
}
friend constexpr diffmax_t & operator%=(diffmax_t & a, diffmax_t b) noexcept
{
return (a = a % b);
}
friend constexpr diffmax_t & operator&=(diffmax_t & a, diffmax_t b) noexcept
{
return (a = a & b);
}
friend constexpr diffmax_t & operator|=(diffmax_t & a, diffmax_t b) noexcept
{
return (a = a | b);
}
friend constexpr diffmax_t & operator^=(diffmax_t & a, diffmax_t b) noexcept
{
return (a = a ^ b);
}
friend constexpr diffmax_t & operator<<=(diffmax_t & a, diffmax_t b) noexcept
{
a = (a << b);
return a;
}
friend constexpr diffmax_t & operator>>=(diffmax_t & a, diffmax_t b) noexcept
{
a = (a >> b);
return a;
}
template<typename T>
friend constexpr auto operator+=(T & a, diffmax_t b) noexcept
-> CPP_broken_friend_ret(T &)(
requires integral<T>)
{
return (a = static_cast<T>(diffmax_t{a} + b));
}
template<typename T>
friend constexpr auto operator-=(T & a, diffmax_t b) noexcept
-> CPP_broken_friend_ret(T &)(
requires integral<T>)
{
return (a = static_cast<T>(diffmax_t{a} - b));
}
template<typename T>
friend constexpr auto operator*=(T & a, diffmax_t b) noexcept
-> CPP_broken_friend_ret(T &)(
requires integral<T>)
{
return (a = static_cast<T>(diffmax_t{a} * b));
}
template<typename T>
friend constexpr auto operator/=(T & a, diffmax_t b) noexcept
-> CPP_broken_friend_ret(T &)(
requires integral<T>)
{
return (a = static_cast<T>(diffmax_t{a} / b));
}
template<typename T>
friend constexpr auto operator%=(T & a, diffmax_t b) noexcept
-> CPP_broken_friend_ret(T &)(
requires integral<T>)
{
return (a = static_cast<T>(diffmax_t{a} % b));
}
template<typename T>
friend constexpr auto operator&=(T & a, diffmax_t b) noexcept
-> CPP_broken_friend_ret(T &)(
requires integral<T>)
{
return (a = static_cast<T>(diffmax_t{a} & b));
}
template<typename T>
friend constexpr auto operator|=(T & a, diffmax_t b) noexcept
-> CPP_broken_friend_ret(T &)(
requires integral<T>)
{
return (a = static_cast<T>(diffmax_t{a} | b));
}
template<typename T>
friend constexpr auto operator^=(T & a, diffmax_t b) noexcept
-> CPP_broken_friend_ret(T &)(
requires integral<T>)
{
return (a = static_cast<T>(diffmax_t{a} ^ b));
}
template<typename T>
friend constexpr auto operator<<=(T & a, diffmax_t b) noexcept
-> CPP_broken_friend_ret(T &)(
requires integral<T>)
{
a = static_cast<T>(diffmax_t{a} << b);
return a;
}
template<typename T>
friend constexpr auto operator>>=(T & a, diffmax_t b) noexcept
-> CPP_broken_friend_ret(T &)(
requires integral<T>)
{
a = static_cast<T>(diffmax_t{a} >> b);
return a;
}
friend constexpr diffmax_t & operator++(diffmax_t & a) noexcept
{
a.neg_ = (a.neg_ ? --a.val_ : ++a.val_) && a.neg_;
return a;
}
friend constexpr diffmax_t & operator--(diffmax_t & a) noexcept
{
a.neg_ = (a.neg_ ? ++a.val_ : --a.val_) && a.neg_;
return a;
}
friend constexpr diffmax_t operator++(diffmax_t & a, int) noexcept
{
auto tmp = a;
++a;
return tmp;
}
friend constexpr diffmax_t operator--(diffmax_t & a, int) noexcept
{
auto tmp = a;
--a;
return tmp;
}
template(typename T)(
requires integral<T>)
constexpr explicit
operator T() const noexcept
{
return neg_ ? -static_cast<T>(val_) : static_cast<T>(val_);
}
constexpr explicit operator bool() const noexcept
{
return val_ != 0;
}
constexpr bool operator!() const noexcept
{
return val_ == 0;
}
template<typename Ostream>
friend auto operator<<(Ostream & sout, diffmax_t a)
-> CPP_broken_friend_ret(std::ostream &)(
requires derived_from<
Ostream, std::basic_ostream<typename Ostream::char_type,
typename Ostream::traits_type>>)
{
return sout << (&"-"[!a.neg_]) << a.val_;
}
};
#if RANGES_CXX_INLINE_VARIABLES >= RANGES_CXX_INLINE_VARIABLES_17
template<>
inline constexpr bool _is_integer_like_<diffmax_t> = true;
#else
template<typename Enable>
constexpr bool _is_integer_like_<diffmax_t, Enable> = true;
#endif
} // namespace detail
/// \endcond
} // namespace ranges
/// \cond
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
namespace std
{
template<>
struct numeric_limits<::ranges::detail::diffmax_t>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = true;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_NaN = false;
static constexpr bool has_signaling_NaN = false;
static constexpr bool has_denorm = false;
static constexpr bool has_denorm_loss = false;
static constexpr std::float_round_style round_style = std::round_toward_zero;
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = false;
static constexpr int digits = CHAR_BIT * sizeof(std::uintmax_t) + 1;
static constexpr int digits10 =
static_cast<int>(digits * 0.301029996); // digits * std::log10(2)
static constexpr int max_digits10 = 0;
static constexpr int radix = 2;
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr bool traps = true;
static constexpr bool tinyness_before = false;
static constexpr ::ranges::detail::diffmax_t max() noexcept
{
return std::uintmax_t(-1);
}
static constexpr ::ranges::detail::diffmax_t min() noexcept
{
return -max();
}
static constexpr ::ranges::detail::diffmax_t lowest() noexcept
{
return min();
}
static constexpr ::ranges::detail::diffmax_t epsilon() noexcept
{
return 0;
}
static constexpr ::ranges::detail::diffmax_t round_error() noexcept
{
return 0;
}
static constexpr ::ranges::detail::diffmax_t infinity() noexcept
{
return 0;
}
static constexpr ::ranges::detail::diffmax_t quiet_NaN() noexcept
{
return 0;
}
static constexpr ::ranges::detail::diffmax_t signaling_NaN() noexcept
{
return 0;
}
static constexpr ::ranges::detail::diffmax_t denorm_min() noexcept
{
return 0;
}
};
template<>
struct numeric_limits<::ranges::detail::diffmax_t const>
: numeric_limits<::ranges::detail::diffmax_t>
{};
template<>
struct numeric_limits<::ranges::detail::diffmax_t volatile>
: numeric_limits<::ranges::detail::diffmax_t>
{};
template<>
struct numeric_limits<::ranges::detail::diffmax_t const volatile>
: numeric_limits<::ranges::detail::diffmax_t>
{};
#if RANGES_CXX_INLINE_VARIABLES >= RANGES_CXX_INLINE_VARIABLES_17
inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_specialized;
inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_signed;
inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_integer;
inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_exact;
inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::has_infinity;
inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::has_quiet_NaN;
inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::has_signaling_NaN;
inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::has_denorm;
inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::has_denorm_loss;
inline constexpr std::float_round_style
numeric_limits<::ranges::detail::diffmax_t>::round_style;
inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_iec559;
inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_bounded;
inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_modulo;
inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::digits;
inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::digits10;
inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::max_digits10;
inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::radix;
inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::min_exponent;
inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::min_exponent10;
inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::max_exponent;
inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::max_exponent10;
inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::traps;
inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::tinyness_before;
#endif
} // namespace std
/// \endcond
RANGES_DIAGNOSTIC_POP
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,219 @@
/// \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_ITERATOR_INSERT_ITERATORS_HPP
#define RANGES_V3_ITERATOR_INSERT_ITERATORS_HPP
#include <cstddef>
#include <utility>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/utility/addressof.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator
/// @{
template<typename Container>
struct back_insert_iterator
{
using container_type = Container;
using difference_type = std::ptrdiff_t;
constexpr back_insert_iterator() = default;
constexpr explicit back_insert_iterator(Container & x)
: container_(detail::addressof(x))
{}
back_insert_iterator & operator=(typename Container::value_type const & value)
{
container_->push_back(value);
return *this;
}
back_insert_iterator & operator=(typename Container::value_type && value)
{
container_->push_back(std::move(value));
return *this;
}
back_insert_iterator & operator*()
{
return *this;
}
back_insert_iterator & operator++()
{
return *this;
}
back_insert_iterator operator++(int)
{
return *this;
}
private:
Container * container_ = nullptr;
};
struct back_inserter_fn
{
template<typename Container>
constexpr back_insert_iterator<Container> operator()(Container & x) const
{
return back_insert_iterator<Container>{x};
}
};
/// \sa `back_inserter_fn`
RANGES_INLINE_VARIABLE(back_inserter_fn, back_inserter)
template<typename Container>
struct front_insert_iterator
{
using container_type = Container;
using difference_type = std::ptrdiff_t;
constexpr front_insert_iterator() = default;
constexpr explicit front_insert_iterator(Container & x)
: container_(detail::addressof(x))
{}
front_insert_iterator & operator=(typename Container::value_type const & value)
{
container_->push_front(value);
return *this;
}
front_insert_iterator & operator=(typename Container::value_type && value)
{
container_->push_front(std::move(value));
return *this;
}
front_insert_iterator & operator*()
{
return *this;
}
front_insert_iterator & operator++()
{
return *this;
}
front_insert_iterator operator++(int)
{
return *this;
}
private:
Container * container_ = nullptr;
};
struct front_inserter_fn
{
template<typename Cont>
constexpr front_insert_iterator<Cont> operator()(Cont & cont) const
{
return front_insert_iterator<Cont>{cont};
}
};
/// \sa `front_inserter_fn`
RANGES_INLINE_VARIABLE(front_inserter_fn, front_inserter)
template<typename Container>
struct insert_iterator
{
using container_type = Container;
using difference_type = std::ptrdiff_t;
constexpr insert_iterator() = default;
constexpr explicit insert_iterator(Container & x, typename Container::iterator w)
: container_(detail::addressof(x))
, where_(w)
{}
insert_iterator & operator=(typename Container::value_type const & value)
{
where_ = ranges::next(container_->insert(where_, value));
return *this;
}
insert_iterator & operator=(typename Container::value_type && value)
{
where_ = ranges::next(container_->insert(where_, std::move(value)));
return *this;
}
insert_iterator & operator*()
{
return *this;
}
insert_iterator & operator++()
{
return *this;
}
insert_iterator & operator++(int)
{
return *this;
}
private:
Container * container_ = nullptr;
typename Container::iterator where_ = typename Container::iterator();
};
struct inserter_fn
{
template<typename Cont>
constexpr insert_iterator<Cont> operator()(Cont & cont,
typename Cont::iterator where) const
{
return insert_iterator<Cont>{cont, std::move(where)};
}
};
/// \sa `inserter_fn`
RANGES_INLINE_VARIABLE(inserter_fn, inserter)
namespace cpp20
{
using ranges::back_insert_iterator;
using ranges::back_inserter;
using ranges::front_insert_iterator;
using ranges::front_inserter;
using ranges::insert_iterator;
using ranges::inserter;
} // namespace cpp20
/// @}
} // namespace ranges
/// \cond
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
namespace std
{
template<typename Container>
struct iterator_traits<::ranges::back_insert_iterator<Container>>
: ::ranges::detail::std_output_iterator_traits<>
{};
template<typename Container>
struct iterator_traits<::ranges::front_insert_iterator<Container>>
: ::ranges::detail::std_output_iterator_traits<>
{};
template<typename Container>
struct iterator_traits<::ranges::insert_iterator<Container>>
: ::ranges::detail::std_output_iterator_traits<>
{};
} // namespace std
RANGES_DIAGNOSTIC_POP
/// \endcond
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_ITERATOR_INSERT_ITERATORS_HPP

View File

@@ -0,0 +1,453 @@
/// \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_ITERATOR_MOVE_ITERATORS_HPP
#define RANGES_V3_ITERATOR_MOVE_ITERATORS_HPP
#include <cstddef>
#include <utility>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/basic_iterator.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/iterator/traits.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator
/// @{
template<typename I>
struct move_iterator
{
private:
CPP_assert(input_iterator<I>);
I current_ = I{};
public:
using iterator_type = I;
using difference_type = iter_difference_t<I>;
using value_type = iter_value_t<I>;
using iterator_category = std::input_iterator_tag;
using reference = iter_rvalue_reference_t<I>;
constexpr move_iterator() = default;
explicit move_iterator(I i)
: current_(i)
{}
template(typename O)(
requires convertible_to<O, I>)
move_iterator(move_iterator<O> const & i)
: current_(i.base())
{}
template(typename O)(
requires convertible_to<O, I>)
move_iterator & operator=(move_iterator<O> const & i)
{
current_ = i.base();
return *this;
}
I base() const
{
return current_;
}
// clang-format off
auto CPP_auto_fun(operator*)()(const)
(
return iter_move(current_)
)
// clang-format on
move_iterator &
operator++()
{
++current_;
return *this;
}
CPP_member
auto operator++(int) //
-> CPP_ret(void)(
requires (!forward_iterator<I>))
{
++current_;
}
CPP_member
auto operator++(int) //
-> CPP_ret(move_iterator)(
requires forward_iterator<I>)
{
return move_iterator(current_++);
}
CPP_member
auto operator--() //
-> CPP_ret(move_iterator &)(
requires forward_iterator<I>)
{
--current_;
return *this;
}
CPP_member
auto operator--(int) //
-> CPP_ret(move_iterator)(
requires bidirectional_iterator<I>)
{
return move_iterator(current_--);
}
CPP_member
auto operator+(difference_type n) const //
-> CPP_ret(move_iterator)(
requires random_access_iterator<I>)
{
return move_iterator(current_ + n);
}
CPP_member
auto operator+=(difference_type n)
-> CPP_ret(move_iterator &)(
requires random_access_iterator<I>)
{
current_ += n;
return *this;
}
CPP_member
auto operator-(difference_type n) const //
-> CPP_ret(move_iterator)(
requires random_access_iterator<I>)
{
return move_iterator(current_ - n);
}
CPP_member
auto operator-=(difference_type n) //
-> CPP_ret(move_iterator &)(
requires random_access_iterator<I>)
{
current_ -= n;
return *this;
}
CPP_member
auto operator[](difference_type n) const //
-> CPP_ret(reference)(
requires random_access_iterator<I>)
{
return iter_move(current_ + n);
}
template<typename I2>
friend auto operator==(move_iterator const & x, move_iterator<I2> const & y)
-> CPP_broken_friend_ret(bool)(
requires equality_comparable_with<I, I2>)
{
return x.base() == y.base();
}
template<typename I2>
friend auto operator!=(move_iterator const & x, move_iterator<I2> const & y)
-> CPP_broken_friend_ret(bool)(
requires equality_comparable_with<I, I2>)
{
return !(x == y);
}
template<typename I2>
friend auto operator<(move_iterator const & x, move_iterator<I2> const & y)
-> CPP_broken_friend_ret(bool)(
requires totally_ordered_with<I, I2>)
{
return x.base() < y.base();
}
template<typename I2>
friend auto operator<=(move_iterator const & x, move_iterator<I2> const & y)
-> CPP_broken_friend_ret(bool)(
requires totally_ordered_with<I, I2>)
{
return !(y < x);
}
template<typename I2>
friend auto operator>(move_iterator const & x, move_iterator<I2> const & y)
-> CPP_broken_friend_ret(bool)(
requires totally_ordered_with<I, I2>)
{
return y < x;
}
template<typename I2>
friend auto operator>=(move_iterator const & x, move_iterator<I2> const & y)
-> CPP_broken_friend_ret(bool)(
requires totally_ordered_with<I, I2>)
{
return !(x < y);
}
template<typename I2>
friend auto operator-(move_iterator const & x, move_iterator<I2> const & y)
-> CPP_broken_friend_ret(iter_difference_t<I2>)(
requires sized_sentinel_for<I, I2>)
{
return x.base() - y.base();
}
CPP_broken_friend_member
friend auto operator+(iter_difference_t<I> n,
move_iterator const & x)
-> CPP_broken_friend_ret(move_iterator)(
requires random_access_iterator<I>)
{
return x + n;
}
};
struct make_move_iterator_fn
{
template(typename I)(
requires input_iterator<I>)
constexpr move_iterator<I> operator()(I it) const
{
return move_iterator<I>{detail::move(it)};
}
};
RANGES_INLINE_VARIABLE(make_move_iterator_fn, make_move_iterator)
template<typename S>
struct move_sentinel
{
private:
S sent_;
public:
constexpr move_sentinel()
: sent_{}
{}
constexpr explicit move_sentinel(S s)
: sent_(detail::move(s))
{}
template(typename OS)(
requires convertible_to<OS, S>)
constexpr explicit move_sentinel(move_sentinel<OS> const & that)
: sent_(that.base())
{}
template(typename OS)(
requires convertible_to<OS, S>)
move_sentinel & operator=(move_sentinel<OS> const & that)
{
sent_ = that.base();
return *this;
}
S base() const
{
return sent_;
}
template<typename I>
friend auto operator==(move_iterator<I> const & i, move_sentinel const & s)
-> CPP_broken_friend_ret(bool)(
requires sentinel_for<S, I>)
{
return i.base() == s.base();
}
template<typename I>
friend auto operator==(move_sentinel const & s, move_iterator<I> const & i)
-> CPP_broken_friend_ret(bool)(
requires sentinel_for<S, I>)
{
return s.base() == i.base();
}
template<typename I>
friend auto operator!=(move_iterator<I> const & i, move_sentinel const & s)
-> CPP_broken_friend_ret(bool)(
requires sentinel_for<S, I>)
{
return i.base() != s.base();
}
template<typename I>
friend auto operator!=(move_sentinel const & s, move_iterator<I> const & i)
-> CPP_broken_friend_ret(bool)(
requires sentinel_for<S, I>)
{
return s.base() != i.base();
}
};
struct make_move_sentinel_fn
{
template(typename I)(
requires input_iterator<I>)
constexpr move_iterator<I> operator()(I i) const
{
return move_iterator<I>{detail::move(i)};
}
template(typename S)(
requires semiregular<S> AND (!input_iterator<S>)) //
constexpr move_sentinel<S> operator()(S s) const
{
return move_sentinel<S>{detail::move(s)};
}
};
RANGES_INLINE_VARIABLE(make_move_sentinel_fn, make_move_sentinel)
/// \cond
namespace detail
{
template<typename I, bool IsReadable>
struct move_into_cursor_types_
{};
template<typename I>
struct move_into_cursor_types_<I, true>
{
using value_type = iter_value_t<I>;
using single_pass = meta::bool_<(bool)single_pass_iterator_<I>>;
};
template<typename I>
using move_into_cursor_types =
move_into_cursor_types_<I, (bool)indirectly_readable<I>>;
template<typename I>
struct move_into_cursor : move_into_cursor_types<I>
{
private:
friend range_access;
struct mixin : basic_mixin<move_into_cursor>
{
mixin() = default;
#ifndef _MSC_VER
using basic_mixin<move_into_cursor>::basic_mixin;
#else
constexpr explicit mixin(move_into_cursor && cur)
: basic_mixin<move_into_cursor>(static_cast<move_into_cursor &&>(cur))
{}
constexpr explicit mixin(move_into_cursor const & cur)
: basic_mixin<move_into_cursor>(cur)
{}
#endif
explicit mixin(I it)
: mixin{move_into_cursor{std::move(it)}}
{}
I base() const
{
return this->get().it_;
}
};
I it_ = I();
explicit move_into_cursor(I it)
: it_(std::move(it))
{}
void next()
{
++it_;
}
template(typename T)(
requires indirectly_writable<I, aux::move_t<T>>)
void write(T && t) noexcept(noexcept(*it_ = std::move(t)))
{
*it_ = std::move(t);
}
template(typename T)(
requires indirectly_writable<I, aux::move_t<T>>)
void write(T && t) const noexcept(noexcept(*it_ = std::move(t)))
{
*it_ = std::move(t);
}
CPP_member
auto read() const noexcept(noexcept(*std::declval<I const &>()))
-> CPP_ret(iter_reference_t<I>)(
requires indirectly_readable<I>)
{
return *it_;
}
CPP_member
auto equal(move_into_cursor const & that) const //
-> CPP_ret(bool)(
requires input_iterator<I>)
{
return it_ == that.it_;
}
CPP_member
auto prev() //
-> CPP_ret(void)(
requires bidirectional_iterator<I>)
{
--it_;
}
CPP_member
auto advance(iter_difference_t<I> n) //
-> CPP_ret(void)(
requires random_access_iterator<I>)
{
it_ += n;
}
CPP_member
auto distance_to(move_into_cursor const & that) const //
-> CPP_ret(iter_difference_t<I>)(
requires sized_sentinel_for<I, I>)
{
return that.it_ - it_;
}
template(typename II = I const)(
requires same_as<I const, II> AND indirectly_readable<II>)
constexpr iter_rvalue_reference_t<II> move() const //
noexcept(has_nothrow_iter_move_v<II>)
{
return iter_move(it_);
}
public:
constexpr move_into_cursor() = default;
};
} // namespace detail
/// \endcond
struct move_into_fn
{
template<typename I>
constexpr move_into_iterator<I> operator()(I it) const
{
return move_into_iterator<I>{std::move(it)};
}
};
/// \sa `move_into_fn`
RANGES_INLINE_VARIABLE(move_into_fn, move_into)
namespace cpp20
{
using ranges::make_move_iterator;
using ranges::move_iterator;
using ranges::move_sentinel;
} // namespace cpp20
/// @}
} // namespace ranges
/// \cond
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
namespace std
{
template<typename I>
struct iterator_traits<::ranges::move_iterator<I>>
{
using iterator_category = std::input_iterator_tag;
using difference_type = typename ::ranges::move_iterator<I>::difference_type;
using value_type = typename ::ranges::move_iterator<I>::value_type;
using reference = typename ::ranges::move_iterator<I>::reference;
using pointer = meta::_t<std::add_pointer<reference>>;
};
} // namespace std
RANGES_DIAGNOSTIC_POP
/// \endcond
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_ITERATOR_MOVE_ITERATORS_HPP

View File

@@ -0,0 +1,650 @@
/// \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_ITERATOR_OPERATIONS_HPP
#define RANGES_V3_ITERATOR_OPERATIONS_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/concepts.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator
/// @{
/// \cond
template<typename I>
// requires input_or_output_iterator<I>
struct counted_iterator;
/// \endcond
struct advance_fn
{
#if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
template(typename I)(
requires input_or_output_iterator<I>)
constexpr void operator()(I & i, iter_difference_t<I> n) const
// [[expects: n >= 0 || bidirectional_iterator<I>]]
{
if constexpr(random_access_iterator<I>)
{
i += n;
}
else
{
if constexpr(bidirectional_iterator<I>)
for(; 0 > n; ++n)
--i;
RANGES_EXPECT(0 <= n);
for(; 0 < n; --n)
++i;
}
}
template(typename I, typename S)(
requires sentinel_for<S, I>)
constexpr void operator()(I & i, S bound) const
// [[expects axiom: reachable(i, bound)]]
{
if constexpr(assignable_from<I &, S>)
{
i = std::move(bound);
}
else if constexpr(sized_sentinel_for<S, I>)
{
iter_difference_t<I> d = bound - i;
RANGES_EXPECT(0 <= d);
(*this)(i, d);
}
else
while(i != bound)
++i;
}
template(typename I, typename S)(
requires sentinel_for<S, I>)
constexpr iter_difference_t<I> //
operator()(I & i, iter_difference_t<I> n, S bound) const
// [[expects axiom: 0 == n ||
// (0 < n && reachable(i, bound)) ||
// (0 > n && same_as<I, S> && bidirectional_iterator<I> && reachable(bound,
// i))]]
{
if constexpr(sized_sentinel_for<S, I>)
{
if(0 == n)
return 0;
const auto d = bound - i;
if constexpr(bidirectional_iterator<I> && same_as<I, S>)
{
RANGES_EXPECT(0 <= n ? 0 <= d : 0 >= d);
if(0 <= n ? d <= n : d >= n)
{
i = std::move(bound);
return n - d;
}
}
else
{
RANGES_EXPECT(0 <= n && 0 <= d);
if(d <= n)
{
(*this)(i, std::move(bound));
return n - d;
}
}
(*this)(i, n);
return 0;
}
else
{
if constexpr(bidirectional_iterator<I> && same_as<I, S>)
{
if(0 > n)
{
do
{
--i;
++n;
} while(0 != n && i != bound);
return n;
}
}
RANGES_EXPECT(0 <= n);
while(0 != n && i != bound)
{
++i;
--n;
}
return n;
}
}
#else
private:
template<typename I>
static constexpr void n_(I & i, iter_difference_t<I> n, std::input_iterator_tag);
template<typename I>
static constexpr void n_(I & i, iter_difference_t<I> n,
std::bidirectional_iterator_tag);
template<typename I>
static constexpr void n_(I & i, iter_difference_t<I> n,
std::random_access_iterator_tag);
template<typename I, typename S>
static constexpr void to_impl_(I & i, S s, sentinel_tag);
template<typename I, typename S>
static constexpr void to_impl_(I & i, S s, sized_sentinel_tag);
template<typename I, typename S>
static constexpr void to_(I & i, S s, std::true_type); // assignable
template<typename I, typename S>
static constexpr void to_(I & i, S s, std::false_type); // !assignable
template<typename I, typename S>
static constexpr iter_difference_t<I> bounded_(I & it, iter_difference_t<I> n,
S bound, sentinel_tag,
std::input_iterator_tag);
template<typename I>
static constexpr iter_difference_t<I> bounded_(I & it, iter_difference_t<I> n,
I bound, sentinel_tag,
std::bidirectional_iterator_tag);
template<typename I, typename S, typename Concept>
static constexpr iter_difference_t<I> bounded_(I & it, iter_difference_t<I> n,
S bound, sized_sentinel_tag,
Concept);
public:
// Advance a certain number of steps:
template(typename I)(
requires input_or_output_iterator<I>)
constexpr void operator()(I & i, iter_difference_t<I> n) const
{
advance_fn::n_(i, n, iterator_tag_of<I>{});
}
// Advance to a certain position:
template(typename I, typename S)(
requires sentinel_for<S, I>)
constexpr void operator()(I & i, S s) const
{
advance_fn::to_(
i, static_cast<S &&>(s), meta::bool_<assignable_from<I &, S>>());
}
// Advance a certain number of times, with a bound:
template(typename I, typename S)(
requires sentinel_for<S, I>)
constexpr iter_difference_t<I> //
operator()(I & it, iter_difference_t<I> n, S bound) const
{
return advance_fn::bounded_(it,
n,
static_cast<S &&>(bound),
sentinel_tag_of<S, I>(),
iterator_tag_of<I>());
}
#endif
template(typename I)(
requires input_or_output_iterator<I>)
constexpr void operator()(counted_iterator<I> & i, iter_difference_t<I> n) const;
};
/// \sa `advance_fn`
RANGES_INLINE_VARIABLE(advance_fn, advance)
#if RANGES_CXX_IF_CONSTEXPR < RANGES_CXX_IF_CONSTEXPR_17
template<typename I>
constexpr void advance_fn::n_(I & i, iter_difference_t<I> n, std::input_iterator_tag)
{
RANGES_EXPECT(n >= 0);
for(; n > 0; --n)
++i;
}
template<typename I>
constexpr void advance_fn::n_(I & i, iter_difference_t<I> n,
std::bidirectional_iterator_tag)
{
if(n > 0)
for(; n > 0; --n)
++i;
else
for(; n < 0; ++n)
--i;
}
template<typename I>
constexpr void advance_fn::n_(I & i, iter_difference_t<I> n,
std::random_access_iterator_tag)
{
i += n;
}
template<typename I, typename S>
constexpr void advance_fn::to_impl_(I & i, S s, sentinel_tag)
{
while(i != s)
++i;
}
template<typename I, typename S>
constexpr void advance_fn::to_impl_(I & i, S s, sized_sentinel_tag)
{
iter_difference_t<I> d = s - i;
RANGES_EXPECT(0 <= d);
advance(i, d);
}
// Advance to a certain position:
template<typename I, typename S>
constexpr void advance_fn::to_(I & i, S s, std::true_type)
{
i = static_cast<S &&>(s);
}
template<typename I, typename S>
constexpr void advance_fn::to_(I & i, S s, std::false_type)
{
advance_fn::to_impl_(i, static_cast<S &&>(s), sentinel_tag_of<S, I>());
}
template<typename I, typename S>
constexpr iter_difference_t<I> advance_fn::bounded_(I & it, iter_difference_t<I> n,
S bound, sentinel_tag,
std::input_iterator_tag)
{
RANGES_EXPECT(0 <= n);
for(; 0 != n && it != bound; --n)
++it;
return n;
}
template<typename I>
constexpr iter_difference_t<I> advance_fn::bounded_(I & it, iter_difference_t<I> n,
I bound, sentinel_tag,
std::bidirectional_iterator_tag)
{
if(0 <= n)
for(; 0 != n && it != bound; --n)
++it;
else
for(; 0 != n && it != bound; ++n)
--it;
return n;
}
template<typename I, typename S, typename Concept>
constexpr iter_difference_t<I> advance_fn::bounded_(I & it, iter_difference_t<I> n,
S bound, sized_sentinel_tag,
Concept)
{
RANGES_EXPECT(((bool)same_as<I, S> || 0 <= n));
if(n == 0)
return 0;
iter_difference_t<I> d = bound - it;
RANGES_EXPECT(0 <= n ? 0 <= d : 0 >= d);
if(0 <= n ? n >= d : n <= d)
{
advance(it, static_cast<S &&>(bound));
return n - d;
}
advance(it, n);
return 0;
}
#endif
struct next_fn
{
template(typename I)(
requires input_or_output_iterator<I>)
constexpr I operator()(I it) const
{
return ++it;
}
template(typename I)(
requires input_or_output_iterator<I>)
constexpr I operator()(I it, iter_difference_t<I> n) const
{
advance(it, n);
return it;
}
template(typename I, typename S)(
requires sentinel_for<S, I>)
constexpr I operator()(I it, S s) const
{
advance(it, static_cast<S &&>(s));
return it;
}
template(typename I, typename S)(
requires sentinel_for<S, I>)
constexpr I operator()(I it, iter_difference_t<I> n, S bound) const
{
advance(it, n, static_cast<S &&>(bound));
return it;
}
};
/// \sa `next_fn`
RANGES_INLINE_VARIABLE(next_fn, next)
struct prev_fn
{
template(typename I)(
requires bidirectional_iterator<I>)
constexpr I operator()(I it) const
{
return --it;
}
template(typename I)(
requires bidirectional_iterator<I>)
constexpr I operator()(I it, iter_difference_t<I> n) const
{
advance(it, -n);
return it;
}
template(typename I)(
requires bidirectional_iterator<I>)
constexpr I operator()(I it, iter_difference_t<I> n, I bound) const
{
advance(it, -n, static_cast<I &&>(bound));
return it;
}
};
/// \sa `prev_fn`
RANGES_INLINE_VARIABLE(prev_fn, prev)
struct iter_enumerate_fn
{
private:
template(typename I, typename S)(
requires (!sized_sentinel_for<I, I>)) //
static constexpr std::pair<iter_difference_t<I>, I> //
impl_i(I first, S last, sentinel_tag)
{
iter_difference_t<I> d = 0;
for(; first != last; ++first)
++d;
return {d, first};
}
template(typename I, typename S)(
requires sized_sentinel_for<I, I>)
static constexpr std::pair<iter_difference_t<I>, I> //
impl_i(I first, S end_, sentinel_tag)
{
I last = ranges::next(first, end_);
auto n = static_cast<iter_difference_t<I>>(last - first);
RANGES_EXPECT(((bool)same_as<I, S> || 0 <= n));
return {n, last};
}
template<typename I, typename S>
static constexpr std::pair<iter_difference_t<I>, I> //
impl_i(I first, S last, sized_sentinel_tag)
{
auto n = static_cast<iter_difference_t<I>>(last - first);
RANGES_EXPECT(((bool)same_as<I, S> || 0 <= n));
return {n, ranges::next(first, last)};
}
public:
template(typename I, typename S)(
requires sentinel_for<S, I>)
constexpr std::pair<iter_difference_t<I>, I> operator()(I first, S last) const
{
return iter_enumerate_fn::impl_i(static_cast<I &&>(first),
static_cast<S &&>(last),
sentinel_tag_of<S, I>());
}
};
/// \sa `iter_enumerate_fn`
RANGES_INLINE_VARIABLE(iter_enumerate_fn, iter_enumerate)
struct iter_distance_fn
{
private:
template<typename I, typename S>
static constexpr iter_difference_t<I> impl_i(I first, S last, sentinel_tag)
{
return iter_enumerate(static_cast<I &&>(first), static_cast<S &&>(last))
.first;
}
template<typename I, typename S>
static constexpr iter_difference_t<I> impl_i(I first, S last, sized_sentinel_tag)
{
auto n = static_cast<iter_difference_t<I>>(last - first);
RANGES_EXPECT(((bool)same_as<I, S> || 0 <= n));
return n;
}
public:
template(typename I, typename S)(
requires input_or_output_iterator<I> AND sentinel_for<S, I>)
constexpr iter_difference_t<I> operator()(I first, S last) const
{
return iter_distance_fn::impl_i(static_cast<I &&>(first),
static_cast<S &&>(last),
sentinel_tag_of<S, I>());
}
};
/// \sa `iter_distance_fn`
RANGES_INLINE_VARIABLE(iter_distance_fn, iter_distance)
struct iter_distance_compare_fn
{
private:
template<typename I, typename S>
static constexpr int impl_i(I first, S last, iter_difference_t<I> n, sentinel_tag)
{
if(n < 0)
return 1;
for(; n > 0; --n, ++first)
{
if(first == last)
return -1;
}
return first == last ? 0 : 1;
}
template<typename I, typename S>
static constexpr int impl_i(I first, S last, iter_difference_t<I> n,
sized_sentinel_tag)
{
iter_difference_t<I> dist = last - first;
if(n < dist)
return 1;
if(dist < n)
return -1;
return 0;
}
public:
template(typename I, typename S)(
requires input_iterator<I> AND sentinel_for<S, I>)
constexpr int operator()(I first, S last, iter_difference_t<I> n) const
{
return iter_distance_compare_fn::impl_i(static_cast<I &&>(first),
static_cast<S &&>(last),
n,
sentinel_tag_of<S, I>());
}
};
/// \sa `iter_distance_compare_fn`
RANGES_INLINE_VARIABLE(iter_distance_compare_fn, iter_distance_compare)
// Like distance(b,e), but guaranteed to be O(1)
struct iter_size_fn
{
template(typename I, typename S)(
requires sized_sentinel_for<S, I>)
constexpr meta::_t<std::make_unsigned<iter_difference_t<I>>> //
operator()(I const & first, S last) const
{
using size_type = meta::_t<std::make_unsigned<iter_difference_t<I>>>;
iter_difference_t<I> n = last - first;
RANGES_EXPECT(0 <= n);
return static_cast<size_type>(n);
}
};
/// \sa `iter_size_fn`
RANGES_INLINE_VARIABLE(iter_size_fn, iter_size)
/// \cond
namespace adl_uncounted_recounted_detail
{
template<typename I>
constexpr I uncounted(I i)
{
return i;
}
template<typename I>
constexpr I recounted(I const &, I i, iter_difference_t<I>)
{
return i;
}
struct uncounted_fn
{
template<typename I>
constexpr auto operator()(I i) const -> decltype(uncounted((I &&) i))
{
return uncounted((I &&) i);
}
};
struct recounted_fn
{
template<typename I, typename J>
constexpr auto operator()(I i, J j, iter_difference_t<J> n) const
-> decltype(recounted((I &&) i, (J &&) j, n))
{
return recounted((I &&) i, (J &&) j, n);
}
};
} // namespace adl_uncounted_recounted_detail
/// \endcond
RANGES_INLINE_VARIABLE(adl_uncounted_recounted_detail::uncounted_fn, uncounted)
RANGES_INLINE_VARIABLE(adl_uncounted_recounted_detail::recounted_fn, recounted)
struct enumerate_fn : iter_enumerate_fn
{
private:
template<typename Rng>
static constexpr std::pair<range_difference_t<Rng>, iterator_t<Rng>> impl_r(
Rng & rng, range_tag, range_tag)
{
return iter_enumerate(begin(rng), end(rng));
}
template<typename Rng>
static constexpr std::pair<range_difference_t<Rng>, iterator_t<Rng>> impl_r(
Rng & rng, common_range_tag, sized_range_tag)
{
return {static_cast<range_difference_t<Rng>>(size(rng)), end(rng)};
}
public:
using iter_enumerate_fn::operator();
template(typename Rng)(
requires range<Rng>)
constexpr std::pair<range_difference_t<Rng>, iterator_t<Rng>> operator()(Rng && rng) const
{
// Better not be trying to compute the distance of an infinite range:
RANGES_EXPECT(!is_infinite<Rng>::value);
return enumerate_fn::impl_r(
rng, common_range_tag_of<Rng>(), sized_range_tag_of<Rng>());
}
};
/// \sa `enumerate_fn`
RANGES_INLINE_VARIABLE(enumerate_fn, enumerate)
struct distance_fn : iter_distance_fn
{
private:
template<typename Rng>
static range_difference_t<Rng> impl_r(Rng & rng, range_tag)
{
return enumerate(rng).first;
}
template<typename Rng>
static constexpr range_difference_t<Rng> impl_r(Rng & rng, sized_range_tag)
{
return static_cast<range_difference_t<Rng>>(size(rng));
}
public:
using iter_distance_fn::operator();
template(typename Rng)(
requires range<Rng>)
constexpr range_difference_t<Rng> operator()(Rng && rng) const
{
// Better not be trying to compute the distance of an infinite range:
RANGES_EXPECT(!is_infinite<Rng>::value);
return distance_fn::impl_r(rng, sized_range_tag_of<Rng>());
}
};
/// \sa `distance_fn`
RANGES_INLINE_VARIABLE(distance_fn, distance)
// The interface of distance_compare is taken from Util.listLengthCmp in the GHC API.
struct distance_compare_fn : iter_distance_compare_fn
{
private:
template<typename Rng>
static constexpr int impl_r(Rng & rng, range_difference_t<Rng> n, range_tag)
{
// Infinite ranges are always compared to be larger than a finite number.
return is_infinite<Rng>::value
? 1
: iter_distance_compare(begin(rng), end(rng), n);
}
template<typename Rng>
static constexpr int impl_r(Rng & rng, range_difference_t<Rng> n, sized_range_tag)
{
auto dist = distance(rng); // O(1) since rng is a sized_range
if(dist > n)
return 1;
else if(dist < n)
return -1;
else
return 0;
}
public:
using iter_distance_compare_fn::operator();
template(typename Rng)(
requires range<Rng>)
constexpr int operator()(Rng && rng, range_difference_t<Rng> n) const
{
return distance_compare_fn::impl_r(rng, n, sized_range_tag_of<Rng>());
}
};
/// \sa `distance_compare_fn`
RANGES_INLINE_VARIABLE(distance_compare_fn, distance_compare)
namespace cpp20
{
using ranges::advance;
using ranges::distance;
using ranges::next;
using ranges::prev;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_ITERATOR_OPERATIONS_HPP

View File

@@ -0,0 +1,155 @@
/// \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_ITERATOR_REVERSE_ITERATOR_HPP
#define RANGES_V3_ITERATOR_REVERSE_ITERATOR_HPP
#include <utility>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/basic_iterator.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator
/// @{
/// \cond
namespace detail
{
template<typename I>
struct reverse_cursor
{
private:
CPP_assert(bidirectional_iterator<I>);
friend range_access;
using value_type = iter_value_t<I>;
template<typename OtherI>
friend struct reverse_cursor;
struct mixin : basic_mixin<reverse_cursor>
{
mixin() = default;
#ifndef _MSC_VER
using basic_mixin<reverse_cursor>::basic_mixin;
#else
constexpr explicit mixin(reverse_cursor && cur)
: basic_mixin<reverse_cursor>(static_cast<reverse_cursor &&>(cur))
{}
constexpr explicit mixin(reverse_cursor const & cur)
: basic_mixin<reverse_cursor>(cur)
{}
#endif
constexpr mixin(I it)
: mixin{reverse_cursor{it}}
{}
constexpr I base() const
{
return this->get().base();
}
};
I it_;
constexpr reverse_cursor(I it)
: it_(std::move(it))
{}
constexpr iter_reference_t<I> read() const
{
return *arrow();
}
constexpr I arrow() const
{
auto tmp = it_;
--tmp;
return tmp;
}
constexpr I base() const
{
return it_;
}
template(typename J)(
requires sentinel_for<J, I>)
constexpr bool equal(reverse_cursor<J> const & that) const
{
return it_ == that.it_;
}
constexpr void next()
{
--it_;
}
constexpr void prev()
{
++it_;
}
CPP_member
constexpr auto advance(iter_difference_t<I> n) //
-> CPP_ret(void)(
requires random_access_iterator<I>)
{
it_ -= n;
}
template(typename J)(
requires sized_sentinel_for<J, I>)
constexpr iter_difference_t<I> distance_to(reverse_cursor<J> const & that) //
const
{
return it_ - that.base();
}
constexpr iter_rvalue_reference_t<I> move() const
noexcept(noexcept((void)I(I(it_)), (void)--const_cast<I &>(it_),
iter_move(it_)))
{
auto tmp = it_;
--tmp;
return iter_move(tmp);
}
public:
reverse_cursor() = default;
template(typename U)(
requires convertible_to<U, I>)
constexpr reverse_cursor(reverse_cursor<U> const & u)
: it_(u.base())
{}
};
} // namespace detail
/// \endcond
struct make_reverse_iterator_fn
{
template(typename I)(
requires bidirectional_iterator<I>)
constexpr reverse_iterator<I> operator()(I i) const
{
return reverse_iterator<I>(i);
}
};
RANGES_INLINE_VARIABLE(make_reverse_iterator_fn, make_reverse_iterator)
namespace cpp20
{
using ranges::make_reverse_iterator;
using ranges::reverse_iterator;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_ITERATOR_REVERSE_ITERATOR_HPP

View File

@@ -0,0 +1,272 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2014-present
// Copyright Google LLC 2020-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_ITERATOR_STREAM_ITERATORS_HPP
#define RANGES_V3_ITERATOR_STREAM_ITERATORS_HPP
#include <cstddef>
#include <iosfwd>
#include <iterator>
#include <string>
#include <type_traits>
#include <utility>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator
/// @{
template<typename T = void, typename Char = char,
typename Traits = std::char_traits<Char>>
struct ostream_iterator
{
private:
template<class U>
using value_t = meta::if_<std::is_void<T>, U, T>;
public:
using difference_type = std::ptrdiff_t;
using char_type = Char;
using traits_type = Traits;
using ostream_type = std::basic_ostream<Char, Traits>;
constexpr ostream_iterator() = default;
ostream_iterator(ostream_type & s, Char const * d = nullptr) noexcept
: sout_(&s)
, delim_(d)
{}
template(typename U)(
requires convertible_to<U, value_t<U> const &>)
ostream_iterator & operator=(U && value)
{
RANGES_EXPECT(sout_);
*sout_ << static_cast<value_t<U> const &>(static_cast<U &&>(value));
if(delim_)
*sout_ << delim_;
return *this;
}
ostream_iterator & operator*()
{
return *this;
}
ostream_iterator & operator++()
{
return *this;
}
ostream_iterator & operator++(int)
{
return *this;
}
private:
ostream_type * sout_;
Char const * delim_;
};
template<typename Delim, typename Char = char,
typename Traits = std::char_traits<Char>>
struct ostream_joiner
{
CPP_assert(semiregular<Delim>);
using difference_type = std::ptrdiff_t;
using char_type = Char;
using traits_type = Traits;
using ostream_type = std::basic_ostream<Char, Traits>;
constexpr ostream_joiner() = default;
ostream_joiner(ostream_type & s, Delim const & d)
: delim_(d)
, sout_(std::addressof(s))
, first_(true)
{}
ostream_joiner(ostream_type & s, Delim && d)
: delim_(std::move(d))
, sout_(std::addressof(s))
, first_(true)
{}
template<typename T>
ostream_joiner & operator=(T const & value)
{
RANGES_EXPECT(sout_);
if(!first_)
*sout_ << delim_;
first_ = false;
*sout_ << value;
return *this;
}
ostream_joiner & operator*() noexcept
{
return *this;
}
ostream_joiner & operator++() noexcept
{
return *this;
}
ostream_joiner & operator++(int) noexcept
{
return *this;
}
private:
Delim delim_;
ostream_type * sout_;
bool first_;
};
struct make_ostream_joiner_fn
{
template(typename Delim, typename Char, typename Traits)(
requires semiregular<detail::decay_t<Delim>>)
ostream_joiner<detail::decay_t<Delim>, Char, Traits> //
operator()(std::basic_ostream<Char, Traits> & s, Delim && d) const
{
return {s, std::forward<Delim>(d)};
}
};
/// \sa `make_ostream_joiner_fn`
RANGES_INLINE_VARIABLE(make_ostream_joiner_fn, make_ostream_joiner)
template<typename Char, typename Traits = std::char_traits<Char>>
struct ostreambuf_iterator
{
public:
typedef ptrdiff_t difference_type;
typedef Char char_type;
typedef Traits traits_type;
typedef std::basic_streambuf<Char, Traits> streambuf_type;
typedef std::basic_ostream<Char, Traits> ostream_type;
constexpr ostreambuf_iterator() = default;
ostreambuf_iterator(ostream_type & s) noexcept
: ostreambuf_iterator(s.rdbuf())
{}
ostreambuf_iterator(streambuf_type * s) noexcept
: sbuf_(s)
{
RANGES_ASSERT(s != nullptr);
}
ostreambuf_iterator & operator=(Char c)
{
RANGES_ASSERT(sbuf_ != nullptr);
if(!failed_)
failed_ = (sbuf_->sputc(c) == Traits::eof());
return *this;
}
ostreambuf_iterator & operator*()
{
return *this;
}
ostreambuf_iterator & operator++()
{
return *this;
}
ostreambuf_iterator & operator++(int)
{
return *this;
}
bool failed() const noexcept
{
return failed_;
}
private:
streambuf_type * sbuf_ = nullptr;
bool failed_ = false;
};
namespace cpp20
{
template<typename T, typename Char = char,
typename Traits = std::char_traits<Char>>
using ostream_iterator = ranges::ostream_iterator<T, Char, Traits>;
using ranges::ostreambuf_iterator;
} // namespace cpp20
/// \brief Writes to an ostream object using the unformatted
/// `std::basic_ostream::write` operation. This means that `32` will be encoded as
/// `100000` as opposed to the string "32".
///
template<typename CharT = char, typename Traits = std::char_traits<CharT>>
class unformatted_ostream_iterator final
{
public:
using iterator_category = std::output_iterator_tag;
using difference_type = std::ptrdiff_t;
using char_type = CharT;
using traits_type = Traits;
using ostream_type = std::basic_ostream<CharT, Traits>;
unformatted_ostream_iterator() = default;
explicit unformatted_ostream_iterator(ostream_type & out) noexcept
: out_(&out)
{}
template<typename T>
// requires stream_insertible<T, ostream_type>
unformatted_ostream_iterator & operator=(T const & t)
{
RANGES_EXPECT(out_);
out_->write(reinterpret_cast<char const *>(std::addressof(t)), sizeof(T));
return *this;
}
unformatted_ostream_iterator & operator*() noexcept
{
return *this;
}
unformatted_ostream_iterator & operator++() noexcept
{
return *this;
}
unformatted_ostream_iterator & operator++(int) noexcept
{
return *this;
}
private:
ostream_type * out_ = nullptr;
};
/// @}
} // namespace ranges
/// \cond
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
namespace std
{
template<typename T, typename Char, typename Traits>
struct iterator_traits<::ranges::ostream_iterator<T, Char, Traits>>
: ::ranges::detail::std_output_iterator_traits<>
{};
template<typename Char, typename Traits>
struct iterator_traits<::ranges::ostreambuf_iterator<Char, Traits>>
: ::ranges::detail::std_output_iterator_traits<>
{};
} // namespace std
RANGES_DIAGNOSTIC_POP
/// \endcond
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_ITERATOR_STREAM_ITERATORS_HPP

View File

@@ -0,0 +1,178 @@
/// \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_ITERATOR_TRAITS_HPP
#define RANGES_V3_ITERATOR_TRAITS_HPP
#include <iterator>
#include <type_traits>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/access.hpp> // for iter_move, iter_swap
#include <range/v3/utility/common_type.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator
/// @{
/// \cond
using input_iterator_tag RANGES_DEPRECATED(
"Please switch to the standard iterator tags") = std::input_iterator_tag;
using forward_iterator_tag RANGES_DEPRECATED(
"Please switch to the standard iterator tags") = std::forward_iterator_tag;
using bidirectional_iterator_tag RANGES_DEPRECATED(
"Please switch to the standard iterator tags") = std::bidirectional_iterator_tag;
using random_access_iterator_tag RANGES_DEPRECATED(
"Please switch to the standard iterator tags") = std::random_access_iterator_tag;
/// \endcond
struct contiguous_iterator_tag : std::random_access_iterator_tag
{};
/// \cond
namespace detail
{
template<typename I, typename = iter_reference_t<I>,
typename R = decltype(iter_move(std::declval<I &>())), typename = R &>
using iter_rvalue_reference_t = R;
template<typename I>
RANGES_INLINE_VAR constexpr bool has_nothrow_iter_move_v =
noexcept(iter_rvalue_reference_t<I>(ranges::iter_move(std::declval<I &>())));
} // namespace detail
/// \endcond
template<typename I>
using iter_rvalue_reference_t = detail::iter_rvalue_reference_t<I>;
template<typename I>
using iter_common_reference_t =
common_reference_t<iter_reference_t<I>, iter_value_t<I> &>;
#if defined(RANGES_DEEP_STL_INTEGRATION) && RANGES_DEEP_STL_INTEGRATION && \
!defined(RANGES_DOXYGEN_INVOKED)
template<typename T>
using iter_difference_t =
typename meta::conditional_t<detail::is_std_iterator_traits_specialized_v<T>,
std::iterator_traits<uncvref_t<T>>,
incrementable_traits<uncvref_t<T>>>::difference_type;
#else
template<typename T>
using iter_difference_t =
typename incrementable_traits<uncvref_t<T>>::difference_type;
#endif
// Defined in <range/v3/iterator/access.hpp>
// template<typename T>
// using iter_value_t = ...
// Defined in <range/v3/iterator/access.hpp>
// template<typename R>
// using iter_reference_t = detail::iter_reference_t_<R>;
// Defined in <range/v3/range_fwd.hpp>:
// template<typename S, typename I>
// inline constexpr bool disable_sized_sentinel = false;
/// \cond
namespace detail
{
template<typename I>
using iter_size_t =
meta::_t<meta::conditional_t<std::is_integral<iter_difference_t<I>>::value,
std::make_unsigned<iter_difference_t<I>>,
meta::id<iter_difference_t<I>>>>;
template<typename I>
using iter_arrow_t = decltype(std::declval<I &>().operator->());
template<typename I>
using iter_pointer_t =
meta::_t<meta::conditional_t<
meta::is_trait<meta::defer<iter_arrow_t, I>>::value,
meta::defer<iter_arrow_t, I>,
std::add_pointer<iter_reference_t<I>>>>;
template<typename T>
struct difference_type_ : meta::defer<iter_difference_t, T>
{};
template<typename T>
struct value_type_ : meta::defer<iter_value_t, T>
{};
template<typename T>
struct size_type_ : meta::defer<iter_size_t, T>
{};
} // namespace detail
template<typename T>
using difference_type_t RANGES_DEPRECATED(
"ranges::difference_type_t is deprecated. Please use "
"ranges::iter_difference_t instead.") = iter_difference_t<T>;
template<typename T>
using value_type_t RANGES_DEPRECATED(
"ranges::value_type_t is deprecated. Please use "
"ranges::iter_value_t instead.") = iter_value_t<T>;
template<typename R>
using reference_t RANGES_DEPRECATED(
"ranges::reference_t is deprecated. Use ranges::iter_reference_t "
"instead.") = iter_reference_t<R>;
template<typename I>
using rvalue_reference_t RANGES_DEPRECATED(
"rvalue_reference_t is deprecated; "
"use iter_rvalue_reference_t instead") = iter_rvalue_reference_t<I>;
template<typename T>
struct RANGES_DEPRECATED(
"ranges::size_type is deprecated. Iterators do not have an associated "
"size_type.") size_type : detail::size_type_<T>
{};
template<typename I>
using size_type_t RANGES_DEPRECATED("size_type_t is deprecated.") =
detail::iter_size_t<I>;
/// \endcond
namespace cpp20
{
using ranges::iter_common_reference_t;
using ranges::iter_difference_t;
using ranges::iter_reference_t;
using ranges::iter_rvalue_reference_t;
using ranges::iter_value_t;
// Specialize these in the ranges:: namespace
using ranges::disable_sized_sentinel;
template<typename T>
using incrementable_traits = ranges::incrementable_traits<T>;
template<typename T>
using indirectly_readable_traits = ranges::indirectly_readable_traits<T>;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_ITERATOR_TRAITS_HPP

View File

@@ -0,0 +1,70 @@
/// \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_ITERATOR_UNREACHABLE_SENTINEL_HPP
#define RANGES_V3_ITERATOR_UNREACHABLE_SENTINEL_HPP
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator
/// @{
struct unreachable_sentinel_t
{
template<typename I>
friend constexpr auto operator==(I const &, unreachable_sentinel_t) noexcept
-> CPP_broken_friend_ret(bool)(
requires weakly_incrementable<I>)
{
return false;
}
template<typename I>
friend constexpr auto operator==(unreachable_sentinel_t, I const &) noexcept
-> CPP_broken_friend_ret(bool)(
requires weakly_incrementable<I>)
{
return false;
}
template<typename I>
friend constexpr auto operator!=(I const &, unreachable_sentinel_t) noexcept
-> CPP_broken_friend_ret(bool)(
requires weakly_incrementable<I>)
{
return true;
}
template<typename I>
friend constexpr auto operator!=(unreachable_sentinel_t, I const &) noexcept
-> CPP_broken_friend_ret(bool)(
requires weakly_incrementable<I>)
{
return true;
}
};
RANGES_INLINE_VARIABLE(unreachable_sentinel_t, unreachable)
namespace cpp20
{
using ranges::unreachable;
using ranges::unreachable_sentinel_t;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_ITERATOR_UNREACHABLE_SENTINEL_HPP