xref: /llvm-project/libcxx/test/std/utilities/utility/pairs/pairs.spec/three_way_comparison.pass.cpp (revision 882fba9ff275f724a998facba12ad8fc22ab54a3)
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 
test()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 
main(int,char **)135 int main(int, char**) {
136   test();
137   static_assert(test());
138 
139   return 0;
140 }
141