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