Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3070)

Unified Diff: base/numerics/safe_math_impl.h

Issue 2510793004: Performance optimizations for Checked(Add|Sub|Mul|Div) (Closed)
Patch Set: nit Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/numerics/safe_math_impl.h
diff --git a/base/numerics/safe_math_impl.h b/base/numerics/safe_math_impl.h
index c8e4e20c2a84ee00b9f9fe996c7a1dc34ebcb823..ed87c44f999a5f1f224c010a3385e506be1e2431 100644
--- a/base/numerics/safe_math_impl.h
+++ b/base/numerics/safe_math_impl.h
@@ -226,6 +226,21 @@ struct ArithmeticPromotion<BIG_ENOUGH_PROMOTION, Lhs, Rhs> {
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 @@ typename std::enable_if<std::numeric_limits<T>::is_integer &&
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);
+
+ if (IsIntegerArithmeticSafe<Promotion, U, V>::value) {
+ presult = static_cast<Promotion>(x) + static_cast<Promotion>(y);
+ } else {
+ is_valid &= CheckedAddImpl(static_cast<Promotion>(x),
Tom Sepez 2016/11/16 21:16:08 Do we maybe perform an operation here that we woul
jschuh 2016/11/16 21:22:28 The Impl functions should all be safe from undefin
+ static_cast<Promotion>(y), &presult);
}
-
- 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);
}
@@ -297,16 +314,18 @@ typename std::enable_if<std::numeric_limits<T>::is_integer &&
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);
+
+ 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);
}
-
- 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);
}
@@ -374,16 +393,18 @@ typename std::enable_if<std::numeric_limits<T>::is_integer &&
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);
+
+ 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);
}
-
- 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);
}
@@ -409,16 +430,13 @@ typename std::enable_if<std::numeric_limits<T>::is_integer &&
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);
}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698