xref: /llvm-project/libcxx/test/support/test_comparisons.h (revision 0b46606ca5b52aa515c5359ed6f24fb18d825b50)
1c17628fbSMarshall Clow //===----------------------------------------------------------------------===//
2c17628fbSMarshall Clow //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c17628fbSMarshall Clow //
7c17628fbSMarshall Clow //===----------------------------------------------------------------------===//
8c17628fbSMarshall Clow //  A set of routines for testing the comparison operators of a type
9c17628fbSMarshall Clow //
10984f5f3fSMark de Wever //      FooOrder<expected-ordering>  All seven comparison operators, requires C++20 or newer.
11984f5f3fSMark de Wever //      FooComparison                All six pre-C++20 comparison operators
12984f5f3fSMark de Wever //      FooEquality                  Equality operators operator== and operator!=
13c17628fbSMarshall Clow //
14984f5f3fSMark de Wever //      AssertXAreNoexcept           static_asserts that the operations are all noexcept.
15984f5f3fSMark de Wever //      AssertXReturnBool            static_asserts that the operations return bool.
16984f5f3fSMark de Wever //      AssertOrderReturn            static_asserts that the pre-C++20 comparison operations
17984f5f3fSMark de Wever //                                   return bool and operator<=> returns the proper type.
18984f5f3fSMark de Wever //      AssertXConvertibleToBool     static_asserts that the operations return something convertible to bool.
19984f5f3fSMark de Wever //      testXValues                  returns the result of the comparison of all operations.
20984f5f3fSMark de Wever //
21984f5f3fSMark de Wever //      AssertOrderConvertibleToBool doesn't exist yet. It will be implemented when needed.
22c17628fbSMarshall Clow 
23c17628fbSMarshall Clow #ifndef TEST_COMPARISONS_H
24c17628fbSMarshall Clow #define TEST_COMPARISONS_H
25c17628fbSMarshall Clow 
26c87a4a46SKonstantin Boyarinov #include <cassert>
272a06757aSAdrian Vogelsgesang #include <compare>
283818b4dfSMark de Wever #include <concepts>
292a06757aSAdrian Vogelsgesang #include <limits>
30c4566cacSKent Ross #include <type_traits>
31c4566cacSKent Ross #include <utility>
32c4566cacSKent Ross 
33c17628fbSMarshall Clow #include "test_macros.h"
34c17628fbSMarshall Clow 
35c4566cacSKent Ross // Test the consistency of the six basic comparison operators for values that are ordered or unordered.
36f3126c8bSMarshall Clow template <class T, class U = T>
37c4566cacSKent Ross TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool
testComparisonsComplete(const T & t1,const U & t2,bool isEqual,bool isLess,bool isGreater)38c4566cacSKent Ross testComparisonsComplete(const T& t1, const U& t2, bool isEqual, bool isLess, bool isGreater) {
39c4566cacSKent Ross     assert(((isEqual ? 1 : 0) + (isLess ? 1 : 0) + (isGreater ? 1 : 0) <= 1) &&
40c4566cacSKent Ross            "at most one of isEqual, isLess, and isGreater can be true");
41c4566cacSKent Ross     if (isEqual) {
42c17628fbSMarshall Clow         if (!(t1 == t2)) return false;
43c17628fbSMarshall Clow         if (!(t2 == t1)) return false;
44c17628fbSMarshall Clow         if ( (t1 != t2)) return false;
45c17628fbSMarshall Clow         if ( (t2 != t1)) return false;
46c17628fbSMarshall Clow         if ( (t1  < t2)) return false;
47c17628fbSMarshall Clow         if ( (t2  < t1)) return false;
48c17628fbSMarshall Clow         if (!(t1 <= t2)) return false;
49c17628fbSMarshall Clow         if (!(t2 <= t1)) return false;
50c17628fbSMarshall Clow         if ( (t1  > t2)) return false;
51c17628fbSMarshall Clow         if ( (t2  > t1)) return false;
52c17628fbSMarshall Clow         if (!(t1 >= t2)) return false;
53c17628fbSMarshall Clow         if (!(t2 >= t1)) return false;
54c4566cacSKent Ross     } else if (isLess) {
55c17628fbSMarshall Clow         if ( (t1 == t2)) return false;
56c17628fbSMarshall Clow         if ( (t2 == t1)) return false;
57c17628fbSMarshall Clow         if (!(t1 != t2)) return false;
58c17628fbSMarshall Clow         if (!(t2 != t1)) return false;
59c17628fbSMarshall Clow         if (!(t1  < t2)) return false;
60c17628fbSMarshall Clow         if ( (t2  < t1)) return false;
61c17628fbSMarshall Clow         if (!(t1 <= t2)) return false;
62c17628fbSMarshall Clow         if ( (t2 <= t1)) return false;
63c17628fbSMarshall Clow         if ( (t1  > t2)) return false;
64c17628fbSMarshall Clow         if (!(t2  > t1)) return false;
65c17628fbSMarshall Clow         if ( (t1 >= t2)) return false;
66c17628fbSMarshall Clow         if (!(t2 >= t1)) return false;
67c4566cacSKent Ross     } else if (isGreater) {
68c17628fbSMarshall Clow         if ( (t1 == t2)) return false;
69c17628fbSMarshall Clow         if ( (t2 == t1)) return false;
70c17628fbSMarshall Clow         if (!(t1 != t2)) return false;
71c17628fbSMarshall Clow         if (!(t2 != t1)) return false;
72c17628fbSMarshall Clow         if ( (t1  < t2)) return false;
73c17628fbSMarshall Clow         if (!(t2  < t1)) return false;
74c17628fbSMarshall Clow         if ( (t1 <= t2)) return false;
75c17628fbSMarshall Clow         if (!(t2 <= t1)) return false;
76c17628fbSMarshall Clow         if (!(t1  > t2)) return false;
77c17628fbSMarshall Clow         if ( (t2  > t1)) return false;
78c17628fbSMarshall Clow         if (!(t1 >= t2)) return false;
79c17628fbSMarshall Clow         if ( (t2 >= t1)) return false;
80c4566cacSKent Ross     } else { // unordered
81c4566cacSKent Ross         if ( (t1 == t2)) return false;
82c4566cacSKent Ross         if ( (t2 == t1)) return false;
83c4566cacSKent Ross         if (!(t1 != t2)) return false;
84c4566cacSKent Ross         if (!(t2 != t1)) return false;
85c4566cacSKent Ross         if ( (t1  < t2)) return false;
86c4566cacSKent Ross         if ( (t2  < t1)) return false;
87c4566cacSKent Ross         if ( (t1 <= t2)) return false;
88c4566cacSKent Ross         if ( (t2 <= t1)) return false;
89c4566cacSKent Ross         if ( (t1  > t2)) return false;
90c4566cacSKent Ross         if ( (t2  > t1)) return false;
91c4566cacSKent Ross         if ( (t1 >= t2)) return false;
92c4566cacSKent Ross         if ( (t2 >= t1)) return false;
93c17628fbSMarshall Clow     }
94c17628fbSMarshall Clow 
95c17628fbSMarshall Clow     return true;
96c17628fbSMarshall Clow }
97c17628fbSMarshall Clow 
98c4566cacSKent Ross // Test the six basic comparison operators for ordered values.
99c4566cacSKent Ross template <class T, class U = T>
testComparisons(const T & t1,const U & t2,bool isEqual,bool isLess)100c4566cacSKent Ross TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t2, bool isEqual, bool isLess) {
101c4566cacSKent Ross     assert(!(isEqual && isLess) && "isEqual and isLess cannot be both true");
102c4566cacSKent Ross     bool isGreater = !isEqual && !isLess;
103c4566cacSKent Ross     return testComparisonsComplete(t1, t2, isEqual, isLess, isGreater);
104c4566cacSKent Ross }
105c4566cacSKent Ross 
106c17628fbSMarshall Clow //  Easy call when you can init from something already comparable.
107c17628fbSMarshall Clow template <class T, class Param>
testComparisonsValues(Param val1,Param val2)108d7e0cec6SAdrian Vogelsgesang TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisonsValues(Param val1, Param val2)
109c17628fbSMarshall Clow {
110c17628fbSMarshall Clow     const bool isEqual   = val1 == val2;
111c17628fbSMarshall Clow     const bool isLess    = val1 <  val2;
112c4566cacSKent Ross     const bool isGreater = val1  > val2;
113c17628fbSMarshall Clow 
114c4566cacSKent Ross     return testComparisonsComplete(T(val1), T(val2), isEqual, isLess, isGreater);
115c17628fbSMarshall Clow }
116c17628fbSMarshall Clow 
117f3126c8bSMarshall Clow template <class T, class U = T>
AssertComparisonsAreNoexcept()1183818b4dfSMark de Wever TEST_CONSTEXPR_CXX14 void AssertComparisonsAreNoexcept() {
119f3126c8bSMarshall Clow     ASSERT_NOEXCEPT(std::declval<const T&>() == std::declval<const U&>());
120f3126c8bSMarshall Clow     ASSERT_NOEXCEPT(std::declval<const T&>() != std::declval<const U&>());
121f3126c8bSMarshall Clow     ASSERT_NOEXCEPT(std::declval<const T&>() <  std::declval<const U&>());
122f3126c8bSMarshall Clow     ASSERT_NOEXCEPT(std::declval<const T&>() <= std::declval<const U&>());
123f3126c8bSMarshall Clow     ASSERT_NOEXCEPT(std::declval<const T&>() >  std::declval<const U&>());
124f3126c8bSMarshall Clow     ASSERT_NOEXCEPT(std::declval<const T&>() >= std::declval<const U&>());
125c17628fbSMarshall Clow }
126c17628fbSMarshall Clow 
127f3126c8bSMarshall Clow template <class T, class U = T>
AssertComparisonsReturnBool()1283818b4dfSMark de Wever TEST_CONSTEXPR_CXX14 void AssertComparisonsReturnBool() {
129f3126c8bSMarshall Clow     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() == std::declval<const U&>()), bool);
130f3126c8bSMarshall Clow     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() != std::declval<const U&>()), bool);
131f3126c8bSMarshall Clow     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() <  std::declval<const U&>()), bool);
132f3126c8bSMarshall Clow     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() <= std::declval<const U&>()), bool);
133f3126c8bSMarshall Clow     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() >  std::declval<const U&>()), bool);
134f3126c8bSMarshall Clow     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() >= std::declval<const U&>()), bool);
135c17628fbSMarshall Clow }
136c17628fbSMarshall Clow 
137f3126c8bSMarshall Clow template <class T, class U = T>
AssertComparisonsConvertibleToBool()138984f5f3fSMark de Wever void AssertComparisonsConvertibleToBool()
139c17628fbSMarshall Clow {
140f3126c8bSMarshall Clow     static_assert((std::is_convertible<decltype(std::declval<const T&>() == std::declval<const U&>()), bool>::value), "");
141f3126c8bSMarshall Clow     static_assert((std::is_convertible<decltype(std::declval<const T&>() != std::declval<const U&>()), bool>::value), "");
142f3126c8bSMarshall Clow     static_assert((std::is_convertible<decltype(std::declval<const T&>() <  std::declval<const U&>()), bool>::value), "");
143f3126c8bSMarshall Clow     static_assert((std::is_convertible<decltype(std::declval<const T&>() <= std::declval<const U&>()), bool>::value), "");
144f3126c8bSMarshall Clow     static_assert((std::is_convertible<decltype(std::declval<const T&>() >  std::declval<const U&>()), bool>::value), "");
145f3126c8bSMarshall Clow     static_assert((std::is_convertible<decltype(std::declval<const T&>() >= std::declval<const U&>()), bool>::value), "");
146c17628fbSMarshall Clow }
147c17628fbSMarshall Clow 
148984f5f3fSMark de Wever #if TEST_STD_VER > 17
149984f5f3fSMark de Wever template <class T, class U = T>
AssertOrderAreNoexcept()1503818b4dfSMark de Wever constexpr void AssertOrderAreNoexcept() {
151984f5f3fSMark de Wever     AssertComparisonsAreNoexcept<T, U>();
152984f5f3fSMark de Wever     ASSERT_NOEXCEPT(std::declval<const T&>() <=> std::declval<const U&>());
153984f5f3fSMark de Wever }
154984f5f3fSMark de Wever 
155984f5f3fSMark de Wever template <class Order, class T, class U = T>
AssertOrderReturn()1563818b4dfSMark de Wever constexpr void AssertOrderReturn() {
157984f5f3fSMark de Wever     AssertComparisonsReturnBool<T, U>();
158984f5f3fSMark de Wever     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() <=> std::declval<const U&>()), Order);
159984f5f3fSMark de Wever }
160984f5f3fSMark de Wever 
161984f5f3fSMark de Wever template <class Order, class T, class U = T>
testOrder(const T & t1,const U & t2,Order order)162d7e0cec6SAdrian Vogelsgesang TEST_NODISCARD constexpr bool testOrder(const T& t1, const U& t2, Order order) {
1633818b4dfSMark de Wever     bool equal   = order == Order::equivalent;
1643818b4dfSMark de Wever     bool less    = order == Order::less;
165c4566cacSKent Ross     bool greater = order == Order::greater;
1663818b4dfSMark de Wever 
167c4566cacSKent Ross     return (t1 <=> t2 == order) && testComparisonsComplete(t1, t2, equal, less, greater);
168984f5f3fSMark de Wever }
169984f5f3fSMark de Wever 
170984f5f3fSMark de Wever template <class T, class Param>
testOrderValues(Param val1,Param val2)171d7e0cec6SAdrian Vogelsgesang TEST_NODISCARD constexpr bool testOrderValues(Param val1, Param val2) {
172984f5f3fSMark de Wever   return testOrder(T(val1), T(val2), val1 <=> val2);
173984f5f3fSMark de Wever }
174984f5f3fSMark de Wever 
175984f5f3fSMark de Wever #endif
176984f5f3fSMark de Wever 
177f3126c8bSMarshall Clow //  Test all two comparison operations for sanity
178f3126c8bSMarshall Clow template <class T, class U = T>
testEquality(const T & t1,const U & t2,bool isEqual)179d7e0cec6SAdrian Vogelsgesang TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testEquality(const T& t1, const U& t2, bool isEqual)
180c17628fbSMarshall Clow {
181c17628fbSMarshall Clow     if (isEqual)
182c17628fbSMarshall Clow         {
183c17628fbSMarshall Clow         if (!(t1 == t2)) return false;
184c17628fbSMarshall Clow         if (!(t2 == t1)) return false;
185c17628fbSMarshall Clow         if ( (t1 != t2)) return false;
186c17628fbSMarshall Clow         if ( (t2 != t1)) return false;
187c17628fbSMarshall Clow         }
188f3126c8bSMarshall Clow     else /* not equal */
189c17628fbSMarshall Clow         {
190c17628fbSMarshall Clow         if ( (t1 == t2)) return false;
191c17628fbSMarshall Clow         if ( (t2 == t1)) return false;
192c17628fbSMarshall Clow         if (!(t1 != t2)) return false;
193c17628fbSMarshall Clow         if (!(t2 != t1)) return false;
194c17628fbSMarshall Clow         }
195c17628fbSMarshall Clow 
196c17628fbSMarshall Clow     return true;
197c17628fbSMarshall Clow }
198c17628fbSMarshall Clow 
199c17628fbSMarshall Clow //  Easy call when you can init from something already comparable.
200c17628fbSMarshall Clow template <class T, class Param>
testEqualityValues(Param val1,Param val2)201d7e0cec6SAdrian Vogelsgesang TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testEqualityValues(Param val1, Param val2)
202c17628fbSMarshall Clow {
203c17628fbSMarshall Clow     const bool isEqual = val1 == val2;
204c17628fbSMarshall Clow 
205984f5f3fSMark de Wever     return testEquality(T(val1), T(val2), isEqual);
206c17628fbSMarshall Clow }
207c17628fbSMarshall Clow 
208f3126c8bSMarshall Clow template <class T, class U = T>
AssertEqualityAreNoexcept()209984f5f3fSMark de Wever void AssertEqualityAreNoexcept()
210c17628fbSMarshall Clow {
211f3126c8bSMarshall Clow     ASSERT_NOEXCEPT(std::declval<const T&>() == std::declval<const U&>());
212f3126c8bSMarshall Clow     ASSERT_NOEXCEPT(std::declval<const T&>() != std::declval<const U&>());
213c17628fbSMarshall Clow }
214c17628fbSMarshall Clow 
215f3126c8bSMarshall Clow template <class T, class U = T>
AssertEqualityReturnBool()216*0b46606cSJakub Mazurkiewicz TEST_CONSTEXPR_CXX14 void AssertEqualityReturnBool() {
217f3126c8bSMarshall Clow   ASSERT_SAME_TYPE(decltype(std::declval<const T&>() == std::declval<const U&>()), bool);
218f3126c8bSMarshall Clow   ASSERT_SAME_TYPE(decltype(std::declval<const T&>() != std::declval<const U&>()), bool);
219c17628fbSMarshall Clow }
220c17628fbSMarshall Clow 
221f3126c8bSMarshall Clow template <class T, class U = T>
AssertEqualityConvertibleToBool()222984f5f3fSMark de Wever void AssertEqualityConvertibleToBool()
223c17628fbSMarshall Clow {
224f3126c8bSMarshall Clow     static_assert((std::is_convertible<decltype(std::declval<const T&>() == std::declval<const U&>()), bool>::value), "");
225f3126c8bSMarshall Clow     static_assert((std::is_convertible<decltype(std::declval<const T&>() != std::declval<const U&>()), bool>::value), "");
226c17628fbSMarshall Clow }
227c17628fbSMarshall Clow 
228c87a4a46SKonstantin Boyarinov struct LessAndEqComp {
229c87a4a46SKonstantin Boyarinov   int value;
230c87a4a46SKonstantin Boyarinov 
LessAndEqCompLessAndEqComp231d7ac595fSKonstantin Boyarinov   TEST_CONSTEXPR_CXX14 LessAndEqComp(int v) : value(v) {}
232c87a4a46SKonstantin Boyarinov 
233d7ac595fSKonstantin Boyarinov   friend TEST_CONSTEXPR_CXX14 bool operator<(const LessAndEqComp& lhs, const LessAndEqComp& rhs) {
234c87a4a46SKonstantin Boyarinov     return lhs.value < rhs.value;
235c87a4a46SKonstantin Boyarinov   }
236c87a4a46SKonstantin Boyarinov 
237d7ac595fSKonstantin Boyarinov   friend TEST_CONSTEXPR_CXX14 bool operator==(const LessAndEqComp& lhs, const LessAndEqComp& rhs) {
238c87a4a46SKonstantin Boyarinov     return lhs.value == rhs.value;
239c87a4a46SKonstantin Boyarinov   }
240c87a4a46SKonstantin Boyarinov };
2412a06757aSAdrian Vogelsgesang 
242f8b5ac34SHristo Hristov #if TEST_STD_VER >= 20
243f8b5ac34SHristo Hristov 
2442a06757aSAdrian Vogelsgesang struct StrongOrder {
2452a06757aSAdrian Vogelsgesang   int value;
StrongOrderStrongOrder2462a06757aSAdrian Vogelsgesang   constexpr StrongOrder(int v) : value(v) {}
2472a06757aSAdrian Vogelsgesang   friend std::strong_ordering operator<=>(StrongOrder, StrongOrder) = default;
2482a06757aSAdrian Vogelsgesang };
2492a06757aSAdrian Vogelsgesang 
2502a06757aSAdrian Vogelsgesang struct WeakOrder {
2512a06757aSAdrian Vogelsgesang   int value;
WeakOrderWeakOrder2522a06757aSAdrian Vogelsgesang   constexpr WeakOrder(int v) : value(v) {}
2532a06757aSAdrian Vogelsgesang   friend std::weak_ordering operator<=>(WeakOrder, WeakOrder) = default;
2542a06757aSAdrian Vogelsgesang };
2552a06757aSAdrian Vogelsgesang 
2562a06757aSAdrian Vogelsgesang struct PartialOrder {
2572a06757aSAdrian Vogelsgesang   int value;
PartialOrderPartialOrder2582a06757aSAdrian Vogelsgesang   constexpr PartialOrder(int v) : value(v) {}
2592a06757aSAdrian Vogelsgesang   friend constexpr std::partial_ordering operator<=>(PartialOrder lhs, PartialOrder rhs) {
2602a06757aSAdrian Vogelsgesang     if (lhs.value == std::numeric_limits<int>::min() || rhs.value == std::numeric_limits<int>::min())
2612a06757aSAdrian Vogelsgesang       return std::partial_ordering::unordered;
262f8b5ac34SHristo Hristov     if (lhs.value == std::numeric_limits<int>::max() || rhs.value == std::numeric_limits<int>::max())
263f8b5ac34SHristo Hristov       return std::partial_ordering::unordered;
2642a06757aSAdrian Vogelsgesang     return lhs.value <=> rhs.value;
2652a06757aSAdrian Vogelsgesang   }
2662a06757aSAdrian Vogelsgesang   friend constexpr bool operator==(PartialOrder lhs, PartialOrder rhs) {
2672a06757aSAdrian Vogelsgesang     return (lhs <=> rhs) == std::partial_ordering::equivalent;
2682a06757aSAdrian Vogelsgesang   }
2692a06757aSAdrian Vogelsgesang };
2702a06757aSAdrian Vogelsgesang 
2712a06757aSAdrian Vogelsgesang #endif
2722a06757aSAdrian Vogelsgesang 
273c17628fbSMarshall Clow #endif // TEST_COMPARISONS_H
274