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

Unified Diff: base/numerics/checked_math_impl.h

Issue 2945433003: Add ClampedNumeric templates (Closed)
Patch Set: more docs and modulus Created 3 years, 6 months 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
Index: base/numerics/checked_math_impl.h
diff --git a/base/numerics/checked_math_impl.h b/base/numerics/checked_math_impl.h
index 0492d1dbb5540e4f7a90a51bf4217a0a07388b27..203b286282b2c779cc13fa4292e529a8ae4e654e 100644
--- a/base/numerics/checked_math_impl.h
+++ b/base/numerics/checked_math_impl.h
@@ -182,17 +182,19 @@ struct CheckedMulOp<T,
return !__builtin_mul_overflow(x, y, result);
#endif
using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
+ // Verify the destination type can hold the result (always true for 0).
+ if (!(IsValueInRangeForNumericType<Promotion>(x) &&
+ IsValueInRangeForNumericType<Promotion>(y)) &&
+ x && y) {
+ return false;
jschuh 2017/06/26 20:26:50 The only functional change here is supporting the
+ }
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.
- bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
- IsValueInRangeForNumericType<Promotion>(y);
-
+ bool is_valid = true;
if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
} else {
- is_valid &= CheckedMulImpl(static_cast<Promotion>(x),
- static_cast<Promotion>(y), &presult);
+ is_valid = CheckedMulImpl(static_cast<Promotion>(x),
+ static_cast<Promotion>(y), &presult);
}
*result = static_cast<V>(presult);
return is_valid && IsValueInRangeForNumericType<V>(presult);
@@ -242,7 +244,7 @@ struct CheckedDivOp<T,
template <typename T>
bool CheckedModImpl(T x, T y, T* result) {
static_assert(std::is_integral<T>::value, "Type must be integral");
- if (y > 0) {
+ if (y) {
*result = static_cast<T>(x % y);
return true;
}
@@ -272,9 +274,6 @@ struct CheckedModOp<T,
template <typename T, typename U, class Enable = void>
struct CheckedLshOp {};
-// 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>
struct CheckedLshOp<T,
U,
@@ -283,27 +282,22 @@ struct CheckedLshOp<T,
using result_type = T;
template <typename V>
static bool Do(T x, U shift, V* result) {
- using ShiftType = typename std::make_unsigned<T>::type;
- static const ShiftType kBitWidth = IntegerBitsPlusSign<T>::value;
- const ShiftType real_shift = static_cast<ShiftType>(shift);
- // Signed shift is not legal on negative values.
- if (!IsValueNegative(x) && real_shift < kBitWidth) {
+ if (!IsValueNegative(x) &&
+ as_unsigned(shift) < std::numeric_limits<T>::digits) {
// 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 CheckedMulOp<T, T>::Do(x, static_cast<T>(1) << shift, result);
- return !x; // Special case zero for a full width signed shift.
+ return CheckedMulOp<T, T>::Do(x, T(1) << shift, result);
}
- return false;
+ // The standard defines only the result of the shift, rather than the
+ // values of source operands. So, shifting zero by any amount is legal.
+ // Otherwise, we overflowed or have an undefined operation.
+ return !x ? (*result = V(0)), true : false;
jschuh 2017/06/26 20:26:50 Stumbled on a spec error in how I was handling zer
dcheng 2017/06/28 07:25:06 Acknowledged--though for future CLs, it would be n
jschuh 2017/06/28 12:32:37 Weird. I'm looking at it now and you're right. May
}
};
template <typename T, typename U, class Enable = void>
struct CheckedRshOp {};
-// 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>
struct CheckedRshOp<T,
U,
@@ -314,7 +308,7 @@ struct CheckedRshOp<T,
static bool Do(T x, U shift, V* result) {
// Use the type conversion push negative values out of range.
using ShiftType = typename std::make_unsigned<T>::type;
- if (static_cast<ShiftType>(shift) < IntegerBitsPlusSign<T>::value) {
+ if (!x || static_cast<ShiftType>(shift) < IntegerBitsPlusSign<T>::value) {
jschuh 2017/06/26 20:26:50 Stumbled on a spec error in how I was handling zer
dcheng 2017/06/28 07:25:06 Ditto.
jschuh 2017/06/28 12:32:37 Yup.
T tmp = x >> shift;
*result = static_cast<V>(tmp);
return IsValueInRangeForNumericType<V>(tmp);

Powered by Google App Engine
This is Rietveld 408576698