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 THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_ 6 #define THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include <climits> 12 #include <cmath> 13 #include <cstdlib> 14 #include <limits> 15 #include <type_traits> 16 17 #include "third_party/base/numerics/safe_conversions.h" 18 19 namespace pdfium { 20 namespace base { 21 namespace internal { 22 23 // Everything from here up to the floating point operations is portable C++, 24 // but it may not be fast. This code could be split based on 25 // platform/architecture and replaced with potentially faster implementations. 26 27 // This is used for UnsignedAbs, where we need to support floating-point 28 // template instantiations even though we don't actually support the operations. 29 // However, there is no corresponding implementation of e.g. SafeUnsignedAbs, 30 // so the float versions will not compile. 31 template <typename Numeric, 32 bool IsInteger = std::is_integral<Numeric>::value, 33 bool IsFloat = std::is_floating_point<Numeric>::value> 34 struct UnsignedOrFloatForSize; 35 36 template <typename Numeric> 37 struct UnsignedOrFloatForSize<Numeric, true, false> { 38 using type = typename std::make_unsigned<Numeric>::type; 39 }; 40 41 template <typename Numeric> 42 struct UnsignedOrFloatForSize<Numeric, false, true> { 43 using type = Numeric; 44 }; 45 46 // Probe for builtin math overflow support on Clang and version check on GCC. 47 #if defined(EMSCRIPTEN) 48 // Emscripten Clang reports that it has the builtins, it may be lowered to an 49 // instruction that is unsupported in asm.js 50 #define USE_OVERFLOW_BUILTINS (0) 51 #elif defined(__has_builtin) 52 #define USE_OVERFLOW_BUILTINS (__has_builtin(__builtin_add_overflow)) 53 #elif defined(__GNUC__) 54 #define USE_OVERFLOW_BUILTINS (__GNUC__ >= 5) 55 #else 56 #define USE_OVERFLOW_BUILTINS (0) 57 #endif 58 59 template <typename T> 60 bool CheckedAddImpl(T x, T y, T* result) { 61 static_assert(std::is_integral<T>::value, "Type must be integral"); 62 // Since the value of x+y is undefined if we have a signed type, we compute 63 // it using the unsigned type of the same size. 64 using UnsignedDst = typename std::make_unsigned<T>::type; 65 using SignedDst = typename std::make_signed<T>::type; 66 auto ux = static_cast<UnsignedDst>(x); 67 auto uy = static_cast<UnsignedDst>(y); 68 auto uresult = static_cast<UnsignedDst>(ux + uy); 69 *result = static_cast<T>(uresult); 70 // Addition is valid if the sign of (x + y) is equal to either that of x or 71 // that of y. 72 return (std::is_signed<T>::value) 73 ? static_cast<SignedDst>((uresult ^ ux) & (uresult ^ uy)) >= 0 74 : uresult >= uy; // Unsigned is either valid or underflow. 75 } 76 77 template <typename T, typename U, class Enable = void> 78 struct CheckedAddOp {}; 79 80 template <typename T, typename U> 81 struct CheckedAddOp<T, 82 U, 83 typename std::enable_if<std::is_integral<T>::value && 84 std::is_integral<U>::value>::type> { 85 using result_type = typename MaxExponentPromotion<T, U>::type; 86 template <typename V> 87 static bool Do(T x, U y, V* result) { 88 #if USE_OVERFLOW_BUILTINS 89 return !__builtin_add_overflow(x, y, result); 90 #else 91 using Promotion = typename BigEnoughPromotion<T, U>::type; 92 Promotion presult; 93 // Fail if either operand is out of range for the promoted type. 94 // TODO(jschuh): This could be made to work for a broader range of values. 95 bool is_valid = IsValueInRangeForNumericType<Promotion>(x) && 96 IsValueInRangeForNumericType<Promotion>(y); 97 98 if (IsIntegerArithmeticSafe<Promotion, T, U>::value) { 99 presult = static_cast<Promotion>(x) + static_cast<Promotion>(y); 100 } else { 101 is_valid &= CheckedAddImpl(static_cast<Promotion>(x), 102 static_cast<Promotion>(y), &presult); 103 } 104 *result = static_cast<V>(presult); 105 return is_valid && IsValueInRangeForNumericType<V>(presult); 106 #endif 107 } 108 }; 109 110 template <typename T> 111 bool CheckedSubImpl(T x, T y, T* result) { 112 static_assert(std::is_integral<T>::value, "Type must be integral"); 113 // Since the value of x+y is undefined if we have a signed type, we compute 114 // it using the unsigned type of the same size. 115 using UnsignedDst = typename std::make_unsigned<T>::type; 116 using SignedDst = typename std::make_signed<T>::type; 117 auto ux = static_cast<UnsignedDst>(x); 118 auto uy = static_cast<UnsignedDst>(y); 119 auto uresult = static_cast<UnsignedDst>(ux - uy); 120 *result = static_cast<T>(uresult); 121 // Subtraction is valid if either x and y have same sign, or (x-y) and x have 122 // the same sign. 123 return (std::is_signed<T>::value) 124 ? static_cast<SignedDst>((uresult ^ ux) & (ux ^ uy)) >= 0 125 : x >= y; 126 } 127 128 template <typename T, typename U, class Enable = void> 129 struct CheckedSubOp {}; 130 131 template <typename T, typename U> 132 struct CheckedSubOp<T, 133 U, 134 typename std::enable_if<std::is_integral<T>::value && 135 std::is_integral<U>::value>::type> { 136 using result_type = typename MaxExponentPromotion<T, U>::type; 137 template <typename V> 138 static bool Do(T x, U y, V* result) { 139 #if USE_OVERFLOW_BUILTINS 140 return !__builtin_sub_overflow(x, y, result); 141 #else 142 using Promotion = typename BigEnoughPromotion<T, U>::type; 143 Promotion presult; 144 // Fail if either operand is out of range for the promoted type. 145 // TODO(jschuh): This could be made to work for a broader range of values. 146 bool is_valid = IsValueInRangeForNumericType<Promotion>(x) && 147 IsValueInRangeForNumericType<Promotion>(y); 148 149 if (IsIntegerArithmeticSafe<Promotion, T, U>::value) { 150 presult = static_cast<Promotion>(x) - static_cast<Promotion>(y); 151 } else { 152 is_valid &= CheckedSubImpl(static_cast<Promotion>(x), 153 static_cast<Promotion>(y), &presult); 154 } 155 *result = static_cast<V>(presult); 156 return is_valid && IsValueInRangeForNumericType<V>(presult); 157 #endif 158 } 159 }; 160 161 template <typename T> 162 bool CheckedMulImpl(T x, T y, T* result) { 163 static_assert(std::is_integral<T>::value, "Type must be integral"); 164 // Since the value of x*y is potentially undefined if we have a signed type, 165 // we compute it using the unsigned type of the same size. 166 using UnsignedDst = typename std::make_unsigned<T>::type; 167 using SignedDst = typename std::make_signed<T>::type; 168 const UnsignedDst ux = SafeUnsignedAbs(x); 169 const UnsignedDst uy = SafeUnsignedAbs(y); 170 auto uresult = static_cast<UnsignedDst>(ux * uy); 171 const bool is_negative = 172 std::is_signed<T>::value && static_cast<SignedDst>(x ^ y) < 0; 173 *result = is_negative ? 0 - uresult : uresult; 174 // We have a fast out for unsigned identity or zero on the second operand. 175 // After that it's an unsigned overflow check on the absolute value, with 176 // a +1 bound for a negative result. 177 return uy <= UnsignedDst(!std::is_signed<T>::value || is_negative) || 178 ux <= (std::numeric_limits<T>::max() + UnsignedDst(is_negative)) / uy; 179 } 180 181 template <typename T, typename U, class Enable = void> 182 struct CheckedMulOp {}; 183 184 template <typename T, typename U> 185 struct CheckedMulOp<T, 186 U, 187 typename std::enable_if<std::is_integral<T>::value && 188 std::is_integral<U>::value>::type> { 189 using result_type = typename MaxExponentPromotion<T, U>::type; 190 template <typename V> 191 static bool Do(T x, U y, V* result) { 192 #if USE_OVERFLOW_BUILTINS 193 #if defined(__clang__) 194 // TODO(jschuh): Get the Clang runtime library issues sorted out so we can 195 // support full-width, mixed-sign multiply builtins. 196 // https://crbug.com/613003 197 static const bool kUseMaxInt = 198 // Narrower type than uintptr_t is always safe. 199 std::numeric_limits<__typeof__(x * y)>::digits < 200 std::numeric_limits<intptr_t>::digits || 201 // Safe for intptr_t and uintptr_t if the sign matches. 202 (IntegerBitsPlusSign<__typeof__(x * y)>::value == 203 IntegerBitsPlusSign<intptr_t>::value && 204 std::is_signed<T>::value == std::is_signed<U>::value); 205 #else 206 static const bool kUseMaxInt = true; 207 #endif 208 if (kUseMaxInt) 209 return !__builtin_mul_overflow(x, y, result); 210 #endif 211 using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type; 212 Promotion presult; 213 // Fail if either operand is out of range for the promoted type. 214 // TODO(jschuh): This could be made to work for a broader range of values. 215 bool is_valid = IsValueInRangeForNumericType<Promotion>(x) && 216 IsValueInRangeForNumericType<Promotion>(y); 217 218 if (IsIntegerArithmeticSafe<Promotion, T, U>::value) { 219 presult = static_cast<Promotion>(x) * static_cast<Promotion>(y); 220 } else { 221 is_valid &= CheckedMulImpl(static_cast<Promotion>(x), 222 static_cast<Promotion>(y), &presult); 223 } 224 *result = static_cast<V>(presult); 225 return is_valid && IsValueInRangeForNumericType<V>(presult); 226 } 227 }; 228 229 // Avoid poluting the namespace once we're done with the macro. 230 #undef USE_OVERFLOW_BUILTINS 231 232 // Division just requires a check for a zero denominator or an invalid negation 233 // on signed min/-1. 234 template <typename T> 235 bool CheckedDivImpl(T x, T y, T* result) { 236 static_assert(std::is_integral<T>::value, "Type must be integral"); 237 if (y && (!std::is_signed<T>::value || 238 x != std::numeric_limits<T>::lowest() || y != static_cast<T>(-1))) { 239 *result = x / y; 240 return true; 241 } 242 return false; 243 } 244 245 template <typename T, typename U, class Enable = void> 246 struct CheckedDivOp {}; 247 248 template <typename T, typename U> 249 struct CheckedDivOp<T, 250 U, 251 typename std::enable_if<std::is_integral<T>::value && 252 std::is_integral<U>::value>::type> { 253 using result_type = typename MaxExponentPromotion<T, U>::type; 254 template <typename V> 255 static bool Do(T x, U y, V* result) { 256 using Promotion = typename BigEnoughPromotion<T, U>::type; 257 Promotion presult; 258 // Fail if either operand is out of range for the promoted type. 259 // TODO(jschuh): This could be made to work for a broader range of values. 260 bool is_valid = IsValueInRangeForNumericType<Promotion>(x) && 261 IsValueInRangeForNumericType<Promotion>(y); 262 is_valid &= CheckedDivImpl(static_cast<Promotion>(x), 263 static_cast<Promotion>(y), &presult); 264 *result = static_cast<V>(presult); 265 return is_valid && IsValueInRangeForNumericType<V>(presult); 266 } 267 }; 268 269 template <typename T> 270 bool CheckedModImpl(T x, T y, T* result) { 271 static_assert(std::is_integral<T>::value, "Type must be integral"); 272 if (y > 0) { 273 *result = static_cast<T>(x % y); 274 return true; 275 } 276 return false; 277 } 278 279 template <typename T, typename U, class Enable = void> 280 struct CheckedModOp {}; 281 282 template <typename T, typename U> 283 struct CheckedModOp<T, 284 U, 285 typename std::enable_if<std::is_integral<T>::value && 286 std::is_integral<U>::value>::type> { 287 using result_type = typename MaxExponentPromotion<T, U>::type; 288 template <typename V> 289 static bool Do(T x, U y, V* result) { 290 using Promotion = typename BigEnoughPromotion<T, U>::type; 291 Promotion presult; 292 bool is_valid = CheckedModImpl(static_cast<Promotion>(x), 293 static_cast<Promotion>(y), &presult); 294 *result = static_cast<V>(presult); 295 return is_valid && IsValueInRangeForNumericType<V>(presult); 296 } 297 }; 298 299 template <typename T, typename U, class Enable = void> 300 struct CheckedLshOp {}; 301 302 // Left shift. Shifts less than 0 or greater than or equal to the number 303 // of bits in the promoted type are undefined. Shifts of negative values 304 // are undefined. Otherwise it is defined when the result fits. 305 template <typename T, typename U> 306 struct CheckedLshOp<T, 307 U, 308 typename std::enable_if<std::is_integral<T>::value && 309 std::is_integral<U>::value>::type> { 310 using result_type = T; 311 template <typename V> 312 static bool Do(T x, U shift, V* result) { 313 using ShiftType = typename std::make_unsigned<T>::type; 314 static const ShiftType kBitWidth = IntegerBitsPlusSign<T>::value; 315 const auto real_shift = static_cast<ShiftType>(shift); 316 // Signed shift is not legal on negative values. 317 if (!IsValueNegative(x) && real_shift < kBitWidth) { 318 // Just use a multiplication because it's easy. 319 // TODO(jschuh): This could probably be made more efficient. 320 if (!std::is_signed<T>::value || real_shift != kBitWidth - 1) 321 return CheckedMulOp<T, T>::Do(x, static_cast<T>(1) << shift, result); 322 return !x; // Special case zero for a full width signed shift. 323 } 324 return false; 325 } 326 }; 327 328 template <typename T, typename U, class Enable = void> 329 struct CheckedRshOp {}; 330 331 // Right shift. Shifts less than 0 or greater than or equal to the number 332 // of bits in the promoted type are undefined. Otherwise, it is always defined, 333 // but a right shift of a negative value is implementation-dependent. 334 template <typename T, typename U> 335 struct CheckedRshOp<T, 336 U, 337 typename std::enable_if<std::is_integral<T>::value && 338 std::is_integral<U>::value>::type> { 339 using result_type = T; 340 template <typename V = result_type> 341 static bool Do(T x, U shift, V* result) { 342 // Use the type conversion push negative values out of range. 343 using ShiftType = typename std::make_unsigned<T>::type; 344 if (static_cast<ShiftType>(shift) < IntegerBitsPlusSign<T>::value) { 345 T tmp = x >> shift; 346 *result = static_cast<V>(tmp); 347 return IsValueInRangeForNumericType<V>(tmp); 348 } 349 return false; 350 } 351 }; 352 353 template <typename T, typename U, class Enable = void> 354 struct CheckedAndOp {}; 355 356 // For simplicity we support only unsigned integer results. 357 template <typename T, typename U> 358 struct CheckedAndOp<T, 359 U, 360 typename std::enable_if<std::is_integral<T>::value && 361 std::is_integral<U>::value>::type> { 362 using result_type = typename std::make_unsigned< 363 typename MaxExponentPromotion<T, U>::type>::type; 364 template <typename V = result_type> 365 static bool Do(T x, U y, V* result) { 366 result_type tmp = static_cast<result_type>(x) & static_cast<result_type>(y); 367 *result = static_cast<V>(tmp); 368 return IsValueInRangeForNumericType<V>(tmp); 369 } 370 }; 371 372 template <typename T, typename U, class Enable = void> 373 struct CheckedOrOp {}; 374 375 // For simplicity we support only unsigned integers. 376 template <typename T, typename U> 377 struct CheckedOrOp<T, 378 U, 379 typename std::enable_if<std::is_integral<T>::value && 380 std::is_integral<U>::value>::type> { 381 using result_type = typename std::make_unsigned< 382 typename MaxExponentPromotion<T, U>::type>::type; 383 template <typename V = result_type> 384 static bool Do(T x, U y, V* result) { 385 result_type tmp = static_cast<result_type>(x) | static_cast<result_type>(y); 386 *result = static_cast<V>(tmp); 387 return IsValueInRangeForNumericType<V>(tmp); 388 } 389 }; 390 391 template <typename T, typename U, class Enable = void> 392 struct CheckedXorOp {}; 393 394 // For simplicity we support only unsigned integers. 395 template <typename T, typename U> 396 struct CheckedXorOp<T, 397 U, 398 typename std::enable_if<std::is_integral<T>::value && 399 std::is_integral<U>::value>::type> { 400 using result_type = typename std::make_unsigned< 401 typename MaxExponentPromotion<T, U>::type>::type; 402 template <typename V = result_type> 403 static bool Do(T x, U y, V* result) { 404 result_type tmp = static_cast<result_type>(x) ^ static_cast<result_type>(y); 405 *result = static_cast<V>(tmp); 406 return IsValueInRangeForNumericType<V>(tmp); 407 } 408 }; 409 410 // Max doesn't really need to be implemented this way because it can't fail, 411 // but it makes the code much cleaner to use the MathOp wrappers. 412 template <typename T, typename U, class Enable = void> 413 struct CheckedMaxOp {}; 414 415 template <typename T, typename U> 416 struct CheckedMaxOp< 417 T, 418 U, 419 typename std::enable_if<std::is_arithmetic<T>::value && 420 std::is_arithmetic<U>::value>::type> { 421 using result_type = typename MaxExponentPromotion<T, U>::type; 422 template <typename V = result_type> 423 static bool Do(T x, U y, V* result) { 424 *result = IsGreater<T, U>::Test(x, y) ? static_cast<result_type>(x) 425 : static_cast<result_type>(y); 426 return true; 427 } 428 }; 429 430 // Min doesn't really need to be implemented this way because it can't fail, 431 // but it makes the code much cleaner to use the MathOp wrappers. 432 template <typename T, typename U, class Enable = void> 433 struct CheckedMinOp {}; 434 435 template <typename T, typename U> 436 struct CheckedMinOp< 437 T, 438 U, 439 typename std::enable_if<std::is_arithmetic<T>::value && 440 std::is_arithmetic<U>::value>::type> { 441 using result_type = typename LowestValuePromotion<T, U>::type; 442 template <typename V = result_type> 443 static bool Do(T x, U y, V* result) { 444 *result = IsLess<T, U>::Test(x, y) ? static_cast<result_type>(x) 445 : static_cast<result_type>(y); 446 return true; 447 } 448 }; 449 450 // This is just boilerplate that wraps the standard floating point arithmetic. 451 // A macro isn't the nicest solution, but it beats rewriting these repeatedly. 452 #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \ 453 template <typename T, typename U> \ 454 struct Checked##NAME##Op< \ 455 T, U, typename std::enable_if<std::is_floating_point<T>::value || \ 456 std::is_floating_point<U>::value>::type> { \ 457 using result_type = typename MaxExponentPromotion<T, U>::type; \ 458 template <typename V> \ 459 static bool Do(T x, U y, V* result) { \ 460 using Promotion = typename MaxExponentPromotion<T, U>::type; \ 461 Promotion presult = x OP y; \ 462 *result = static_cast<V>(presult); \ 463 return IsValueInRangeForNumericType<V>(presult); \ 464 } \ 465 }; 466 467 BASE_FLOAT_ARITHMETIC_OPS(Add, +) 468 BASE_FLOAT_ARITHMETIC_OPS(Sub, -) 469 BASE_FLOAT_ARITHMETIC_OPS(Mul, *) 470 BASE_FLOAT_ARITHMETIC_OPS(Div, /) 471 472 #undef BASE_FLOAT_ARITHMETIC_OPS 473 474 // Wrap the unary operations to allow SFINAE when instantiating integrals versus 475 // floating points. These don't perform any overflow checking. Rather, they 476 // exhibit well-defined overflow semantics and rely on the caller to detect 477 // if an overflow occured. 478 479 template <typename T, 480 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> 481 constexpr T NegateWrapper(T value) { 482 using UnsignedT = typename std::make_unsigned<T>::type; 483 // This will compile to a NEG on Intel, and is normal negation on ARM. 484 return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value)); 485 } 486 487 template < 488 typename T, 489 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> 490 constexpr T NegateWrapper(T value) { 491 return -value; 492 } 493 494 template <typename T, 495 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> 496 constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) { 497 return ~value; 498 } 499 500 template <typename T, 501 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> 502 constexpr T AbsWrapper(T value) { 503 return static_cast<T>(SafeUnsignedAbs(value)); 504 } 505 506 template < 507 typename T, 508 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> 509 constexpr T AbsWrapper(T value) { 510 return value < 0 ? -value : value; 511 } 512 513 // Floats carry around their validity state with them, but integers do not. So, 514 // we wrap the underlying value in a specialization in order to hide that detail 515 // and expose an interface via accessors. 516 enum NumericRepresentation { 517 NUMERIC_INTEGER, 518 NUMERIC_FLOATING, 519 NUMERIC_UNKNOWN 520 }; 521 522 template <typename NumericType> 523 struct GetNumericRepresentation { 524 static const NumericRepresentation value = 525 std::is_integral<NumericType>::value 526 ? NUMERIC_INTEGER 527 : (std::is_floating_point<NumericType>::value ? NUMERIC_FLOATING 528 : NUMERIC_UNKNOWN); 529 }; 530 531 template <typename T, NumericRepresentation type = 532 GetNumericRepresentation<T>::value> 533 class CheckedNumericState {}; 534 535 // Integrals require quite a bit of additional housekeeping to manage state. 536 template <typename T> 537 class CheckedNumericState<T, NUMERIC_INTEGER> { 538 private: 539 // is_valid_ precedes value_ because member intializers in the constructors 540 // are evaluated in field order, and is_valid_ must be read when initializing 541 // value_. 542 bool is_valid_; 543 T value_; 544 545 // Ensures that a type conversion does not trigger undefined behavior. 546 template <typename Src> 547 static constexpr T WellDefinedConversionOrZero(const Src value, 548 const bool is_valid) { 549 using SrcType = typename internal::UnderlyingType<Src>::type; 550 return (std::is_integral<SrcType>::value || is_valid) 551 ? static_cast<T>(value) 552 : static_cast<T>(0); 553 } 554 555 public: 556 template <typename Src, NumericRepresentation type> 557 friend class CheckedNumericState; 558 559 constexpr CheckedNumericState() : is_valid_(true), value_(0) {} 560 561 template <typename Src> 562 constexpr CheckedNumericState(Src value, bool is_valid) 563 : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)), 564 value_(WellDefinedConversionOrZero(value, is_valid_)) { 565 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); 566 } 567 568 // Copy constructor. 569 template <typename Src> 570 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs) 571 : is_valid_(rhs.IsValid()), 572 value_(WellDefinedConversionOrZero(rhs.value(), is_valid_)) {} 573 574 template <typename Src> 575 constexpr explicit CheckedNumericState(Src value) 576 : is_valid_(IsValueInRangeForNumericType<T>(value)), 577 value_(WellDefinedConversionOrZero(value, is_valid_)) {} 578 579 constexpr bool is_valid() const { return is_valid_; } 580 constexpr T value() const { return value_; } 581 }; 582 583 // Floating points maintain their own validity, but need translation wrappers. 584 template <typename T> 585 class CheckedNumericState<T, NUMERIC_FLOATING> { 586 private: 587 T value_; 588 589 // Ensures that a type conversion does not trigger undefined behavior. 590 template <typename Src> 591 static constexpr T WellDefinedConversionOrNaN(const Src value, 592 const bool is_valid) { 593 using SrcType = typename internal::UnderlyingType<Src>::type; 594 return (StaticDstRangeRelationToSrcRange<T, SrcType>::value == 595 NUMERIC_RANGE_CONTAINED || 596 is_valid) 597 ? static_cast<T>(value) 598 : std::numeric_limits<T>::quiet_NaN(); 599 } 600 601 public: 602 template <typename Src, NumericRepresentation type> 603 friend class CheckedNumericState; 604 605 constexpr CheckedNumericState() : value_(0.0) {} 606 607 template <typename Src> 608 constexpr CheckedNumericState(Src value, bool is_valid) 609 : value_(WellDefinedConversionOrNaN(value, is_valid)) {} 610 611 template <typename Src> 612 constexpr explicit CheckedNumericState(Src value) 613 : value_(WellDefinedConversionOrNaN( 614 value, 615 IsValueInRangeForNumericType<T>(value))) {} 616 617 // Copy constructor. 618 template <typename Src> 619 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs) 620 : value_(WellDefinedConversionOrNaN( 621 rhs.value(), 622 rhs.is_valid() && IsValueInRangeForNumericType<T>(rhs.value()))) {} 623 624 constexpr bool is_valid() const { 625 // Written this way because std::isfinite is not reliably constexpr. 626 // TODO(jschuh): Fix this if the libraries ever get fixed. 627 return value_ <= std::numeric_limits<T>::max() && 628 value_ >= std::numeric_limits<T>::lowest(); 629 } 630 constexpr T value() const { return value_; } 631 }; 632 633 template <template <typename, typename, typename> class M, 634 typename L, 635 typename R> 636 struct MathWrapper { 637 using math = M<typename UnderlyingType<L>::type, 638 typename UnderlyingType<R>::type, 639 void>; 640 using type = typename math::result_type; 641 }; 642 643 } // namespace internal 644 } // namespace base 645 } // namespace pdfium 646 647 #endif // THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_ 648