| Index: base/numerics/safe_math_impl.h
|
| diff --git a/base/numerics/safe_math_impl.h b/base/numerics/safe_math_impl.h
|
| index ca3bd5f6ab403f7b7b7e7918f65d0f3a2b46aa1f..1886d6080c92189c4963a6f2d14cf56c34c8214b 100644
|
| --- a/base/numerics/safe_math_impl.h
|
| +++ b/base/numerics/safe_math_impl.h
|
| @@ -95,7 +95,7 @@ struct PositionOfSignBit {
|
|
|
| // This is used for UnsignedAbs, where we need to support floating-point
|
| // template instantiations even though we don't actually support the operations.
|
| -// However, there is no corresponding implementation of e.g. CheckedUnsignedAbs,
|
| +// However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
|
| // so the float versions will not compile.
|
| template <typename Numeric,
|
| bool IsInteger = std::numeric_limits<Numeric>::is_integer,
|
| @@ -132,43 +132,40 @@ constexpr T BinaryComplement(T x) {
|
| // way to coalesce things into the CheckedNumericState specializations below.
|
|
|
| template <typename T>
|
| -typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
|
| -CheckedAdd(T x, T y, bool* validity) {
|
| +typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type
|
| +CheckedAdd(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;
|
| UnsignedDst ux = static_cast<UnsignedDst>(x);
|
| UnsignedDst uy = static_cast<UnsignedDst>(y);
|
| UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy);
|
| + *result = static_cast<T>(uresult);
|
| // Addition is valid if the sign of (x + y) is equal to either that of x or
|
| // that of y.
|
| - if (std::numeric_limits<T>::is_signed) {
|
| - *validity = HasSignBit(BinaryComplement(
|
| - static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy))));
|
| - } else { // Unsigned is either valid or overflow.
|
| - *validity = BinaryComplement(x) >= y;
|
| - }
|
| - return static_cast<T>(uresult);
|
| + return (std::numeric_limits<T>::is_signed)
|
| + ? HasSignBit(BinaryComplement(
|
| + static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy))))
|
| + : (BinaryComplement(x) >=
|
| + y); // Unsigned is either valid or underflow.
|
| }
|
|
|
| template <typename T>
|
| -typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
|
| -CheckedSub(T x, T y, bool* validity) {
|
| +typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type
|
| +CheckedSub(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;
|
| UnsignedDst ux = static_cast<UnsignedDst>(x);
|
| UnsignedDst uy = static_cast<UnsignedDst>(y);
|
| UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy);
|
| + *result = static_cast<T>(uresult);
|
| // Subtraction is valid if either x and y have same sign, or (x-y) and x have
|
| // the same sign.
|
| - if (std::numeric_limits<T>::is_signed) {
|
| - *validity = HasSignBit(
|
| - BinaryComplement(static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy))));
|
| - } else { // Unsigned is either valid or underflow.
|
| - *validity = x >= y;
|
| - }
|
| - return static_cast<T>(uresult);
|
| + return (std::numeric_limits<T>::is_signed)
|
| + ? HasSignBit(BinaryComplement(
|
| + static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy))))
|
| + : (x >= y);
|
| }
|
|
|
| // Integer multiplication is a bit complicated. In the fast case we just
|
| @@ -178,135 +175,143 @@ CheckedSub(T x, T y, bool* validity) {
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| sizeof(T) * 2 <= sizeof(uintmax_t),
|
| - T>::type
|
| -CheckedMul(T x, T y, bool* validity) {
|
| + bool>::type
|
| +CheckedMul(T x, T y, T* result) {
|
| typedef typename TwiceWiderInteger<T>::type IntermediateType;
|
| IntermediateType tmp =
|
| static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y);
|
| - *validity = DstRangeRelationToSrcRange<T>(tmp) == RANGE_VALID;
|
| - return static_cast<T>(tmp);
|
| + *result = static_cast<T>(tmp);
|
| + return DstRangeRelationToSrcRange<T>(tmp) == RANGE_VALID;
|
| }
|
|
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| std::numeric_limits<T>::is_signed &&
|
| (sizeof(T) * 2 > sizeof(uintmax_t)),
|
| - T>::type
|
| -CheckedMul(T x, T y, bool* validity) {
|
| - // If either side is zero then the result will be zero.
|
| - if (!x || !y) {
|
| - *validity = true;
|
| - return static_cast<T>(0);
|
| - }
|
| - if (x > 0) {
|
| - if (y > 0) {
|
| - *validity = x <= std::numeric_limits<T>::max() / y;
|
| + bool>::type
|
| +CheckedMul(T x, T y, T* result) {
|
| + if (x && y) {
|
| + if (x > 0) {
|
| + if (y > 0) {
|
| + if (x > std::numeric_limits<T>::max() / y)
|
| + return false;
|
| + } else {
|
| + if (y < std::numeric_limits<T>::min() / x)
|
| + return false;
|
| + }
|
| } else {
|
| - *validity = y >= std::numeric_limits<T>::min() / x;
|
| - }
|
| - } else {
|
| - if (y > 0) {
|
| - *validity = x >= std::numeric_limits<T>::min() / y;
|
| - } else {
|
| - *validity = y >= std::numeric_limits<T>::max() / x;
|
| + if (y > 0) {
|
| + if (x < std::numeric_limits<T>::min() / y)
|
| + return false;
|
| + } else {
|
| + if (y < std::numeric_limits<T>::max() / x)
|
| + return false;
|
| + }
|
| }
|
| }
|
| - return static_cast<T>(*validity ? x * y : 0);
|
| + *result = x * y;
|
| + return true;
|
| }
|
|
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| !std::numeric_limits<T>::is_signed &&
|
| (sizeof(T) * 2 > sizeof(uintmax_t)),
|
| - T>::type
|
| -CheckedMul(T x, T y, bool* validity) {
|
| - *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y);
|
| - return static_cast<T>(*validity ? x * y : 0);
|
| + bool>::type
|
| +CheckedMul(T x, T y, T* result) {
|
| + *result = x * y;
|
| + return (y == 0 || x <= std::numeric_limits<T>::max() / y);
|
| }
|
|
|
| // Division just requires a check for a zero denominator or an invalid negation
|
| // on signed min/-1.
|
| template <typename T>
|
| -T CheckedDiv(T x,
|
| - T y,
|
| - bool* validity,
|
| - typename std::enable_if<std::numeric_limits<T>::is_integer,
|
| - int>::type = 0) {
|
| - if ((y == 0) ||
|
| - (std::numeric_limits<T>::is_signed &&
|
| - x == std::numeric_limits<T>::min() && y == static_cast<T>(-1))) {
|
| - *validity = false;
|
| - return static_cast<T>(0);
|
| +typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type
|
| +CheckedDiv(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;
|
| + return true;
|
| }
|
| -
|
| - *validity = true;
|
| - return static_cast<T>(x / y);
|
| + return false;
|
| }
|
|
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| std::numeric_limits<T>::is_signed,
|
| - T>::type
|
| -CheckedMod(T x, T y, bool* validity) {
|
| - *validity = y > 0;
|
| - return static_cast<T>(*validity ? x % y : 0);
|
| + bool>::type
|
| +CheckedMod(T x, T y, T* result) {
|
| + if (y > 0) {
|
| + *result = static_cast<T>(x % y);
|
| + return true;
|
| + }
|
| + return false;
|
| }
|
|
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| !std::numeric_limits<T>::is_signed,
|
| - T>::type
|
| -CheckedMod(T x, T y, bool* validity) {
|
| - *validity = y != 0;
|
| - return static_cast<T>(*validity ? x % y : 0);
|
| + bool>::type
|
| +CheckedMod(T x, T y, T* result) {
|
| + if (y != 0) {
|
| + *result = static_cast<T>(x % y);
|
| + return true;
|
| + }
|
| + return false;
|
| }
|
|
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| std::numeric_limits<T>::is_signed,
|
| - T>::type
|
| -CheckedNeg(T value, bool* validity) {
|
| - *validity = value != std::numeric_limits<T>::min();
|
| + bool>::type
|
| +CheckedNeg(T value, T* result) {
|
| // The negation of signed min is min, so catch that one.
|
| - return static_cast<T>(*validity ? -value : 0);
|
| + if (value != std::numeric_limits<T>::min()) {
|
| + *result = static_cast<T>(-value);
|
| + return true;
|
| + }
|
| + return false;
|
| }
|
|
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| !std::numeric_limits<T>::is_signed,
|
| - T>::type
|
| -CheckedNeg(T value, bool* validity) {
|
| - // The only legal unsigned negation is zero.
|
| - *validity = !value;
|
| - return static_cast<T>(
|
| - *validity ? -static_cast<typename SignedIntegerForSize<T>::type>(value)
|
| - : 0);
|
| + bool>::type
|
| +CheckedNeg(T value, T* result) {
|
| + if (!value) { // The only legal unsigned negation is zero.
|
| + *result = static_cast<T>(0);
|
| + return true;
|
| + }
|
| + return false;
|
| }
|
|
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| std::numeric_limits<T>::is_signed,
|
| - T>::type
|
| -CheckedAbs(T value, bool* validity) {
|
| - *validity = value != std::numeric_limits<T>::min();
|
| - return static_cast<T>(*validity ? std::abs(value) : 0);
|
| + bool>::type
|
| +CheckedAbs(T value, T* result) {
|
| + if (value != std::numeric_limits<T>::min()) {
|
| + *result = std::abs(value);
|
| + return true;
|
| + }
|
| + return false;
|
| }
|
|
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| !std::numeric_limits<T>::is_signed,
|
| - T>::type
|
| -CheckedAbs(T value, bool* validity) {
|
| + bool>::type
|
| +CheckedAbs(T value, T* result) {
|
| // T is unsigned, so |value| must already be positive.
|
| - *validity = true;
|
| - return value;
|
| + *result = value;
|
| + return true;
|
| }
|
|
|
| template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| std::numeric_limits<T>::is_signed,
|
| typename UnsignedIntegerForSize<T>::type>::type
|
| -CheckedUnsignedAbs(T value) {
|
| +SafeUnsignedAbs(T value) {
|
| typedef typename UnsignedIntegerForSize<T>::type UnsignedT;
|
| return value == std::numeric_limits<T>::min()
|
| ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1
|
| @@ -317,19 +322,34 @@ template <typename T>
|
| typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
| !std::numeric_limits<T>::is_signed,
|
| T>::type
|
| -CheckedUnsignedAbs(T value) {
|
| +SafeUnsignedAbs(T value) {
|
| // T is unsigned, so |value| must already be positive.
|
| return static_cast<T>(value);
|
| }
|
|
|
| -// These are the floating point stubs that the compiler needs to see. Only the
|
| -// negation operation is ever called.
|
| -#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \
|
| - template <typename T> \
|
| - typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \
|
| - Checked##NAME(T, T, bool*) { \
|
| - NOTREACHED(); \
|
| - return static_cast<T>(0); \
|
| +template <typename T>
|
| +typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
|
| + T value,
|
| + bool*) {
|
| + NOTREACHED();
|
| + return static_cast<T>(-value);
|
| +}
|
| +
|
| +template <typename T>
|
| +typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
|
| + T value,
|
| + bool*) {
|
| + NOTREACHED();
|
| + return static_cast<T>(std::abs(value));
|
| +}
|
| +
|
| +// 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); \
|
| }
|
|
|
| BASE_FLOAT_ARITHMETIC_STUBS(Add)
|
| @@ -341,17 +361,17 @@ BASE_FLOAT_ARITHMETIC_STUBS(Mod)
|
| #undef BASE_FLOAT_ARITHMETIC_STUBS
|
|
|
| template <typename T>
|
| -typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
|
| - T value,
|
| - bool*) {
|
| - return static_cast<T>(-value);
|
| +typename std::enable_if<std::numeric_limits<T>::is_iec559, bool>::type
|
| +CheckedNeg(T value, T* result) {
|
| + *result = static_cast<T>(-value);
|
| + return true;
|
| }
|
|
|
| template <typename T>
|
| -typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
|
| - T value,
|
| - bool*) {
|
| - return static_cast<T>(std::abs(value));
|
| +typename std::enable_if<std::numeric_limits<T>::is_iec559, bool>::type
|
| +CheckedAbs(T value, T* result) {
|
| + *result = static_cast<T>(std::abs(value));
|
| + return true;
|
| }
|
|
|
| // Floats carry around their validity state with them, but integers do not. So,
|
|
|