| Index: base/numerics/safe_math_impl.h
|
| diff --git a/base/numerics/safe_math_impl.h b/base/numerics/safe_math_impl.h
|
| index 1886d6080c92189c4963a6f2d14cf56c34c8214b..7b9e53ab94c012263e4af764a5d1c453b03b9e99 100644
|
| --- a/base/numerics/safe_math_impl.h
|
| +++ b/base/numerics/safe_math_impl.h
|
| @@ -127,13 +127,35 @@ constexpr T BinaryComplement(T x) {
|
| return static_cast<T>(~x);
|
| }
|
|
|
| +// For integers less than 128-bit and floats 32-bit or larger, we have the type
|
| +// with the larger maximum exponent take precedence.
|
| +enum ArithmeticPromotionCategory { LEFT_PROMOTION, RIGHT_PROMOTION };
|
| +
|
| +template <typename Lhs,
|
| + typename Rhs = Lhs,
|
| + ArithmeticPromotionCategory Promotion =
|
| + (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
|
| + ? LEFT_PROMOTION
|
| + : RIGHT_PROMOTION>
|
| +struct ArithmeticPromotion;
|
| +
|
| +template <typename Lhs, typename Rhs>
|
| +struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> {
|
| + typedef Lhs type;
|
| +};
|
| +
|
| +template <typename Lhs, typename Rhs>
|
| +struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
|
| + typedef Rhs type;
|
| +};
|
| +
|
| // Here are the actual portable checked integer math implementations.
|
| // TODO(jschuh): Break this code out from the enable_if pattern and find a clean
|
| // way to coalesce things into the CheckedNumericState specializations below.
|
|
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type
|
| -CheckedAdd(T x, T y, T* result) {
|
| +CheckedAddImpl(T x, T y, T* result) {
|
| // Since the value of x+y is undefined if we have a signed type, we compute
|
| // it using the unsigned type of the same size.
|
| typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
|
| @@ -150,9 +172,30 @@ CheckedAdd(T x, T y, T* result) {
|
| y); // Unsigned is either valid or underflow.
|
| }
|
|
|
| +template <typename T, typename U, typename V>
|
| +typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| + std::numeric_limits<U>::is_integer &&
|
| + std::numeric_limits<V>::is_integer,
|
| + bool>::type
|
| +CheckedAdd(T x, U y, V* result) {
|
| + using Promotion = typename ArithmeticPromotion<T, U>::type;
|
| + // Fail if either operand is out of range for the promoted type.
|
| + // TODO(jschuh): This could be made to work for a broader range of values.
|
| + if (!IsValueInRangeForNumericType<Promotion>(x) ||
|
| + !IsValueInRangeForNumericType<Promotion>(y)) {
|
| + return false;
|
| + }
|
| +
|
| + Promotion presult;
|
| + bool is_valid = CheckedAddImpl(static_cast<Promotion>(x),
|
| + static_cast<Promotion>(y), &presult);
|
| + *result = static_cast<V>(presult);
|
| + return is_valid && IsValueInRangeForNumericType<V>(presult);
|
| +}
|
| +
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type
|
| -CheckedSub(T x, T y, T* result) {
|
| +CheckedSubImpl(T x, T y, T* result) {
|
| // Since the value of x+y is undefined if we have a signed type, we compute
|
| // it using the unsigned type of the same size.
|
| typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
|
| @@ -168,6 +211,27 @@ CheckedSub(T x, T y, T* result) {
|
| : (x >= y);
|
| }
|
|
|
| +template <typename T, typename U, typename V>
|
| +typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| + std::numeric_limits<U>::is_integer &&
|
| + std::numeric_limits<V>::is_integer,
|
| + bool>::type
|
| +CheckedSub(T x, U y, V* result) {
|
| + using Promotion = typename ArithmeticPromotion<T, U>::type;
|
| + // Fail if either operand is out of range for the promoted type.
|
| + // TODO(jschuh): This could be made to work for a broader range of values.
|
| + if (!IsValueInRangeForNumericType<Promotion>(x) ||
|
| + !IsValueInRangeForNumericType<Promotion>(y)) {
|
| + return false;
|
| + }
|
| +
|
| + Promotion presult;
|
| + bool is_valid = CheckedSubImpl(static_cast<Promotion>(x),
|
| + static_cast<Promotion>(y), &presult);
|
| + *result = static_cast<V>(presult);
|
| + return is_valid && IsValueInRangeForNumericType<V>(presult);
|
| +}
|
| +
|
| // Integer multiplication is a bit complicated. In the fast case we just
|
| // we just promote to a twice wider type, and range check the result. In the
|
| // slow case we need to manually check that the result won't be truncated by
|
| @@ -176,7 +240,7 @@ template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| sizeof(T) * 2 <= sizeof(uintmax_t),
|
| bool>::type
|
| -CheckedMul(T x, T y, T* result) {
|
| +CheckedMulImpl(T x, T y, T* result) {
|
| typedef typename TwiceWiderInteger<T>::type IntermediateType;
|
| IntermediateType tmp =
|
| static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y);
|
| @@ -189,7 +253,7 @@ typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| std::numeric_limits<T>::is_signed &&
|
| (sizeof(T) * 2 > sizeof(uintmax_t)),
|
| bool>::type
|
| -CheckedMul(T x, T y, T* result) {
|
| +CheckedMulImpl(T x, T y, T* result) {
|
| if (x && y) {
|
| if (x > 0) {
|
| if (y > 0) {
|
| @@ -218,16 +282,37 @@ typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| !std::numeric_limits<T>::is_signed &&
|
| (sizeof(T) * 2 > sizeof(uintmax_t)),
|
| bool>::type
|
| -CheckedMul(T x, T y, T* result) {
|
| +CheckedMulImpl(T x, T y, T* result) {
|
| *result = x * y;
|
| return (y == 0 || x <= std::numeric_limits<T>::max() / y);
|
| }
|
|
|
| +template <typename T, typename U, typename V>
|
| +typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| + std::numeric_limits<U>::is_integer &&
|
| + std::numeric_limits<V>::is_integer,
|
| + bool>::type
|
| +CheckedMul(T x, U y, V* result) {
|
| + using Promotion = typename ArithmeticPromotion<T, U>::type;
|
| + // Fail if either operand is out of range for the promoted type.
|
| + // TODO(jschuh): This could be made to work for a broader range of values.
|
| + if (!IsValueInRangeForNumericType<Promotion>(x) ||
|
| + !IsValueInRangeForNumericType<Promotion>(y)) {
|
| + return false;
|
| + }
|
| +
|
| + Promotion presult;
|
| + bool is_valid = CheckedMulImpl(static_cast<Promotion>(x),
|
| + static_cast<Promotion>(y), &presult);
|
| + *result = static_cast<V>(presult);
|
| + return is_valid && IsValueInRangeForNumericType<V>(presult);
|
| +}
|
| +
|
| // Division just requires a check for a zero denominator or an invalid negation
|
| // on signed min/-1.
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type
|
| -CheckedDiv(T x, T y, T* result) {
|
| +CheckedDivImpl(T x, T y, T* result) {
|
| if (y && (!std::numeric_limits<T>::is_signed ||
|
| x != std::numeric_limits<T>::min() || y != static_cast<T>(-1))) {
|
| *result = x / y;
|
| @@ -236,11 +321,32 @@ CheckedDiv(T x, T y, T* result) {
|
| return false;
|
| }
|
|
|
| +template <typename T, typename U, typename V>
|
| +typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| + std::numeric_limits<U>::is_integer &&
|
| + std::numeric_limits<V>::is_integer,
|
| + bool>::type
|
| +CheckedDiv(T x, U y, V* result) {
|
| + using Promotion = typename ArithmeticPromotion<T, U>::type;
|
| + // Fail if either operand is out of range for the promoted type.
|
| + // TODO(jschuh): This could be made to work for a broader range of values.
|
| + if (!IsValueInRangeForNumericType<Promotion>(x) ||
|
| + !IsValueInRangeForNumericType<Promotion>(y)) {
|
| + return false;
|
| + }
|
| +
|
| + Promotion presult;
|
| + bool is_valid = CheckedDivImpl(static_cast<Promotion>(x),
|
| + static_cast<Promotion>(y), &presult);
|
| + *result = static_cast<V>(presult);
|
| + return is_valid && IsValueInRangeForNumericType<V>(presult);
|
| +}
|
| +
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| std::numeric_limits<T>::is_signed,
|
| bool>::type
|
| -CheckedMod(T x, T y, T* result) {
|
| +CheckedModImpl(T x, T y, T* result) {
|
| if (y > 0) {
|
| *result = static_cast<T>(x % y);
|
| return true;
|
| @@ -252,7 +358,7 @@ template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| !std::numeric_limits<T>::is_signed,
|
| bool>::type
|
| -CheckedMod(T x, T y, T* result) {
|
| +CheckedModImpl(T x, T y, T* result) {
|
| if (y != 0) {
|
| *result = static_cast<T>(x % y);
|
| return true;
|
| @@ -260,6 +366,20 @@ CheckedMod(T x, T y, T* result) {
|
| return false;
|
| }
|
|
|
| +template <typename T, typename U, typename V>
|
| +typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| + std::numeric_limits<U>::is_integer &&
|
| + std::numeric_limits<V>::is_integer,
|
| + bool>::type
|
| +CheckedMod(T x, U y, V* result) {
|
| + using Promotion = typename ArithmeticPromotion<T, U>::type;
|
| + Promotion presult;
|
| + bool is_valid = CheckedModImpl(static_cast<Promotion>(x),
|
| + static_cast<Promotion>(y), &presult);
|
| + *result = static_cast<V>(presult);
|
| + return is_valid && IsValueInRangeForNumericType<V>(presult);
|
| +}
|
| +
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| std::numeric_limits<T>::is_signed,
|
| @@ -344,12 +464,14 @@ typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
|
| }
|
|
|
| // These are the floating point stubs that the compiler needs to see.
|
| -#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \
|
| - template <typename T> \
|
| - typename std::enable_if<std::numeric_limits<T>::is_iec559, bool>::type \
|
| - Checked##NAME(T, T, T*) { \
|
| - NOTREACHED(); \
|
| - return static_cast<T>(false); \
|
| +#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \
|
| + template <typename T, typename U, typename V> \
|
| + typename std::enable_if<std::numeric_limits<T>::is_iec559 || \
|
| + std::numeric_limits<U>::is_iec559 || \
|
| + std::numeric_limits<V>::is_iec559, \
|
| + bool>::type Checked##NAME(T, U, V*) { \
|
| + NOTREACHED(); \
|
| + return static_cast<T>(false); \
|
| }
|
|
|
| BASE_FLOAT_ARITHMETIC_STUBS(Add)
|
| @@ -474,43 +596,6 @@ class CheckedNumericState<T, NUMERIC_FLOATING> {
|
| T value() const { return value_; }
|
| };
|
|
|
| -// For integers less than 128-bit and floats 32-bit or larger, we have the type
|
| -// with the larger maximum exponent take precedence.
|
| -enum ArithmeticPromotionCategory { LEFT_PROMOTION, RIGHT_PROMOTION };
|
| -
|
| -template <typename Lhs,
|
| - typename Rhs = Lhs,
|
| - ArithmeticPromotionCategory Promotion =
|
| - (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
|
| - ? LEFT_PROMOTION
|
| - : RIGHT_PROMOTION>
|
| -struct ArithmeticPromotion;
|
| -
|
| -template <typename Lhs, typename Rhs>
|
| -struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> {
|
| - typedef Lhs type;
|
| -};
|
| -
|
| -template <typename Lhs, typename Rhs>
|
| -struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
|
| - typedef Rhs type;
|
| -};
|
| -
|
| -// 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>
|
| -struct IsIntegerArithmeticSafe {
|
| - static const bool value = !std::numeric_limits<T>::is_iec559 &&
|
| - StaticDstRangeRelationToSrcRange<T, Lhs>::value ==
|
| - NUMERIC_RANGE_CONTAINED &&
|
| - sizeof(T) >= (2 * sizeof(Lhs)) &&
|
| - StaticDstRangeRelationToSrcRange<T, Rhs>::value !=
|
| - NUMERIC_RANGE_CONTAINED &&
|
| - sizeof(T) >= (2 * sizeof(Rhs));
|
| -};
|
| -
|
| } // namespace internal
|
| } // namespace base
|
|
|
|
|