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 |