From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1984) id EF4CA3B92C24; Fri, 17 Jul 2020 14:30:06 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org EF4CA3B92C24 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1594996206; bh=/1qjrYvNejiwI67/kd4dTFqsf5nqsUWJ95TUQSGAwxA=; h=From:To:Subject:Date:From; b=pZQw+Pp1NrgmzPYqD1AzG/TSFRal0flm5/TMAstDHPJIyz7orStBZ/j30kXY/w+q4 8uIf/w8X4pSDNuHSY0blW1kjI0oUlpPbyYTzdtQBvO014GedJL3z0icl8Qo55zqogq UuMDw6Cj0eim6or5K+51Z7Eov6sVTpT+pwnIRoyk= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Tamar Christina To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc(refs/vendors/ARM/heads/arm-struct-reorg-wip)] libstdc++: Add comparison operators to sequence containers X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/vendors/ARM/heads/arm-struct-reorg-wip X-Git-Oldrev: 3737ccc424c56a2cecff202dd79f88d28850eeb2 X-Git-Newrev: bd2420f8faaf4bb33310e82f7dd45c5e33476c87 Message-Id: <20200717143006.EF4CA3B92C24@sourceware.org> Date: Fri, 17 Jul 2020 14:30:06 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Jul 2020 14:30:07 -0000 https://gcc.gnu.org/g:bd2420f8faaf4bb33310e82f7dd45c5e33476c87 commit bd2420f8faaf4bb33310e82f7dd45c5e33476c87 Author: Jonathan Wakely Date: Fri Apr 17 23:41:04 2020 +0100 libstdc++: Add comparison operators to sequence containers Some more C++20 changes from P1614R2, "The Mothership has Landed". This implements <=> for sequence containers (and the __normal_iterator and _Pointer_adapter class templates). * include/bits/forward_list.h (forward_list): Define operator<=> and remove redundant comparison operators for C++20. * include/bits/stl_bvector.h (vector): Likewise. * include/bits/stl_deque.h (deque): Likewise. * include/bits/stl_iterator.h (__normal_iterator): Likewise. * include/bits/stl_list.h (list): Likewise. * include/bits/stl_vector.h (vector): Likewise. * include/debug/deque (__gnu_debug::deque): Likewise. * include/debug/forward_list (__gnu_debug::forward_list): Likewise. * include/debug/list (__gnu_debug::list): Likewise. * include/debug/safe_iterator.h (__gnu_debug::_Safe_iterator): Likewise. * include/debug/vector (__gnu_debug::vector): Likewise. * include/ext/pointer.h (__gnu_cxx::_Pointer_adapter): Define operator<=> for C++20. * testsuite/23_containers/deque/operators/cmp_c++20.cc: New test. * testsuite/23_containers/forward_list/cmp_c++20.cc: New test. * testsuite/23_containers/list/cmp_c++20.cc: New test. * testsuite/23_containers/vector/bool/cmp_c++20.cc: New test. * testsuite/23_containers/vector/cmp_c++20.cc: New test. Diff: --- libstdc++-v3/ChangeLog | 21 +++ libstdc++-v3/include/bits/forward_list.h | 28 +++- libstdc++-v3/include/bits/stl_bvector.h | 13 +- libstdc++-v3/include/bits/stl_deque.h | 57 +++++++- libstdc++-v3/include/bits/stl_iterator.h | 37 ++--- libstdc++-v3/include/bits/stl_list.h | 26 ++++ libstdc++-v3/include/bits/stl_vector.h | 25 ++++ libstdc++-v3/include/debug/deque | 7 + libstdc++-v3/include/debug/forward_list | 8 + libstdc++-v3/include/debug/list | 7 + libstdc++-v3/include/debug/safe_iterator.h | 21 +++ libstdc++-v3/include/debug/vector | 7 + libstdc++-v3/include/ext/pointer.h | 8 +- .../23_containers/deque/operators/cmp_c++20.cc | 161 +++++++++++++++++++++ .../23_containers/forward_list/cmp_c++20.cc | 138 ++++++++++++++++++ .../testsuite/23_containers/list/cmp_c++20.cc | 138 ++++++++++++++++++ .../23_containers/vector/bool/cmp_c++20.cc | 73 ++++++++++ .../testsuite/23_containers/vector/cmp_c++20.cc | 161 +++++++++++++++++++++ 18 files changed, 908 insertions(+), 28 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index d24c757d00a..de9323bebe0 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,26 @@ 2020-04-17 Jonathan Wakely + * include/bits/forward_list.h (forward_list): Define operator<=> and + remove redundant comparison operators for C++20. + * include/bits/stl_bvector.h (vector): Likewise. + * include/bits/stl_deque.h (deque): Likewise. + * include/bits/stl_iterator.h (__normal_iterator): Likewise. + * include/bits/stl_list.h (list): Likewise. + * include/bits/stl_vector.h (vector): Likewise. + * include/debug/deque (__gnu_debug::deque): Likewise. + * include/debug/forward_list (__gnu_debug::forward_list): Likewise. + * include/debug/list (__gnu_debug::list): Likewise. + * include/debug/safe_iterator.h (__gnu_debug::_Safe_iterator): + Likewise. + * include/debug/vector (__gnu_debug::vector): Likewise. + * include/ext/pointer.h (__gnu_cxx::_Pointer_adapter): Define + operator<=> for C++20. + * testsuite/23_containers/deque/operators/cmp_c++20.cc: New test. + * testsuite/23_containers/forward_list/cmp_c++20.cc: New test. + * testsuite/23_containers/list/cmp_c++20.cc: New test. + * testsuite/23_containers/vector/bool/cmp_c++20.cc: New test. + * testsuite/23_containers/vector/cmp_c++20.cc: New test. + * include/bits/basic_string.h (basic_string): Define operator<=> and remove redundant comparison operators for C++20. * include/bits/char_traits.h (__gnu_cxx::char_traits, char_traits): diff --git a/libstdc++-v3/include/bits/forward_list.h b/libstdc++-v3/include/bits/forward_list.h index b926d45f205..49b2a973718 100644 --- a/libstdc++-v3/include/bits/forward_list.h +++ b/libstdc++-v3/include/bits/forward_list.h @@ -180,13 +180,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER operator==(const _Self& __x, const _Self& __y) noexcept { return __x._M_node == __y._M_node; } - +#if __cpp_impl_three_way_comparison < 201907L /** * @brief Forward list iterator inequality comparison. */ friend bool operator!=(const _Self& __x, const _Self& __y) noexcept { return __x._M_node != __y._M_node; } +#endif _Self _M_next() const noexcept @@ -258,12 +259,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER operator==(const _Self& __x, const _Self& __y) noexcept { return __x._M_node == __y._M_node; } +#if __cpp_impl_three_way_comparison < 201907L /** * @brief Forward list const_iterator inequality comparison. */ friend bool operator!=(const _Self& __x, const _Self& __y) noexcept { return __x._M_node != __y._M_node; } +#endif _Self _M_next() const noexcept @@ -1426,6 +1429,28 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER operator==(const forward_list<_Tp, _Alloc>& __lx, const forward_list<_Tp, _Alloc>& __ly); +#if __cpp_lib_three_way_comparison + /** + * @brief Forward list ordering relation. + * @param __x A `forward_list`. + * @param __y A `forward_list` of the same type as `__x`. + * @return A value indicating whether `__x` is less than, equal to, + * greater than, or incomparable with `__y`. + * + * See `std::lexicographical_compare_three_way()` for how the determination + * is made. This operator is used to synthesize relational operators like + * `<` and `>=` etc. + */ + template + inline __detail::__synth3way_t<_Tp> + operator<=>(const forward_list<_Tp, _Alloc>& __x, + const forward_list<_Tp, _Alloc>& __y) + { + return std::lexicographical_compare_three_way(__x.begin(), __x.end(), + __y.begin(), __y.end(), + __detail::__synth3way); + } +#else /** * @brief Forward list ordering relation. * @param __lx A %forward_list. @@ -1472,6 +1497,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER operator<=(const forward_list<_Tp, _Alloc>& __lx, const forward_list<_Tp, _Alloc>& __ly) { return !(__ly < __lx); } +#endif // three-way comparison /// See std::forward_list::swap(). template diff --git a/libstdc++-v3/include/bits/stl_bvector.h b/libstdc++-v3/include/bits/stl_bvector.h index 1b16bc3b7d8..f245e52b25d 100644 --- a/libstdc++-v3/include/bits/stl_bvector.h +++ b/libstdc++-v3/include/bits/stl_bvector.h @@ -182,10 +182,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_offset = static_cast(__n); } - friend bool + friend _GLIBCXX20_CONSTEXPR bool operator==(const _Bit_iterator_base& __x, const _Bit_iterator_base& __y) { return __x._M_p == __y._M_p && __x._M_offset == __y._M_offset; } +#if __cpp_lib_three_way_comparison + friend constexpr strong_ordering + operator<=>(const _Bit_iterator_base& __x, const _Bit_iterator_base& __y) + noexcept + { + if (const auto __cmp = __x._M_p <=> __y._M_p; __cmp != 0) + return __cmp; + return __x._M_offset <=> __y._M_offset; + } +#else friend bool operator<(const _Bit_iterator_base& __x, const _Bit_iterator_base& __y) { @@ -208,6 +218,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER friend bool operator>=(const _Bit_iterator_base& __x, const _Bit_iterator_base& __y) { return !(__x < __y); } +#endif // three-way comparison friend ptrdiff_t operator-(const _Bit_iterator_base& __x, const _Bit_iterator_base& __y) diff --git a/libstdc++-v3/include/bits/stl_deque.h b/libstdc++-v3/include/bits/stl_deque.h index c1af637f67b..3959dd7899d 100644 --- a/libstdc++-v3/include/bits/stl_deque.h +++ b/libstdc++-v3/include/bits/stl_deque.h @@ -63,6 +63,9 @@ #include #include // for __is_bitwise_relocatable #endif +#if __cplusplus > 201703L +# include +#endif #include @@ -266,14 +269,24 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { return __x._M_cur == __y._M_cur; } // Note: we also provide overloads whose operands are of the same type in - // order to avoid ambiguous overload resolution when std::rel_ops operators - // are in scope (for additional details, see libstdc++/3628) + // order to avoid ambiguous overload resolution when std::rel_ops + // operators are in scope (for additional details, see libstdc++/3628) template friend bool operator==(const _Self& __x, - const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) _GLIBCXX_NOEXCEPT + const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) + _GLIBCXX_NOEXCEPT { return __x._M_cur == __y._M_cur; } +#if __cpp_lib_three_way_comparison + friend strong_ordering + operator<=>(const _Self& __x, const _Self& __y) noexcept + { + if (const auto __cmp = __x._M_node <=> __y._M_node; __cmp != 0) + return __cmp; + return __x._M_cur <=> __y._M_cur; + } +#else friend bool operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT { return !(__x == __y); } @@ -281,7 +294,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template friend bool operator!=(const _Self& __x, - const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) _GLIBCXX_NOEXCEPT + const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) + _GLIBCXX_NOEXCEPT { return !(__x == __y); } friend bool @@ -294,7 +308,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template friend bool operator<(const _Self& __x, - const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) _GLIBCXX_NOEXCEPT + const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) + _GLIBCXX_NOEXCEPT { return (__x._M_node == __y._M_node) ? (__x._M_cur < __y._M_cur) : (__x._M_node < __y._M_node); @@ -307,7 +322,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template friend bool operator>(const _Self& __x, - const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) _GLIBCXX_NOEXCEPT + const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) + _GLIBCXX_NOEXCEPT { return __y < __x; } friend bool @@ -317,7 +333,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template friend bool operator<=(const _Self& __x, - const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) _GLIBCXX_NOEXCEPT + const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) + _GLIBCXX_NOEXCEPT { return !(__y < __x); } friend bool @@ -327,8 +344,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template friend bool operator>=(const _Self& __x, - const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) _GLIBCXX_NOEXCEPT + const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) + _GLIBCXX_NOEXCEPT { return !(__x < __y); } +#endif // three-way comparison friend difference_type operator-(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT @@ -2223,6 +2242,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { return __x.size() == __y.size() && std::equal(__x.begin(), __x.end(), __y.begin()); } +#if __cpp_lib_three_way_comparison + /** + * @brief Deque ordering relation. + * @param __x A `deque`. + * @param __y A `deque` of the same type as `__x`. + * @return A value indicating whether `__x` is less than, equal to, + * greater than, or incomparable with `__y`. + * + * See `std::lexicographical_compare_three_way()` for how the determination + * is made. This operator is used to synthesize relational operators like + * `<` and `>=` etc. + */ + template + inline __detail::__synth3way_t<_Tp> + operator<=>(const deque<_Tp, _Alloc>& __x, const deque<_Tp, _Alloc>& __y) + { + return std::lexicographical_compare_three_way(__x.begin(), __x.end(), + __y.begin(), __y.end(), + __detail::__synth3way); + } +#else /** * @brief Deque ordering relation. * @param __x A %deque. @@ -2263,6 +2303,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER inline bool operator>=(const deque<_Tp, _Alloc>& __x, const deque<_Tp, _Alloc>& __y) { return !(__x < __y); } +#endif // three-way comparison /// See std::deque::swap(). template diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index d7972b71998..5bfdce6af2d 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -1037,7 +1037,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // provide overloads whose operands are of the same type. Can someone // remind me what generic programming is about? -- Gaby - // Forward iterator requirements +#if __cpp_lib_three_way_comparison + template + requires requires (_IteratorL __lhs, _IteratorR __rhs) + { { __lhs == __rhs } -> std::convertible_to; } + constexpr bool + operator==(const __normal_iterator<_IteratorL, _Container>& __lhs, + const __normal_iterator<_IteratorR, _Container>& __rhs) + noexcept(noexcept(__lhs.base() == __rhs.base())) + { return __lhs.base() == __rhs.base(); } + + template + constexpr auto + operator<=>(const __normal_iterator<_IteratorL, _Container>& __lhs, + const __normal_iterator<_IteratorR, _Container>& __rhs) + noexcept(noexcept(__lhs.base() <=> __rhs.base())) + -> decltype(__lhs.base() <=> __rhs.base()) + { return __lhs.base() <=> __rhs.base(); } +#else + // Forward iterator requirements template _GLIBCXX20_CONSTEXPR inline bool @@ -1072,11 +1090,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Random access iterator requirements template -#if __cplusplus > 201703L - constexpr auto -#else inline bool -#endif operator<(const __normal_iterator<_IteratorL, _Container>& __lhs, const __normal_iterator<_IteratorR, _Container>& __rhs) _GLIBCXX_NOEXCEPT @@ -1091,11 +1105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() < __rhs.base(); } template -#if __cplusplus > 201703L - constexpr auto -#else inline bool -#endif operator>(const __normal_iterator<_IteratorL, _Container>& __lhs, const __normal_iterator<_IteratorR, _Container>& __rhs) _GLIBCXX_NOEXCEPT @@ -1110,11 +1120,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() > __rhs.base(); } template -#if __cplusplus > 201703L - constexpr auto -#else inline bool -#endif operator<=(const __normal_iterator<_IteratorL, _Container>& __lhs, const __normal_iterator<_IteratorR, _Container>& __rhs) _GLIBCXX_NOEXCEPT @@ -1129,11 +1135,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() <= __rhs.base(); } template -#if __cplusplus > 201703L - constexpr auto -#else inline bool -#endif operator>=(const __normal_iterator<_IteratorL, _Container>& __lhs, const __normal_iterator<_IteratorR, _Container>& __rhs) _GLIBCXX_NOEXCEPT @@ -1146,6 +1148,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION const __normal_iterator<_Iterator, _Container>& __rhs) _GLIBCXX_NOEXCEPT { return __lhs.base() >= __rhs.base(); } +#endif // three-way comparison // _GLIBCXX_RESOLVE_LIB_DEFECTS // According to the resolution of DR179 not only the various comparison diff --git a/libstdc++-v3/include/bits/stl_list.h b/libstdc++-v3/include/bits/stl_list.h index 97b8fb549b5..e7135e3e7ed 100644 --- a/libstdc++-v3/include/bits/stl_list.h +++ b/libstdc++-v3/include/bits/stl_list.h @@ -247,9 +247,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER operator==(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT { return __x._M_node == __y._M_node; } +#if __cpp_impl_three_way_comparison < 201907L friend bool operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT { return __x._M_node != __y._M_node; } +#endif // The only member points to the %list element. __detail::_List_node_base* _M_node; @@ -331,9 +333,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER operator==(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT { return __x._M_node == __y._M_node; } +#if __cpp_impl_three_way_comparison < 201907L friend bool operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT { return __x._M_node != __y._M_node; } +#endif // The only member points to the %list element. const __detail::_List_node_base* _M_node; @@ -2009,6 +2013,27 @@ _GLIBCXX_END_NAMESPACE_CXX11 return __i1 == __end1 && __i2 == __end2; } +#if __cpp_lib_three_way_comparison +/** + * @brief List ordering relation. + * @param __x A `list`. + * @param __y A `list` of the same type as `__x`. + * @return A value indicating whether `__x` is less than, equal to, + * greater than, or incomparable with `__y`. + * + * See `std::lexicographical_compare_three_way()` for how the determination + * is made. This operator is used to synthesize relational operators like + * `<` and `>=` etc. + */ + template + inline __detail::__synth3way_t<_Tp> + operator<=>(const list<_Tp, _Alloc>& __x, const list<_Tp, _Alloc>& __y) + { + return std::lexicographical_compare_three_way(__x.begin(), __x.end(), + __y.begin(), __y.end(), + __detail::__synth3way); + } +#else /** * @brief List ordering relation. * @param __x A %list. @@ -2049,6 +2074,7 @@ _GLIBCXX_END_NAMESPACE_CXX11 inline bool operator>=(const list<_Tp, _Alloc>& __x, const list<_Tp, _Alloc>& __y) { return !(__x < __y); } +#endif // three-way comparison /// See std::list::swap(). template diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h index 14308a37770..d3f1b1fae5c 100644 --- a/libstdc++-v3/include/bits/stl_vector.h +++ b/libstdc++-v3/include/bits/stl_vector.h @@ -62,6 +62,9 @@ #if __cplusplus >= 201103L #include #endif +#if __cplusplus > 201703L +# include +#endif #include @@ -1890,6 +1893,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { return (__x.size() == __y.size() && std::equal(__x.begin(), __x.end(), __y.begin())); } +#if __cpp_lib_three_way_comparison + /** + * @brief Vector ordering relation. + * @param __x A `vector`. + * @param __y A `vector` of the same type as `__x`. + * @return A value indicating whether `__x` is less than, equal to, + * greater than, or incomparable with `__y`. + * + * See `std::lexicographical_compare_three_way()` for how the determination + * is made. This operator is used to synthesize relational operators like + * `<` and `>=` etc. + */ + template + inline __detail::__synth3way_t<_Tp> + operator<=>(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) + { + return std::lexicographical_compare_three_way(__x.begin(), __x.end(), + __y.begin(), __y.end(), + __detail::__synth3way); + } +#else /** * @brief Vector ordering relation. * @param __x A %vector. @@ -1930,6 +1954,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER inline bool operator>=(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) { return !(__x < __y); } +#endif // three-way comparison /// See std::vector::swap(). template diff --git a/libstdc++-v3/include/debug/deque b/libstdc++-v3/include/debug/deque index 8c6b4d14c2b..4d525bfc0aa 100644 --- a/libstdc++-v3/include/debug/deque +++ b/libstdc++-v3/include/debug/deque @@ -648,6 +648,12 @@ namespace __debug const deque<_Tp, _Alloc>& __rhs) { return __lhs._M_base() == __rhs._M_base(); } +#if __cpp_lib_three_way_comparison + template + constexpr __detail::__synth3way_t<_Tp> + operator<=>(const deque<_Tp, _Alloc>& __x, const deque<_Tp, _Alloc>& __y) + { return __x._M_base() <=> __y._M_base(); } +#else template inline bool operator!=(const deque<_Tp, _Alloc>& __lhs, @@ -677,6 +683,7 @@ namespace __debug operator>(const deque<_Tp, _Alloc>& __lhs, const deque<_Tp, _Alloc>& __rhs) { return __lhs._M_base() > __rhs._M_base(); } +#endif // three-way comparison template inline void diff --git a/libstdc++-v3/include/debug/forward_list b/libstdc++-v3/include/debug/forward_list index f0ff62c8cb1..2fd03e70499 100644 --- a/libstdc++-v3/include/debug/forward_list +++ b/libstdc++-v3/include/debug/forward_list @@ -838,6 +838,13 @@ namespace __debug const forward_list<_Tp, _Alloc>& __ly) { return __lx._M_base() == __ly._M_base(); } +#if __cpp_lib_three_way_comparison + template + constexpr __detail::__synth3way_t<_Tp> + operator<=>(const forward_list<_Tp, _Alloc>& __x, + const forward_list<_Tp, _Alloc>& __y) + { return __x._M_base() <=> __y._M_base(); } +#else template inline bool operator<(const forward_list<_Tp, _Alloc>& __lx, @@ -870,6 +877,7 @@ namespace __debug operator<=(const forward_list<_Tp, _Alloc>& __lx, const forward_list<_Tp, _Alloc>& __ly) { return !(__ly < __lx); } +#endif // three-way comparison /// See std::forward_list::swap(). template diff --git a/libstdc++-v3/include/debug/list b/libstdc++-v3/include/debug/list index ee54ef27e57..6dd85741f81 100644 --- a/libstdc++-v3/include/debug/list +++ b/libstdc++-v3/include/debug/list @@ -864,6 +864,12 @@ namespace __debug const list<_Tp, _Alloc>& __rhs) { return __lhs._M_base() == __rhs._M_base(); } +#if __cpp_lib_three_way_comparison + template + constexpr __detail::__synth3way_t<_Tp> + operator<=>(const list<_Tp, _Alloc>& __x, const list<_Tp, _Alloc>& __y) + { return __x._M_base() <=> __y._M_base(); } +#else template inline bool operator!=(const list<_Tp, _Alloc>& __lhs, @@ -893,6 +899,7 @@ namespace __debug operator>(const list<_Tp, _Alloc>& __lhs, const list<_Tp, _Alloc>& __rhs) { return __lhs._M_base() > __rhs._M_base(); } +#endif // three-way comparison template inline void diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h index f746cca5fb3..687b844fd75 100644 --- a/libstdc++-v3/include/debug/safe_iterator.h +++ b/libstdc++-v3/include/debug/safe_iterator.h @@ -35,6 +35,9 @@ #include #include #include +#if __cplusplus > 201703L +# include +#endif #define _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs, _BadMsgId, _DiffMsgId) \ _GLIBCXX_DEBUG_VERIFY(!_Lhs._M_singular() && !_Rhs._M_singular(), \ @@ -469,6 +472,7 @@ namespace __gnu_debug return __lhs.base() == __rhs.base(); } +#if ! __cpp_lib_three_way_comparison friend bool operator!=(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT { @@ -485,6 +489,7 @@ namespace __gnu_debug _GLIBCXX_DEBUG_VERIFY_EQ_OPERANDS(__lhs, __rhs); return __lhs.base() != __rhs.base(); } +#endif // three-way comparison }; template @@ -805,6 +810,21 @@ namespace __gnu_debug return *this; } +#if __cpp_lib_three_way_comparison + friend auto + operator<=>(const _Self& __lhs, const _Self& __rhs) noexcept + { + _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs); + return __lhs.base() <=> __rhs.base(); + } + + friend auto + operator<=>(const _Self& __lhs, const _OtherSelf& __rhs) noexcept + { + _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs); + return __lhs.base() <=> __rhs.base(); + } +#else friend bool operator<(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT { @@ -860,6 +880,7 @@ namespace __gnu_debug _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs); return __lhs.base() >= __rhs.base(); } +#endif // three-way comparison // _GLIBCXX_RESOLVE_LIB_DEFECTS // According to the resolution of DR179 not only the various comparison diff --git a/libstdc++-v3/include/debug/vector b/libstdc++-v3/include/debug/vector index 96772f72643..4c08ab61ce8 100644 --- a/libstdc++-v3/include/debug/vector +++ b/libstdc++-v3/include/debug/vector @@ -731,6 +731,12 @@ namespace __debug const vector<_Tp, _Alloc>& __rhs) { return __lhs._M_base() == __rhs._M_base(); } +#if __cpp_lib_three_way_comparison + template + constexpr __detail::__synth3way_t<_Tp> + operator<=>(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) + { return __x._M_base() <=> __y._M_base(); } +#else template inline bool operator!=(const vector<_Tp, _Alloc>& __lhs, @@ -760,6 +766,7 @@ namespace __debug operator>(const vector<_Tp, _Alloc>& __lhs, const vector<_Tp, _Alloc>& __rhs) { return __lhs._M_base() > __rhs._M_base(); } +#endif // three-way comparison template inline void diff --git a/libstdc++-v3/include/ext/pointer.h b/libstdc++-v3/include/ext/pointer.h index aef622e2e23..a0ade4a677e 100644 --- a/libstdc++-v3/include/ext/pointer.h +++ b/libstdc++-v3/include/ext/pointer.h @@ -479,7 +479,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Storage_policy::set(_Storage_policy::get() - 1); return __tmp; } - + +#if __cpp_lib_three_way_comparison + friend std::strong_ordering + operator<=>(const _Pointer_adapter& __lhs, const _Pointer_adapter& __rhs) + noexcept + { return __lhs.get() <=> __rhs.get(); } +#endif }; // class _Pointer_adapter diff --git a/libstdc++-v3/testsuite/23_containers/deque/operators/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/deque/operators/cmp_c++20.cc new file mode 100644 index 00000000000..77668fcd1f6 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/deque/operators/cmp_c++20.cc @@ -0,0 +1,161 @@ +// Copyright (C) 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. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +void +test01() +{ + std::deque c1{ 1, 2, 3 }, c2{ 1, 2, 3, 4 }, c3{ 1, 2, 4 }; + VERIFY( c1 == c1 ); + VERIFY( std::is_eq(c1 <=> c1) ); + VERIFY( c1 < c2 ); + VERIFY( std::is_lt(c1 <=> c2) ); + VERIFY( c1 < c3 ); + VERIFY( std::is_lt(c1 <=> c3) ); + VERIFY( c2 < c3 ); + VERIFY( std::is_lt(c2 <=> c3) ); + + static_assert( std::totally_ordered> ); + + static_assert( std::three_way_comparable, + std::strong_ordering> ); + static_assert( ! std::three_way_comparable, + std::strong_ordering> ); + static_assert( ! std::three_way_comparable, + std::weak_ordering> ); + static_assert( std::three_way_comparable, + std::partial_ordering> ); + + struct E + { + bool operator==(E) { return true; } + }; + static_assert( ! std::totally_ordered> ); + static_assert( ! std::three_way_comparable ); + static_assert( ! std::three_way_comparable> ); +} + +void +test02() +{ + struct W + { + int value = 0; + + bool operator==(W rhs) const noexcept + { return (value | 1) == (rhs.value | 1); } + + std::weak_ordering + operator<=>(W rhs) const noexcept + { return (value | 1) <=> (rhs.value | 1); } + }; + + static_assert( std::totally_ordered> ); + + std::deque c1{ {1}, {2}, {3} }, c2{ {0}, {3}, {3} }; + static_assert( std::same_as c1), std::weak_ordering> ); + VERIFY( c1 == c2 ); + VERIFY( std::is_eq(c1 <=> c2) ); +} + +void +test03() +{ + struct P + { + int value = 0; + + bool operator==(P rhs) const noexcept + { + if (value < 0 || rhs.value < 0) + return false; + return value == rhs.value; + } + + std::partial_ordering + operator<=>(P rhs) const noexcept + { + if (value < 0 || rhs.value < 0) + return std::partial_ordering::unordered; + return value <=> rhs.value; + } + }; + + static_assert( std::totally_ordered> ); + + std::deque

