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