Chromium Code Reviews| Index: base/numerics/safe_math_impl.h |
| diff --git a/base/numerics/safe_math_impl.h b/base/numerics/safe_math_impl.h |
| index 7b9e53ab94c012263e4af764a5d1c453b03b9e99..c8e4e20c2a84ee00b9f9fe996c7a1dc34ebcb823 100644 |
| --- a/base/numerics/safe_math_impl.h |
| +++ b/base/numerics/safe_math_impl.h |
| @@ -127,26 +127,103 @@ 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 }; |
| +enum ArithmeticPromotionCategory { |
| + LEFT_PROMOTION, // Use the type of the left-hand argument. |
|
Tom Sepez
2016/11/15 22:32:13
Do we ever do left/right promotion? Or is this fo
jschuh
2016/11/15 22:38:49
Just for the forthcoming shift.
|
| + RIGHT_PROMOTION, // Use the type of the right-hand argument. |
| + MAX_EXPONENT_PROMOTION, // Use the type supporting the largest exponent. |
| + BIG_ENOUGH_PROMOTION // Attempt to find a big enough type. |
| +}; |
| + |
| +template <ArithmeticPromotionCategory Promotion, |
| + typename Lhs, |
| + typename Rhs = Lhs> |
| +struct ArithmeticPromotion; |
| template <typename Lhs, |
| - typename Rhs = Lhs, |
| + typename Rhs, |
| ArithmeticPromotionCategory Promotion = |
| (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) |
| ? LEFT_PROMOTION |
| : RIGHT_PROMOTION> |
| -struct ArithmeticPromotion; |
| +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; |
| +}; |
| + |
| +template <typename Lhs, |
| + typename Rhs = Lhs, |
| + bool is_intmax_type = |
| + std::is_integral< |
| + typename MaxExponentPromotion<Lhs, Rhs>::type>::value && |
| + sizeof(typename MaxExponentPromotion<Lhs, Rhs>::type) == |
| + sizeof(intmax_t), |
| + 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 IntegerForSizeAndSign< |
| + sizeof(typename MaxExponentPromotion<Lhs, Rhs>::type) * 2, |
| + 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; |
| +}; |
| + |
| +// These are the four supported promotion types. |
| + |
| +// Use the type of the left-hand argument. |
| +template <typename Lhs, typename Rhs> |
| +struct ArithmeticPromotion<LEFT_PROMOTION, Lhs, Rhs> { |
| + using type = Lhs; |
| + static const bool is_contained = true; |
| +}; |
| + |
| +// Use the type of the right-hand argument. |
| +template <typename Lhs, typename Rhs> |
| +struct ArithmeticPromotion<RIGHT_PROMOTION, Lhs, Rhs> { |
| + using type = Rhs; |
| + static const bool is_contained = true; |
| +}; |
| +// Use the type supporting the largest exponent. |
| template <typename Lhs, typename Rhs> |
| -struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> { |
| - typedef Lhs type; |
| +struct ArithmeticPromotion<MAX_EXPONENT_PROMOTION, Lhs, Rhs> { |
| + using type = typename MaxExponentPromotion<Lhs, Rhs>::type; |
| + static const bool is_contained = true; |
| }; |
| +// Attempt to find a big enough type. |
| template <typename Lhs, typename Rhs> |
| -struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> { |
| - typedef Rhs type; |
| +struct ArithmeticPromotion<BIG_ENOUGH_PROMOTION, Lhs, Rhs> { |
| + using type = typename BigEnoughPromotion<Lhs, Rhs>::type; |
| + static const bool is_contained = BigEnoughPromotion<Lhs, Rhs>::is_contained; |
| }; |
| // Here are the actual portable checked integer math implementations. |
| @@ -178,7 +255,8 @@ typename std::enable_if<std::numeric_limits<T>::is_integer && |
| std::numeric_limits<V>::is_integer, |
| bool>::type |
| CheckedAdd(T x, U y, V* result) { |
| - using Promotion = typename ArithmeticPromotion<T, U>::type; |
| + using Promotion = |
| + typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, 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) || |
| @@ -217,7 +295,8 @@ typename std::enable_if<std::numeric_limits<T>::is_integer && |
| std::numeric_limits<V>::is_integer, |
| bool>::type |
| CheckedSub(T x, U y, V* result) { |
| - using Promotion = typename ArithmeticPromotion<T, U>::type; |
| + using Promotion = |
| + typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, 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) || |
| @@ -293,7 +372,8 @@ typename std::enable_if<std::numeric_limits<T>::is_integer && |
| std::numeric_limits<V>::is_integer, |
| bool>::type |
| CheckedMul(T x, U y, V* result) { |
| - using Promotion = typename ArithmeticPromotion<T, U>::type; |
| + using Promotion = |
| + typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, 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) || |
| @@ -327,7 +407,8 @@ typename std::enable_if<std::numeric_limits<T>::is_integer && |
| std::numeric_limits<V>::is_integer, |
| bool>::type |
| CheckedDiv(T x, U y, V* result) { |
| - using Promotion = typename ArithmeticPromotion<T, U>::type; |
| + using Promotion = |
| + typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, 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) || |
| @@ -372,7 +453,8 @@ typename std::enable_if<std::numeric_limits<T>::is_integer && |
| std::numeric_limits<V>::is_integer, |
| bool>::type |
| CheckedMod(T x, U y, V* result) { |
| - using Promotion = typename ArithmeticPromotion<T, U>::type; |
| + using Promotion = |
| + typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; |
| Promotion presult; |
| bool is_valid = CheckedModImpl(static_cast<Promotion>(x), |
| static_cast<Promotion>(y), &presult); |