c{ {1}, {2}, {-3} }; + static_assert( std::three_way_comparable

); + static_assert( std::same_as c), std::partial_ordering> ); + VERIFY( (c <=> c) == std::partial_ordering::unordered ); +} + +void +test04() +{ + struct L + { + int value = 0; + + bool operator<(L rhs) const noexcept { return value < rhs.value; } + }; + + static_assert( std::totally_ordered> ); + + std::deque c{ {1}, {2}, {3} }, d{ {1}, {2}, {3}, {4} }; + static_assert( std::same_as c), std::weak_ordering> ); + VERIFY( std::is_lt(c <=> d) ); +} + +void +test05() +{ + // deque iterators are random access, so should support <=> + + std::deque c{ 1, 2, 3 }; + VERIFY( c.begin() == c.cbegin() ); + VERIFY( std::is_eq(c.begin() <=> c.cbegin()) ); + + VERIFY( c.begin() < c.end() ); + VERIFY( std::is_lt(c.begin() <=> c.end()) ); + + VERIFY( c.begin() < c.cend() ); + VERIFY( std::is_lt(c.begin() <=> c.cend()) ); + + VERIFY( c.crbegin() == c.rbegin() ); + VERIFY( std::is_eq(c.crbegin() <=> c.rbegin()) ); + + VERIFY( c.rend() > c.rbegin() ); + VERIFY( std::is_gt(c.rend() <=> c.rbegin()) ); + + static_assert( std::same_as c.begin()), + std::strong_ordering> ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); +} diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/forward_list/cmp_c++20.cc new file mode 100644 index 00000000000..5a26d497ea6 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/forward_list/cmp_c++20.cc @@ -0,0 +1,138 @@ +// Copyright (C) 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. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +void +test01() +{ + std::forward_list c1{ 1, 2, 3 }, c2{ 1, 2, 3, 4 }, c3{ 1, 2, 4 }; + VERIFY( c1 == c1 ); + VERIFY( std::is_eq(c1 <=> c1) ); + VERIFY( c1 < c2 ); + VERIFY( std::is_lt(c1 <=> c2) ); + VERIFY( c1 < c3 ); + VERIFY( std::is_lt(c1 <=> c3) ); + VERIFY( c2 < c3 ); + VERIFY( std::is_lt(c2 <=> c3) ); + + static_assert( std::totally_ordered> ); + + static_assert( std::three_way_comparable, + std::strong_ordering> ); + static_assert( ! std::three_way_comparable, + std::strong_ordering> ); + static_assert( ! std::three_way_comparable, + std::weak_ordering> ); + static_assert( std::three_way_comparable, + std::partial_ordering> ); + + struct E + { + bool operator==(E) { return true; } + }; + static_assert( ! std::totally_ordered> ); + static_assert( ! std::three_way_comparable ); + static_assert( ! std::three_way_comparable> ); +} + +void +test02() +{ + struct W + { + int value = 0; + + bool operator==(W rhs) const noexcept + { return (value | 1) == (rhs.value | 1); } + + std::weak_ordering + operator<=>(W rhs) const noexcept + { return (value | 1) <=> (rhs.value | 1); } + }; + + static_assert( std::totally_ordered> ); + + std::forward_list c1{ {1}, {2}, {3} }, c2{ {0}, {3}, {3} }; + static_assert( std::same_as c1), std::weak_ordering> ); + VERIFY( c1 == c2 ); + VERIFY( std::is_eq(c1 <=> c2) ); +} + +void +test03() +{ + struct P + { + int value = 0; + + bool operator==(P rhs) const noexcept + { + if (value < 0 || rhs.value < 0) + return false; + return value == rhs.value; + } + + std::partial_ordering + operator<=>(P rhs) const noexcept + { + if (value < 0 || rhs.value < 0) + return std::partial_ordering::unordered; + return value <=> rhs.value; + } + }; + + static_assert( std::totally_ordered> ); + + std::forward_list

c{ {1}, {2}, {-3} }; + static_assert( std::three_way_comparable

); + static_assert( std::same_as c), std::partial_ordering> ); + VERIFY( (c <=> c) == std::partial_ordering::unordered ); +} + +void +test04() +{ + struct L + { + int value = 0; + + bool operator<(L rhs) const noexcept { return value < rhs.value; } + }; + + static_assert( std::totally_ordered> ); + + std::forward_list c{ {1}, {2}, {3} }, d{ {1}, {2}, {3}, {4} }; + static_assert( std::same_as c), std::weak_ordering> ); + VERIFY( std::is_lt(c <=> d) ); +} + +static_assert( ! std::totally_ordered::iterator> ); +static_assert( ! std::three_way_comparable::iterator> ); + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/23_containers/list/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/list/cmp_c++20.cc new file mode 100644 index 00000000000..a5b9f8f5459 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/list/cmp_c++20.cc @@ -0,0 +1,138 @@ +// Copyright (C) 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. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +void +test01() +{ + std::list c1{ 1, 2, 3 }, c2{ 1, 2, 3, 4 }, c3{ 1, 2, 4 }; + VERIFY( c1 == c1 ); + VERIFY( std::is_eq(c1 <=> c1) ); + VERIFY( c1 < c2 ); + VERIFY( std::is_lt(c1 <=> c2) ); + VERIFY( c1 < c3 ); + VERIFY( std::is_lt(c1 <=> c3) ); + VERIFY( c2 < c3 ); + VERIFY( std::is_lt(c2 <=> c3) ); + + static_assert( std::totally_ordered> ); + + static_assert( std::three_way_comparable, + std::strong_ordering> ); + static_assert( ! std::three_way_comparable, + std::strong_ordering> ); + static_assert( ! std::three_way_comparable, + std::weak_ordering> ); + static_assert( std::three_way_comparable, + std::partial_ordering> ); + + struct E + { + bool operator==(E) { return true; } + }; + static_assert( ! std::totally_ordered> ); + static_assert( ! std::three_way_comparable ); + static_assert( ! std::three_way_comparable> ); +} + +void +test02() +{ + struct W + { + int value = 0; + + bool operator==(W rhs) const noexcept + { return (value | 1) == (rhs.value | 1); } + + std::weak_ordering + operator<=>(W rhs) const noexcept + { return (value | 1) <=> (rhs.value | 1); } + }; + + static_assert( std::totally_ordered> ); + + std::list c1{ {1}, {2}, {3} }, c2{ {0}, {3}, {3} }; + static_assert( std::same_as c1), std::weak_ordering> ); + VERIFY( c1 == c2 ); + VERIFY( std::is_eq(c1 <=> c2) ); +} + +void +test03() +{ + struct P + { + int value = 0; + + bool operator==(P rhs) const noexcept + { + if (value < 0 || rhs.value < 0) + return false; + return value == rhs.value; + } + + std::partial_ordering + operator<=>(P rhs) const noexcept + { + if (value < 0 || rhs.value < 0) + return std::partial_ordering::unordered; + return value <=> rhs.value; + } + }; + + static_assert( std::totally_ordered> ); + + std::list

