From 3a4cc6281b56c52136cc755e46776c025114d865 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Thu, 5 Dec 2019 00:42:06 +0000 Subject: [PATCH] libstdc++: Implement spaceship for std::array (P1614R2) As done for std::pair, this defines operator<=> as a non-member function template and does not alter operator==, as expected to be proposed as the resolution to an unpublished LWG issue. Instead of calling std::lexicographical_compare_three_way the <=> overload is implemented by hand to take advantage of the fact the element types and array sizes are known to be the same. * include/bits/cpp_type_traits.h (__is_byte): Add specialization. * include/std/array (operator<=>): Likewise. * testsuite/23_containers/array/comparison_operators/constexpr.cc: Test three-way comparisons and arrays of unsigned char. * testsuite/23_containers/array/tuple_interface/get_neg.cc: Adjust dg-error line numbers. From-SVN: r278981 --- libstdc++-v3/ChangeLog | 10 ++++++++++ libstdc++-v3/include/bits/cpp_type_traits.h | 9 +++++++++ libstdc++-v3/include/std/array | 20 +++++++++++++++++++ .../array/comparison_operators/constexpr.cc | 20 +++++++++++++++++++ .../array/tuple_interface/get_neg.cc | 6 +++--- 5 files changed, 62 insertions(+), 3 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 50f506cc38e..ec5c0efa2b8 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,13 @@ +2019-12-05 Jonathan Wakely + + * include/bits/cpp_type_traits.h (__is_byte): Add + specialization. + * include/std/array (operator<=>): Likewise. + * testsuite/23_containers/array/comparison_operators/constexpr.cc: + Test three-way comparisons and arrays of unsigned char. + * testsuite/23_containers/array/tuple_interface/get_neg.cc: Adjust + dg-error line numbers. + 2019-12-03 Jonathan Wakely * include/bits/stl_pair.h [__cpp_lib_three_way_comparison] diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h index 3e165c77707..28180bfc06d 100644 --- a/libstdc++-v3/include/bits/cpp_type_traits.h +++ b/libstdc++-v3/include/bits/cpp_type_traits.h @@ -411,6 +411,15 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3) }; #endif // C++17 +#ifdef _GLIBCXX_USE_CHAR8_T + template<> + struct __is_byte + { + enum { __value = 1 }; + typedef __true_type __type; + }; +#endif + // // Move iterator type // diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array index 9ad1e652b6c..ad3f6518da2 100644 --- a/libstdc++-v3/include/std/array +++ b/libstdc++-v3/include/std/array @@ -253,6 +253,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER operator==(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two) { return std::equal(__one.begin(), __one.end(), __two.begin()); } +#if __cpp_lib_three_way_comparison && __cpp_lib_concepts + template + constexpr __detail::__synth3way_t<_Tp> + operator<=>(const array<_Tp, _Nm>& __a, const array<_Tp, _Nm>& __b) + { + if constexpr (_Nm && __is_byte<_Tp>::__value) + return __builtin_memcmp(__a.data(), __b.data(), _Nm) <=> 0; + else + { + for (size_t __i = 0; __i < _Nm; ++__i) + { + auto __c = __detail::__synth3way(__a[__i], __b[__i]); + if (__c != 0) + return __c; + } + } + return strong_ordering::equal; + } +#else template _GLIBCXX20_CONSTEXPR inline bool @@ -285,6 +304,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER inline bool operator>=(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two) { return !(__one < __two); } +#endif // three_way_comparison && concepts // Specialized algorithms. template diff --git a/libstdc++-v3/testsuite/23_containers/array/comparison_operators/constexpr.cc b/libstdc++-v3/testsuite/23_containers/array/comparison_operators/constexpr.cc index 8655a9bede2..91a8a24b9e5 100644 --- a/libstdc++-v3/testsuite/23_containers/array/comparison_operators/constexpr.cc +++ b/libstdc++-v3/testsuite/23_containers/array/comparison_operators/constexpr.cc @@ -31,3 +31,23 @@ static_assert(a1 < a3); static_assert(a4 > a1); static_assert(a1 <= a3); static_assert(a4 >= a1); +static_assert(std::is_eq(a1 <=> a1)); +static_assert(std::is_neq(a1 <=> a2)); +static_assert(std::is_lt(a1 <=> a3)); +static_assert(std::is_gt(a4 <=> a1)); + +constexpr std::array a5{{1, 2, 3}}; +constexpr std::array a6{{4, 5, 6}}; +constexpr std::array a7{{1, 2, 4}}; +constexpr std::array a8{{1, 3, 3}}; + +static_assert(a5 == a5); +static_assert(a5 != a6); +static_assert(a5 < a7); +static_assert(a8 > a5); +static_assert(a5 <= a7); +static_assert(a8 >= a5); +static_assert(std::is_eq(a5 <=> a5)); +static_assert(std::is_neq(a5 <=> a6)); +static_assert(std::is_lt(a5 <=> a7)); +static_assert(std::is_gt(a8 <=> a5)); diff --git a/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc b/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc index 2ae8a5edc67..7833748392a 100644 --- a/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc @@ -27,6 +27,6 @@ int n1 = std::get<1>(a); int n2 = std::get<1>(std::move(a)); int n3 = std::get<1>(ca); -// { dg-error "static assertion failed" "" { target *-*-* } 316 } -// { dg-error "static assertion failed" "" { target *-*-* } 325 } -// { dg-error "static assertion failed" "" { target *-*-* } 333 } +// { dg-error "static assertion failed" "" { target *-*-* } 336 } +// { dg-error "static assertion failed" "" { target *-*-* } 345 } +// { dg-error "static assertion failed" "" { target *-*-* } 353 } -- 2.30.2