xref: /llvm-project/libcxx/test/support/test_container_comparisons.h (revision f5832bab6f5024cabe32a9f668b7f44e6b7cfef5)
1b5a84ae0SAdrian Vogelsgesang //===----------------------------------------------------------------------===//
2b5a84ae0SAdrian Vogelsgesang //
3b5a84ae0SAdrian Vogelsgesang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b5a84ae0SAdrian Vogelsgesang // See https://llvm.org/LICENSE.txt for license information.
5b5a84ae0SAdrian Vogelsgesang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b5a84ae0SAdrian Vogelsgesang //
7b5a84ae0SAdrian Vogelsgesang //===----------------------------------------------------------------------===//
8b5a84ae0SAdrian Vogelsgesang //  Utility functions to test comparisons on containers.
9b5a84ae0SAdrian Vogelsgesang 
10b5a84ae0SAdrian Vogelsgesang #ifndef TEST_CONTAINER_COMPARISONS
11b5a84ae0SAdrian Vogelsgesang #define TEST_CONTAINER_COMPARISONS
12b5a84ae0SAdrian Vogelsgesang 
136614d36dSHristo Hristov #include <functional>
14f8b5ac34SHristo Hristov #include <set>
15f8b5ac34SHristo Hristov 
16b5a84ae0SAdrian Vogelsgesang #include "test_comparisons.h"
17b5a84ae0SAdrian Vogelsgesang 
18177cb103SLouis Dionne // Implementation detail of `test_sequence_container_spaceship`
19b5a84ae0SAdrian Vogelsgesang template <template <typename...> typename Container, typename Elem, typename Order>
test_sequence_container_spaceship_with_type()20177cb103SLouis Dionne constexpr void test_sequence_container_spaceship_with_type() {
21b5a84ae0SAdrian Vogelsgesang   // Empty containers
22b5a84ae0SAdrian Vogelsgesang   {
23b5a84ae0SAdrian Vogelsgesang     Container<Elem> l1;
24b5a84ae0SAdrian Vogelsgesang     Container<Elem> l2;
25b5a84ae0SAdrian Vogelsgesang     assert(testOrder(l1, l2, Order::equivalent));
26b5a84ae0SAdrian Vogelsgesang   }
27b5a84ae0SAdrian Vogelsgesang   // Identical contents
28b5a84ae0SAdrian Vogelsgesang   {
29b5a84ae0SAdrian Vogelsgesang     Container<Elem> l1{1, 1};
30b5a84ae0SAdrian Vogelsgesang     Container<Elem> l2{1, 1};
31b5a84ae0SAdrian Vogelsgesang     assert(testOrder(l1, l2, Order::equivalent));
32b5a84ae0SAdrian Vogelsgesang   }
33b5a84ae0SAdrian Vogelsgesang   // Less, due to contained values
34b5a84ae0SAdrian Vogelsgesang   {
35b5a84ae0SAdrian Vogelsgesang     Container<Elem> l1{1, 1};
36b5a84ae0SAdrian Vogelsgesang     Container<Elem> l2{1, 2};
37b5a84ae0SAdrian Vogelsgesang     assert(testOrder(l1, l2, Order::less));
38b5a84ae0SAdrian Vogelsgesang   }
39b5a84ae0SAdrian Vogelsgesang   // Greater, due to contained values
40b5a84ae0SAdrian Vogelsgesang   {
41b5a84ae0SAdrian Vogelsgesang     Container<Elem> l1{1, 3};
42b5a84ae0SAdrian Vogelsgesang     Container<Elem> l2{1, 2};
43b5a84ae0SAdrian Vogelsgesang     assert(testOrder(l1, l2, Order::greater));
44b5a84ae0SAdrian Vogelsgesang   }
45b5a84ae0SAdrian Vogelsgesang   // Shorter list
46b5a84ae0SAdrian Vogelsgesang   {
47b5a84ae0SAdrian Vogelsgesang     Container<Elem> l1{1};
48b5a84ae0SAdrian Vogelsgesang     Container<Elem> l2{1, 2};
49b5a84ae0SAdrian Vogelsgesang     assert(testOrder(l1, l2, Order::less));
50b5a84ae0SAdrian Vogelsgesang   }
51b5a84ae0SAdrian Vogelsgesang   // Longer list
52b5a84ae0SAdrian Vogelsgesang   {
53b5a84ae0SAdrian Vogelsgesang     Container<Elem> l1{1, 2};
54b5a84ae0SAdrian Vogelsgesang     Container<Elem> l2{1};
55b5a84ae0SAdrian Vogelsgesang     assert(testOrder(l1, l2, Order::greater));
56b5a84ae0SAdrian Vogelsgesang   }
57b5a84ae0SAdrian Vogelsgesang   // Unordered
58b5a84ae0SAdrian Vogelsgesang   if constexpr (std::is_same_v<Elem, PartialOrder>) {
59b5a84ae0SAdrian Vogelsgesang     Container<Elem> l1{1, std::numeric_limits<int>::min()};
60b5a84ae0SAdrian Vogelsgesang     Container<Elem> l2{1, 2};
61b5a84ae0SAdrian Vogelsgesang     assert(testOrder(l1, l2, Order::unordered));
62b5a84ae0SAdrian Vogelsgesang   }
63b5a84ae0SAdrian Vogelsgesang }
64b5a84ae0SAdrian Vogelsgesang 
65177cb103SLouis Dionne // Tests the `operator<=>` on sequence containers
66b5a84ae0SAdrian Vogelsgesang template <template <typename...> typename Container>
test_sequence_container_spaceship()67177cb103SLouis Dionne constexpr bool test_sequence_container_spaceship() {
68254986d2SHristo Hristov   // The container should fulfill `std::three_way_comparable`
69b5a84ae0SAdrian Vogelsgesang   static_assert(std::three_way_comparable<Container<int>>);
70b5a84ae0SAdrian Vogelsgesang 
71b5a84ae0SAdrian Vogelsgesang   // Test different comparison categories
72177cb103SLouis Dionne   test_sequence_container_spaceship_with_type<Container, int, std::strong_ordering>();
73177cb103SLouis Dionne   test_sequence_container_spaceship_with_type<Container, StrongOrder, std::strong_ordering>();
74177cb103SLouis Dionne   test_sequence_container_spaceship_with_type<Container, WeakOrder, std::weak_ordering>();
75177cb103SLouis Dionne   test_sequence_container_spaceship_with_type<Container, PartialOrder, std::partial_ordering>();
76b5a84ae0SAdrian Vogelsgesang 
77254986d2SHristo Hristov   // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
78177cb103SLouis Dionne   test_sequence_container_spaceship_with_type<Container, LessAndEqComp, std::weak_ordering>();
79b5a84ae0SAdrian Vogelsgesang 
80b5a84ae0SAdrian Vogelsgesang   // Thanks to SFINAE, the following is not a compiler error but returns `false`
81b5a84ae0SAdrian Vogelsgesang   struct NonComparable {};
82b5a84ae0SAdrian Vogelsgesang   static_assert(!std::three_way_comparable<Container<NonComparable>>);
83b5a84ae0SAdrian Vogelsgesang 
84b5a84ae0SAdrian Vogelsgesang   return true;
85b5a84ae0SAdrian Vogelsgesang }
86b5a84ae0SAdrian Vogelsgesang 
87172d990cSHristo Hristov // Implementation detail of `test_sequence_container_adaptor_spaceship`
88172d990cSHristo Hristov template <template <typename...> typename ContainerAdaptor,
89172d990cSHristo Hristov           template <typename...>
90172d990cSHristo Hristov           typename Container,
91172d990cSHristo Hristov           typename Elem,
92172d990cSHristo Hristov           typename Order>
test_sequence_container_adaptor_spaceship_with_type()93172d990cSHristo Hristov constexpr void test_sequence_container_adaptor_spaceship_with_type() {
94172d990cSHristo Hristov   // Empty containers
95172d990cSHristo Hristov   {
96172d990cSHristo Hristov     Container<Elem> l1;
97172d990cSHristo Hristov     ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
98172d990cSHristo Hristov     Container<Elem> l2;
99172d990cSHristo Hristov     ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
100172d990cSHristo Hristov     assert(testOrder(ca1, ca2, Order::equivalent));
101172d990cSHristo Hristov   }
102172d990cSHristo Hristov   // Identical contents
103172d990cSHristo Hristov   {
104172d990cSHristo Hristov     Container<Elem> l1{1, 1};
105172d990cSHristo Hristov     ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
106172d990cSHristo Hristov     Container<Elem> l2{1, 1};
107172d990cSHristo Hristov     ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
108172d990cSHristo Hristov     assert(testOrder(ca1, ca2, Order::equivalent));
109172d990cSHristo Hristov   }
110172d990cSHristo Hristov   // Less, due to contained values
111172d990cSHristo Hristov   {
112172d990cSHristo Hristov     Container<Elem> l1{1, 1};
113172d990cSHristo Hristov     ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
114172d990cSHristo Hristov     Container<Elem> l2{1, 2};
115172d990cSHristo Hristov     ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
116172d990cSHristo Hristov     assert(testOrder(ca1, ca2, Order::less));
117172d990cSHristo Hristov   }
118172d990cSHristo Hristov   // Greater, due to contained values
119172d990cSHristo Hristov   {
120172d990cSHristo Hristov     Container<Elem> l1{1, 3};
121172d990cSHristo Hristov     ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
122172d990cSHristo Hristov     Container<Elem> l2{1, 2};
123172d990cSHristo Hristov     ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
124172d990cSHristo Hristov     assert(testOrder(ca1, ca2, Order::greater));
125172d990cSHristo Hristov   }
126172d990cSHristo Hristov   // Shorter list
127172d990cSHristo Hristov   {
128172d990cSHristo Hristov     Container<Elem> l1{1};
129172d990cSHristo Hristov     ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
130172d990cSHristo Hristov     Container<Elem> l2{1, 2};
131172d990cSHristo Hristov     ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
132172d990cSHristo Hristov     assert(testOrder(ca1, ca2, Order::less));
133172d990cSHristo Hristov   }
134172d990cSHristo Hristov   // Longer list
135172d990cSHristo Hristov   {
136172d990cSHristo Hristov     Container<Elem> l1{1, 2};
137172d990cSHristo Hristov     ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
138172d990cSHristo Hristov     Container<Elem> l2{1};
139172d990cSHristo Hristov     ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
140172d990cSHristo Hristov     assert(testOrder(ca1, ca2, Order::greater));
141172d990cSHristo Hristov   }
142172d990cSHristo Hristov   // Unordered
143172d990cSHristo Hristov   if constexpr (std::is_same_v<Elem, PartialOrder>) {
144172d990cSHristo Hristov     Container<Elem> l1{1, std::numeric_limits<int>::min()};
145172d990cSHristo Hristov     ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
146172d990cSHristo Hristov     Container<Elem> l2{1, 2};
147172d990cSHristo Hristov     ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
148172d990cSHristo Hristov     assert(testOrder(ca1, ca2, Order::unordered));
149172d990cSHristo Hristov   }
150172d990cSHristo Hristov }
151172d990cSHristo Hristov 
152172d990cSHristo Hristov // Tests the `operator<=>` on sequence container adaptors
153172d990cSHristo Hristov template <template <typename...> typename ContainerAdaptor, template <typename...> typename Container>
test_sequence_container_adaptor_spaceship()154172d990cSHristo Hristov constexpr bool test_sequence_container_adaptor_spaceship() {
155172d990cSHristo Hristov   // Thanks to SFINAE, the following is not a compiler error but returns `false`
156172d990cSHristo Hristov   struct NonComparable {};
157172d990cSHristo Hristov   static_assert(!std::three_way_comparable<ContainerAdaptor<NonComparable>>);
158172d990cSHristo Hristov 
159172d990cSHristo Hristov   // The container should fulfill `std::three_way_comparable`
160172d990cSHristo Hristov   static_assert(std::three_way_comparable<ContainerAdaptor<int, Container<int>>>);
161172d990cSHristo Hristov 
162172d990cSHristo Hristov   // Test different comparison categories
163172d990cSHristo Hristov   test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, int, std::strong_ordering>();
164172d990cSHristo Hristov   test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, StrongOrder, std::strong_ordering>();
165172d990cSHristo Hristov   test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, WeakOrder, std::weak_ordering>();
166172d990cSHristo Hristov   test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor,
167172d990cSHristo Hristov                                                       Container,
168172d990cSHristo Hristov                                                       PartialOrder,
169172d990cSHristo Hristov                                                       std::partial_ordering>();
170172d990cSHristo Hristov 
171172d990cSHristo Hristov   // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
172172d990cSHristo Hristov   test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, LessAndEqComp, std::weak_ordering>();
173172d990cSHristo Hristov 
174172d990cSHristo Hristov   return true;
175172d990cSHristo Hristov }
176172d990cSHristo Hristov 
177bc47a195SHristo Hristov // Implementation detail of `test_ordered_map_container_spaceship`
1786614d36dSHristo Hristov template <template <typename...> typename Container, typename Key, typename Val, typename Order, typename Compare>
test_ordered_map_container_spaceship_with_type(Compare comp)1796614d36dSHristo Hristov constexpr void test_ordered_map_container_spaceship_with_type(Compare comp) {
180bc47a195SHristo Hristov   // Empty containers
181bc47a195SHristo Hristov   {
1826614d36dSHristo Hristov     Container<Key, Val, Compare> l1{{}, comp};
1836614d36dSHristo Hristov     Container<Key, Val, Compare> l2{{}, comp};
184bc47a195SHristo Hristov     assert(testOrder(l1, l2, Order::equivalent));
185bc47a195SHristo Hristov   }
186bc47a195SHristo Hristov   // Identical contents
187bc47a195SHristo Hristov   {
1886614d36dSHristo Hristov     Container<Key, Val, Compare> l1{{{1, 1}, {2, 1}}, comp};
1896614d36dSHristo Hristov     Container<Key, Val, Compare> l2{{{1, 1}, {2, 1}}, comp};
190bc47a195SHristo Hristov     assert(testOrder(l1, l2, Order::equivalent));
191bc47a195SHristo Hristov   }
192bc47a195SHristo Hristov   // Less, due to contained values
193bc47a195SHristo Hristov   {
1946614d36dSHristo Hristov     Container<Key, Val, Compare> l1{{{1, 1}, {2, 1}}, comp};
1956614d36dSHristo Hristov     Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
196bc47a195SHristo Hristov     assert(testOrder(l1, l2, Order::less));
197bc47a195SHristo Hristov   }
198bc47a195SHristo Hristov   // Greater, due to contained values
199bc47a195SHristo Hristov   {
2006614d36dSHristo Hristov     Container<Key, Val, Compare> l1{{{1, 1}, {2, 3}}, comp};
2016614d36dSHristo Hristov     Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
202bc47a195SHristo Hristov     assert(testOrder(l1, l2, Order::greater));
203bc47a195SHristo Hristov   }
204bc47a195SHristo Hristov   // Shorter list
205bc47a195SHristo Hristov   {
2066614d36dSHristo Hristov     Container<Key, Val, Compare> l1{{{1, 1}}, comp};
2076614d36dSHristo Hristov     Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
208bc47a195SHristo Hristov     assert(testOrder(l1, l2, Order::less));
209bc47a195SHristo Hristov   }
210bc47a195SHristo Hristov   // Longer list
211bc47a195SHristo Hristov   {
2126614d36dSHristo Hristov     Container<Key, Val, Compare> l1{{{1, 2}, {2, 2}}, comp};
2136614d36dSHristo Hristov     Container<Key, Val, Compare> l2{{{1, 1}}, comp};
214bc47a195SHristo Hristov     assert(testOrder(l1, l2, Order::greater));
215bc47a195SHristo Hristov   }
216bc47a195SHristo Hristov   // Unordered
217bc47a195SHristo Hristov   if constexpr (std::is_same_v<Val, PartialOrder>) {
2186614d36dSHristo Hristov     Container<Key, Val, Compare> l1{{{1, 1}, {2, std::numeric_limits<int>::min()}}, comp};
2196614d36dSHristo Hristov     Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
220bc47a195SHristo Hristov     assert(testOrder(l1, l2, Order::unordered));
221bc47a195SHristo Hristov   }
222bc47a195SHristo Hristov 
223bc47a195SHristo Hristov   // Identical contents
224bc47a195SHristo Hristov   {
2256614d36dSHristo Hristov     Container<Key, Val, Compare> l1{{{1, 1}, {2, 1}, {2, 2}}, comp};
2266614d36dSHristo Hristov     Container<Key, Val, Compare> l2{{{1, 1}, {2, 1}, {2, 2}}, comp};
227bc47a195SHristo Hristov     assert(testOrder(l1, l2, Order::equivalent));
2286614d36dSHristo Hristov 
2296614d36dSHristo Hristov     Container<Key, Val, Compare> l3{{{1, 1}, {2, 1}, {2, 2}}, comp};
2306614d36dSHristo Hristov     Container<Key, Val, Compare> l4{{{2, 1}, {2, 2}, {1, 1}}, comp};
231bc47a195SHristo Hristov     assert(testOrder(l3, l4, Order::equivalent));
232bc47a195SHristo Hristov   }
233bc47a195SHristo Hristov   // Less, due to contained values
234bc47a195SHristo Hristov   {
2356614d36dSHristo Hristov     Container<Key, Val, Compare> l1{{{1, 1}, {2, 1}, {2, 1}}, comp};
2366614d36dSHristo Hristov     Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}, {2, 2}}, comp};
237bc47a195SHristo Hristov     assert(testOrder(l1, l2, Order::less));
2386614d36dSHristo Hristov 
2396614d36dSHristo Hristov     Container<Key, Val, Compare> l3{{{1, 1}, {2, 1}, {2, 1}}, comp};
2406614d36dSHristo Hristov     Container<Key, Val, Compare> l4{{{2, 2}, {2, 2}, {1, 1}}, comp};
241bc47a195SHristo Hristov     assert(testOrder(l3, l4, Order::less));
242bc47a195SHristo Hristov   }
243bc47a195SHristo Hristov   // Greater, due to contained values
244bc47a195SHristo Hristov   {
2456614d36dSHristo Hristov     Container<Key, Val, Compare> l1{{{1, 1}, {2, 3}, {2, 3}}, comp};
2466614d36dSHristo Hristov     Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}, {2, 2}}, comp};
247bc47a195SHristo Hristov     assert(testOrder(l1, l2, Order::greater));
2486614d36dSHristo Hristov 
2496614d36dSHristo Hristov     Container<Key, Val, Compare> l3{{{1, 1}, {2, 3}, {2, 3}}, comp};
2506614d36dSHristo Hristov     Container<Key, Val, Compare> l4{{{2, 2}, {2, 2}, {1, 1}}, comp};
251bc47a195SHristo Hristov     assert(testOrder(l3, l4, Order::greater));
252bc47a195SHristo Hristov   }
253bc47a195SHristo Hristov   // Shorter list
254bc47a195SHristo Hristov   {
2556614d36dSHristo Hristov     Container<Key, Val, Compare> l1{{{1, 1}, {2, 2}}, comp};
2566614d36dSHristo Hristov     Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}, {2, 2}, {3, 1}}, comp};
257bc47a195SHristo Hristov     assert(testOrder(l1, l2, Order::less));
2586614d36dSHristo Hristov 
2596614d36dSHristo Hristov     Container<Key, Val, Compare> l3{{{1, 1}, {2, 2}}, comp};
2606614d36dSHristo Hristov     Container<Key, Val, Compare> l4{{{3, 1}, {2, 2}, {2, 2}, {1, 1}}, comp};
261bc47a195SHristo Hristov     assert(testOrder(l3, l4, Order::less));
262bc47a195SHristo Hristov   }
263bc47a195SHristo Hristov   // Longer list
264bc47a195SHristo Hristov   {
2656614d36dSHristo Hristov     Container<Key, Val, Compare> l1{{{1, 2}, {2, 2}, {2, 2}, {3, 1}}, comp};
2666614d36dSHristo Hristov     Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
267bc47a195SHristo Hristov     assert(testOrder(l1, l2, Order::greater));
2686614d36dSHristo Hristov 
2696614d36dSHristo Hristov     Container<Key, Val, Compare> l3{{{1, 2}, {2, 2}, {2, 2}, {3, 1}}, comp};
2706614d36dSHristo Hristov     Container<Key, Val, Compare> l4{{{2, 2}, {1, 1}}, comp};
271bc47a195SHristo Hristov     assert(testOrder(l3, l4, Order::greater));
272bc47a195SHristo Hristov   }
273bc47a195SHristo Hristov   // Unordered
274bc47a195SHristo Hristov   if constexpr (std::is_same_v<Val, PartialOrder>) {
2756614d36dSHristo Hristov     Container<Key, Val, Compare> l1{{{1, 1}, {2, std::numeric_limits<int>::min()}, {2, 3}}, comp};
2766614d36dSHristo Hristov     Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}, {2, 3}}, comp};
277bc47a195SHristo Hristov     assert(testOrder(l1, l2, Order::unordered));
2786614d36dSHristo Hristov 
2796614d36dSHristo Hristov     Container<Key, Val, Compare> l3{{{1, 1}, {2, std::numeric_limits<int>::min()}, {2, 3}}, comp};
2806614d36dSHristo Hristov     Container<Key, Val, Compare> l4{{{2, 3}, {2, 2}, {1, 1}}, comp};
281bc47a195SHristo Hristov     assert(testOrder(l3, l4, Order::unordered));
282bc47a195SHristo Hristov   }
283bc47a195SHristo Hristov }
284bc47a195SHristo Hristov 
285f8b5ac34SHristo Hristov // Tests the `operator<=>` on ordered map containers
286bc47a195SHristo Hristov template <template <typename...> typename Container>
test_ordered_map_container_spaceship()287bc47a195SHristo Hristov constexpr bool test_ordered_map_container_spaceship() {
2886614d36dSHristo Hristov   // Thanks to SFINAE, the following is not a compiler error but returns `false`
2896614d36dSHristo Hristov   struct NonComparable {};
2906614d36dSHristo Hristov   static_assert(!std::three_way_comparable<Container<int, NonComparable>>);
2916614d36dSHristo Hristov 
292254986d2SHristo Hristov   // The container should fulfill `std::three_way_comparable`
293bc47a195SHristo Hristov   static_assert(std::three_way_comparable<Container<int, int>>);
294bc47a195SHristo Hristov 
295bc47a195SHristo Hristov   // Test different comparison categories
2966614d36dSHristo Hristov   test_ordered_map_container_spaceship_with_type<Container, int, int, std::strong_ordering>(std::less{});
2976614d36dSHristo Hristov   test_ordered_map_container_spaceship_with_type<Container, int, int, std::strong_ordering>(std::greater{});
2986614d36dSHristo Hristov   test_ordered_map_container_spaceship_with_type<Container, int, StrongOrder, std::strong_ordering>(std::less{});
2996614d36dSHristo Hristov   test_ordered_map_container_spaceship_with_type<Container, int, StrongOrder, std::strong_ordering>(std::greater{});
3006614d36dSHristo Hristov   test_ordered_map_container_spaceship_with_type<Container, int, WeakOrder, std::weak_ordering>(std::less{});
3016614d36dSHristo Hristov   test_ordered_map_container_spaceship_with_type<Container, int, WeakOrder, std::weak_ordering>(std::greater{});
3026614d36dSHristo Hristov   test_ordered_map_container_spaceship_with_type<Container, int, PartialOrder, std::partial_ordering>(std ::less{});
3036614d36dSHristo Hristov   test_ordered_map_container_spaceship_with_type<Container, int, PartialOrder, std::partial_ordering>(std ::greater{});
304bc47a195SHristo Hristov 
305254986d2SHristo Hristov   // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
3066614d36dSHristo Hristov   test_ordered_map_container_spaceship_with_type<Container, int, LessAndEqComp, std::weak_ordering>(std::less{});
307bc47a195SHristo Hristov 
308bc47a195SHristo Hristov   return true;
309bc47a195SHristo Hristov }
310bc47a195SHristo Hristov 
311f8b5ac34SHristo Hristov // Implementation detail of `test_ordered_set_container_spaceship`
312f8b5ac34SHristo Hristov template <template <typename...> typename Container, typename Elem, typename Order, typename Compare>
test_ordered_set_spaceship_with_type(Compare comp)313f8b5ac34SHristo Hristov constexpr void test_ordered_set_spaceship_with_type(Compare comp) {
314f8b5ac34SHristo Hristov   // Empty containers
315f8b5ac34SHristo Hristov   {
316f8b5ac34SHristo Hristov     Container<Elem, Compare> l1{{}, comp};
317f8b5ac34SHristo Hristov     Container<Elem, Compare> l2{{}, comp};
318f8b5ac34SHristo Hristov     assert(testOrder(l1, l2, Order::equivalent));
319f8b5ac34SHristo Hristov   }
320f8b5ac34SHristo Hristov   // Identical contents
321f8b5ac34SHristo Hristov   {
322f8b5ac34SHristo Hristov     Container<Elem, Compare> l1{{1, 1, 2}, comp};
323f8b5ac34SHristo Hristov     Container<Elem, Compare> l2{{1, 1, 2}, comp};
324f8b5ac34SHristo Hristov     assert(testOrder(l1, l2, Order::equivalent));
325f8b5ac34SHristo Hristov   }
326f8b5ac34SHristo Hristov   // Less, due to contained values
327f8b5ac34SHristo Hristov   {
328f8b5ac34SHristo Hristov     Container<Elem, Compare> l1{{1, 1, 2, 3}, comp};
329f8b5ac34SHristo Hristov     Container<Elem, Compare> l2{{1, 2, 2, 4}, comp};
330f8b5ac34SHristo Hristov     assert(testOrder(l1, l2, Order::less));
331f8b5ac34SHristo Hristov   }
332f8b5ac34SHristo Hristov   // Greater, due to contained values
333f8b5ac34SHristo Hristov   {
334f8b5ac34SHristo Hristov     Container<Elem, Compare> l1{{1, 2, 2, 4}, comp};
335f8b5ac34SHristo Hristov     Container<Elem, Compare> l2{{1, 1, 2, 3}, comp};
336f8b5ac34SHristo Hristov     assert(testOrder(l1, l2, Order::greater));
337f8b5ac34SHristo Hristov   }
338f8b5ac34SHristo Hristov   // Shorter list
339f8b5ac34SHristo Hristov   {
340f8b5ac34SHristo Hristov     Container<Elem, Compare> l1{{1, 1, 2, 2}, comp};
341f8b5ac34SHristo Hristov     Container<Elem, Compare> l2{{1, 1, 2, 2, 3}, comp};
342f8b5ac34SHristo Hristov     assert(testOrder(l1, l2, Order::less));
343f8b5ac34SHristo Hristov   }
344f8b5ac34SHristo Hristov   // Longer list
345f8b5ac34SHristo Hristov   {
346f8b5ac34SHristo Hristov     Container<Elem, Compare> l1{{1, 1, 2, 2, 3}, comp};
347f8b5ac34SHristo Hristov     Container<Elem, Compare> l2{{1, 1, 2, 2}, comp};
348f8b5ac34SHristo Hristov     assert(testOrder(l1, l2, Order::greater));
349f8b5ac34SHristo Hristov   }
350f8b5ac34SHristo Hristov   // Unordered
351f8b5ac34SHristo Hristov   if constexpr (std::is_same_v< Container<Elem>, std::multiset<PartialOrder>>) {
352f8b5ac34SHristo Hristov     if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {
353f8b5ac34SHristo Hristov       Container<Elem, Compare> l1{{1, std::numeric_limits<int>::min()}, comp};
354f8b5ac34SHristo Hristov       Container<Elem, Compare> l2{{1, 2}, comp};
355f8b5ac34SHristo Hristov       assert(testOrder(l1, l2, Order::unordered));
356f8b5ac34SHristo Hristov     }
357f8b5ac34SHristo Hristov     if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {
358f8b5ac34SHristo Hristov       Container<Elem, Compare> l1{{1, std::numeric_limits<int>::max()}, comp};
359f8b5ac34SHristo Hristov       Container<Elem, Compare> l2{{1, 2}, comp};
360f8b5ac34SHristo Hristov       assert(testOrder(l1, l2, Order::unordered));
361f8b5ac34SHristo Hristov     }
362f8b5ac34SHristo Hristov   }
363f8b5ac34SHristo Hristov   if constexpr (std::is_same_v< Container<Elem>, std::set<PartialOrder>>) {
364*f5832babSStephan T. Lavavej     // Unordered values are not supported for `set`
365f8b5ac34SHristo Hristov     if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {
366f8b5ac34SHristo Hristov       Container<Elem, Compare> l1{{1, std::numeric_limits<int>::min()}, comp};
367f8b5ac34SHristo Hristov       Container<Elem, Compare> l2{{1, 2}, comp};
368f8b5ac34SHristo Hristov       assert(testOrder(l1, l2, Order::less));
369f8b5ac34SHristo Hristov     }
370f8b5ac34SHristo Hristov     if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {
371f8b5ac34SHristo Hristov       Container<Elem, Compare> l1{{1, std::numeric_limits<int>::max()}, comp};
372f8b5ac34SHristo Hristov       Container<Elem, Compare> l2{{1, 2}, comp};
373f8b5ac34SHristo Hristov       assert(testOrder(l1, l2, Order::less));
374f8b5ac34SHristo Hristov     }
375f8b5ac34SHristo Hristov   }
376f8b5ac34SHristo Hristov   if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::greater{})>) {
377f8b5ac34SHristo Hristov     Container<Elem, Compare> l1{{1, std::numeric_limits<int>::min()}, comp};
378f8b5ac34SHristo Hristov     Container<Elem, Compare> l2{{1, 2}, comp};
379f8b5ac34SHristo Hristov     assert(testOrder(l1, l2, Order::less));
380f8b5ac34SHristo Hristov   }
381f8b5ac34SHristo Hristov   if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::greater{})>) {
382f8b5ac34SHristo Hristov     Container<Elem, Compare> l1{{1, std::numeric_limits<int>::max()}, comp};
383f8b5ac34SHristo Hristov     Container<Elem, Compare> l2{{1, 2}, comp};
384f8b5ac34SHristo Hristov     assert(testOrder(l1, l2, Order::less));
385f8b5ac34SHristo Hristov   }
386f8b5ac34SHristo Hristov }
387f8b5ac34SHristo Hristov 
388f8b5ac34SHristo Hristov // Tests the `operator<=>` on ordered set containers
389f8b5ac34SHristo Hristov template <template <typename...> typename Container>
test_ordered_set_container_spaceship()390f8b5ac34SHristo Hristov constexpr bool test_ordered_set_container_spaceship() {
391f8b5ac34SHristo Hristov   // Thanks to SFINAE, the following is not a compiler error but returns `false`
392f8b5ac34SHristo Hristov   struct NonComparable {};
393f8b5ac34SHristo Hristov   static_assert(!std::three_way_comparable<Container<NonComparable>>);
394f8b5ac34SHristo Hristov 
395f8b5ac34SHristo Hristov   // The container should fulfill `std::three_way_comparable`
396f8b5ac34SHristo Hristov   static_assert(std::three_way_comparable<Container<int>>);
397f8b5ac34SHristo Hristov 
398f8b5ac34SHristo Hristov   // Test different comparison categories
399f8b5ac34SHristo Hristov   test_ordered_set_spaceship_with_type<Container, int, std::strong_ordering>(std::less{});
400f8b5ac34SHristo Hristov   test_ordered_set_spaceship_with_type<Container, int, std::strong_ordering>(std::greater{});
401f8b5ac34SHristo Hristov   test_ordered_set_spaceship_with_type<Container, StrongOrder, std::strong_ordering>(std::less{});
402f8b5ac34SHristo Hristov   test_ordered_set_spaceship_with_type<Container, StrongOrder, std::strong_ordering>(std::greater{});
403f8b5ac34SHristo Hristov   test_ordered_set_spaceship_with_type<Container, WeakOrder, std::weak_ordering>(std::less{});
404f8b5ac34SHristo Hristov   test_ordered_set_spaceship_with_type<Container, WeakOrder, std::weak_ordering>(std::greater{});
405f8b5ac34SHristo Hristov   test_ordered_set_spaceship_with_type<Container, PartialOrder, std::partial_ordering>(std::less{});
406f8b5ac34SHristo Hristov   test_ordered_set_spaceship_with_type<Container, PartialOrder, std::partial_ordering>(std::greater{});
407f8b5ac34SHristo Hristov 
408f8b5ac34SHristo Hristov   // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
409f8b5ac34SHristo Hristov   test_ordered_set_spaceship_with_type<Container, LessAndEqComp, std::weak_ordering>(std::less{});
410f8b5ac34SHristo Hristov 
411f8b5ac34SHristo Hristov   return true;
412f8b5ac34SHristo Hristov }
413f8b5ac34SHristo Hristov 
414b5a84ae0SAdrian Vogelsgesang #endif
415