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