c{ {1}, {2}, {-3} }; + static_assert( std::three_way_comparable

); + static_assert( std::same_as c), std::partial_ordering> ); + VERIFY( (c <=> c) == std::partial_ordering::unordered ); +} + +void +test04() +{ + struct L + { + int value = 0; + + bool operator<(L rhs) const noexcept { return value < rhs.value; } + }; + + static_assert( std::totally_ordered> ); + + std::list c{ {1}, {2}, {3} }, d{ {1}, {2}, {3}, {4} }; + static_assert( std::same_as c), std::weak_ordering> ); + VERIFY( std::is_lt(c <=> d) ); +} + +static_assert( ! std::totally_ordered::iterator> ); +static_assert( ! std::three_way_comparable::iterator> ); + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc new file mode 100644 index 00000000000..a586ab65cd7 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc @@ -0,0 +1,73 @@ +// Copyright (C) 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. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +void +test01() +{ + std::vector c1{ 1, 0, 1 }, c2{ 1, 0, 1, 0 }, c3{ 1, 1, 1 }; + VERIFY( c1 == c1 ); + VERIFY( std::is_eq(c1 <=> c1) ); + VERIFY( c1 < c2 ); + VERIFY( std::is_lt(c1 <=> c2) ); + VERIFY( c1 < c3 ); + VERIFY( std::is_lt(c1 <=> c3) ); + VERIFY( c2 < c3 ); + VERIFY( std::is_lt(c2 <=> c3) ); + + static_assert( std::totally_ordered> ); + + static_assert( std::three_way_comparable, + std::strong_ordering> ); +} + +void +test05() +{ + // vector iterators are random access, so should support <=> + + std::vector c{ 1, 1, 1 }; + VERIFY( c.begin() == c.cbegin() ); + VERIFY( std::is_eq(c.begin() <=> c.cbegin()) ); + + VERIFY( c.begin() < c.end() ); + VERIFY( std::is_lt(c.begin() <=> c.end()) ); + + VERIFY( c.begin() < c.cend() ); + VERIFY( std::is_lt(c.begin() <=> c.cend()) ); + + VERIFY( c.crbegin() == c.rbegin() ); + VERIFY( std::is_eq(c.crbegin() <=> c.rbegin()) ); + + VERIFY( c.rend() > c.rbegin() ); + VERIFY( std::is_gt(c.rend() <=> c.rbegin()) ); + + static_assert( std::same_as c.begin()), + std::strong_ordering> ); +} + +int +main() +{ + test01(); + test05(); +} diff --git a/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc new file mode 100644 index 00000000000..ca6a4f43e22 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc @@ -0,0 +1,161 @@ +// Copyright (C) 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. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +void +test01() +{ + std::vector c1{ 1, 2, 3 }, c2{ 1, 2, 3, 4 }, c3{ 1, 2, 4 }; + VERIFY( c1 == c1 ); + VERIFY( std::is_eq(c1 <=> c1) ); + VERIFY( c1 < c2 ); + VERIFY( std::is_lt(c1 <=> c2) ); + VERIFY( c1 < c3 ); + VERIFY( std::is_lt(c1 <=> c3) ); + VERIFY( c2 < c3 ); + VERIFY( std::is_lt(c2 <=> c3) ); + + static_assert( std::totally_ordered> ); + + static_assert( std::three_way_comparable, + std::strong_ordering> ); + static_assert( ! std::three_way_comparable, + std::strong_ordering> ); + static_assert( ! std::three_way_comparable, + std::weak_ordering> ); + static_assert( std::three_way_comparable, + std::partial_ordering> ); + + struct E + { + bool operator==(E) { return true; } + }; + static_assert( ! std::totally_ordered> ); + static_assert( ! std::three_way_comparable ); + static_assert( ! std::three_way_comparable> ); +} + +void +test02() +{ + struct W + { + int value = 0; + + bool operator==(W rhs) const noexcept + { return (value | 1) == (rhs.value | 1); } + + std::weak_ordering + operator<=>(W rhs) const noexcept + { return (value | 1) <=> (rhs.value | 1); } + }; + + static_assert( std::totally_ordered> ); + + std::vector c1{ {1}, {2}, {3} }, c2{ {0}, {3}, {3} }; + static_assert( std::same_as c1), std::weak_ordering> ); + VERIFY( c1 == c2 ); + VERIFY( std::is_eq(c1 <=> c2) ); +} + +void +test03() +{ + struct P + { + int value = 0; + + bool operator==(P rhs) const noexcept + { + if (value < 0 || rhs.value < 0) + return false; + return value == rhs.value; + } + + std::partial_ordering + operator<=>(P rhs) const noexcept + { + if (value < 0 || rhs.value < 0) + return std::partial_ordering::unordered; + return value <=> rhs.value; + } + }; + + static_assert( std::totally_ordered> ); + + std::vector

