gcc/libstdc++-v3/include/bits/ranges_base.h
Jonathan Wakely 419201f566 libstdc++: Use function object for __decay_copy helper
By changing __cust_access::__decay_copy from a function template to a
function object we avoid ADL. That means it's fine to call it
unqualified (the compiler won't waste time doing ADL in associated
namespaces, and won't try to complete associated types).

This also makes some other minor simplications to other concepts for the
[range.access] CPOs.

Signed-off-by: Jonathan Wakely <jwakely@redhat.com>

libstdc++-v3/ChangeLog:

	* include/bits/iterator_concepts.h (__cust_access::__decay_copy):
	Replace with function object.
	(__cust_access::__member_begin, ___cust_access::_adl_begin): Use
	__decay_copy unqualified.
	* include/bits/ranges_base.h (__member_end, __adl_end):
	Likewise. Use __range_iter_t for type of ranges::begin.
	(__member_rend): Use correct value category for rbegin argument.
	(__member_data): Use __decay_copy unqualified.
	(__begin_data): Use __range_iter_t for type of ranges::begin.

(cherry picked from commit cb326a6442)
2021-07-16 14:14:51 +01:00

899 lines
24 KiB
C++

// Core concepts and definitions for <ranges> -*- C++ -*-
// Copyright (C) 2019-2021 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
/** @file bits/ranges_base.h
* This is an internal header file, included by other library headers.
* Do not attempt to use it directly. @headername{ranges}
*/
#ifndef _GLIBCXX_RANGES_BASE_H
#define _GLIBCXX_RANGES_BASE_H 1
#pragma GCC system_header
#if __cplusplus > 201703L
#include <bits/iterator_concepts.h>
#include <ext/numeric_traits.h>
#include <bits/max_size_type.h>
#ifdef __cpp_lib_concepts
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
namespace ranges
{
template<typename>
inline constexpr bool disable_sized_range = false;
template<typename _Tp>
inline constexpr bool enable_borrowed_range = false;
namespace __detail
{
constexpr __max_size_type
__to_unsigned_like(__max_size_type __t) noexcept
{ return __t; }
constexpr __max_size_type
__to_unsigned_like(__max_diff_type __t) noexcept
{ return __max_size_type(__t); }
template<integral _Tp>
constexpr auto
__to_unsigned_like(_Tp __t) noexcept
{ return static_cast<make_unsigned_t<_Tp>>(__t); }
#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
constexpr unsigned __int128
__to_unsigned_like(__int128 __t) noexcept
{ return __t; }
constexpr unsigned __int128
__to_unsigned_like(unsigned __int128 __t) noexcept
{ return __t; }
#endif
template<typename _Tp>
using __make_unsigned_like_t
= decltype(__detail::__to_unsigned_like(std::declval<_Tp>()));
// Part of the constraints of ranges::borrowed_range
template<typename _Tp>
concept __maybe_borrowed_range
= is_lvalue_reference_v<_Tp>
|| enable_borrowed_range<remove_cvref_t<_Tp>>;
} // namespace __detail
namespace __cust_access
{
using std::ranges::__detail::__maybe_borrowed_range;
using std::__detail::__range_iter_t;
struct _Begin
{
private:
template<typename _Tp>
static constexpr bool
_S_noexcept()
{
if constexpr (is_array_v<remove_reference_t<_Tp>>)
return true;
else if constexpr (__member_begin<_Tp>)
return noexcept(__decay_copy(std::declval<_Tp&>().begin()));
else
return noexcept(__decay_copy(begin(std::declval<_Tp&>())));
}
public:
template<__maybe_borrowed_range _Tp>
requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
|| __adl_begin<_Tp>
constexpr auto
operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
{
if constexpr (is_array_v<remove_reference_t<_Tp>>)
{
static_assert(is_lvalue_reference_v<_Tp>);
return __t + 0;
}
else if constexpr (__member_begin<_Tp>)
return __t.begin();
else
return begin(__t);
}
};
template<typename _Tp>
concept __member_end = requires(_Tp& __t)
{
{ __decay_copy(__t.end()) } -> sentinel_for<__range_iter_t<_Tp>>;
};
// Poison pills so that unqualified lookup doesn't find std::end.
void end(auto&) = delete;
void end(const auto&) = delete;
template<typename _Tp>
concept __adl_end = __class_or_enum<remove_reference_t<_Tp>>
&& requires(_Tp& __t)
{
{ __decay_copy(end(__t)) } -> sentinel_for<__range_iter_t<_Tp>>;
};
struct _End
{
private:
template<typename _Tp>
static constexpr bool
_S_noexcept()
{
if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
return true;
else if constexpr (__member_end<_Tp>)
return noexcept(__decay_copy(std::declval<_Tp&>().end()));
else
return noexcept(__decay_copy(end(std::declval<_Tp&>())));
}
public:
template<__maybe_borrowed_range _Tp>
requires is_bounded_array_v<remove_reference_t<_Tp>>
|| __member_end<_Tp> || __adl_end<_Tp>
constexpr auto
operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
{
if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
{
static_assert(is_lvalue_reference_v<_Tp>);
return __t + extent_v<remove_reference_t<_Tp>>;
}
else if constexpr (__member_end<_Tp>)
return __t.end();
else
return end(__t);
}
};
// If _To is an lvalue-reference, return const _Tp&, otherwise const _Tp&&.
template<typename _To, typename _Tp>
constexpr decltype(auto)
__as_const(_Tp& __t) noexcept
{
static_assert(std::is_same_v<_To&, _Tp&>);
if constexpr (is_lvalue_reference_v<_To>)
return const_cast<const _Tp&>(__t);
else
return static_cast<const _Tp&&>(__t);
}
struct _CBegin
{
template<typename _Tp>
constexpr auto
operator()(_Tp&& __e) const
noexcept(noexcept(_Begin{}(__cust_access::__as_const<_Tp>(__e))))
requires requires { _Begin{}(__cust_access::__as_const<_Tp>(__e)); }
{
return _Begin{}(__cust_access::__as_const<_Tp>(__e));
}
};
struct _CEnd
{
template<typename _Tp>
constexpr auto
operator()(_Tp&& __e) const
noexcept(noexcept(_End{}(__cust_access::__as_const<_Tp>(__e))))
requires requires { _End{}(__cust_access::__as_const<_Tp>(__e)); }
{
return _End{}(__cust_access::__as_const<_Tp>(__e));
}
};
template<typename _Tp>
concept __member_rbegin = requires(_Tp& __t)
{
{ __decay_copy(__t.rbegin()) } -> input_or_output_iterator;
};
void rbegin(auto&) = delete;
void rbegin(const auto&) = delete;
template<typename _Tp>
concept __adl_rbegin = __class_or_enum<remove_reference_t<_Tp>>
&& requires(_Tp& __t)
{
{ __decay_copy(rbegin(__t)) } -> input_or_output_iterator;
};
template<typename _Tp>
concept __reversable = requires(_Tp& __t)
{
{ _Begin{}(__t) } -> bidirectional_iterator;
{ _End{}(__t) } -> same_as<decltype(_Begin{}(__t))>;
};
struct _RBegin
{
private:
template<typename _Tp>
static constexpr bool
_S_noexcept()
{
if constexpr (__member_rbegin<_Tp>)
return noexcept(__decay_copy(std::declval<_Tp&>().rbegin()));
else if constexpr (__adl_rbegin<_Tp>)
return noexcept(__decay_copy(rbegin(std::declval<_Tp&>())));
else
{
if constexpr (noexcept(_End{}(std::declval<_Tp&>())))
{
using _It = decltype(_End{}(std::declval<_Tp&>()));
// std::reverse_iterator copy-initializes its member.
return is_nothrow_copy_constructible_v<_It>;
}
else
return false;
}
}
public:
template<__maybe_borrowed_range _Tp>
requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> || __reversable<_Tp>
constexpr auto
operator()(_Tp&& __t) const
noexcept(_S_noexcept<_Tp&>())
{
if constexpr (__member_rbegin<_Tp>)
return __t.rbegin();
else if constexpr (__adl_rbegin<_Tp>)
return rbegin(__t);
else
return std::make_reverse_iterator(_End{}(__t));
}
};
template<typename _Tp>
concept __member_rend = requires(_Tp& __t)
{
{ __decay_copy(__t.rend()) }
-> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
};
void rend(auto&) = delete;
void rend(const auto&) = delete;
template<typename _Tp>
concept __adl_rend = __class_or_enum<remove_reference_t<_Tp>>
&& requires(_Tp& __t)
{
{ __decay_copy(rend(__t)) }
-> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
};
struct _REnd
{
private:
template<typename _Tp>
static constexpr bool
_S_noexcept()
{
if constexpr (__member_rend<_Tp>)
return noexcept(__decay_copy(std::declval<_Tp&>().rend()));
else if constexpr (__adl_rend<_Tp>)
return noexcept(__decay_copy(rend(std::declval<_Tp&>())));
else
{
if constexpr (noexcept(_Begin{}(std::declval<_Tp&>())))
{
using _It = decltype(_Begin{}(std::declval<_Tp&>()));
// std::reverse_iterator copy-initializes its member.
return is_nothrow_copy_constructible_v<_It>;
}
else
return false;
}
}
public:
template<__maybe_borrowed_range _Tp>
requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp>
constexpr auto
operator()(_Tp&& __t) const
noexcept(_S_noexcept<_Tp&>())
{
if constexpr (__member_rend<_Tp>)
return __t.rend();
else if constexpr (__adl_rend<_Tp>)
return rend(__t);
else
return std::make_reverse_iterator(_Begin{}(__t));
}
};
struct _CRBegin
{
template<typename _Tp>
constexpr auto
operator()(_Tp&& __e) const
noexcept(noexcept(_RBegin{}(__cust_access::__as_const<_Tp>(__e))))
requires requires { _RBegin{}(__cust_access::__as_const<_Tp>(__e)); }
{
return _RBegin{}(__cust_access::__as_const<_Tp>(__e));
}
};
struct _CREnd
{
template<typename _Tp>
constexpr auto
operator()(_Tp&& __e) const
noexcept(noexcept(_REnd{}(__cust_access::__as_const<_Tp>(__e))))
requires requires { _REnd{}(__cust_access::__as_const<_Tp>(__e)); }
{
return _REnd{}(__cust_access::__as_const<_Tp>(__e));
}
};
template<typename _Tp>
concept __member_size = !disable_sized_range<remove_cvref_t<_Tp>>
&& requires(_Tp& __t)
{
{ __decay_copy(__t.size()) } -> __detail::__is_integer_like;
};
void size(auto&) = delete;
void size(const auto&) = delete;
template<typename _Tp>
concept __adl_size = __class_or_enum<remove_reference_t<_Tp>>
&& !disable_sized_range<remove_cvref_t<_Tp>>
&& requires(_Tp& __t)
{
{ __decay_copy(size(__t)) } -> __detail::__is_integer_like;
};
template<typename _Tp>
concept __sentinel_size = requires(_Tp& __t)
{
{ _Begin{}(__t) } -> forward_iterator;
{ _End{}(__t) } -> sized_sentinel_for<decltype(_Begin{}(__t))>;
__detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
};
struct _Size
{
private:
template<typename _Tp>
static constexpr bool
_S_noexcept()
{
if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
return true;
else if constexpr (__member_size<_Tp>)
return noexcept(__decay_copy(std::declval<_Tp&>().size()));
else if constexpr (__adl_size<_Tp>)
return noexcept(__decay_copy(size(std::declval<_Tp&>())));
else if constexpr (__sentinel_size<_Tp>)
return noexcept(_End{}(std::declval<_Tp&>())
- _Begin{}(std::declval<_Tp&>()));
}
public:
template<typename _Tp>
requires is_bounded_array_v<remove_reference_t<_Tp>>
|| __member_size<_Tp> || __adl_size<_Tp> || __sentinel_size<_Tp>
constexpr auto
operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
{
if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
return extent_v<remove_reference_t<_Tp>>;
else if constexpr (__member_size<_Tp>)
return __t.size();
else if constexpr (__adl_size<_Tp>)
return size(__t);
else if constexpr (__sentinel_size<_Tp>)
return __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
}
};
struct _SSize
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 3403. Domain of ranges::ssize(E) doesn't match ranges::size(E)
template<typename _Tp>
requires requires (_Tp& __t) { _Size{}(__t); }
constexpr auto
operator()(_Tp&& __t) const noexcept(noexcept(_Size{}(__t)))
{
auto __size = _Size{}(__t);
using __size_type = decltype(__size);
// Return the wider of ptrdiff_t and make-signed-like-t<__size_type>.
if constexpr (integral<__size_type>)
{
using __gnu_cxx::__int_traits;
if constexpr (__int_traits<__size_type>::__digits
< __int_traits<ptrdiff_t>::__digits)
return static_cast<ptrdiff_t>(__size);
else
return static_cast<make_signed_t<__size_type>>(__size);
}
#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
// For strict-ansi modes integral<__int128> is false
else if constexpr (__detail::__is_int128<__size_type>)
return static_cast<__int128>(__size);
#endif
else // Must be one of __max_diff_type or __max_size_type.
return __detail::__max_diff_type(__size);
}
};
template<typename _Tp>
concept __member_empty = requires(_Tp& __t) { bool(__t.empty()); };
template<typename _Tp>
concept __size0_empty = requires(_Tp& __t) { _Size{}(__t) == 0; };
template<typename _Tp>
concept __eq_iter_empty = requires(_Tp& __t)
{
{ _Begin{}(__t) } -> forward_iterator;
bool(_Begin{}(__t) == _End{}(__t));
};
struct _Empty
{
private:
template<typename _Tp>
static constexpr bool
_S_noexcept()
{
if constexpr (__member_empty<_Tp>)
return noexcept(bool(std::declval<_Tp&>().empty()));
else if constexpr (__size0_empty<_Tp>)
return noexcept(_Size{}(std::declval<_Tp&>()) == 0);
else
return noexcept(bool(_Begin{}(std::declval<_Tp&>())
== _End{}(std::declval<_Tp&>())));
}
public:
template<typename _Tp>
requires __member_empty<_Tp> || __size0_empty<_Tp>
|| __eq_iter_empty<_Tp>
constexpr bool
operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
{
if constexpr (__member_empty<_Tp>)
return bool(__t.empty());
else if constexpr (__size0_empty<_Tp>)
return _Size{}(__t) == 0;
else
return bool(_Begin{}(__t) == _End{}(__t));
}
};
template<typename _Tp>
concept __pointer_to_object = is_pointer_v<_Tp>
&& is_object_v<remove_pointer_t<_Tp>>;
template<typename _Tp>
concept __member_data = requires(_Tp& __t)
{
{ __decay_copy(__t.data()) } -> __pointer_to_object;
};
template<typename _Tp>
concept __begin_data = contiguous_iterator<__range_iter_t<_Tp>>;
struct _Data
{
private:
template<typename _Tp>
static constexpr bool
_S_noexcept()
{
if constexpr (__member_data<_Tp>)
return noexcept(__decay_copy(std::declval<_Tp&>().data()));
else
return noexcept(_Begin{}(std::declval<_Tp&>()));
}
public:
template<__maybe_borrowed_range _Tp>
requires __member_data<_Tp> || __begin_data<_Tp>
constexpr auto
operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
{
if constexpr (__member_data<_Tp>)
return __t.data();
else
return std::to_address(_Begin{}(__t));
}
};
struct _CData
{
template<typename _Tp>
constexpr auto
operator()(_Tp&& __e) const
noexcept(noexcept(_Data{}(__cust_access::__as_const<_Tp>(__e))))
requires requires { _Data{}(__cust_access::__as_const<_Tp>(__e)); }
{
return _Data{}(__cust_access::__as_const<_Tp>(__e));
}
};
} // namespace __cust_access
inline namespace __cust
{
inline constexpr __cust_access::_Begin begin{};
inline constexpr __cust_access::_End end{};
inline constexpr __cust_access::_CBegin cbegin{};
inline constexpr __cust_access::_CEnd cend{};
inline constexpr __cust_access::_RBegin rbegin{};
inline constexpr __cust_access::_REnd rend{};
inline constexpr __cust_access::_CRBegin crbegin{};
inline constexpr __cust_access::_CREnd crend{};
inline constexpr __cust_access::_Size size{};
inline constexpr __cust_access::_SSize ssize{};
inline constexpr __cust_access::_Empty empty{};
inline constexpr __cust_access::_Data data{};
inline constexpr __cust_access::_CData cdata{};
}
/// [range.range] The range concept.
template<typename _Tp>
concept range = requires(_Tp& __t)
{
ranges::begin(__t);
ranges::end(__t);
};
/// [range.range] The borrowed_range concept.
template<typename _Tp>
concept borrowed_range
= range<_Tp> && __detail::__maybe_borrowed_range<_Tp>;
template<typename _Tp>
using iterator_t = std::__detail::__range_iter_t<_Tp>;
template<range _Range>
using sentinel_t = decltype(ranges::end(std::declval<_Range&>()));
template<range _Range>
using range_difference_t = iter_difference_t<iterator_t<_Range>>;
template<range _Range>
using range_value_t = iter_value_t<iterator_t<_Range>>;
template<range _Range>
using range_reference_t = iter_reference_t<iterator_t<_Range>>;
template<range _Range>
using range_rvalue_reference_t
= iter_rvalue_reference_t<iterator_t<_Range>>;
/// [range.sized] The sized_range concept.
template<typename _Tp>
concept sized_range = range<_Tp>
&& requires(_Tp& __t) { ranges::size(__t); };
template<sized_range _Range>
using range_size_t = decltype(ranges::size(std::declval<_Range&>()));
/// [range.view] The ranges::view_base type.
struct view_base { };
/// [range.view] The ranges::enable_view boolean.
template<typename _Tp>
inline constexpr bool enable_view = derived_from<_Tp, view_base>;
/// [range.view] The ranges::view concept.
template<typename _Tp>
concept view
= range<_Tp> && movable<_Tp> && default_initializable<_Tp>
&& enable_view<_Tp>;
// [range.refinements]
/// A range for which ranges::begin returns an output iterator.
template<typename _Range, typename _Tp>
concept output_range
= range<_Range> && output_iterator<iterator_t<_Range>, _Tp>;
/// A range for which ranges::begin returns an input iterator.
template<typename _Tp>
concept input_range = range<_Tp> && input_iterator<iterator_t<_Tp>>;
/// A range for which ranges::begin returns a forward iterator.
template<typename _Tp>
concept forward_range
= input_range<_Tp> && forward_iterator<iterator_t<_Tp>>;
/// A range for which ranges::begin returns a bidirectional iterator.
template<typename _Tp>
concept bidirectional_range
= forward_range<_Tp> && bidirectional_iterator<iterator_t<_Tp>>;
/// A range for which ranges::begin returns a random access iterator.
template<typename _Tp>
concept random_access_range
= bidirectional_range<_Tp> && random_access_iterator<iterator_t<_Tp>>;
/// A range for which ranges::begin returns a contiguous iterator.
template<typename _Tp>
concept contiguous_range
= random_access_range<_Tp> && contiguous_iterator<iterator_t<_Tp>>
&& requires(_Tp& __t)
{
{ ranges::data(__t) } -> same_as<add_pointer_t<range_reference_t<_Tp>>>;
};
/// A range for which ranges::begin and ranges::end return the same type.
template<typename _Tp>
concept common_range
= range<_Tp> && same_as<iterator_t<_Tp>, sentinel_t<_Tp>>;
/// A range which can be safely converted to a view.
template<typename _Tp>
concept viewable_range = range<_Tp>
&& (borrowed_range<_Tp> || view<remove_cvref_t<_Tp>>);
// [range.iter.ops] range iterator operations
struct __advance_fn
{
template<input_or_output_iterator _It>
constexpr void
operator()(_It& __it, iter_difference_t<_It> __n) const
{
if constexpr (random_access_iterator<_It>)
__it += __n;
else if constexpr (bidirectional_iterator<_It>)
{
if (__n > 0)
{
do
{
++__it;
}
while (--__n);
}
else if (__n < 0)
{
do
{
--__it;
}
while (++__n);
}
}
else
{
// cannot decrement a non-bidirectional iterator
__glibcxx_assert(__n >= 0);
while (__n-- > 0)
++__it;
}
}
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
constexpr void
operator()(_It& __it, _Sent __bound) const
{
if constexpr (assignable_from<_It&, _Sent>)
__it = std::move(__bound);
else if constexpr (sized_sentinel_for<_Sent, _It>)
(*this)(__it, __bound - __it);
else
{
while (__it != __bound)
++__it;
}
}
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
constexpr iter_difference_t<_It>
operator()(_It& __it, iter_difference_t<_It> __n, _Sent __bound) const
{
if constexpr (sized_sentinel_for<_Sent, _It>)
{
const auto __diff = __bound - __it;
// n and bound must not lead in opposite directions:
__glibcxx_assert(__n == 0 || __diff == 0 || (__n < 0 == __diff < 0));
const auto __absdiff = __diff < 0 ? -__diff : __diff;
const auto __absn = __n < 0 ? -__n : __n;;
if (__absn >= __absdiff)
{
(*this)(__it, __bound);
return __n - __diff;
}
else
{
(*this)(__it, __n);
return 0;
}
}
else if (__it == __bound || __n == 0)
return __n;
else if (__n > 0)
{
iter_difference_t<_It> __m = 0;
do
{
++__it;
++__m;
}
while (__m != __n && __it != __bound);
return __n - __m;
}
else if constexpr (bidirectional_iterator<_It> && same_as<_It, _Sent>)
{
iter_difference_t<_It> __m = 0;
do
{
--__it;
--__m;
}
while (__m != __n && __it != __bound);
return __n - __m;
}
else
{
// cannot decrement a non-bidirectional iterator
__glibcxx_assert(__n >= 0);
return __n;
}
}
};
inline constexpr __advance_fn advance{};
struct __distance_fn
{
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
constexpr iter_difference_t<_It>
operator()(_It __first, _Sent __last) const
{
if constexpr (sized_sentinel_for<_Sent, _It>)
return __last - __first;
else
{
iter_difference_t<_It> __n = 0;
while (__first != __last)
{
++__first;
++__n;
}
return __n;
}
}
template<range _Range>
constexpr range_difference_t<_Range>
operator()(_Range&& __r) const
{
if constexpr (sized_range<_Range>)
return static_cast<range_difference_t<_Range>>(ranges::size(__r));
else
return (*this)(ranges::begin(__r), ranges::end(__r));
}
};
inline constexpr __distance_fn distance{};
struct __next_fn
{
template<input_or_output_iterator _It>
constexpr _It
operator()(_It __x) const
{
++__x;
return __x;
}
template<input_or_output_iterator _It>
constexpr _It
operator()(_It __x, iter_difference_t<_It> __n) const
{
ranges::advance(__x, __n);
return __x;
}
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
constexpr _It
operator()(_It __x, _Sent __bound) const
{
ranges::advance(__x, __bound);
return __x;
}
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
constexpr _It
operator()(_It __x, iter_difference_t<_It> __n, _Sent __bound) const
{
ranges::advance(__x, __n, __bound);
return __x;
}
};
inline constexpr __next_fn next{};
struct __prev_fn
{
template<bidirectional_iterator _It>
constexpr _It
operator()(_It __x) const
{
--__x;
return __x;
}
template<bidirectional_iterator _It>
constexpr _It
operator()(_It __x, iter_difference_t<_It> __n) const
{
ranges::advance(__x, -__n);
return __x;
}
template<bidirectional_iterator _It>
constexpr _It
operator()(_It __x, iter_difference_t<_It> __n, _It __bound) const
{
ranges::advance(__x, -__n, __bound);
return __x;
}
};
inline constexpr __prev_fn prev{};
/// Type returned by algorithms instead of a dangling iterator or subrange.
struct dangling
{
constexpr dangling() noexcept = default;
template<typename... _Args>
constexpr dangling(_Args&&...) noexcept { }
};
template<range _Range>
using borrowed_iterator_t = conditional_t<borrowed_range<_Range>,
iterator_t<_Range>,
dangling>;
} // namespace ranges
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // library concepts
#endif // C++20
#endif // _GLIBCXX_RANGES_BASE_H