libstdc++: Introduce new headers for C++20 ranges components
authorJonathan Wakely <jwakely@redhat.com>
Tue, 22 Sep 2020 14:45:54 +0000 (15:45 +0100)
committerJonathan Wakely <jwakely@redhat.com>
Tue, 22 Sep 2020 14:45:54 +0000 (15:45 +0100)
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.

17 files changed:
libstdc++-v3/include/Makefile.am
libstdc++-v3/include/Makefile.in
libstdc++-v3/include/bits/iterator_concepts.h
libstdc++-v3/include/bits/range_access.h
libstdc++-v3/include/bits/range_cmp.h [deleted file]
libstdc++-v3/include/bits/ranges_algo.h
libstdc++-v3/include/bits/ranges_algobase.h
libstdc++-v3/include/bits/ranges_base.h [new file with mode: 0644]
libstdc++-v3/include/bits/ranges_cmp.h [new file with mode: 0644]
libstdc++-v3/include/bits/ranges_util.h [new file with mode: 0644]
libstdc++-v3/include/experimental/string_view
libstdc++-v3/include/std/functional
libstdc++-v3/include/std/ranges
libstdc++-v3/include/std/span
libstdc++-v3/include/std/string_view
libstdc++-v3/testsuite/24_iterators/back_insert_iterator/pr93884.cc
libstdc++-v3/testsuite/24_iterators/front_insert_iterator/pr93884.cc

index c9df9a9d6c62751fa8cbd8e3cb6cf9f5e634f1c8..28d273924ee0fa321ef58ea9379f7574a20ca20b 100644 (file)
@@ -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 \
index 3d86b733ccde3fb76a9e74a953aac964dec40523..2dfd8d2cb36a7e3cb0b33c76597529945c46eeed 100644 (file)
@@ -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 \
index a568f2ab825f5f9ed87126ff92afe760572a6c91..8ff4f8667dd11471cd180dea58b4762345a5673c 100644 (file)
@@ -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)
index 5c5b2fe0c6c820fb234c71e47e2fdaf56418556f..c8d8185172d772e2dbb0e959957b732ec9515b7e 100644 (file)
@@ -1,4 +1,4 @@
-// <range_access.h> -*- C++ -*-
+// Range access functions for containers -*- C++ -*-
 
 // Copyright (C) 2010-2020 Free Software Foundation, Inc.
 //
 
 #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
