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<bool, Alloc>): 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.
This commit is contained in:
Jonathan Wakely 2020-04-17 23:41:04 +01:00
parent 3737ccc424
commit bd2420f8fa
18 changed files with 908 additions and 28 deletions

View File

@ -1,5 +1,26 @@
2020-04-17 Jonathan Wakely <jwakely@redhat.com>
* include/bits/forward_list.h (forward_list): Define operator<=> and
remove redundant comparison operators for C++20.
* include/bits/stl_bvector.h (vector<bool, Alloc>): 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):

View File

@ -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<typename _Tp, typename _Alloc>
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<typename _Tp, typename _Alloc>

View File

@ -182,10 +182,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
_M_offset = static_cast<unsigned int>(__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)

View File

@ -63,6 +63,9 @@
#include <initializer_list>
#include <bits/stl_uninitialized.h> // for __is_bitwise_relocatable
#endif
#if __cplusplus > 201703L
# include <compare>
#endif
#include <debug/assertions.h>
@ -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<typename _RefR, typename _PtrR>
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<typename _RefR, typename _PtrR>
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<typename _RefR, typename _PtrR>
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<typename _RefR, typename _PtrR>
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<typename _RefR, typename _PtrR>
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<typename _RefR, typename _PtrR>
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<typename _Tp, typename _Alloc>
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<typename _Tp, typename _Alloc>

View File

@ -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<typename _IteratorL, typename _IteratorR, typename _Container>
requires requires (_IteratorL __lhs, _IteratorR __rhs)
{ { __lhs == __rhs } -> std::convertible_to<bool>; }
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<typename _IteratorL, typename _IteratorR, typename _Container>
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<typename _IteratorL, typename _IteratorR, typename _Container>
_GLIBCXX20_CONSTEXPR
inline bool
@ -1072,11 +1090,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Random access iterator requirements
template<typename _IteratorL, typename _IteratorR, typename _Container>
#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<typename _IteratorL, typename _IteratorR, typename _Container>
#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<typename _IteratorL, typename _IteratorR, typename _Container>
#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<typename _IteratorL, typename _IteratorR, typename _Container>
#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

View File

@ -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<typename _Tp, typename _Alloc>
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<typename _Tp, typename _Alloc>

View File

@ -62,6 +62,9 @@
#if __cplusplus >= 201103L
#include <initializer_list>
#endif
#if __cplusplus > 201703L
# include <compare>
#endif
#include <debug/assertions.h>
@ -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<typename _Tp, typename _Alloc>
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<typename _Tp, typename _Alloc>

View File

@ -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<typename _Tp, typename _Alloc>
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<typename _Tp, typename _Alloc>
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<typename _Tp, typename _Alloc>
inline void

View File

@ -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<typename _Tp, typename _Alloc>
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<typename _Tp, typename _Alloc>
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<typename _Tp, typename _Alloc>

View File

@ -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<typename _Tp, typename _Alloc>
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<typename _Tp, typename _Alloc>
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<typename _Tp, typename _Alloc>
inline void

View File

@ -35,6 +35,9 @@
#include <debug/safe_base.h>
#include <bits/stl_pair.h>
#include <ext/type_traits.h>
#if __cplusplus > 201703L
# include <compare>
#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<typename _Iterator, typename _Sequence>
@ -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

View File

@ -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<typename _Tp, typename _Alloc>
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<typename _Tp, typename _Alloc>
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<typename _Tp, typename _Alloc>
inline void

View File

@ -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

View File

@ -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
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
#include <deque>
#include <testsuite_hooks.h>
void
test01()
{
std::deque<int> 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<std::deque<int>> );
static_assert( std::three_way_comparable<std::deque<int>,
std::strong_ordering> );
static_assert( ! std::three_way_comparable<std::deque<float>,
std::strong_ordering> );
static_assert( ! std::three_way_comparable<std::deque<float>,
std::weak_ordering> );
static_assert( std::three_way_comparable<std::deque<float>,
std::partial_ordering> );
struct E
{
bool operator==(E) { return true; }
};
static_assert( ! std::totally_ordered<std::deque<E>> );
static_assert( ! std::three_way_comparable<E> );
static_assert( ! std::three_way_comparable<std::deque<E>> );
}
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<W>> );
std::deque<W> c1{ {1}, {2}, {3} }, c2{ {0}, {3}, {3} };
static_assert( std::same_as<decltype(c1 <=> 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<P>> );
std::deque<P> c{ {1}, {2}, {-3} };
static_assert( std::three_way_comparable<P> );
static_assert( std::same_as<decltype(c <=> 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<L>> );
std::deque<L> c{ {1}, {2}, {3} }, d{ {1}, {2}, {3}, {4} };
static_assert( std::same_as<decltype(c <=> c), std::weak_ordering> );
VERIFY( std::is_lt(c <=> d) );
}
void
test05()
{
// deque iterators are random access, so should support <=>
std::deque<int> 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<decltype(c.begin() <=> c.begin()),
std::strong_ordering> );
}
int
main()
{
test01();
test02();
test03();
test04();
test05();
}

View File

