Index: base/numerics/safe_conversions.h |
diff --git a/base/numerics/safe_conversions.h b/base/numerics/safe_conversions.h |
index 66b278ff3d3e41b3ce33f1d56bea183f12dc7b61..51edac649c8ce59b59509041eec860e1ac2d499a 100644 |
--- a/base/numerics/safe_conversions.h |
+++ b/base/numerics/safe_conversions.h |
@@ -55,6 +55,22 @@ |
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> |
@@ -83,62 +99,62 @@ |
: CheckHandler::template HandleFailure<Dst>(); |
} |
-// 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(); |
+// HandleNaN will return 0 in this case. |
+struct SaturatedCastNaNBehaviorReturnZero { |
+ template <typename T> |
+ static constexpr T HandleFailure() { |
+ return T(); |
} |
}; |
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 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. |
+// 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. |
template <typename Dst, |
- template <typename> |
- class SaturationHandler = SaturatedCastDefaultHandler, |
+ class NaNHandler = SaturatedCastNaNBehaviorReturnZero, |
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 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()); |
+ return internal::saturated_cast_impl<Dst, NaNHandler>( |
+ value, internal::DstRangeRelationToSrcRange<Dst, SrcType>(value)); |
} |
// strict_cast<> is analogous to static_cast<> for numeric types, except that |
@@ -269,7 +285,6 @@ |
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>; |