| // Copyright 2014 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ | 
 | #define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ | 
 |  | 
 | #include <stdint.h> | 
 |  | 
 | #include <limits> | 
 | #include <type_traits> | 
 |  | 
 | #if defined(__GNUC__) || defined(__clang__) | 
 | #define BASE_NUMERICS_LIKELY(x) __builtin_expect(!!(x), 1) | 
 | #define BASE_NUMERICS_UNLIKELY(x) __builtin_expect(!!(x), 0) | 
 | #else | 
 | #define BASE_NUMERICS_LIKELY(x) (x) | 
 | #define BASE_NUMERICS_UNLIKELY(x) (x) | 
 | #endif | 
 |  | 
 | namespace base { | 
 | namespace internal { | 
 |  | 
 | // The std library doesn't provide a binary max_exponent for integers, however | 
 | // we can compute an analog using std::numeric_limits<>::digits. | 
 | template <typename NumericType> | 
 | struct MaxExponent { | 
 |   static const int value = std::is_floating_point<NumericType>::value | 
 |                                ? std::numeric_limits<NumericType>::max_exponent | 
 |                                : std::numeric_limits<NumericType>::digits + 1; | 
 | }; | 
 |  | 
 | // The number of bits (including the sign) in an integer. Eliminates sizeof | 
 | // hacks. | 
 | template <typename NumericType> | 
 | struct IntegerBitsPlusSign { | 
 |   static const int value = std::numeric_limits<NumericType>::digits + | 
 |                            std::is_signed<NumericType>::value; | 
 | }; | 
 |  | 
 | // Helper templates for integer manipulations. | 
 |  | 
 | template <typename Integer> | 
 | struct PositionOfSignBit { | 
 |   static const size_t value = IntegerBitsPlusSign<Integer>::value - 1; | 
 | }; | 
 |  | 
 | // Determines if a numeric value is negative without throwing compiler | 
 | // warnings on: unsigned(value) < 0. | 
 | template <typename T, | 
 |           typename std::enable_if<std::is_signed<T>::value>::type* = nullptr> | 
 | constexpr bool IsValueNegative(T value) { | 
 |   static_assert(std::is_arithmetic<T>::value, "Argument must be numeric."); | 
 |   return value < 0; | 
 | } | 
 |  | 
 | template <typename T, | 
 |           typename std::enable_if<!std::is_signed<T>::value>::type* = nullptr> | 
 | constexpr bool IsValueNegative(T) { | 
 |   static_assert(std::is_arithmetic<T>::value, "Argument must be numeric."); | 
 |   return false; | 
 | } | 
 |  | 
 | // This performs a fast negation, returning a signed value. It works on unsigned | 
 | // arguments, but probably doesn't do what you want for any unsigned value | 
 | // larger than max / 2 + 1 (i.e. signed min cast to unsigned). | 
 | template <typename T> | 
 | constexpr typename std::make_signed<T>::type ConditionalNegate( | 
 |     T x, | 
 |     bool is_negative) { | 
 |   static_assert(std::is_integral<T>::value, "Type must be integral"); | 
 |   using SignedT = typename std::make_signed<T>::type; | 
 |   using UnsignedT = typename std::make_unsigned<T>::type; | 
 |   return static_cast<SignedT>( | 
 |       (static_cast<UnsignedT>(x) ^ -SignedT(is_negative)) + is_negative); | 
 | } | 
 |  | 
 | // This performs a safe, absolute value via unsigned overflow. | 
 | template <typename T> | 
 | constexpr typename std::make_unsigned<T>::type SafeUnsignedAbs(T value) { | 
 |   static_assert(std::is_integral<T>::value, "Type must be integral"); | 
 |   using UnsignedT = typename std::make_unsigned<T>::type; | 
 |   return IsValueNegative(value) ? 0 - static_cast<UnsignedT>(value) | 
 |                                 : static_cast<UnsignedT>(value); | 
 | } | 
 |  | 
 | // This allows us to switch paths on known compile-time constants. | 
 | #if defined(__clang__) || defined(__GNUC__) | 
 | constexpr bool CanDetectCompileTimeConstant() { | 
 |   return true; | 
 | } | 
 | template <typename T> | 
 | constexpr bool IsCompileTimeConstant(const T v) { | 
 |   return __builtin_constant_p(v); | 
 | } | 
 | #else | 
 | constexpr bool CanDetectCompileTimeConstant() { | 
 |   return false; | 
 | } | 
 | template <typename T> | 
 | constexpr bool IsCompileTimeConstant(const T) { | 
 |   return false; | 
 | } | 
 | #endif | 
 | template <typename T> | 
 | constexpr bool MustTreatAsConstexpr(const T v) { | 
 |   // Either we can't detect a compile-time constant, and must always use the | 
 |   // constexpr path, or we know we have a compile-time constant. | 
 |   return !CanDetectCompileTimeConstant() || IsCompileTimeConstant(v); | 
 | } | 
 |  | 
 | // Forces a crash, like a CHECK(false). Used for numeric boundary errors. | 
 | // Also used in a constexpr template to trigger a compilation failure on | 
 | // an error condition. | 
 | struct CheckOnFailure { | 
 |   template <typename T> | 
 |   static T HandleFailure() { | 
 | #if defined(_MSC_VER) | 
 |     __debugbreak(); | 
 | #elif defined(__GNUC__) || defined(__clang__) | 
 |     __builtin_trap(); | 
 | #else | 
 |     ((void)(*(volatile char*)0 = 0)); | 
 | #endif | 
 |     return T(); | 
 |   } | 
 | }; | 
 |  | 
 | enum IntegerRepresentation { | 
 |   INTEGER_REPRESENTATION_UNSIGNED, | 
 |   INTEGER_REPRESENTATION_SIGNED | 
 | }; | 
 |  | 
 | // A range for a given nunmeric Src type is contained for a given numeric Dst | 
 | // type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and | 
 | // numeric_limits<Src>::lowest() >= numeric_limits<Dst>::lowest() are true. | 
 | // We implement this as template specializations rather than simple static | 
 | // comparisons to ensure type correctness in our comparisons. | 
 | enum NumericRangeRepresentation { | 
 |   NUMERIC_RANGE_NOT_CONTAINED, | 
 |   NUMERIC_RANGE_CONTAINED | 
 | }; | 
 |  | 
 | // Helper templates to statically determine if our destination type can contain | 
 | // maximum and minimum values represented by the source type. | 
 |  | 
 | template <typename Dst, | 
 |           typename Src, | 
 |           IntegerRepresentation DstSign = std::is_signed<Dst>::value | 
 |                                               ? INTEGER_REPRESENTATION_SIGNED | 
 |                                               : INTEGER_REPRESENTATION_UNSIGNED, | 
 |           IntegerRepresentation SrcSign = std::is_signed<Src>::value | 
 |                                               ? INTEGER_REPRESENTATION_SIGNED | 
 |                                               : INTEGER_REPRESENTATION_UNSIGNED> | 
 | struct StaticDstRangeRelationToSrcRange; | 
 |  | 
 | // Same sign: Dst is guaranteed to contain Src only if its range is equal or | 
 | // larger. | 
 | template <typename Dst, typename Src, IntegerRepresentation Sign> | 
 | struct StaticDstRangeRelationToSrcRange<Dst, Src, Sign, Sign> { | 
 |   static const NumericRangeRepresentation value = | 
 |       MaxExponent<Dst>::value >= MaxExponent<Src>::value | 
 |           ? NUMERIC_RANGE_CONTAINED | 
 |           : NUMERIC_RANGE_NOT_CONTAINED; | 
 | }; | 
 |  | 
 | // Unsigned to signed: Dst is guaranteed to contain source only if its range is | 
 | // larger. | 
 | template <typename Dst, typename Src> | 
 | struct StaticDstRangeRelationToSrcRange<Dst, | 
 |                                         Src, | 
 |                                         INTEGER_REPRESENTATION_SIGNED, | 
 |                                         INTEGER_REPRESENTATION_UNSIGNED> { | 
 |   static const NumericRangeRepresentation value = | 
 |       MaxExponent<Dst>::value > MaxExponent<Src>::value | 
 |           ? NUMERIC_RANGE_CONTAINED | 
 |           : NUMERIC_RANGE_NOT_CONTAINED; | 
 | }; | 
 |  | 
 | // Signed to unsigned: Dst cannot be statically determined to contain Src. | 
 | template <typename Dst, typename Src> | 
 | struct StaticDstRangeRelationToSrcRange<Dst, | 
 |                                         Src, | 
 |                                         INTEGER_REPRESENTATION_UNSIGNED, | 
 |                                         INTEGER_REPRESENTATION_SIGNED> { | 
 |   static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED; | 
 | }; | 
 |  | 
 | // This class wraps the range constraints as separate booleans so the compiler | 
 | // can identify constants and eliminate unused code paths. | 
 | class RangeCheck { | 
 |  public: | 
 |   constexpr RangeCheck(bool is_in_lower_bound, bool is_in_upper_bound) | 
 |       : is_underflow_(!is_in_lower_bound), is_overflow_(!is_in_upper_bound) {} | 
 |   constexpr RangeCheck() : is_underflow_(0), is_overflow_(0) {} | 
 |   constexpr bool IsValid() const { return !is_overflow_ && !is_underflow_; } | 
 |   constexpr bool IsInvalid() const { return is_overflow_ && is_underflow_; } | 
 |   constexpr bool IsOverflow() const { return is_overflow_ && !is_underflow_; } | 
 |   constexpr bool IsUnderflow() const { return !is_overflow_ && is_underflow_; } | 
 |   constexpr bool IsOverflowFlagSet() const { return is_overflow_; } | 
 |   constexpr bool IsUnderflowFlagSet() const { return is_underflow_; } | 
 |   constexpr bool operator==(const RangeCheck rhs) const { | 
 |     return is_underflow_ == rhs.is_underflow_ && | 
 |            is_overflow_ == rhs.is_overflow_; | 
 |   } | 
 |   constexpr bool operator!=(const RangeCheck rhs) const { | 
 |     return !(*this == rhs); | 
 |   } | 
 |  | 
 |  private: | 
 |   // Do not change the order of these member variables. The integral conversion | 
 |   // optimization depends on this exact order. | 
 |   const bool is_underflow_; | 
 |   const bool is_overflow_; | 
 | }; | 
 |  | 
 | // The following helper template addresses a corner case in range checks for | 
 | // conversion from a floating-point type to an integral type of smaller range | 
 | // but larger precision (e.g. float -> unsigned). The problem is as follows: | 
 | //   1. Integral maximum is always one less than a power of two, so it must be | 
 | //      truncated to fit the mantissa of the floating point. The direction of | 
 | //      rounding is implementation defined, but by default it's always IEEE | 
 | //      floats, which round to nearest and thus result in a value of larger | 
 | //      magnitude than the integral value. | 
 | //      Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX | 
 | //                                   // is 4294967295u. | 
 | //   2. If the floating point value is equal to the promoted integral maximum | 
 | //      value, a range check will erroneously pass. | 
 | //      Example: (4294967296f <= 4294967295u) // This is true due to a precision | 
 | //                                            // loss in rounding up to float. | 
 | //   3. When the floating point value is then converted to an integral, the | 
 | //      resulting value is out of range for the target integral type and | 
 | //      thus is implementation defined. | 
 | //      Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0. | 
 | // To fix this bug we manually truncate the maximum value when the destination | 
 | // type is an integral of larger precision than the source floating-point type, | 
 | // such that the resulting maximum is represented exactly as a floating point. | 
 | template <typename Dst, typename Src, template <typename> class Bounds> | 
 | struct NarrowingRange { | 
 |   using SrcLimits = std::numeric_limits<Src>; | 
 |   using DstLimits = typename std::numeric_limits<Dst>; | 
 |  | 
 |   // Computes the mask required to make an accurate comparison between types. | 
 |   static const int kShift = | 
 |       (MaxExponent<Src>::value > MaxExponent<Dst>::value && | 
 |        SrcLimits::digits < DstLimits::digits) | 
 |           ? (DstLimits::digits - SrcLimits::digits) | 
 |           : 0; | 
 |   template < | 
 |       typename T, | 
 |       typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> | 
 |  | 
 |   // Masks out the integer bits that are beyond the precision of the | 
 |   // intermediate type used for comparison. | 
 |   static constexpr T Adjust(T value) { | 
 |     static_assert(std::is_same<T, Dst>::value, ""); | 
 |     static_assert(kShift < DstLimits::digits, ""); | 
 |     return static_cast<T>( | 
 |         ConditionalNegate(SafeUnsignedAbs(value) & ~((T(1) << kShift) - T(1)), | 
 |                           IsValueNegative(value))); | 
 |   } | 
 |  | 
 |   template <typename T, | 
 |             typename std::enable_if<std::is_floating_point<T>::value>::type* = | 
 |                 nullptr> | 
 |   static constexpr T Adjust(T value) { | 
 |     static_assert(std::is_same<T, Dst>::value, ""); | 
 |     static_assert(kShift == 0, ""); | 
 |     return value; | 
 |   } | 
 |  | 
 |   static constexpr Dst max() { return Adjust(Bounds<Dst>::max()); } | 
 |   static constexpr Dst lowest() { return Adjust(Bounds<Dst>::lowest()); } | 
 | }; | 
 |  | 
 | template <typename Dst, | 
 |           typename Src, | 
 |           template <typename> | 
 |           class Bounds, | 
 |           IntegerRepresentation DstSign = std::is_signed<Dst>::value | 
 |                                               ? INTEGER_REPRESENTATION_SIGNED | 
 |                                               : INTEGER_REPRESENTATION_UNSIGNED, | 
 |           IntegerRepresentation SrcSign = std::is_signed<Src>::value | 
 |                                               ? INTEGER_REPRESENTATION_SIGNED | 
 |                                               : INTEGER_REPRESENTATION_UNSIGNED, | 
 |           NumericRangeRepresentation DstRange = | 
 |               StaticDstRangeRelationToSrcRange<Dst, Src>::value> | 
 | struct DstRangeRelationToSrcRangeImpl; | 
 |  | 
 | // The following templates are for ranges that must be verified at runtime. We | 
 | // split it into checks based on signedness to avoid confusing casts and | 
 | // compiler warnings on signed an unsigned comparisons. | 
 |  | 
 | // Same sign narrowing: The range is contained for normal limits. | 
 | template <typename Dst, | 
 |           typename Src, | 
 |           template <typename> | 
 |           class Bounds, | 
 |           IntegerRepresentation DstSign, | 
 |           IntegerRepresentation SrcSign> | 
 | struct DstRangeRelationToSrcRangeImpl<Dst, | 
 |                                       Src, | 
 |                                       Bounds, | 
 |                                       DstSign, | 
 |                                       SrcSign, | 
 |                                       NUMERIC_RANGE_CONTAINED> { | 
 |   static constexpr RangeCheck Check(Src value) { | 
 |     using SrcLimits = std::numeric_limits<Src>; | 
 |     using DstLimits = NarrowingRange<Dst, Src, Bounds>; | 
 |     return RangeCheck( | 
 |         static_cast<Dst>(SrcLimits::lowest()) >= DstLimits::lowest() || | 
 |             static_cast<Dst>(value) >= DstLimits::lowest(), | 
 |         static_cast<Dst>(SrcLimits::max()) <= DstLimits::max() || | 
 |             static_cast<Dst>(value) <= DstLimits::max()); | 
 |   } | 
 | }; | 
 |  | 
 | // Signed to signed narrowing: Both the upper and lower boundaries may be | 
 | // exceeded for standard limits. | 
 | template <typename Dst, typename Src, template <typename> class Bounds> | 
 | struct DstRangeRelationToSrcRangeImpl<Dst, | 
 |                                       Src, | 
 |                                       Bounds, | 
 |                                       INTEGER_REPRESENTATION_SIGNED, | 
 |                                       INTEGER_REPRESENTATION_SIGNED, | 
 |                                       NUMERIC_RANGE_NOT_CONTAINED> { | 
 |   static constexpr RangeCheck Check(Src value) { | 
 |     using DstLimits = NarrowingRange<Dst, Src, Bounds>; | 
 |     return RangeCheck(value >= DstLimits::lowest(), value <= DstLimits::max()); | 
 |   } | 
 | }; | 
 |  | 
 | // Unsigned to unsigned narrowing: Only the upper bound can be exceeded for | 
 | // standard limits. | 
 | template <typename Dst, typename Src, template <typename> class Bounds> | 
 | struct DstRangeRelationToSrcRangeImpl<Dst, | 
 |                                       Src, | 
 |                                       Bounds, | 
 |                                       INTEGER_REPRESENTATION_UNSIGNED, | 
 |                                       INTEGER_REPRESENTATION_UNSIGNED, | 
 |                                       NUMERIC_RANGE_NOT_CONTAINED> { | 
 |   static constexpr RangeCheck Check(Src value) { | 
 |     using DstLimits = NarrowingRange<Dst, Src, Bounds>; | 
 |     return RangeCheck( | 
 |         DstLimits::lowest() == Dst(0) || value >= DstLimits::lowest(), | 
 |         value <= DstLimits::max()); | 
 |   } | 
 | }; | 
 |  | 
 | // Unsigned to signed: Only the upper bound can be exceeded for standard limits. | 
 | template <typename Dst, typename Src, template <typename> class Bounds> | 
 | struct DstRangeRelationToSrcRangeImpl<Dst, | 
 |                                       Src, | 
 |                                       Bounds, | 
 |                                       INTEGER_REPRESENTATION_SIGNED, | 
 |                                       INTEGER_REPRESENTATION_UNSIGNED, | 
 |                                       NUMERIC_RANGE_NOT_CONTAINED> { | 
 |   static constexpr RangeCheck Check(Src value) { | 
 |     using DstLimits = NarrowingRange<Dst, Src, Bounds>; | 
 |     using Promotion = decltype(Src() + Dst()); | 
 |     return RangeCheck(DstLimits::lowest() <= Dst(0) || | 
 |                           static_cast<Promotion>(value) >= | 
 |                               static_cast<Promotion>(DstLimits::lowest()), | 
 |                       static_cast<Promotion>(value) <= | 
 |                           static_cast<Promotion>(DstLimits::max())); | 
 |   } | 
 | }; | 
 |  | 
 | // Signed to unsigned: The upper boundary may be exceeded for a narrower Dst, | 
 | // and any negative value exceeds the lower boundary for standard limits. | 
 | template <typename Dst, typename Src, template <typename> class Bounds> | 
 | struct DstRangeRelationToSrcRangeImpl<Dst, | 
 |                                       Src, | 
 |                                       Bounds, | 
 |                                       INTEGER_REPRESENTATION_UNSIGNED, | 
 |                                       INTEGER_REPRESENTATION_SIGNED, | 
 |                                       NUMERIC_RANGE_NOT_CONTAINED> { | 
 |   static constexpr RangeCheck Check(Src value) { | 
 |     using SrcLimits = std::numeric_limits<Src>; | 
 |     using DstLimits = NarrowingRange<Dst, Src, Bounds>; | 
 |     using Promotion = decltype(Src() + Dst()); | 
 |     return RangeCheck( | 
 |         value >= Src(0) && (DstLimits::lowest() == 0 || | 
 |                             static_cast<Dst>(value) >= DstLimits::lowest()), | 
 |         static_cast<Promotion>(SrcLimits::max()) <= | 
 |                 static_cast<Promotion>(DstLimits::max()) || | 
 |             static_cast<Promotion>(value) <= | 
 |                 static_cast<Promotion>(DstLimits::max())); | 
 |   } | 
 | }; | 
 |  | 
 | // Simple wrapper for statically checking if a type's range is contained. | 
 | template <typename Dst, typename Src> | 
 | struct IsTypeInRangeForNumericType { | 
 |   static const bool value = StaticDstRangeRelationToSrcRange<Dst, Src>::value == | 
 |                             NUMERIC_RANGE_CONTAINED; | 
 | }; | 
 |  | 
 | template <typename Dst, | 
 |           template <typename> class Bounds = std::numeric_limits, | 
 |           typename Src> | 
 | constexpr RangeCheck DstRangeRelationToSrcRange(Src value) { | 
 |   static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); | 
 |   static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric."); | 
 |   static_assert(Bounds<Dst>::lowest() < Bounds<Dst>::max(), ""); | 
 |   return DstRangeRelationToSrcRangeImpl<Dst, Src, Bounds>::Check(value); | 
 | } | 
 |  | 
 | // Integer promotion templates used by the portable checked integer arithmetic. | 
 | template <size_t Size, bool IsSigned> | 
 | struct IntegerForDigitsAndSign; | 
 |  | 
 | #define INTEGER_FOR_DIGITS_AND_SIGN(I)                          \ | 
 |   template <>                                                   \ | 
 |   struct IntegerForDigitsAndSign<IntegerBitsPlusSign<I>::value, \ | 
 |                                  std::is_signed<I>::value> {    \ | 
 |     using type = I;                                             \ | 
 |   } | 
 |  | 
 | INTEGER_FOR_DIGITS_AND_SIGN(int8_t); | 
 | INTEGER_FOR_DIGITS_AND_SIGN(uint8_t); | 
 | INTEGER_FOR_DIGITS_AND_SIGN(int16_t); | 
 | INTEGER_FOR_DIGITS_AND_SIGN(uint16_t); | 
 | INTEGER_FOR_DIGITS_AND_SIGN(int32_t); | 
 | INTEGER_FOR_DIGITS_AND_SIGN(uint32_t); | 
 | INTEGER_FOR_DIGITS_AND_SIGN(int64_t); | 
 | INTEGER_FOR_DIGITS_AND_SIGN(uint64_t); | 
 | #undef INTEGER_FOR_DIGITS_AND_SIGN | 
 |  | 
 | // WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to | 
 | // support 128-bit math, then the ArithmeticPromotion template below will need | 
 | // to be updated (or more likely replaced with a decltype expression). | 
 | static_assert(IntegerBitsPlusSign<intmax_t>::value == 64, | 
 |               "Max integer size not supported for this toolchain."); | 
 |  | 
 | template <typename Integer, bool IsSigned = std::is_signed<Integer>::value> | 
 | struct TwiceWiderInteger { | 
 |   using type = | 
 |       typename IntegerForDigitsAndSign<IntegerBitsPlusSign<Integer>::value * 2, | 
 |                                        IsSigned>::type; | 
 | }; | 
 |  | 
 | enum ArithmeticPromotionCategory { | 
 |   LEFT_PROMOTION,  // Use the type of the left-hand argument. | 
 |   RIGHT_PROMOTION  // Use the type of the right-hand argument. | 
 | }; | 
 |  | 
 | // Determines the type that can represent the largest positive value. | 
 | template <typename Lhs, | 
 |           typename Rhs, | 
 |           ArithmeticPromotionCategory Promotion = | 
 |               (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) | 
 |                   ? LEFT_PROMOTION | 
 |                   : RIGHT_PROMOTION> | 
 | struct MaxExponentPromotion; | 
 |  | 
 | template <typename Lhs, typename Rhs> | 
 | struct MaxExponentPromotion<Lhs, Rhs, LEFT_PROMOTION> { | 
 |   using type = Lhs; | 
 | }; | 
 |  | 
 | template <typename Lhs, typename Rhs> | 
 | struct MaxExponentPromotion<Lhs, Rhs, RIGHT_PROMOTION> { | 
 |   using type = Rhs; | 
 | }; | 
 |  | 
 | // Determines the type that can represent the lowest arithmetic value. | 
 | template <typename Lhs, | 
 |           typename Rhs, | 
 |           ArithmeticPromotionCategory Promotion = | 
 |               std::is_signed<Lhs>::value | 
 |                   ? (std::is_signed<Rhs>::value | 
 |                          ? (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value | 
 |                                 ? LEFT_PROMOTION | 
 |                                 : RIGHT_PROMOTION) | 
 |                          : LEFT_PROMOTION) | 
 |                   : (std::is_signed<Rhs>::value | 
 |                          ? RIGHT_PROMOTION | 
 |                          : (MaxExponent<Lhs>::value < MaxExponent<Rhs>::value | 
 |                                 ? LEFT_PROMOTION | 
 |                                 : RIGHT_PROMOTION))> | 
 | struct LowestValuePromotion; | 
 |  | 
 | template <typename Lhs, typename Rhs> | 
 | struct LowestValuePromotion<Lhs, Rhs, LEFT_PROMOTION> { | 
 |   using type = Lhs; | 
 | }; | 
 |  | 
 | template <typename Lhs, typename Rhs> | 
 | struct LowestValuePromotion<Lhs, Rhs, RIGHT_PROMOTION> { | 
 |   using type = Rhs; | 
 | }; | 
 |  | 
 | // Determines the type that is best able to represent an arithmetic result. | 
 | template < | 
 |     typename Lhs, | 
 |     typename Rhs = Lhs, | 
 |     bool is_intmax_type = | 
 |         std::is_integral< | 
 |             typename MaxExponentPromotion<Lhs, Rhs>::type>::value && | 
 |         IntegerBitsPlusSign<typename MaxExponentPromotion<Lhs, Rhs>::type>:: | 
 |                 value == IntegerBitsPlusSign<intmax_t>::value, | 
 |     bool is_max_exponent = StaticDstRangeRelationToSrcRange< | 
 |                                typename MaxExponentPromotion<Lhs, Rhs>::type, | 
 |                                Lhs>::value == NUMERIC_RANGE_CONTAINED && | 
 |                            StaticDstRangeRelationToSrcRange< | 
 |                                typename MaxExponentPromotion<Lhs, Rhs>::type, | 
 |                                Rhs>::value == NUMERIC_RANGE_CONTAINED> | 
 | struct BigEnoughPromotion; | 
 |  | 
 | // The side with the max exponent is big enough. | 
 | template <typename Lhs, typename Rhs, bool is_intmax_type> | 
 | struct BigEnoughPromotion<Lhs, Rhs, is_intmax_type, true> { | 
 |   using type = typename MaxExponentPromotion<Lhs, Rhs>::type; | 
 |   static const bool is_contained = true; | 
 | }; | 
 |  | 
 | // We can use a twice wider type to fit. | 
 | template <typename Lhs, typename Rhs> | 
 | struct BigEnoughPromotion<Lhs, Rhs, false, false> { | 
 |   using type = | 
 |       typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type, | 
 |                                  std::is_signed<Lhs>::value || | 
 |                                      std::is_signed<Rhs>::value>::type; | 
 |   static const bool is_contained = true; | 
 | }; | 
 |  | 
 | // No type is large enough. | 
 | template <typename Lhs, typename Rhs> | 
 | struct BigEnoughPromotion<Lhs, Rhs, true, false> { | 
 |   using type = typename MaxExponentPromotion<Lhs, Rhs>::type; | 
 |   static const bool is_contained = false; | 
 | }; | 
 |  | 
 | // We can statically check if operations on the provided types can wrap, so we | 
 | // can skip the checked operations if they're not needed. So, for an integer we | 
 | // care if the destination type preserves the sign and is twice the width of | 
 | // the source. | 
 | template <typename T, typename Lhs, typename Rhs = Lhs> | 
 | struct IsIntegerArithmeticSafe { | 
 |   static const bool value = | 
 |       !std::is_floating_point<T>::value && | 
 |       !std::is_floating_point<Lhs>::value && | 
 |       !std::is_floating_point<Rhs>::value && | 
 |       std::is_signed<T>::value >= std::is_signed<Lhs>::value && | 
 |       IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Lhs>::value) && | 
 |       std::is_signed<T>::value >= std::is_signed<Rhs>::value && | 
 |       IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Rhs>::value); | 
 | }; | 
 |  | 
 | // Promotes to a type that can represent any possible result of a binary | 
 | // arithmetic operation with the source types. | 
 | template <typename Lhs, | 
 |           typename Rhs, | 
 |           bool is_promotion_possible = IsIntegerArithmeticSafe< | 
 |               typename std::conditional<std::is_signed<Lhs>::value || | 
 |                                             std::is_signed<Rhs>::value, | 
 |                                         intmax_t, | 
 |                                         uintmax_t>::type, | 
 |               typename MaxExponentPromotion<Lhs, Rhs>::type>::value> | 
 | struct FastIntegerArithmeticPromotion; | 
 |  | 
 | template <typename Lhs, typename Rhs> | 
 | struct FastIntegerArithmeticPromotion<Lhs, Rhs, true> { | 
 |   using type = | 
 |       typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type, | 
 |                                  std::is_signed<Lhs>::value || | 
 |                                      std::is_signed<Rhs>::value>::type; | 
 |   static_assert(IsIntegerArithmeticSafe<type, Lhs, Rhs>::value, ""); | 
 |   static const bool is_contained = true; | 
 | }; | 
 |  | 
 | template <typename Lhs, typename Rhs> | 
 | struct FastIntegerArithmeticPromotion<Lhs, Rhs, false> { | 
 |   using type = typename BigEnoughPromotion<Lhs, Rhs>::type; | 
 |   static const bool is_contained = false; | 
 | }; | 
 |  | 
 | // Extracts the underlying type from an enum. | 
 | template <typename T, bool is_enum = std::is_enum<T>::value> | 
 | struct ArithmeticOrUnderlyingEnum; | 
 |  | 
 | template <typename T> | 
 | struct ArithmeticOrUnderlyingEnum<T, true> { | 
 |   using type = typename std::underlying_type<T>::type; | 
 |   static const bool value = std::is_arithmetic<type>::value; | 
 | }; | 
 |  | 
 | template <typename T> | 
 | struct ArithmeticOrUnderlyingEnum<T, false> { | 
 |   using type = T; | 
 |   static const bool value = std::is_arithmetic<type>::value; | 
 | }; | 
 |  | 
 | // The following are helper templates used in the CheckedNumeric class. | 
 | template <typename T> | 
 | class CheckedNumeric; | 
 |  | 
 | template <typename T> | 
 | class ClampedNumeric; | 
 |  | 
 | template <typename T> | 
 | class StrictNumeric; | 
 |  | 
 | // Used to treat CheckedNumeric and arithmetic underlying types the same. | 
 | template <typename T> | 
 | struct UnderlyingType { | 
 |   using type = typename ArithmeticOrUnderlyingEnum<T>::type; | 
 |   static const bool is_numeric = std::is_arithmetic<type>::value; | 
 |   static const bool is_checked = false; | 
 |   static const bool is_clamped = false; | 
 |   static const bool is_strict = false; | 
 | }; | 
 |  | 
 | template <typename T> | 
 | struct UnderlyingType<CheckedNumeric<T>> { | 
 |   using type = T; | 
 |   static const bool is_numeric = true; | 
 |   static const bool is_checked = true; | 
 |   static const bool is_clamped = false; | 
 |   static const bool is_strict = false; | 
 | }; | 
 |  | 
 | template <typename T> | 
 | struct UnderlyingType<ClampedNumeric<T>> { | 
 |   using type = T; | 
 |   static const bool is_numeric = true; | 
 |   static const bool is_checked = false; | 
 |   static const bool is_clamped = true; | 
 |   static const bool is_strict = false; | 
 | }; | 
 |  | 
 | template <typename T> | 
 | struct UnderlyingType<StrictNumeric<T>> { | 
 |   using type = T; | 
 |   static const bool is_numeric = true; | 
 |   static const bool is_checked = false; | 
 |   static const bool is_clamped = false; | 
 |   static const bool is_strict = true; | 
 | }; | 
 |  | 
 | template <typename L, typename R> | 
 | struct IsCheckedOp { | 
 |   static const bool value = | 
 |       UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric && | 
 |       (UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked); | 
 | }; | 
 |  | 
 | template <typename L, typename R> | 
 | struct IsClampedOp { | 
 |   static const bool value = | 
 |       UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric && | 
 |       (UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped) && | 
 |       !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked); | 
 | }; | 
 |  | 
 | template <typename L, typename R> | 
 | struct IsStrictOp { | 
 |   static const bool value = | 
 |       UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric && | 
 |       (UnderlyingType<L>::is_strict || UnderlyingType<R>::is_strict) && | 
 |       !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked) && | 
 |       !(UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped); | 
 | }; | 
 |  | 
 | // as_signed<> returns the supplied integral value (or integral castable | 
 | // Numeric template) cast as a signed integral of equivalent precision. | 
 | // I.e. it's mostly an alias for: static_cast<std::make_signed<T>::type>(t) | 
 | template <typename Src> | 
 | constexpr typename std::make_signed< | 
 |     typename base::internal::UnderlyingType<Src>::type>::type | 
 | as_signed(const Src value) { | 
 |   static_assert(std::is_integral<decltype(as_signed(value))>::value, | 
 |                 "Argument must be a signed or unsigned integer type."); | 
 |   return static_cast<decltype(as_signed(value))>(value); | 
 | } | 
 |  | 
 | // as_unsigned<> returns the supplied integral value (or integral castable | 
 | // Numeric template) cast as an unsigned integral of equivalent precision. | 
 | // I.e. it's mostly an alias for: static_cast<std::make_unsigned<T>::type>(t) | 
 | template <typename Src> | 
 | constexpr typename std::make_unsigned< | 
 |     typename base::internal::UnderlyingType<Src>::type>::type | 
 | as_unsigned(const Src value) { | 
 |   static_assert(std::is_integral<decltype(as_unsigned(value))>::value, | 
 |                 "Argument must be a signed or unsigned integer type."); | 
 |   return static_cast<decltype(as_unsigned(value))>(value); | 
 | } | 
 |  | 
 | template <typename L, typename R> | 
 | constexpr bool IsLessImpl(const L lhs, | 
 |                           const R rhs, | 
 |                           const RangeCheck l_range, | 
 |                           const RangeCheck r_range) { | 
 |   return l_range.IsUnderflow() || r_range.IsOverflow() || | 
 |          (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) < | 
 |                                     static_cast<decltype(lhs + rhs)>(rhs)); | 
 | } | 
 |  | 
 | template <typename L, typename R> | 
 | struct IsLess { | 
 |   static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value, | 
 |                 "Types must be numeric."); | 
 |   static constexpr bool Test(const L lhs, const R rhs) { | 
 |     return IsLessImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs), | 
 |                       DstRangeRelationToSrcRange<L>(rhs)); | 
 |   } | 
 | }; | 
 |  | 
 | template <typename L, typename R> | 
 | constexpr bool IsLessOrEqualImpl(const L lhs, | 
 |                                  const R rhs, | 
 |                                  const RangeCheck l_range, | 
 |                                  const RangeCheck r_range) { | 
 |   return l_range.IsUnderflow() || r_range.IsOverflow() || | 
 |          (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) <= | 
 |                                     static_cast<decltype(lhs + rhs)>(rhs)); | 
 | } | 
 |  | 
 | template <typename L, typename R> | 
 | struct IsLessOrEqual { | 
 |   static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value, | 
 |                 "Types must be numeric."); | 
 |   static constexpr bool Test(const L lhs, const R rhs) { | 
 |     return IsLessOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs), | 
 |                              DstRangeRelationToSrcRange<L>(rhs)); | 
 |   } | 
 | }; | 
 |  | 
 | template <typename L, typename R> | 
 | constexpr bool IsGreaterImpl(const L lhs, | 
 |                              const R rhs, | 
 |                              const RangeCheck l_range, | 
 |                              const RangeCheck r_range) { | 
 |   return l_range.IsOverflow() || r_range.IsUnderflow() || | 
 |          (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) > | 
 |                                     static_cast<decltype(lhs + rhs)>(rhs)); | 
 | } | 
 |  | 
 | template <typename L, typename R> | 
 | struct IsGreater { | 
 |   static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value, | 
 |                 "Types must be numeric."); | 
 |   static constexpr bool Test(const L lhs, const R rhs) { | 
 |     return IsGreaterImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs), | 
 |                          DstRangeRelationToSrcRange<L>(rhs)); | 
 |   } | 
 | }; | 
 |  | 
 | template <typename L, typename R> | 
 | constexpr bool IsGreaterOrEqualImpl(const L lhs, | 
 |                                     const R rhs, | 
 |                                     const RangeCheck l_range, | 
 |                                     const RangeCheck r_range) { | 
 |   return l_range.IsOverflow() || r_range.IsUnderflow() || | 
 |          (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) >= | 
 |                                     static_cast<decltype(lhs + rhs)>(rhs)); | 
 | } | 
 |  | 
 | template <typename L, typename R> | 
 | struct IsGreaterOrEqual { | 
 |   static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value, | 
 |                 "Types must be numeric."); | 
 |   static constexpr bool Test(const L lhs, const R rhs) { | 
 |     return IsGreaterOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs), | 
 |                                 DstRangeRelationToSrcRange<L>(rhs)); | 
 |   } | 
 | }; | 
 |  | 
 | template <typename L, typename R> | 
 | struct IsEqual { | 
 |   static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value, | 
 |                 "Types must be numeric."); | 
 |   static constexpr bool Test(const L lhs, const R rhs) { | 
 |     return DstRangeRelationToSrcRange<R>(lhs) == | 
 |                DstRangeRelationToSrcRange<L>(rhs) && | 
 |            static_cast<decltype(lhs + rhs)>(lhs) == | 
 |                static_cast<decltype(lhs + rhs)>(rhs); | 
 |   } | 
 | }; | 
 |  | 
 | template <typename L, typename R> | 
 | struct IsNotEqual { | 
 |   static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value, | 
 |                 "Types must be numeric."); | 
 |   static constexpr bool Test(const L lhs, const R rhs) { | 
 |     return DstRangeRelationToSrcRange<R>(lhs) != | 
 |                DstRangeRelationToSrcRange<L>(rhs) || | 
 |            static_cast<decltype(lhs + rhs)>(lhs) != | 
 |                static_cast<decltype(lhs + rhs)>(rhs); | 
 |   } | 
 | }; | 
 |  | 
 | // These perform the actual math operations on the CheckedNumerics. | 
 | // Binary arithmetic operations. | 
 | template <template <typename, typename> class C, typename L, typename R> | 
 | constexpr bool SafeCompare(const L lhs, const R rhs) { | 
 |   static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value, | 
 |                 "Types must be numeric."); | 
 |   using Promotion = BigEnoughPromotion<L, R>; | 
 |   using BigType = typename Promotion::type; | 
 |   return Promotion::is_contained | 
 |              // Force to a larger type for speed if both are contained. | 
 |              ? C<BigType, BigType>::Test( | 
 |                    static_cast<BigType>(static_cast<L>(lhs)), | 
 |                    static_cast<BigType>(static_cast<R>(rhs))) | 
 |              // Let the template functions figure it out for mixed types. | 
 |              : C<L, R>::Test(lhs, rhs); | 
 | } | 
 |  | 
 | template <typename Dst, typename Src> | 
 | constexpr bool IsMaxInRangeForNumericType() { | 
 |   return IsGreaterOrEqual<Dst, Src>::Test(std::numeric_limits<Dst>::max(), | 
 |                                           std::numeric_limits<Src>::max()); | 
 | } | 
 |  | 
 | template <typename Dst, typename Src> | 
 | constexpr bool IsMinInRangeForNumericType() { | 
 |   return IsLessOrEqual<Dst, Src>::Test(std::numeric_limits<Dst>::lowest(), | 
 |                                        std::numeric_limits<Src>::lowest()); | 
 | } | 
 |  | 
 | template <typename Dst, typename Src> | 
 | constexpr Dst CommonMax() { | 
 |   return !IsMaxInRangeForNumericType<Dst, Src>() | 
 |              ? Dst(std::numeric_limits<Dst>::max()) | 
 |              : Dst(std::numeric_limits<Src>::max()); | 
 | } | 
 |  | 
 | template <typename Dst, typename Src> | 
 | constexpr Dst CommonMin() { | 
 |   return !IsMinInRangeForNumericType<Dst, Src>() | 
 |              ? Dst(std::numeric_limits<Dst>::lowest()) | 
 |              : Dst(std::numeric_limits<Src>::lowest()); | 
 | } | 
 |  | 
 | // This is a wrapper to generate return the max or min for a supplied type. | 
 | // If the argument is false, the returned value is the maximum. If true the | 
 | // returned value is the minimum. | 
 | template <typename Dst, typename Src = Dst> | 
 | constexpr Dst CommonMaxOrMin(bool is_min) { | 
 |   return is_min ? CommonMin<Dst, Src>() : CommonMax<Dst, Src>(); | 
 | } | 
 |  | 
 | }  // namespace internal | 
 | }  // namespace base | 
 |  | 
 | #endif  // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ |