From f8b5ac34adb9d6e60202d8cc92d9c3cd02806c66 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Mon, 22 May 2023 23:33:45 +0300 Subject: [PATCH] [libc++][spaceship] Implement `operator<=>` for `multiset` and `set` Implements parts of P1614R2 Implemented `operator<=>` for `multiset` and `set` Reviewed By: #libc, Mordante Differential Revision: https://reviews.llvm.org/D148416 --- libcxx/include/set | 55 +++++++++-- .../multiset.nonmember/compare.three_way.pass.cpp | 27 ++++++ .../compare.three_way.verify.cpp | 60 ++++++++++++ .../set/set.nonmember/compare.three_way.pass.cpp | 27 ++++++ .../set/set.nonmember/compare.three_way.verify.cpp | 60 ++++++++++++ libcxx/test/support/test_comparisons.h | 5 +- libcxx/test/support/test_container_comparisons.h | 107 ++++++++++++++++++++- 7 files changed, 329 insertions(+), 12 deletions(-) create mode 100644 libcxx/test/std/containers/associative/multiset/multiset.nonmember/compare.three_way.pass.cpp create mode 100644 libcxx/test/std/containers/associative/multiset/multiset.nonmember/compare.three_way.verify.cpp create mode 100644 libcxx/test/std/containers/associative/set/set.nonmember/compare.three_way.pass.cpp create mode 100644 libcxx/test/std/containers/associative/set/set.nonmember/compare.three_way.verify.cpp diff --git a/libcxx/include/set b/libcxx/include/set index b0e5e50..7d54c90 100644 --- a/libcxx/include/set +++ b/libcxx/include/set @@ -210,27 +210,31 @@ operator==(const set& x, template bool operator< (const set& x, - const set& y); + const set& y); // removed in C++20 template bool operator!=(const set& x, - const set& y); + const set& y); // removed in C++20 template bool operator> (const set& x, - const set& y); + const set& y); // removed in C++20 template bool operator>=(const set& x, - const set& y); + const set& y); // removed in C++20 template bool operator<=(const set& x, - const set& y); + const set& y); // removed in C++20 + +template + synth-three-way-result operator<=>(const set& x, + const set& y); // since C++20 // specialized algorithms: template @@ -435,27 +439,31 @@ operator==(const multiset& x, template bool operator< (const multiset& x, - const multiset& y); + const multiset& y); // removed in C++20 template bool operator!=(const multiset& x, - const multiset& y); + const multiset& y); // removed in C++20 template bool operator> (const multiset& x, - const multiset& y); + const multiset& y); // removed in C++20 template bool operator>=(const multiset& x, - const multiset& y); + const multiset& y); // removed in C++20 template bool operator<=(const multiset& x, - const multiset& y); + const multiset& y); // removed in C++20 + +template + synth-three-way-result operator<=>(const multiset& x, + const multiset& y); // since C++20 // specialized algorithms: template @@ -473,6 +481,7 @@ erase_if(multiset& c, Predicate pred); // C++20 #include <__algorithm/equal.h> #include <__algorithm/lexicographical_compare.h> +#include <__algorithm/lexicographical_compare_three_way.h> #include <__assert> // all public C++ headers provide the assertion handler #include <__config> #include <__functional/is_transparent.h> @@ -982,6 +991,8 @@ operator==(const set<_Key, _Compare, _Allocator>& __x, return __x.size() == __y.size() && _VSTD::equal(__x.begin(), __x.end(), __y.begin()); } +#if _LIBCPP_STD_VER <= 17 + template inline _LIBCPP_INLINE_VISIBILITY bool @@ -1027,6 +1038,17 @@ operator<=(const set<_Key, _Compare, _Allocator>& __x, return !(__y < __x); } +#else // _LIBCPP_STD_VER <= 17 + +template +_LIBCPP_HIDE_FROM_ABI __synth_three_way_result<_Key> +operator<=>(const set<_Key, _Allocator>& __x, const set<_Key, _Allocator>& __y) { + return std::lexicographical_compare_three_way( + __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way<_Key, _Key>); +} + +#endif // _LIBCPP_STD_VER <= 17 + // specialized algorithms: template inline _LIBCPP_INLINE_VISIBILITY @@ -1518,6 +1540,8 @@ operator==(const multiset<_Key, _Compare, _Allocator>& __x, return __x.size() == __y.size() && _VSTD::equal(__x.begin(), __x.end(), __y.begin()); } +#if _LIBCPP_STD_VER <= 17 + template inline _LIBCPP_INLINE_VISIBILITY bool @@ -1563,6 +1587,17 @@ operator<=(const multiset<_Key, _Compare, _Allocator>& __x, return !(__y < __x); } +#else // _LIBCPP_STD_VER <= 17 + +template +_LIBCPP_HIDE_FROM_ABI __synth_three_way_result<_Key> +operator<=>(const multiset<_Key, _Allocator>& __x, const multiset<_Key, _Allocator>& __y) { + return std::lexicographical_compare_three_way( + __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way<_Key, _Key>); +} + +#endif // _LIBCPP_STD_VER <= 17 + template inline _LIBCPP_INLINE_VISIBILITY void diff --git a/libcxx/test/std/containers/associative/multiset/multiset.nonmember/compare.three_way.pass.cpp b/libcxx/test/std/containers/associative/multiset/multiset.nonmember/compare.three_way.pass.cpp new file mode 100644 index 0000000..fb575c8 --- /dev/null +++ b/libcxx/test/std/containers/associative/multiset/multiset.nonmember/compare.three_way.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// class multiset + +// template +// synth-three-way-result operator<=>(const multiset& x, +// const multiset& y); + +#include +#include + +#include "test_container_comparisons.h" + +int main(int, char**) { + assert(test_ordered_set_container_spaceship()); + // `std::multiset` is not constexpr, so no `static_assert` test here. + return 0; +} diff --git a/libcxx/test/std/containers/associative/multiset/multiset.nonmember/compare.three_way.verify.cpp b/libcxx/test/std/containers/associative/multiset/multiset.nonmember/compare.three_way.verify.cpp new file mode 100644 index 0000000..9bde360 --- /dev/null +++ b/libcxx/test/std/containers/associative/multiset/multiset.nonmember/compare.three_way.verify.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// class set + +// template +// synth-three-way-result operator<=>(const set& x, +// const set& y); + +#include + +#include "test_allocator.h" + +int main(int, char**) { + // Mismatching allocators + { + std::multiset, std::allocator> s1; + std::multiset, test_allocator> s2; + // expected-error@+1 {{invalid operands to binary expression}} + s1 <=> s2; + // expected-error@+1 {{invalid operands to binary expression}} + s2 <=> s1; + } + // Mismatching comparision functions + { + std::multiset> s1; + std::multiset> s2; + // expected-error@+1 {{invalid operands to binary expression}} + s1 <=> s2; + // expected-error@+1 {{invalid operands to binary expression}} + s2 <=> s1; + } + { + std::multiset> s1; + std::multiset> s2; + // expected-error@+1 {{invalid operands to binary expression}} + s1 <=> s2; + // expected-error@+1 {{invalid operands to binary expression}} + s2 <=> s1; + } + // Mismatching types + { + std::multiset s1; + std::multiset s2; + // expected-error@+1 {{invalid operands to binary expression}} + s1 <=> s2; + // expected-error@+1 {{invalid operands to binary expression}} + s2 <=> s1; + } + + return 0; +} diff --git a/libcxx/test/std/containers/associative/set/set.nonmember/compare.three_way.pass.cpp b/libcxx/test/std/containers/associative/set/set.nonmember/compare.three_way.pass.cpp new file mode 100644 index 0000000..dc513d9 --- /dev/null +++ b/libcxx/test/std/containers/associative/set/set.nonmember/compare.three_way.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// class set + +// template +// synth-three-way-result operator<=>(const set& x, +// const set& y); + +#include +#include + +#include "test_container_comparisons.h" + +int main(int, char**) { + assert((test_ordered_set_container_spaceship())); + // `std::set` is not constexpr, so no `static_assert` test here. + return 0; +} diff --git a/libcxx/test/std/containers/associative/set/set.nonmember/compare.three_way.verify.cpp b/libcxx/test/std/containers/associative/set/set.nonmember/compare.three_way.verify.cpp new file mode 100644 index 0000000..a2d8c4e4 --- /dev/null +++ b/libcxx/test/std/containers/associative/set/set.nonmember/compare.three_way.verify.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// class set + +// template +// synth-three-way-result operator<=>(const set& x, +// const set& y); + +#include + +#include "test_allocator.h" + +int main(int, char**) { + // Mismatching allocators + { + std::set, std::allocator> s1; + std::set, test_allocator> s2; + // expected-error@+1 {{invalid operands to binary expression}} + s1 <=> s2; + // expected-error@+1 {{invalid operands to binary expression}} + s2 <=> s1; + } + // Mismatching comparision functions + { + std::set> s1; + std::set> s2; + // expected-error@+1 {{invalid operands to binary expression}} + s1 <=> s2; + // expected-error@+1 {{invalid operands to binary expression}} + s2 <=> s1; + } + { + std::set> s1; + std::set> s2; + // expected-error@+1 {{invalid operands to binary expression}} + s1 <=> s2; + // expected-error@+1 {{invalid operands to binary expression}} + s2 <=> s1; + } + // Mismatching types + { + std::set s1; + std::set s2; + // expected-error@+1 {{invalid operands to binary expression}} + s1 <=> s2; + // expected-error@+1 {{invalid operands to binary expression}} + s2 <=> s1; + } + + return 0; +} diff --git a/libcxx/test/support/test_comparisons.h b/libcxx/test/support/test_comparisons.h index c54e877..e006f69 100644 --- a/libcxx/test/support/test_comparisons.h +++ b/libcxx/test/support/test_comparisons.h @@ -241,7 +241,8 @@ struct LessAndEqComp { } }; -#if TEST_STD_VER > 17 +#if TEST_STD_VER >= 20 + struct StrongOrder { int value; constexpr StrongOrder(int v) : value(v) {} @@ -260,6 +261,8 @@ struct PartialOrder { friend constexpr std::partial_ordering operator<=>(PartialOrder lhs, PartialOrder rhs) { if (lhs.value == std::numeric_limits::min() || rhs.value == std::numeric_limits::min()) return std::partial_ordering::unordered; + if (lhs.value == std::numeric_limits::max() || rhs.value == std::numeric_limits::max()) + return std::partial_ordering::unordered; return lhs.value <=> rhs.value; } friend constexpr bool operator==(PartialOrder lhs, PartialOrder rhs) { diff --git a/libcxx/test/support/test_container_comparisons.h b/libcxx/test/support/test_container_comparisons.h index f9dae9d..d3b4033 100644 --- a/libcxx/test/support/test_container_comparisons.h +++ b/libcxx/test/support/test_container_comparisons.h @@ -10,6 +10,8 @@ #ifndef TEST_CONTAINER_COMPARISONS #define TEST_CONTAINER_COMPARISONS +#include + #include "test_comparisons.h" // Implementation detail of `test_sequence_container_spaceship` @@ -183,7 +185,7 @@ constexpr void test_ordered_map_container_spaceship_with_type() { } } -// Tests the `operator<=>` on ordered containers +// Tests the `operator<=>` on ordered map containers template