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