1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
8 // A set of routines for testing the comparison operators of a type
10 // FooOrder<expected-ordering> All seven comparison operators, requires C++20 or newer.
11 // FooComparison All six pre-C++20 comparison operators
12 // FooEquality Equality operators operator== and operator!=
14 // AssertXAreNoexcept static_asserts that the operations are all noexcept.
15 // AssertXReturnBool static_asserts that the operations return bool.
16 // AssertOrderReturn static_asserts that the pre-C++20 comparison operations
17 // return bool and operator<=> returns the proper type.
18 // AssertXConvertibleToBool static_asserts that the operations return something convertible to bool.
19 // testXValues returns the result of the comparison of all operations.
21 // AssertOrderConvertibleToBool doesn't exist yet. It will be implemented when needed.
23 #ifndef TEST_COMPARISONS_H
24 #define TEST_COMPARISONS_H
30 #include <type_traits>
33 #include "test_macros.h"
35 // Test the consistency of the six basic comparison operators for values that are ordered or unordered.
36 template <class T
, class U
= T
>
37 TEST_NODISCARD TEST_CONSTEXPR_CXX14
bool
38 testComparisonsComplete(const T
& t1
, const U
& t2
, bool isEqual
, bool isLess
, bool isGreater
) {
39 assert(((isEqual
? 1 : 0) + (isLess
? 1 : 0) + (isGreater
? 1 : 0) <= 1) &&
40 "at most one of isEqual, isLess, and isGreater can be true");
42 if (!(t1
== t2
)) return false;
43 if (!(t2
== t1
)) return false;
44 if ( (t1
!= t2
)) return false;
45 if ( (t2
!= t1
)) return false;
46 if ( (t1
< t2
)) return false;
47 if ( (t2
< t1
)) return false;
48 if (!(t1
<= t2
)) return false;
49 if (!(t2
<= t1
)) return false;
50 if ( (t1
> t2
)) return false;
51 if ( (t2
> t1
)) return false;
52 if (!(t1
>= t2
)) return false;
53 if (!(t2
>= t1
)) return false;
55 if ( (t1
== t2
)) return false;
56 if ( (t2
== t1
)) return false;
57 if (!(t1
!= t2
)) return false;
58 if (!(t2
!= t1
)) return false;
59 if (!(t1
< t2
)) return false;
60 if ( (t2
< t1
)) return false;
61 if (!(t1
<= t2
)) return false;
62 if ( (t2
<= t1
)) return false;
63 if ( (t1
> t2
)) return false;
64 if (!(t2
> t1
)) return false;
65 if ( (t1
>= t2
)) return false;
66 if (!(t2
>= t1
)) return false;
67 } else if (isGreater
) {
68 if ( (t1
== t2
)) return false;
69 if ( (t2
== t1
)) return false;
70 if (!(t1
!= t2
)) return false;
71 if (!(t2
!= t1
)) return false;
72 if ( (t1
< t2
)) return false;
73 if (!(t2
< t1
)) return false;
74 if ( (t1
<= t2
)) return false;
75 if (!(t2
<= t1
)) return false;
76 if (!(t1
> t2
)) return false;
77 if ( (t2
> t1
)) return false;
78 if (!(t1
>= t2
)) return false;
79 if ( (t2
>= t1
)) return false;
81 if ( (t1
== t2
)) return false;
82 if ( (t2
== t1
)) return false;
83 if (!(t1
!= t2
)) return false;
84 if (!(t2
!= t1
)) return false;
85 if ( (t1
< t2
)) return false;
86 if ( (t2
< t1
)) return false;
87 if ( (t1
<= t2
)) return false;
88 if ( (t2
<= t1
)) return false;
89 if ( (t1
> t2
)) return false;
90 if ( (t2
> t1
)) return false;
91 if ( (t1
>= t2
)) return false;
92 if ( (t2
>= t1
)) return false;
98 // Test the six basic comparison operators for ordered values.
99 template <class T
, class U
= T
>
100 TEST_NODISCARD TEST_CONSTEXPR_CXX14
bool testComparisons(const T
& t1
, const U
& t2
, bool isEqual
, bool isLess
) {
101 assert(!(isEqual
&& isLess
) && "isEqual and isLess cannot be both true");
102 bool isGreater
= !isEqual
&& !isLess
;
103 return testComparisonsComplete(t1
, t2
, isEqual
, isLess
, isGreater
);
106 // Easy call when you can init from something already comparable.
107 template <class T
, class Param
>
108 TEST_NODISCARD TEST_CONSTEXPR_CXX14
bool testComparisonsValues(Param val1
, Param val2
)
110 const bool isEqual
= val1
== val2
;
111 const bool isLess
= val1
< val2
;
112 const bool isGreater
= val1
> val2
;
114 return testComparisonsComplete(T(val1
), T(val2
), isEqual
, isLess
, isGreater
);
117 template <class T
, class U
= T
>
118 TEST_CONSTEXPR_CXX14
void AssertComparisonsAreNoexcept() {
119 ASSERT_NOEXCEPT(std::declval
<const T
&>() == std::declval
<const U
&>());
120 ASSERT_NOEXCEPT(std::declval
<const T
&>() != std::declval
<const U
&>());
121 ASSERT_NOEXCEPT(std::declval
<const T
&>() < std::declval
<const U
&>());
122 ASSERT_NOEXCEPT(std::declval
<const T
&>() <= std::declval
<const U
&>());
123 ASSERT_NOEXCEPT(std::declval
<const T
&>() > std::declval
<const U
&>());
124 ASSERT_NOEXCEPT(std::declval
<const T
&>() >= std::declval
<const U
&>());
127 template <class T
, class U
= T
>
128 TEST_CONSTEXPR_CXX14
void AssertComparisonsReturnBool() {
129 ASSERT_SAME_TYPE(decltype(std::declval
<const T
&>() == std::declval
<const U
&>()), bool);
130 ASSERT_SAME_TYPE(decltype(std::declval
<const T
&>() != std::declval
<const U
&>()), bool);
131 ASSERT_SAME_TYPE(decltype(std::declval
<const T
&>() < std::declval
<const U
&>()), bool);
132 ASSERT_SAME_TYPE(decltype(std::declval
<const T
&>() <= std::declval
<const U
&>()), bool);
133 ASSERT_SAME_TYPE(decltype(std::declval
<const T
&>() > std::declval
<const U
&>()), bool);
134 ASSERT_SAME_TYPE(decltype(std::declval
<const T
&>() >= std::declval
<const U
&>()), bool);
137 template <class T
, class U
= T
>
138 void AssertComparisonsConvertibleToBool()
140 static_assert((std::is_convertible
<decltype(std::declval
<const T
&>() == std::declval
<const U
&>()), bool>::value
), "");
141 static_assert((std::is_convertible
<decltype(std::declval
<const T
&>() != std::declval
<const U
&>()), bool>::value
), "");
142 static_assert((std::is_convertible
<decltype(std::declval
<const T
&>() < std::declval
<const U
&>()), bool>::value
), "");
143 static_assert((std::is_convertible
<decltype(std::declval
<const T
&>() <= std::declval
<const U
&>()), bool>::value
), "");
144 static_assert((std::is_convertible
<decltype(std::declval
<const T
&>() > std::declval
<const U
&>()), bool>::value
), "");
145 static_assert((std::is_convertible
<decltype(std::declval
<const T
&>() >= std::declval
<const U
&>()), bool>::value
), "");
148 #if TEST_STD_VER > 17
149 template <class T
, class U
= T
>
150 constexpr void AssertOrderAreNoexcept() {
151 AssertComparisonsAreNoexcept
<T
, U
>();
152 ASSERT_NOEXCEPT(std::declval
<const T
&>() <=> std::declval
<const U
&>());
155 template <class Order
, class T
, class U
= T
>
156 constexpr void AssertOrderReturn() {
157 AssertComparisonsReturnBool
<T
, U
>();
158 ASSERT_SAME_TYPE(decltype(std::declval
<const T
&>() <=> std::declval
<const U
&>()), Order
);
161 template <class Order
, class T
, class U
= T
>
162 TEST_NODISCARD
constexpr bool testOrder(const T
& t1
, const U
& t2
, Order order
) {
163 bool equal
= order
== Order::equivalent
;
164 bool less
= order
== Order::less
;
165 bool greater
= order
== Order::greater
;
167 return (t1
<=> t2
== order
) && testComparisonsComplete(t1
, t2
, equal
, less
, greater
);
170 template <class T
, class Param
>
171 TEST_NODISCARD
constexpr bool testOrderValues(Param val1
, Param val2
) {
172 return testOrder(T(val1
), T(val2
), val1
<=> val2
);
177 // Test all two comparison operations for sanity
178 template <class T
, class U
= T
>
179 TEST_NODISCARD TEST_CONSTEXPR_CXX14
bool testEquality(const T
& t1
, const U
& t2
, bool isEqual
)
183 if (!(t1
== t2
)) return false;
184 if (!(t2
== t1
)) return false;
185 if ( (t1
!= t2
)) return false;
186 if ( (t2
!= t1
)) return false;
190 if ( (t1
== t2
)) return false;
191 if ( (t2
== t1
)) return false;
192 if (!(t1
!= t2
)) return false;
193 if (!(t2
!= t1
)) return false;
199 // Easy call when you can init from something already comparable.
200 template <class T
, class Param
>
201 TEST_NODISCARD TEST_CONSTEXPR_CXX14
bool testEqualityValues(Param val1
, Param val2
)
203 const bool isEqual
= val1
== val2
;
205 return testEquality(T(val1
), T(val2
), isEqual
);
208 template <class T
, class U
= T
>
209 void AssertEqualityAreNoexcept()
211 ASSERT_NOEXCEPT(std::declval
<const T
&>() == std::declval
<const U
&>());
212 ASSERT_NOEXCEPT(std::declval
<const T
&>() != std::declval
<const U
&>());
215 template <class T
, class U
= T
>
216 void AssertEqualityReturnBool()
218 ASSERT_SAME_TYPE(decltype(std::declval
<const T
&>() == std::declval
<const U
&>()), bool);
219 ASSERT_SAME_TYPE(decltype(std::declval
<const T
&>() != std::declval
<const U
&>()), bool);
223 template <class T
, class U
= T
>
224 void AssertEqualityConvertibleToBool()
226 static_assert((std::is_convertible
<decltype(std::declval
<const T
&>() == std::declval
<const U
&>()), bool>::value
), "");
227 static_assert((std::is_convertible
<decltype(std::declval
<const T
&>() != std::declval
<const U
&>()), bool>::value
), "");
230 struct LessAndEqComp
{
233 TEST_CONSTEXPR_CXX14
LessAndEqComp(int v
) : value(v
) {}
235 friend TEST_CONSTEXPR_CXX14
bool operator<(const LessAndEqComp
& lhs
, const LessAndEqComp
& rhs
) {
236 return lhs
.value
< rhs
.value
;
239 friend TEST_CONSTEXPR_CXX14
bool operator==(const LessAndEqComp
& lhs
, const LessAndEqComp
& rhs
) {
240 return lhs
.value
== rhs
.value
;
244 #if TEST_STD_VER >= 20
248 constexpr StrongOrder(int v
) : value(v
) {}
249 friend std::strong_ordering
operator<=>(StrongOrder
, StrongOrder
) = default;
254 constexpr WeakOrder(int v
) : value(v
) {}
255 friend std::weak_ordering
operator<=>(WeakOrder
, WeakOrder
) = default;
258 struct PartialOrder
{
260 constexpr PartialOrder(int v
) : value(v
) {}
261 friend constexpr std::partial_ordering
operator<=>(PartialOrder lhs
, PartialOrder rhs
) {
262 if (lhs
.value
== std::numeric_limits
<int>::min() || rhs
.value
== std::numeric_limits
<int>::min())
263 return std::partial_ordering::unordered
;
264 if (lhs
.value
== std::numeric_limits
<int>::max() || rhs
.value
== std::numeric_limits
<int>::max())
265 return std::partial_ordering::unordered
;
266 return lhs
.value
<=> rhs
.value
;
268 friend constexpr bool operator==(PartialOrder lhs
, PartialOrder rhs
) {
269 return (lhs
<=> rhs
) == std::partial_ordering::equivalent
;
275 #endif // TEST_COMPARISONS_H