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

Unified Diff: base/numerics/safe_math_impl.h

Issue 2566733002: Performance optimizations for base/numerics absolute value and multiply (Closed)
Patch Set: one more nit Created 4 years 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 | « base/numerics/safe_conversions_impl.h ('k') | base/numerics/safe_numerics_unittest.cc » ('j') | 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 ae0a5b1d4f031d8228ee47172daf27153dd6ce77..65589baadb26a4e0d8382cc2cf59af10063a9e3a 100644
--- a/base/numerics/safe_math_impl.h
+++ b/base/numerics/safe_math_impl.h
@@ -42,21 +42,6 @@ struct UnsignedOrFloatForSize<Numeric, false, true> {
using type = Numeric;
};
-// Helper templates for integer manipulations.
-
-template <typename T>
-constexpr bool HasSignBit(T x) {
- // Cast to unsigned since right shift on signed is undefined.
- return !!(static_cast<typename std::make_unsigned<T>::type>(x) >>
- PositionOfSignBit<T>::value);
-}
-
-// This wrapper undoes the standard integer promotions.
-template <typename T>
-constexpr T BinaryComplement(T x) {
- return static_cast<T>(~x);
-}
-
// Probe for builtin math overflow support on Clang and version check on GCC.
#if defined(__has_builtin)
#define USE_OVERFLOW_BUILTINS (__has_builtin(__builtin_add_overflow))
@@ -192,27 +177,21 @@ template <typename T,
((IntegerBitsPlusSign<T>::value * 2) >
IntegerBitsPlusSign<intmax_t>::value)>::type* = nullptr>
bool CheckedMulImpl(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>::lowest() / x)
- return false;
- }
- } else {
- if (y > 0) {
- if (x < std::numeric_limits<T>::lowest() / y)
- return false;
- } else {
- if (y < std::numeric_limits<T>::max() / x)
- return false;
- }
- }
- }
- *result = x * y;
- return true;
+ // Since the value of x*y is potentially undefined if we have a signed type,
+ // we compute it using the unsigned type of the same size.
+ using UnsignedDst = typename std::make_unsigned<T>::type;
+ const T is_negative = HasSignBit(x) ^ HasSignBit(y);
+ const UnsignedDst ux = SafeUnsignedAbs(x);
+ const UnsignedDst uy = SafeUnsignedAbs(y);
+ UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy);
+ // This is a non-branching conditional negation.
+ *result = static_cast<T>((uresult ^ -is_negative) + is_negative);
scottmg 2016/12/10 01:01:31 I would have moved that before this line instead,
+ // This uses the unsigned overflow check on the absolute value, with a +1
+ // bound for a negative result.
+ return (uy == 0 ||
+ ux <= (static_cast<UnsignedDst>(std::numeric_limits<T>::max()) +
+ is_negative) /
+ uy);
}
template <typename T,
@@ -529,11 +508,8 @@ template <typename T,
typename std::enable_if<std::is_integral<T>::value &&
std::is_signed<T>::value>::type* = nullptr>
bool CheckedAbs(T value, T* result) {
- if (value != std::numeric_limits<T>::lowest()) {
- *result = std::abs(value);
- return true;
- }
- return false;
+ *result = static_cast<T>(SafeUnsignedAbs(value));
+ return *result != std::numeric_limits<T>::lowest();
}
template <typename T,
@@ -545,24 +521,6 @@ bool CheckedAbs(T value, T* result) {
return true;
}
-template <typename T,
- typename std::enable_if<std::is_integral<T>::value &&
- std::is_signed<T>::value>::type* = nullptr>
-constexpr typename std::make_unsigned<T>::type SafeUnsignedAbs(T value) {
- using UnsignedT = typename std::make_unsigned<T>::type;
- return value == std::numeric_limits<T>::lowest()
- ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1
- : static_cast<UnsignedT>(std::abs(value));
-}
-
-template <typename T,
- typename std::enable_if<std::is_integral<T>::value &&
- !std::is_signed<T>::value>::type* = nullptr>
-constexpr T SafeUnsignedAbs(T value) {
- // T is unsigned, so |value| must already be positive.
- return static_cast<T>(value);
-}
-
// This is just boilerplate that wraps the standard floating point arithmetic.
// A macro isn't the nicest solution, but it beats rewriting these repeatedly.
#define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \
« no previous file with comments | « base/numerics/safe_conversions_impl.h ('k') | base/numerics/safe_numerics_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698