1 //===- unittests/StaticAnalyzer/RangeSetTest.cpp ----------------------===// 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 9 #include "clang/Basic/Builtins.h" 10 #include "clang/Basic/FileManager.h" 11 #include "clang/Basic/SourceManager.h" 12 #include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h" 13 #include "clang/Tooling/Tooling.h" 14 #include "llvm/ADT/APSInt.h" 15 #include "llvm/Support/raw_ostream.h" 16 #include "gtest/gtest.h" 17 18 using namespace clang; 19 using namespace ento; 20 21 namespace clang { 22 namespace ento { 23 24 template <class RangeOrSet> static std::string toString(const RangeOrSet &Obj) { 25 std::string ObjRepresentation; 26 llvm::raw_string_ostream SS(ObjRepresentation); 27 Obj.dump(SS); 28 return SS.str(); 29 } 30 LLVM_ATTRIBUTE_UNUSED static std::string toString(const llvm::APSInt &Point) { 31 return toString(Point, 10); 32 } 33 // We need it here for better fail diagnostics from gtest. 34 LLVM_ATTRIBUTE_UNUSED static std::ostream &operator<<(std::ostream &OS, 35 const RangeSet &Set) { 36 return OS << toString(Set); 37 } 38 // We need it here for better fail diagnostics from gtest. 39 LLVM_ATTRIBUTE_UNUSED static std::ostream &operator<<(std::ostream &OS, 40 const Range &R) { 41 return OS << toString(R); 42 } 43 LLVM_ATTRIBUTE_UNUSED static std::ostream &operator<<(std::ostream &OS, 44 APSIntType Ty) { 45 return OS << (Ty.isUnsigned() ? "u" : "s") << Ty.getBitWidth(); 46 } 47 48 } // namespace ento 49 } // namespace clang 50 51 namespace { 52 53 template <class T> constexpr bool is_signed_v = std::is_signed<T>::value; 54 55 template <typename T> struct TestValues { 56 static constexpr T MIN = std::numeric_limits<T>::min(); 57 static constexpr T MAX = std::numeric_limits<T>::max(); 58 // MID is a value in the middle of the range 59 // which unary minus does not affect on, 60 // e.g. int8/int32(0), uint8(128), uint32(2147483648). 61 static constexpr T MID = 62 is_signed_v<T> ? 0 : ~(static_cast<T>(-1) / static_cast<T>(2)); 63 static constexpr T A = MID - (MAX - MID) / 3 * 2; 64 static constexpr T B = MID - (MAX - MID) / 3; 65 static constexpr T C = -B; 66 static constexpr T D = -A; 67 68 static_assert(MIN < A && A < B && B < MID && MID < C && C < D && D < MAX, 69 "Values shall be in an ascending order"); 70 // Clear bits in low bytes by the given amount. 71 template <T Value, size_t Bytes> 72 static constexpr T ClearLowBytes = 73 static_cast<T>(static_cast<uint64_t>(Value) 74 << ((Bytes >= CHAR_BIT) ? 0 : Bytes) * CHAR_BIT); 75 76 template <T Value, typename Base> 77 static constexpr T TruncZeroOf = ClearLowBytes<Value + 1, sizeof(Base)>; 78 79 // Random number with active bits in every byte. 0xAAAA'AAAA 80 static constexpr T XAAA = static_cast<T>( 81 0b10101010'10101010'10101010'10101010'10101010'10101010'10101010'10101010); 82 template <typename Base> 83 static constexpr T XAAATruncZeroOf = TruncZeroOf<XAAA, Base>; // 0xAAAA'AB00 84 85 // Random number with active bits in every byte. 0x5555'5555 86 static constexpr T X555 = static_cast<T>( 87 0b01010101'01010101'01010101'01010101'01010101'01010101'01010101'01010101); 88 template <typename Base> 89 static constexpr T X555TruncZeroOf = TruncZeroOf<X555, Base>; // 0x5555'5600 90 91 // Numbers for ranges with the same bits in the lowest byte. 92 // 0xAAAA'AA2A 93 static constexpr T FromA = ClearLowBytes<XAAA, sizeof(T) - 1> + 42; 94 static constexpr T ToA = FromA + 2; // 0xAAAA'AA2C 95 // 0x5555'552A 96 static constexpr T FromB = ClearLowBytes<X555, sizeof(T) - 1> + 42; 97 static constexpr T ToB = FromB + 2; // 0x5555'552C 98 }; 99 100 template <typename T> 101 static constexpr APSIntType APSIntTy = 102 APSIntType(sizeof(T) * CHAR_BIT, !is_signed_v<T>); 103 104 template <typename BaseType> class RangeSetTest : public testing::Test { 105 public: 106 // Init block 107 std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCode("struct foo;"); 108 ASTContext &Context = AST->getASTContext(); 109 llvm::BumpPtrAllocator Arena; 110 BasicValueFactory BVF{Context, Arena}; 111 RangeSet::Factory F{BVF}; 112 // End init block 113 114 using Self = RangeSetTest<BaseType>; 115 template <typename T> using RawRangeT = std::pair<T, T>; 116 template <typename T> 117 using RawRangeSetT = std::initializer_list<RawRangeT<T>>; 118 using RawRange = RawRangeT<BaseType>; 119 using RawRangeSet = RawRangeSetT<BaseType>; 120 121 template <typename T> const llvm::APSInt &from(T X) { 122 static llvm::APSInt Int = APSIntTy<T>.getZeroValue(); 123 Int = X; 124 return BVF.getValue(Int); 125 } 126 127 template <typename T> Range from(const RawRangeT<T> &Init) { 128 return Range(from(Init.first), from(Init.second)); 129 } 130 131 template <typename T> 132 RangeSet from(RawRangeSetT<T> Init, APSIntType Ty = APSIntTy<BaseType>) { 133 RangeSet RangeSet = F.getEmptySet(); 134 for (const auto &Raw : Init) { 135 RangeSet = F.add(RangeSet, from(Raw)); 136 } 137 return RangeSet; 138 } 139 140 template <class F, class... RawArgTypes> 141 void wrap(F ActualFunction, RawArgTypes &&... Args) { 142 (this->*ActualFunction)(from(std::forward<RawArgTypes>(Args))...); 143 } 144 145 void checkNegateImpl(RangeSet Original, RangeSet Expected) { 146 RangeSet NegatedFromOriginal = F.negate(Original); 147 EXPECT_EQ(NegatedFromOriginal, Expected); 148 // Negate negated back and check with original. 149 RangeSet NegatedBackward = F.negate(NegatedFromOriginal); 150 EXPECT_EQ(NegatedBackward, Original); 151 } 152 153 void checkNegate(RawRangeSet RawOriginal, RawRangeSet RawExpected) { 154 wrap(&Self::checkNegateImpl, RawOriginal, RawExpected); 155 } 156 157 template <class PointOrSet> 158 void checkIntersectImpl(RangeSet LHS, PointOrSet RHS, RangeSet Expected) { 159 RangeSet Result = F.intersect(LHS, RHS); 160 EXPECT_EQ(Result, Expected) 161 << "while intersecting " << toString(LHS) << " and " << toString(RHS); 162 } 163 164 void checkIntersectRangeImpl(RangeSet LHS, const llvm::APSInt &Lower, 165 const llvm::APSInt &Upper, RangeSet Expected) { 166 RangeSet Result = F.intersect(LHS, Lower, Upper); 167 EXPECT_EQ(Result, Expected) 168 << "while intersecting " << toString(LHS) << " and [" << toString(Lower) 169 << ", " << toString(Upper) << "]"; 170 } 171 172 void checkIntersect(RawRangeSet RawLHS, RawRangeSet RawRHS, 173 RawRangeSet RawExpected) { 174 wrap(&Self::checkIntersectImpl<RangeSet>, RawLHS, RawRHS, RawExpected); 175 } 176 177 void checkIntersect(RawRangeSet RawLHS, BaseType RawRHS, 178 RawRangeSet RawExpected) { 179 wrap(&Self::checkIntersectImpl<const llvm::APSInt &>, RawLHS, RawRHS, 180 RawExpected); 181 } 182 183 void checkIntersect(RawRangeSet RawLHS, BaseType RawLower, BaseType RawUpper, 184 RawRangeSet RawExpected) { 185 wrap(&Self::checkIntersectRangeImpl, RawLHS, RawLower, RawUpper, 186 RawExpected); 187 } 188 189 void checkContainsImpl(RangeSet LHS, const llvm::APSInt &RHS, bool Expected) { 190 bool Result = LHS.contains(RHS); 191 EXPECT_EQ(Result, Expected) 192 << toString(LHS) << (Result ? " contains " : " doesn't contain ") 193 << toString(RHS); 194 } 195 196 void checkContains(RawRangeSet RawLHS, BaseType RawRHS, bool Expected) { 197 checkContainsImpl(from(RawLHS), from(RawRHS), Expected); 198 } 199 200 template <class RHSType> 201 void checkAddImpl(RangeSet LHS, RHSType RHS, RangeSet Expected) { 202 RangeSet Result = F.add(LHS, RHS); 203 EXPECT_EQ(Result, Expected) 204 << "while adding " << toString(LHS) << " and " << toString(RHS); 205 } 206 207 void checkAdd(RawRangeSet RawLHS, RawRange RawRHS, RawRangeSet RawExpected) { 208 wrap(&Self::checkAddImpl<Range>, RawLHS, RawRHS, RawExpected); 209 } 210 211 void checkAdd(RawRangeSet RawLHS, RawRangeSet RawRHS, 212 RawRangeSet RawExpected) { 213 wrap(&Self::checkAddImpl<RangeSet>, RawLHS, RawRHS, RawExpected); 214 } 215 216 void checkAdd(RawRangeSet RawLHS, BaseType RawRHS, RawRangeSet RawExpected) { 217 wrap(&Self::checkAddImpl<const llvm::APSInt &>, RawLHS, RawRHS, 218 RawExpected); 219 } 220 221 template <class RHSType> 222 void checkUniteImpl(RangeSet LHS, RHSType RHS, RangeSet Expected) { 223 RangeSet Result = F.unite(LHS, RHS); 224 EXPECT_EQ(Result, Expected) 225 << "while uniting " << toString(LHS) << " and " << toString(RHS); 226 } 227 228 void checkUnite(RawRangeSet RawLHS, RawRange RawRHS, 229 RawRangeSet RawExpected) { 230 wrap(&Self::checkUniteImpl<Range>, RawLHS, RawRHS, RawExpected); 231 } 232 233 void checkUnite(RawRangeSet RawLHS, RawRangeSet RawRHS, 234 RawRangeSet RawExpected) { 235 wrap(&Self::checkUniteImpl<RangeSet>, RawLHS, RawRHS, RawExpected); 236 } 237 238 void checkUnite(RawRangeSet RawLHS, BaseType RawRHS, 239 RawRangeSet RawExpected) { 240 wrap(&Self::checkUniteImpl<const llvm::APSInt &>, RawLHS, RawRHS, 241 RawExpected); 242 } 243 244 void checkDeleteImpl(const llvm::APSInt &Point, RangeSet From, 245 RangeSet Expected) { 246 RangeSet Result = F.deletePoint(From, Point); 247 EXPECT_EQ(Result, Expected) 248 << "while deleting " << toString(Point) << " from " << toString(From); 249 } 250 251 void checkDelete(BaseType Point, RawRangeSet RawFrom, 252 RawRangeSet RawExpected) { 253 wrap(&Self::checkDeleteImpl, Point, RawFrom, RawExpected); 254 } 255 256 void checkCastToImpl(RangeSet What, APSIntType Ty, RangeSet Expected) { 257 RangeSet Result = F.castTo(What, Ty); 258 EXPECT_EQ(Result, Expected) 259 << "while casting " << toString(What) << " to " << Ty; 260 } 261 262 template <typename From, typename To> 263 void checkCastTo(RawRangeSetT<From> What, RawRangeSetT<To> Expected) { 264 static constexpr APSIntType FromTy = APSIntTy<From>; 265 static constexpr APSIntType ToTy = APSIntTy<To>; 266 this->checkCastToImpl(from(What, FromTy), ToTy, from(Expected, ToTy)); 267 } 268 }; 269 270 using IntTypes = ::testing::Types<int8_t, uint8_t, int16_t, uint16_t, int32_t, 271 uint32_t, int64_t, uint64_t>; 272 TYPED_TEST_SUITE(RangeSetTest, IntTypes, ); 273 274 TYPED_TEST(RangeSetTest, RangeSetNegateTest) { 275 using TV = TestValues<TypeParam>; 276 constexpr auto MIN = TV::MIN; 277 constexpr auto MAX = TV::MAX; 278 constexpr auto MID = TV::MID; 279 constexpr auto A = TV::A; 280 constexpr auto B = TV::B; 281 constexpr auto C = TV::C; 282 constexpr auto D = TV::D; 283 284 this->checkNegate({{MIN, A}}, {{MIN, MIN}, {D, MAX}}); 285 this->checkNegate({{MIN, C}}, {{MIN, MIN}, {B, MAX}}); 286 this->checkNegate({{MIN, MID}}, {{MIN, MIN}, {MID, MAX}}); 287 this->checkNegate({{MIN, MAX}}, {{MIN, MAX}}); 288 this->checkNegate({{A, D}}, {{A, D}}); 289 this->checkNegate({{A, B}}, {{C, D}}); 290 this->checkNegate({{MIN, A}, {D, MAX}}, {{MIN, A}, {D, MAX}}); 291 this->checkNegate({{MIN, B}, {MID, D}}, {{MIN, MIN}, {A, MID}, {C, MAX}}); 292 this->checkNegate({{MIN, MID}, {C, D}}, {{MIN, MIN}, {A, B}, {MID, MAX}}); 293 this->checkNegate({{MIN, MID}, {C, MAX}}, {{MIN, B}, {MID, MAX}}); 294 this->checkNegate({{A, MID}, {D, MAX}}, {{MIN + 1, A}, {MID, D}}); 295 this->checkNegate({{A, A}}, {{D, D}}); 296 this->checkNegate({{MID, MID}}, {{MID, MID}}); 297 this->checkNegate({{MAX, MAX}}, {{MIN + 1, MIN + 1}}); 298 } 299 300 TYPED_TEST(RangeSetTest, RangeSetPointIntersectTest) { 301 // Check that we can correctly intersect empty sets. 302 this->checkIntersect({}, 42, {}); 303 // Check that intersection with itself produces the same set. 304 this->checkIntersect({{42, 42}}, 42, {{42, 42}}); 305 // Check more general cases. 306 this->checkIntersect({{0, 10}, {20, 30}, {30, 40}, {50, 60}}, 42, {}); 307 this->checkIntersect({{0, 10}, {20, 30}, {30, 60}}, 42, {{42, 42}}); 308 } 309 310 TYPED_TEST(RangeSetTest, RangeSetRangeIntersectTest) { 311 using TV = TestValues<TypeParam>; 312 constexpr auto MIN = TV::MIN; 313 constexpr auto MAX = TV::MAX; 314 315 // Check that we can correctly intersect empty sets. 316 this->checkIntersect({}, 10, 20, {}); 317 this->checkIntersect({}, 20, 10, {}); 318 // Check that intersection with itself produces the same set. 319 this->checkIntersect({{10, 20}}, 10, 20, {{10, 20}}); 320 this->checkIntersect({{MIN, 10}, {20, MAX}}, 20, 10, {{MIN, 10}, {20, MAX}}); 321 // Check non-overlapping range intersections. 322 this->checkIntersect({{10, 20}}, 21, 9, {}); 323 this->checkIntersect({{MIN, 9}, {21, MAX}}, 10, 20, {}); 324 // Check more general cases. 325 this->checkIntersect({{0, 10}, {20, 30}, {30, 40}, {50, 60}}, 10, 35, 326 {{10, 10}, {20, 30}, {30, 35}}); 327 this->checkIntersect({{0, 10}, {20, 30}, {30, 40}, {50, 60}}, 35, 10, 328 {{0, 10}, {35, 40}, {50, 60}}); 329 } 330 331 TYPED_TEST(RangeSetTest, RangeSetGenericIntersectTest) { 332 // Check that we can correctly intersect empty sets. 333 this->checkIntersect({}, {}, {}); 334 this->checkIntersect({}, {{0, 10}}, {}); 335 this->checkIntersect({{0, 10}}, {}, {}); 336 337 this->checkIntersect({{0, 10}}, {{4, 6}}, {{4, 6}}); 338 this->checkIntersect({{0, 10}}, {{4, 20}}, {{4, 10}}); 339 // Check that intersection with points works as expected. 340 this->checkIntersect({{0, 10}}, {{4, 4}}, {{4, 4}}); 341 // All ranges are closed, check that intersection with edge points works as 342 // expected. 343 this->checkIntersect({{0, 10}}, {{10, 10}}, {{10, 10}}); 344 345 // Let's check that we can skip some intervals and partially intersect 346 // other intervals. 347 this->checkIntersect({{0, 2}, {4, 5}, {6, 9}, {10, 11}, {12, 12}, {13, 15}}, 348 {{8, 14}, {20, 30}}, 349 {{8, 9}, {10, 11}, {12, 12}, {13, 14}}); 350 // Check more generic case. 351 this->checkIntersect( 352 {{0, 1}, {2, 3}, {5, 6}, {7, 15}, {25, 30}}, 353 {{4, 10}, {11, 11}, {12, 16}, {17, 17}, {19, 20}, {21, 23}, {24, 27}}, 354 {{5, 6}, {7, 10}, {11, 11}, {12, 15}, {25, 27}}); 355 } 356 357 TYPED_TEST(RangeSetTest, RangeSetContainsTest) { 358 // Check with an empty set. 359 this->checkContains({}, 10, false); 360 // Check contains with sets of size one: 361 // * when the whole range is less 362 this->checkContains({{0, 5}}, 10, false); 363 // * when the whole range is greater 364 this->checkContains({{20, 25}}, 10, false); 365 // * when the range is just the point we are looking for 366 this->checkContains({{10, 10}}, 10, true); 367 // * when the range starts with the point 368 this->checkContains({{10, 15}}, 10, true); 369 // * when the range ends with the point 370 this->checkContains({{5, 10}}, 10, true); 371 // * when the range has the point somewhere in the middle 372 this->checkContains({{0, 25}}, 10, true); 373 // Check similar cases, but with larger sets. 374 this->checkContains({{0, 5}, {10, 10}, {15, 20}}, 10, true); 375 this->checkContains({{0, 5}, {10, 12}, {15, 20}}, 10, true); 376 this->checkContains({{0, 5}, {5, 7}, {8, 10}, {12, 41}}, 10, true); 377 378 using TV = TestValues<TypeParam>; 379 constexpr auto MIN = TV::MIN; 380 constexpr auto MAX = TV::MAX; 381 constexpr auto MID = TV::MID; 382 383 this->checkContains({{MIN, MAX}}, 0, true); 384 this->checkContains({{MIN, MAX}}, MID, true); 385 this->checkContains({{MIN, MAX}}, -10, true); 386 this->checkContains({{MIN, MAX}}, 10, true); 387 } 388 389 TYPED_TEST(RangeSetTest, RangeSetAddTest) { 390 // Check adding single points 391 this->checkAdd({}, 10, {{10, 10}}); 392 this->checkAdd({{0, 5}}, 10, {{0, 5}, {10, 10}}); 393 this->checkAdd({{0, 5}, {30, 40}}, 10, {{0, 5}, {10, 10}, {30, 40}}); 394 395 // Check adding single ranges. 396 this->checkAdd({}, {10, 20}, {{10, 20}}); 397 this->checkAdd({{0, 5}}, {10, 20}, {{0, 5}, {10, 20}}); 398 this->checkAdd({{0, 5}, {30, 40}}, {10, 20}, {{0, 5}, {10, 20}, {30, 40}}); 399 400 // Check adding whole sets of ranges. 401 this->checkAdd({{0, 5}}, {{10, 20}}, {{0, 5}, {10, 20}}); 402 // Check that ordering of ranges is as expected. 403 this->checkAdd({{0, 5}, {30, 40}}, {{10, 20}}, {{0, 5}, {10, 20}, {30, 40}}); 404 this->checkAdd({{0, 5}, {30, 40}}, {{10, 20}, {50, 60}}, 405 {{0, 5}, {10, 20}, {30, 40}, {50, 60}}); 406 this->checkAdd({{10, 20}, {50, 60}}, {{0, 5}, {30, 40}, {70, 80}}, 407 {{0, 5}, {10, 20}, {30, 40}, {50, 60}, {70, 80}}); 408 } 409 410 TYPED_TEST(RangeSetTest, RangeSetDeletePointTest) { 411 using TV = TestValues<TypeParam>; 412 constexpr auto MIN = TV::MIN; 413 constexpr auto MAX = TV::MAX; 414 constexpr auto MID = TV::MID; 415 416 this->checkDelete(MID, {{MIN, MAX}}, {{MIN, MID - 1}, {MID + 1, MAX}}); 417 // Check that delete works with an empty set. 418 this->checkDelete(10, {}, {}); 419 // Check that delete can remove entire ranges. 420 this->checkDelete(10, {{10, 10}}, {}); 421 this->checkDelete(10, {{0, 5}, {10, 10}, {20, 30}}, {{0, 5}, {20, 30}}); 422 // Check that delete can split existing ranges into two. 423 this->checkDelete(10, {{0, 5}, {7, 15}, {20, 30}}, 424 {{0, 5}, {7, 9}, {11, 15}, {20, 30}}); 425 // Check that delete of the point not from the range set works as expected. 426 this->checkDelete(10, {{0, 5}, {20, 30}}, {{0, 5}, {20, 30}}); 427 } 428 429 TYPED_TEST(RangeSetTest, RangeSetUniteTest) { 430 using TV = TestValues<TypeParam>; 431 constexpr auto MIN = TV::MIN; 432 constexpr auto MAX = TV::MAX; 433 constexpr auto MID = TV::MID; 434 constexpr auto A = TV::A; 435 constexpr auto B = TV::B; 436 constexpr auto C = TV::C; 437 constexpr auto D = TV::D; 438 439 // LHS and RHS is empty. 440 // RHS => 441 // LHS => = 442 // ___________________ ___________________ 443 this->checkUnite({}, {}, {}); 444 445 // RHS is empty. 446 // RHS => 447 // LHS => _____ = _____ 448 // ______/_____\______ ______/_____\______ 449 this->checkUnite({{A, B}}, {}, {{A, B}}); 450 this->checkUnite({{A, B}, {C, D}}, {}, {{A, B}, {C, D}}); 451 this->checkUnite({{MIN, MIN}}, {}, {{MIN, MIN}}); 452 this->checkUnite({{MAX, MAX}}, {}, {{MAX, MAX}}); 453 this->checkUnite({{MIN, MIN}, {MAX, MAX}}, {}, {{MIN, MIN}, {MAX, MAX}}); 454 455 // LHS is empty. 456 // RHS => ___ 457 // LHS => / \ = _____ 458 // ______/_____\______ ______/_____\______ 459 this->checkUnite({}, B, {{B, B}}); 460 this->checkUnite({}, {B, C}, {{B, C}}); 461 this->checkUnite({}, {{MIN, B}, {C, MAX}}, {{MIN, B}, {C, MAX}}); 462 this->checkUnite({}, {{MIN, MIN}}, {{MIN, MIN}}); 463 this->checkUnite({}, {{MAX, MAX}}, {{MAX, MAX}}); 464 this->checkUnite({}, {{MIN, MIN}, {MAX, MAX}}, {{MIN, MIN}, {MAX, MAX}}); 465 466 // RHS is detached from LHS. 467 // RHS => ___ 468 // LHS => ___ / \ = ___ _____ 469 // __/___\___/_____\__ __/___\___/_____\__ 470 this->checkUnite({{A, C}}, D, {{A, C}, {D, D}}); 471 this->checkUnite({{MID, C}, {D, MAX}}, A, {{A, A}, {MID, C}, {D, MAX}}); 472 this->checkUnite({{A, B}}, {MID, D}, {{A, B}, {MID, D}}); 473 this->checkUnite({{MIN, A}, {D, MAX}}, {B, C}, {{MIN, A}, {B, C}, {D, MAX}}); 474 this->checkUnite({{B, MID}, {D, MAX}}, {{MIN, A}, {C, C}}, 475 {{MIN, A}, {B, MID}, {C, C}, {D, MAX}}); 476 this->checkUnite({{MIN, A}, {C, C}}, {{B, MID}, {D, MAX}}, 477 {{MIN, A}, {B, MID}, {C, C}, {D, MAX}}); 478 this->checkUnite({{A, B}}, {{MAX, MAX}}, {{A, B}, {MAX, MAX}}); 479 this->checkUnite({{MIN, MIN}}, {A, B}, {{MIN, MIN}, {A, B}}); 480 this->checkUnite({{MIN, MIN}}, {MAX, MAX}, {{MIN, MIN}, {MAX, MAX}}); 481 482 // RHS is inside LHS. 483 // RHS => ___ 484 // LHS => ___/___\___ = ___________ 485 // ___/__/_____\__\___ ___/___________\___ 486 this->checkUnite({{A, C}}, MID, {{A, C}}); 487 this->checkUnite({{A, D}}, {B, C}, {{A, D}}); 488 this->checkUnite({{MIN, MAX}}, {B, C}, {{MIN, MAX}}); 489 490 // RHS wraps LHS. 491 // RHS => _________ 492 // LHS => / _____ \ = ___________ 493 // ___/__/_____\__\___ ___/___________\___ 494 this->checkUnite({{MID, MID}}, {A, D}, {{A, D}}); 495 this->checkUnite({{B, C}}, {A, D}, {{A, D}}); 496 this->checkUnite({{A, B}}, {MIN, MAX}, {{MIN, MAX}}); 497 498 // RHS equals to LHS. 499 // RHS => _________ 500 // LHS => /_________\ = ___________ 501 // ___/___________\___ ___/___________\___ 502 this->checkUnite({{MIN, MIN}}, MIN, {{MIN, MIN}}); 503 this->checkUnite({{A, B}}, {A, B}, {{A, B}}); 504 this->checkUnite({{MAX, MAX}}, {{MAX, MAX}}, {{MAX, MAX}}); 505 this->checkUnite({{MIN, MIN}}, {{MIN, MIN}}, {{MIN, MIN}}); 506 this->checkUnite({{MIN, MIN}, {MAX, MAX}}, {{MIN, MIN}, {MAX, MAX}}, 507 {{MIN, MIN}, {MAX, MAX}}); 508 509 // RHS edge is MIN and attached and inside LHS. 510 // RHS => _____ 511 // LHS => /_____\_____ = ___________ 512 // /_______\____\___ /___________\___ 513 this->checkUnite({{MIN, A}}, {MIN, B}, {{MIN, B}}); 514 515 // RHS edge is MIN and attached and outsude LHS. 516 // RHS => __________ 517 // LHS => /______ \ = ___________ 518 // /_______\____\___ /___________\___ 519 this->checkUnite({{MIN, B}}, {MIN, A}, {{MIN, B}}); 520 521 // RHS intersects right of LHS. 522 // RHS => ______ 523 // LHS => ___/____ \ = ___________ 524 // ___/__/_____\__\___ ___/___________\___ 525 this->checkUnite({{A, C}}, C, {{A, C}}); 526 this->checkUnite({{A, C}}, {B, D}, {{A, D}}); 527 528 // RHS intersects left of LHS. 529 // RHS => ______ 530 // LHS => / ____\___ = ___________ 531 // ___/__/_____\__\___ ___/___________\___ 532 this->checkUnite({{B, D}}, B, {{B, D}}); 533 this->checkUnite({{B, D}}, {A, C}, {{A, D}}); 534 this->checkUnite({{MID, MAX}}, {MIN, MID}, {{MIN, MAX}}); 535 536 // RHS adjacent to LHS on right. 537 // RHS => _____ 538 // LHS => ______ / \ = _______________ 539 // _/______\/_______\_ _/_______________\_ 540 this->checkUnite({{A, B - 1}}, B, {{A, B}}); 541 this->checkUnite({{A, C}}, {C + 1, D}, {{A, D}}); 542 this->checkUnite({{MIN, MID}}, {MID + 1, MAX}, {{MIN, MAX}}); 543 544 // RHS adjacent to LHS on left. 545 // RHS => _____ 546 // LHS => / \ ______ = _______________ 547 // _/_______\/______\_ _/_______________\_ 548 this->checkUnite({{B + 1, C}}, B, {{B, C}}); 549 this->checkUnite({{B, D}}, {A, B - 1}, {{A, D}}); 550 551 // RHS adjacent to LHS in between. 552 // RHS => ___ 553 // LHS => ___ / \ ___ = _______________ 554 // _/___\/_____\/___\_ _/_______________\_ 555 this->checkUnite({{A, MID - 1}, {MID + 1, D}}, MID, {{A, D}}); 556 this->checkUnite({{MIN, A}, {D, MAX}}, {A + 1, D - 1}, {{MIN, MAX}}); 557 558 // RHS adjacent to LHS on the outside. 559 // RHS => __ __ 560 // LHS => / \ ___ / \ = _______________ 561 // _/____\/___\/____\_ _/_______________\_ 562 this->checkUnite({{C, C}}, {{A, C - 1}, {C + 1, D}}, {{A, D}}); 563 this->checkUnite({{B, MID}}, {{A, B - 1}, {MID + 1, D}}, {{A, D}}); 564 565 // RHS wraps two subranges of LHS. 566 // RHS => ___________ 567 // LHS => / ___ ___ \ = _____________ 568 // __/_/___\_/___\_\__ __/_____________\__ 569 this->checkUnite({{B, B}, {MID, MID}, {C, C}}, {{A, D}}, {{A, D}}); 570 this->checkUnite({{A, B}, {MID, C}}, {{MIN, D}}, {{MIN, D}}); 571 572 // RHS intersects two subranges of LHS. 573 // RHS => _________ 574 // LHS => __/__ _\__ = _______________ 575 // _/_/___\____/__\_\_ _/_______________\_ 576 this->checkUnite({{MIN, B}, {C, MAX}}, {{A, D}}, {{MIN, MAX}}); 577 this->checkUnite({{A, MID}, {C, MAX}}, {{B, D}}, {{A, MAX}}); 578 579 // Multiple intersections. 580 581 // clang-format off 582 // RHS => 583 // LHS => /\ /\ = __ __ 584 // _/__\_/__\_/\_/\_/\_ _/__\_/__\_/\_/\_/\_ 585 this->checkUnite({{MID, C}, {C + 2, D - 2}, {D, MAX}}, 586 {{MIN, A}, {A + 2, B}}, 587 {{MIN, A}, {A + 2, B}, {MID, C}, {C + 2, D - 2}, {D, MAX}}); 588 this->checkUnite({{B, B}, {C, C}, {MAX, MAX}}, 589 {{MIN, MIN}, {A, A}}, 590 {{MIN, MIN}, {A, A}, {B, B}, {C, C}, {MAX, MAX}}); 591 592 // RHS => 593 // LHS => /\ /\ = __ __ 594 // _/\_/\_/\__/__\_/__\_ _/\_/\_/\_/__\_/__\_ 595 this->checkUnite({{MIN, A}, {A + 2, B}, {MID, C}}, 596 {{C + 2, D - 2}, {D, MAX}}, 597 {{MIN, A}, {A + 2, B}, {MID, C}, {C + 2, D - 2}, {D, MAX}}); 598 this->checkUnite({{MIN, MIN}, {A, A}, {B, B}}, 599 {{C, C}, {MAX, MAX}}, 600 {{MIN, MIN}, {A, A}, {B, B}, {C, C}, {MAX, MAX}}); 601 602 // RHS => 603 // LHS => _ /\ _ /\ _ /\ = 604 // _/_\_/__\_/_\_/__\_/_\_/__\_ 605 // 606 // RSLT => _ __ _ __ _ __ 607 // _/_\_/__\_/_\_/__\_/_\_/__\_ 608 this->checkUnite({{MIN, A}, {B + 2, MID}, {C + 2, D}}, 609 {{A + 2, B}, {MID + 2, C}, {D + 2, MAX}}, 610 {{MIN, A}, {A + 2, B}, {B + 2, MID}, {MID + 2, C}, {C + 2, D}, {D + 2, MAX}}); 611 this->checkUnite({{MIN, MIN}, {B, B}, {D, D}}, 612 {{A, A}, {C, C}, {MAX, MAX}}, 613 {{MIN, MIN}, {A, A}, {B, B}, {C, C}, {D, D}, {MAX, MAX}}); 614 615 // RHS => 616 // LHS => /\ _ /\ _ /\ _ = 617 // _/__\_/_\_/__\_/_\_/__\_/_\_ 618 // 619 // RSLT => __ _ __ _ __ _ 620 // _/__\_/_\_/__\_/_\_/__\_/_\_ 621 this->checkUnite({{A + 2, B}, {MID + 2, C}, {D + 2, MAX}}, 622 {{MIN, A}, {B + 2, MID}, {C + 2, D}}, 623 {{MIN, A}, {A + 2, B}, {B + 2, MID}, {MID + 2, C}, {C + 2, D}, {D + 2, MAX}}); 624 this->checkUnite({{A, A}, {C, C}, {MAX, MAX}}, 625 {{MIN, MIN}, {B, B}, {D, D}}, 626 {{MIN, MIN}, {A, A}, {B, B}, {C, C}, {D, D}, {MAX, MAX}}); 627 628 // RHS => _ __ _ 629 // LHS => /_\ /_ \ _ / \ = ___ ____________ 630 // _/___\_/__\_\/_\/___\_ _/___\_/____________\_ 631 this->checkUnite({{MIN, A}, {B, C}, {D, MAX}}, 632 {{MIN, A}, {B, C - 2}, {C + 1, D - 1}}, 633 {{MIN, A}, {B, MAX}}); 634 this->checkUnite({{A, A}, {B, MID}, {D, D}}, 635 {{A, A}, {B, B}, {MID + 1, D - 1}}, 636 {{A, A}, {B, D}}); 637 638 // RHS => ___ ___ 639 // LHS => /\ _/_ \_ / _ \ /\ = 640 // _/\_/__\//__\ /\\_/_/_\_\_/__\_ 641 // 642 // RSLT => ___________ _____ __ 643 // _/\_/___________\_/_____\_/__\_ 644 this->checkUnite({{MIN, MIN}, {B, MID}, {MID + 1, C}, {C + 4, D - 1}}, 645 {{A, B - 1}, {B + 1, C - 1}, {C + 2, D}, {MAX - 1, MAX}}, 646 {{MIN, MIN}, {A, C}, {C + 2, D}, {MAX - 1, MAX}}); 647 // clang-format on 648 } 649 650 template <typename From, typename To> struct CastType { 651 using FromType = From; 652 using ToType = To; 653 }; 654 655 template <typename Type> 656 class RangeSetCastToNoopTest : public RangeSetTest<typename Type::FromType> {}; 657 template <typename Type> 658 class RangeSetCastToPromotionTest 659 : public RangeSetTest<typename Type::FromType> {}; 660 template <typename Type> 661 class RangeSetCastToTruncationTest 662 : public RangeSetTest<typename Type::FromType> {}; 663 template <typename Type> 664 class RangeSetCastToConversionTest 665 : public RangeSetTest<typename Type::FromType> {}; 666 template <typename Type> 667 class RangeSetCastToPromotionConversionTest 668 : public RangeSetTest<typename Type::FromType> {}; 669 template <typename Type> 670 class RangeSetCastToTruncationConversionTest 671 : public RangeSetTest<typename Type::FromType> {}; 672 673 using NoopCastTypes = 674 ::testing::Types<CastType<int8_t, int8_t>, CastType<uint8_t, uint8_t>, 675 CastType<int16_t, int16_t>, CastType<uint16_t, uint16_t>, 676 CastType<int32_t, int32_t>, CastType<uint32_t, uint32_t>, 677 CastType<int64_t, int64_t>, CastType<uint64_t, uint64_t>>; 678 679 using PromotionCastTypes = 680 ::testing::Types<CastType<int8_t, int16_t>, CastType<int8_t, int32_t>, 681 CastType<int8_t, int64_t>, CastType<uint8_t, uint16_t>, 682 CastType<uint8_t, uint32_t>, CastType<uint8_t, uint64_t>, 683 CastType<int16_t, int32_t>, CastType<int16_t, int64_t>, 684 CastType<uint16_t, uint32_t>, CastType<uint16_t, uint64_t>, 685 CastType<int32_t, int64_t>, CastType<uint32_t, uint64_t>>; 686 687 using TruncationCastTypes = 688 ::testing::Types<CastType<int16_t, int8_t>, CastType<uint16_t, uint8_t>, 689 CastType<int32_t, int16_t>, CastType<int32_t, int8_t>, 690 CastType<uint32_t, uint16_t>, CastType<uint32_t, uint8_t>, 691 CastType<int64_t, int32_t>, CastType<int64_t, int16_t>, 692 CastType<int64_t, int8_t>, CastType<uint64_t, uint32_t>, 693 CastType<uint64_t, uint16_t>, CastType<uint64_t, uint8_t>>; 694 695 using ConversionCastTypes = 696 ::testing::Types<CastType<int8_t, uint8_t>, CastType<uint8_t, int8_t>, 697 CastType<int16_t, uint16_t>, CastType<uint16_t, int16_t>, 698 CastType<int32_t, uint32_t>, CastType<uint32_t, int32_t>, 699 CastType<int64_t, uint64_t>, CastType<uint64_t, int64_t>>; 700 701 using PromotionConversionCastTypes = 702 ::testing::Types<CastType<int8_t, uint16_t>, CastType<int8_t, uint32_t>, 703 CastType<int8_t, uint64_t>, CastType<uint8_t, int16_t>, 704 CastType<uint8_t, int32_t>, CastType<uint8_t, int64_t>, 705 CastType<int16_t, uint32_t>, CastType<int16_t, uint64_t>, 706 CastType<uint16_t, int32_t>, CastType<uint16_t, int64_t>, 707 CastType<int32_t, uint64_t>, CastType<uint32_t, int64_t>>; 708 709 using TruncationConversionCastTypes = 710 ::testing::Types<CastType<int16_t, uint8_t>, CastType<uint16_t, int8_t>, 711 CastType<int32_t, uint16_t>, CastType<int32_t, uint8_t>, 712 CastType<uint32_t, int16_t>, CastType<uint32_t, int8_t>, 713 CastType<int64_t, uint32_t>, CastType<int64_t, uint16_t>, 714 CastType<int64_t, uint8_t>, CastType<uint64_t, int32_t>, 715 CastType<uint64_t, int16_t>, CastType<uint64_t, int8_t>>; 716 717 TYPED_TEST_SUITE(RangeSetCastToNoopTest, NoopCastTypes); 718 TYPED_TEST_SUITE(RangeSetCastToPromotionTest, PromotionCastTypes); 719 TYPED_TEST_SUITE(RangeSetCastToTruncationTest, TruncationCastTypes); 720 TYPED_TEST_SUITE(RangeSetCastToConversionTest, ConversionCastTypes); 721 TYPED_TEST_SUITE(RangeSetCastToPromotionConversionTest, 722 PromotionConversionCastTypes); 723 TYPED_TEST_SUITE(RangeSetCastToTruncationConversionTest, 724 TruncationConversionCastTypes); 725 726 TYPED_TEST(RangeSetCastToNoopTest, RangeSetCastToNoopTest) { 727 // Just to reduce the verbosity. 728 using F = typename TypeParam::FromType; // From 729 using T = typename TypeParam::ToType; // To 730 731 using TV = TestValues<F>; 732 constexpr auto MIN = TV::MIN; 733 constexpr auto MAX = TV::MAX; 734 constexpr auto MID = TV::MID; 735 constexpr auto B = TV::B; 736 constexpr auto C = TV::C; 737 // One point 738 this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}}); 739 this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}}); 740 this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}}); 741 this->template checkCastTo<F, T>({{B, B}}, {{B, B}}); 742 this->template checkCastTo<F, T>({{C, C}}, {{C, C}}); 743 // Two points 744 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, 745 {{MIN, MIN}, {MAX, MAX}}); 746 this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}}); 747 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}}, 748 {{MID, MID}, {MAX, MAX}}); 749 this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}}); 750 this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}}); 751 this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}}); 752 this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}}); 753 // One range 754 this->template checkCastTo<F, T>({{MIN, MAX}}, {{MIN, MAX}}); 755 this->template checkCastTo<F, T>({{MIN, MID}}, {{MIN, MID}}); 756 this->template checkCastTo<F, T>({{MID, MAX}}, {{MID, MAX}}); 757 this->template checkCastTo<F, T>({{B, MAX}}, {{B, MAX}}); 758 this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}}); 759 this->template checkCastTo<F, T>({{MIN, C}}, {{MIN, C}}); 760 this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}}); 761 this->template checkCastTo<F, T>({{B, C}}, {{B, C}}); 762 // Two ranges 763 this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{MIN, B}, {C, MAX}}); 764 this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, {{B, MID}, {C, MAX}}); 765 this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{MIN, B}, {MID, C}}); 766 } 767 768 TYPED_TEST(RangeSetCastToPromotionTest, Test) { 769 // Just to reduce the verbosity. 770 using F = typename TypeParam::FromType; // From 771 using T = typename TypeParam::ToType; // To 772 773 using TV = TestValues<F>; 774 constexpr auto MIN = TV::MIN; 775 constexpr auto MAX = TV::MAX; 776 constexpr auto MID = TV::MID; 777 constexpr auto B = TV::B; 778 constexpr auto C = TV::C; 779 // One point 780 this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}}); 781 this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}}); 782 this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}}); 783 this->template checkCastTo<F, T>({{B, B}}, {{B, B}}); 784 this->template checkCastTo<F, T>({{C, C}}, {{C, C}}); 785 // Two points 786 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, 787 {{MIN, MIN}, {MAX, MAX}}); 788 this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}}); 789 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}}, 790 {{MID, MID}, {MAX, MAX}}); 791 this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}}); 792 this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}}); 793 this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}}); 794 this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}}); 795 // One range 796 this->template checkCastTo<F, T>({{MIN, MAX}}, {{MIN, MAX}}); 797 this->template checkCastTo<F, T>({{MIN, MID}}, {{MIN, MID}}); 798 this->template checkCastTo<F, T>({{MID, MAX}}, {{MID, MAX}}); 799 this->template checkCastTo<F, T>({{B, MAX}}, {{B, MAX}}); 800 this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}}); 801 this->template checkCastTo<F, T>({{MIN, C}}, {{MIN, C}}); 802 this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}}); 803 this->template checkCastTo<F, T>({{B, C}}, {{B, C}}); 804 // Two ranges 805 this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{MIN, B}, {C, MAX}}); 806 this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, {{B, MID}, {C, MAX}}); 807 this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{MIN, B}, {MID, C}}); 808 } 809 810 TYPED_TEST(RangeSetCastToTruncationTest, Test) { 811 // Just to reduce the verbosity. 812 using F = typename TypeParam::FromType; // From 813 using T = typename TypeParam::ToType; // To 814 815 using TV = TestValues<F>; 816 constexpr auto MIN = TV::MIN; 817 constexpr auto MAX = TV::MAX; 818 constexpr auto MID = TV::MID; 819 constexpr auto B = TV::B; 820 constexpr auto C = TV::C; 821 // One point 822 // 823 // NOTE: We can't use ToMIN, ToMAX, ... everywhere. That would be incorrect: 824 // int16(-32768, 32767) -> int8(-128, 127), 825 // aka (MIN, MAX) -> (ToMIN, ToMAX) // OK. 826 // int16(-32768, -32768) -> int8(-128, -128), 827 // aka (MIN, MIN) -> (ToMIN, ToMIN) // NOK. 828 // int16(-32768,-32768) -> int8(0, 0), 829 // aka (MIN, MIN) -> ((int8)MIN, (int8)MIN) // OK. 830 this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}}); 831 this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}}); 832 this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}}); 833 this->template checkCastTo<F, T>({{B, B}}, {{B, B}}); 834 this->template checkCastTo<F, T>({{C, C}}, {{C, C}}); 835 // Two points 836 // Use `if constexpr` here. 837 if (is_signed_v<F>) { 838 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, {{MAX, MIN}}); 839 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}}, {{MAX, MID}}); 840 } else { 841 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, 842 {{MIN, MIN}, {MAX, MAX}}); 843 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}}, 844 {{MID, MID}, {MAX, MAX}}); 845 } 846 this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}}); 847 this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}}); 848 this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}}); 849 this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}}); 850 this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}}); 851 // One range 852 constexpr auto ToMIN = TestValues<T>::MIN; 853 constexpr auto ToMAX = TestValues<T>::MAX; 854 this->template checkCastTo<F, T>({{MIN, MAX}}, {{ToMIN, ToMAX}}); 855 this->template checkCastTo<F, T>({{MIN, MID}}, {{ToMIN, ToMAX}}); 856 this->template checkCastTo<F, T>({{MID, MAX}}, {{ToMIN, ToMAX}}); 857 this->template checkCastTo<F, T>({{B, MAX}}, {{ToMIN, ToMAX}}); 858 this->template checkCastTo<F, T>({{C, MAX}}, {{ToMIN, ToMAX}}); 859 this->template checkCastTo<F, T>({{MIN, C}}, {{ToMIN, ToMAX}}); 860 this->template checkCastTo<F, T>({{MIN, B}}, {{ToMIN, ToMAX}}); 861 this->template checkCastTo<F, T>({{B, C}}, {{ToMIN, ToMAX}}); 862 // Two ranges 863 this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{ToMIN, ToMAX}}); 864 this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, {{ToMIN, ToMAX}}); 865 this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{ToMIN, ToMAX}}); 866 constexpr auto XAAA = TV::XAAA; 867 constexpr auto X555 = TV::X555; 868 constexpr auto ZA = TV::template XAAATruncZeroOf<T>; 869 constexpr auto Z5 = TV::template X555TruncZeroOf<T>; 870 this->template checkCastTo<F, T>({{XAAA, ZA}, {X555, Z5}}, 871 {{ToMIN, 0}, {X555, ToMAX}}); 872 // Use `if constexpr` here. 873 if (is_signed_v<F>) { 874 // One range 875 this->template checkCastTo<F, T>({{XAAA, ZA}}, {{XAAA, 0}}); 876 // Two ranges 877 this->template checkCastTo<F, T>({{XAAA, ZA}, {1, 42}}, {{XAAA, 42}}); 878 } else { 879 // One range 880 this->template checkCastTo<F, T>({{XAAA, ZA}}, {{0, 0}, {XAAA, ToMAX}}); 881 // Two ranges 882 this->template checkCastTo<F, T>({{1, 42}, {XAAA, ZA}}, 883 {{0, 42}, {XAAA, ToMAX}}); 884 } 885 constexpr auto FromA = TV::FromA; 886 constexpr auto ToA = TV::ToA; 887 constexpr auto FromB = TV::FromB; 888 constexpr auto ToB = TV::ToB; 889 // int16 -> int8 890 // (0x00'01, 0x00'05)U(0xFF'01, 0xFF'05) casts to 891 // (0x01, 0x05)U(0x01, 0x05) unites to 892 // (0x01, 0x05) 893 this->template checkCastTo<F, T>({{FromA, ToA}, {FromB, ToB}}, 894 {{FromA, ToA}}); 895 } 896 897 TYPED_TEST(RangeSetCastToConversionTest, Test) { 898 // Just to reduce the verbosity. 899 using F = typename TypeParam::FromType; // From 900 using T = typename TypeParam::ToType; // To 901 902 using TV = TestValues<F>; 903 constexpr auto MIN = TV::MIN; 904 constexpr auto MAX = TV::MAX; 905 constexpr auto MID = TV::MID; 906 constexpr auto B = TV::B; 907 constexpr auto C = TV::C; 908 // One point 909 this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}}); 910 this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}}); 911 this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}}); 912 this->template checkCastTo<F, T>({{B, B}}, {{B, B}}); 913 this->template checkCastTo<F, T>({{C, C}}, {{C, C}}); 914 // Two points 915 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, {{MAX, MIN}}); 916 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}}, 917 {{MID, MID}, {MAX, MAX}}); 918 this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}}); 919 this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}}); 920 this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}}); 921 this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}}); 922 this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}}); 923 // One range 924 constexpr auto ToMIN = TestValues<T>::MIN; 925 constexpr auto ToMAX = TestValues<T>::MAX; 926 this->template checkCastTo<F, T>({{MIN, MAX}}, {{ToMIN, ToMAX}}); 927 this->template checkCastTo<F, T>({{MIN, MID}}, 928 {{ToMIN, ToMIN}, {MIN, ToMAX}}); 929 this->template checkCastTo<F, T>({{MID, MAX}}, {{MID, MAX}}); 930 this->template checkCastTo<F, T>({{B, MAX}}, {{ToMIN, MAX}, {B, ToMAX}}); 931 this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}}); 932 this->template checkCastTo<F, T>({{MIN, C}}, {{ToMIN, C}, {MIN, ToMAX}}); 933 this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}}); 934 this->template checkCastTo<F, T>({{B, C}}, {{ToMIN, C}, {B, ToMAX}}); 935 // Two ranges 936 this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{C, B}}); 937 this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, 938 {{MID, MID}, {C, MAX}, {B, ToMAX}}); 939 this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{MID, C}, {MIN, B}}); 940 } 941 942 TYPED_TEST(RangeSetCastToPromotionConversionTest, Test) { 943 // Just to reduce the verbosity. 944 using F = typename TypeParam::FromType; // From 945 using T = typename TypeParam::ToType; // To 946 947 using TV = TestValues<F>; 948 constexpr auto MIN = TV::MIN; 949 constexpr auto MAX = TV::MAX; 950 constexpr auto MID = TV::MID; 951 constexpr auto B = TV::B; 952 constexpr auto C = TV::C; 953 // One point 954 this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}}); 955 this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}}); 956 this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}}); 957 this->template checkCastTo<F, T>({{B, B}}, {{B, B}}); 958 this->template checkCastTo<F, T>({{C, C}}, {{C, C}}); 959 // Two points 960 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, 961 {{MAX, MAX}, {MIN, MIN}}); 962 this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}}); 963 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}}, 964 {{MID, MID}, {MAX, MAX}}); 965 this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}}); 966 this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}}); 967 this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}}); 968 this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}}); 969 970 // Use `if constexpr` here. 971 if (is_signed_v<F>) { 972 // One range 973 this->template checkCastTo<F, T>({{MIN, MAX}}, {{0, MAX}, {MIN, -1}}); 974 this->template checkCastTo<F, T>({{MIN, MID}}, {{0, 0}, {MIN, -1}}); 975 this->template checkCastTo<F, T>({{MID, MAX}}, {{0, MAX}}); 976 this->template checkCastTo<F, T>({{B, MAX}}, {{0, MAX}, {B, -1}}); 977 this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}}); 978 this->template checkCastTo<F, T>({{MIN, C}}, {{0, C}, {MIN, -1}}); 979 this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}}); 980 this->template checkCastTo<F, T>({{B, C}}, {{0, C}, {B, -1}}); 981 // Two ranges 982 this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, 983 {{C, MAX}, {MIN, B}}); 984 this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, 985 {{0, 0}, {C, MAX}, {B, -1}}); 986 this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{0, C}, {MIN, B}}); 987 } else { 988 // One range 989 this->template checkCastTo<F, T>({{MIN, MAX}}, {{MIN, MAX}}); 990 this->template checkCastTo<F, T>({{MIN, MID}}, {{MIN, MID}}); 991 this->template checkCastTo<F, T>({{MID, MAX}}, {{MID, MAX}}); 992 this->template checkCastTo<F, T>({{B, MAX}}, {{B, MAX}}); 993 this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}}); 994 this->template checkCastTo<F, T>({{MIN, C}}, {{MIN, C}}); 995 this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}}); 996 this->template checkCastTo<F, T>({{B, C}}, {{B, C}}); 997 // Two ranges 998 this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, 999 {{MIN, B}, {C, MAX}}); 1000 this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, 1001 {{B, MID}, {C, MAX}}); 1002 this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, 1003 {{MIN, B}, {MID, C}}); 1004 } 1005 } 1006 1007 TYPED_TEST(RangeSetCastToTruncationConversionTest, Test) { 1008 // Just to reduce the verbosity. 1009 using F = typename TypeParam::FromType; // From 1010 using T = typename TypeParam::ToType; // To 1011 1012 using TV = TestValues<F>; 1013 constexpr auto MIN = TV::MIN; 1014 constexpr auto MAX = TV::MAX; 1015 constexpr auto MID = TV::MID; 1016 constexpr auto B = TV::B; 1017 constexpr auto C = TV::C; 1018 // One point 1019 this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}}); 1020 this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}}); 1021 this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}}); 1022 this->template checkCastTo<F, T>({{B, B}}, {{B, B}}); 1023 this->template checkCastTo<F, T>({{C, C}}, {{C, C}}); 1024 // Two points 1025 // Use `if constexpr` here. 1026 if (is_signed_v<F>) { 1027 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, 1028 {{MIN, MIN}, {MAX, MAX}}); 1029 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}}, 1030 {{MID, MID}, {MAX, MAX}}); 1031 } else { 1032 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, {{MAX, MIN}}); 1033 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}}, {{MAX, MIN}}); 1034 } 1035 this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}}); 1036 this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}}); 1037 this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}}); 1038 this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}}); 1039 this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}}); 1040 // One range 1041 constexpr auto ToMIN = TestValues<T>::MIN; 1042 constexpr auto ToMAX = TestValues<T>::MAX; 1043 this->template checkCastTo<F, T>({{MIN, MAX}}, {{ToMIN, ToMAX}}); 1044 this->template checkCastTo<F, T>({{MIN, MID}}, {{ToMIN, ToMAX}}); 1045 this->template checkCastTo<F, T>({{MID, MAX}}, {{ToMIN, ToMAX}}); 1046 this->template checkCastTo<F, T>({{B, MAX}}, {{ToMIN, ToMAX}}); 1047 this->template checkCastTo<F, T>({{C, MAX}}, {{ToMIN, ToMAX}}); 1048 this->template checkCastTo<F, T>({{MIN, C}}, {{ToMIN, ToMAX}}); 1049 this->template checkCastTo<F, T>({{MIN, B}}, {{ToMIN, ToMAX}}); 1050 this->template checkCastTo<F, T>({{B, C}}, {{ToMIN, ToMAX}}); 1051 // Two ranges 1052 this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{ToMIN, ToMAX}}); 1053 this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, {{ToMIN, ToMAX}}); 1054 this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{ToMIN, ToMAX}}); 1055 constexpr auto XAAA = TV::XAAA; 1056 constexpr auto X555 = TV::X555; 1057 constexpr auto ZA = TV::template XAAATruncZeroOf<T>; 1058 constexpr auto Z5 = TV::template X555TruncZeroOf<T>; 1059 this->template checkCastTo<F, T>({{XAAA, ZA}, {X555, Z5}}, 1060 {{ToMIN, 0}, {X555, ToMAX}}); 1061 // Use `if constexpr` here. 1062 if (is_signed_v<F>) { 1063 // One range 1064 this->template checkCastTo<F, T>({{XAAA, ZA}}, {{0, 0}, {XAAA, ToMAX}}); 1065 // Two ranges 1066 this->template checkCastTo<F, T>({{XAAA, ZA}, {1, 42}}, 1067 {{0, 42}, {XAAA, ToMAX}}); 1068 } else { 1069 // One range 1070 this->template checkCastTo<F, T>({{XAAA, ZA}}, {{XAAA, 0}}); 1071 // Two ranges 1072 this->template checkCastTo<F, T>({{1, 42}, {XAAA, ZA}}, {{XAAA, 42}}); 1073 } 1074 constexpr auto FromA = TV::FromA; 1075 constexpr auto ToA = TV::ToA; 1076 constexpr auto FromB = TV::FromB; 1077 constexpr auto ToB = TV::ToB; 1078 this->template checkCastTo<F, T>({{FromA, ToA}, {FromB, ToB}}, 1079 {{FromA, ToA}}); 1080 } 1081 1082 } // namespace 1083