473 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8// Utility functions to test comparisons on containers.9 10#ifndef TEST_CONTAINER_COMPARISONS11#define TEST_CONTAINER_COMPARISONS12 13#include <functional>14#include <set>15 16#include "test_allocator.h"17#include "test_comparisons.h"18 19// Implementation detail of `test_sequence_container_spaceship`20template <template <typename...> typename Container, typename Elem, typename Allocator, typename Order>21constexpr void test_sequence_container_spaceship_with_type() {22 // Empty containers23 {24 Container<Elem, Allocator> l1;25 Container<Elem, Allocator> l2;26 assert(testOrder(l1, l2, Order::equivalent));27 }28 // Identical contents29 {30 Container<Elem, Allocator> l1{1, 1};31 Container<Elem, Allocator> l2{1, 1};32 assert(testOrder(l1, l2, Order::equivalent));33 }34 // Less, due to contained values35 {36 Container<Elem, Allocator> l1{1, 1};37 Container<Elem, Allocator> l2{1, 2};38 assert(testOrder(l1, l2, Order::less));39 }40 // Greater, due to contained values41 {42 Container<Elem, Allocator> l1{1, 3};43 Container<Elem, Allocator> l2{1, 2};44 assert(testOrder(l1, l2, Order::greater));45 }46 // Shorter list47 {48 Container<Elem, Allocator> l1{1};49 Container<Elem, Allocator> l2{1, 2};50 assert(testOrder(l1, l2, Order::less));51 }52 // Longer list53 {54 Container<Elem, Allocator> l1{1, 2};55 Container<Elem, Allocator> l2{1};56 assert(testOrder(l1, l2, Order::greater));57 }58 // Unordered59 if constexpr (std::is_same_v<Elem, PartialOrder>) {60 Container<Elem, Allocator> l1{1, std::numeric_limits<int>::min()};61 Container<Elem, Allocator> l2{1, 2};62 assert(testOrder(l1, l2, Order::unordered));63 }64}65 66// Tests the `operator<=>` on sequence containers67template <template <typename...> typename Container>68constexpr bool test_sequence_container_spaceship() {69 // The container should fulfill `std::three_way_comparable`70 static_assert(std::three_way_comparable<Container<int>>);71 72 // Test different comparison categories73 test_sequence_container_spaceship_with_type<Container, int, std::allocator<int>, std::strong_ordering>();74 test_sequence_container_spaceship_with_type<Container,75 StrongOrder,76 test_allocator<StrongOrder>,77 std::strong_ordering>();78 test_sequence_container_spaceship_with_type<Container, WeakOrder, std::allocator<WeakOrder>, std::weak_ordering>();79 test_sequence_container_spaceship_with_type<Container,80 PartialOrder,81 test_allocator<PartialOrder>,82 std::partial_ordering>();83 84 // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`85 test_sequence_container_spaceship_with_type<Container,86 LessAndEqComp,87 std::allocator<LessAndEqComp>,88 std::weak_ordering>();89 90 // Thanks to SFINAE, the following is not a compiler error but returns `false`91 static_assert(!std::three_way_comparable<Container<NonComparable>>);92 93 return true;94}95 96// Implementation detail of `test_sequence_container_adaptor_spaceship`97template <template <typename...> typename ContainerAdaptor,98 template <typename...>99 typename Container,100 typename Elem,101 typename Order>102constexpr void test_sequence_container_adaptor_spaceship_with_type() {103 // Empty containers104 {105 Container<Elem> l1;106 ContainerAdaptor<Elem, Container<Elem>> ca1{l1};107 Container<Elem> l2;108 ContainerAdaptor<Elem, Container<Elem>> ca2{l2};109 assert(testOrder(ca1, ca2, Order::equivalent));110 }111 // Identical contents112 {113 Container<Elem> l1{1, 1};114 ContainerAdaptor<Elem, Container<Elem>> ca1{l1};115 Container<Elem> l2{1, 1};116 ContainerAdaptor<Elem, Container<Elem>> ca2{l2};117 assert(testOrder(ca1, ca2, Order::equivalent));118 }119 // Less, due to contained values120 {121 Container<Elem> l1{1, 1};122 ContainerAdaptor<Elem, Container<Elem>> ca1{l1};123 Container<Elem> l2{1, 2};124 ContainerAdaptor<Elem, Container<Elem>> ca2{l2};125 assert(testOrder(ca1, ca2, Order::less));126 }127 // Greater, due to contained values128 {129 Container<Elem> l1{1, 3};130 ContainerAdaptor<Elem, Container<Elem>> ca1{l1};131 Container<Elem> l2{1, 2};132 ContainerAdaptor<Elem, Container<Elem>> ca2{l2};133 assert(testOrder(ca1, ca2, Order::greater));134 }135 // Shorter list136 {137 Container<Elem> l1{1};138 ContainerAdaptor<Elem, Container<Elem>> ca1{l1};139 Container<Elem> l2{1, 2};140 ContainerAdaptor<Elem, Container<Elem>> ca2{l2};141 assert(testOrder(ca1, ca2, Order::less));142 }143 // Longer list144 {145 Container<Elem> l1{1, 2};146 ContainerAdaptor<Elem, Container<Elem>> ca1{l1};147 Container<Elem> l2{1};148 ContainerAdaptor<Elem, Container<Elem>> ca2{l2};149 assert(testOrder(ca1, ca2, Order::greater));150 }151 // Unordered152 if constexpr (std::is_same_v<Elem, PartialOrder>) {153 Container<Elem> l1{1, std::numeric_limits<int>::min()};154 ContainerAdaptor<Elem, Container<Elem>> ca1{l1};155 Container<Elem> l2{1, 2};156 ContainerAdaptor<Elem, Container<Elem>> ca2{l2};157 assert(testOrder(ca1, ca2, Order::unordered));158 }159}160 161// Tests the `operator<=>` on sequence container adaptors162template <template <typename...> typename ContainerAdaptor, template <typename...> typename Container>163constexpr bool test_sequence_container_adaptor_spaceship() {164 // Thanks to SFINAE, the following is not a compiler error but returns `false`165 static_assert(!std::three_way_comparable<ContainerAdaptor<NonComparable>>);166 167 // The container should fulfill `std::three_way_comparable`168 static_assert(std::three_way_comparable<ContainerAdaptor<int, Container<int>>>);169 170 // Test different comparison categories171 test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, int, std::strong_ordering>();172 test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, StrongOrder, std::strong_ordering>();173 test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, WeakOrder, std::weak_ordering>();174 test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor,175 Container,176 PartialOrder,177 std::partial_ordering>();178 179 // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`180 test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, LessAndEqComp, std::weak_ordering>();181 182 return true;183}184 185// Implementation detail of `test_ordered_map_container_spaceship`186template <template <typename...> typename Container,187 typename Key,188 typename Val,189 typename Allocator,190 typename Order,191 typename Compare>192constexpr void test_ordered_map_container_spaceship_with_type(Compare comp) {193 // Empty containers194 {195 Container<Key, Val, Compare, Allocator> l1{{}, comp};196 Container<Key, Val, Compare, Allocator> l2{{}, comp};197 assert(testOrder(l1, l2, Order::equivalent));198 }199 // Identical contents200 {201 Container<Key, Val, Compare, Allocator> l1{{{1, 1}, {2, 1}}, comp};202 Container<Key, Val, Compare, Allocator> l2{{{1, 1}, {2, 1}}, comp};203 assert(testOrder(l1, l2, Order::equivalent));204 }205 // Less, due to contained values206 {207 Container<Key, Val, Compare, Allocator> l1{{{1, 1}, {2, 1}}, comp};208 Container<Key, Val, Compare, Allocator> l2{{{1, 1}, {2, 2}}, comp};209 assert(testOrder(l1, l2, Order::less));210 }211 // Greater, due to contained values212 {213 Container<Key, Val, Compare, Allocator> l1{{{1, 1}, {2, 3}}, comp};214 Container<Key, Val, Compare, Allocator> l2{{{1, 1}, {2, 2}}, comp};215 assert(testOrder(l1, l2, Order::greater));216 }217 // Shorter list218 {219 Container<Key, Val, Compare, Allocator> l1{{{1, 1}}, comp};220 Container<Key, Val, Compare, Allocator> l2{{{1, 1}, {2, 2}}, comp};221 assert(testOrder(l1, l2, Order::less));222 }223 // Longer list224 {225 Container<Key, Val, Compare, Allocator> l1{{{1, 2}, {2, 2}}, comp};226 Container<Key, Val, Compare, Allocator> l2{{{1, 1}}, comp};227 assert(testOrder(l1, l2, Order::greater));228 }229 // Unordered230 if constexpr (std::is_same_v<Val, PartialOrder>) {231 Container<Key, Val, Compare, Allocator> l1{{{1, 1}, {2, std::numeric_limits<int>::min()}}, comp};232 Container<Key, Val, Compare, Allocator> l2{{{1, 1}, {2, 2}}, comp};233 assert(testOrder(l1, l2, Order::unordered));234 }235 236 // Identical contents237 {238 Container<Key, Val, Compare, Allocator> l1{{{1, 1}, {2, 1}, {2, 2}}, comp};239 Container<Key, Val, Compare, Allocator> l2{{{1, 1}, {2, 1}, {2, 2}}, comp};240 assert(testOrder(l1, l2, Order::equivalent));241 242 Container<Key, Val, Compare, Allocator> l3{{{1, 1}, {2, 1}, {2, 2}}, comp};243 Container<Key, Val, Compare, Allocator> l4{{{2, 1}, {2, 2}, {1, 1}}, comp};244 assert(testOrder(l3, l4, Order::equivalent));245 }246 // Less, due to contained values247 {248 Container<Key, Val, Compare, Allocator> l1{{{1, 1}, {2, 1}, {2, 1}}, comp};249 Container<Key, Val, Compare, Allocator> l2{{{1, 1}, {2, 2}, {2, 2}}, comp};250 assert(testOrder(l1, l2, Order::less));251 252 Container<Key, Val, Compare, Allocator> l3{{{1, 1}, {2, 1}, {2, 1}}, comp};253 Container<Key, Val, Compare, Allocator> l4{{{2, 2}, {2, 2}, {1, 1}}, comp};254 assert(testOrder(l3, l4, Order::less));255 }256 // Greater, due to contained values257 {258 Container<Key, Val, Compare, Allocator> l1{{{1, 1}, {2, 3}, {2, 3}}, comp};259 Container<Key, Val, Compare, Allocator> l2{{{1, 1}, {2, 2}, {2, 2}}, comp};260 assert(testOrder(l1, l2, Order::greater));261 262 Container<Key, Val, Compare, Allocator> l3{{{1, 1}, {2, 3}, {2, 3}}, comp};263 Container<Key, Val, Compare, Allocator> l4{{{2, 2}, {2, 2}, {1, 1}}, comp};264 assert(testOrder(l3, l4, Order::greater));265 }266 // Shorter list267 {268 Container<Key, Val, Compare, Allocator> l1{{{1, 1}, {2, 2}}, comp};269 Container<Key, Val, Compare, Allocator> l2{{{1, 1}, {2, 2}, {2, 2}, {3, 1}}, comp};270 assert(testOrder(l1, l2, Order::less));271 272 Container<Key, Val, Compare, Allocator> l3{{{1, 1}, {2, 2}}, comp};273 Container<Key, Val, Compare, Allocator> l4{{{3, 1}, {2, 2}, {2, 2}, {1, 1}}, comp};274 assert(testOrder(l3, l4, Order::less));275 }276 // Longer list277 {278 Container<Key, Val, Compare, Allocator> l1{{{1, 2}, {2, 2}, {2, 2}, {3, 1}}, comp};279 Container<Key, Val, Compare, Allocator> l2{{{1, 1}, {2, 2}}, comp};280 assert(testOrder(l1, l2, Order::greater));281 282 Container<Key, Val, Compare, Allocator> l3{{{1, 2}, {2, 2}, {2, 2}, {3, 1}}, comp};283 Container<Key, Val, Compare, Allocator> l4{{{2, 2}, {1, 1}}, comp};284 assert(testOrder(l3, l4, Order::greater));285 }286 // Unordered287 if constexpr (std::is_same_v<Val, PartialOrder>) {288 Container<Key, Val, Compare, Allocator> l1{{{1, 1}, {2, std::numeric_limits<int>::min()}, {2, 3}}, comp};289 Container<Key, Val, Compare, Allocator> l2{{{1, 1}, {2, 2}, {2, 3}}, comp};290 assert(testOrder(l1, l2, Order::unordered));291 292 Container<Key, Val, Compare, Allocator> l3{{{1, 1}, {2, std::numeric_limits<int>::min()}, {2, 3}}, comp};293 Container<Key, Val, Compare, Allocator> l4{{{2, 3}, {2, 2}, {1, 1}}, comp};294 assert(testOrder(l3, l4, Order::unordered));295 }296}297 298// Tests the `operator<=>` on ordered map containers299template <template <typename...> typename Container>300constexpr bool test_ordered_map_container_spaceship() {301 // Thanks to SFINAE, the following is not a compiler error but returns `false`302 static_assert(!std::three_way_comparable<Container<int, NonComparable>>);303 304 // The container should fulfill `std::three_way_comparable`305 static_assert(std::three_way_comparable<Container<int, int>>);306 307 // Test different comparison categories308 test_ordered_map_container_spaceship_with_type<Container,309 int,310 int,311 std::allocator<std::pair<const int, int>>,312 std::strong_ordering>(std::less{});313 test_ordered_map_container_spaceship_with_type<Container,314 int,315 int,316 test_allocator<std::pair<const int, int>>,317 std::strong_ordering>(std::greater{});318 test_ordered_map_container_spaceship_with_type<Container,319 int,320 StrongOrder,321 std::allocator<std::pair<const int, StrongOrder>>,322 std::strong_ordering>(std::less{});323 test_ordered_map_container_spaceship_with_type<Container,324 int,325 StrongOrder,326 test_allocator<std::pair<const int, StrongOrder>>,327 std::strong_ordering>(std::greater{});328 test_ordered_map_container_spaceship_with_type<Container,329 int,330 WeakOrder,331 std::allocator<std::pair<const int, WeakOrder>>,332 std::weak_ordering>(std::less{});333 test_ordered_map_container_spaceship_with_type<Container,334 int,335 WeakOrder,336 test_allocator<std::pair<const int, WeakOrder>>,337 std::weak_ordering>(std::greater{});338 test_ordered_map_container_spaceship_with_type<Container,339 int,340 PartialOrder,341 std::allocator<std::pair<const int, PartialOrder>>,342 std::partial_ordering>(std ::less{});343 test_ordered_map_container_spaceship_with_type<Container,344 int,345 PartialOrder,346 test_allocator<std::pair<const int, PartialOrder>>,347 std::partial_ordering>(std ::greater{});348 349 // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`350 test_ordered_map_container_spaceship_with_type<Container,351 int,352 LessAndEqComp,353 std::allocator<std::pair<const int, LessAndEqComp>>,354 std::weak_ordering>(std::less{});355 356 return true;357}358 359// Implementation detail of `test_ordered_set_container_spaceship`360template <template <typename...> typename Container,361 typename Elem,362 typename Allocator,363 typename Order,364 typename Compare>365constexpr void test_ordered_set_spaceship_with_type(Compare comp) {366 // Empty containers367 {368 Container<Elem, Compare, Allocator> l1{{}, comp};369 Container<Elem, Compare, Allocator> l2{{}, comp};370 assert(testOrder(l1, l2, Order::equivalent));371 }372 // Identical contents373 {374 Container<Elem, Compare, Allocator> l1{{1, 1, 2}, comp};375 Container<Elem, Compare, Allocator> l2{{1, 1, 2}, comp};376 assert(testOrder(l1, l2, Order::equivalent));377 }378 // Less, due to contained values379 {380 Container<Elem, Compare, Allocator> l1{{1, 1, 2, 3}, comp};381 Container<Elem, Compare, Allocator> l2{{1, 2, 2, 4}, comp};382 assert(testOrder(l1, l2, Order::less));383 }384 // Greater, due to contained values385 {386 Container<Elem, Compare, Allocator> l1{{1, 2, 2, 4}, comp};387 Container<Elem, Compare, Allocator> l2{{1, 1, 2, 3}, comp};388 assert(testOrder(l1, l2, Order::greater));389 }390 // Shorter list391 {392 Container<Elem, Compare, Allocator> l1{{1, 1, 2, 2}, comp};393 Container<Elem, Compare, Allocator> l2{{1, 1, 2, 2, 3}, comp};394 assert(testOrder(l1, l2, Order::less));395 }396 // Longer list397 {398 Container<Elem, Compare, Allocator> l1{{1, 1, 2, 2, 3}, comp};399 Container<Elem, Compare, Allocator> l2{{1, 1, 2, 2}, comp};400 assert(testOrder(l1, l2, Order::greater));401 }402 // Unordered403 if constexpr (std::is_same_v< Container<Elem>, std::multiset<PartialOrder>>) {404 if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {405 Container<Elem, Compare, Allocator> l1{{1, std::numeric_limits<int>::min()}, comp};406 Container<Elem, Compare, Allocator> l2{{1, 2}, comp};407 assert(testOrder(l1, l2, Order::unordered));408 }409 if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {410 Container<Elem, Compare, Allocator> l1{{1, std::numeric_limits<int>::max()}, comp};411 Container<Elem, Compare, Allocator> l2{{1, 2}, comp};412 assert(testOrder(l1, l2, Order::unordered));413 }414 }415 if constexpr (std::is_same_v< Container<Elem>, std::set<PartialOrder>>) {416 // Unordered values are not supported for `set`417 if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {418 Container<Elem, Compare, Allocator> l1{{1, std::numeric_limits<int>::min()}, comp};419 Container<Elem, Compare, Allocator> l2{{1, 2}, comp};420 assert(testOrder(l1, l2, Order::less));421 }422 if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::less{})>) {423 Container<Elem, Compare, Allocator> l1{{1, std::numeric_limits<int>::max()}, comp};424 Container<Elem, Compare, Allocator> l2{{1, 2}, comp};425 assert(testOrder(l1, l2, Order::less));426 }427 }428 if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::greater{})>) {429 Container<Elem, Compare, Allocator> l1{{1, std::numeric_limits<int>::min()}, comp};430 Container<Elem, Compare, Allocator> l2{{1, 2}, comp};431 assert(testOrder(l1, l2, Order::less));432 }433 if constexpr (std::is_same_v<Elem, PartialOrder> && std::is_same_v<Compare, decltype(std::greater{})>) {434 Container<Elem, Compare, Allocator> l1{{1, std::numeric_limits<int>::max()}, comp};435 Container<Elem, Compare, Allocator> l2{{1, 2}, comp};436 assert(testOrder(l1, l2, Order::less));437 }438}439 440// Tests the `operator<=>` on ordered set containers441template <template <typename...> typename Container>442constexpr bool test_ordered_set_container_spaceship() {443 // Thanks to SFINAE, the following is not a compiler error but returns `false`444 static_assert(!std::three_way_comparable<Container<NonComparable>>);445 446 // The container should fulfill `std::three_way_comparable`447 static_assert(std::three_way_comparable<Container<int>>);448 449 // Test different comparison categories450 test_ordered_set_spaceship_with_type<Container, int, std::allocator<int>, std::strong_ordering>(std::less{});451 test_ordered_set_spaceship_with_type<Container, int, test_allocator<int>, std::strong_ordering>(std::greater{});452 test_ordered_set_spaceship_with_type<Container, StrongOrder, std::allocator<StrongOrder>, std::strong_ordering>(453 std::less{});454 test_ordered_set_spaceship_with_type<Container, StrongOrder, test_allocator<StrongOrder>, std::strong_ordering>(455 std::greater{});456 test_ordered_set_spaceship_with_type<Container, WeakOrder, std::allocator<WeakOrder>, std::weak_ordering>(457 std::less{});458 test_ordered_set_spaceship_with_type<Container, WeakOrder, test_allocator<WeakOrder>, std::weak_ordering>(459 std::greater{});460 test_ordered_set_spaceship_with_type<Container, PartialOrder, std::allocator<PartialOrder>, std::partial_ordering>(461 std::less{});462 test_ordered_set_spaceship_with_type<Container, PartialOrder, test_allocator<PartialOrder>, std::partial_ordering>(463 std::greater{});464 465 // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`466 test_ordered_set_spaceship_with_type<Container, LessAndEqComp, std::allocator<LessAndEqComp>, std::weak_ordering>(467 std::less{});468 469 return true;470}471 472#endif473