| Index: base/numerics/safe_math.h
|
| diff --git a/base/numerics/safe_math.h b/base/numerics/safe_math.h
|
| index 78b88326c44bdf697091f4ea74232b71a434788a..dc346acb7cc2b48d4b1ba6b9181260f496d73abd 100644
|
| --- a/base/numerics/safe_math.h
|
| +++ b/base/numerics/safe_math.h
|
| @@ -15,7 +15,7 @@
|
| namespace base {
|
| namespace internal {
|
|
|
| -// CheckedNumeric implements all the logic and operators for detecting integer
|
| +// CheckedNumeric<> implements all the logic and operators for detecting integer
|
| // boundary conditions such as overflow, underflow, and invalid conversions.
|
| // The CheckedNumeric type implicitly converts from floating point and integer
|
| // data types, and contains overloads for basic arithmetic operations (i.e.: +,
|
| @@ -33,6 +33,9 @@ namespace internal {
|
| // CheckMod() - Modulous (integer only).
|
| // CheckLsh() - Left integer shift (integer only).
|
| // CheckRsh() - Right integer shift (integer only).
|
| +// CheckAnd() - Bitwise AND (integer only with unsigned result).
|
| +// CheckOr() - Bitwise OR (integer only with unsigned result).
|
| +// CheckXor() - Bitwise XOR (integer only with unsigned result).
|
| //
|
| // The unary negation, increment, and decrement operators are supported, along
|
| // with the following unary arithmetic methods, which return a new
|
| @@ -42,17 +45,26 @@ namespace internal {
|
| // (valid for only integral types).
|
| //
|
| // The following methods convert from CheckedNumeric to standard numeric values:
|
| -// IsValid() - Returns true if the underlying numeric value is valid (i.e. has
|
| -// has not wrapped and is not the result of an invalid conversion).
|
| -// AssignIfValid() - Assigns the underlying value to the supplied destination
|
| +// AssignIfValid() - Assigns the underlying value to the supplied destination
|
| // pointer if the value is currently valid and within the range
|
| // supported by the destination type. Returns true on success.
|
| +// ****************************************************************************
|
| +// * WARNING: All of the following functions return a StrictNumeric, which *
|
| +// * is valid for comparison and assignment operations, but will trigger a *
|
| +// * compile failure on attempts to assign to a type of insufficient range. *
|
| +// ****************************************************************************
|
| +// IsValid() - Returns true if the underlying numeric value is valid (i.e. has
|
| +// has not wrapped and is not the result of an invalid conversion).
|
| // ValueOrDie() - Returns the underlying value. If the state is not valid this
|
| // call will crash on a CHECK.
|
| // ValueOrDefault() - Returns the current value, or the supplied default if the
|
| // state is not valid (will not trigger a CHECK).
|
| -// ValueFloating() - Returns the underlying floating point value (valid only
|
| -// for floating point CheckedNumeric types; will not cause a CHECK).
|
| +//
|
| +// The following wrapper functions can be used to avoid the template
|
| +// disambiguator syntax when converting a destination type.
|
| +// IsValidForType<>() in place of: a.template IsValid<Dst>()
|
| +// ValueOrDieForType<>() in place of: a.template ValueOrDie()
|
| +// ValueOrDefaultForType<>() in place of: a.template ValueOrDefault(default)
|
| //
|
| // The following are general utility methods that are useful for converting
|
| // between arithmetic types and CheckedNumeric types:
|
| @@ -131,8 +143,8 @@ class CheckedNumeric {
|
| // template parameter, for test code, etc. However, the handler cannot access
|
| // the underlying value, and it is not available through other means.
|
| template <typename Dst = T, class CheckHandler = CheckOnFailure>
|
| - constexpr Dst ValueOrDie() const {
|
| - return IsValid<Dst>() ? state_.value()
|
| + constexpr StrictNumeric<Dst> ValueOrDie() const {
|
| + return IsValid<Dst>() ? static_cast<Dst>(state_.value())
|
| : CheckHandler::template HandleFailure<Dst>();
|
| }
|
|
|
| @@ -143,22 +155,9 @@ class CheckedNumeric {
|
| // parameter. WARNING: This function may fail to compile or CHECK at runtime
|
| // if the supplied default_value is not within range of the destination type.
|
| template <typename Dst = T, typename Src>
|
| - constexpr Dst ValueOrDefault(const Src default_value) const {
|
| - return IsValid<Dst>() ? state_.value() : checked_cast<Dst>(default_value);
|
| - }
|
| -
|
| - // ValueFloating() - Since floating point values include their validity state,
|
| - // we provide an easy method for extracting them directly, without a risk of
|
| - // crashing on a CHECK.
|
| - // A range checked destination type can be supplied using the Dst template
|
| - // parameter.
|
| - template <typename Dst = T>
|
| - constexpr Dst ValueFloating() const {
|
| - static_assert(std::numeric_limits<T>::is_iec559,
|
| - "Type must be floating point.");
|
| - static_assert(std::numeric_limits<Dst>::is_iec559,
|
| - "Type must be floating point.");
|
| - return static_cast<Dst>(state_.value());
|
| + constexpr StrictNumeric<Dst> ValueOrDefault(const Src default_value) const {
|
| + return IsValid<Dst>() ? static_cast<Dst>(state_.value())
|
| + : checked_cast<Dst>(default_value);
|
| }
|
|
|
| // Returns a checked numeric of the specified type, cast from the current
|
| @@ -302,6 +301,25 @@ class CheckedNumeric {
|
| };
|
| };
|
|
|
| +// Convenience functions to avoid the ugly template disambiguator syntax.
|
| +template <typename Dst, typename Src>
|
| +constexpr bool IsValidForType(const CheckedNumeric<Src> value) {
|
| + return value.template IsValid<Dst>();
|
| +}
|
| +
|
| +template <typename Dst, typename Src>
|
| +constexpr StrictNumeric<Dst> ValueOrDieForType(
|
| + const CheckedNumeric<Src> value) {
|
| + return value.template ValueOrDie<Dst>();
|
| +}
|
| +
|
| +template <typename Dst, typename Src, typename Default>
|
| +constexpr StrictNumeric<Dst> ValueOrDefaultForType(
|
| + const CheckedNumeric<Src> value,
|
| + const Default default_value) {
|
| + return value.template ValueOrDefault<Dst>(default_value);
|
| +}
|
| +
|
| // These variadic templates work out the return types.
|
| // TODO(jschuh): Rip all this out once we have C++14 non-trailing auto support.
|
| template <template <typename, typename, typename> class M,
|
| @@ -394,9 +412,31 @@ BASE_NUMERIC_ARITHMETIC_OPERATORS(Xor, ^, ^=)
|
|
|
| #undef BASE_NUMERIC_ARITHMETIC_OPERATORS
|
|
|
| +// These are some extra StrictNumeric operators to support simple pointer
|
| +// arithmetic with our result types. Since wrapping on a pointer is always
|
| +// bad, we trigger the CHECK condition here.
|
| +template <typename L, typename R>
|
| +L* operator+(L* lhs, const StrictNumeric<R> rhs) {
|
| + uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs),
|
| + CheckMul(sizeof(L), static_cast<R>(rhs)))
|
| + .template ValueOrDie<uintptr_t>();
|
| + return reinterpret_cast<L*>(result);
|
| +}
|
| +
|
| +template <typename L, typename R>
|
| +L* operator-(L* lhs, const StrictNumeric<R> rhs) {
|
| + uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs),
|
| + CheckMul(sizeof(L), static_cast<R>(rhs)))
|
| + .template ValueOrDie<uintptr_t>();
|
| + return reinterpret_cast<L*>(result);
|
| +}
|
| +
|
| } // namespace internal
|
|
|
| using internal::CheckedNumeric;
|
| +using internal::IsValidForType;
|
| +using internal::ValueOrDieForType;
|
| +using internal::ValueOrDefaultForType;
|
| using internal::CheckNum;
|
| using internal::CheckAdd;
|
| using internal::CheckSub;
|
|
|