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

Unified Diff: base/numerics/safe_math_impl.h

Issue 141583008: Add support for safe math operations in base/numerics (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 6 years, 11 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
« 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
===================================================================
--- base/numerics/safe_math_impl.h (revision 0)
+++ base/numerics/safe_math_impl.h (revision 0)
@@ -0,0 +1,696 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SAFE_MATH_IMPL_H_
+#define SAFE_MATH_IMPL_H_
+
+#include <stdint.h>
+
+#include <limits>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+
+namespace base {
+namespace internal {
+
+using std::numeric_limits;
+
+// Everything from here up to the definition of CheckedNumericState is
+// portable C++, but it may not be fast. This code could be split based on
+// platform/architecture and replaced with potentially faster implementations.
+
+template <size_t Size, bool IsSigned>
+struct IntegerTypeForSizeAndSign {};
+
+template <>
+struct IntegerTypeForSizeAndSign<1, true> {
+ typedef int8_t Type;
+};
+
+template <>
+struct IntegerTypeForSizeAndSign<1, false> {
+ typedef uint8_t Type;
+};
+
+template <>
+struct IntegerTypeForSizeAndSign<2, true> {
+ typedef int16_t Type;
+};
+
+template <>
+struct IntegerTypeForSizeAndSign<2, false> {
+ typedef uint16_t Type;
+};
+
+template <>
+struct IntegerTypeForSizeAndSign<4, true> {
+ typedef int32_t Type;
+};
+
+template <>
+struct IntegerTypeForSizeAndSign<4, false> {
+ typedef uint32_t Type;
+};
+
+template <>
+struct IntegerTypeForSizeAndSign<8, true> {
+ typedef int64_t Type;
+};
+
+template <>
+struct IntegerTypeForSizeAndSign<8, false> {
+ typedef uint64_t Type;
+};
+
+// This is effectively a compile assert to ensure we're supporting the full
+// type range for this compiler (otherwise multiply may not compile).
+typedef IntegerTypeForSizeAndSign<sizeof(intmax_t), true> MaxSupportedInteger;
+
+template <typename IntegerType>
+struct UnsignedType {
+ typedef typename IntegerTypeForSizeAndSign<sizeof(IntegerType), false>::Type
+ Type;
+};
+
+template <typename IntegerType>
+struct SignedType {
+ typedef typename IntegerTypeForSizeAndSign<sizeof(IntegerType), true>::Type
+ Type;
+};
+
+template <typename IntegerType>
+struct TwiceWiderType {
+ typedef typename IntegerTypeForSizeAndSign<sizeof(IntegerType) * 2,
+ numeric_limits<IntegerType>::is_signed>::Type
+ Type;
+};
+
+template <typename IntegerType>
+struct PositionOfSignBit {
+ static const size_t value = 8 * sizeof(IntegerType) - 1;
+};
+
+
+template <typename T>
+bool HasSignBit(T x) {
+ // Cast to unsigned since right shift on signed is undefined.
+ return !!(static_cast<typename UnsignedType<T>::Type>(x) >>
+ PositionOfSignBit<T>::value);
+}
+
+
+// This wrapper undoes the standard integer promotions.
+template <typename T>
+T BinaryComplement(T x) {
+ return ~x;
+}
+
+template <typename T,
+ DstSignId DstSign = numeric_limits<T>::is_signed ?
+ DST_SIGNED : DST_UNSIGNED>
+struct NegIntegerImpl;
+
+template <typename T>
+struct NegIntegerImpl<T, DST_SIGNED> {
+ static RangeCheckId run(T value, T* result) {
+ *result = -value;
+ // The negation of signed min is min, so catch that one.
+ return value != numeric_limits<T>::min() ? TYPE_VALID : TYPE_OVERFLOW;
+ }
+};
+
+template <typename T>
+struct NegIntegerImpl<T, DST_UNSIGNED> {
+ static RangeCheckId run(T value, T* result) {
+ *result = static_cast<T>(
+ -static_cast<typename SignedType<T>::Type>(value));
+ // The only legal unsigned negation is zero.
+ return *result ? TYPE_UNDERFLOW : TYPE_VALID;
+ }
+};
+
+template <typename T>
+RangeCheckId NegInteger(T value, T* result) {
+ return NegIntegerImpl<T>::run(value, result);
+}
+
+
+template <typename T>
+RangeCheckId AddIntegers(T x, T y, T* result) {
+ COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers);
+ // Since the value of x+y is undefined if we have a signed type, we compute
+ // it using the unsigned type of the same size.
+ typedef typename UnsignedType<T>::Type UnsignedDst;
+ UnsignedDst ux = static_cast<UnsignedDst>(x);
+ UnsignedDst uy = static_cast<UnsignedDst>(y);
+ UnsignedDst uresult = ux + uy;
+ *result = static_cast<T>(uresult);
+ // Addition is valid if the sign of (x + y) is equal to either that of x or
+ // that of y.
+ if (numeric_limits<T>::is_signed) {
+ if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy))))
+ return TYPE_VALID;
+ // Direction of wrap is inverse of result sign.
+ return HasSignBit(uresult) ? TYPE_OVERFLOW : TYPE_UNDERFLOW;
+ }
+ // Unsigned is either valid or overflow.
+ return BinaryComplement(x) >= y ? TYPE_VALID : TYPE_OVERFLOW;
+}
+
+template <typename T>
+RangeCheckId SubIntegers(T x, T y, T* result) {
+ COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers);
+ // Since the value of x+y is undefined if we have a signed type, we compute
+ // it using the unsigned type of the same size.
+ typedef typename UnsignedType<T>::Type UnsignedDst;
+ UnsignedDst ux = static_cast<UnsignedDst>(x);
+ UnsignedDst uy = static_cast<UnsignedDst>(y);
+ UnsignedDst uresult = ux - uy;
+ *result = static_cast<T>(uresult);
+ // Subtraction is valid if either x and y have same sign, or (x-y) and x have
+ // the same sign.
+ if (numeric_limits<T>::is_signed) {
+ if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy))))
+ return TYPE_VALID;
+ // Direction of wrap is inverse of result sign.
+ return HasSignBit(uresult) ? TYPE_OVERFLOW : TYPE_UNDERFLOW;
+ }
+ // Unsigned is either valid or underflow.
+ return x >= y ? TYPE_VALID : TYPE_UNDERFLOW;
+}
+
+// Integer multiplication is a bit complicated. In the fast case we just
+// we just promote to a twice wider type, and range check the result. In the
+// slow case we need to manually check that the result won't be truncated by
+// checking with division against the appropriate bound.
+enum IntegerMathId {
+ FAST_MATH,
+ SLOW_MATH
+};
+template <typename T,
+ DstSignId DstSign = numeric_limits<T>::is_signed ?
+ DST_SIGNED : DST_UNSIGNED,
+ IntegerMathId MathType = sizeof(T)* 2 <= sizeof(uintmax_t) ?
+ FAST_MATH : SLOW_MATH>
+struct MulIntegersImpl {};
+
+template <typename T, DstSignId DstSign>
+struct MulIntegersImpl<T, DstSign, FAST_MATH> {
+ static RangeCheckId run(T x, T y, T* result) {
+ typedef typename TwiceWiderType<T>::Type IntermediateType;
+ IntermediateType tmp = static_cast<IntermediateType>(x) *
+ static_cast<IntermediateType>(y);
+ *result = static_cast<T>(tmp);
+ return RangeCheck<T>(tmp);
+ }
+};
+
+template <typename T>
+struct MulIntegersImpl<T, DST_SIGNED, SLOW_MATH> {
+ static RangeCheckId run(T x, T y, T* result) {
+ *result = x * y;
+
+ // if either side is zero then the result will be zero.
+ if (!(x || y))
+ return TYPE_VALID;
+
+ // Check each boundary based on the sign.
+ if (x > 0) {
+ if (y > 0)
+ return x <= numeric_limits<T>::max() / y ? TYPE_VALID : TYPE_OVERFLOW;
+ return y >= numeric_limits<T>::min() / x ? TYPE_VALID : TYPE_UNDERFLOW;
+ }
+
+ if (y > 0)
+ return x >= numeric_limits<T>::min() / y ? TYPE_VALID : TYPE_UNDERFLOW;
+ return y >= numeric_limits<T>::max() / x ? TYPE_VALID : TYPE_OVERFLOW;
+ }
+};
+
+template <typename T>
+struct MulIntegersImpl<T, DST_UNSIGNED, SLOW_MATH> {
+ static RangeCheckId run(T x, T y, T* result) {
+ *result = x * y;
+ return (y == 0 || x <= numeric_limits<T>::max() / y) ?
+ TYPE_VALID : TYPE_OVERFLOW;
+ }
+};
+
+template <typename T>
+RangeCheckId MulIntegers(T x, T y, T* result) {
+ COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers);
+ return MulIntegersImpl<T>::run(x, y, result);
+}
+
+
+// Division is really easy. Just check for an invalid negation on signed min/-1.
+template <typename T>
+RangeCheckId DivIntegers(T x, T y, T* result) {
+ COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers);
+ *result = x / y;
+ return (!numeric_limits<T>::is_signed || x != numeric_limits<T>::min()
+ || y != -1) ? TYPE_VALID : TYPE_OVERFLOW;
+}
+
+// Modulus is easy, but we split it into signed and unsigned to avoid warnings.
+template <typename T,
+ DstSignId DstSign = numeric_limits<T>::is_signed ?
+ DST_SIGNED : DST_UNSIGNED>
+struct ModIntegersImpl {};
+
+template <typename T>
+struct ModIntegersImpl<T, DST_SIGNED> {
+ static RangeCheckId run(T x, T y, T* result) {
+ *result = x % y;
+ return y > 0 ? TYPE_VALID : TYPE_INVALID;
+ }
+};
+
+template <typename T>
+struct ModIntegersImpl<T, DST_UNSIGNED> {
+ static RangeCheckId run(T x, T y, T* result) {
+ *result = x % y;
+ return TYPE_VALID;
+ }
+};
+
+template <typename T>
+RangeCheckId ModIntegers(T x, T y, T* result) {
+ COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers);
+ return ModIntegersImpl<T>::run(x, y, result);
+}
+
+
+// Floats carry around their validity state with them, but integers do not. So,
+// we wrap the underlying value in a specialization in order to hide that detail
+// and expose an interface via accessors.
+enum NumericTypeId {
+ NUMERIC_INTEGER,
+ NUMERIC_FLOATING,
+ NUMERIC_UNKNOWN
+};
+
+template <typename NumericType>
+struct GetNumericTypeId {
+ static const NumericTypeId value = numeric_limits<NumericType>::is_integer ?
+ NUMERIC_INTEGER : (numeric_limits<NumericType>::is_iec559 ?
+ NUMERIC_FLOATING : NUMERIC_UNKNOWN);
+};
+
+template <typename T, NumericTypeId Type = GetNumericTypeId<T>::value>
+class CheckedNumericState {};
+
+// Integrals require quite a bit of additional housekeeping to manage state.
+template <typename T>
+class CheckedNumericState<T, NUMERIC_INTEGER> {
+ private:
+ T value_;
+ RangeCheckId validity_;
+
+ public:
+ template <typename Src, NumericTypeId Type>
+ friend class CheckedNumericState;
+
+ CheckedNumericState() : value_(0), validity_(TYPE_VALID) {}
+
+ template <typename Src>
+ CheckedNumericState(Src value, RangeCheckId validity) :
+ value_(value), validity_(static_cast<RangeCheckId>(
+ validity | RangeCheck<T>(value))) {
+ COMPILE_ASSERT(numeric_limits<Src>::is_specialized,
+ argument_must_be_numeric);
+ }
+
+ template <typename Src>
+ explicit CheckedNumericState(const CheckedNumericState<Src>& rhs) :
+ value_(static_cast<T>(rhs.value_)), validity_(
+ static_cast<RangeCheckId>(rhs.validity() |
+ RangeCheck<T>(rhs.value_))) {
+ COMPILE_ASSERT(numeric_limits<Src>::is_specialized,
+ argument_must_be_numeric);
+ }
+
+ template <typename Src>
+ explicit CheckedNumericState(Src value) :
+ value_(static_cast<T>(value)), validity_(RangeCheck<T>(value)) {
+ COMPILE_ASSERT(numeric_limits<Src>::is_specialized,
+ argument_must_be_numeric);
+ }
Ryan Sleevi 2014/02/05 02:45:06 So, templated CTORS = generally a bad/tricky thing
+
+ RangeCheckId validity() const { return validity_; }
+ T value() const { return value_; }
+};
+
+// Floating points maintain their own validity, but need translation wrappers.
+template <typename T>
+class CheckedNumericState<T, NUMERIC_FLOATING> {
+ private:
+ T value_;
+
+ public:
+ template <typename Src, NumericTypeId Type>
+ friend class CheckedNumericState;
+
+ CheckedNumericState() : value_(0.0) {}
+
+ template <typename Src>
+ CheckedNumericState(Src value, RangeCheckId validity) {
+ // A non-integer specialization can get generated in non-optimized builds,
+ // but it should be impossible to trigger the code path.
+ DCHECK(numeric_limits<Src>::is_integer);
+
+ switch (RangeCheck<T>(value)) {
+ case TYPE_VALID:
+ value_ = static_cast<T>(value_);
+ break;
+
+ case TYPE_UNDERFLOW:
+ value_ = -numeric_limits<T>::infinity();
+ break;
+
+ case TYPE_OVERFLOW:
+ value_ = numeric_limits<T>::infinity();
+ break;
+
+ case TYPE_INVALID:
+ value_ = numeric_limits<T>::quiet_NaN();
+ break;
+
+ default:
+ NOTREACHED();
+ }
+ }
+
+ template <typename Src>
+ explicit CheckedNumericState(Src value) : value_(static_cast<T>(value)) {
+ COMPILE_ASSERT(numeric_limits<Src>::is_specialized,
+ argument_must_be_numeric);
+ }
+
+ template <typename Src>
+ explicit CheckedNumericState(const CheckedNumericState<Src>& rhs) :
+ value_(static_cast<T>(rhs.value_)) {
+ COMPILE_ASSERT(numeric_limits<Src>::is_specialized,
+ argument_must_be_numeric);
+ }
+
+ RangeCheckId validity() const {
+ return BASE_NUMERIC_RANGE_CHECK_RESULT(
+ value_ < numeric_limits<T>::max(),
+ value_ > -numeric_limits<T>::max());
+ }
+ T value() const { return value_; }
+};
+
+// In addition to wrapping the state, we also need to wrap all the arithmetic
+// operations because we use a fast path for floating points, but a slower,
+// checked path for integers.
+template <typename T, NumericTypeId Type = GetNumericTypeId<T>::value>
+class CheckedIntegerArithmetic {};
+
+// Wrap the checked integer operations injected as a dependency.
+template <typename T>
+class CheckedIntegerArithmetic<T, NUMERIC_INTEGER> {
+ public:
+ static RangeCheckId Neg(T value, T* result) {
+ return NegInteger(value, result);
+ }
+ static RangeCheckId Add(T x, T y, T* result) {
+ return AddIntegers(x, y, result);
+ }
+ static RangeCheckId Sub(T x, T y, T* result) {
+ return SubIntegers(x, y, result);
+ }
+ static RangeCheckId Mul(T x, T y, T* result) {
+ return MulIntegers(x, y, result);
+ }
+ static RangeCheckId Div(T x, T y, T* result) {
+ return DivIntegers(x, y, result);
+ }
+ static RangeCheckId Mod(T x, T y, T* result) {
+ return ModIntegers(x, y, result);
+ }
+};
+
+// We never use these for floats, but the compiler needs to see an
+// implementation.
+template <typename T>
+class CheckedIntegerArithmetic<T, NUMERIC_FLOATING> {
+ private:
+ static RangeCheckId not_implemented() {
+ NOTREACHED();
+ return TYPE_INVALID;
+ }
+
+ public:
+ static RangeCheckId Add(T, T, T*) { return not_implemented(); }
+ static RangeCheckId Sub(T, T, T*) { return not_implemented(); }
+ static RangeCheckId Mul(T, T, T*) { return not_implemented(); }
+ static RangeCheckId Div(T, T, T*) { return not_implemented(); }
+ static RangeCheckId Mod(T, T, T*) { return not_implemented(); }
+ static RangeCheckId Neg(T, T*) { return not_implemented(); }
+};
+
+
+// This template class implements all the logic and operators for safe numeric
+// arithmetic and conversions.
+template <typename T>
+class CheckedNumeric {
+ private:
+ CheckedNumericState<T> state_;
+
+ public:
+ template <typename Src>
+ friend class CheckedNumeric;
+
+ CheckedNumeric() {}
+
+ template <typename Src>
+ CheckedNumeric(const CheckedNumeric<Src>& rhs) : state_(rhs.state_) {}
+
+ template <typename Src>
+ CheckedNumeric(Src value, RangeCheckId validity) : state_(value, validity) {}
+
+ template <typename Src>
+ CheckedNumeric(Src value) : state_(value) {}
+
+ RangeCheckId validity() const { return state_.validity(); }
+ bool IsValid() const { return validity() == TYPE_VALID; }
+ bool IsOverflow() const { return validity() == TYPE_OVERFLOW; }
+ bool IsUnderflow() const { return validity() == TYPE_UNDERFLOW; }
+ bool IsInvalid() const { return validity() == TYPE_INVALID; }
+
+ T ValueUnsafe() const { return state_.value(); }
+
+ template <typename FloatingType>
+ FloatingType ValueFloating() const {
+ if (std::numeric_limits<T>::is_iec559)
+ return ValueUnsafe();
+ return CheckedNumeric<FloatingType>(ValueUnsafe()).ValueUnsafe();
+ }
+
+ T ValueOrDie() const {
+ CHECK(IsValid());
+ return state_.value();
+ }
+
+ T ValueOrDefault(T default_value) const {
+ return IsValid() ? state_.value() : default_value;
+ }
+
+ // Friend all the operator overloads
+ template <typename Src>
+ CheckedNumeric& operator +=(Src rhs);
+
+ template <typename Src>
+ CheckedNumeric& operator -=(Src rhs);
+
+ template <typename Src>
+ CheckedNumeric& operator *=(Src rhs);
+
+ template <typename Src>
+ CheckedNumeric& operator /=(Src rhs);
+
+ template <typename Src>
+ CheckedNumeric& operator %=(Src rhs);
+
+ CheckedNumeric operator -() const {
+ // Negation is always valid for floating point
+ if (numeric_limits<T>::is_iec559)
+ return -state_.value();
+
+ T value;
+ RangeCheckId validity = static_cast<RangeCheckId>(
+ state_.validity() |
+ CheckedIntegerArithmetic<T>::Neg(state_.value(), &value));
+ return CheckedNumeric<T>(value, validity);
+ }
+
+ CheckedNumeric& operator++() {
+ *this += 1;
+ return *this;
+ }
+
+ CheckedNumeric operator++(int) {
+ CheckedNumeric tmp = *this;
+ *this += 1;
+ return tmp;
+ }
+
+ CheckedNumeric& operator--() {
+ *this -= 1;
+ return *this;
+ }
+
+ CheckedNumeric operator--(int) {
+ CheckedNumeric tmp = *this;
+ *this -= 1;
+ return tmp;
+ }
+
+ // These static functions behave like a convenience operator for casting to
+ // the desired numeric base type or CheckedNumeric type. As an optimization,
+ // a reference is returned when Src is the same type as T.
+ template <typename Src>
+ CheckedNumeric<T> static cast(Src u) {
+ COMPILE_ASSERT(numeric_limits<Src>::is_specialized,
+ argument_must_be_numeric);
+ return u;
+ }
+
+ template <typename Src>
+ CheckedNumeric<T> static cast(const CheckedNumeric<Src>& u) {
+ return u;
+ }
+
+ CheckedNumeric<T> static cast(const CheckedNumeric<T>& u) {
+ return u;
+ }
+};
+
+enum ArithmeticPromotionId {
+ LEFT_PROMOTION,
+ RIGHT_PROMOTION,
+ DEFAULT_PROMOTION
+};
+
+template <typename Lhs, typename Rhs,
+ ArithmeticPromotionId Promotion =
+ (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) ?
+ (MaxExponent<Lhs>::value > MaxExponent<int>::value ?
+ LEFT_PROMOTION : DEFAULT_PROMOTION) :
+ (MaxExponent<Rhs>::value > MaxExponent<int>::value ?
+ RIGHT_PROMOTION : DEFAULT_PROMOTION)>
+struct ArithmeticPromotion {};
+
+template <typename Lhs, typename Rhs>
+struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> {
+ typedef Lhs Type;
+};
+
+template <typename Lhs, typename Rhs>
+struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
+ typedef Rhs Type;
+};
+
+template <typename Lhs, typename Rhs>
+struct ArithmeticPromotion<Lhs, Rhs, DEFAULT_PROMOTION> {
+ typedef int Type;
+};
+
+// Statically check if operations on the provided types can wrap, so we can skip
+// the checked operations if they're not needed. An integer is safe if the
+// destination type preserves sign and is wider.
+template <typename T, typename Lhs, typename Rhs>
+struct IsIntegerArithmeticSafe {
+ static const bool value = !numeric_limits<T>::is_iec559 &&
+ StaticRangeCheck<T, Lhs>::value == CONTAINS_RANGE &&
+ sizeof(T) >= (2 * sizeof(Lhs)) &&
+ StaticRangeCheck<T, Rhs>::value != CONTAINS_RANGE &&
+ sizeof(T) >= (2 * sizeof(Rhs));
+};
+
+// 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:
+// * We employ the standard aritmetic promotions.
+// * We skip the range checking operations for floating points.
+// * We skip the range checking operations for integers with sufficient range.
+#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME,OP,COMPOUND_OP) \
+/* Binary arithmetic operator for CheckedNumerics of the same type. */ \
+template <typename T> \
+CheckedNumeric<typename ArithmeticPromotion<T, T>::Type> \
+operator OP(const CheckedNumeric<T> &lhs, const CheckedNumeric<T> &rhs) { \
+ typedef typename ArithmeticPromotion<T, T>::Type Promotion; \
+ /* Floating point always takes the fast path */ \
+ if (numeric_limits<T>::is_iec559) \
+ return CheckedNumeric<T>(lhs.template ValueFloating<T>() OP \
+ rhs.template ValueFloating<T>()); \
+ if (IsIntegerArithmeticSafe<Promotion, T, T>::value) \
+ return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \
+ static_cast<RangeCheckId>(rhs.validity() | lhs.validity())); \
+ T result = 0; \
+ RangeCheckId validity = \
+ CheckedIntegerArithmetic<Promotion>::NAME(lhs.ValueUnsafe(), \
+ rhs.ValueUnsafe(), \
+ &result); \
+ return CheckedNumeric<Promotion>(result, static_cast<RangeCheckId>( \
+ validity | lhs.validity() | rhs.validity())); \
+} \
+/* Binary arithmetic operator for CheckedNumeric of different type. */ \
+template <typename T, typename Src> \
+CheckedNumeric<typename ArithmeticPromotion<T, Src>::Type> \
+operator OP(const CheckedNumeric<Src> &lhs, const CheckedNumeric<T> &rhs) { \
+ typedef typename ArithmeticPromotion<T, Src>::Type Promotion; \
+ if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
+ return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \
+ static_cast<RangeCheckId>(rhs.validity() | lhs.validity())); \
+ return CheckedNumeric<Promotion>::cast(lhs) OP \
+ CheckedNumeric<Promotion>::cast(rhs); \
+} \
+/* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \
+template <typename T, typename Src> \
+CheckedNumeric<typename ArithmeticPromotion<T, Src>::Type> \
+operator OP(const CheckedNumeric<T> &lhs, Src rhs) { \
+ typedef typename ArithmeticPromotion<T, Src>::Type Promotion; \
+ if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
+ return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP \
+ rhs, lhs.validity()); \
+ return CheckedNumeric<Promotion>::cast(lhs) OP \
+ CheckedNumeric<Promotion>::cast(rhs); \
+} \
+/* Assignment arithmetic operator implementation from CheckedNumeric above. */ \
+template <typename T> \
+template <typename Src> \
+CheckedNumeric<T>& \
+CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) { \
+ *this = CheckedNumeric<T>::cast(*this) OP CheckedNumeric<Src>::cast(rhs); \
+ return *this; \
+} \
+/* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \
+template <typename T, typename Src> \
+CheckedNumeric<typename ArithmeticPromotion<T, Src>::Type> \
+operator OP(Src lhs, const CheckedNumeric<T> &rhs) { \
+ typedef typename ArithmeticPromotion<T, Src>::Type Promotion; \
+ if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
+ return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(), \
+ rhs.validity()); \
+ return CheckedNumeric<Promotion>::cast(lhs) OP \
+ CheckedNumeric<Promotion>::cast(rhs); \
+}
+
+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, %, %=)
+
+#undef BASE_NUMERIC_ARITHMETIC_OPERATORS
+
+} // namespace internal
+} // namespace base
+
+#endif // SAFE_MATH_IMPL_H_
+
Property changes on: base\numerics\safe_math_impl.h
___________________________________________________________________
Added: svn:eol-style
+ LF
« 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