1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 // Utility functions to test comparisons on containers.
9
10 #ifndef TEST_CONTAINER_COMPARISONS
11 #define TEST_CONTAINER_COMPARISONS
12
13 #include <functional>
14 #include <set>
15
16 #include "test_comparisons.h"
17
18 // Implementation detail of `test_sequence_container_spaceship`
19 template <template <typename...> typename Container, typename Elem, typename Order>
test_sequence_container_spaceship_with_type()20 constexpr void test_sequence_container_spaceship_with_type() {
21 // Empty containers
22 {
23 Container<Elem> l1;
24 Container<Elem> l2;
25 assert(testOrder(l1, l2, Order::equivalent));
26 }
27 // Identical contents
28 {
29 Container<Elem> l1{1, 1};
30 Container<Elem> l2{1, 1};
31 assert(testOrder(l1, l2, Order::equivalent));
32 }
33 // Less, due to contained values
34 {
35 Container<Elem> l1{1, 1};
36 Container<Elem> l2{1, 2};
37 assert(testOrder(l1, l2, Order::less));
38 }
39 // Greater, due to contained values
40 {
41 Container<Elem> l1{1, 3};
42 Container<Elem> l2{1, 2};
43 assert(testOrder(l1, l2, Order::greater));
44 }
45 // Shorter list
46 {
47 Container<Elem> l1{1};
48 Container<Elem> l2{1, 2};
49 assert(testOrder(l1, l2, Order::less));
50 }
51 // Longer list
52 {
53 Container<Elem> l1{1, 2};
54 Container<Elem> l2{1};
55 assert(testOrder(l1, l2, Order::greater));
56 }
57 // Unordered
58 if constexpr (std::is_same_v<Elem, PartialOrder>) {
59 Container<Elem> l1{1, std::numeric_limits<int>::min()};
60 Container<Elem> l2{1, 2};
61 assert(testOrder(l1, l2, Order::unordered));
62 }
63 }
64
65 // Tests the `operator<=>` on sequence containers
66 template <template <typename...> typename Container>
test_sequence_container_spaceship()67 constexpr bool test_sequence_container_spaceship() {
68 // The container should fulfill `std::three_way_comparable`
69 static_assert(std::three_way_comparable<Container<int>>);
70
71 // Test different comparison categories
72 test_sequence_container_spaceship_with_type<Container, int, std::strong_ordering>();
73 test_sequence_container_spaceship_with_type<Container, StrongOrder, std::strong_ordering>();
74 test_sequence_container_spaceship_with_type<Container, WeakOrder, std::weak_ordering>();
75 test_sequence_container_spaceship_with_type<Container, PartialOrder, std::partial_ordering>();
76
77 // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
78 test_sequence_container_spaceship_with_type<Container, LessAndEqComp, std::weak_ordering>();
79
80 // Thanks to SFINAE, the following is not a compiler error but returns `false`
81 struct NonComparable {};
82 static_assert(!std::three_way_comparable<Container<NonComparable>>);
83
84 return true;
85 }
86
87 // Implementation detail of `test_sequence_container_adaptor_spaceship`
88 template <template <typename...> typename ContainerAdaptor,
89 template <typename...>
90 typename Container,
91 typename Elem,
92 typename Order>
test_sequence_container_adaptor_spaceship_with_type()93 constexpr void test_sequence_container_adaptor_spaceship_with_type() {
94 // Empty containers
95 {
96 Container<Elem> l1;
97 ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
98 Container<Elem> l2;
99 ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
100 assert(testOrder(ca1, ca2, Order::equivalent));
101 }
102 // Identical contents
103 {
104 Container<Elem> l1{1, 1};
105 ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
106 Container<Elem> l2{1, 1};
107 ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
108 assert(testOrder(ca1, ca2, Order::equivalent));
109 }
110 // Less, due to contained values
111 {
112 Container<Elem> l1{1, 1};
113 ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
114 Container<Elem> l2{1, 2};
115 ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
116 assert(testOrder(ca1, ca2, Order::less));
117 }
118 // Greater, due to contained values
119 {
120 Container<Elem> l1{1, 3};
121 ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
122 Container<Elem> l2{1, 2};
123 ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
124 assert(testOrder(ca1, ca2, Order::greater));
125 }
126 // Shorter list
127 {
128 Container<Elem> l1{1};
129 ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
130 Container<Elem> l2{1, 2};
131 ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
132 assert(testOrder(ca1, ca2, Order::less));
133 }
134 // Longer list
135 {
136 Container<Elem> l1{1, 2};
137 ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
138 Container<Elem> l2{1};
139 ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
140 assert(testOrder(ca1, ca2, Order::greater));
141 }
142 // Unordered
143 if constexpr (std::is_same_v<Elem, PartialOrder>) {
144 Container<Elem> l1{1, std::numeric_limits<int>::min()};
145 ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
146 Container<Elem> l2{1, 2};
147 ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
148 assert(testOrder(ca1, ca2, Order::unordered));
149 }
150 }
151
152 // Tests the `operator<=>` on sequence container adaptors
153 template <template <typename...> typename ContainerAdaptor, template <typename...> typename Container>
test_sequence_container_adaptor_spaceship()154 constexpr bool test_sequence_container_adaptor_spaceship() {
155 // Thanks to SFINAE, the following is not a compiler error but returns `false`
156 struct NonComparable {};
157 static_assert(!std::three_way_comparable<ContainerAdaptor<NonComparable>>);
158
159 // The container should fulfill `std::three_way_comparable`
160 static_assert(std::three_way_comparable<ContainerAdaptor<int, Container<int>>>);
161
162 // Test different comparison categories
163 test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, int, std::strong_ordering>();
164 test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, StrongOrder, std::strong_ordering>();
165 test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, WeakOrder, std::weak_ordering>();
166 test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor,
167 Container,
168 PartialOrder,
169 std::partial_ordering>();
170
171 // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
172 test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, LessAndEqComp, std::weak_ordering>();
173
174 return true;
175 }
176
177 // Implementation detail of `test_ordered_map_container_spaceship`
178 template <template <typename...> typename Container, typename Key, typename Val, typename Order, typename Compare>
test_ordered_map_container_spaceship_with_type(Compare comp)179 constexpr void test_ordered_map_container_spaceship_with_type(Compare comp) {
180 // Empty containers
181 {
182 Container<Key, Val, Compare> l1{{}, comp};
183 Container<Key, Val, Compare> l2{{}, comp};
184 assert(testOrder(l1, l2, Order::equivalent));
185 }
186 // Identical contents
187 {
188 Container<Key, Val, Compare> l1{{{1, 1}, {2, 1}}, comp};
189 Container<Key, Val, Compare> l2{{{1, 1}, {2, 1}}, comp};
190 assert(testOrder(l1, l2, Order::equivalent));
191 }
192 // Less, due to contained values
193 {
194 Container<Key, Val, Compare> l1{{{1, 1}, {2, 1}}, comp};
195 Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
196 assert(testOrder(l1, l2, Order::less));
197 }
198 // Greater, due to contained values
199 {
200 Container<Key, Val, Compare> l1{{{1, 1}, {2, 3}}, comp};
201 Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
202 assert(testOrder(l1, l2, Order::greater));
203 }
204 // Shorter list
205 {
206 Container<Key, Val, Compare> l1{{{1, 1}}, comp};
207 Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
208 assert(testOrder(l1, l2, Order::less));
209 }
210 // Longer list
211 {
212 Container<Key, Val, Compare> l1{{{1, 2}, {2, 2}}, comp};
213 Container<Key, Val, Compare> l2{{{1, 1}}, comp};
214 assert(testOrder(l1, l2, Order::greater));
215 }
216 // Unordered
217 if constexpr (std::is_same_v<Val, PartialOrder>) {
218 Container<Key, Val, Compare> l1{{{1, 1}, {2, std::numeric_limits<int>::min()}}, comp};
219 Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
220 assert(testOrder(l1, l2, Order::unordered));
221 }
222
223 // Identical contents
224 {
225 Container<Key, Val, Compare> l1{{{1, 1}, {2, 1}, {2, 2}}, comp};
226 Container<Key, Val, Compare> l2{{{1, 1}, {2, 1}, {2, 2}}, comp};
227 assert(testOrder(l1, l2, Order::equivalent));
228
229 Container<Key, Val, Compare> l3{{{1, 1}, {2, 1}, {2, 2}}, comp};
230 Container<Key, Val, Compare> l4{{{2, 1}, {2, 2}, {1, 1}}, comp};
231 assert(testOrder(l3, l4, Order::equivalent));
232 }
233 // Less, due to contained values
234 {
235 Container<Key, Val, Compare> l1{{{1, 1}, {2, 1}, {2, 1}}, comp};
236 Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}, {2, 2}}, comp};
237 assert(testOrder(l1, l2, Order::less));
238
239 Container<Key, Val, Compare> l3{{{1, 1}, {2, 1}, {2, 1}}, comp};
240 Container<Key, Val, Compare> l4{{{2, 2}, {2, 2}, {1, 1}}, comp};
241 assert(testOrder(l3, l4, Order::less));
242 }
243 // Greater, due to contained values
244 {
245 Container<Key, Val, Compare> l1{{{1, 1}, {2, 3}, {2, 3}}, comp};
246 Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}, {2, 2}}, comp};
247 assert(testOrder(l1, l2, Order::greater));
248
249 Container<Key, Val, Compare> l3{{{1, 1}, {2, 3}, {2, 3}}, comp};
250 Container<Key, Val, Compare> l4{{{2, 2}, {2, 2}, {1, 1}}, comp};
251 assert(testOrder(l3, l4, Order::greater));
252 }
253 // Shorter list
254 {
255 Container<Key, Val, Compare> l1{{{1, 1}, {2, 2}}, comp};
256 Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}, {2, 2}, {3, 1}}, comp};
257 assert(testOrder(l1, l2, Order::less));
258
259 Container<Key, Val, Compare> l3{{{1, 1}, {2, 2}}, comp};
260 Container<Key, Val, Compare> l4{{{3, 1}, {2, 2}, {2, 2}, {1, 1}}, comp};
261 assert(testOrder(l3, l4, Order::less));
262 }
263 // Longer list
264 {
265 Container<Key, Val, Compare> l1{{{1, 2}, {2, 2}, {2, 2}, {3, 1}}, comp};
266 Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
267 assert(testOrder(l1, l2, Order::greater));
268
269 Container<Key, Val, Compare> l3{{{1, 2}, {2, 2}, {2, 2}, {3, 1}}, comp};
270 Container<Key, Val, Compare> l4{{{2, 2}, {1, 1}}, comp};
271 assert(testOrder(l3, l4, Order::greater));
272 }
273 // Unordered
274 if constexpr (std::is_same_v<Val, PartialOrder>) {
275 Container<Key, Val, Compare> l1{{{1, 1}, {2, std::numeric_limits<int>::min()}, {2, 3}}, comp};
276 Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}, {2, 3}}, comp};
277 assert(testOrder(l1, l2, Order::unordered));
278
279 Container<Key, Val, Compare> l3{{{1, 1}, {2, std::numeric_limits<int>::min()}, {2, 3}}, comp};
280 Container<Key, Val, Compare> l4{{{2, 3}, {2, 2}, {1, 1}}, comp};
281 assert(testOrder(l3, l4, Order::unordered));
282 }
283 }
284
285 // Tests the `operator<=>` on ordered map containers
286 template <template <typename...> typename Container>
test_ordered_map_container_spaceship()287 constexpr bool test_ordered_map_container_spaceship() {
288 // Thanks to SFINAE, the following is not a compiler error but returns `false`
289 struct NonComparable {};
290 static_assert(!std::three_way_comparable<Container<int, NonComparable>>);
291
292 // The container should fulfill `std::three_way_comparable`
293 static_assert(std::three_way_comparable<Container<int, int>>);
294
295 // Test different comparison categories
296 test_ordered_map_container_spaceship_with_type<Container, int, int, std::strong_ordering>(std::less{});
297 test_ordered_map_container_spaceship_with_type<Container, int, int, std::strong_ordering>(std::greater{});
298 test_ordered_map_container_spaceship_with_type<Container, int, StrongOrder, std::strong_ordering>(std::less{});
299 test_ordered_map_container_spaceship_with_type<Container, int, StrongOrder, std::strong_ordering>(std::greater{});
300 test_ordered_map_container_spaceship_with_type<Container, int, WeakOrder, std::weak_ordering>(std::less{});
301 test_ordered_map_container_spaceship_with_type<Container, int, WeakOrder, std::weak_ordering>(std::greater{});
302 test_ordered_map_container_spaceship_with_type<Container, int, PartialOrder, std::partial_ordering>(std ::less{});
303 test_ordered_map_container_spaceship_with_type<Container, int, PartialOrder, std::partial_ordering>(std ::greater{});
304
305 // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
306 test_ordered_map_container_spaceship_with_type<Container, int, LessAndEqComp, std::weak_ordering>(std::less{});
307
308 return true;
309 }
310
311 // Implementation detail of `test_ordered_set_container_spaceship`
312 template <template <typename...> typename Container, typename Elem, typename Order, typename Compare>
test_ordered_set_spaceship_with_type(Compare comp)313 constexpr void test_ordered_set_spaceship_with_type(Compare comp) {
314 // Empty containers
315 {
316 Container<Elem, Compare> l1{{}, comp};
317 Container<Elem, Compare> l2{{}, comp};
318 assert(testOrder(l1, l2, Order::equivalent));
319 }
320 // Identical contents
321 {
322 Container<Elem, Compare> l1{{1, 1, 2}, comp};
323 Container<Elem, Compare> l2{{1, 1, 2}, comp};
324 assert(testOrder(l1, l2, Order::equivalent));
325 }
326 // Less, due to contained values
327 {
328 Container<Elem, Compare> l1{{1, 1, 2, 3}, comp};
329 Container<Elem, Compare> l2{{1, 2, 2, 4}, comp};
330 assert(testOrder(l1, l2, Order::less));
331 }
332 // Greater, due to contained values
333 {
334 Container<Elem, Compare> l1{{1, 2, 2, 4}, comp};
335 Container<Elem, Compare> l2{{1, 1, 2, 3}, comp};
336 assert(testOrder(l1, l2, Order::greater));
337 }
338 // Shorter list
339 {
340 Container<Elem, Compare> l1{{1, 1, 2, 2}, comp};
341 Container<Elem, Compare> l2{{1, 1, 2, 2, 3}, comp};
342 assert(testOrder(l1, l2, Order::less));
343 }
344 // Longer list
345 {
346 Container<Elem, Compare> l1{{1, 1, 2, 2, 3}, comp};
347 Container<Elem, Compare> l2{{1, 1, 2, 2}, comp};
348 assert(testOrder(l1, l2, Order::greater));
349 }
350 // Unordered
351 if constexpr (std::is_same_v< Container<Elem>, std::multiset<PartialOrder>>) {
352 if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {
353 Container<Elem, Compare> l1{{1, std::numeric_limits<int>::min()}, comp};
354 Container<Elem, Compare> l2{{1, 2}, comp};
355 assert(testOrder(l1, l2, Order::unordered));
356 }
357 if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {
358 Container<Elem, Compare> l1{{1, std::numeric_limits<int>::max()}, comp};
359 Container<Elem, Compare> l2{{1, 2}, comp};
360 assert(testOrder(l1, l2, Order::unordered));
361 }
362 }
363 if constexpr (std::is_same_v< Container<Elem>, std::set<PartialOrder>>) {
364 // Unordered values are not supported for `set`
365 if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {
366 Container<Elem, Compare> l1{{1, std::numeric_limits<int>::min()}, comp};
367 Container<Elem, Compare> l2{{1, 2}, comp};
368 assert(testOrder(l1, l2, Order::less));
369 }
370 if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {
371 Container<Elem, Compare> l1{{1, std::numeric_limits<int>::max()}, comp};
372 Container<Elem, Compare> l2{{1, 2}, comp};
373 assert(testOrder(l1, l2, Order::less));
374 }
375 }
376 if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::greater{})>) {
377 Container<Elem, Compare> l1{{1, std::numeric_limits<int>::min()}, comp};
378 Container<Elem, Compare> l2{{1, 2}, comp};
379 assert(testOrder(l1, l2, Order::less));
380 }
381 if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::greater{})>) {
382 Container<Elem, Compare> l1{{1, std::numeric_limits<int>::max()}, comp};
383 Container<Elem, Compare> l2{{1, 2}, comp};
384 assert(testOrder(l1, l2, Order::less));
385 }
386 }
387
388 // Tests the `operator<=>` on ordered set containers
389 template <template <typename...> typename Container>
test_ordered_set_container_spaceship()390 constexpr bool test_ordered_set_container_spaceship() {
391 // Thanks to SFINAE, the following is not a compiler error but returns `false`
392 struct NonComparable {};
393 static_assert(!std::three_way_comparable<Container<NonComparable>>);
394
395 // The container should fulfill `std::three_way_comparable`
396 static_assert(std::three_way_comparable<Container<int>>);
397
398 // Test different comparison categories
399 test_ordered_set_spaceship_with_type<Container, int, std::strong_ordering>(std::less{});
400 test_ordered_set_spaceship_with_type<Container, int, std::strong_ordering>(std::greater{});
401 test_ordered_set_spaceship_with_type<Container, StrongOrder, std::strong_ordering>(std::less{});
402 test_ordered_set_spaceship_with_type<Container, StrongOrder, std::strong_ordering>(std::greater{});
403 test_ordered_set_spaceship_with_type<Container, WeakOrder, std::weak_ordering>(std::less{});
404 test_ordered_set_spaceship_with_type<Container, WeakOrder, std::weak_ordering>(std::greater{});
405 test_ordered_set_spaceship_with_type<Container, PartialOrder, std::partial_ordering>(std::less{});
406 test_ordered_set_spaceship_with_type<Container, PartialOrder, std::partial_ordering>(std::greater{});
407
408 // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
409 test_ordered_set_spaceship_with_type<Container, LessAndEqComp, std::weak_ordering>(std::less{});
410
411 return true;
412 }
413
414 #endif
415