diff --git a/libstdc++-v3/include/bits/range_cmp.h b/libstdc++-v3/include/bits/range_cmp.h
deleted file mode 100644 (file)
index 0587c59..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-// Concept-constrained comparison implementations -*- 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/range_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
-
-#if __cplusplus > 201703L
-# include <bits/move.h>
-# include <concepts>
-
-namespace std _GLIBCXX_VISIBILITY(default)
-{
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
-  struct __is_transparent; // not defined
-
-  // Define std::identity here so that <iterator> and <ranges>
-  // don't need to include <bits/stl_function.h> to get it.
-
-  /// [func.identity] The identity function.
-  struct identity
-  {
-    template<typename _Tp>
-      constexpr _Tp&&
-      operator()(_Tp&& __t) const noexcept
-      { return std::forward<_Tp>(__t); }
-
-    using is_transparent = __is_transparent;
-  };
-
-#ifdef __cpp_lib_concepts
-// Define this here, included by all the headers that need to define it.
-#define __cpp_lib_ranges 201911L
-
-namespace ranges
-{
-  namespace __detail
-  {
-    // BUILTIN-PTR-CMP(T, ==, U)
-    template<typename _Tp, typename _Up>
-      concept __eq_builtin_ptr_cmp
-       = requires (_Tp&& __t, _Up&& __u) { { __t == __u } -> same_as<bool>; }
-         && convertible_to<_Tp, const volatile void*>
-         && convertible_to<_Up, const volatile void*>
-         && (! requires(_Tp&& __t, _Up&& __u)
-             { operator==(std::forward<_Tp>(__t), std::forward<_Up>(__u)); }
-             &&
-             ! requires(_Tp&& __t, _Up&& __u)
-             { std::forward<_Tp>(__t).operator==(std::forward<_Up>(__u)); });
-
-    // BUILTIN-PTR-CMP(T, <, U)
-    template<typename _Tp, typename _Up>
-      concept __less_builtin_ptr_cmp
-       = requires (_Tp&& __t, _Up&& __u) { { __t < __u } -> same_as<bool>; }
-         && convertible_to<_Tp, const volatile void*>
-         && convertible_to<_Up, const volatile void*>
-         && (! requires(_Tp&& __t, _Up&& __u)
-             { operator<(std::forward<_Tp>(__t), std::forward<_Up>(__u)); }
-             && ! requires(_Tp&& __t, _Up&& __u)
-             { std::forward<_Tp>(__t).operator<(std::forward<_Up>(__u)); });
-  } // namespace __detail
-
-  // [range.cmp] Concept-constrained comparisons
-
-  /// ranges::equal_to function object type.
-  struct equal_to
-  {
-    template<typename _Tp, typename _Up>
-      requires equality_comparable_with<_Tp, _Up>
-       || __detail::__eq_builtin_ptr_cmp<_Tp, _Up>
-      constexpr bool
-      operator()(_Tp&& __t, _Up&& __u) const
-      noexcept(noexcept(std::declval<_Tp>() == std::declval<_Up>()))
-      { return std::forward<_Tp>(__t) == std::forward<_Up>(__u); }
-
-    using is_transparent = __is_transparent;
-  };
-
-  /// ranges::not_equal_to function object type.
-  struct not_equal_to
-  {
-    template<typename _Tp, typename _Up>
-      requires equality_comparable_with<_Tp, _Up>
-       || __detail::__eq_builtin_ptr_cmp<_Tp, _Up>
-      constexpr bool
-      operator()(_Tp&& __t, _Up&& __u) const
-      noexcept(noexcept(std::declval<_Up>() == std::declval<_Tp>()))
-      { return !equal_to{}(std::forward<_Tp>(__t), std::forward<_Up>(__u)); }
-
-    using is_transparent = __is_transparent;
-  };
-
-  /// ranges::less function object type.
-  struct less
-  {
-    template<typename _Tp, typename _Up>
-      requires totally_ordered_with<_Tp, _Up>
-       || __detail::__less_builtin_ptr_cmp<_Tp, _Up>
-      constexpr bool
-      operator()(_Tp&& __t, _Up&& __u) const
-      noexcept(noexcept(std::declval<_Tp>() < std::declval<_Up>()))
-      {
-       if constexpr (__detail::__less_builtin_ptr_cmp<_Tp, _Up>)
-         {
-#ifdef __cpp_lib_is_constant_evaluated
-           if (std::is_constant_evaluated())
-             return __t < __u;
-#endif
-           auto __x = reinterpret_cast<__UINTPTR_TYPE__>(
-             static_cast<const volatile void*>(std::forward<_Tp>(__t)));
-           auto __y = reinterpret_cast<__UINTPTR_TYPE__>(
-             static_cast<const volatile void*>(std::forward<_Up>(__u)));
-           return __x < __y;
-         }
-       else
-         return std::forward<_Tp>(__t) < std::forward<_Up>(__u);
-      }
-
-    using is_transparent = __is_transparent;
-  };
-
-  /// ranges::greater function object type.
-  struct greater
-  {
-    template<typename _Tp, typename _Up>
-      requires totally_ordered_with<_Tp, _Up>
-       || __detail::__less_builtin_ptr_cmp<_Up, _Tp>
-      constexpr bool
-      operator()(_Tp&& __t, _Up&& __u) const
-      noexcept(noexcept(std::declval<_Up>() < std::declval<_Tp>()))
-      { return less{}(std::forward<_Up>(__u), std::forward<_Tp>(__t)); }
-
-    using is_transparent = __is_transparent;
-  };
-
-  /// ranges::greater_equal function object type.
-  struct greater_equal
-  {
-    template<typename _Tp, typename _Up>
-      requires totally_ordered_with<_Tp, _Up>
-       || __detail::__less_builtin_ptr_cmp<_Tp, _Up>
-      constexpr bool
-      operator()(_Tp&& __t, _Up&& __u) const
-      noexcept(noexcept(std::declval<_Tp>() < std::declval<_Up>()))
-      { return !less{}(std::forward<_Tp>(__t), std::forward<_Up>(__u)); }
-
-    using is_transparent = __is_transparent;
-  };
-
-  /// ranges::less_equal function object type.
-  struct less_equal
-  {
-    template<typename _Tp, typename _Up>
-      requires totally_ordered_with<_Tp, _Up>
-       || __detail::__less_builtin_ptr_cmp<_Up, _Tp>
-      constexpr bool
-      operator()(_Tp&& __t, _Up&& __u) const
-      noexcept(noexcept(std::declval<_Up>() < std::declval<_Tp>()))
-      { return !less{}(std::forward<_Up>(__u), std::forward<_Tp>(__t)); }
-
-    using is_transparent = __is_transparent;
-  };
-
-} // namespace ranges
-#endif // library concepts
-_GLIBCXX_END_NAMESPACE_VERSION
-} // namespace std
-#endif // C++20
-#endif // _RANGE_CMP_H
index a5539650edcfd82eb7cb067614c55dd3e38fc959..61673e38fa69153675f386eef14b4dfd550637ab 100644 (file)
@@ -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
index 2adff643ac2bc481634ea4b2170aeac31707ddec..eb8573972fa4377598bad9818f9ff79bcbcf3e8a 100644 (file)
@@ -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
diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h
new file mode 100644 (file)
index 0000000..681b24e
--- /dev/null
@@ -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
diff --git a/libstdc++-v3/include/bits/ranges_cmp.h b/libstdc++-v3/include/bits/ranges_cmp.h
new file mode 100644 (file)
index 0000000..a48f950
--- /dev/null
@@ -0,0 +1,195 @@
+// Concept-constrained comparison implementations -*- 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_cmp.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{functional}
+ */
+
+#ifndef _RANGES_CMP_H
+#define _RANGES_CMP_H 1
+
+#if __cplusplus > 201703L
+# include <bits/move.h>
+# include <concepts>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  struct __is_transparent; // not defined
+
+  // Define std::identity here so that <iterator> and <ranges>
+  // don't need to include <bits/stl_function.h> to get it.
+
+  /// [func.identity] The identity function.
+  struct identity
+  {
+    template<typename _Tp>
+      constexpr _Tp&&
+      operator()(_Tp&& __t) const noexcept
+      { return std::forward<_Tp>(__t); }
+
+    using is_transparent = __is_transparent;
+  };
+
+#ifdef __cpp_lib_concepts
+// Define this here, included by all the headers that need to define it.
+#define __cpp_lib_ranges 201911L
+
+namespace ranges
+{
+  namespace __detail
+  {
+    // BUILTIN-PTR-CMP(T, ==, U)
+    template<typename _Tp, typename _Up>
+      concept __eq_builtin_ptr_cmp
+       = requires (_Tp&& __t, _Up&& __u) { { __t == __u } -> same_as<bool>; }
+         && convertible_to<_Tp, const volatile void*>
+         && convertible_to<_Up, const volatile void*>
+         && (! requires(_Tp&& __t, _Up&& __u)
+             { operator==(std::forward<_Tp>(__t), std::forward<_Up>(__u)); }
+             &&
+             ! requires(_Tp&& __t, _Up&& __u)
+             { std::forward<_Tp>(__t).operator==(std::forward<_Up>(__u)); });
+
+    // BUILTIN-PTR-CMP(T, <, U)
+    template<typename _Tp, typename _Up>
+      concept __less_builtin_ptr_cmp
+       = requires (_Tp&& __t, _Up&& __u) { { __t < __u } -> same_as<bool>; }
+         && convertible_to<_Tp, const volatile void*>
+         && convertible_to<_Up, const volatile void*>
+         && (! requires(_Tp&& __t, _Up&& __u)
+             { operator<(std::forward<_Tp>(__t), std::forward<_Up>(__u)); }
+             && ! requires(_Tp&& __t, _Up&& __u)
+             { std::forward<_Tp>(__t).operator<(std::forward<_Up>(__u)); });
+  } // namespace __detail
+
+  // [range.cmp] Concept-constrained comparisons
+
+  /// ranges::equal_to function object type.
+  struct equal_to
+  {
+    template<typename _Tp, typename _Up>
+      requires equality_comparable_with<_Tp, _Up>
+       || __detail::__eq_builtin_ptr_cmp<_Tp, _Up>
+      constexpr bool
+      operator()(_Tp&& __t, _Up&& __u) const
+      noexcept(noexcept(std::declval<_Tp>() == std::declval<_Up>()))
+      { return std::forward<_Tp>(__t) == std::forward<_Up>(__u); }
+
+    using is_transparent = __is_transparent;
+  };
+
+  /// ranges::not_equal_to function object type.
+  struct not_equal_to
+  {
+    template<typename _Tp, typename _Up>
+      requires equality_comparable_with<_Tp, _Up>
+       || __detail::__eq_builtin_ptr_cmp<_Tp, _Up>
+      constexpr bool
+      operator()(_Tp&& __t, _Up&& __u) const
+      noexcept(noexcept(std::declval<_Up>() == std::declval<_Tp>()))
+      { return !equal_to{}(std::forward<_Tp>(__t), std::forward<_Up>(__u)); }
+
+    using is_transparent = __is_transparent;
+  };
+
+  /// ranges::less function object type.
+  struct less
+  {
+    template<typename _Tp, typename _Up>
+      requires totally_ordered_with<_Tp, _Up>
+       || __detail::__less_builtin_ptr_cmp<_Tp, _Up>
+      constexpr bool
+      operator()(_Tp&& __t, _Up&& __u) const
+      noexcept(noexcept(std::declval<_Tp>() < std::declval<_Up>()))
+      {
+       if constexpr (__detail::__less_builtin_ptr_cmp<_Tp, _Up>)
+         {
+#ifdef __cpp_lib_is_constant_evaluated
+           if (std::is_constant_evaluated())
+             return __t < __u;
+#endif
+           auto __x = reinterpret_cast<__UINTPTR_TYPE__>(
+             static_cast<const volatile void*>(std::forward<_Tp>(__t)));
+           auto __y = reinterpret_cast<__UINTPTR_TYPE__>(
+             static_cast<const volatile void*>(std::forward<_Up>(__u)));
+           return __x < __y;
+         }
+       else
+         return std::forward<_Tp>(__t) < std::forward<_Up>(__u);
+      }
+
+    using is_transparent = __is_transparent;
+  };
+
+  /// ranges::greater function object type.
+  struct greater
+  {
+    template<typename _Tp, typename _Up>
+      requires totally_ordered_with<_Tp, _Up>
+       || __detail::__less_builtin_ptr_cmp<_Up, _Tp>
+      constexpr bool
+      operator()(_Tp&& __t, _Up&& __u) const
+      noexcept(noexcept(std::declval<_Up>() < std::declval<_Tp>()))
+      { return less{}(std::forward<_Up>(__u), std::forward<_Tp>(__t)); }
+
+    using is_transparent = __is_transparent;
+  };
+
+  /// ranges::greater_equal function object type.
+  struct greater_equal
+  {
+    template<typename _Tp, typename _Up>
+      requires totally_ordered_with<_Tp, _Up>
+       || __detail::__less_builtin_ptr_cmp<_Tp, _Up>
+      constexpr bool
+      operator()(_Tp&& __t, _Up&& __u) const
+      noexcept(noexcept(std::declval<_Tp>() < std::declval<_Up>()))
+      { return !less{}(std::forward<_Tp>(__t), std::forward<_Up>(__u)); }
+
+    using is_transparent = __is_transparent;
+  };
+
+  /// ranges::less_equal function object type.
+  struct less_equal
+  {
+    template<typename _Tp, typename _Up>
+      requires totally_ordered_with<_Tp, _Up>
+       || __detail::__less_builtin_ptr_cmp<_Up, _Tp>
+      constexpr bool
+      operator()(_Tp&& __t, _Up&& __u) const
+      noexcept(noexcept(std::declval<_Up>() < std::declval<_Tp>()))
+      { return !less{}(std::forward<_Up>(__u), std::forward<_Tp>(__t)); }
+
+    using is_transparent = __is_transparent;
+  };
+
+} // namespace ranges
+#endif // library concepts
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+#endif // _RANGES_CMP_H
diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h
new file mode 100644 (file)
index 0000000..694ae79
--- /dev/null
@@ -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
index 5567184cf0eb86312fe4c47336afdf0f42f1bee8..1d6399acbed70e333929b034283ffbdc714a8ad0 100644 (file)
@@ -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)
index 407b93f3eb707c5bfc6d7d8551fbd376b11ff095..9bad692f2ad477a9af339aa448695523efd2a1f1 100644 (file)
@@ -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
 
