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