Chromium Code Reviews| 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 |