| Index: base/numerics/safe_conversions.h
|
| diff --git a/base/numerics/safe_conversions.h b/base/numerics/safe_conversions.h
|
| index 51edac649c8ce59b59509041eec860e1ac2d499a..66b278ff3d3e41b3ce33f1d56bea183f12dc7b61 100644
|
| --- a/base/numerics/safe_conversions.h
|
| +++ b/base/numerics/safe_conversions.h
|
| @@ -55,22 +55,6 @@ constexpr bool IsValueInRangeForNumericType(Src value) {
|
| internal::RANGE_VALID;
|
| }
|
|
|
| -// Convenience function for determining if a numeric value is negative without
|
| -// throwing compiler warnings on: unsigned(value) < 0.
|
| -template <typename T,
|
| - typename std::enable_if<std::is_signed<T>::value>::type* = nullptr>
|
| -constexpr bool IsValueNegative(T value) {
|
| - static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
|
| - return value < 0;
|
| -}
|
| -
|
| -template <typename T,
|
| - typename std::enable_if<!std::is_signed<T>::value>::type* = nullptr>
|
| -constexpr bool IsValueNegative(T) {
|
| - static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
|
| - return false;
|
| -}
|
| -
|
| // Forces a crash, like a CHECK(false). Used for numeric boundary errors.
|
| struct CheckOnFailure {
|
| template <typename T>
|
| @@ -99,62 +83,62 @@ constexpr Dst checked_cast(Src value) {
|
| : CheckHandler::template HandleFailure<Dst>();
|
| }
|
|
|
| -// HandleNaN will return 0 in this case.
|
| -struct SaturatedCastNaNBehaviorReturnZero {
|
| - template <typename T>
|
| - static constexpr T HandleFailure() {
|
| - return T();
|
| +// Default boundaries for integral/float: max/infinity, lowest/-infinity, 0/NaN.
|
| +template <typename T>
|
| +struct SaturatedCastDefaultHandler {
|
| + static constexpr T HandleNaN() {
|
| + 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 HandleOverflow() {
|
| + 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 HandleUnderflow() {
|
| + return std::numeric_limits<T>::has_infinity
|
| + ? std::numeric_limits<T>::infinity() * -1
|
| + : std::numeric_limits<T>::lowest();
|
| }
|
| };
|
|
|
| namespace internal {
|
| -// These wrappers are used for C++11 constexpr support by avoiding both the
|
| -// declaration of local variables and invalid evaluation resulting from the
|
| -// lack of "constexpr if" support in the saturated_cast template function.
|
| -// TODO(jschuh): Convert to single function with a switch once we support C++14.
|
| -template <
|
| - typename Dst,
|
| - class NaNHandler,
|
| - typename Src,
|
| - typename std::enable_if<std::is_integral<Dst>::value>::type* = nullptr>
|
| -constexpr Dst saturated_cast_impl(const Src value,
|
| - const RangeConstraint constraint) {
|
| - return constraint == RANGE_VALID
|
| - ? static_cast<Dst>(value)
|
| - : (constraint == RANGE_UNDERFLOW
|
| - ? std::numeric_limits<Dst>::lowest()
|
| - : (constraint == RANGE_OVERFLOW
|
| - ? std::numeric_limits<Dst>::max()
|
| - : NaNHandler::template HandleFailure<Dst>()));
|
| -}
|
| -
|
| -template <typename Dst,
|
| - class NaNHandler,
|
| - typename Src,
|
| - typename std::enable_if<std::is_floating_point<Dst>::value>::type* =
|
| - nullptr>
|
| -constexpr Dst saturated_cast_impl(const Src value,
|
| - const RangeConstraint constraint) {
|
| - return constraint == RANGE_VALID
|
| - ? static_cast<Dst>(value)
|
| - : (constraint == RANGE_UNDERFLOW
|
| - ? -std::numeric_limits<Dst>::infinity()
|
| - : (constraint == RANGE_OVERFLOW
|
| - ? std::numeric_limits<Dst>::infinity()
|
| - : std::numeric_limits<Dst>::quiet_NaN()));
|
| -}
|
| -
|
| // saturated_cast<> is analogous to static_cast<> for numeric types, except
|
| -// that the specified numeric conversion will saturate rather than overflow or
|
| -// underflow. NaN assignment to an integral will defer the behavior to a
|
| -// specified class. By default, it will return 0.
|
| +// that the specified numeric conversion will saturate by default rather than
|
| +// 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,
|
| - class NaNHandler = SaturatedCastNaNBehaviorReturnZero,
|
| + template <typename>
|
| + class SaturationHandler = SaturatedCastDefaultHandler,
|
| typename Src>
|
| constexpr Dst saturated_cast(Src value) {
|
| + static_assert(
|
| + SaturationHandler<Dst>::lowest() < SaturationHandler<Dst>::max(), "");
|
| + // While this looks like a lot of code, it's all constexpr and all but
|
| + // one variable are compile-time constants (enforced by a static_assert).
|
| + // So, it should evaluate to the minimum number of comparisons required
|
| + // for the range check, which is 0-3, depending on the exact source and
|
| + // destination types, and whatever custom range is specified.
|
| using SrcType = typename UnderlyingType<Src>::type;
|
| - return internal::saturated_cast_impl<Dst, NaNHandler>(
|
| - value, internal::DstRangeRelationToSrcRange<Dst, SrcType>(value));
|
| + return IsGreaterOrEqual<SrcType, Dst>::Test(
|
| + value, NarrowingRange<Dst, SrcType, SaturationHandler>::lowest())
|
| + ? (IsLessOrEqual<SrcType, Dst>::Test(
|
| + value,
|
| + NarrowingRange<Dst, SrcType, SaturationHandler>::max())
|
| + ? static_cast<Dst>(value)
|
| + : SaturationHandler<Dst>::HandleOverflow())
|
| + // This last branch is a little confusing. It's specifically to
|
| + // catch NaN when converting from float to integral.
|
| + : (std::is_integral<SrcType>::value ||
|
| + std::is_floating_point<Dst>::value ||
|
| + IsLessOrEqual<SrcType, Dst>::Test(
|
| + value, NarrowingRange<Dst, SrcType,
|
| + SaturationHandler>::max())
|
| + ? SaturationHandler<Dst>::HandleUnderflow()
|
| + : SaturationHandler<Dst>::HandleNaN());
|
| }
|
|
|
| // strict_cast<> is analogous to static_cast<> for numeric types, except that
|
| @@ -285,6 +269,7 @@ using internal::saturated_cast;
|
| using internal::SafeUnsignedAbs;
|
| using internal::StrictNumeric;
|
| using internal::MakeStrictNum;
|
| +using internal::IsValueNegative;
|
|
|
| // Explicitly make a shorter size_t alias for convenience.
|
| using SizeT = StrictNumeric<size_t>;
|
|
|