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

Unified Diff: base/numerics/safe_math_impl.h

Issue 2510973002: Add support for CheckedNumeric bitshift operators (Closed)
Patch Set: format 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 | « base/numerics/safe_math.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 c8e4e20c2a84ee00b9f9fe996c7a1dc34ebcb823..2760ca563846b17165d93fbc64008d10935d133f 100644
--- a/base/numerics/safe_math_impl.h
+++ b/base/numerics/safe_math_impl.h
@@ -127,6 +127,21 @@ constexpr T BinaryComplement(T x) {
return static_cast<T>(~x);
}
+// Return if a numeric value is negative regardless of type.
+template <typename T,
+ typename std::enable_if<std::is_arithmetic<T>::value &&
+ std::is_signed<T>::value>::type* = nullptr>
+constexpr bool IsNegative(T x) {
+ return x < 0;
+}
+
+template <typename T,
+ typename std::enable_if<std::is_arithmetic<T>::value &&
+ !std::is_signed<T>::value>::type* = nullptr>
+constexpr bool IsNegative(T x) {
+ return false;
+}
+
enum ArithmeticPromotionCategory {
LEFT_PROMOTION, // Use the type of the left-hand argument.
RIGHT_PROMOTION, // Use the type of the right-hand argument.
@@ -462,6 +477,48 @@ CheckedMod(T x, U y, V* result) {
return is_valid && IsValueInRangeForNumericType<V>(presult);
}
+// Left shift. Shifts less than 0 or greater than or equal to the number
+// of bits in the promoted type are undefined. Shifts of negative values
+// are undefined. Otherwise it is defined when the result fits.
+template <typename T, typename U, typename V>
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ std::numeric_limits<U>::is_integer &&
+ std::numeric_limits<V>::is_integer,
+ bool>::type
+CheckedLeftShift(T x, U shift, V* result) {
+ using ShiftType = typename UnsignedIntegerForSize<T>::type;
+ static const ShiftType kBitWidth = CHAR_BIT * sizeof(T);
+ const ShiftType real_shift = static_cast<ShiftType>(shift);
+ // Signed shift is not legal on negative values.
+ if (!IsNegative(x) && real_shift < kBitWidth) {
+ // Just use a multiplication because it's easy.
+ // TODO(jschuh): This could probably be made more efficient.
+ if (!std::is_signed<T>::value || real_shift != kBitWidth - 1)
+ return CheckedMul(x, static_cast<T>(1) << shift, result);
+ return !x; // Special case zero for a full width signed shift.
+ }
+ return false;
+}
+
+// Right shift. Shifts less than 0 or greater than or equal to the number
+// of bits in the promoted type are undefined. Otherwise, it is always defined,
+// but a right shift of a negative value is implementation-dependent.
+template <typename T, typename U, typename V>
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ std::numeric_limits<U>::is_integer &&
+ std::numeric_limits<V>::is_integer,
+ bool>::type
+CheckedRightShift(T x, U shift, V* result) {
+ // Use the type conversion push negative values out of range.
+ using ShiftType = typename UnsignedIntegerForSize<T>::type;
+ if (static_cast<ShiftType>(shift) < (CHAR_BIT * sizeof(T))) {
+ T tmp = x >> shift;
+ *result = static_cast<V>(tmp);
+ return IsValueInRangeForNumericType<unsigned>(tmp);
+ }
+ return false;
+}
+
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<T>::is_signed,
« no previous file with comments | « base/numerics/safe_math.h ('k') | base/numerics/safe_numerics_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698