template <class Key, class Compare, class Allocator>
bool
operator< (const set<Key, Compare, Allocator>& x,
- const set<Key, Compare, Allocator>& y);
+ const set<Key, Compare, Allocator>& y); // removed in C++20
template <class Key, class Compare, class Allocator>
bool
operator!=(const set<Key, Compare, Allocator>& x,
- const set<Key, Compare, Allocator>& y);
+ const set<Key, Compare, Allocator>& y); // removed in C++20
template <class Key, class Compare, class Allocator>
bool
operator> (const set<Key, Compare, Allocator>& x,
- const set<Key, Compare, Allocator>& y);
+ const set<Key, Compare, Allocator>& y); // removed in C++20
template <class Key, class Compare, class Allocator>
bool
operator>=(const set<Key, Compare, Allocator>& x,
- const set<Key, Compare, Allocator>& y);
+ const set<Key, Compare, Allocator>& y); // removed in C++20
template <class Key, class Compare, class Allocator>
bool
operator<=(const set<Key, Compare, Allocator>& x,
- const set<Key, Compare, Allocator>& y);
+ const set<Key, Compare, Allocator>& y); // removed in C++20
+
+template<class Key, class Compare, class Allocator>
+ synth-three-way-result<Key> operator<=>(const set<Key, Compare, Allocator>& x,
+ const set<Key, Compare, Allocator>& y); // since C++20
// specialized algorithms:
template <class Key, class Compare, class Allocator>
template <class Key, class Compare, class Allocator>
bool
operator< (const multiset<Key, Compare, Allocator>& x,
- const multiset<Key, Compare, Allocator>& y);
+ const multiset<Key, Compare, Allocator>& y); // removed in C++20
template <class Key, class Compare, class Allocator>
bool
operator!=(const multiset<Key, Compare, Allocator>& x,
- const multiset<Key, Compare, Allocator>& y);
+ const multiset<Key, Compare, Allocator>& y); // removed in C++20
template <class Key, class Compare, class Allocator>
bool
operator> (const multiset<Key, Compare, Allocator>& x,
- const multiset<Key, Compare, Allocator>& y);
+ const multiset<Key, Compare, Allocator>& y); // removed in C++20
template <class Key, class Compare, class Allocator>
bool
operator>=(const multiset<Key, Compare, Allocator>& x,
- const multiset<Key, Compare, Allocator>& y);
+ const multiset<Key, Compare, Allocator>& y); // removed in C++20
template <class Key, class Compare, class Allocator>
bool
operator<=(const multiset<Key, Compare, Allocator>& x,
- const multiset<Key, Compare, Allocator>& y);
+ const multiset<Key, Compare, Allocator>& y); // removed in C++20
+
+template<class Key, class Compare, class Allocator>
+ synth-three-way-result<Key> operator<=>(const multiset<Key, Compare, Allocator>& x,
+ const multiset<Key, Compare, Allocator>& y); // since C++20
// specialized algorithms:
template <class Key, class Compare, class Allocator>
#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>
return __x.size() == __y.size() && _VSTD::equal(__x.begin(), __x.end(), __y.begin());
}
+#if _LIBCPP_STD_VER <= 17
+
template <class _Key, class _Compare, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY
bool
return !(__y < __x);
}
+#else // _LIBCPP_STD_VER <= 17
+
+template <class _Key, class _Allocator>
+_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 <class _Key, class _Compare, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY
return __x.size() == __y.size() && _VSTD::equal(__x.begin(), __x.end(), __y.begin());
}
+#if _LIBCPP_STD_VER <= 17
+
template <class _Key, class _Compare, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY
bool
return !(__y < __x);
}
+#else // _LIBCPP_STD_VER <= 17
+
+template <class _Key, class _Allocator>
+_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 <class _Key, class _Compare, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY
void
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <set>
+
+// class multiset
+
+// template<class Key, class Compare, class Allocator>
+// synth-three-way-result<Key> operator<=>(const multiset<Key, Compare, Allocator>& x,
+// const multiset<Key, Compare, Allocator>& y);
+
+#include <cassert>
+#include <set>
+
+#include "test_container_comparisons.h"
+
+int main(int, char**) {
+ assert(test_ordered_set_container_spaceship<std::multiset>());
+ // `std::multiset` is not constexpr, so no `static_assert` test here.
+ return 0;
+}
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <set>
+
+// class set
+
+// template<class Key, class Compare, class Allocator>
+// synth-three-way-result<Key> operator<=>(const set<Key, Compare, Allocator>& x,
+// const set<Key, Compare, Allocator>& y);
+
+#include <set>
+
+#include "test_allocator.h"
+
+int main(int, char**) {
+ // Mismatching allocators
+ {
+ std::multiset<int, std::less<int>, std::allocator<int>> s1;
+ std::multiset<int, std::less<int>, test_allocator<int>> 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<int, std::less<int>> s1;
+ std::multiset<int, std::greater<int>> s2;
+ // expected-error@+1 {{invalid operands to binary expression}}
+ s1 <=> s2;
+ // expected-error@+1 {{invalid operands to binary expression}}
+ s2 <=> s1;
+ }
+ {
+ std::multiset<int, std::less<int>> s1;
+ std::multiset<int, std::less<float>> 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<int> s1;
+ std::multiset<float> s2;
+ // expected-error@+1 {{invalid operands to binary expression}}
+ s1 <=> s2;
+ // expected-error@+1 {{invalid operands to binary expression}}
+ s2 <=> s1;
+ }
+
+ return 0;
+}
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <set>
+
+// class set
+
+// template<class Key, class Compare, class Allocator>
+// synth-three-way-result<Key> operator<=>(const set<Key, Compare, Allocator>& x,
+// const set<Key, Compare, Allocator>& y);
+
+#include <cassert>
+#include <set>
+
+#include "test_container_comparisons.h"
+
+int main(int, char**) {
+ assert((test_ordered_set_container_spaceship<std::set>()));
+ // `std::set` is not constexpr, so no `static_assert` test here.
+ return 0;
+}
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <set>
+
+// class set
+
+// template<class Key, class Compare, class Allocator>
+// synth-three-way-result<Key> operator<=>(const set<Key, Compare, Allocator>& x,
+// const set<Key, Compare, Allocator>& y);
+
+#include <set>
+
+#include "test_allocator.h"
+
+int main(int, char**) {
+ // Mismatching allocators
+ {
+ std::set<int, std::less<int>, std::allocator<int>> s1;
+ std::set<int, std::less<int>, test_allocator<int>> 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<int, std::less<int>> s1;
+ std::set<int, std::greater<int>> s2;
+ // expected-error@+1 {{invalid operands to binary expression}}
+ s1 <=> s2;
+ // expected-error@+1 {{invalid operands to binary expression}}
+ s2 <=> s1;
+ }
+ {
+ std::set<int, std::less<int>> s1;
+ std::set<int, std::less<float>> 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<int> s1;
+ std::set<float> s2;
+ // expected-error@+1 {{invalid operands to binary expression}}
+ s1 <=> s2;
+ // expected-error@+1 {{invalid operands to binary expression}}
+ s2 <=> s1;
+ }
+
+ return 0;
+}
}
};
-#if TEST_STD_VER > 17
+#if TEST_STD_VER >= 20
+
struct StrongOrder {
int value;
constexpr StrongOrder(int v) : value(v) {}
friend constexpr std::partial_ordering operator<=>(PartialOrder lhs, PartialOrder rhs) {
if (lhs.value == std::numeric_limits<int>::min() || rhs.value == std::numeric_limits<int>::min())
return std::partial_ordering::unordered;
+ if (lhs.value == std::numeric_limits<int>::max() || rhs.value == std::numeric_limits<int>::max())
+ return std::partial_ordering::unordered;
return lhs.value <=> rhs.value;
}
friend constexpr bool operator==(PartialOrder lhs, PartialOrder rhs) {
#ifndef TEST_CONTAINER_COMPARISONS
#define TEST_CONTAINER_COMPARISONS
+#include <set>
+
#include "test_comparisons.h"
// Implementation detail of `test_sequence_container_spaceship`
}
}
-// Tests the `operator<=>` on ordered containers
+// Tests the `operator<=>` on ordered map containers
template <template <typename...> typename Container>
constexpr bool test_ordered_map_container_spaceship() {
// The container should fulfill `std::three_way_comparable`
return true;
}
+// Implementation detail of `test_ordered_set_container_spaceship`
+template <template <typename...> typename Container, typename Elem, typename Order, typename Compare>
+constexpr void test_ordered_set_spaceship_with_type(Compare comp) {
+ // Empty containers
+ {
+ Container<Elem, Compare> l1{{}, comp};
+ Container<Elem, Compare> l2{{}, comp};
+ assert(testOrder(l1, l2, Order::equivalent));
+ }
+ // Identical contents
+ {
+ Container<Elem, Compare> l1{{1, 1, 2}, comp};
+ Container<Elem, Compare> l2{{1, 1, 2}, comp};
+ assert(testOrder(l1, l2, Order::equivalent));
+ }
+ // Less, due to contained values
+ {
+ Container<Elem, Compare> l1{{1, 1, 2, 3}, comp};
+ Container<Elem, Compare> l2{{1, 2, 2, 4}, comp};
+ assert(testOrder(l1, l2, Order::less));
+ }
+ // Greater, due to contained values
+ {
+ Container<Elem, Compare> l1{{1, 2, 2, 4}, comp};
+ Container<Elem, Compare> l2{{1, 1, 2, 3}, comp};
+ assert(testOrder(l1, l2, Order::greater));
+ }
+ // Shorter list
+ {
+ Container<Elem, Compare> l1{{1, 1, 2, 2}, comp};
+ Container<Elem, Compare> l2{{1, 1, 2, 2, 3}, comp};
+ assert(testOrder(l1, l2, Order::less));
+ }
+ // Longer list
+ {
+ Container<Elem, Compare> l1{{1, 1, 2, 2, 3}, comp};
+ Container<Elem, Compare> l2{{1, 1, 2, 2}, comp};
+ assert(testOrder(l1, l2, Order::greater));
+ }
+ // Unordered
+ if constexpr (std::is_same_v< Container<Elem>, std::multiset<PartialOrder>>) {
+ if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {
+ Container<Elem, Compare> l1{{1, std::numeric_limits<int>::min()}, comp};
+ Container<Elem, Compare> l2{{1, 2}, comp};
+ assert(testOrder(l1, l2, Order::unordered));
+ }
+ if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {
+ Container<Elem, Compare> l1{{1, std::numeric_limits<int>::max()}, comp};
+ Container<Elem, Compare> l2{{1, 2}, comp};
+ assert(testOrder(l1, l2, Order::unordered));
+ }
+ }
+ if constexpr (std::is_same_v< Container<Elem>, std::set<PartialOrder>>) {
+ // Unodered values are not supported for `set`
+ if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {
+ Container<Elem, Compare> l1{{1, std::numeric_limits<int>::min()}, comp};
+ Container<Elem, Compare> l2{{1, 2}, comp};
+ assert(testOrder(l1, l2, Order::less));
+ }
+ if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {
+ Container<Elem, Compare> l1{{1, std::numeric_limits<int>::max()}, comp};
+ Container<Elem, Compare> l2{{1, 2}, comp};
+ assert(testOrder(l1, l2, Order::less));
+ }
+ }
+ if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::greater{})>) {
+ Container<Elem, Compare> l1{{1, std::numeric_limits<int>::min()}, comp};
+ Container<Elem, Compare> l2{{1, 2}, comp};
+ assert(testOrder(l1, l2, Order::less));
+ }
+ if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::greater{})>) {
+ Container<Elem, Compare> l1{{1, std::numeric_limits<int>::max()}, comp};
+ Container<Elem, Compare> l2{{1, 2}, comp};
+ assert(testOrder(l1, l2, Order::less));
+ }
+}
+
+// Tests the `operator<=>` on ordered set containers
+template <template <typename...> typename Container>
+constexpr bool test_ordered_set_container_spaceship() {
+ // Thanks to SFINAE, the following is not a compiler error but returns `false`
+ struct NonComparable {};
+ static_assert(!std::three_way_comparable<Container<NonComparable>>);
+
+ // The container should fulfill `std::three_way_comparable`
+ static_assert(std::three_way_comparable<Container<int>>);
+
+ // Test different comparison categories
+ test_ordered_set_spaceship_with_type<Container, int, std::strong_ordering>(std::less{});
+ test_ordered_set_spaceship_with_type<Container, int, std::strong_ordering>(std::greater{});
+ test_ordered_set_spaceship_with_type<Container, StrongOrder, std::strong_ordering>(std::less{});
+ test_ordered_set_spaceship_with_type<Container, StrongOrder, std::strong_ordering>(std::greater{});
+ test_ordered_set_spaceship_with_type<Container, WeakOrder, std::weak_ordering>(std::less{});
+ test_ordered_set_spaceship_with_type<Container, WeakOrder, std::weak_ordering>(std::greater{});
+ test_ordered_set_spaceship_with_type<Container, PartialOrder, std::partial_ordering>(std::less{});
+ test_ordered_set_spaceship_with_type<Container, PartialOrder, std::partial_ordering>(std::greater{});
+
+ // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
+ test_ordered_set_spaceship_with_type<Container, LessAndEqComp, std::weak_ordering>(std::less{});
+
+ return true;
+}
+
#endif