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 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 // UNSUPPORTED: libcpp-no-concepts
11 
12 // <compare>
13 
14 // template<class T> constexpr partial_ordering partial_order(const T& a, const T& b);
15 
16 #include <compare>
17 
18 #include <cassert>
19 #include <cmath>
20 #include <iterator> // std::size
21 #include <limits>
22 #include <type_traits>
23 #include <utility>
24 
25 #include "test_macros.h"
26 
27 template<class T, class U>
28 constexpr auto has_partial_order(T&& t, U&& u)
29     -> decltype(std::partial_order(static_cast<T&&>(t), static_cast<U&&>(u)), true)
30 {
31     return true;
32 }
33 
34 constexpr bool has_partial_order(...) {
35     return false;
36 }
37 
38 namespace N11 {
39     struct A {};
40     struct B {};
41     std::strong_ordering partial_order(const A&, const A&) { return std::strong_ordering::less; }
42     std::strong_ordering partial_order(const A&, const B&);
43 }
44 
45 void test_1_1()
46 {
47     // If the decayed types of E and F differ, partial_order(E, F) is ill-formed.
48 
49     static_assert( has_partial_order(1, 2));
50     static_assert(!has_partial_order(1, (short)2));
51     static_assert(!has_partial_order(1, 2.0));
52     static_assert(!has_partial_order(1.0f, 2.0));
53 
54     static_assert( has_partial_order((int*)nullptr, (int*)nullptr));
55     static_assert(!has_partial_order((int*)nullptr, (const int*)nullptr));
56     static_assert(!has_partial_order((const int*)nullptr, (int*)nullptr));
57     static_assert( has_partial_order((const int*)nullptr, (const int*)nullptr));
58 
59     N11::A a;
60     N11::B b;
61     static_assert( has_partial_order(a, a));
62     static_assert(!has_partial_order(a, b));
63 }
64 
65 namespace N12 {
66     struct A {};
67     std::strong_ordering partial_order(A&, A&&) { return std::strong_ordering::less; }
68     std::weak_ordering partial_order(A&&, A&&) { return std::weak_ordering::equivalent; }
69     std::strong_ordering partial_order(const A&, const A&);
70 
71     struct B {
72         friend int partial_order(B, B);
73     };
74 
75     struct PartialOrder {
76         explicit operator std::partial_ordering() const { return std::partial_ordering::less; }
77     };
78     struct C {
79         bool touched = false;
80         friend PartialOrder partial_order(C& lhs, C&) { lhs.touched = true; return PartialOrder(); }
81     };
82 }
83 
84 void test_1_2()
85 {
86     // Otherwise, partial_ordering(partial_order(E, F))
87     // if it is a well-formed expression with overload resolution performed
88     // in a context that does not include a declaration of std::partial_order.
89 
90     // Test that partial_order does not const-qualify the forwarded arguments.
91     N12::A a;
92     assert(std::partial_order(a, std::move(a)) == std::partial_ordering::less);
93     assert(std::partial_order(std::move(a), std::move(a)) == std::partial_ordering::equivalent);
94 
95     // The type of partial_order(e,f) must be explicitly convertible to partial_ordering.
96     N12::B b;
97     static_assert(!has_partial_order(b, b));
98 
99     N12::C c1, c2;
100     ASSERT_SAME_TYPE(decltype(std::partial_order(c1, c2)), std::partial_ordering);
101     assert(std::partial_order(c1, c2) == std::partial_ordering::less);
102     assert(c1.touched);
103     assert(!c2.touched);
104 }
105 
106 namespace N13 {
107     // Compare to N12::A.
108     struct A {};
109     bool operator==(const A&, const A&);
110     constexpr std::partial_ordering operator<=>(A&, A&&) { return std::partial_ordering::less; }
111     constexpr std::partial_ordering operator<=>(A&&, A&&) { return std::partial_ordering::equivalent; }
112     std::partial_ordering operator<=>(const A&, const A&);
113     static_assert(std::three_way_comparable<A>);
114 
115     struct B {
116         std::partial_ordering operator<=>(const B&) const;  // lacks operator==
117     };
118     static_assert(!std::three_way_comparable<B>);
119 
120     struct C {
121         bool *touched;
122         bool operator==(const C&) const;
123         constexpr std::partial_ordering operator<=>(const C& rhs) const {
124             *rhs.touched = true;
125             return std::partial_ordering::equivalent;
126         }
127     };
128     static_assert(std::three_way_comparable<C>);
129 }
130 
131 constexpr bool test_1_3()
132 {
133     // Otherwise, partial_ordering(compare_three_way()(E, F)) if it is a well-formed expression.
134 
135     // Test neither partial_order nor compare_three_way const-qualify the forwarded arguments.
136     N13::A a;
137     assert(std::partial_order(a, std::move(a)) == std::partial_ordering::less);
138     assert(std::partial_order(std::move(a), std::move(a)) == std::partial_ordering::equivalent);
139 
140     N13::B b;
141     static_assert(!has_partial_order(b, b));
142 
143     // Test that the arguments are passed to <=> in the correct order.
144     bool c1_touched = false;
145     bool c2_touched = false;
146     N13::C c1 = {&c1_touched};
147     N13::C c2 = {&c2_touched};
148     assert(std::partial_order(c1, c2) == std::partial_ordering::equivalent);
149     assert(!c1_touched);
150     assert(c2_touched);
151 
152     // For partial_order, this bullet point takes care of floating-point types;
153     // they receive their natural partial order.
154     {
155         using F = float;
156         F nan = std::numeric_limits<F>::quiet_NaN();
157         assert(std::partial_order(F(1), F(2)) == std::partial_ordering::less);
158         assert(std::partial_order(F(0), -F(0)) == std::partial_ordering::equivalent);
159 #ifndef TEST_COMPILER_GCC  // GCC can't compare NaN to non-NaN in a constant-expression
160         assert(std::partial_order(nan, F(1)) == std::partial_ordering::unordered);
161 #endif
162         assert(std::partial_order(nan, nan) == std::partial_ordering::unordered);
163     }
164     {
165         using F = double;
166         F nan = std::numeric_limits<F>::quiet_NaN();
167         assert(std::partial_order(F(1), F(2)) == std::partial_ordering::less);
168         assert(std::partial_order(F(0), -F(0)) == std::partial_ordering::equivalent);
169 #ifndef TEST_COMPILER_GCC
170         assert(std::partial_order(nan, F(1)) == std::partial_ordering::unordered);
171 #endif
172         assert(std::partial_order(nan, nan) == std::partial_ordering::unordered);
173     }
174     {
175         using F = long double;
176         F nan = std::numeric_limits<F>::quiet_NaN();
177         assert(std::partial_order(F(1), F(2)) == std::partial_ordering::less);
178         assert(std::partial_order(F(0), -F(0)) == std::partial_ordering::equivalent);
179 #ifndef TEST_COMPILER_GCC
180         assert(std::partial_order(nan, F(1)) == std::partial_ordering::unordered);
181 #endif
182         assert(std::partial_order(nan, nan) == std::partial_ordering::unordered);
183     }
184 
185     return true;
186 }
187 
188 namespace N14 {
189     struct A {};
190     constexpr std::strong_ordering weak_order(A&, A&&) { return std::strong_ordering::less; }
191     constexpr std::strong_ordering weak_order(A&&, A&&) { return std::strong_ordering::equal; }
192     std::strong_ordering weak_order(const A&, const A&);
193 
194     struct B {
195         friend std::partial_ordering weak_order(B, B);
196     };
197 
198     struct StrongOrder {
199         operator std::strong_ordering() const { return std::strong_ordering::less; }
200     };
201     struct C {
202         friend StrongOrder weak_order(C& lhs, C&);
203     };
204 
205     struct WeakOrder {
206         constexpr explicit operator std::weak_ordering() const { return std::weak_ordering::less; }
207         operator std::partial_ordering() const = delete;
208     };
209     struct D {
210         bool touched = false;
211         friend constexpr WeakOrder weak_order(D& lhs, D&) { lhs.touched = true; return WeakOrder(); }
212     };
213 }
214 
215 constexpr bool test_1_4()
216 {
217     // Otherwise, partial_ordering(weak_order(E, F)) [that is, std::weak_order]
218     // if it is a well-formed expression.
219 
220     // Test that partial_order and weak_order do not const-qualify the forwarded arguments.
221     N14::A a;
222     assert(std::partial_order(a, std::move(a)) == std::partial_ordering::less);
223     assert(std::partial_order(std::move(a), std::move(a)) == std::partial_ordering::equivalent);
224 
225     // The type of ADL weak_order(e,f) must be explicitly convertible to weak_ordering
226     // (not just to partial_ordering), or else std::weak_order(e,f) won't exist.
227     N14::B b;
228     static_assert(!has_partial_order(b, b));
229 
230     // The type of ADL weak_order(e,f) must be explicitly convertible to weak_ordering
231     // (not just to strong_ordering), or else std::weak_order(e,f) won't exist.
232     N14::C c;
233     static_assert(!has_partial_order(c, c));
234 
235     N14::D d1, d2;
236     ASSERT_SAME_TYPE(decltype(std::partial_order(d1, d2)), std::partial_ordering);
237     assert(std::partial_order(d1, d2) == std::partial_ordering::less);
238     assert(d1.touched);
239     assert(!d2.touched);
240 
241     return true;
242 }
243 
244 int main(int, char**)
245 {
246     test_1_1();
247     test_1_2();
248     test_1_3();
249     test_1_4();
250 
251     static_assert(test_1_3());
252     static_assert(test_1_4());
253 
254     return 0;
255 }
256