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