mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-28 22:34:03 +08:00
libstdc++: Introduce new headers for C++20 ranges components
This introduces two new headers: <bits/ranges_base.h> defines the minimal components needed for using C++20 ranges (customization point objects such as std::ranges::begin, concepts such as std::ranges::range, etc.) <bits/ranges_util.h> includes <bits/ranges_base.h> and additionally defines subrange, which is needed by <bits/ranges_algo.h>. Most of the content of <bits/ranges_base.h> was previously defined in <bits/range_access.h>, but a few pieces were only defined in <ranges>. This meant the entire <ranges> header was needed in <algorithm> and <memory>, even though they don't use all the range adaptors. By moving the ranges components out of <bits/range_access.h> that file is left defining just the contents of [iterator.range] i.e. std::begin, std::end, std::size etc. and not C++20 ranges components. For consistency with other C++20 ranges headers, <bits/range_cmp.h> is renamed to <bits/ranges_cmp.h>. libstdc++-v3/ChangeLog: * include/Makefile.am: Add new headers and adjust for renamed header. * include/Makefile.in: Regenerate. * include/bits/iterator_concepts.h: Adjust for renamed header. * include/bits/range_access.h (ranges::*): Move to new <bits/ranges_base.h> header. * include/bits/ranges_algobase.h: Include new <bits/ranges_base.h> header instead of <ranges>. * include/bits/ranges_algo.h: Include new <bits/ranges_util.h> header. * include/bits/range_cmp.h: Moved to... * include/bits/ranges_cmp.h: ...here. * include/bits/ranges_base.h: New header. * include/bits/ranges_util.h: New header. * include/experimental/string_view: Include new <bits/ranges_base.h> header. * include/std/functional: Adjust for renamed header. * include/std/ranges (ranges::view_base, ranges::enable_view) (ranges::dangling, ranges::borrowed_iterator_t): Move to new <bits/ranges_base.h> header. (ranges::view_interface, ranges::subrange) (ranges::borrowed_subrange_t): Move to new <bits/ranges_util.h> header. * include/std/span: Include new <bits/ranges_base.h> header. * include/std/string_view: Likewise. * testsuite/24_iterators/back_insert_iterator/pr93884.cc: Add missing <ranges> header. * testsuite/24_iterators/front_insert_iterator/pr93884.cc: Likewise.
This commit is contained in:
parent
7df1534c13
commit
160061ac10
@ -158,10 +158,12 @@ bits_headers = \
|
||||
${bits_srcdir}/random.h \
|
||||
${bits_srcdir}/random.tcc \
|
||||
${bits_srcdir}/range_access.h \
|
||||
${bits_srcdir}/range_cmp.h \
|
||||
${bits_srcdir}/ranges_algobase.h \
|
||||
${bits_srcdir}/ranges_algo.h \
|
||||
${bits_srcdir}/ranges_base.h \
|
||||
${bits_srcdir}/ranges_cmp.h \
|
||||
${bits_srcdir}/ranges_uninitialized.h \
|
||||
${bits_srcdir}/ranges_util.h \
|
||||
${bits_srcdir}/refwrap.h \
|
||||
${bits_srcdir}/regex.h \
|
||||
${bits_srcdir}/regex.tcc \
|
||||
|
@ -504,10 +504,12 @@ bits_headers = \
|
||||
${bits_srcdir}/random.h \
|
||||
${bits_srcdir}/random.tcc \
|
||||
${bits_srcdir}/range_access.h \
|
||||
${bits_srcdir}/range_cmp.h \
|
||||
${bits_srcdir}/ranges_algobase.h \
|
||||
${bits_srcdir}/ranges_algo.h \
|
||||
${bits_srcdir}/ranges_base.h \
|
||||
${bits_srcdir}/ranges_cmp.h \
|
||||
${bits_srcdir}/ranges_uninitialized.h \
|
||||
${bits_srcdir}/ranges_util.h \
|
||||
${bits_srcdir}/refwrap.h \
|
||||
${bits_srcdir}/regex.h \
|
||||
${bits_srcdir}/regex.tcc \
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
#include <concepts>
|
||||
#include <bits/ptr_traits.h> // to_address
|
||||
#include <bits/range_cmp.h> // identity, ranges::less
|
||||
#include <bits/ranges_cmp.h> // identity, ranges::less
|
||||
|
||||
#if __cpp_lib_concepts
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
|
@ -1,4 +1,4 @@
|
||||
// <range_access.h> -*- C++ -*-
|
||||
// Range access functions for containers -*- C++ -*-
|
||||
|
||||
// Copyright (C) 2010-2020 Free Software Foundation, Inc.
|
||||
//
|
||||
@ -34,11 +34,7 @@
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
#include <initializer_list>
|
||||
#include <bits/iterator_concepts.h>
|
||||
#include <ext/numeric_traits.h>
|
||||
#if __cplusplus > 201703L
|
||||
#include <bits/max_size_type.h>
|
||||
#endif
|
||||
#include <type_traits> // common_type_t, make_signed_t
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
@ -322,8 +318,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
data(initializer_list<_Tp> __il) noexcept
|
||||
{ return __il.begin(); }
|
||||
|
||||
#endif // C++17
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
#define __cpp_lib_ssize 201902L
|
||||
template<typename _Container>
|
||||
@ -340,824 +334,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
constexpr ptrdiff_t
|
||||
ssize(const _Tp (&)[_Num]) noexcept
|
||||
{ return _Num; }
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges
|
||||
{
|
||||
template<typename>
|
||||
inline constexpr bool disable_sized_range = false;
|
||||
|
||||
template<typename _Tp>
|
||||
inline constexpr bool enable_borrowed_range = false;
|
||||
|
||||
template<typename _Tp>
|
||||
extern const bool enable_view;
|
||||
|
||||
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::__class_or_enum;
|
||||
using std::__detail::__decay_copy;
|
||||
using std::__detail::__member_begin;
|
||||
using std::__detail::__adl_begin;
|
||||
|
||||
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>);
|
||||
using _Up = remove_all_extents_t<remove_reference_t<_Tp>>;
|
||||
static_assert(sizeof(_Up) != 0, "not array of incomplete type");
|
||||
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<decltype(_Begin{}(std::forward<_Tp>(__t)))>;
|
||||
};
|
||||
|
||||
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<decltype(_Begin{}(std::forward<_Tp>(__t)))>;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _Tp>
|
||||
constexpr decltype(auto)
|
||||
__as_const(_Tp&& __t) noexcept
|
||||
{
|
||||
if constexpr (is_lvalue_reference_v<_Tp>)
|
||||
return static_cast<const remove_reference_t<_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(std::forward<_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(std::forward<_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{}(__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(std::forward<_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(std::forward<_Tp>(__e)));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _Tp>
|
||||
concept __member_size = !disable_sized_range<remove_cvref_t<_Tp>>
|
||||
&& requires(_Tp&& __t)
|
||||
{
|
||||
{ __decay_copy(std::forward<_Tp>(__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(std::forward<_Tp>(__t))) }
|
||||
-> __detail::__is_integer_like;
|
||||
};
|
||||
|
||||
template<typename _Tp>
|
||||
concept __sentinel_size = requires(_Tp&& __t)
|
||||
{
|
||||
{ _Begin{}(std::forward<_Tp>(__t)) } -> forward_iterator;
|
||||
|
||||
{ _End{}(std::forward<_Tp>(__t)) }
|
||||
-> sized_sentinel_for<decltype(_Begin{}(std::forward<_Tp>(__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&& __e) 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 std::forward<_Tp>(__e).size();
|
||||
else if constexpr (__adl_size<_Tp>)
|
||||
return size(std::forward<_Tp>(__e));
|
||||
else if constexpr (__sentinel_size<_Tp>)
|
||||
return __detail::__to_unsigned_like(
|
||||
_End{}(std::forward<_Tp>(__e))
|
||||
- _Begin{}(std::forward<_Tp>(__e)));
|
||||
}
|
||||
};
|
||||
|
||||
struct _SSize
|
||||
{
|
||||
template<typename _Tp>
|
||||
requires requires (_Tp&& __e)
|
||||
{
|
||||
_Begin{}(std::forward<_Tp>(__e));
|
||||
_Size{}(std::forward<_Tp>(__e));
|
||||
}
|
||||
constexpr auto
|
||||
operator()(_Tp&& __e) const
|
||||
noexcept(noexcept(_Size{}(std::forward<_Tp>(__e))))
|
||||
{
|
||||
using __iter_type = decltype(_Begin{}(std::forward<_Tp>(__e)));
|
||||
using __diff_type = iter_difference_t<__iter_type>;
|
||||
using __gnu_cxx::__int_traits;
|
||||
auto __size = _Size{}(std::forward<_Tp>(__e));
|
||||
if constexpr (integral<__diff_type>)
|
||||
{
|
||||
if constexpr (__int_traits<__diff_type>::__digits
|
||||
< __int_traits<ptrdiff_t>::__digits)
|
||||
return static_cast<ptrdiff_t>(__size);
|
||||
}
|
||||
return static_cast<__diff_type>(__size);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _Tp>
|
||||
concept __member_empty = requires(_Tp&& __t)
|
||||
{ bool(std::forward<_Tp>(__t).empty()); };
|
||||
|
||||
template<typename _Tp>
|
||||
concept __size0_empty = requires(_Tp&& __t)
|
||||
{ _Size{}(std::forward<_Tp>(__t)) == 0; };
|
||||
|
||||
template<typename _Tp>
|
||||
concept __eq_iter_empty = requires(_Tp&& __t)
|
||||
{
|
||||
{ _Begin{}(std::forward<_Tp>(__t)) } -> forward_iterator;
|
||||
bool(_Begin{}(std::forward<_Tp>(__t))
|
||||
== _End{}(std::forward<_Tp>(__t)));
|
||||
};
|
||||
|
||||
struct _Empty
|
||||
{
|
||||
private:
|
||||
template<typename _Tp>
|
||||
static constexpr bool
|
||||
_S_noexcept()
|
||||
{
|
||||
if constexpr (__member_empty<_Tp>)
|
||||
return noexcept(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&& __e) const noexcept(_S_noexcept<_Tp>())
|
||||
{
|
||||
if constexpr (__member_empty<_Tp>)
|
||||
return bool(std::forward<_Tp>(__e).empty());
|
||||
else if constexpr (__size0_empty<_Tp>)
|
||||
return _Size{}(std::forward<_Tp>(__e)) == 0;
|
||||
else
|
||||
return bool(_Begin{}(std::forward<_Tp>(__e))
|
||||
== _End{}(std::forward<_Tp>(__e)));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _Tp>
|
||||
concept __pointer_to_object = is_pointer_v<_Tp>
|
||||
&& is_object_v<remove_pointer_t<_Tp>>;
|
||||
|
||||
template<typename _Tp>
|
||||
concept __member_data = is_lvalue_reference_v<_Tp>
|
||||
&& requires(_Tp __t) { { __t.data() } -> __pointer_to_object; };
|
||||
|
||||
template<typename _Tp>
|
||||
concept __begin_data = requires(_Tp&& __t)
|
||||
{ { _Begin{}(std::forward<_Tp>(__t)) } -> contiguous_iterator; };
|
||||
|
||||
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&& __e) const noexcept(_S_noexcept<_Tp>())
|
||||
{
|
||||
if constexpr (__member_data<_Tp>)
|
||||
return __e.data();
|
||||
else
|
||||
return std::to_address(_Begin{}(std::forward<_Tp>(__e)));
|
||||
}
|
||||
};
|
||||
|
||||
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(std::forward<_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.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>>;
|
||||
|
||||
// [range.iter.ops] range iterator operations
|
||||
|
||||
template<input_or_output_iterator _It>
|
||||
constexpr void
|
||||
advance(_It& __it, iter_difference_t<_It> __n)
|
||||
{
|
||||
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
|
||||
advance(_It& __it, _Sent __bound)
|
||||
{
|
||||
if constexpr (assignable_from<_It&, _Sent>)
|
||||
__it = std::move(__bound);
|
||||
else if constexpr (sized_sentinel_for<_Sent, _It>)
|
||||
ranges::advance(__it, __bound - __it);
|
||||
else
|
||||
{
|
||||
while (__it != __bound)
|
||||
++__it;
|
||||
}
|
||||
}
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
|
||||
constexpr iter_difference_t<_It>
|
||||
advance(_It& __it, iter_difference_t<_It> __n, _Sent __bound)
|
||||
{
|
||||
if constexpr (sized_sentinel_for<_Sent, _It>)
|
||||
{
|
||||
const auto __diff = __bound - __it;
|
||||
#ifdef __cpp_lib_is_constant_evaluated
|
||||
if (std::is_constant_evaluated()
|
||||
&& !(__n == 0 || __diff == 0 || (__n < 0 == __diff < 0)))
|
||||
throw "inconsistent directions for distance and bound";
|
||||
#endif
|
||||
// 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)
|
||||
{
|
||||
ranges::advance(__it, __bound);
|
||||
return __n - __diff;
|
||||
}
|
||||
else
|
||||
{
|
||||
ranges::advance(__it, __n);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (__it == __bound || __n == 0)
|
||||
return iter_difference_t<_It>(0);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
|
||||
constexpr iter_difference_t<_It>
|
||||
distance(_It __first, _Sent __last)
|
||||
{
|
||||
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>
|
||||
distance(_Range&& __r)
|
||||
{
|
||||
if constexpr (sized_range<_Range>)
|
||||
return static_cast<range_difference_t<_Range>>(ranges::size(__r));
|
||||
else
|
||||
return ranges::distance(ranges::begin(__r), ranges::end(__r));
|
||||
}
|
||||
|
||||
template<input_or_output_iterator _It>
|
||||
constexpr _It
|
||||
next(_It __x)
|
||||
{
|
||||
++__x;
|
||||
return __x;
|
||||
}
|
||||
|
||||
template<input_or_output_iterator _It>
|
||||
constexpr _It
|
||||
next(_It __x, iter_difference_t<_It> __n)
|
||||
{
|
||||
ranges::advance(__x, __n);
|
||||
return __x;
|
||||
}
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
|
||||
constexpr _It
|
||||
next(_It __x, _Sent __bound)
|
||||
{
|
||||
ranges::advance(__x, __bound);
|
||||
return __x;
|
||||
}
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
|
||||
constexpr _It
|
||||
next(_It __x, iter_difference_t<_It> __n, _Sent __bound)
|
||||
{
|
||||
ranges::advance(__x, __n, __bound);
|
||||
return __x;
|
||||
}
|
||||
|
||||
template<bidirectional_iterator _It>
|
||||
constexpr _It
|
||||
prev(_It __x)
|
||||
{
|
||||
--__x;
|
||||
return __x;
|
||||
}
|
||||
|
||||
template<bidirectional_iterator _It>
|
||||
constexpr _It
|
||||
prev(_It __x, iter_difference_t<_It> __n)
|
||||
{
|
||||
ranges::advance(__x, -__n);
|
||||
return __x;
|
||||
}
|
||||
|
||||
template<bidirectional_iterator _It>
|
||||
constexpr _It
|
||||
prev(_It __x, iter_difference_t<_It> __n, _It __bound)
|
||||
{
|
||||
ranges::advance(__x, -__n, __bound);
|
||||
return __x;
|
||||
}
|
||||
|
||||
} // namespace ranges
|
||||
#endif // library concepts
|
||||
#endif // C++20
|
||||
|
||||
#endif // C++17
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace
|
||||
|
||||
#endif // C++11
|
||||
|
||||
#endif // _GLIBCXX_RANGE_ACCESS_H
|
||||
|
@ -33,6 +33,7 @@
|
||||
#if __cplusplus > 201703L
|
||||
|
||||
#include <bits/ranges_algobase.h>
|
||||
#include <bits/ranges_util.h>
|
||||
#include <bits/uniform_int_dist.h> // concept uniform_random_bit_generator
|
||||
|
||||
#if __cpp_lib_concepts
|
||||
|
@ -34,9 +34,8 @@
|
||||
|
||||
#include <compare>
|
||||
#include <iterator>
|
||||
// #include <bits/range_concepts.h>
|
||||
#include <ranges>
|
||||
#include <bits/invoke.h>
|
||||
#include <bits/ranges_base.h> // ranges::begin, ranges::range etc.
|
||||
#include <bits/invoke.h> // __invoke
|
||||
#include <bits/cpp_type_traits.h> // __is_byte
|
||||
|
||||
#if __cpp_lib_concepts
|
||||
|
887
libstdc++-v3/include/bits/ranges_base.h
Normal file
887
libstdc++-v3/include/bits/ranges_base.h
Normal file
@ -0,0 +1,887 @@
|
||||
// Core concepts and definitions for <ranges> -*- C++ -*-
|
||||
|
||||
// Copyright (C) 2019-2020 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::__class_or_enum;
|
||||
using std::__detail::__decay_copy;
|
||||
using std::__detail::__member_begin;
|
||||
using std::__detail::__adl_begin;
|
||||
|
||||
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>);
|
||||
using _Up = remove_all_extents_t<remove_reference_t<_Tp>>;
|
||||
static_assert(sizeof(_Up) != 0, "not array of incomplete type");
|
||||
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<decltype(_Begin{}(std::forward<_Tp>(__t)))>;
|
||||
};
|
||||
|
||||
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<decltype(_Begin{}(std::forward<_Tp>(__t)))>;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _Tp>
|
||||
constexpr decltype(auto)
|
||||
__as_const(_Tp&& __t) noexcept
|
||||
{
|
||||
if constexpr (is_lvalue_reference_v<_Tp>)
|
||||
return static_cast<const remove_reference_t<_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(std::forward<_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(std::forward<_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{}(__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(std::forward<_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(std::forward<_Tp>(__e)));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _Tp>
|
||||
concept __member_size = !disable_sized_range<remove_cvref_t<_Tp>>
|
||||
&& requires(_Tp&& __t)
|
||||
{
|
||||
{ __decay_copy(std::forward<_Tp>(__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(std::forward<_Tp>(__t))) }
|
||||
-> __detail::__is_integer_like;
|
||||
};
|
||||
|
||||
template<typename _Tp>
|
||||
concept __sentinel_size = requires(_Tp&& __t)
|
||||
{
|
||||
{ _Begin{}(std::forward<_Tp>(__t)) } -> forward_iterator;
|
||||
|
||||
{ _End{}(std::forward<_Tp>(__t)) }
|
||||
-> sized_sentinel_for<decltype(_Begin{}(std::forward<_Tp>(__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&& __e) 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 std::forward<_Tp>(__e).size();
|
||||
else if constexpr (__adl_size<_Tp>)
|
||||
return size(std::forward<_Tp>(__e));
|
||||
else if constexpr (__sentinel_size<_Tp>)
|
||||
return __detail::__to_unsigned_like(
|
||||
_End{}(std::forward<_Tp>(__e))
|
||||
- _Begin{}(std::forward<_Tp>(__e)));
|
||||
}
|
||||
};
|
||||
|
||||
struct _SSize
|
||||
{
|
||||
template<typename _Tp>
|
||||
requires requires (_Tp&& __e)
|
||||
{
|
||||
_Begin{}(std::forward<_Tp>(__e));
|
||||
_Size{}(std::forward<_Tp>(__e));
|
||||
}
|
||||
constexpr auto
|
||||
operator()(_Tp&& __e) const
|
||||
noexcept(noexcept(_Size{}(std::forward<_Tp>(__e))))
|
||||
{
|
||||
using __iter_type = decltype(_Begin{}(std::forward<_Tp>(__e)));
|
||||
using __diff_type = iter_difference_t<__iter_type>;
|
||||
using __gnu_cxx::__int_traits;
|
||||
auto __size = _Size{}(std::forward<_Tp>(__e));
|
||||
if constexpr (integral<__diff_type>)
|
||||
{
|
||||
if constexpr (__int_traits<__diff_type>::__digits
|
||||
< __int_traits<ptrdiff_t>::__digits)
|
||||
return static_cast<ptrdiff_t>(__size);
|
||||
}
|
||||
return static_cast<__diff_type>(__size);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _Tp>
|
||||
concept __member_empty = requires(_Tp&& __t)
|
||||
{ bool(std::forward<_Tp>(__t).empty()); };
|
||||
|
||||
template<typename _Tp>
|
||||
concept __size0_empty = requires(_Tp&& __t)
|
||||
{ _Size{}(std::forward<_Tp>(__t)) == 0; };
|
||||
|
||||
template<typename _Tp>
|
||||
concept __eq_iter_empty = requires(_Tp&& __t)
|
||||
{
|
||||
{ _Begin{}(std::forward<_Tp>(__t)) } -> forward_iterator;
|
||||
bool(_Begin{}(std::forward<_Tp>(__t))
|
||||
== _End{}(std::forward<_Tp>(__t)));
|
||||
};
|
||||
|
||||
struct _Empty
|
||||
{
|
||||
private:
|
||||
template<typename _Tp>
|
||||
static constexpr bool
|
||||
_S_noexcept()
|
||||
{
|
||||
if constexpr (__member_empty<_Tp>)
|
||||
return noexcept(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&& __e) const noexcept(_S_noexcept<_Tp>())
|
||||
{
|
||||
if constexpr (__member_empty<_Tp>)
|
||||
return bool(std::forward<_Tp>(__e).empty());
|
||||
else if constexpr (__size0_empty<_Tp>)
|
||||
return _Size{}(std::forward<_Tp>(__e)) == 0;
|
||||
else
|
||||
return bool(_Begin{}(std::forward<_Tp>(__e))
|
||||
== _End{}(std::forward<_Tp>(__e)));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _Tp>
|
||||
concept __pointer_to_object = is_pointer_v<_Tp>
|
||||
&& is_object_v<remove_pointer_t<_Tp>>;
|
||||
|
||||
template<typename _Tp>
|
||||
concept __member_data = is_lvalue_reference_v<_Tp>
|
||||
&& requires(_Tp __t) { { __t.data() } -> __pointer_to_object; };
|
||||
|
||||
template<typename _Tp>
|
||||
concept __begin_data = requires(_Tp&& __t)
|
||||
{ { _Begin{}(std::forward<_Tp>(__t)) } -> contiguous_iterator; };
|
||||
|
||||
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&& __e) const noexcept(_S_noexcept<_Tp>())
|
||||
{
|
||||
if constexpr (__member_data<_Tp>)
|
||||
return __e.data();
|
||||
else
|
||||
return std::to_address(_Begin{}(std::forward<_Tp>(__e)));
|
||||
}
|
||||
};
|
||||
|
||||
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(std::forward<_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
|
||||
|
||||
template<input_or_output_iterator _It>
|
||||
constexpr void
|
||||
advance(_It& __it, iter_difference_t<_It> __n)
|
||||
{
|
||||
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
|
||||
advance(_It& __it, _Sent __bound)
|
||||
{
|
||||
if constexpr (assignable_from<_It&, _Sent>)
|
||||
__it = std::move(__bound);
|
||||
else if constexpr (sized_sentinel_for<_Sent, _It>)
|
||||
ranges::advance(__it, __bound - __it);
|
||||
else
|
||||
{
|
||||
while (__it != __bound)
|
||||
++__it;
|
||||
}
|
||||
}
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
|
||||
constexpr iter_difference_t<_It>
|
||||
advance(_It& __it, iter_difference_t<_It> __n, _Sent __bound)
|
||||
{
|
||||
if constexpr (sized_sentinel_for<_Sent, _It>)
|
||||
{
|
||||
const auto __diff = __bound - __it;
|
||||
#ifdef __cpp_lib_is_constant_evaluated
|
||||
if (std::is_constant_evaluated()
|
||||
&& !(__n == 0 || __diff == 0 || (__n < 0 == __diff < 0)))
|
||||
throw "inconsistent directions for distance and bound";
|
||||
#endif
|
||||
// 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)
|
||||
{
|
||||
ranges::advance(__it, __bound);
|
||||
return __n - __diff;
|
||||
}
|
||||
else
|
||||
{
|
||||
ranges::advance(__it, __n);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (__it == __bound || __n == 0)
|
||||
return iter_difference_t<_It>(0);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
|
||||
constexpr iter_difference_t<_It>
|
||||
distance(_It __first, _Sent __last)
|
||||
{
|
||||
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>
|
||||
distance(_Range&& __r)
|
||||
{
|
||||
if constexpr (sized_range<_Range>)
|
||||
return static_cast<range_difference_t<_Range>>(ranges::size(__r));
|
||||
else
|
||||
return ranges::distance(ranges::begin(__r), ranges::end(__r));
|
||||
}
|
||||
|
||||
template<input_or_output_iterator _It>
|
||||
constexpr _It
|
||||
next(_It __x)
|
||||
{
|
||||
++__x;
|
||||
return __x;
|
||||
}
|
||||
|
||||
template<input_or_output_iterator _It>
|
||||
constexpr _It
|
||||
next(_It __x, iter_difference_t<_It> __n)
|
||||
{
|
||||
ranges::advance(__x, __n);
|
||||
return __x;
|
||||
}
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
|
||||
constexpr _It
|
||||
next(_It __x, _Sent __bound)
|
||||
{
|
||||
ranges::advance(__x, __bound);
|
||||
return __x;
|
||||
}
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
|
||||
constexpr _It
|
||||
next(_It __x, iter_difference_t<_It> __n, _Sent __bound)
|
||||
{
|
||||
ranges::advance(__x, __n, __bound);
|
||||
return __x;
|
||||
}
|
||||
|
||||
template<bidirectional_iterator _It>
|
||||
constexpr _It
|
||||
prev(_It __x)
|
||||
{
|
||||
--__x;
|
||||
return __x;
|
||||
}
|
||||
|
||||
template<bidirectional_iterator _It>
|
||||
constexpr _It
|
||||
prev(_It __x, iter_difference_t<_It> __n)
|
||||
{
|
||||
ranges::advance(__x, -__n);
|
||||
return __x;
|
||||
}
|
||||
|
||||
template<bidirectional_iterator _It>
|
||||
constexpr _It
|
||||
prev(_It __x, iter_difference_t<_It> __n, _It __bound)
|
||||
{
|
||||
ranges::advance(__x, -__n, __bound);
|
||||
return __x;
|
||||
}
|
||||
|
||||
/// 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
|
@ -22,13 +22,13 @@
|
||||
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
/** @file bits/range_cmp.h
|
||||
/** @file bits/ranges_cmp.h
|
||||
* This is an internal header file, included by other library headers.
|
||||
* Do not attempt to use it directly. @headername{functional}
|
||||
*/
|
||||
|
||||
#ifndef _RANGE_CMP_H
|
||||
#define _RANGE_CMP_H 1
|
||||
#ifndef _RANGES_CMP_H
|
||||
#define _RANGES_CMP_H 1
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
# include <bits/move.h>
|
||||
@ -192,4 +192,4 @@ namespace ranges
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace std
|
||||
#endif // C++20
|
||||
#endif // _RANGE_CMP_H
|
||||
#endif // _RANGES_CMP_H
|
417
libstdc++-v3/include/bits/ranges_util.h
Normal file
417
libstdc++-v3/include/bits/ranges_util.h
Normal file
@ -0,0 +1,417 @@
|
||||
// Utilities for representing and manipulating ranges -*- C++ -*-
|
||||
|
||||
// Copyright (C) 2019-2020 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_util.h
|
||||
* This is an internal header file, included by other library headers.
|
||||
* Do not attempt to use it directly. @headername{ranges}
|
||||
*/
|
||||
|
||||
#ifndef _RANGES_UTIL_H
|
||||
#define _RANGES_UTIL_H 1
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
# include <bits/ranges_base.h>
|
||||
|
||||
#ifdef __cpp_lib_ranges
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
namespace ranges
|
||||
{
|
||||
// C++20 24.5 [range.utility] Range utilities
|
||||
|
||||
namespace __detail
|
||||
{
|
||||
template<typename _Range>
|
||||
concept __simple_view = view<_Range> && range<const _Range>
|
||||
&& same_as<iterator_t<_Range>, iterator_t<const _Range>>
|
||||
&& same_as<sentinel_t<_Range>, sentinel_t<const _Range>>;
|
||||
|
||||
template<typename _It>
|
||||
concept __has_arrow = input_iterator<_It>
|
||||
&& (is_pointer_v<_It> || requires(_It __it) { __it.operator->(); });
|
||||
|
||||
template<typename _Tp, typename _Up>
|
||||
concept __not_same_as
|
||||
= !same_as<remove_cvref_t<_Tp>, remove_cvref_t<_Up>>;
|
||||
} // namespace __detail
|
||||
|
||||
/// The ranges::view_interface class template
|
||||
template<typename _Derived>
|
||||
requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
|
||||
class view_interface : public view_base
|
||||
{
|
||||
private:
|
||||
constexpr _Derived& _M_derived() noexcept
|
||||
{
|
||||
static_assert(derived_from<_Derived, view_interface<_Derived>>);
|
||||
static_assert(view<_Derived>);
|
||||
return static_cast<_Derived&>(*this);
|
||||
}
|
||||
|
||||
constexpr const _Derived& _M_derived() const noexcept
|
||||
{
|
||||
static_assert(derived_from<_Derived, view_interface<_Derived>>);
|
||||
static_assert(view<_Derived>);
|
||||
return static_cast<const _Derived&>(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr bool
|
||||
empty() requires forward_range<_Derived>
|
||||
{ return ranges::begin(_M_derived()) == ranges::end(_M_derived()); }
|
||||
|
||||
constexpr bool
|
||||
empty() const requires forward_range<const _Derived>
|
||||
{ return ranges::begin(_M_derived()) == ranges::end(_M_derived()); }
|
||||
|
||||
constexpr explicit
|
||||
operator bool() requires requires { ranges::empty(_M_derived()); }
|
||||
{ return !ranges::empty(_M_derived()); }
|
||||
|
||||
constexpr explicit
|
||||
operator bool() const requires requires { ranges::empty(_M_derived()); }
|
||||
{ return !ranges::empty(_M_derived()); }
|
||||
|
||||
constexpr auto
|
||||
data() requires contiguous_iterator<iterator_t<_Derived>>
|
||||
{ return to_address(ranges::begin(_M_derived())); }
|
||||
|
||||
constexpr auto
|
||||
data() const
|
||||
requires range<const _Derived>
|
||||
&& contiguous_iterator<iterator_t<const _Derived>>
|
||||
{ return to_address(ranges::begin(_M_derived())); }
|
||||
|
||||
constexpr auto
|
||||
size()
|
||||
requires forward_range<_Derived>
|
||||
&& sized_sentinel_for<sentinel_t<_Derived>, iterator_t<_Derived>>
|
||||
{ return ranges::end(_M_derived()) - ranges::begin(_M_derived()); }
|
||||
|
||||
constexpr auto
|
||||
size() const
|
||||
requires forward_range<const _Derived>
|
||||
&& sized_sentinel_for<sentinel_t<const _Derived>,
|
||||
iterator_t<const _Derived>>
|
||||
{ return ranges::end(_M_derived()) - ranges::begin(_M_derived()); }
|
||||
|
||||
constexpr decltype(auto)
|
||||
front() requires forward_range<_Derived>
|
||||
{
|
||||
__glibcxx_assert(!empty());
|
||||
return *ranges::begin(_M_derived());
|
||||
}
|
||||
|
||||
constexpr decltype(auto)
|
||||
front() const requires forward_range<const _Derived>
|
||||
{
|
||||
__glibcxx_assert(!empty());
|
||||
return *ranges::begin(_M_derived());
|
||||
}
|
||||
|
||||
constexpr decltype(auto)
|
||||
back()
|
||||
requires bidirectional_range<_Derived> && common_range<_Derived>
|
||||
{
|
||||
__glibcxx_assert(!empty());
|
||||
return *ranges::prev(ranges::end(_M_derived()));
|
||||
}
|
||||
|
||||
constexpr decltype(auto)
|
||||
back() const
|
||||
requires bidirectional_range<const _Derived>
|
||||
&& common_range<const _Derived>
|
||||
{
|
||||
__glibcxx_assert(!empty());
|
||||
return *ranges::prev(ranges::end(_M_derived()));
|
||||
}
|
||||
|
||||
template<random_access_range _Range = _Derived>
|
||||
constexpr decltype(auto)
|
||||
operator[](range_difference_t<_Range> __n)
|
||||
{ return ranges::begin(_M_derived())[__n]; }
|
||||
|
||||
template<random_access_range _Range = const _Derived>
|
||||
constexpr decltype(auto)
|
||||
operator[](range_difference_t<_Range> __n) const
|
||||
{ return ranges::begin(_M_derived())[__n]; }
|
||||
};
|
||||
|
||||
namespace __detail
|
||||
{
|
||||
template<class _From, class _To>
|
||||
concept __convertible_to_non_slicing = convertible_to<_From, _To>
|
||||
&& !(is_pointer_v<decay_t<_From>> && is_pointer_v<decay_t<_To>>
|
||||
&& __not_same_as<remove_pointer_t<decay_t<_From>>,
|
||||
remove_pointer_t<decay_t<_To>>>);
|
||||
|
||||
template<typename _Tp>
|
||||
concept __pair_like
|
||||
= !is_reference_v<_Tp> && requires(_Tp __t)
|
||||
{
|
||||
typename tuple_size<_Tp>::type;
|
||||
requires derived_from<tuple_size<_Tp>, integral_constant<size_t, 2>>;
|
||||
typename tuple_element_t<0, remove_const_t<_Tp>>;
|
||||
typename tuple_element_t<1, remove_const_t<_Tp>>;
|
||||
{ get<0>(__t) } -> convertible_to<const tuple_element_t<0, _Tp>&>;
|
||||
{ get<1>(__t) } -> convertible_to<const tuple_element_t<1, _Tp>&>;
|
||||
};
|
||||
|
||||
template<typename _Tp, typename _Up, typename _Vp>
|
||||
concept __pair_like_convertible_from
|
||||
= !range<_Tp> && __pair_like<_Tp>
|
||||
&& constructible_from<_Tp, _Up, _Vp>
|
||||
&& __convertible_to_non_slicing<_Up, tuple_element_t<0, _Tp>>
|
||||
&& convertible_to<_Vp, tuple_element_t<1, _Tp>>;
|
||||
|
||||
template<typename _Tp>
|
||||
concept __iterator_sentinel_pair
|
||||
= !range<_Tp> && __pair_like<_Tp>
|
||||
&& sentinel_for<tuple_element_t<1, _Tp>, tuple_element_t<0, _Tp>>;
|
||||
|
||||
} // namespace __detail
|
||||
|
||||
enum class subrange_kind : bool { unsized, sized };
|
||||
|
||||
/// The ranges::subrange class template
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent = _It,
|
||||
subrange_kind _Kind = sized_sentinel_for<_Sent, _It>
|
||||
? subrange_kind::sized : subrange_kind::unsized>
|
||||
requires (_Kind == subrange_kind::sized || !sized_sentinel_for<_Sent, _It>)
|
||||
class subrange : public view_interface<subrange<_It, _Sent, _Kind>>
|
||||
{
|
||||
private:
|
||||
// XXX: gcc complains when using constexpr here
|
||||
static const bool _S_store_size
|
||||
= _Kind == subrange_kind::sized && !sized_sentinel_for<_Sent, _It>;
|
||||
|
||||
_It _M_begin = _It();
|
||||
_Sent _M_end = _Sent();
|
||||
|
||||
template<typename, bool = _S_store_size>
|
||||
struct _Size
|
||||
{ };
|
||||
|
||||
template<typename _Tp>
|
||||
struct _Size<_Tp, true>
|
||||
{ __detail::__make_unsigned_like_t<_Tp> _M_size; };
|
||||
|
||||
[[no_unique_address]] _Size<iter_difference_t<_It>> _M_size = {};
|
||||
|
||||
public:
|
||||
subrange() = default;
|
||||
|
||||
constexpr
|
||||
subrange(__detail::__convertible_to_non_slicing<_It> auto __i, _Sent __s)
|
||||
requires (!_S_store_size)
|
||||
: _M_begin(std::move(__i)), _M_end(__s)
|
||||
{ }
|
||||
|
||||
constexpr
|
||||
subrange(__detail::__convertible_to_non_slicing<_It> auto __i, _Sent __s,
|
||||
__detail::__make_unsigned_like_t<iter_difference_t<_It>> __n)
|
||||
requires (_Kind == subrange_kind::sized)
|
||||
: _M_begin(std::move(__i)), _M_end(__s)
|
||||
{
|
||||
using __detail::__to_unsigned_like;
|
||||
__glibcxx_assert(__n == __to_unsigned_like(ranges::distance(__i, __s)));
|
||||
if constexpr (_S_store_size)
|
||||
_M_size._M_size = __n;
|
||||
}
|
||||
|
||||
template<__detail::__not_same_as<subrange> _Rng>
|
||||
requires borrowed_range<_Rng>
|
||||
&& __detail::__convertible_to_non_slicing<iterator_t<_Rng>, _It>
|
||||
&& convertible_to<sentinel_t<_Rng>, _Sent>
|
||||
constexpr
|
||||
subrange(_Rng&& __r) requires _S_store_size && sized_range<_Rng>
|
||||
: subrange{__r, ranges::size(__r)}
|
||||
{ }
|
||||
|
||||
template<__detail::__not_same_as<subrange> _Rng>
|
||||
requires borrowed_range<_Rng>
|
||||
&& __detail::__convertible_to_non_slicing<iterator_t<_Rng>, _It>
|
||||
&& convertible_to<sentinel_t<_Rng>, _Sent>
|
||||
constexpr
|
||||
subrange(_Rng&& __r) requires (!_S_store_size)
|
||||
: subrange{ranges::begin(__r), ranges::end(__r)}
|
||||
{ }
|
||||
|
||||
template<borrowed_range _Rng>
|
||||
requires __detail::__convertible_to_non_slicing<iterator_t<_Rng>, _It>
|
||||
&& convertible_to<sentinel_t<_Rng>, _Sent>
|
||||
constexpr
|
||||
subrange(_Rng&& __r,
|
||||
__detail::__make_unsigned_like_t<iter_difference_t<_It>> __n)
|
||||
requires (_Kind == subrange_kind::sized)
|
||||
: subrange{ranges::begin(__r), ranges::end(__r), __n}
|
||||
{ }
|
||||
|
||||
template<__detail::__not_same_as<subrange> _PairLike>
|
||||
requires __detail::__pair_like_convertible_from<_PairLike, const _It&,
|
||||
const _Sent&>
|
||||
constexpr
|
||||
operator _PairLike() const
|
||||
{ return _PairLike(_M_begin, _M_end); }
|
||||
|
||||
constexpr _It
|
||||
begin() const requires copyable<_It>
|
||||
{ return _M_begin; }
|
||||
|
||||
[[nodiscard]] constexpr _It
|
||||
begin() requires (!copyable<_It>)
|
||||
{ return std::move(_M_begin); }
|
||||
|
||||
constexpr _Sent end() const { return _M_end; }
|
||||
|
||||
constexpr bool empty() const { return _M_begin == _M_end; }
|
||||
|
||||
constexpr __detail::__make_unsigned_like_t<iter_difference_t<_It>>
|
||||
size() const requires (_Kind == subrange_kind::sized)
|
||||
{
|
||||
if constexpr (_S_store_size)
|
||||
return _M_size._M_size;
|
||||
else
|
||||
return __detail::__to_unsigned_like(_M_end - _M_begin);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr subrange
|
||||
next(iter_difference_t<_It> __n = 1) const &
|
||||
requires forward_iterator<_It>
|
||||
{
|
||||
auto __tmp = *this;
|
||||
__tmp.advance(__n);
|
||||
return __tmp;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr subrange
|
||||
next(iter_difference_t<_It> __n = 1) &&
|
||||
{
|
||||
advance(__n);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr subrange
|
||||
prev(iter_difference_t<_It> __n = 1) const
|
||||
requires bidirectional_iterator<_It>
|
||||
{
|
||||
auto __tmp = *this;
|
||||
__tmp.advance(-__n);
|
||||
return __tmp;
|
||||
}
|
||||
|
||||
constexpr subrange&
|
||||
advance(iter_difference_t<_It> __n)
|
||||
{
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 3433. subrange::advance(n) has UB when n < 0
|
||||
if constexpr (bidirectional_iterator<_It>)
|
||||
if (__n < 0)
|
||||
{
|
||||
ranges::advance(_M_begin, __n);
|
||||
if constexpr (_S_store_size)
|
||||
_M_size._M_size += __detail::__to_unsigned_like(-__n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
__glibcxx_assert(__n >= 0);
|
||||
auto __d = __n - ranges::advance(_M_begin, __n, _M_end);
|
||||
if constexpr (_S_store_size)
|
||||
_M_size._M_size -= __detail::__to_unsigned_like(__d);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
|
||||
subrange(_It, _Sent) -> subrange<_It, _Sent>;
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
|
||||
subrange(_It, _Sent,
|
||||
__detail::__make_unsigned_like_t<iter_difference_t<_It>>)
|
||||
-> subrange<_It, _Sent, subrange_kind::sized>;
|
||||
|
||||
template<__detail::__iterator_sentinel_pair _Pr>
|
||||
subrange(_Pr)
|
||||
-> subrange<tuple_element_t<0, _Pr>, tuple_element_t<1, _Pr>>;
|
||||
|
||||
template<__detail::__iterator_sentinel_pair _Pr>
|
||||
subrange(_Pr, __detail::__make_unsigned_like_t<iter_difference_t<
|
||||
tuple_element_t<0, _Pr>>>)
|
||||
-> subrange<tuple_element_t<0, _Pr>, tuple_element_t<1, _Pr>,
|
||||
subrange_kind::sized>;
|
||||
|
||||
template<borrowed_range _Rng>
|
||||
subrange(_Rng&&)
|
||||
-> subrange<iterator_t<_Rng>, sentinel_t<_Rng>,
|
||||
(sized_range<_Rng>
|
||||
|| sized_sentinel_for<sentinel_t<_Rng>, iterator_t<_Rng>>)
|
||||
? subrange_kind::sized : subrange_kind::unsized>;
|
||||
|
||||
template<borrowed_range _Rng>
|
||||
subrange(_Rng&&,
|
||||
__detail::__make_unsigned_like_t<range_difference_t<_Rng>>)
|
||||
-> subrange<iterator_t<_Rng>, sentinel_t<_Rng>, subrange_kind::sized>;
|
||||
|
||||
template<size_t _Num, class _It, class _Sent, subrange_kind _Kind>
|
||||
requires (_Num < 2)
|
||||
constexpr auto
|
||||
get(const subrange<_It, _Sent, _Kind>& __r)
|
||||
{
|
||||
if constexpr (_Num == 0)
|
||||
return __r.begin();
|
||||
else
|
||||
return __r.end();
|
||||
}
|
||||
|
||||
template<size_t _Num, class _It, class _Sent, subrange_kind _Kind>
|
||||
requires (_Num < 2)
|
||||
constexpr auto
|
||||
get(subrange<_It, _Sent, _Kind>&& __r)
|
||||
{
|
||||
if constexpr (_Num == 0)
|
||||
return __r.begin();
|
||||
else
|
||||
return __r.end();
|
||||
}
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent,
|
||||
subrange_kind _Kind>
|
||||
inline constexpr bool
|
||||
enable_borrowed_range<subrange<_It, _Sent, _Kind>> = true;
|
||||
|
||||
template<range _Range>
|
||||
using borrowed_subrange_t = conditional_t<borrowed_range<_Range>,
|
||||
subrange<iterator_t<_Range>>,
|
||||
dangling>;
|
||||
|
||||
} // namespace ranges
|
||||
|
||||
using ranges::get;
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace std
|
||||
#endif // library concepts
|
||||
#endif // C++20
|
||||
#endif // _RANGES_UTIL_H
|
@ -40,6 +40,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <limits>
|
||||
#include <bits/ranges_base.h> // enable_borrowed_range, enable_view
|
||||
#include <experimental/bits/lfts_config.h>
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
|
@ -65,7 +65,7 @@
|
||||
# include <bits/stl_algo.h>
|
||||
#endif
|
||||
#if __cplusplus > 201703L
|
||||
# include <bits/range_cmp.h>
|
||||
# include <bits/ranges_cmp.h>
|
||||
# include <compare>
|
||||
#endif
|
||||
|
||||
|
@ -38,12 +38,13 @@
|
||||
|
||||
#if __cpp_lib_concepts
|
||||
|
||||
#include <bits/refwrap.h>
|
||||
#include <compare>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
#include <bits/ranges_util.h>
|
||||
#include <bits/refwrap.h>
|
||||
|
||||
/**
|
||||
* @defgroup ranges Ranges
|
||||
@ -56,410 +57,18 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
namespace ranges
|
||||
{
|
||||
// [range.range] The range concept.
|
||||
// [range.sized] The sized_range concept.
|
||||
// Defined in <bits/range_access.h>
|
||||
// [range.access] customization point objects
|
||||
// [range.req] range and view concepts
|
||||
// [range.dangling] dangling iterator handling
|
||||
// Defined in <bits/ranges_base.h>
|
||||
|
||||
// [range.refinements]
|
||||
// Defined in <bits/range_access.h>
|
||||
// [view.interface] View interface
|
||||
// [range.subrange] Sub-ranges
|
||||
// Defined in <bits/ranges_util.h>
|
||||
|
||||
struct view_base { };
|
||||
|
||||
template<typename _Tp>
|
||||
inline constexpr bool enable_view = derived_from<_Tp, view_base>;
|
||||
|
||||
template<typename _Tp>
|
||||
concept view
|
||||
= range<_Tp> && movable<_Tp> && default_initializable<_Tp>
|
||||
&& enable_view<_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>>);
|
||||
|
||||
namespace __detail
|
||||
{
|
||||
template<typename _Range>
|
||||
concept __simple_view = view<_Range> && range<const _Range>
|
||||
&& same_as<iterator_t<_Range>, iterator_t<const _Range>>
|
||||
&& same_as<sentinel_t<_Range>, sentinel_t<const _Range>>;
|
||||
|
||||
template<typename _It>
|
||||
concept __has_arrow = input_iterator<_It>
|
||||
&& (is_pointer_v<_It> || requires(_It __it) { __it.operator->(); });
|
||||
|
||||
template<typename _Tp, typename _Up>
|
||||
concept __not_same_as
|
||||
= !same_as<remove_cvref_t<_Tp>, remove_cvref_t<_Up>>;
|
||||
} // namespace __detail
|
||||
|
||||
template<typename _Derived>
|
||||
requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
|
||||
class view_interface : public view_base
|
||||
{
|
||||
private:
|
||||
constexpr _Derived& _M_derived() noexcept
|
||||
{
|
||||
static_assert(derived_from<_Derived, view_interface<_Derived>>);
|
||||
static_assert(view<_Derived>);
|
||||
return static_cast<_Derived&>(*this);
|
||||
}
|
||||
|
||||
constexpr const _Derived& _M_derived() const noexcept
|
||||
{
|
||||
static_assert(derived_from<_Derived, view_interface<_Derived>>);
|
||||
static_assert(view<_Derived>);
|
||||
return static_cast<const _Derived&>(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr bool
|
||||
empty() requires forward_range<_Derived>
|
||||
{ return ranges::begin(_M_derived()) == ranges::end(_M_derived()); }
|
||||
|
||||
constexpr bool
|
||||
empty() const requires forward_range<const _Derived>
|
||||
{ return ranges::begin(_M_derived()) == ranges::end(_M_derived()); }
|
||||
|
||||
constexpr explicit
|
||||
operator bool() requires requires { ranges::empty(_M_derived()); }
|
||||
{ return !ranges::empty(_M_derived()); }
|
||||
|
||||
constexpr explicit
|
||||
operator bool() const requires requires { ranges::empty(_M_derived()); }
|
||||
{ return !ranges::empty(_M_derived()); }
|
||||
|
||||
constexpr auto
|
||||
data() requires contiguous_iterator<iterator_t<_Derived>>
|
||||
{ return to_address(ranges::begin(_M_derived())); }
|
||||
|
||||
constexpr auto
|
||||
data() const
|
||||
requires range<const _Derived>
|
||||
&& contiguous_iterator<iterator_t<const _Derived>>
|
||||
{ return to_address(ranges::begin(_M_derived())); }
|
||||
|
||||
constexpr auto
|
||||
size()
|
||||
requires forward_range<_Derived>
|
||||
&& sized_sentinel_for<sentinel_t<_Derived>, iterator_t<_Derived>>
|
||||
{ return ranges::end(_M_derived()) - ranges::begin(_M_derived()); }
|
||||
|
||||
constexpr auto
|
||||
size() const
|
||||
requires forward_range<const _Derived>
|
||||
&& sized_sentinel_for<sentinel_t<const _Derived>,
|
||||
iterator_t<const _Derived>>
|
||||
{ return ranges::end(_M_derived()) - ranges::begin(_M_derived()); }
|
||||
|
||||
constexpr decltype(auto)
|
||||
front() requires forward_range<_Derived>
|
||||
{
|
||||
__glibcxx_assert(!empty());
|
||||
return *ranges::begin(_M_derived());
|
||||
}
|
||||
|
||||
constexpr decltype(auto)
|
||||
front() const requires forward_range<const _Derived>
|
||||
{
|
||||
__glibcxx_assert(!empty());
|
||||
return *ranges::begin(_M_derived());
|
||||
}
|
||||
|
||||
constexpr decltype(auto)
|
||||
back()
|
||||
requires bidirectional_range<_Derived> && common_range<_Derived>
|
||||
{
|
||||
__glibcxx_assert(!empty());
|
||||
return *ranges::prev(ranges::end(_M_derived()));
|
||||
}
|
||||
|
||||
constexpr decltype(auto)
|
||||
back() const
|
||||
requires bidirectional_range<const _Derived>
|
||||
&& common_range<const _Derived>
|
||||
{
|
||||
__glibcxx_assert(!empty());
|
||||
return *ranges::prev(ranges::end(_M_derived()));
|
||||
}
|
||||
|
||||
template<random_access_range _Range = _Derived>
|
||||
constexpr decltype(auto)
|
||||
operator[](range_difference_t<_Range> __n)
|
||||
{ return ranges::begin(_M_derived())[__n]; }
|
||||
|
||||
template<random_access_range _Range = const _Derived>
|
||||
constexpr decltype(auto)
|
||||
operator[](range_difference_t<_Range> __n) const
|
||||
{ return ranges::begin(_M_derived())[__n]; }
|
||||
};
|
||||
|
||||
namespace __detail
|
||||
{
|
||||
template<class _From, class _To>
|
||||
concept __convertible_to_non_slicing = convertible_to<_From, _To>
|
||||
&& !(is_pointer_v<decay_t<_From>> && is_pointer_v<decay_t<_To>>
|
||||
&& __not_same_as<remove_pointer_t<decay_t<_From>>,
|
||||
remove_pointer_t<decay_t<_To>>>);
|
||||
|
||||
template<typename _Tp>
|
||||
concept __pair_like
|
||||
= !is_reference_v<_Tp> && requires(_Tp __t)
|
||||
{
|
||||
typename tuple_size<_Tp>::type;
|
||||
requires derived_from<tuple_size<_Tp>, integral_constant<size_t, 2>>;
|
||||
typename tuple_element_t<0, remove_const_t<_Tp>>;
|
||||
typename tuple_element_t<1, remove_const_t<_Tp>>;
|
||||
{ get<0>(__t) } -> convertible_to<const tuple_element_t<0, _Tp>&>;
|
||||
{ get<1>(__t) } -> convertible_to<const tuple_element_t<1, _Tp>&>;
|
||||
};
|
||||
|
||||
template<typename _Tp, typename _Up, typename _Vp>
|
||||
concept __pair_like_convertible_from
|
||||
= !range<_Tp> && __pair_like<_Tp>
|
||||
&& constructible_from<_Tp, _Up, _Vp>
|
||||
&& __convertible_to_non_slicing<_Up, tuple_element_t<0, _Tp>>
|
||||
&& convertible_to<_Vp, tuple_element_t<1, _Tp>>;
|
||||
|
||||
template<typename _Tp>
|
||||
concept __iterator_sentinel_pair
|
||||
= !range<_Tp> && __pair_like<_Tp>
|
||||
&& sentinel_for<tuple_element_t<1, _Tp>, tuple_element_t<0, _Tp>>;
|
||||
|
||||
} // namespace __detail
|
||||
|
||||
enum class subrange_kind : bool { unsized, sized };
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent = _It,
|
||||
subrange_kind _Kind = sized_sentinel_for<_Sent, _It>
|
||||
? subrange_kind::sized : subrange_kind::unsized>
|
||||
requires (_Kind == subrange_kind::sized || !sized_sentinel_for<_Sent, _It>)
|
||||
class subrange : public view_interface<subrange<_It, _Sent, _Kind>>
|
||||
{
|
||||
private:
|
||||
// XXX: gcc complains when using constexpr here
|
||||
static const bool _S_store_size
|
||||
= _Kind == subrange_kind::sized && !sized_sentinel_for<_Sent, _It>;
|
||||
|
||||
_It _M_begin = _It();
|
||||
_Sent _M_end = _Sent();
|
||||
|
||||
template<typename, bool = _S_store_size>
|
||||
struct _Size
|
||||
{ };
|
||||
|
||||
template<typename _Tp>
|
||||
struct _Size<_Tp, true>
|
||||
{ __detail::__make_unsigned_like_t<_Tp> _M_size; };
|
||||
|
||||
[[no_unique_address]] _Size<iter_difference_t<_It>> _M_size = {};
|
||||
|
||||
public:
|
||||
subrange() = default;
|
||||
|
||||
constexpr
|
||||
subrange(__detail::__convertible_to_non_slicing<_It> auto __i, _Sent __s)
|
||||
requires (!_S_store_size)
|
||||
: _M_begin(std::move(__i)), _M_end(__s)
|
||||
{ }
|
||||
|
||||
constexpr
|
||||
subrange(__detail::__convertible_to_non_slicing<_It> auto __i, _Sent __s,
|
||||
__detail::__make_unsigned_like_t<iter_difference_t<_It>> __n)
|
||||
requires (_Kind == subrange_kind::sized)
|
||||
: _M_begin(std::move(__i)), _M_end(__s)
|
||||
{
|
||||
using __detail::__to_unsigned_like;
|
||||
__glibcxx_assert(__n == __to_unsigned_like(ranges::distance(__i, __s)));
|
||||
if constexpr (_S_store_size)
|
||||
_M_size._M_size = __n;
|
||||
}
|
||||
|
||||
template<__detail::__not_same_as<subrange> _Rng>
|
||||
requires borrowed_range<_Rng>
|
||||
&& __detail::__convertible_to_non_slicing<iterator_t<_Rng>, _It>
|
||||
&& convertible_to<sentinel_t<_Rng>, _Sent>
|
||||
constexpr
|
||||
subrange(_Rng&& __r) requires _S_store_size && sized_range<_Rng>
|
||||
: subrange{__r, ranges::size(__r)}
|
||||
{ }
|
||||
|
||||
template<__detail::__not_same_as<subrange> _Rng>
|
||||
requires borrowed_range<_Rng>
|
||||
&& __detail::__convertible_to_non_slicing<iterator_t<_Rng>, _It>
|
||||
&& convertible_to<sentinel_t<_Rng>, _Sent>
|
||||
constexpr
|
||||
subrange(_Rng&& __r) requires (!_S_store_size)
|
||||
: subrange{ranges::begin(__r), ranges::end(__r)}
|
||||
{ }
|
||||
|
||||
template<borrowed_range _Rng>
|
||||
requires __detail::__convertible_to_non_slicing<iterator_t<_Rng>, _It>
|
||||
&& convertible_to<sentinel_t<_Rng>, _Sent>
|
||||
constexpr
|
||||
subrange(_Rng&& __r,
|
||||
__detail::__make_unsigned_like_t<iter_difference_t<_It>> __n)
|
||||
requires (_Kind == subrange_kind::sized)
|
||||
: subrange{ranges::begin(__r), ranges::end(__r), __n}
|
||||
{ }
|
||||
|
||||
template<__detail::__not_same_as<subrange> _PairLike>
|
||||
requires __detail::__pair_like_convertible_from<_PairLike, const _It&,
|
||||
const _Sent&>
|
||||
constexpr
|
||||
operator _PairLike() const
|
||||
{ return _PairLike(_M_begin, _M_end); }
|
||||
|
||||
constexpr _It
|
||||
begin() const requires copyable<_It>
|
||||
{ return _M_begin; }
|
||||
|
||||
[[nodiscard]] constexpr _It
|
||||
begin() requires (!copyable<_It>)
|
||||
{ return std::move(_M_begin); }
|
||||
|
||||
constexpr _Sent end() const { return _M_end; }
|
||||
|
||||
constexpr bool empty() const { return _M_begin == _M_end; }
|
||||
|
||||
constexpr __detail::__make_unsigned_like_t<iter_difference_t<_It>>
|
||||
size() const requires (_Kind == subrange_kind::sized)
|
||||
{
|
||||
if constexpr (_S_store_size)
|
||||
return _M_size._M_size;
|
||||
else
|
||||
return __detail::__to_unsigned_like(_M_end - _M_begin);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr subrange
|
||||
next(iter_difference_t<_It> __n = 1) const &
|
||||
requires forward_iterator<_It>
|
||||
{
|
||||
auto __tmp = *this;
|
||||
__tmp.advance(__n);
|
||||
return __tmp;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr subrange
|
||||
next(iter_difference_t<_It> __n = 1) &&
|
||||
{
|
||||
advance(__n);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr subrange
|
||||
prev(iter_difference_t<_It> __n = 1) const
|
||||
requires bidirectional_iterator<_It>
|
||||
{
|
||||
auto __tmp = *this;
|
||||
__tmp.advance(-__n);
|
||||
return __tmp;
|
||||
}
|
||||
|
||||
constexpr subrange&
|
||||
advance(iter_difference_t<_It> __n)
|
||||
{
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 3433. subrange::advance(n) has UB when n < 0
|
||||
if constexpr (bidirectional_iterator<_It>)
|
||||
if (__n < 0)
|
||||
{
|
||||
ranges::advance(_M_begin, __n);
|
||||
if constexpr (_S_store_size)
|
||||
_M_size._M_size += __detail::__to_unsigned_like(-__n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
__glibcxx_assert(__n >= 0);
|
||||
auto __d = __n - ranges::advance(_M_begin, __n, _M_end);
|
||||
if constexpr (_S_store_size)
|
||||
_M_size._M_size -= __detail::__to_unsigned_like(__d);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
|
||||
subrange(_It, _Sent) -> subrange<_It, _Sent>;
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
|
||||
subrange(_It, _Sent,
|
||||
__detail::__make_unsigned_like_t<iter_difference_t<_It>>)
|
||||
-> subrange<_It, _Sent, subrange_kind::sized>;
|
||||
|
||||
template<__detail::__iterator_sentinel_pair _Pr>
|
||||
subrange(_Pr)
|
||||
-> subrange<tuple_element_t<0, _Pr>, tuple_element_t<1, _Pr>>;
|
||||
|
||||
template<__detail::__iterator_sentinel_pair _Pr>
|
||||
subrange(_Pr, __detail::__make_unsigned_like_t<iter_difference_t<
|
||||
tuple_element_t<0, _Pr>>>)
|
||||
-> subrange<tuple_element_t<0, _Pr>, tuple_element_t<1, _Pr>,
|
||||
subrange_kind::sized>;
|
||||
|
||||
template<borrowed_range _Rng>
|
||||
subrange(_Rng&&)
|
||||
-> subrange<iterator_t<_Rng>, sentinel_t<_Rng>,
|
||||
(sized_range<_Rng>
|
||||
|| sized_sentinel_for<sentinel_t<_Rng>, iterator_t<_Rng>>)
|
||||
? subrange_kind::sized : subrange_kind::unsized>;
|
||||
|
||||
template<borrowed_range _Rng>
|
||||
subrange(_Rng&&,
|
||||
__detail::__make_unsigned_like_t<range_difference_t<_Rng>>)
|
||||
-> subrange<iterator_t<_Rng>, sentinel_t<_Rng>, subrange_kind::sized>;
|
||||
|
||||
template<size_t _Num, class _It, class _Sent, subrange_kind _Kind>
|
||||
requires (_Num < 2)
|
||||
constexpr auto
|
||||
get(const subrange<_It, _Sent, _Kind>& __r)
|
||||
{
|
||||
if constexpr (_Num == 0)
|
||||
return __r.begin();
|
||||
else
|
||||
return __r.end();
|
||||
}
|
||||
|
||||
template<size_t _Num, class _It, class _Sent, subrange_kind _Kind>
|
||||
requires (_Num < 2)
|
||||
constexpr auto
|
||||
get(subrange<_It, _Sent, _Kind>&& __r)
|
||||
{
|
||||
if constexpr (_Num == 0)
|
||||
return __r.begin();
|
||||
else
|
||||
return __r.end();
|
||||
}
|
||||
|
||||
template<input_or_output_iterator _It, sentinel_for<_It> _Sent,
|
||||
subrange_kind _Kind>
|
||||
inline constexpr bool
|
||||
enable_borrowed_range<subrange<_It, _Sent, _Kind>> = true;
|
||||
|
||||
} // namespace ranges
|
||||
|
||||
using ranges::get;
|
||||
|
||||
namespace ranges
|
||||
{
|
||||
/// 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>;
|
||||
|
||||
template<range _Range>
|
||||
using borrowed_subrange_t = conditional_t<borrowed_range<_Range>,
|
||||
subrange<iterator_t<_Range>>,
|
||||
dangling>;
|
||||
// C++20 24.6 [range.factories] Range factories
|
||||
|
||||
/// A view that contains no elements.
|
||||
template<typename _Tp> requires is_object_v<_Tp>
|
||||
class empty_view
|
||||
: public view_interface<empty_view<_Tp>>
|
||||
@ -1038,6 +647,8 @@ namespace views
|
||||
istream_view(basic_istream<_CharT, _Traits>& __s)
|
||||
{ return basic_istream_view<_Val, _CharT, _Traits>{__s}; }
|
||||
|
||||
// C++20 24.7 [range.adaptors] Range adaptors
|
||||
|
||||
namespace __detail
|
||||
{
|
||||
struct _Empty { };
|
||||
|
@ -41,7 +41,7 @@
|
||||
#include <type_traits>
|
||||
#include <array>
|
||||
#include <bits/stl_iterator.h>
|
||||
#include <bits/range_access.h>
|
||||
#include <bits/ranges_base.h>
|
||||
|
||||
#if __cpp_lib_concepts
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <bits/char_traits.h>
|
||||
#include <bits/functional_hash.h>
|
||||
#include <bits/range_access.h>
|
||||
#include <bits/ranges_base.h>
|
||||
#include <bits/ostream_insert.h>
|
||||
#include <ext/numeric_traits.h>
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <ranges>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
namespace ranges = std::ranges;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <ranges>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
namespace ranges = std::ranges;
|
||||
|
Loading…
Reference in New Issue
Block a user