index 1bf894dd57015232037f83f8e237557b6cf75db1..e7fa44936120c863c50709e1103494908d5912b1 100644 (file)
 
 #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.refinements]
-  // Defined in <bits/range_access.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 { }
-  };
+  // [range.access] customization point objects
+  // [range.req] range and view concepts
+  // [range.dangling] dangling iterator handling
+  // Defined in <bits/ranges_base.h>
 
-  template<range _Range>
-    using borrowed_iterator_t = conditional_t<borrowed_range<_Range>,
-                                             iterator_t<_Range>,
-                                             dangling>;
+  // [view.interface] View interface
+  // [range.subrange] Sub-ranges
+  // Defined in <bits/ranges_util.h>
 
-  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 { };
index 1cdc0589ddb1e5a97742155ea1d86f6b7456cb0a..fb349403c9ee0297afd1e35a6d0eefc340c3c1c8 100644 (file)
@@ -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)
index f05ff32d9e5f3792c95d31e87a8b088c46cbc103..32c51b2bbd4c4438d0f10fa21ac1af732815364e 100644 (file)
@@ -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>
 
index 5a6287ddd404dd652b5a57278a2c5cffa6a6ce99..b620be8cb982cda4598faa5e2eee39b87dd39211 100644 (file)
@@ -21,6 +21,7 @@
 #include <iterator>
 #include <algorithm>
 #include <vector>
+#include <ranges>
 #include <testsuite_hooks.h>
 
 namespace ranges = std::ranges;
index eaf4e9a187f32f441dfa81b5c9ebf52d189e65f9..0f6e9f57ebfca7781ca0d1ab3238a397c9066e13 100644 (file)
@@ -21,6 +21,7 @@
 #include <iterator>
 #include <algorithm>
 #include <deque>
+#include <ranges>
 #include <testsuite_hooks.h>
 
 namespace ranges = std::ranges;