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_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