xref: /llvm-project/libcxx/test/support/test_comparisons.h (revision d7ac595fc5175b08e9d0da4b608f4f9ffa45afca)
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 //  A set of routines for testing the comparison operators of a type
9 //
10 //      XXXX6 tests all six comparison operators
11 //      XXXX2 tests only op== and op!=
12 //
13 //      AssertComparisonsXAreNoexcept       static_asserts that the operations are all noexcept.
14 //      AssertComparisonsXReturnBool        static_asserts that the operations return bool.
15 //      AssertComparisonsXConvertibleToBool static_asserts that the operations return something convertible to bool.
16 
17 
18 #ifndef TEST_COMPARISONS_H
19 #define TEST_COMPARISONS_H
20 
21 #include <type_traits>
22 #include <cassert>
23 #include "test_macros.h"
24 
25 //  Test all six comparison operations for sanity
26 template <class T, class U = T>
27 TEST_CONSTEXPR_CXX14 bool testComparisons6(const T& t1, const U& t2, bool isEqual, bool isLess)
28 {
29     assert(!(isEqual && isLess) && "isEqual and isLess cannot be both true");
30     if (isEqual)
31         {
32         if (!(t1 == t2)) return false;
33         if (!(t2 == t1)) return false;
34         if ( (t1 != t2)) return false;
35         if ( (t2 != t1)) return false;
36         if ( (t1  < t2)) return false;
37         if ( (t2  < t1)) return false;
38         if (!(t1 <= t2)) return false;
39         if (!(t2 <= t1)) return false;
40         if ( (t1  > t2)) return false;
41         if ( (t2  > t1)) return false;
42         if (!(t1 >= t2)) return false;
43         if (!(t2 >= t1)) return false;
44         }
45     else if (isLess)
46         {
47         if ( (t1 == t2)) return false;
48         if ( (t2 == t1)) return false;
49         if (!(t1 != t2)) return false;
50         if (!(t2 != t1)) return false;
51         if (!(t1  < t2)) return false;
52         if ( (t2  < t1)) return false;
53         if (!(t1 <= t2)) return false;
54         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         }
60     else /* greater */
61         {
62         if ( (t1 == t2)) return false;
63         if ( (t2 == t1)) return false;
64         if (!(t1 != t2)) return false;
65         if (!(t2 != t1)) return false;
66         if ( (t1  < t2)) return false;
67         if (!(t2  < t1)) return false;
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         }
75 
76     return true;
77 }
78 
79 //  Easy call when you can init from something already comparable.
80 template <class T, class Param>
81 TEST_CONSTEXPR_CXX14 bool testComparisons6Values(Param val1, Param val2)
82 {
83     const bool isEqual = val1 == val2;
84     const bool isLess  = val1  < val2;
85 
86     return testComparisons6(T(val1), T(val2), isEqual, isLess);
87 }
88 
89 template <class T, class U = T>
90 void AssertComparisons6AreNoexcept()
91 {
92     ASSERT_NOEXCEPT(std::declval<const T&>() == std::declval<const U&>());
93     ASSERT_NOEXCEPT(std::declval<const T&>() != std::declval<const U&>());
94     ASSERT_NOEXCEPT(std::declval<const T&>() <  std::declval<const U&>());
95     ASSERT_NOEXCEPT(std::declval<const T&>() <= std::declval<const U&>());
96     ASSERT_NOEXCEPT(std::declval<const T&>() >  std::declval<const U&>());
97     ASSERT_NOEXCEPT(std::declval<const T&>() >= std::declval<const U&>());
98 }
99 
100 template <class T, class U = T>
101 void AssertComparisons6ReturnBool()
102 {
103     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() == std::declval<const U&>()), bool);
104     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() != std::declval<const U&>()), bool);
105     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() <  std::declval<const U&>()), bool);
106     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() <= std::declval<const U&>()), bool);
107     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() >  std::declval<const U&>()), bool);
108     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() >= std::declval<const U&>()), bool);
109 }
110 
111 
112 template <class T, class U = T>
113 void AssertComparisons6ConvertibleToBool()
114 {
115     static_assert((std::is_convertible<decltype(std::declval<const T&>() == std::declval<const U&>()), bool>::value), "");
116     static_assert((std::is_convertible<decltype(std::declval<const T&>() != std::declval<const U&>()), bool>::value), "");
117     static_assert((std::is_convertible<decltype(std::declval<const T&>() <  std::declval<const U&>()), bool>::value), "");
118     static_assert((std::is_convertible<decltype(std::declval<const T&>() <= std::declval<const U&>()), bool>::value), "");
119     static_assert((std::is_convertible<decltype(std::declval<const T&>() >  std::declval<const U&>()), bool>::value), "");
120     static_assert((std::is_convertible<decltype(std::declval<const T&>() >= std::declval<const U&>()), bool>::value), "");
121 }
122 
123 //  Test all two comparison operations for sanity
124 template <class T, class U = T>
125 TEST_CONSTEXPR_CXX14 bool testComparisons2(const T& t1, const U& t2, bool isEqual)
126 {
127     if (isEqual)
128         {
129         if (!(t1 == t2)) return false;
130         if (!(t2 == t1)) return false;
131         if ( (t1 != t2)) return false;
132         if ( (t2 != t1)) return false;
133         }
134     else /* not equal */
135         {
136         if ( (t1 == t2)) return false;
137         if ( (t2 == t1)) return false;
138         if (!(t1 != t2)) return false;
139         if (!(t2 != t1)) return false;
140         }
141 
142     return true;
143 }
144 
145 //  Easy call when you can init from something already comparable.
146 template <class T, class Param>
147 TEST_CONSTEXPR_CXX14 bool testComparisons2Values(Param val1, Param val2)
148 {
149     const bool isEqual = val1 == val2;
150 
151     return testComparisons2(T(val1), T(val2), isEqual);
152 }
153 
154 template <class T, class U = T>
155 void AssertComparisons2AreNoexcept()
156 {
157     ASSERT_NOEXCEPT(std::declval<const T&>() == std::declval<const U&>());
158     ASSERT_NOEXCEPT(std::declval<const T&>() != std::declval<const U&>());
159 }
160 
161 template <class T, class U = T>
162 void AssertComparisons2ReturnBool()
163 {
164     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() == std::declval<const U&>()), bool);
165     ASSERT_SAME_TYPE(decltype(std::declval<const T&>() != std::declval<const U&>()), bool);
166 }
167 
168 
169 template <class T, class U = T>
170 void AssertComparisons2ConvertibleToBool()
171 {
172     static_assert((std::is_convertible<decltype(std::declval<const T&>() == std::declval<const U&>()), bool>::value), "");
173     static_assert((std::is_convertible<decltype(std::declval<const T&>() != std::declval<const U&>()), bool>::value), "");
174 }
175 
176 struct LessAndEqComp {
177   int value;
178 
179   TEST_CONSTEXPR_CXX14 LessAndEqComp(int v) : value(v) {}
180 
181   friend TEST_CONSTEXPR_CXX14 bool operator<(const LessAndEqComp& lhs, const LessAndEqComp& rhs) {
182     return lhs.value < rhs.value;
183   }
184 
185   friend TEST_CONSTEXPR_CXX14 bool operator==(const LessAndEqComp& lhs, const LessAndEqComp& rhs) {
186     return lhs.value == rhs.value;
187   }
188 };
189 #endif // TEST_COMPARISONS_H
190