Index: base/numerics/safe_conversions_impl.h |
diff --git a/base/numerics/safe_conversions_impl.h b/base/numerics/safe_conversions_impl.h |
index 5ef3321474e5d2ac83777dc1f3210cf7f0af59ad..c4d96365ff4d71d96ceffa739fc02dccff868c3f 100644 |
--- a/base/numerics/safe_conversions_impl.h |
+++ b/base/numerics/safe_conversions_impl.h |
@@ -48,36 +48,6 @@ |
template <typename T> |
constexpr T BinaryComplement(T x) { |
return static_cast<T>(~x); |
-} |
- |
-// Determines 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; |
-} |
- |
-// This performs a fast negation, returning a signed value. It works on unsigned |
-// arguments, but probably doesn't do what you want for any unsigned value |
-// larger than max / 2 + 1 (i.e. signed min cast to unsigned). |
-template <typename T> |
-constexpr typename std::make_signed<T>::type ConditionalNegate( |
- T x, |
- bool is_negative) { |
- static_assert(std::is_integral<T>::value, "Type must be integral"); |
- using SignedT = typename std::make_signed<T>::type; |
- using UnsignedT = typename std::make_unsigned<T>::type; |
- return static_cast<SignedT>( |
- (static_cast<UnsignedT>(x) ^ -SignedT(is_negative)) + is_negative); |
} |
// This performs a safe, non-branching absolute value via unsigned overflow. |
@@ -211,44 +181,28 @@ |
// To fix this bug we manually truncate the maximum value when the destination |
// type is an integral of larger precision than the source floating-point type, |
// such that the resulting maximum is represented exactly as a floating point. |
-template <typename Dst, |
- typename Src, |
- template <typename> class Bounds = std::numeric_limits> |
+template <typename Dst, typename Src> |
struct NarrowingRange { |
using SrcLimits = typename std::numeric_limits<Src>; |
using DstLimits = typename std::numeric_limits<Dst>; |
- |
- // Computes the mask required to make an accurate comparison between types. |
- static const int kShift = |
- (MaxExponent<Src>::value > MaxExponent<Dst>::value && |
- SrcLimits::digits < DstLimits::digits) |
- ? (DstLimits::digits - SrcLimits::digits) |
- : 0; |
- template < |
- typename T, |
- typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> |
- |
- // Masks out the integer bits that are beyond the precision of the |
- // intermediate type used for comparison. |
- static constexpr T Adjust(T value) { |
- static_assert(std::is_same<T, Dst>::value, ""); |
- static_assert(kShift < DstLimits::digits, ""); |
- return static_cast<T>( |
- ConditionalNegate(SafeUnsignedAbs(value) & ~((T(1) << kShift) - T(1)), |
- IsValueNegative(value))); |
- } |
- |
- template <typename T, |
- typename std::enable_if<std::is_floating_point<T>::value>::type* = |
- nullptr> |
- static constexpr T Adjust(T value) { |
- static_assert(std::is_same<T, Dst>::value, ""); |
- static_assert(kShift == 0, ""); |
- return value; |
- } |
- |
- static constexpr Dst max() { return Adjust(Bounds<Dst>::max()); } |
- static constexpr Dst lowest() { return Adjust(Bounds<Dst>::lowest()); } |
+ // The following logic avoids warnings where the max function is |
+ // instantiated with invalid values for a bit shift (even though |
+ // such a function can never be called). |
+ static const int shift = (MaxExponent<Src>::value > MaxExponent<Dst>::value && |
+ SrcLimits::digits < DstLimits::digits && |
+ SrcLimits::is_iec559 && |
+ DstLimits::is_integer) |
+ ? (DstLimits::digits - SrcLimits::digits) |
+ : 0; |
+ |
+ static constexpr Dst max() { |
+ // We use UINTMAX_C below to avoid compiler warnings about shifting floating |
+ // points. Since it's a compile time calculation, it shouldn't have any |
+ // performance impact. |
+ return DstLimits::max() - static_cast<Dst>((UINTMAX_C(1) << shift) - 1); |
+ } |
+ |
+ static constexpr Dst lowest() { return DstLimits::lowest(); } |
}; |
template <typename Dst, |