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 | |
9 | // <utility> |
10 | |
11 | // template <class T1, class T2> struct pair |
12 | |
13 | // template <class T1, class T2, class U1, class U2> |
14 | // constexpr common_comparison_category_t<synth-three-way-result<T1, U1>,synth-three-way-result<T2, U2>> |
15 | // operator<=>(const pair<T1,T2>&, const pair<U1,U2>&); |
16 | |
17 | // UNSUPPORTED: c++03, c++11, c++14, c++17 |
18 | |
19 | #include <cassert> |
20 | #include <compare> |
21 | #include <limits> |
22 | #include <type_traits> // std::is_constant_evaluated |
23 | #include <utility> |
24 | #include <string> |
25 | |
26 | #include "test_macros.h" |
27 | |
28 | template <class T> |
29 | concept HasEqual = requires(T t) { t == t; }; |
30 | template <class T> |
31 | concept HasLess = requires(T t) { t < t; }; |
32 | template <class T, class U = T> |
33 | concept HasSpaceship = requires(T t, U u) { t <=> u; }; |
34 | |
35 | constexpr bool test() { |
36 | { |
37 | // Pairs of different types should compare with strong ordering. |
38 | using P1 = std::pair<int, int>; |
39 | using P2 = std::pair<long long, long long>; |
40 | ASSERT_SAME_TYPE(decltype(P1() <=> P2()), std::strong_ordering); |
41 | assert((P1(1, 1) <=> P2(1, 2)) == std::strong_ordering::less); |
42 | assert((P1(2, 1) <=> P2(1, 2)) == std::strong_ordering::greater); |
43 | assert((P1(0, 0) <=> P2(0, 0)) == std::strong_ordering::equal); |
44 | } |
45 | { |
46 | // Pairs of different types should compare with partial ordering. |
47 | using P1 = std::pair<int, int>; |
48 | using P2 = std::pair<double, double>; |
49 | ASSERT_SAME_TYPE(decltype(P1() <=> P2()), std::partial_ordering); |
50 | assert((P1(1, 1) <=> P2(1.0, 2.0)) == std::partial_ordering::less); |
51 | assert((P1(2, 1) <=> P2(1.0, 2.0)) == std::partial_ordering::greater); |
52 | assert((P1(0, 0) <=> P2(0.0, 0.0)) == std::partial_ordering::equivalent); |
53 | } |
54 | { static_assert(!HasSpaceship<std::pair<int, int>, std::pair<std::string, int>>); } |
55 | { |
56 | // Pairs of types that both have strong ordering should compare with strong ordering. |
57 | using P = std::pair<int, int>; |
58 | ASSERT_SAME_TYPE(decltype(P() <=> P()), std::strong_ordering); |
59 | assert((P(1, 1) <=> P(1, 2)) == std::strong_ordering::less); |
60 | assert((P(2, 1) <=> P(1, 2)) == std::strong_ordering::greater); |
61 | assert((P(0, 0) <=> P(0, 0)) == std::strong_ordering::equal); |
62 | } |
63 | { |
64 | // Pairs of int and a type with no spaceship operator should compare with weak ordering. |
65 | struct NoSpaceship { |
66 | int value; |
67 | constexpr bool operator==(const NoSpaceship&) const = default; |
68 | constexpr bool operator<(const NoSpaceship& other) const { return value < other.value; } |
69 | }; |
70 | using P = std::pair<int, NoSpaceship>; |
71 | ASSERT_SAME_TYPE(decltype(P() <=> P()), std::weak_ordering); |
72 | assert((P(1, {1}) <=> P(1, {2})) == std::weak_ordering::less); |
73 | assert((P(2, {1}) <=> P(1, {2})) == std::weak_ordering::greater); |
74 | assert((P(0, {0}) <=> P(0, {0})) == std::weak_ordering::equivalent); |
75 | } |
76 | { |
77 | // Pairs of int (strongly ordered) and double (partially ordered) should compare with partial ordering. |
78 | using P = std::pair<int, double>; |
79 | constexpr double nan = std::numeric_limits<double>::quiet_NaN(); |
80 | ASSERT_SAME_TYPE(decltype(P() <=> P()), std::partial_ordering); |
81 | assert((P(1, 1.0) <=> P(1, 2.0)) == std::partial_ordering::less); |
82 | assert((P(1, 1.0) <=> P(1, 1.0)) == std::partial_ordering::equivalent); |
83 | assert((P(1, -0.0) <=> P(1, 0.0)) == std::partial_ordering::equivalent); |
84 | assert((P(1, 2.0) <=> P(1, 1.0)) == std::partial_ordering::greater); |
85 | assert((P(1, nan) <=> P(2, nan)) == std::partial_ordering::less); |
86 | assert((P(2, nan) <=> P(1, nan)) == std::partial_ordering::greater); |
87 | assert((P(1, nan) <=> P(1, nan)) == std::partial_ordering::unordered); |
88 | } |
89 | { |
90 | using P = std::pair<double, int>; |
91 | constexpr double nan = std::numeric_limits<double>::quiet_NaN(); |
92 | ASSERT_SAME_TYPE(decltype(P() <=> P()), std::partial_ordering); |
93 | assert((P(2.0, 1) <=> P(1.0, 2)) == std::partial_ordering::greater); |
94 | assert((P(1.0, 1) <=> P(1.0, 2)) == std::partial_ordering::less); |
95 | assert((P(nan, 1) <=> P(nan, 2)) == std::partial_ordering::unordered); |
96 | } |
97 | { |
98 | struct NoRelative { |
99 | constexpr bool operator==(const NoRelative&) const; |
100 | }; |
101 | static_assert(HasEqual<std::pair<int, NoRelative>>); |
102 | static_assert(!HasLess<std::pair<int, NoRelative>>); |
103 | static_assert(!HasSpaceship<std::pair<int, NoRelative>>); |
104 | } |
105 | { |
106 | struct NoLessThan { |
107 | constexpr bool operator==(const NoLessThan&) const; |
108 | constexpr bool operator>(const NoLessThan&) const; |
109 | }; |
110 | static_assert(HasEqual<std::pair<int, NoLessThan>>); |
111 | static_assert(!HasLess<std::pair<int, NoLessThan>>); |
112 | static_assert(!HasSpaceship<std::pair<int, NoLessThan>>); |
113 | } |
114 | |
115 | #ifdef TEST_COMPILER_GCC |
116 | // GCC cannot evaluate NaN @ non-NaN constexpr, so test that runtime-only. |
117 | if (!std::is_constant_evaluated()) |
118 | #endif |
119 | { |
120 | { |
121 | using P = std::pair<int, double>; |
122 | constexpr double nan = std::numeric_limits<double>::quiet_NaN(); |
123 | assert((P(1, 2.0) <=> P(1, nan)) == std::partial_ordering::unordered); |
124 | } |
125 | { |
126 | using P = std::pair<double, int>; |
127 | constexpr double nan = std::numeric_limits<double>::quiet_NaN(); |
128 | assert((P(1.0, 1) <=> P(nan, 2)) == std::partial_ordering::unordered); |
129 | } |
130 | } |
131 | |
132 | return true; |
133 | } |
134 | |
135 | int main(int, char**) { |
136 | test(); |
137 | static_assert(test()); |
138 | |
139 | return 0; |
140 | } |
141 | |