Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Unified Diff: base/numerics/safe_conversions.h

Issue 2945433003: Add ClampedNumeric templates (Closed)
Patch Set: more docs and modulus Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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;

Powered by Google App Engine
This is Rietveld 408576698