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; |