Chromium Code Reviews| Index: base/numerics/safe_conversions.h |
| diff --git a/base/numerics/safe_conversions.h b/base/numerics/safe_conversions.h |
| index b0ec279eb58551f9f792c18b43949951176083b3..828d523bfd92eac81ac8ae1b60461ec51e07de54 100644 |
| --- a/base/numerics/safe_conversions.h |
| +++ b/base/numerics/safe_conversions.h |
| @@ -15,38 +15,6 @@ |
| namespace base { |
| -// The following are helper constexpr template functions and classes for safely |
| -// performing a range of conversions, assignments, and tests: |
| -// |
| -// checked_cast<> - Analogous to static_cast<> for numeric types, except |
| -// that it CHECKs that the specified numeric conversion will not overflow |
| -// or underflow. NaN source will always trigger a CHECK. |
| -// The default CHECK triggers a crash, but the handler can be overriden. |
| -// saturated_cast<> - Analogous to static_cast<> for numeric types, except |
| -// that it returns a saturated result when the specified numeric conversion |
| -// would otherwise overflow or underflow. An NaN source returns 0 by |
| -// default, but can be overridden to return a different result. |
| -// strict_cast<> - Analogous to static_cast<> for numeric types, except that |
| -// it will cause a compile failure if the destination type is not large |
| -// enough to contain any value in the source type. It performs no runtime |
| -// checking and thus introduces no runtime overhead. |
| -// IsValueInRangeForNumericType<>() - A convenience function that returns true |
| -// if the type supplied to the template parameter can represent the value |
| -// passed as an argument to the function. |
| -// IsValueNegative<>() - A convenience function that will accept any arithmetic |
| -// type as an argument and will return whether the value is less than zero. |
| -// Unsigned types always return false. |
| -// SafeUnsignedAbs() - Returns the absolute value of the supplied integer |
| -// parameter as an unsigned result (thus avoiding an overflow if the value |
| -// is the signed, two's complement minimum). |
| -// StrictNumeric<> - A wrapper type that performs assignments and copies via |
| -// the strict_cast<> template, and can perform valid arithmetic comparisons |
| -// across any range of arithmetic types. StrictNumeric is the return type |
| -// for values extracted from a CheckedNumeric class instance. The raw |
| -// arithmetic value is extracted via static_cast to the underlying type. |
| -// MakeStrictNum() - Creates a new StrictNumeric from the underlying type of |
| -// the supplied arithmetic or StrictNumeric type. |
| - |
| // Convenience function that returns true if the supplied value is in range |
| // for the destination type. |
| template <typename Dst, typename Src> |
| @@ -82,21 +50,45 @@ constexpr Dst checked_cast(Src value) { |
| : CheckHandler::template HandleFailure<Dst>(); |
| } |
| +// as_signed<> returns the supplied integral value (or integral castable |
| +// Numeric template) cast as a signed integral of equivalent precision. |
| +// I.e. it's mostly an alias for: static_cast<std::make_signed<T>::type>(t) |
| +template <typename Src> |
| +constexpr typename std::make_signed< |
| + typename base::internal::UnderlyingType<Src>::type>::type |
| +as_signed(const Src value) { |
| + static_assert(std::is_integral<decltype(as_signed(value))>::value, |
| + "Argument must be a signed or unsigned integer type."); |
| + return static_cast<decltype(as_signed(value))>(value); |
| +} |
| + |
| +// as_unsigned<> returns the supplied integral value (or integral castable |
| +// Numeric template) cast as an unsigned integral of equivalent precision. |
| +// I.e. it's mostly an alias for: static_cast<std::make_unsigned<T>::type>(t) |
| +template <typename Src> |
| +constexpr typename std::make_unsigned< |
| + typename base::internal::UnderlyingType<Src>::type>::type |
| +as_unsigned(const Src value) { |
| + static_assert(std::is_integral<decltype(as_unsigned(value))>::value, |
| + "Argument must be a signed or unsigned integer type."); |
| + return static_cast<decltype(as_unsigned(value))>(value); |
| +} |
| + |
| // Default boundaries for integral/float: max/infinity, lowest/-infinity, 0/NaN. |
| template <typename T> |
| -struct SaturationDefaultHandler { |
| +struct SaturationDefaultLimits : public std::numeric_limits<T> { |
| static constexpr T NaN() { |
| return std::numeric_limits<T>::has_quiet_NaN |
| ? std::numeric_limits<T>::quiet_NaN() |
| : T(); |
| } |
| - static constexpr T max() { return std::numeric_limits<T>::max(); } |
| + // static constexpr T required() is required by the library. |
|
dcheng
2017/06/28 07:25:06
required() => max()?
Also I don't quite understan
jschuh
2017/06/28 12:32:38
D'oh! Typo. But the gist is that you can provide a
|
| static constexpr T Overflow() { |
| return std::numeric_limits<T>::has_infinity |
| ? std::numeric_limits<T>::infinity() |
| : std::numeric_limits<T>::max(); |
| } |
| - static constexpr T lowest() { return std::numeric_limits<T>::lowest(); } |
| + // static constexpr T lowest() is required by the library. |
| static constexpr T Underflow() { |
| return std::numeric_limits<T>::has_infinity |
| ? std::numeric_limits<T>::infinity() * -1 |
| @@ -124,8 +116,7 @@ constexpr Dst saturated_cast_impl(Src value, RangeCheck constraint) { |
| // overflow or underflow, and NaN assignment to an integral will return 0. |
| // All boundary condition behaviors can be overriden with a custom handler. |
| template <typename Dst, |
| - template <typename> |
| - class SaturationHandler = SaturationDefaultHandler, |
| + template <typename> class SaturationHandler = SaturationDefaultLimits, |
| typename Src> |
| constexpr Dst saturated_cast(Src value) { |
| using SrcType = typename UnderlyingType<Src>::type; |
| @@ -238,24 +229,23 @@ std::ostream& operator<<(std::ostream& os, const StrictNumeric<T>& value) { |
| return os; |
| } |
| -#define STRICT_COMPARISON_OP(NAME, OP) \ |
| - template <typename L, typename R, \ |
| - typename std::enable_if< \ |
| - internal::IsStrictOp<L, R>::value>::type* = nullptr> \ |
| - constexpr bool operator OP(const L lhs, const R rhs) { \ |
| - return SafeCompare<NAME, typename UnderlyingType<L>::type, \ |
| - typename UnderlyingType<R>::type>(lhs, rhs); \ |
| +#define BASE_NUMERIC_COMPARISON_OPERATORS(CLASS, NAME, OP) \ |
|
jschuh
2017/06/26 20:26:50
Generalized the implementation so ClampedNumeric c
|
| + template <typename L, typename R, \ |
| + typename std::enable_if< \ |
| + internal::Is##CLASS##Op<L, R>::value>::type* = nullptr> \ |
| + constexpr bool operator OP(const L lhs, const R rhs) { \ |
| + return SafeCompare<NAME, typename UnderlyingType<L>::type, \ |
| + typename UnderlyingType<R>::type>(lhs, rhs); \ |
| } |
| -STRICT_COMPARISON_OP(IsLess, <); |
| -STRICT_COMPARISON_OP(IsLessOrEqual, <=); |
| -STRICT_COMPARISON_OP(IsGreater, >); |
| -STRICT_COMPARISON_OP(IsGreaterOrEqual, >=); |
| -STRICT_COMPARISON_OP(IsEqual, ==); |
| -STRICT_COMPARISON_OP(IsNotEqual, !=); |
| +BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsLess, <); |
| +BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsLessOrEqual, <=); |
| +BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsGreater, >); |
| +BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsGreaterOrEqual, >=); |
| +BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsEqual, ==); |
| +BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsNotEqual, !=); |
| -#undef STRICT_COMPARISON_OP |
| -}; |
| +}; // namespace internal |
| using internal::strict_cast; |
| using internal::saturated_cast; |