c{ {1}, {2}, {-3} }; + static_assert( std::three_way_comparable

); + static_assert( std::same_as c), std::partial_ordering> ); + VERIFY( (c <=> c) == std::partial_ordering::unordered ); +} + +void +test04() +{ + struct L + { + int value = 0; + + bool operator<(L rhs) const noexcept { return value < rhs.value; } + }; + + static_assert( std::totally_ordered> ); + + std::vector c{ {1}, {2}, {3} }, d{ {1}, {2}, {3}, {4} }; + static_assert( std::same_as c), std::weak_ordering> ); + VERIFY( std::is_lt(c <=> d) ); +} + +void +test05() +{ + // vector iterators are random access, so should support <=> + + std::vector c{ 1, 2, 3 }; + VERIFY( c.begin() == c.cbegin() ); + VERIFY( std::is_eq(c.begin() <=> c.cbegin()) ); + + VERIFY( c.begin() < c.end() ); + VERIFY( std::is_lt(c.begin() <=> c.end()) ); + + VERIFY( c.begin() < c.cend() ); + VERIFY( std::is_lt(c.begin() <=> c.cend()) ); + + VERIFY( c.crbegin() == c.rbegin() ); + VERIFY( std::is_eq(c.crbegin() <=> c.rbegin()) ); + + VERIFY( c.rend() > c.rbegin() ); + VERIFY( std::is_gt(c.rend() <=> c.rbegin()) ); + + static_assert( std::same_as c.begin()), + std::strong_ordering> ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); +}