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

Unified Diff: base/numerics/safe_math_impl.h

Issue 2522073004: Add variadic helper functions for CheckedNumeric math operations (Closed)
Patch Set: compile fix 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 f514aecc42ed81db9c6b45ed39036281c03bc030..1102deca967150619c58e5b01a3f359184863e97 100644
--- a/base/numerics/safe_math_impl.h
+++ b/base/numerics/safe_math_impl.h
@@ -262,10 +262,10 @@ CheckedAddImpl(T x, T y, T* result) {
}
template <typename T, typename U, class Enable = void>
-struct CheckedAdd {};
+struct CheckedAddOp {};
template <typename T, typename U>
-struct CheckedAdd<
+struct CheckedAddOp<
T,
U,
typename std::enable_if<std::numeric_limits<T>::is_integer &&
@@ -273,7 +273,7 @@ struct CheckedAdd<
using result_type =
typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type;
template <typename V>
- static bool Op(T x, U y, V* result) {
+ static bool Do(T x, U y, V* result) {
#if USE_OVERFLOW_BUILTINS
return !__builtin_add_overflow(x, y, result);
#else
@@ -316,10 +316,10 @@ CheckedSubImpl(T x, T y, T* result) {
}
template <typename T, typename U, class Enable = void>
-struct CheckedSub {};
+struct CheckedSubOp {};
template <typename T, typename U>
-struct CheckedSub<
+struct CheckedSubOp<
T,
U,
typename std::enable_if<std::numeric_limits<T>::is_integer &&
@@ -327,7 +327,7 @@ struct CheckedSub<
using result_type =
typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type;
template <typename V>
- static bool Op(T x, U y, V* result) {
+ static bool Do(T x, U y, V* result) {
#if USE_OVERFLOW_BUILTINS
return !__builtin_sub_overflow(x, y, result);
#else
@@ -407,10 +407,10 @@ CheckedMulImpl(T x, T y, T* result) {
}
template <typename T, typename U, class Enable = void>
-struct CheckedMul {};
+struct CheckedMulOp {};
template <typename T, typename U>
-struct CheckedMul<
+struct CheckedMulOp<
T,
U,
typename std::enable_if<std::numeric_limits<T>::is_integer &&
@@ -418,7 +418,7 @@ struct CheckedMul<
using result_type =
typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type;
template <typename V>
- static bool Op(T x, U y, V* result) {
+ static bool Do(T x, U y, V* result) {
#if USE_OVERFLOW_BUILTINS
#if defined(__clang__)
// TODO(jschuh): Get the Clang runtime library issues sorted out so we can
@@ -470,10 +470,10 @@ CheckedDivImpl(T x, T y, T* result) {
}
template <typename T, typename U, class Enable = void>
-struct CheckedDiv {};
+struct CheckedDivOp {};
template <typename T, typename U>
-struct CheckedDiv<
+struct CheckedDivOp<
T,
U,
typename std::enable_if<std::numeric_limits<T>::is_integer &&
@@ -481,7 +481,7 @@ struct CheckedDiv<
using result_type =
typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type;
template <typename V>
- static bool Op(T x, U y, V* result) {
+ static bool Do(T x, U y, V* result) {
using Promotion =
typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
Promotion presult;
@@ -521,10 +521,10 @@ CheckedModImpl(T x, T y, T* result) {
}
template <typename T, typename U, class Enable = void>
-struct CheckedMod {};
+struct CheckedModOp {};
template <typename T, typename U>
-struct CheckedMod<
+struct CheckedModOp<
T,
U,
typename std::enable_if<std::numeric_limits<T>::is_integer &&
@@ -532,7 +532,7 @@ struct CheckedMod<
using result_type =
typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type;
template <typename V>
- static bool Op(T x, U y, V* result) {
+ static bool Do(T x, U y, V* result) {
using Promotion =
typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
Promotion presult;
@@ -544,20 +544,20 @@ struct CheckedMod<
};
template <typename T, typename U, class Enable = void>
-struct CheckedLeftShift {};
+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 CheckedLeftShift<
+struct CheckedLshOp<
T,
U,
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<U>::is_integer>::type> {
using result_type = T;
template <typename V>
- static bool Op(T x, U shift, V* result) {
+ static bool Do(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);
@@ -566,7 +566,7 @@ struct CheckedLeftShift<
// 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<T, T>::Op(x, static_cast<T>(1) << shift, result);
+ return CheckedMulOp<T, T>::Do(x, static_cast<T>(1) << shift, result);
return !x; // Special case zero for a full width signed shift.
}
return false;
@@ -574,20 +574,20 @@ struct CheckedLeftShift<
};
template <typename T, typename U, class Enable = void>
-struct CheckedRightShift {};
+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 CheckedRightShift<
+struct CheckedRshOp<
T,
U,
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<U>::is_integer>::type> {
using result_type = T;
template <typename V = result_type>
- static bool Op(T x, U shift, V* result) {
+ static bool Do(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))) {
@@ -669,21 +669,22 @@ SafeUnsignedAbs(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) \
- template <typename T, typename U> \
- struct Checked##NAME<T, U, typename std::enable_if< \
- std::numeric_limits<T>::is_iec559 || \
- std::numeric_limits<U>::is_iec559>::type> { \
- using result_type = \
- typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; \
- template <typename V> \
- static bool Op(T x, U y, V* result) { \
- using Promotion = \
- typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; \
- Promotion presult = x OP y; \
- *result = static_cast<V>(presult); \
- return IsValueInRangeForNumericType<V>(presult); \
- } \
+#define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \
+ template <typename T, typename U> \
+ struct Checked##NAME##Op< \
+ T, U, \
+ typename std::enable_if<std::numeric_limits<T>::is_iec559 || \
+ std::numeric_limits<U>::is_iec559>::type> { \
+ using result_type = \
+ typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; \
+ template <typename V> \
+ static bool Do(T x, U y, V* result) { \
+ using Promotion = \
+ typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; \
+ Promotion presult = x OP y; \
+ *result = static_cast<V>(presult); \
+ return IsValueInRangeForNumericType<V>(presult); \
+ } \
};
BASE_FLOAT_ARITHMETIC_OPS(Add, +)
@@ -805,6 +806,42 @@ class CheckedNumericState<T, NUMERIC_FLOATING> {
constexpr T value() const { return value_; }
};
+// The following are helper templates used in the CheckedNumeric class.
+template <typename T>
+class CheckedNumeric;
+
+// Used to treat CheckedNumeric and arithmetic underlying types the same.
+template <typename T>
+struct UnderlyingType {
+ using type = T;
+ static const bool is_numeric = std::is_arithmetic<T>::value;
+ static const bool is_checked = false;
+};
+
+template <typename T>
+struct UnderlyingType<CheckedNumeric<T>> {
+ using type = T;
+ static const bool is_numeric = true;
+ static const bool is_checked = true;
+};
+
+template <typename L, typename R>
+struct IsCheckedOp {
+ static const bool value =
+ UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
+ (UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
+};
+
+template <template <typename, typename, typename> class M,
+ typename L,
+ typename R>
+struct MathWrapper {
+ using math = M<typename UnderlyingType<L>::type,
+ typename UnderlyingType<R>::type,
+ void>;
+ using type = typename math::result_type;
+};
+
} // namespace internal
} // namespace base
« 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