@ -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
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
#include <forward_list>
#include <testsuite_hooks.h>
void
test01()
{
std::forward_list<int> 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<std::forward_list<int>> );
static_assert( std::three_way_comparable<std::forward_list<int>,
std::strong_ordering> );
static_assert( ! std::three_way_comparable<std::forward_list<float>,
std::strong_ordering> );
static_assert( ! std::three_way_comparable<std::forward_list<float>,
std::weak_ordering> );
static_assert( std::three_way_comparable<std::forward_list<float>,
std::partial_ordering> );
struct E
{
bool operator==(E) { return true; }
};
static_assert( ! std::totally_ordered<std::forward_list<E>> );
static_assert( ! std::three_way_comparable<E> );
static_assert( ! std::three_way_comparable<std::forward_list<E>> );
}
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<W>> );
std::forward_list<W> c1{ {1}, {2}, {3} }, c2{ {0}, {3}, {3} };
static_assert( std::same_as<decltype(c1 <=> 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<P>> );
std::forward_list<P> c{ {1}, {2}, {-3} };
static_assert( std::three_way_comparable<P> );
static_assert( std::same_as<decltype(c <=> 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<L>> );
std::forward_list<L> c{ {1}, {2}, {3} }, d{ {1}, {2}, {3}, {4} };
static_assert( std::same_as<decltype(c <=> c), std::weak_ordering> );
VERIFY( std::is_lt(c <=> d) );
}
static_assert( ! std::totally_ordered<std::forward_list<int>::iterator> );
static_assert( ! std::three_way_comparable<std::forward_list<int>::iterator> );
int
main()
{
test01();
test02();
test03();
test04();
}

View File

@ -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
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
#include <list>
#include <testsuite_hooks.h>
void
test01()
{
std::list<int> 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<std::list<int>> );
static_assert( std::three_way_comparable<std::list<int>,
std::strong_ordering> );
static_assert( ! std::three_way_comparable<std::list<float>,
std::strong_ordering> );
static_assert( ! std::three_way_comparable<std::list<float>,
std::weak_ordering> );
static_assert( std::three_way_comparable<std::list<float>,
std::partial_ordering> );
struct E
{
bool operator==(E) { return true; }
};
static_assert( ! std::totally_ordered<std::list<E>> );
static_assert( ! std::three_way_comparable<E> );
static_assert( ! std::three_way_comparable<std::list<E>> );
}
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<W>> );
std::list<W> c1{ {1}, {2}, {3} }, c2{ {0}, {3}, {3} };
static_assert( std::same_as<decltype(c1 <=> 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<P>> );
std::list<P> c{ {1}, {2}, {-3} };
static_assert( std::three_way_comparable<P> );
static_assert( std::same_as<decltype(c <=> 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<L>> );
std::list<L> c{ {1}, {2}, {3} }, d{ {1}, {2}, {3}, {4} };
static_assert( std::same_as<decltype(c <=> c), std::weak_ordering> );
VERIFY( std::is_lt(c <=> d) );
}
static_assert( ! std::totally_ordered<std::list<int>::iterator> );
static_assert( ! std::three_way_comparable<std::list<int>::iterator> );
int
main()
{
test01();
test02();
test03();
test04();
}

View File

@ -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
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
#include <vector>
#include <testsuite_hooks.h>
void
test01()
{
std::vector<bool> 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<std::vector<bool>> );
static_assert( std::three_way_comparable<std::vector<bool>,
std::strong_ordering> );
}
void
test05()
{
// vector<bool> iterators are random access, so should support <=>
std::vector<bool> 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<decltype(c.begin() <=> c.begin()),
std::strong_ordering> );
}
int
main()
{
test01();
test05();
}

View File

@ -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
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
#include <vector>
#include <testsuite_hooks.h>
void
test01()
{
std::vector<int> 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<std::vector<int>> );
static_assert( std::three_way_comparable<std::vector<int>,
std::strong_ordering> );
static_assert( ! std::three_way_comparable<std::vector<float>,
std::strong_ordering> );
static_assert( ! std::three_way_comparable<std::vector<float>,
std::weak_ordering> );
static_assert( std::three_way_comparable<std::vector<float>,
std::partial_ordering> );
struct E
{
bool operator==(E) { return true; }
};
static_assert( ! std::totally_ordered<std::vector<E>> );
static_assert( ! std::three_way_comparable<E> );
static_assert( ! std::three_way_comparable<std::vector<E>> );
}
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<W>> );
std::vector<W> c1{ {1}, {2}, {3} }, c2{ {0}, {3}, {3} };
static_assert( std::same_as<decltype(c1 <=> 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<P>> );
std::vector<P> c{ {1}, {2}, {-3} };
static_assert( std::three_way_comparable<P> );
static_assert( std::same_as<decltype(c <=> 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<L>> );
std::vector<L> c{ {1}, {2}, {3} }, d{ {1}, {2}, {3}, {4} };
static_assert( std::same_as<decltype(c <=> c), std::weak_ordering> );
VERIFY( std::is_lt(c <=> d) );
}
void
test05()
{
// vector iterators are random access, so should support <=>
std::vector<int> 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<decltype(c.begin() <=> c.begin()),
std::strong_ordering> );
}
int
main()
{
test01();
test02();
test03();
test04();
test05();
}