1 /* 2 Copyright (c) 2020-2021 Intel Corporation 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #ifndef __TBB_test_common_test_comparisons_H 18 #define __TBB_test_common_test_comparisons_H 19 20 #include "test.h" 21 22 #ifndef __TBB_TEST_CPP20_COMPARISONS 23 #define __TBB_TEST_CPP20_COMPARISONS __TBB_CPP20_COMPARISONS_PRESENT 24 #endif 25 26 #if __TBB_TEST_CPP20_COMPARISONS 27 #include <compare> 28 #endif 29 30 namespace comparisons_testing { 31 32 template <bool ExpectEqual, bool ExpectLess, typename T> 33 void testTwoWayComparisons( const T& lhs, const T& rhs ) { 34 REQUIRE_MESSAGE(((lhs < rhs) == ExpectLess), 35 "Incorrect 2-way comparison result for less operation"); 36 REQUIRE_MESSAGE(((lhs <= rhs) == (ExpectLess || ExpectEqual)), 37 "Incorrect 2-way comparison result for less or equal operation"); 38 bool ExpectGreater = ExpectEqual ? false : !ExpectLess; 39 REQUIRE_MESSAGE(((lhs > rhs) == ExpectGreater), 40 "Incorrect 2-way comparison result for greater operation"); 41 REQUIRE_MESSAGE(((lhs >= rhs) == (ExpectGreater || ExpectEqual)), 42 "Incorrect 2-way comparison result for greater or equal operation"); 43 } 44 45 template <bool ExpectEqual, typename T> 46 void testEqualityComparisons( const T& lhs, const T& rhs ) { 47 REQUIRE_MESSAGE((lhs == rhs) == ExpectEqual, 48 "Incorrect 2-way comparison result for equal operation"); 49 REQUIRE_MESSAGE((lhs != rhs) == !ExpectEqual, 50 "Incorrect 2-way comparison result for unequal operation"); 51 } 52 53 #if __TBB_TEST_CPP20_COMPARISONS 54 template <bool ExpectEqual, bool ExpectLess, typename T> 55 void testThreeWayComparisons( const T& lhs, const T& rhs ) { 56 auto three_way_result = lhs <=> rhs; 57 REQUIRE_MESSAGE((three_way_result < 0) == ExpectLess, 58 "Incorrect 3-way comparison result for less operation"); 59 REQUIRE_MESSAGE((lhs <=> rhs <= 0) == (ExpectLess || ExpectEqual), 60 "Incorrect 3-way comparison result for less or equal operation"); 61 bool ExpectGreater = ExpectEqual ? false : !ExpectLess; 62 REQUIRE_MESSAGE((lhs <=> rhs > 0) == ExpectGreater, 63 "Incorrect 3-way comparison result for greater operation"); 64 REQUIRE_MESSAGE((lhs <=> rhs >= 0) == (ExpectGreater || ExpectEqual), 65 "Incorrect 3-way comparison result for greater or equal operation"); 66 REQUIRE_MESSAGE((lhs <=> rhs == 0) == ExpectEqual, 67 "Incorrect 3-way comparison result for equal operation"); 68 REQUIRE_MESSAGE((lhs <=> rhs != 0) == !ExpectEqual, 69 "Incorrect 3-way comparison result for unequal operation"); 70 } 71 72 #endif // __TBB_TEST_CPP20_COMPARISONS 73 74 template <bool ExpectEqual, bool ExpectLess, typename T> 75 void testEqualityAndLessComparisons( const T& lhs, const T& rhs ) { 76 testEqualityComparisons<ExpectEqual>(lhs, rhs); 77 testTwoWayComparisons<ExpectEqual, ExpectLess>(lhs, rhs); 78 #if __TBB_TEST_CPP20_COMPARISONS 79 testThreeWayComparisons<ExpectEqual, ExpectLess>(lhs, rhs); 80 #endif 81 } 82 83 class TwoWayComparable { 84 public: 85 TwoWayComparable() : n(0) { 86 reset(); 87 } 88 89 TwoWayComparable( std::size_t num ) : n(num) { 90 reset(); 91 } 92 93 static void reset() { 94 equal_called = false; 95 unequal_called = false; 96 less_called = false; 97 greater_called = false; 98 less_or_equal_called = false; 99 greater_or_equal_called = false; 100 } 101 102 static bool equal_called; 103 static bool unequal_called; 104 static bool less_called; 105 static bool greater_called; 106 static bool less_or_equal_called; 107 static bool greater_or_equal_called; 108 109 friend bool operator==( const TwoWayComparable& lhs, const TwoWayComparable& rhs ) { 110 equal_called = true; 111 return lhs.n == rhs.n; 112 } 113 114 friend bool operator!=( const TwoWayComparable& lhs, const TwoWayComparable& rhs ) { 115 unequal_called = true; 116 return lhs.n != rhs.n; 117 } 118 119 friend bool operator<( const TwoWayComparable& lhs, const TwoWayComparable& rhs ) { 120 less_called = true; 121 return lhs.n < rhs.n; 122 } 123 124 friend bool operator>( const TwoWayComparable& lhs, const TwoWayComparable& rhs ) { 125 greater_called = true; 126 return lhs.n > rhs.n; 127 } 128 129 friend bool operator<=( const TwoWayComparable& lhs, const TwoWayComparable& rhs ) { 130 less_or_equal_called = true; 131 return lhs.n <= rhs.n; 132 } 133 134 friend bool operator>=( const TwoWayComparable& lhs, const TwoWayComparable& rhs ) { 135 greater_or_equal_called = true; 136 return lhs.n >= rhs.n; 137 } 138 139 protected: 140 std::size_t n; 141 142 friend struct std::hash<TwoWayComparable>; 143 }; // struct TwoWayComparable 144 145 bool TwoWayComparable::equal_called = false; 146 bool TwoWayComparable::unequal_called = false; 147 bool TwoWayComparable::less_called = false; 148 bool TwoWayComparable::greater_called = false; 149 bool TwoWayComparable::less_or_equal_called = false; 150 bool TwoWayComparable::greater_or_equal_called = false; 151 152 // This function should be executed after comparing two objects, containing TwoWayComparables 153 // using one of the comparison operators (<=>, <, >, <=, >=) 154 void check_two_way_comparison() { 155 REQUIRE_MESSAGE(TwoWayComparable::less_called, 156 "operator < was not called during the comparison"); 157 REQUIRE_MESSAGE(!TwoWayComparable::greater_called, 158 "operator > was called during the comparison"); 159 REQUIRE_MESSAGE(!TwoWayComparable::less_or_equal_called, 160 "operator <= was called during the comparison"); 161 REQUIRE_MESSAGE(!TwoWayComparable::greater_or_equal_called, 162 "operator >= was called during the comparison"); 163 REQUIRE_MESSAGE(!(TwoWayComparable::equal_called), 164 "operator == was called during the comparison"); 165 REQUIRE_MESSAGE(!(TwoWayComparable::unequal_called), 166 "operator == was called during the comparison"); 167 TwoWayComparable::reset(); 168 } 169 170 // This function should be executed after comparing two objects, containing TwoWayComparables 171 // using operator == or != 172 void check_equality_comparison() { 173 REQUIRE_MESSAGE(TwoWayComparable::equal_called, 174 "operator == was not called during the comparison"); 175 REQUIRE_MESSAGE(!(TwoWayComparable::unequal_called), 176 "operator != was called during the comparison"); 177 TwoWayComparable::reset(); 178 } 179 180 #if __TBB_TEST_CPP20_COMPARISONS 181 class ThreeWayComparable : public TwoWayComparable { 182 public: 183 ThreeWayComparable() : TwoWayComparable() { reset(); } 184 185 ThreeWayComparable( std::size_t num ) : TwoWayComparable(num) { reset(); } 186 187 static void reset() { 188 TwoWayComparable::reset(); 189 three_way_called = false; 190 } 191 192 static bool three_way_called; 193 194 friend auto operator<=>( const ThreeWayComparable& lhs, const ThreeWayComparable& rhs ) { 195 three_way_called = true; 196 return lhs.n <=> rhs.n; 197 } 198 199 friend bool operator==( const ThreeWayComparable&, const ThreeWayComparable& ) = default; 200 }; // class ThreeWayComparable 201 202 bool ThreeWayComparable::three_way_called = false; 203 204 // This function should be executed after comparing objects, containing ThreeWayComparables 205 // using one of the comparison operators (<=>, <, >, <=, >=) 206 void check_three_way_comparison() { 207 REQUIRE_MESSAGE(ThreeWayComparable::three_way_called, "operator <=> was not called during the comparison"); 208 REQUIRE_MESSAGE(!ThreeWayComparable::less_called, "operator < was called during the comparison"); 209 REQUIRE_MESSAGE(!ThreeWayComparable::greater_called, "operator > was called during the comparison"); 210 REQUIRE_MESSAGE(!ThreeWayComparable::less_or_equal_called, "operator <= was called during the comparison"); 211 REQUIRE_MESSAGE(!ThreeWayComparable::greater_or_equal_called, "operator >= was called during the comparison"); 212 ThreeWayComparable::reset(); 213 } 214 215 // Required for testing synthesized_three_way_comparison 216 class ThreeWayComparableOnly { 217 public: 218 ThreeWayComparableOnly() : n(0) {} 219 ThreeWayComparableOnly( std::size_t num ) : n(num) {} 220 221 friend auto operator<=>( const ThreeWayComparableOnly& lhs, const ThreeWayComparableOnly& rhs ) { 222 return lhs.n <=> rhs.n; 223 } 224 friend bool operator==( const ThreeWayComparableOnly& lhs, const ThreeWayComparableOnly& rhs ) { 225 return lhs.n == rhs.n; 226 } 227 private: 228 std::size_t n; 229 }; // class ThreeWayComparableOnly 230 231 // Required for testing synthesized_three_way_comparison 232 class LessComparableOnly { 233 public: 234 LessComparableOnly() : n(0) {} 235 LessComparableOnly( std::size_t num ) : n(num) {} 236 237 friend bool operator<( const LessComparableOnly& lhs, const LessComparableOnly& rhs ) { 238 return lhs.n < rhs.n; 239 } 240 friend bool operator==( const LessComparableOnly& lhs, const LessComparableOnly& rhs ) { 241 return lhs.n == rhs.n; 242 } 243 private: 244 std::size_t n; 245 }; // class LessComparableOnly 246 247 #endif // __TBB_TEST_CPP20_COMPARISONS 248 } // namespace comparisons_testing 249 250 namespace std { 251 252 template <> 253 struct hash<comparisons_testing::TwoWayComparable> { 254 std::size_t operator()( const comparisons_testing::TwoWayComparable& val ) const { 255 return std::hash<std::size_t>{}(val.n); 256 } 257 }; 258 259 } // namespace std 260 261 #endif // __TBB_test_common_test_comparisons_H 262