Performance optimizations for Checked(Add|Sub|Mul|Div)
This skips the more complicated math functions if we can can perform
the operations on a wider intermediate type.
R=tsepez@chromium.org
Review-Url: https://codereview.chromium.org/2510793004
Cr-Commit-Position: refs/heads/master@{#432768}
diff --git a/base/numerics/safe_math_impl.h b/base/numerics/safe_math_impl.h
index c8e4e20c..ed87c44 100644
--- a/base/numerics/safe_math_impl.h
+++ b/base/numerics/safe_math_impl.h
@@ -226,6 +226,21 @@
static const bool is_contained = BigEnoughPromotion<Lhs, Rhs>::is_contained;
};
+// 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));
+};
+
// 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.
@@ -257,16 +272,18 @@
CheckedAdd(T x, U y, V* result) {
using Promotion =
typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
+ Promotion presult;
// 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;
- }
+ bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
+ IsValueInRangeForNumericType<Promotion>(y);
- Promotion presult;
- bool is_valid = CheckedAddImpl(static_cast<Promotion>(x),
- static_cast<Promotion>(y), &presult);
+ if (IsIntegerArithmeticSafe<Promotion, U, V>::value) {
+ presult = static_cast<Promotion>(x) + static_cast<Promotion>(y);
+ } else {
+ is_valid &= CheckedAddImpl(static_cast<Promotion>(x),
+ static_cast<Promotion>(y), &presult);
+ }
*result = static_cast<V>(presult);
return is_valid && IsValueInRangeForNumericType<V>(presult);
}
@@ -297,16 +314,18 @@
CheckedSub(T x, U y, V* result) {
using Promotion =
typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
+ Promotion presult;
// 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;
- }
+ bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
+ IsValueInRangeForNumericType<Promotion>(y);
- Promotion presult;
- bool is_valid = CheckedSubImpl(static_cast<Promotion>(x),
- static_cast<Promotion>(y), &presult);
+ if (IsIntegerArithmeticSafe<Promotion, U, V>::value) {
+ presult = static_cast<Promotion>(x) - static_cast<Promotion>(y);
+ } else {
+ is_valid &= CheckedSubImpl(static_cast<Promotion>(x),
+ static_cast<Promotion>(y), &presult);
+ }
*result = static_cast<V>(presult);
return is_valid && IsValueInRangeForNumericType<V>(presult);
}
@@ -374,16 +393,18 @@
CheckedMul(T x, U y, V* result) {
using Promotion =
typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
+ Promotion presult;
// 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;
- }
+ bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
+ IsValueInRangeForNumericType<Promotion>(y);
- Promotion presult;
- bool is_valid = CheckedMulImpl(static_cast<Promotion>(x),
- static_cast<Promotion>(y), &presult);
+ if (IsIntegerArithmeticSafe<Promotion, U, V>::value) {
+ presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
+ } else {
+ is_valid &= CheckedMulImpl(static_cast<Promotion>(x),
+ static_cast<Promotion>(y), &presult);
+ }
*result = static_cast<V>(presult);
return is_valid && IsValueInRangeForNumericType<V>(presult);
}
@@ -409,16 +430,13 @@
CheckedDiv(T x, U y, V* result) {
using Promotion =
typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
+ Promotion presult;
// 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);
+ bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
+ IsValueInRangeForNumericType<Promotion>(y);
+ is_valid &= CheckedDivImpl(static_cast<Promotion>(x),
+ static_cast<Promotion>(y), &presult);
*result = static_cast<V>(presult);
return is_valid && IsValueInRangeForNumericType<V>(presult);
}