1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ 6 #define PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ 7 8 #include <stdint.h> 9 10 #include <limits> 11 #include <type_traits> 12 13 namespace pdfium { 14 namespace base { 15 namespace internal { 16 17 // The std library doesn't provide a binary max_exponent for integers, however 18 // we can compute an analog using std::numeric_limits<>::digits. 19 template <typename NumericType> 20 struct MaxExponent { 21 static const int value = std::is_floating_point<NumericType>::value 22 ? std::numeric_limits<NumericType>::max_exponent 23 : std::numeric_limits<NumericType>::digits + 1; 24 }; 25 26 // The number of bits (including the sign) in an integer. Eliminates sizeof 27 // hacks. 28 template <typename NumericType> 29 struct IntegerBitsPlusSign { 30 static const int value = std::numeric_limits<NumericType>::digits + 31 std::is_signed<NumericType>::value; 32 }; 33 34 // Helper templates for integer manipulations. 35 36 template <typename Integer> 37 struct PositionOfSignBit { 38 static const size_t value = IntegerBitsPlusSign<Integer>::value - 1; 39 }; 40 41 // Determines if a numeric value is negative without throwing compiler 42 // warnings on: unsigned(value) < 0. 43 template <typename T, 44 typename std::enable_if<std::is_signed<T>::value>::type* = nullptr> 45 constexpr bool IsValueNegative(T value) { 46 static_assert(std::is_arithmetic<T>::value, "Argument must be numeric."); 47 return value < 0; 48 } 49 50 template <typename T, 51 typename std::enable_if<!std::is_signed<T>::value>::type* = nullptr> 52 constexpr bool IsValueNegative(T) { 53 static_assert(std::is_arithmetic<T>::value, "Argument must be numeric."); 54 return false; 55 } 56 57 // This performs a fast negation, returning a signed value. It works on unsigned 58 // arguments, but probably doesn't do what you want for any unsigned value 59 // larger than max / 2 + 1 (i.e. signed min cast to unsigned). 60 template <typename T> 61 constexpr typename std::make_signed<T>::type ConditionalNegate( 62 T x, 63 bool is_negative) { 64 static_assert(std::is_integral<T>::value, "Type must be integral"); 65 using SignedT = typename std::make_signed<T>::type; 66 using UnsignedT = typename std::make_unsigned<T>::type; 67 return static_cast<SignedT>( 68 (static_cast<UnsignedT>(x) ^ -SignedT(is_negative)) + is_negative); 69 } 70 71 // This performs a safe, absolute value via unsigned overflow. 72 template <typename T> 73 constexpr typename std::make_unsigned<T>::type SafeUnsignedAbs(T value) { 74 static_assert(std::is_integral<T>::value, "Type must be integral"); 75 using UnsignedT = typename std::make_unsigned<T>::type; 76 return IsValueNegative(value) ? 0 - static_cast<UnsignedT>(value) 77 : static_cast<UnsignedT>(value); 78 } 79 80 enum IntegerRepresentation { 81 INTEGER_REPRESENTATION_UNSIGNED, 82 INTEGER_REPRESENTATION_SIGNED 83 }; 84 85 // A range for a given nunmeric Src type is contained for a given numeric Dst 86 // type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and 87 // numeric_limits<Src>::lowest() >= numeric_limits<Dst>::lowest() are true. 88 // We implement this as template specializations rather than simple static 89 // comparisons to ensure type correctness in our comparisons. 90 enum NumericRangeRepresentation { 91 NUMERIC_RANGE_NOT_CONTAINED, 92 NUMERIC_RANGE_CONTAINED 93 }; 94 95 // Helper templates to statically determine if our destination type can contain 96 // maximum and minimum values represented by the source type. 97 98 template <typename Dst, 99 typename Src, 100 IntegerRepresentation DstSign = std::is_signed<Dst>::value 101 ? INTEGER_REPRESENTATION_SIGNED 102 : INTEGER_REPRESENTATION_UNSIGNED, 103 IntegerRepresentation SrcSign = std::is_signed<Src>::value 104 ? INTEGER_REPRESENTATION_SIGNED 105 : INTEGER_REPRESENTATION_UNSIGNED> 106 struct StaticDstRangeRelationToSrcRange; 107 108 // Same sign: Dst is guaranteed to contain Src only if its range is equal or 109 // larger. 110 template <typename Dst, typename Src, IntegerRepresentation Sign> 111 struct StaticDstRangeRelationToSrcRange<Dst, Src, Sign, Sign> { 112 static const NumericRangeRepresentation value = 113 MaxExponent<Dst>::value >= MaxExponent<Src>::value 114 ? NUMERIC_RANGE_CONTAINED 115 : NUMERIC_RANGE_NOT_CONTAINED; 116 }; 117 118 // Unsigned to signed: Dst is guaranteed to contain source only if its range is 119 // larger. 120 template <typename Dst, typename Src> 121 struct StaticDstRangeRelationToSrcRange<Dst, 122 Src, 123 INTEGER_REPRESENTATION_SIGNED, 124 INTEGER_REPRESENTATION_UNSIGNED> { 125 static const NumericRangeRepresentation value = 126 MaxExponent<Dst>::value > MaxExponent<Src>::value 127 ? NUMERIC_RANGE_CONTAINED 128 : NUMERIC_RANGE_NOT_CONTAINED; 129 }; 130 131 // Signed to unsigned: Dst cannot be statically determined to contain Src. 132 template <typename Dst, typename Src> 133 struct StaticDstRangeRelationToSrcRange<Dst, 134 Src, 135 INTEGER_REPRESENTATION_UNSIGNED, 136 INTEGER_REPRESENTATION_SIGNED> { 137 static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED; 138 }; 139 140 // This class wraps the range constraints as separate booleans so the compiler 141 // can identify constants and eliminate unused code paths. 142 class RangeCheck { 143 public: 144 constexpr RangeCheck(bool is_in_lower_bound, bool is_in_upper_bound) 145 : is_underflow_(!is_in_lower_bound), is_overflow_(!is_in_upper_bound) {} 146 constexpr RangeCheck() : is_underflow_(0), is_overflow_(0) {} 147 constexpr bool IsValid() const { return !is_overflow_ && !is_underflow_; } 148 constexpr bool IsInvalid() const { return is_overflow_ && is_underflow_; } 149 constexpr bool IsOverflow() const { return is_overflow_ && !is_underflow_; } 150 constexpr bool IsUnderflow() const { return !is_overflow_ && is_underflow_; } 151 constexpr bool IsOverflowFlagSet() const { return is_overflow_; } 152 constexpr bool IsUnderflowFlagSet() const { return is_underflow_; } 153 constexpr bool operator==(const RangeCheck rhs) const { 154 return is_underflow_ == rhs.is_underflow_ && 155 is_overflow_ == rhs.is_overflow_; 156 } 157 constexpr bool operator!=(const RangeCheck rhs) const { 158 return !(*this == rhs); 159 } 160 161 private: 162 // Do not change the order of these member variables. The integral conversion 163 // optimization depends on this exact order. 164 const bool is_underflow_; 165 const bool is_overflow_; 166 }; 167 168 // The following helper template addresses a corner case in range checks for 169 // conversion from a floating-point type to an integral type of smaller range 170 // but larger precision (e.g. float -> unsigned). The problem is as follows: 171 // 1. Integral maximum is always one less than a power of two, so it must be 172 // truncated to fit the mantissa of the floating point. The direction of 173 // rounding is implementation defined, but by default it's always IEEE 174 // floats, which round to nearest and thus result in a value of larger 175 // magnitude than the integral value. 176 // Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX 177 // // is 4294967295u. 178 // 2. If the floating point value is equal to the promoted integral maximum 179 // value, a range check will erroneously pass. 180 // Example: (4294967296f <= 4294967295u) // This is true due to a precision 181 // // loss in rounding up to float. 182 // 3. When the floating point value is then converted to an integral, the 183 // resulting value is out of range for the target integral type and 184 // thus is implementation defined. 185 // Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0. 186 // To fix this bug we manually truncate the maximum value when the destination 187 // type is an integral of larger precision than the source floating-point type, 188 // such that the resulting maximum is represented exactly as a floating point. 189 template <typename Dst, typename Src, template <typename> class Bounds> 190 struct NarrowingRange { 191 using SrcLimits = std::numeric_limits<Src>; 192 using DstLimits = typename std::numeric_limits<Dst>; 193 194 // Computes the mask required to make an accurate comparison between types. 195 static const int kShift = 196 (MaxExponent<Src>::value > MaxExponent<Dst>::value && 197 SrcLimits::digits < DstLimits::digits) 198 ? (DstLimits::digits - SrcLimits::digits) 199 : 0; 200 template < 201 typename T, 202 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> 203 204 // Masks out the integer bits that are beyond the precision of the 205 // intermediate type used for comparison. 206 static constexpr T Adjust(T value) { 207 static_assert(std::is_same<T, Dst>::value, ""); 208 static_assert(kShift < DstLimits::digits, ""); 209 return static_cast<T>( 210 ConditionalNegate(SafeUnsignedAbs(value) & ~((T(1) << kShift) - T(1)), 211 IsValueNegative(value))); 212 } 213 214 template <typename T, 215 typename std::enable_if<std::is_floating_point<T>::value>::type* = 216 nullptr> 217 static constexpr T Adjust(T value) { 218 static_assert(std::is_same<T, Dst>::value, ""); 219 static_assert(kShift == 0, ""); 220 return value; 221 } 222 223 static constexpr Dst max() { return Adjust(Bounds<Dst>::max()); } 224 static constexpr Dst lowest() { return Adjust(Bounds<Dst>::lowest()); } 225 }; 226 227 template <typename Dst, 228 typename Src, 229 template <typename> class Bounds, 230 IntegerRepresentation DstSign = std::is_signed<Dst>::value 231 ? INTEGER_REPRESENTATION_SIGNED 232 : INTEGER_REPRESENTATION_UNSIGNED, 233 IntegerRepresentation SrcSign = std::is_signed<Src>::value 234 ? INTEGER_REPRESENTATION_SIGNED 235 : INTEGER_REPRESENTATION_UNSIGNED, 236 NumericRangeRepresentation DstRange = 237 StaticDstRangeRelationToSrcRange<Dst, Src>::value> 238 struct DstRangeRelationToSrcRangeImpl; 239 240 // The following templates are for ranges that must be verified at runtime. We 241 // split it into checks based on signedness to avoid confusing casts and 242 // compiler warnings on signed an unsigned comparisons. 243 244 // Same sign narrowing: The range is contained for normal limits. 245 template <typename Dst, 246 typename Src, 247 template <typename> class Bounds, 248 IntegerRepresentation DstSign, 249 IntegerRepresentation SrcSign> 250 struct DstRangeRelationToSrcRangeImpl<Dst, 251 Src, 252 Bounds, 253 DstSign, 254 SrcSign, 255 NUMERIC_RANGE_CONTAINED> { 256 static constexpr RangeCheck Check(Src value) { 257 using SrcLimits = std::numeric_limits<Src>; 258 using DstLimits = NarrowingRange<Dst, Src, Bounds>; 259 return RangeCheck( 260 static_cast<Dst>(SrcLimits::lowest()) >= DstLimits::lowest() || 261 static_cast<Dst>(value) >= DstLimits::lowest(), 262 static_cast<Dst>(SrcLimits::max()) <= DstLimits::max() || 263 static_cast<Dst>(value) <= DstLimits::max()); 264 } 265 }; 266 267 // Signed to signed narrowing: Both the upper and lower boundaries may be 268 // exceeded for standard limits. 269 template <typename Dst, typename Src, template <typename> class Bounds> 270 struct DstRangeRelationToSrcRangeImpl<Dst, 271 Src, 272 Bounds, 273 INTEGER_REPRESENTATION_SIGNED, 274 INTEGER_REPRESENTATION_SIGNED, 275 NUMERIC_RANGE_NOT_CONTAINED> { 276 static constexpr RangeCheck Check(Src value) { 277 using DstLimits = NarrowingRange<Dst, Src, Bounds>; 278 return RangeCheck(value >= DstLimits::lowest(), value <= DstLimits::max()); 279 } 280 }; 281 282 // Unsigned to unsigned narrowing: Only the upper bound can be exceeded for 283 // standard limits. 284 template <typename Dst, typename Src, template <typename> class Bounds> 285 struct DstRangeRelationToSrcRangeImpl<Dst, 286 Src, 287 Bounds, 288 INTEGER_REPRESENTATION_UNSIGNED, 289 INTEGER_REPRESENTATION_UNSIGNED, 290 NUMERIC_RANGE_NOT_CONTAINED> { 291 static constexpr RangeCheck Check(Src value) { 292 using DstLimits = NarrowingRange<Dst, Src, Bounds>; 293 return RangeCheck( 294 DstLimits::lowest() == Dst(0) || value >= DstLimits::lowest(), 295 value <= DstLimits::max()); 296 } 297 }; 298 299 // Unsigned to signed: Only the upper bound can be exceeded for standard limits. 300 template <typename Dst, typename Src, template <typename> class Bounds> 301 struct DstRangeRelationToSrcRangeImpl<Dst, 302 Src, 303 Bounds, 304 INTEGER_REPRESENTATION_SIGNED, 305 INTEGER_REPRESENTATION_UNSIGNED, 306 NUMERIC_RANGE_NOT_CONTAINED> { 307 static constexpr RangeCheck Check(Src value) { 308 using DstLimits = NarrowingRange<Dst, Src, Bounds>; 309 using Promotion = decltype(Src() + Dst()); 310 return RangeCheck(DstLimits::lowest() <= Dst(0) || 311 static_cast<Promotion>(value) >= 312 static_cast<Promotion>(DstLimits::lowest()), 313 static_cast<Promotion>(value) <= 314 static_cast<Promotion>(DstLimits::max())); 315 } 316 }; 317 318 // Signed to unsigned: The upper boundary may be exceeded for a narrower Dst, 319 // and any negative value exceeds the lower boundary for standard limits. 320 template <typename Dst, typename Src, template <typename> class Bounds> 321 struct DstRangeRelationToSrcRangeImpl<Dst, 322 Src, 323 Bounds, 324 INTEGER_REPRESENTATION_UNSIGNED, 325 INTEGER_REPRESENTATION_SIGNED, 326 NUMERIC_RANGE_NOT_CONTAINED> { 327 static constexpr RangeCheck Check(Src value) { 328 using SrcLimits = std::numeric_limits<Src>; 329 using DstLimits = NarrowingRange<Dst, Src, Bounds>; 330 using Promotion = decltype(Src() + Dst()); 331 return RangeCheck( 332 value >= Src(0) && (DstLimits::lowest() == 0 || 333 static_cast<Dst>(value) >= DstLimits::lowest()), 334 static_cast<Promotion>(SrcLimits::max()) <= 335 static_cast<Promotion>(DstLimits::max()) || 336 static_cast<Promotion>(value) <= 337 static_cast<Promotion>(DstLimits::max())); 338 } 339 }; 340 341 template <typename Dst, 342 template <typename> class Bounds = std::numeric_limits, 343 typename Src> 344 constexpr RangeCheck DstRangeRelationToSrcRange(Src value) { 345 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); 346 static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric."); 347 static_assert(Bounds<Dst>::lowest() < Bounds<Dst>::max(), ""); 348 return DstRangeRelationToSrcRangeImpl<Dst, Src, Bounds>::Check(value); 349 } 350 351 // Integer promotion templates used by the portable checked integer arithmetic. 352 template <size_t Size, bool IsSigned> 353 struct IntegerForDigitsAndSign; 354 355 #define INTEGER_FOR_DIGITS_AND_SIGN(I) \ 356 template <> \ 357 struct IntegerForDigitsAndSign<IntegerBitsPlusSign<I>::value, \ 358 std::is_signed<I>::value> { \ 359 using type = I; \ 360 } 361 362 INTEGER_FOR_DIGITS_AND_SIGN(int8_t); 363 INTEGER_FOR_DIGITS_AND_SIGN(uint8_t); 364 INTEGER_FOR_DIGITS_AND_SIGN(int16_t); 365 INTEGER_FOR_DIGITS_AND_SIGN(uint16_t); 366 INTEGER_FOR_DIGITS_AND_SIGN(int32_t); 367 INTEGER_FOR_DIGITS_AND_SIGN(uint32_t); 368 INTEGER_FOR_DIGITS_AND_SIGN(int64_t); 369 INTEGER_FOR_DIGITS_AND_SIGN(uint64_t); 370 #undef INTEGER_FOR_DIGITS_AND_SIGN 371 372 // WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to 373 // support 128-bit math, then the ArithmeticPromotion template below will need 374 // to be updated (or more likely replaced with a decltype expression). 375 static_assert(IntegerBitsPlusSign<intmax_t>::value == 64, 376 "Max integer size not supported for this toolchain."); 377 378 template <typename Integer, bool IsSigned = std::is_signed<Integer>::value> 379 struct TwiceWiderInteger { 380 using type = 381 typename IntegerForDigitsAndSign<IntegerBitsPlusSign<Integer>::value * 2, 382 IsSigned>::type; 383 }; 384 385 enum ArithmeticPromotionCategory { 386 LEFT_PROMOTION, // Use the type of the left-hand argument. 387 RIGHT_PROMOTION // Use the type of the right-hand argument. 388 }; 389 390 // Determines the type that can represent the largest positive value. 391 template <typename Lhs, 392 typename Rhs, 393 ArithmeticPromotionCategory Promotion = 394 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) 395 ? LEFT_PROMOTION 396 : RIGHT_PROMOTION> 397 struct MaxExponentPromotion; 398 399 template <typename Lhs, typename Rhs> 400 struct MaxExponentPromotion<Lhs, Rhs, LEFT_PROMOTION> { 401 using type = Lhs; 402 }; 403 404 template <typename Lhs, typename Rhs> 405 struct MaxExponentPromotion<Lhs, Rhs, RIGHT_PROMOTION> { 406 using type = Rhs; 407 }; 408 409 // Determines the type that can represent the lowest arithmetic value. 410 template <typename Lhs, 411 typename Rhs, 412 ArithmeticPromotionCategory Promotion = 413 std::is_signed<Lhs>::value 414 ? (std::is_signed<Rhs>::value 415 ? (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value 416 ? LEFT_PROMOTION 417 : RIGHT_PROMOTION) 418 : LEFT_PROMOTION) 419 : (std::is_signed<Rhs>::value 420 ? RIGHT_PROMOTION 421 : (MaxExponent<Lhs>::value < MaxExponent<Rhs>::value 422 ? LEFT_PROMOTION 423 : RIGHT_PROMOTION))> 424 struct LowestValuePromotion; 425 426 template <typename Lhs, typename Rhs> 427 struct LowestValuePromotion<Lhs, Rhs, LEFT_PROMOTION> { 428 using type = Lhs; 429 }; 430 431 template <typename Lhs, typename Rhs> 432 struct LowestValuePromotion<Lhs, Rhs, RIGHT_PROMOTION> { 433 using type = Rhs; 434 }; 435 436 // Determines the type that is best able to represent an arithmetic result. 437 template < 438 typename Lhs, 439 typename Rhs = Lhs, 440 bool is_intmax_type = 441 std::is_integral<typename MaxExponentPromotion<Lhs, Rhs>::type>::value&& 442 IntegerBitsPlusSign<typename MaxExponentPromotion<Lhs, Rhs>::type>:: 443 value == IntegerBitsPlusSign<intmax_t>::value, 444 bool is_max_exponent = 445 StaticDstRangeRelationToSrcRange< 446 typename MaxExponentPromotion<Lhs, Rhs>::type, 447 Lhs>::value == 448 NUMERIC_RANGE_CONTAINED&& StaticDstRangeRelationToSrcRange< 449 typename MaxExponentPromotion<Lhs, Rhs>::type, 450 Rhs>::value == NUMERIC_RANGE_CONTAINED> 451 struct BigEnoughPromotion; 452 453 // The side with the max exponent is big enough. 454 template <typename Lhs, typename Rhs, bool is_intmax_type> 455 struct BigEnoughPromotion<Lhs, Rhs, is_intmax_type, true> { 456 using type = typename MaxExponentPromotion<Lhs, Rhs>::type; 457 static const bool is_contained = true; 458 }; 459 460 // We can use a twice wider type to fit. 461 template <typename Lhs, typename Rhs> 462 struct BigEnoughPromotion<Lhs, Rhs, false, false> { 463 using type = 464 typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type, 465 std::is_signed<Lhs>::value || 466 std::is_signed<Rhs>::value>::type; 467 static const bool is_contained = true; 468 }; 469 470 // No type is large enough. 471 template <typename Lhs, typename Rhs> 472 struct BigEnoughPromotion<Lhs, Rhs, true, false> { 473 using type = typename MaxExponentPromotion<Lhs, Rhs>::type; 474 static const bool is_contained = false; 475 }; 476 477 // We can statically check if operations on the provided types can wrap, so we 478 // can skip the checked operations if they're not needed. So, for an integer we 479 // care if the destination type preserves the sign and is twice the width of 480 // the source. 481 template <typename T, typename Lhs, typename Rhs = Lhs> 482 struct IsIntegerArithmeticSafe { 483 static const bool value = 484 !std::is_floating_point<T>::value && 485 !std::is_floating_point<Lhs>::value && 486 !std::is_floating_point<Rhs>::value && 487 std::is_signed<T>::value >= std::is_signed<Lhs>::value && 488 IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Lhs>::value) && 489 std::is_signed<T>::value >= std::is_signed<Rhs>::value && 490 IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Rhs>::value); 491 }; 492 493 // Promotes to a type that can represent any possible result of a binary 494 // arithmetic operation with the source types. 495 template <typename Lhs, 496 typename Rhs, 497 bool is_promotion_possible = IsIntegerArithmeticSafe< 498 typename std::conditional<std::is_signed<Lhs>::value || 499 std::is_signed<Rhs>::value, 500 intmax_t, 501 uintmax_t>::type, 502 typename MaxExponentPromotion<Lhs, Rhs>::type>::value> 503 struct FastIntegerArithmeticPromotion; 504 505 template <typename Lhs, typename Rhs> 506 struct FastIntegerArithmeticPromotion<Lhs, Rhs, true> { 507 using type = 508 typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type, 509 std::is_signed<Lhs>::value || 510 std::is_signed<Rhs>::value>::type; 511 static_assert(IsIntegerArithmeticSafe<type, Lhs, Rhs>::value, ""); 512 static const bool is_contained = true; 513 }; 514 515 template <typename Lhs, typename Rhs> 516 struct FastIntegerArithmeticPromotion<Lhs, Rhs, false> { 517 using type = typename BigEnoughPromotion<Lhs, Rhs>::type; 518 static const bool is_contained = false; 519 }; 520 521 // This hacks around libstdc++ 4.6 missing stuff in type_traits. 522 #if defined(__GLIBCXX__) 523 #define PRIV_GLIBCXX_4_7_0 20120322 524 #define PRIV_GLIBCXX_4_5_4 20120702 525 #define PRIV_GLIBCXX_4_6_4 20121127 526 #if (__GLIBCXX__ < PRIV_GLIBCXX_4_7_0 || __GLIBCXX__ == PRIV_GLIBCXX_4_5_4 || \ 527 __GLIBCXX__ == PRIV_GLIBCXX_4_6_4) 528 #define PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX 529 #undef PRIV_GLIBCXX_4_7_0 530 #undef PRIV_GLIBCXX_4_5_4 531 #undef PRIV_GLIBCXX_4_6_4 532 #endif 533 #endif 534 535 // Extracts the underlying type from an enum. 536 template <typename T, bool is_enum = std::is_enum<T>::value> 537 struct ArithmeticOrUnderlyingEnum; 538 539 template <typename T> 540 struct ArithmeticOrUnderlyingEnum<T, true> { 541 #if defined(PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX) 542 using type = __underlying_type(T); 543 #else 544 using type = typename std::underlying_type<T>::type; 545 #endif 546 static const bool value = std::is_arithmetic<type>::value; 547 }; 548 549 #if defined(PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX) 550 #undef PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX 551 #endif 552 553 template <typename T> 554 struct ArithmeticOrUnderlyingEnum<T, false> { 555 using type = T; 556 static const bool value = std::is_arithmetic<type>::value; 557 }; 558 559 // The following are helper templates used in the CheckedNumeric class. 560 template <typename T> 561 class CheckedNumeric; 562 563 template <typename T> 564 class StrictNumeric; 565 566 // Used to treat CheckedNumeric and arithmetic underlying types the same. 567 template <typename T> 568 struct UnderlyingType { 569 using type = typename ArithmeticOrUnderlyingEnum<T>::type; 570 static const bool is_numeric = std::is_arithmetic<type>::value; 571 static const bool is_checked = false; 572 static const bool is_strict = false; 573 }; 574 575 template <typename T> 576 struct UnderlyingType<CheckedNumeric<T>> { 577 using type = T; 578 static const bool is_numeric = true; 579 static const bool is_checked = true; 580 static const bool is_strict = false; 581 }; 582 583 template <typename T> 584 struct UnderlyingType<StrictNumeric<T>> { 585 using type = T; 586 static const bool is_numeric = true; 587 static const bool is_checked = false; 588 static const bool is_strict = true; 589 }; 590 591 template <typename L, typename R> 592 struct IsCheckedOp { 593 static const bool value = 594 UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric && 595 (UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked); 596 }; 597 598 template <typename L, typename R> 599 struct IsStrictOp { 600 static const bool value = 601 UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric && 602 (UnderlyingType<L>::is_strict || UnderlyingType<R>::is_strict); 603 }; 604 605 template <typename L, typename R> 606 constexpr bool IsLessImpl(const L lhs, 607 const R rhs, 608 const RangeCheck l_range, 609 const RangeCheck r_range) { 610 return l_range.IsUnderflow() || r_range.IsOverflow() || 611 (l_range == r_range && 612 static_cast<decltype(lhs + rhs)>(lhs) < 613 static_cast<decltype(lhs + rhs)>(rhs)); 614 } 615 616 template <typename L, typename R> 617 struct IsLess { 618 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value, 619 "Types must be numeric."); 620 static constexpr bool Test(const L lhs, const R rhs) { 621 return IsLessImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs), 622 DstRangeRelationToSrcRange<L>(rhs)); 623 } 624 }; 625 626 template <typename L, typename R> 627 constexpr bool IsLessOrEqualImpl(const L lhs, 628 const R rhs, 629 const RangeCheck l_range, 630 const RangeCheck r_range) { 631 return l_range.IsUnderflow() || r_range.IsOverflow() || 632 (l_range == r_range && 633 static_cast<decltype(lhs + rhs)>(lhs) <= 634 static_cast<decltype(lhs + rhs)>(rhs)); 635 } 636 637 template <typename L, typename R> 638 struct IsLessOrEqual { 639 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value, 640 "Types must be numeric."); 641 static constexpr bool Test(const L lhs, const R rhs) { 642 return IsLessOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs), 643 DstRangeRelationToSrcRange<L>(rhs)); 644 } 645 }; 646 647 template <typename L, typename R> 648 constexpr bool IsGreaterImpl(const L lhs, 649 const R rhs, 650 const RangeCheck l_range, 651 const RangeCheck r_range) { 652 return l_range.IsOverflow() || r_range.IsUnderflow() || 653 (l_range == r_range && 654 static_cast<decltype(lhs + rhs)>(lhs) > 655 static_cast<decltype(lhs + rhs)>(rhs)); 656 } 657 658 template <typename L, typename R> 659 struct IsGreater { 660 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value, 661 "Types must be numeric."); 662 static constexpr bool Test(const L lhs, const R rhs) { 663 return IsGreaterImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs), 664 DstRangeRelationToSrcRange<L>(rhs)); 665 } 666 }; 667 668 template <typename L, typename R> 669 constexpr bool IsGreaterOrEqualImpl(const L lhs, 670 const R rhs, 671 const RangeCheck l_range, 672 const RangeCheck r_range) { 673 return l_range.IsOverflow() || r_range.IsUnderflow() || 674 (l_range == r_range && 675 static_cast<decltype(lhs + rhs)>(lhs) >= 676 static_cast<decltype(lhs + rhs)>(rhs)); 677 } 678 679 template <typename L, typename R> 680 struct IsGreaterOrEqual { 681 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value, 682 "Types must be numeric."); 683 static constexpr bool Test(const L lhs, const R rhs) { 684 return IsGreaterOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs), 685 DstRangeRelationToSrcRange<L>(rhs)); 686 } 687 }; 688 689 template <typename L, typename R> 690 struct IsEqual { 691 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value, 692 "Types must be numeric."); 693 static constexpr bool Test(const L lhs, const R rhs) { 694 return DstRangeRelationToSrcRange<R>(lhs) == 695 DstRangeRelationToSrcRange<L>(rhs) && 696 static_cast<decltype(lhs + rhs)>(lhs) == 697 static_cast<decltype(lhs + rhs)>(rhs); 698 } 699 }; 700 701 template <typename L, typename R> 702 struct IsNotEqual { 703 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value, 704 "Types must be numeric."); 705 static constexpr bool Test(const L lhs, const R rhs) { 706 return DstRangeRelationToSrcRange<R>(lhs) != 707 DstRangeRelationToSrcRange<L>(rhs) || 708 static_cast<decltype(lhs + rhs)>(lhs) != 709 static_cast<decltype(lhs + rhs)>(rhs); 710 } 711 }; 712 713 // These perform the actual math operations on the CheckedNumerics. 714 // Binary arithmetic operations. 715 template <template <typename, typename> class C, typename L, typename R> 716 constexpr bool SafeCompare(const L lhs, const R rhs) { 717 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value, 718 "Types must be numeric."); 719 using Promotion = BigEnoughPromotion<L, R>; 720 using BigType = typename Promotion::type; 721 return Promotion::is_contained 722 // Force to a larger type for speed if both are contained. 723 ? C<BigType, BigType>::Test( 724 static_cast<BigType>(static_cast<L>(lhs)), 725 static_cast<BigType>(static_cast<R>(rhs))) 726 // Let the template functions figure it out for mixed types. 727 : C<L, R>::Test(lhs, rhs); 728 }; 729 730 } // namespace internal 731 } // namespace base 732 } // namespace pdfium 733 734 #endif // PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ 735