255 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710 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::size20#include <limits>21#include <type_traits>22#include <utility>23 24#include "test_macros.h"25 26template<class T, class U>27constexpr 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 33constexpr bool has_partial_order(...) {34 return false;35}36 37namespace N11 {38 struct A {};39 struct B {};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 44void 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 64namespace N12 {65 struct A {};66 std::strong_ordering partial_order(A&, A&&) { return std::strong_ordering::less; }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 {75 explicit operator std::partial_ordering() const { return std::partial_ordering::less; }76 };77 struct C {78 bool touched = false;79 friend PartialOrder partial_order(C& lhs, C&) { lhs.touched = true; return PartialOrder(); }80 };81}82 83void test_1_2()84{85 // Otherwise, partial_ordering(partial_order(E, F))86 // if it is a well-formed expression with overload resolution performed87 // 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 105namespace N13 {106 // Compare to N12::A.107 struct A {};108 bool operator==(const A&, const A&);109 constexpr std::partial_ordering operator<=>(A&, A&&) { return std::partial_ordering::less; }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;122 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 130constexpr 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-expression159 assert(std::partial_order(nan, F(1)) == std::partial_ordering::unordered);160#endif161 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_GCC169 assert(std::partial_order(nan, F(1)) == std::partial_ordering::unordered);170#endif171 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_GCC179 assert(std::partial_order(nan, F(1)) == std::partial_ordering::unordered);180#endif181 assert(std::partial_order(nan, nan) == std::partial_ordering::unordered);182 }183 184 return true;185}186 187namespace N14 {188 struct A {};189 constexpr std::strong_ordering weak_order(A&, A&&) { return std::strong_ordering::less; }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 {198 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 {205 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;210 friend constexpr WeakOrder weak_order(D& lhs, D&) { lhs.touched = true; return WeakOrder(); }211 };212}213 214constexpr 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_ordering225 // (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_ordering230 // (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 243int 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