| Index: base/numerics/safe_math.h
|
| diff --git a/base/numerics/safe_math.h b/base/numerics/safe_math.h
|
| index 511eb23f78763c929e86db014f08911d17d0acf2..73a50b2a549fd9d439f4a9ce59afa11275c900af 100644
|
| --- a/base/numerics/safe_math.h
|
| +++ b/base/numerics/safe_math.h
|
| @@ -46,6 +46,25 @@ namespace internal {
|
| // checked_size += HEADER LENGTH;
|
| // if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size)
|
| // Do stuff...
|
| +
|
| +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 T>
|
| class CheckedNumeric {
|
| static_assert(std::is_arithmetic<T>::value,
|
| @@ -59,10 +78,10 @@ class CheckedNumeric {
|
| // Copy constructor.
|
| template <typename Src>
|
| CheckedNumeric(const CheckedNumeric<Src>& rhs)
|
| - : state_(rhs.ValueUnsafe(), rhs.IsValid()) {}
|
| + : state_(rhs.state_.value(), rhs.IsValid()) {}
|
|
|
| template <typename Src>
|
| - CheckedNumeric(Src value, bool is_valid) : state_(value, is_valid) {}
|
| + friend class CheckedNumeric;
|
|
|
| // This is not an explicit constructor because we implicitly upgrade regular
|
| // numerics to CheckedNumerics to make them easier to use.
|
| @@ -102,30 +121,30 @@ class CheckedNumeric {
|
| // crashing on a CHECK.
|
| T ValueFloating() const {
|
| static_assert(std::numeric_limits<T>::is_iec559, "Argument must be float.");
|
| - return CheckedNumeric<T>::cast(*this).ValueUnsafe();
|
| + return state_.value();
|
| }
|
|
|
| - // ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now
|
| - // for tests and to avoid a big matrix of friend operator overloads. But the
|
| - // values it returns are unintuitive and likely to change in the future.
|
| - // Returns: the raw numeric value, regardless of the current state.
|
| - T ValueUnsafe() const { return state_.value(); }
|
| + // This friend method is available solely for providing more detailed logging
|
| + // in the the tests. Do not implement it in production code, because the
|
| + // underlying values may change at any time.
|
| + template <typename U>
|
| + friend U GetNumericValueForTest(const CheckedNumeric<U>& src);
|
|
|
| // Prototypes for the supported arithmetic operator overloads.
|
| template <typename Src>
|
| - CheckedNumeric& operator+=(Src rhs);
|
| + CheckedNumeric& operator+=(const Src rhs);
|
| template <typename Src>
|
| - CheckedNumeric& operator-=(Src rhs);
|
| + CheckedNumeric& operator-=(const Src rhs);
|
| template <typename Src>
|
| - CheckedNumeric& operator*=(Src rhs);
|
| + CheckedNumeric& operator*=(const Src rhs);
|
| template <typename Src>
|
| - CheckedNumeric& operator/=(Src rhs);
|
| + CheckedNumeric& operator/=(const Src rhs);
|
| template <typename Src>
|
| - CheckedNumeric& operator%=(Src rhs);
|
| + CheckedNumeric& operator%=(const Src rhs);
|
| template <typename Src>
|
| - CheckedNumeric& operator<<=(Src rhs);
|
| + CheckedNumeric& operator<<=(const Src rhs);
|
| template <typename Src>
|
| - CheckedNumeric& operator>>=(Src rhs);
|
| + CheckedNumeric& operator>>=(const Src rhs);
|
|
|
| CheckedNumeric operator-() const {
|
| // Negation is always valid for floating point.
|
| @@ -173,84 +192,83 @@ class CheckedNumeric {
|
| return value;
|
| }
|
|
|
| - // These static methods behave like a convenience cast operator targeting
|
| - // the desired CheckedNumeric type. As an optimization, a reference is
|
| - // returned when Src is the same type as T.
|
| - template <typename Src>
|
| - static CheckedNumeric<T> cast(
|
| - Src u,
|
| - typename std::enable_if<std::numeric_limits<Src>::is_specialized,
|
| - int>::type = 0) {
|
| - return u;
|
| - }
|
| + // These perform the actual math operations on the CheckedNumerics.
|
| + // Binary arithmetic operations.
|
| + template <template <typename, typename, typename> class M,
|
| + typename L,
|
| + typename R>
|
| + static CheckedNumeric MathOp(const L& lhs, const R& rhs) {
|
| + using Math = M<typename UnderlyingType<L>::type,
|
| + typename UnderlyingType<R>::type, void>;
|
| + T result = 0;
|
| + bool is_valid =
|
| + Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) &&
|
| + Math::Op(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result);
|
| + return CheckedNumeric<T>(result, is_valid);
|
| + };
|
| +
|
| + // Assignment arithmetic operations.
|
| + template <template <typename, typename, typename> class M, typename R>
|
| + CheckedNumeric& MathOp(const R& rhs) {
|
| + using Math = M<T, typename UnderlyingType<R>::type, void>;
|
| + T result = 0; // Using T as the destination saves a range check.
|
| + bool is_valid = state_.is_valid() && Wrapper<R>::is_valid(rhs) &&
|
| + Math::Op(state_.value(), Wrapper<R>::value(rhs), &result);
|
| + *this = CheckedNumeric<T>(result, is_valid);
|
| + return *this;
|
| + };
|
| +
|
| + private:
|
| + CheckedNumericState<T> state_;
|
|
|
| template <typename Src>
|
| - static CheckedNumeric<T> cast(
|
| - const CheckedNumeric<Src>& u,
|
| - typename std::enable_if<!std::is_same<Src, T>::value, int>::type = 0) {
|
| - return u;
|
| - }
|
| + CheckedNumeric(Src value, bool is_valid) : state_(value, is_valid) {}
|
|
|
| - static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; }
|
| + // These wrappers allow us to handle state the same way for both
|
| + // CheckedNumeric and POD arithmetic types.
|
| + template <typename Src>
|
| + struct Wrapper {
|
| + static bool is_valid(Src) { return true; }
|
| + static Src value(Src value) { return value; }
|
| + };
|
|
|
| - private:
|
| - CheckedNumericState<T> state_;
|
| + template <typename Src>
|
| + struct Wrapper<CheckedNumeric<Src>> {
|
| + static bool is_valid(const CheckedNumeric<Src>& v) { return v.IsValid(); }
|
| + static Src value(const CheckedNumeric<Src>& v) { return v.state_.value(); }
|
| + };
|
| };
|
|
|
| -// This is the boilerplate for the standard arithmetic operator overloads. A
|
| -// macro isn't the prettiest solution, but it beats rewriting these five times.
|
| -// Some details worth noting are:
|
| -// * We apply the standard arithmetic promotions.
|
| -// * We skip range checks for floating points.
|
| -// * We skip range checks for destination integers with sufficient range.
|
| -// TODO(jschuh): extract these out into templates.
|
| -#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP, PROMOTION) \
|
| - /* Binary arithmetic operator for CheckedNumerics of the same type. */ \
|
| - template <typename L, typename R> \
|
| - CheckedNumeric<typename ArithmeticPromotion<PROMOTION, L, R>::type> \
|
| - operator OP(const CheckedNumeric<L>& lhs, const CheckedNumeric<R>& rhs) { \
|
| - using P = typename ArithmeticPromotion<PROMOTION, L, R>::type; \
|
| - if (!rhs.IsValid() || !lhs.IsValid()) \
|
| - return CheckedNumeric<P>(0, false); \
|
| - /* Floating point always takes the fast path */ \
|
| - if (std::is_floating_point<L>::value || std::is_floating_point<R>::value) \
|
| - return CheckedNumeric<P>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \
|
| - P result = 0; \
|
| - bool is_valid = \
|
| - Checked##NAME(lhs.ValueUnsafe(), rhs.ValueUnsafe(), &result); \
|
| - return CheckedNumeric<P>(result, is_valid); \
|
| +// This is just boilerplate for the standard arithmetic operator overloads.
|
| +// A macro isn't the nicest solution, but it beats rewriting these repeatedly.
|
| +#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \
|
| + /* Binary arithmetic operator for all CheckedNumeric operations. */ \
|
| + template <typename L, typename R, \
|
| + typename std::enable_if<UnderlyingType<L>::is_numeric && \
|
| + UnderlyingType<R>::is_numeric && \
|
| + (UnderlyingType<L>::is_checked || \
|
| + UnderlyingType<R>::is_checked)>::type* = \
|
| + nullptr> \
|
| + CheckedNumeric< \
|
| + typename Checked##NAME<typename UnderlyingType<L>::type, \
|
| + typename UnderlyingType<R>::type>::result_type> \
|
| + operator OP(const L lhs, const R rhs) { \
|
| + return decltype(lhs OP rhs)::template MathOp<Checked##NAME>(lhs, rhs); \
|
| } \
|
| /* Assignment arithmetic operator implementation from CheckedNumeric. */ \
|
| template <typename L> \
|
| template <typename R> \
|
| - CheckedNumeric<L>& CheckedNumeric<L>::operator COMPOUND_OP(R rhs) { \
|
| - *this = *this OP rhs; \
|
| - return *this; \
|
| - } \
|
| - /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \
|
| - template <typename L, typename R, \
|
| - typename std::enable_if<std::is_arithmetic<R>::value>::type* = \
|
| - nullptr> \
|
| - CheckedNumeric<typename ArithmeticPromotion<PROMOTION, L, R>::type> \
|
| - operator OP(const CheckedNumeric<L>& lhs, R rhs) { \
|
| - return lhs OP CheckedNumeric<R>(rhs); \
|
| - } \
|
| - /* Binary arithmetic operator for left numeric and right CheckedNumeric. */ \
|
| - template <typename L, typename R, \
|
| - typename std::enable_if<std::is_arithmetic<L>::value>::type* = \
|
| - nullptr> \
|
| - CheckedNumeric<typename ArithmeticPromotion<PROMOTION, L, R>::type> \
|
| - operator OP(L lhs, const CheckedNumeric<R>& rhs) { \
|
| - return CheckedNumeric<L>(lhs) OP rhs; \
|
| + CheckedNumeric<L>& CheckedNumeric<L>::operator COMPOUND_OP(const R rhs) { \
|
| + return MathOp<Checked##NAME>(rhs); \
|
| }
|
|
|
| -BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=, MAX_EXPONENT_PROMOTION)
|
| -BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=, MAX_EXPONENT_PROMOTION)
|
| -BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *=, MAX_EXPONENT_PROMOTION)
|
| -BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=, MAX_EXPONENT_PROMOTION)
|
| -BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=, MAX_EXPONENT_PROMOTION)
|
| -BASE_NUMERIC_ARITHMETIC_OPERATORS(LeftShift, <<, <<=, LEFT_PROMOTION)
|
| -BASE_NUMERIC_ARITHMETIC_OPERATORS(RightShift, >>, >>=, LEFT_PROMOTION)
|
| +BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=)
|
| +BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=)
|
| +BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *=)
|
| +BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=)
|
| +BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=)
|
| +BASE_NUMERIC_ARITHMETIC_OPERATORS(LeftShift, <<, <<=)
|
| +BASE_NUMERIC_ARITHMETIC_OPERATORS(RightShift, >>, >>=)
|
|
|
| #undef BASE_NUMERIC_ARITHMETIC_OPERATORS
|
|
|
|
|