Files
2020-10-17 20:11:16 -04:00

1082 lines
40 KiB
C++

/// \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_BASIC_ITERATOR_HPP
#define RANGES_V3_ITERATOR_BASIC_ITERATOR_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/detail/range_access.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/iterator/traits.hpp>
#include <range/v3/utility/addressof.hpp>
#include <range/v3/utility/box.hpp>
#include <range/v3/utility/move.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/detail/prologue.hpp>
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_MULTIPLE_ASSIGNMENT_OPERATORS
namespace ranges
{
/// \addtogroup group-iterator Iterator
/// @{
///
template<typename T>
struct basic_mixin : private box<T>
{
CPP_member
constexpr CPP_ctor(basic_mixin)()( //
noexcept(std::is_nothrow_default_constructible<T>::value) //
requires default_constructible<T>)
: box<T>{}
{}
CPP_member
constexpr explicit CPP_ctor(basic_mixin)(T && t)( //
noexcept(std::is_nothrow_move_constructible<T>::value) //
requires move_constructible<T>)
: box<T>(detail::move(t))
{}
CPP_member
constexpr explicit CPP_ctor(basic_mixin)(T const & t)( //
noexcept(std::is_nothrow_copy_constructible<T>::value) //
requires copy_constructible<T>)
: box<T>(t)
{}
protected:
using box<T>::get;
};
/// \cond
namespace detail
{
template<typename Cur>
using cursor_reference_t =
decltype(range_access::read(std::declval<Cur const &>()));
// Compute the rvalue reference type of a cursor
template<typename Cur>
auto cursor_move(Cur const & cur, int) -> decltype(range_access::move(cur));
template<typename Cur>
auto cursor_move(Cur const & cur, long) -> aux::move_t<cursor_reference_t<Cur>>;
template<typename Cur>
using cursor_rvalue_reference_t =
decltype(detail::cursor_move(std::declval<Cur const &>(), 42));
// Define conversion operators from the proxy reference type
// to the common reference types, so that basic_iterator can model readable
// even with getters/setters.
template<typename Derived, typename Head>
struct proxy_reference_conversion
{
operator Head() const
noexcept(noexcept(Head(Head(std::declval<Derived const &>().read_()))))
{
return Head(static_cast<Derived const *>(this)->read_());
}
};
// Collect the reference types associated with cursors
template<typename Cur, bool IsReadable>
struct cursor_traits_
{
private:
struct private_
{};
public:
using value_t_ = private_;
using reference_t_ = private_;
using rvalue_reference_t_ = private_;
using common_refs = meta::list<>;
};
template<typename Cur>
struct cursor_traits_<Cur, true>
{
using value_t_ = range_access::cursor_value_t<Cur>;
using reference_t_ = cursor_reference_t<Cur>;
using rvalue_reference_t_ = cursor_rvalue_reference_t<Cur>;
private:
using R1 = reference_t_;
using R2 = common_reference_t<reference_t_, value_t_ &>;
using R3 = common_reference_t<reference_t_, rvalue_reference_t_>;
using tmp1 = meta::list<value_t_, R1>;
using tmp2 =
meta::if_<meta::in<tmp1, uncvref_t<R2>>, tmp1, meta::push_back<tmp1, R2>>;
using tmp3 =
meta::if_<meta::in<tmp2, uncvref_t<R3>>, tmp2, meta::push_back<tmp2, R3>>;
public:
using common_refs = meta::unique<meta::pop_front<tmp3>>;
};
template<typename Cur>
using cursor_traits = cursor_traits_<Cur, (bool)readable_cursor<Cur>>;
template<typename Cur>
using cursor_value_t = typename cursor_traits<Cur>::value_t_;
template<typename Cur, bool IsReadable>
struct basic_proxy_reference_;
template<typename Cur>
using basic_proxy_reference =
basic_proxy_reference_<Cur, (bool)readable_cursor<Cur>>;
// The One Proxy Reference type to rule them all. basic_iterator uses this
// as the return type of operator* when the cursor type has a set() member
// function of the correct signature (i.e., if it can accept a value_type &&).
template<typename Cur, bool IsReadable /*= (bool) readable_cursor<Cur>*/>
struct RANGES_EMPTY_BASES basic_proxy_reference_
: cursor_traits<Cur>
// The following adds conversion operators to the common reference
// types, so that basic_proxy_reference can model readable
, meta::inherit<meta::transform<
typename cursor_traits<Cur>::common_refs,
meta::bind_front<meta::quote<proxy_reference_conversion>,
basic_proxy_reference_<Cur, IsReadable>>>>
{
private:
Cur * cur_;
template<typename, bool>
friend struct basic_proxy_reference_;
template<typename, typename>
friend struct proxy_reference_conversion;
using typename cursor_traits<Cur>::value_t_;
using typename cursor_traits<Cur>::reference_t_;
using typename cursor_traits<Cur>::rvalue_reference_t_;
static_assert((bool)common_reference_with<value_t_ &, reference_t_>,
"Your readable and writable cursor must have a value type and "
"a reference type that share a common reference type. See the "
"ranges::common_reference type trait.");
// BUGBUG make these private:
public:
constexpr reference_t_ read_() const noexcept(
noexcept(reference_t_(range_access::read(std::declval<Cur const &>()))))
{
return range_access::read(*cur_);
}
template<typename T>
constexpr void write_(T && t) const
{
range_access::write(*cur_, (T &&) t);
}
// public:
basic_proxy_reference_() = default;
basic_proxy_reference_(basic_proxy_reference_ const &) = default;
template(typename OtherCur)(
/// \pre
requires convertible_to<OtherCur *, Cur *>)
constexpr basic_proxy_reference_(
basic_proxy_reference<OtherCur> const & that) noexcept
: cur_(that.cur_)
{}
constexpr explicit basic_proxy_reference_(Cur & cur) noexcept
: cur_(&cur)
{}
CPP_member
constexpr auto operator=(basic_proxy_reference_ && that)
-> CPP_ret(basic_proxy_reference_ &)(
/// \pre
requires readable_cursor<Cur>)
{
return *this = that;
}
CPP_member
constexpr auto operator=(basic_proxy_reference_ const & that)
-> CPP_ret(basic_proxy_reference_ &)(
/// \pre
requires readable_cursor<Cur>)
{
this->write_(that.read_());
return *this;
}
CPP_member
constexpr auto operator=(basic_proxy_reference_ && that) const
-> CPP_ret(basic_proxy_reference_ const &)(
/// \pre
requires readable_cursor<Cur>)
{
return *this = that;
}
CPP_member
constexpr auto operator=(basic_proxy_reference_ const & that) const
-> CPP_ret(basic_proxy_reference_ const &)(
/// \pre
requires readable_cursor<Cur>)
{
this->write_(that.read_());
return *this;
}
template(typename OtherCur)(
/// \pre
requires readable_cursor<OtherCur> AND
writable_cursor<Cur, cursor_reference_t<OtherCur>>)
constexpr basic_proxy_reference_ & //
operator=(basic_proxy_reference<OtherCur> && that)
{
return *this = that;
}
template(typename OtherCur)(
/// \pre
requires readable_cursor<OtherCur> AND
writable_cursor<Cur, cursor_reference_t<OtherCur>>)
constexpr basic_proxy_reference_ & //
operator=(basic_proxy_reference<OtherCur> const & that)
{
this->write_(that.read_());
return *this;
}
template(typename OtherCur)(
/// \pre
requires readable_cursor<OtherCur> AND
writable_cursor<Cur, cursor_reference_t<OtherCur>>)
constexpr basic_proxy_reference_ const & //
operator=(basic_proxy_reference<OtherCur> && that) const
{
return *this = that;
}
template(typename OtherCur)(
/// \pre
requires readable_cursor<OtherCur> AND
writable_cursor<Cur, cursor_reference_t<OtherCur>>)
constexpr basic_proxy_reference_ const & //
operator=(basic_proxy_reference<OtherCur> const & that) const
{
this->write_(that.read_());
return *this;
}
template(typename T)(
/// \pre
requires writable_cursor<Cur, T>)
constexpr basic_proxy_reference_ & operator=(T && t) //
{
this->write_((T &&) t);
return *this;
}
template(typename T)(
/// \pre
requires writable_cursor<Cur, T>)
constexpr basic_proxy_reference_ const & operator=(T && t) const
{
this->write_((T &&) t);
return *this;
}
};
template(typename Cur, bool IsReadable)(
/// \pre
requires readable_cursor<Cur> AND equality_comparable<cursor_value_t<Cur>>)
constexpr bool operator==(basic_proxy_reference_<Cur, IsReadable> const & x,
cursor_value_t<Cur> const & y)
{
return x.read_() == y;
}
template(typename Cur, bool IsReadable)(
/// \pre
requires readable_cursor<Cur> AND equality_comparable<cursor_value_t<Cur>>)
constexpr bool operator!=(basic_proxy_reference_<Cur, IsReadable> const & x,
cursor_value_t<Cur> const & y)
{
return !(x == y);
}
template(typename Cur, bool IsReadable)(
/// \pre
requires readable_cursor<Cur> AND equality_comparable<cursor_value_t<Cur>>)
constexpr bool operator==(cursor_value_t<Cur> const & x,
basic_proxy_reference_<Cur, IsReadable> const & y)
{
return x == y.read_();
}
template(typename Cur, bool IsReadable)(
/// \pre
requires readable_cursor<Cur> AND equality_comparable<cursor_value_t<Cur>>)
constexpr bool operator!=(cursor_value_t<Cur> const & x,
basic_proxy_reference_<Cur, IsReadable> const & y)
{
return !(x == y);
}
template(typename Cur, bool IsReadable)(
/// \pre
requires readable_cursor<Cur> AND equality_comparable<cursor_value_t<Cur>>)
constexpr bool operator==(basic_proxy_reference_<Cur, IsReadable> const & x,
basic_proxy_reference_<Cur, IsReadable> const & y)
{
return x.read_() == y.read_();
}
template(typename Cur, bool IsReadable)(
/// \pre
requires readable_cursor<Cur> AND equality_comparable<cursor_value_t<Cur>>)
constexpr bool operator!=(basic_proxy_reference_<Cur, IsReadable> const & x,
basic_proxy_reference_<Cur, IsReadable> const & y)
{
return !(x == y);
}
template<typename Cur>
using cpp20_iter_cat_of_t = //
std::enable_if_t< //
input_cursor<Cur>, //
meta::conditional_t< //
contiguous_cursor<Cur>, //
ranges::contiguous_iterator_tag, //
meta::conditional_t< //
random_access_cursor<Cur>, //
std::random_access_iterator_tag, //
meta::conditional_t< //
bidirectional_cursor<Cur>, //
std::bidirectional_iterator_tag, //
meta::conditional_t< //
forward_cursor<Cur>, //
std::forward_iterator_tag, //
std::input_iterator_tag>>>>>;
// clang-format off
template(typename C)(
concept (cpp17_input_cursor_)(C),
// Either it is not single-pass, or else we can create a
// proxy for postfix increment.
!range_access::single_pass_t<uncvref_t<C>>::value ||
(move_constructible<range_access::cursor_value_t<C>> &&
constructible_from<range_access::cursor_value_t<C>, cursor_reference_t<C>>)
);
template<typename C>
CPP_concept cpp17_input_cursor =
input_cursor<C> &&
sentinel_for_cursor<C, C> &&
CPP_concept_ref(cpp17_input_cursor_, C);
template(typename C)(
concept (cpp17_forward_cursor_)(C),
std::is_reference<cursor_reference_t<C>>::value
);
template<typename C>
CPP_concept cpp17_forward_cursor =
forward_cursor<C> &&
CPP_concept_ref(cpp17_forward_cursor_, C);
// clang-format on
template<typename Category, typename Base = void>
struct with_iterator_category : Base
{
using iterator_category = Category;
};
template<typename Category>
struct with_iterator_category<Category>
{
using iterator_category = Category;
};
template<typename Cur>
using cpp17_iter_cat_of_t = //
std::enable_if_t< //
cpp17_input_cursor<Cur>, //
meta::conditional_t< //
random_access_cursor<Cur>, //
std::random_access_iterator_tag, //
meta::conditional_t< //
bidirectional_cursor<Cur>, //
std::bidirectional_iterator_tag, //
meta::conditional_t< //
cpp17_forward_cursor<Cur>, //
std::forward_iterator_tag, //
std::input_iterator_tag>>>>;
template<typename Cur, typename = void>
struct readable_iterator_associated_types_base : range_access::mixin_base_t<Cur>
{
readable_iterator_associated_types_base() = default;
using range_access::mixin_base_t<Cur>::mixin_base_t;
readable_iterator_associated_types_base(Cur && cur)
: range_access::mixin_base_t<Cur>(static_cast<Cur &&>(cur))
{}
readable_iterator_associated_types_base(Cur const & cur)
: range_access::mixin_base_t<Cur>(cur)
{}
};
template<typename Cur>
struct readable_iterator_associated_types_base<
Cur, always_<void, cpp17_iter_cat_of_t<Cur>>>
: range_access::mixin_base_t<Cur>
{
using iterator_category = cpp17_iter_cat_of_t<Cur>;
readable_iterator_associated_types_base() = default;
using range_access::mixin_base_t<Cur>::mixin_base_t;
readable_iterator_associated_types_base(Cur && cur)
: range_access::mixin_base_t<Cur>(static_cast<Cur &&>(cur))
{}
readable_iterator_associated_types_base(Cur const & cur)
: range_access::mixin_base_t<Cur>(cur)
{}
};
template<typename Cur, bool IsReadable /*= (bool) readable_cursor<Cur>*/>
struct iterator_associated_types_base_ : range_access::mixin_base_t<Cur>
{
// BUGBUG
// protected:
using iter_reference_t = basic_proxy_reference<Cur>;
using const_reference_t = basic_proxy_reference<Cur const>;
public:
using reference = void;
using difference_type = range_access::cursor_difference_t<Cur>;
iterator_associated_types_base_() = default;
using range_access::mixin_base_t<Cur>::mixin_base_t;
iterator_associated_types_base_(Cur && cur)
: range_access::mixin_base_t<Cur>(static_cast<Cur &&>(cur))
{}
iterator_associated_types_base_(Cur const & cur)
: range_access::mixin_base_t<Cur>(cur)
{}
};
template<typename Cur>
using cursor_arrow_t = decltype(range_access::arrow(std::declval<Cur const &>()));
template<typename Cur>
struct iterator_associated_types_base_<Cur, true>
: readable_iterator_associated_types_base<Cur>
{
// BUGBUG
// protected:
using iter_reference_t =
meta::conditional_t<is_writable_cursor_v<Cur const>,
basic_proxy_reference<Cur const>,
meta::conditional_t<is_writable_cursor_v<Cur>,
basic_proxy_reference<Cur>, cursor_reference_t<Cur>>>;
using const_reference_t =
meta::conditional_t<is_writable_cursor_v<Cur const>,
basic_proxy_reference<Cur const>, cursor_reference_t<Cur>>;
public:
using difference_type = range_access::cursor_difference_t<Cur>;
using value_type = range_access::cursor_value_t<Cur>;
using reference = iter_reference_t;
using iterator_concept = cpp20_iter_cat_of_t<Cur>;
using pointer = meta::_t<
meta::conditional_t<
(bool)has_cursor_arrow<Cur>,
meta::defer<cursor_arrow_t, Cur>,
std::add_pointer<reference>>>;
using common_reference = common_reference_t<reference, value_type &>;
iterator_associated_types_base_() = default;
using readable_iterator_associated_types_base<
Cur>::readable_iterator_associated_types_base;
iterator_associated_types_base_(Cur && cur)
: readable_iterator_associated_types_base<Cur>(static_cast<Cur &&>(cur))
{}
iterator_associated_types_base_(Cur const & cur)
: readable_iterator_associated_types_base<Cur>(cur)
{}
};
template<typename Cur>
using iterator_associated_types_base =
iterator_associated_types_base_<Cur, (bool)readable_cursor<Cur>>;
template<typename Value>
struct postfix_increment_proxy
{
private:
Value cache_;
public:
template<typename T>
constexpr postfix_increment_proxy(T && t)
: cache_(static_cast<T &&>(t))
{}
constexpr Value const & operator*() const noexcept
{
return cache_;
}
};
} // namespace detail
/// \endcond
#if RANGES_BROKEN_CPO_LOOKUP
namespace _basic_iterator_
{
template<typename>
struct adl_hook
{};
} // namespace _basic_iterator_
#endif
template<typename Cur>
struct RANGES_EMPTY_BASES basic_iterator
: detail::iterator_associated_types_base<Cur>
#if RANGES_BROKEN_CPO_LOOKUP
, private _basic_iterator_::adl_hook<basic_iterator<Cur>>
#endif
{
private:
template<typename>
friend struct basic_iterator;
friend range_access;
using base_t = detail::iterator_associated_types_base<Cur>;
using mixin_t = range_access::mixin_base_t<Cur>;
static_assert((bool)detail::cursor<Cur>, "");
using assoc_types_ = detail::iterator_associated_types_base<Cur>;
using typename assoc_types_::const_reference_t;
using typename assoc_types_::iter_reference_t;
constexpr Cur & pos() noexcept
{
return this->mixin_t::basic_mixin::get();
}
constexpr Cur const & pos() const noexcept
{
return this->mixin_t::basic_mixin::get();
}
public:
using typename assoc_types_::difference_type;
constexpr basic_iterator() = default;
template(typename OtherCur)(
/// \pre
requires (!same_as<OtherCur, Cur>) AND convertible_to<OtherCur, Cur> AND
constructible_from<mixin_t, OtherCur>)
constexpr basic_iterator(basic_iterator<OtherCur> that)
: base_t{std::move(that.pos())}
{}
// Mix in any additional constructors provided by the mixin
using base_t::base_t;
explicit basic_iterator(Cur && cur)
: base_t(static_cast<Cur &&>(cur))
{}
explicit basic_iterator(Cur const & cur)
: base_t(cur)
{}
template(typename OtherCur)(
/// \pre
requires (!same_as<OtherCur, Cur>) AND convertible_to<OtherCur, Cur>)
constexpr basic_iterator & operator=(basic_iterator<OtherCur> that)
{
pos() = std::move(that.pos());
return *this;
}
CPP_member
constexpr auto operator*() const
noexcept(noexcept(range_access::read(std::declval<Cur const &>())))
-> CPP_ret(const_reference_t)(
/// \pre
requires detail::readable_cursor<Cur> &&
(!detail::is_writable_cursor_v<Cur>))
{
return range_access::read(pos());
}
CPP_member
constexpr auto operator*() //
noexcept(noexcept(iter_reference_t{std::declval<Cur &>()})) //
-> CPP_ret(iter_reference_t)(
/// \pre
requires detail::has_cursor_next<Cur> &&
detail::is_writable_cursor_v<Cur>)
{
return iter_reference_t{pos()};
}
CPP_member
constexpr auto operator*() const
noexcept(noexcept(const_reference_t{std::declval<Cur const &>()}))
-> CPP_ret(const_reference_t)(
/// \pre
requires detail::has_cursor_next<Cur> &&
detail::is_writable_cursor_v<Cur const>)
{
return const_reference_t{pos()};
}
CPP_member
constexpr auto operator*() noexcept //
-> CPP_ret(basic_iterator &)(
/// \pre
requires (!detail::has_cursor_next<Cur>))
{
return *this;
}
// Use cursor's arrow() member, if any.
template(typename C = Cur)(
/// \pre
requires detail::has_cursor_arrow<C>)
constexpr detail::cursor_arrow_t<C> operator-> () const
noexcept(noexcept(range_access::arrow(std::declval<C const &>())))
{
return range_access::arrow(pos());
}
// Otherwise, if iter_reference_t is an lvalue reference to cv-qualified
// iter_value_t, return the address of **this.
template(typename C = Cur)(
/// \pre
requires (!detail::has_cursor_arrow<C>) AND detail::readable_cursor<C> AND
std::is_lvalue_reference<const_reference_t>::value AND
same_as<typename detail::iterator_associated_types_base<C>::value_type,
uncvref_t<const_reference_t>>)
constexpr std::add_pointer_t<const_reference_t> operator-> () const
noexcept(noexcept(*std::declval<basic_iterator const &>()))
{
return detail::addressof(**this);
}
CPP_member
constexpr auto operator++() //
-> CPP_ret(basic_iterator &)(
/// \pre
requires detail::has_cursor_next<Cur>)
{
range_access::next(pos());
return *this;
}
CPP_member
constexpr auto operator++() noexcept //
-> CPP_ret(basic_iterator &)(
/// \pre
requires (!detail::has_cursor_next<Cur>))
{
return *this;
}
private:
constexpr basic_iterator post_increment_(std::false_type, int)
{
basic_iterator tmp{*this};
++*this;
return tmp;
}
// Attempt to satisfy the C++17 iterator requirements by returning a
// proxy from postfix increment:
template(typename A = assoc_types_, typename V = typename A::value_type)(
/// \pre
requires constructible_from<V, typename A::reference> AND
move_constructible<V>)
constexpr auto post_increment_(std::true_type, int) //
-> detail::postfix_increment_proxy<V>
{
detail::postfix_increment_proxy<V> p{**this};
++*this;
return p;
}
constexpr void post_increment_(std::true_type, long)
{
++*this;
}
public:
CPP_member
constexpr auto operator++(int)
{
return this->post_increment_(meta::bool_ < detail::input_cursor<Cur> &&
!detail::forward_cursor<Cur>> {},
0);
}
CPP_member
constexpr auto operator--()
-> CPP_ret(basic_iterator &)(
/// \pre
requires detail::bidirectional_cursor<Cur>)
{
range_access::prev(pos());
return *this;
}
CPP_member
constexpr auto operator--(int) //
-> CPP_ret(basic_iterator)(
/// \pre
requires detail::bidirectional_cursor<Cur>)
{
basic_iterator tmp(*this);
--*this;
return tmp;
}
CPP_member
constexpr auto operator+=(difference_type n) //
-> CPP_ret(basic_iterator &)(
/// \pre
requires detail::random_access_cursor<Cur>)
{
range_access::advance(pos(), n);
return *this;
}
CPP_member
constexpr auto operator-=(difference_type n) //
-> CPP_ret(basic_iterator &)(
/// \pre
requires detail::random_access_cursor<Cur>)
{
range_access::advance(pos(), (difference_type)-n);
return *this;
}
CPP_member
constexpr auto operator[](difference_type n) const //
-> CPP_ret(const_reference_t)(
/// \pre
requires detail::random_access_cursor<Cur>)
{
return *(*this + n);
}
#if !RANGES_BROKEN_CPO_LOOKUP
// Optionally support hooking iter_move when the cursor sports a
// move() member function.
template<typename C = Cur>
friend constexpr auto iter_move(basic_iterator const & it) noexcept(
noexcept(range_access::move(std::declval<C const &>())))
-> CPP_broken_friend_ret(
decltype(range_access::move(std::declval<C const &>())))(
/// \pre
requires same_as<C, Cur> && detail::input_cursor<Cur>)
{
return range_access::move(it.pos());
}
#endif
};
template(typename Cur, typename Cur2)(
/// \pre
requires detail::sentinel_for_cursor<Cur2, Cur>)
constexpr bool operator==(basic_iterator<Cur> const & left,
basic_iterator<Cur2> const & right)
{
return range_access::equal(range_access::pos(left), range_access::pos(right));
}
template(typename Cur, typename Cur2)(
/// \pre
requires detail::sentinel_for_cursor<Cur2, Cur>)
constexpr bool operator!=(basic_iterator<Cur> const & left,
basic_iterator<Cur2> const & right)
{
return !(left == right);
}
template(typename Cur, typename S)(
/// \pre
requires detail::sentinel_for_cursor<S, Cur>)
constexpr bool operator==(basic_iterator<Cur> const & left,
S const & right)
{
return range_access::equal(range_access::pos(left), right);
}
template(typename Cur, typename S)(
/// \pre
requires detail::sentinel_for_cursor<S, Cur>)
constexpr bool operator!=(basic_iterator<Cur> const & left,
S const & right)
{
return !(left == right);
}
template(typename S, typename Cur)(
/// \pre
requires detail::sentinel_for_cursor<S, Cur>)
constexpr bool operator==(S const & left,
basic_iterator<Cur> const & right)
{
return right == left;
}
template(typename S, typename Cur)(
/// \pre
requires detail::sentinel_for_cursor<S, Cur>)
constexpr bool operator!=(S const & left,
basic_iterator<Cur> const & right)
{
return right != left;
}
template(typename Cur)(
/// \pre
requires detail::random_access_cursor<Cur>)
constexpr basic_iterator<Cur> //
operator+(basic_iterator<Cur> left, typename basic_iterator<Cur>::difference_type n)
{
left += n;
return left;
}
template(typename Cur)(
/// \pre
requires detail::random_access_cursor<Cur>)
constexpr basic_iterator<Cur> //
operator+(typename basic_iterator<Cur>::difference_type n, basic_iterator<Cur> right)
{
right += n;
return right;
}
template(typename Cur)(
/// \pre
requires detail::random_access_cursor<Cur>)
constexpr basic_iterator<Cur> //
operator-(basic_iterator<Cur> left, typename basic_iterator<Cur>::difference_type n)
{
left -= n;
return left;
}
template(typename Cur2, typename Cur)(
/// \pre
requires detail::sized_sentinel_for_cursor<Cur2, Cur>)
constexpr typename basic_iterator<Cur>::difference_type //
operator-(basic_iterator<Cur2> const & left, basic_iterator<Cur> const & right)
{
return range_access::distance_to(range_access::pos(right),
range_access::pos(left));
}
template(typename S, typename Cur)(
/// \pre
requires detail::sized_sentinel_for_cursor<S, Cur>)
constexpr typename basic_iterator<Cur>::difference_type //
operator-(S const & left, basic_iterator<Cur> const & right)
{
return range_access::distance_to(range_access::pos(right), left);
}
template(typename Cur, typename S)(
/// \pre
requires detail::sized_sentinel_for_cursor<S, Cur>)
constexpr typename basic_iterator<Cur>::difference_type //
operator-(basic_iterator<Cur> const & left, S const & right)
{
return -(right - left);
}
// Asymmetric comparisons
template(typename Left, typename Right)(
/// \pre
requires detail::sized_sentinel_for_cursor<Right, Left>)
constexpr bool operator<(basic_iterator<Left> const & left,
basic_iterator<Right> const & right)
{
return 0 < (right - left);
}
template(typename Left, typename Right)(
/// \pre
requires detail::sized_sentinel_for_cursor<Right, Left>)
constexpr bool operator<=(basic_iterator<Left> const & left,
basic_iterator<Right> const & right)
{
return 0 <= (right - left);
}
template(typename Left, typename Right)(
/// \pre
requires detail::sized_sentinel_for_cursor<Right, Left>)
constexpr bool operator>(basic_iterator<Left> const & left,
basic_iterator<Right> const & right)
{
return (right - left) < 0;
}
template(typename Left, typename Right)(
/// \pre
requires detail::sized_sentinel_for_cursor<Right, Left>)
constexpr bool operator>=(basic_iterator<Left> const & left,
basic_iterator<Right> const & right)
{
return (right - left) <= 0;
}
#if RANGES_BROKEN_CPO_LOOKUP
namespace _basic_iterator_
{
// Optionally support hooking iter_move when the cursor sports a
// move() member function.
template<typename Cur>
constexpr auto iter_move(basic_iterator<Cur> const & it) noexcept(
noexcept(range_access::move(std::declval<Cur const &>())))
-> CPP_broken_friend_ret(
decltype(range_access::move(std::declval<Cur const &>())))(
/// \pre
requires detail::input_cursor<Cur>)
{
return range_access::move(range_access::pos(it));
}
} // namespace _basic_iterator_
#endif
/// Get a cursor from a basic_iterator
struct get_cursor_fn
{
template<typename Cur>
constexpr Cur & operator()(basic_iterator<Cur> & it) const noexcept
{
return range_access::pos(it);
}
template<typename Cur>
constexpr Cur const & operator()(basic_iterator<Cur> const & it) const noexcept
{
return range_access::pos(it);
}
template<typename Cur>
constexpr Cur operator()(basic_iterator<Cur> && it) const
noexcept(std::is_nothrow_move_constructible<Cur>::value)
{
return range_access::pos(std::move(it));
}
};
/// \sa `get_cursor_fn`
RANGES_INLINE_VARIABLE(get_cursor_fn, get_cursor)
/// @}
} // namespace ranges
/// \cond
namespace concepts
{
// common_reference specializations for basic_proxy_reference
template<typename Cur, typename U, template<typename> class TQual,
template<typename> class UQual>
struct basic_common_reference<::ranges::detail::basic_proxy_reference_<Cur, true>, U,
TQual, UQual>
: basic_common_reference<::ranges::detail::cursor_reference_t<Cur>, U, TQual, UQual>
{};
template<typename T, typename Cur, template<typename> class TQual,
template<typename> class UQual>
struct basic_common_reference<T, ::ranges::detail::basic_proxy_reference_<Cur, true>,
TQual, UQual>
: basic_common_reference<T, ::ranges::detail::cursor_reference_t<Cur>, TQual, UQual>
{};
template<typename Cur1, typename Cur2, template<typename> class TQual,
template<typename> class UQual>
struct basic_common_reference<::ranges::detail::basic_proxy_reference_<Cur1, true>,
::ranges::detail::basic_proxy_reference_<Cur2, true>,
TQual, UQual>
: basic_common_reference<::ranges::detail::cursor_reference_t<Cur1>,
::ranges::detail::cursor_reference_t<Cur2>, TQual, UQual>
{};
// common_type specializations for basic_proxy_reference
template<typename Cur, typename U>
struct common_type<::ranges::detail::basic_proxy_reference_<Cur, true>, U>
: common_type<::ranges::range_access::cursor_value_t<Cur>, U>
{};
template<typename T, typename Cur>
struct common_type<T, ::ranges::detail::basic_proxy_reference_<Cur, true>>
: common_type<T, ::ranges::range_access::cursor_value_t<Cur>>
{};
template<typename Cur1, typename Cur2>
struct common_type<::ranges::detail::basic_proxy_reference_<Cur1, true>,
::ranges::detail::basic_proxy_reference_<Cur2, true>>
: common_type<::ranges::range_access::cursor_value_t<Cur1>,
::ranges::range_access::cursor_value_t<Cur2>>
{};
} // namespace concepts
#if RANGES_CXX_VER > RANGES_CXX_STD_17
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
RANGES_BEGIN_NAMESPACE_STD
RANGES_BEGIN_NAMESPACE_VERSION
template<typename, typename, template <typename> class, template<typename> class>
struct basic_common_reference;
// common_reference specializations for basic_proxy_reference
template<typename Cur, typename U, template<typename> class TQual,
template<typename> class UQual>
struct basic_common_reference<::ranges::detail::basic_proxy_reference_<Cur, true>, U,
TQual, UQual>
: basic_common_reference<::ranges::detail::cursor_reference_t<Cur>, U, TQual, UQual>
{};
template<typename T, typename Cur, template<typename> class TQual,
template<typename> class UQual>
struct basic_common_reference<T, ::ranges::detail::basic_proxy_reference_<Cur, true>,
TQual, UQual>
: basic_common_reference<T, ::ranges::detail::cursor_reference_t<Cur>, TQual, UQual>
{};
template<typename Cur1, typename Cur2, template<typename> class TQual,
template<typename> class UQual>
struct basic_common_reference<::ranges::detail::basic_proxy_reference_<Cur1, true>,
::ranges::detail::basic_proxy_reference_<Cur2, true>,
TQual, UQual>
: basic_common_reference<::ranges::detail::cursor_reference_t<Cur1>,
::ranges::detail::cursor_reference_t<Cur2>, TQual, UQual>
{};
template<typename...>
struct common_type;
// common_type specializations for basic_proxy_reference
template<typename Cur, typename U>
struct common_type<::ranges::detail::basic_proxy_reference_<Cur, true>, U>
: common_type<::ranges::range_access::cursor_value_t<Cur>, U>
{};
template<typename T, typename Cur>
struct common_type<T, ::ranges::detail::basic_proxy_reference_<Cur, true>>
: common_type<T, ::ranges::range_access::cursor_value_t<Cur>>
{};
template<typename Cur1, typename Cur2>
struct common_type<::ranges::detail::basic_proxy_reference_<Cur1, true>,
::ranges::detail::basic_proxy_reference_<Cur2, true>>
: common_type<::ranges::range_access::cursor_value_t<Cur1>,
::ranges::range_access::cursor_value_t<Cur2>>
{};
RANGES_END_NAMESPACE_VERSION
RANGES_END_NAMESPACE_STD
RANGES_DIAGNOSTIC_POP
#endif // RANGES_CXX_VER > RANGES_CXX_STD_17
namespace ranges
{
/// \cond
namespace detail
{
template<typename Cur, bool IsReadable>
struct std_iterator_traits_
{
using difference_type =
typename iterator_associated_types_base<Cur>::difference_type;
using value_type = void;
using reference = void;
using pointer = void;
using iterator_category = std::output_iterator_tag;
using iterator_concept = std::output_iterator_tag;
};
template<typename Cur>
struct std_iterator_traits_<Cur, true> : iterator_associated_types_base<Cur>
{};
template<typename Cur>
using std_iterator_traits = std_iterator_traits_<Cur, (bool)readable_cursor<Cur>>;
} // namespace detail
/// \endcond
} // namespace ranges
namespace std
{
template<typename Cur>
struct iterator_traits<::ranges::basic_iterator<Cur>>
: ::ranges::detail::std_iterator_traits<Cur>
{};
} // namespace std
/// \endcond
RANGES_DIAGNOSTIC_POP
#include <range/v3/detail/epilogue.hpp>
#endif