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

Unified Diff: base/numerics/safe_math.h

Issue 2545253002: Add support for CheckedNumeric Max and Min constexpr functions (Closed)
Patch Set: MakeStrictNum 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_math_impl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/numerics/safe_math.h
diff --git a/base/numerics/safe_math.h b/base/numerics/safe_math.h
index 73bed4e0538b519aac245a8cfdf8a6cd24c5a518..3d765c949a8ed1adb5d3d4655f0f08371ecbc7f4 100644
--- a/base/numerics/safe_math.h
+++ b/base/numerics/safe_math.h
@@ -37,13 +37,21 @@ namespace internal {
// CheckAnd() - Bitwise AND (integer only with unsigned result).
// CheckOr() - Bitwise OR (integer only with unsigned result).
// CheckXor() - Bitwise XOR (integer only with unsigned result).
+// CheckMax() - Maximum of supplied arguments.
+// CheckMin() - Minimum of supplied arguments.
//
// The unary negation, increment, and decrement operators are supported, along
// with the following unary arithmetic methods, which return a new
// CheckedNumeric as a result of the operation:
// Abs() - Absolute value.
-// UnsignedAbs() - Absolute value as an equival-width unsigned underlying type
+// UnsignedAbs() - Absolute value as an equal-width unsigned underlying type
// (valid for only integral types).
+// Max() - Returns whichever is greater of the current instance or argument.
+// The underlying return type is whichever has the greatest magnitude.
+// Min() - Returns whichever is lowest of the current instance or argument.
+// The underlying return type is whichever has can represent the lowest
+// number in the smallest width (e.g. int8_t over unsigned, int over
+// int8_t, and float over int).
//
// The following methods convert from CheckedNumeric to standard numeric values:
// AssignIfValid() - Assigns the underlying value to the supplied destination
@@ -73,7 +81,7 @@ namespace internal {
// derived from casting the current instance to a CheckedNumeric of
// the supplied destination type.
// CheckNum() - Creates a new CheckedNumeric from the underlying type of the
-// supplied arithmetic or CheckedNumeric type.
+// supplied arithmetic, CheckedNumeric, or StrictNumeric type.
//
// Comparison operations are explicitly not supported because they could result
// in a crash on an unexpected CHECK condition. You should use patterns like the
@@ -220,6 +228,36 @@ class CheckedNumeric {
return CheckedNumeric<T>(value, is_valid);
}
+ template <typename U>
+ constexpr CheckedNumeric<typename MathWrapper<CheckedMaxOp, T, U>::type> Max(
+ const U rhs) const {
+ using R = typename UnderlyingType<U>::type;
+ using result_type = typename MathWrapper<CheckedMaxOp, T, U>::type;
+ // TODO(jschuh): This can be converted to the MathOp version and remain
+ // constexpr once we have C++14 support.
+ return CheckedNumeric<result_type>(
+ static_cast<result_type>(
+ IsGreater<T, R>::Test(state_.value(), Wrapper<U>::value(rhs))
+ ? state_.value()
+ : Wrapper<U>::value(rhs)),
+ state_.is_valid() && Wrapper<U>::is_valid(rhs));
+ }
+
+ template <typename U>
+ constexpr CheckedNumeric<typename MathWrapper<CheckedMinOp, T, U>::type> Min(
+ const U rhs) const {
+ using R = typename UnderlyingType<U>::type;
+ using result_type = typename MathWrapper<CheckedMinOp, T, U>::type;
+ // TODO(jschuh): This can be converted to the MathOp version and remain
+ // constexpr once we have C++14 support.
+ return CheckedNumeric<result_type>(
+ static_cast<result_type>(
+ IsLess<T, R>::Test(state_.value(), Wrapper<U>::value(rhs))
+ ? state_.value()
+ : Wrapper<U>::value(rhs)),
+ state_.is_valid() && Wrapper<U>::is_valid(rhs));
+ }
+
// This function is available only for integral types. It returns an unsigned
// integer of the same width as the source type, containing the absolute value
// of the source, and properly handling signed min.
@@ -300,6 +338,14 @@ class CheckedNumeric {
return v.state_.value();
}
};
+
+ template <typename Src>
+ struct Wrapper<StrictNumeric<Src>> {
+ static constexpr bool is_valid(const StrictNumeric<Src>) { return true; }
+ static constexpr Src value(const StrictNumeric<Src> v) {
+ return static_cast<Src>(v);
+ }
+ };
};
// Convenience functions to avoid the ugly template disambiguator syntax.
@@ -350,7 +396,8 @@ struct ResultType {
// Convience wrapper to return a new CheckedNumeric from the provided arithmetic
// or CheckedNumericType.
template <typename T>
-CheckedNumeric<typename UnderlyingType<T>::type> CheckNum(T value) {
+constexpr CheckedNumeric<typename UnderlyingType<T>::type> CheckNum(
+ const T value) {
return value;
}
@@ -363,8 +410,9 @@ CheckedNumeric<typename MathWrapper<M, L, R>::type> ChkMathOp(const L lhs,
using Math = typename MathWrapper<M, L, R>::math;
return CheckedNumeric<typename Math::result_type>::template MathOp<M>(lhs,
rhs);
-};
+}
+// General purpose wrapper template for arithmetic operations.
template <template <typename, typename, typename> class M,
typename L,
typename R,
@@ -376,8 +424,16 @@ ChkMathOp(const L lhs, const R rhs, const Args... args) {
: decltype(ChkMathOp<M>(tmp, args...))(tmp);
};
-// This is just boilerplate for the standard arithmetic operator overloads.
-// A macro isn't the nicest solution, but it beats rewriting these repeatedly.
+// The following macros are just boilerplate for the standard arithmetic
+// operator overloads and variadic function templates. A macro isn't the nicest
+// solution, but it beats rewriting these over and over again.
+#define BASE_NUMERIC_ARITHMETIC_VARIADIC(NAME) \
+ template <typename L, typename R, typename... Args> \
+ CheckedNumeric<typename ResultType<Checked##NAME##Op, L, R, Args...>::type> \
+ Check##NAME(const L lhs, const R rhs, const Args... args) { \
+ return ChkMathOp<Checked##NAME##Op, L, R, Args...>(lhs, rhs, args...); \
+ }
+
#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \
/* Binary arithmetic operator for all CheckedNumeric operations. */ \
template <typename L, typename R, \
@@ -394,11 +450,7 @@ ChkMathOp(const L lhs, const R rhs, const Args... args) {
return MathOp<Checked##NAME##Op>(rhs); \
} \
/* Variadic arithmetic functions that return CheckedNumeric. */ \
- template <typename L, typename R, typename... Args> \
- CheckedNumeric<typename ResultType<Checked##NAME##Op, L, R, Args...>::type> \
- Check##NAME(const L lhs, const R rhs, const Args... args) { \
- return ChkMathOp<Checked##NAME##Op, L, R, Args...>(lhs, rhs, args...); \
- }
+ BASE_NUMERIC_ARITHMETIC_VARIADIC(NAME)
BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=)
BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=)
@@ -410,7 +462,10 @@ BASE_NUMERIC_ARITHMETIC_OPERATORS(Rsh, >>, >>=)
BASE_NUMERIC_ARITHMETIC_OPERATORS(And, &, &=)
BASE_NUMERIC_ARITHMETIC_OPERATORS(Or, |, |=)
BASE_NUMERIC_ARITHMETIC_OPERATORS(Xor, ^, ^=)
+BASE_NUMERIC_ARITHMETIC_VARIADIC(Max)
+BASE_NUMERIC_ARITHMETIC_VARIADIC(Min)
+#undef BASE_NUMERIC_ARITHMETIC_VARIADIC
#undef BASE_NUMERIC_ARITHMETIC_OPERATORS
// These are some extra StrictNumeric operators to support simple pointer
@@ -439,6 +494,8 @@ using internal::IsValidForType;
using internal::ValueOrDieForType;
using internal::ValueOrDefaultForType;
using internal::CheckNum;
+using internal::CheckMax;
+using internal::CheckMin;
using internal::CheckAdd;
using internal::CheckSub;
using internal::CheckMul;
« no previous file with comments | « base/numerics/safe_conversions_impl.h ('k') | base/numerics/safe_math_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698