Index: base/numerics/safe_math.h |
diff --git a/base/numerics/safe_math.h b/base/numerics/safe_math.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..cb5c80c2c0e9fa298395331f8c986eeed8c5cdd2 |
--- /dev/null |
+++ b/base/numerics/safe_math.h |
@@ -0,0 +1,264 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef BASE_SAFE_MATH_H_ |
+#define BASE_SAFE_MATH_H_ |
+ |
+#include "base/numerics/safe_math_impl.h" |
+ |
+namespace base { |
+ |
+namespace internal { |
+ |
+// CheckedNumeric implements all the logic and operators for detecting integer |
+// boundary conditions such as overflow, underflow, and invalid conversions. |
+// The CheckedNumeric type implicitly converts from floating point and integer |
+// dat types, and contains overloads for basic arithmetic operations (i.e.: +, |
Ryan Sleevi
2014/02/10 23:42:41
typo: data
jschuh
2014/02/11 00:43:28
Done.
|
+// -, *, /, %). |
+// |
+// The following methods convert from CheckedNumeric to standard numeric values: |
+// IsValid() - Returns true if the underlying numeric value is valid (i.e. has |
+// has not wrapped and is not the result of an invalid conversion). |
+// ValueOrDie() - Returns the underlying value. If the state is not valid this |
+// call will crash on a CHECK. |
+// ValueOrDefault() - Returns the current value, or the supplied default if the |
+// state is not valid. |
+// ValueFloating() - Returns the underlying floating point value (valid only |
+// only for floating point CheckedNumeric types). |
+// |
+// Bitwise operations are explicitly not supported, because correct |
+// handling of some cases (e.g. sign manipulation) is ambiguous. Comparison |
+// operations are explicitly not supported because they could result in a crash |
+// on a CHECK condition. You should use patterns like the following for these |
+// operations: |
+// Bitwise operation: |
+// int x = checked_int.ValueOrDefault(0) | kFlagValues; |
+// Comparison: |
+// if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size) |
+// Do stuff... |
+template <typename T> |
+class CheckedNumeric { |
+ private: |
+ CheckedNumericState<T> state_; |
+ |
+ public: |
+ typedef T type; |
+ template <typename Src> |
+ friend class CheckedNumeric; |
Ryan Sleevi
2014/02/10 23:42:41
Does this actually work? I didn't think generic fr
jschuh
2014/02/11 00:43:28
Yep, works correct in msvc, gcc, and clang.
|
+ |
+ CheckedNumeric() {} |
+ |
+ // Copy constructor. |
+ template <typename Src> |
+ CheckedNumeric(const CheckedNumeric<Src>& rhs) : |
+ state_(rhs.state_.value(), rhs.state_.validity()) {} |
Ryan Sleevi
2014/02/10 23:42:41
git-cl-format this
CheckedNumeric(const CheckedNu
jschuh
2014/02/11 00:43:28
Done.
|
+ |
+ template <typename Src> |
+ CheckedNumeric(Src value, RangeCheckId validity) : state_(value, validity) {} |
+ |
+ // This is not an explicit constructor because we implicitly upgrade regular |
+ // numerics to CheckedNumerics to make them easier to use. |
+ template <typename Src> |
+ CheckedNumeric(Src value) : state_(value) { |
+ COMPILE_ASSERT(numeric_limits<Src>::is_specialized, |
+ argument_must_be_numeric); |
+ } |
+ |
+ // validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for |
+ // tests and to avoid a big matrix of friend operator overloads. But the |
+ // values it returns are likely to change in the future. |
+ // Returns: current validity state (i.e. valid, overflow, underflow, nan). |
+ // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for |
+ // saturation/wrapping so we can expose this state consistently and implement |
+ // saturated arithmetic. |
+ RangeCheckId validity() const { return state_.validity(); } |
Ryan Sleevi
2014/02/10 23:42:41
if it's only for tests, you can call it validity()
jschuh
2014/02/11 00:43:28
So... that doesn't solve the nasty mess of friend
|
+ |
+ // IsValid() is the public API to test if a CheckedNumeric is currently valid. |
+ bool IsValid() const { return validity() == TYPE_VALID; } |
+ |
+ // ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now |
+ // for tests and to avoid a big matrix of friend operator overloads. But the |
+ // values it returns are likely to change in the future. |
+ // Returns: the raw numeric value, regardless of the current state. |
+ // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for |
+ // saturation/wrapping so we can expose this state consistently and implement |
+ // saturated arithmetic. |
+ T ValueUnsafe() const { return state_.value(); } |
Ryan Sleevi
2014/02/10 23:42:41
Ditto
|
+ |
+ // ValueOrDie() The primary accessor for the underlying value. If the current |
+ // state is not valid it will CHECK and crash. |
+ T ValueOrDie() const { |
+ CHECK(IsValid()); |
+ return state_.value(); |
+ } |
+ |
+ // ValueOrDefault(T default_value) A convenience method that returns the |
+ // current value if the state is valid, and the supplied default_value for |
+ // any other state. |
+ T ValueOrDefault(T default_value) const { |
+ return IsValid() ? state_.value() : default_value; |
+ } |
+ |
+ // ValueFloating() - Since floating point values include their validity state, |
+ // we provide an easy method for extracting them directly, without a risk of |
+ // crashing on a CHECK. |
+ T ValueFloating() { |
+ COMPILE_ASSERT(numeric_limits<T>::is_iec559, argument_must_be_float); |
+ return CheckedNumeric<T>::cast(*this).ValueUnsafe(); |
+ } |
+ |
+ // Prototypes for the supported arithmetic operator overloads. |
+ template <typename Src> CheckedNumeric& operator +=(Src rhs); |
+ template <typename Src> CheckedNumeric& operator -=(Src rhs); |
+ template <typename Src> CheckedNumeric& operator *=(Src rhs); |
+ template <typename Src> CheckedNumeric& operator /=(Src rhs); |
+ template <typename Src> CheckedNumeric& operator %=(Src rhs); |
+ |
+ CheckedNumeric operator -() const { |
+ RangeCheckId validity; |
+ T value = CheckedNeg(state_.value(), &validity); |
+ // Negation is always valid for floating point. |
+ if (numeric_limits<T>::is_iec559) |
+ return CheckedNumeric<T>(value); |
+ |
+ validity = static_cast<RangeCheckId>(state_.validity() | validity); |
+ return CheckedNumeric<T>(value, validity); |
+ } |
+ |
+ CheckedNumeric Abs() const { |
+ RangeCheckId validity; |
+ T value = CheckedAbs(state_.value(), &validity); |
+ // Absolute value is always valid for floating point. |
+ if (numeric_limits<T>::is_iec559) |
+ return CheckedNumeric<T>(value); |
+ |
+ validity = static_cast<RangeCheckId>(state_.validity() | validity); |
+ return CheckedNumeric<T>(value, validity); |
+ } |
+ |
+ CheckedNumeric& operator++() { |
+ *this += 1; |
+ return *this; |
+ } |
+ |
+ CheckedNumeric operator++(int) { |
+ CheckedNumeric value = *this; |
+ *this += 1; |
+ return value; |
+ } |
+ |
+ CheckedNumeric& operator--() { |
+ *this -= 1; |
+ return *this; |
+ } |
+ |
+ CheckedNumeric operator--(int) { |
+ CheckedNumeric value = *this; |
+ *this -= 1; |
+ return value; |
+ } |
+ |
+ // These static methods behave like a convenience cast operator targeting |
+ // the desired CheckedNumeric type. As an optimization, a reference is |
+ // returned when Src is the same type as T. |
+ template <typename Src> |
+ static CheckedNumeric<T> cast(Src u, |
+ typename enable_if<numeric_limits<Src>::is_specialized, int>::type = 0) { |
+ return u; |
+ } |
+ |
+ template <typename Src> |
+ static CheckedNumeric<T> cast(const CheckedNumeric<Src>& u, |
+ typename enable_if<!is_same<Src, T>::value, int>::type = 0) { |
+ return u; |
+ } |
+ |
+ static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { |
+ return u; |
+ } |
+}; |
+ |
+// This is the boilerplate for the standard arithmetic operator overloads. A |
+// macro isn't the prettiest solution, but it beats rewriting these five times. |
+// Some details worth noting are: |
+// * We apply the standard arithmetic promotions. |
+// * We skip range checks for floating points. |
+// * We skip range checks for destination integers with sufficient range. |
+#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME,OP,COMPOUND_OP) \ |
+/* Binary arithmetic operator for CheckedNumerics of the same type. */ \ |
+template <typename T> \ |
+CheckedNumeric<typename ArithmeticPromotion<T>::type> \ |
+operator OP(const CheckedNumeric<T> &lhs, const CheckedNumeric<T> &rhs) { \ |
+ typedef typename ArithmeticPromotion<T>::type Promotion; \ |
+ /* Floating point always takes the fast path */ \ |
+ if (numeric_limits<T>::is_iec559) \ |
+ return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \ |
+ if (IsIntegerArithmeticSafe<Promotion, T, T>::value) \ |
+ return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ |
+ static_cast<RangeCheckId>(rhs.validity() | lhs.validity())); \ |
+ RangeCheckId validity = TYPE_VALID; \ |
+ T result = \ |
+ Checked##NAME(static_cast<Promotion>(lhs.ValueUnsafe()), \ |
+ static_cast<Promotion>(rhs.ValueUnsafe()), &validity); \ |
+ return CheckedNumeric<Promotion>(result, static_cast<RangeCheckId>( \ |
+ validity | lhs.validity() | rhs.validity())); \ |
+} \ |
+/* Assignment arithmetic operator implementation from CheckedNumeric above. */ \ |
+template <typename T> \ |
+template <typename Src> \ |
+CheckedNumeric<T>& \ |
+CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) { \ |
+ *this = CheckedNumeric<T>::cast(*this) OP CheckedNumeric<Src>::cast(rhs); \ |
+ return *this; \ |
+} \ |
+/* Binary arithmetic operator for CheckedNumeric of different type. */ \ |
+template <typename T, typename Src> \ |
+CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> \ |
+operator OP(const CheckedNumeric<Src> &lhs, const CheckedNumeric<T> &rhs) { \ |
+ typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ |
+ if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ |
+ return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ |
+ static_cast<RangeCheckId>(rhs.validity() | lhs.validity())); \ |
+ return CheckedNumeric<Promotion>::cast(lhs) OP \ |
+ CheckedNumeric<Promotion>::cast(rhs); \ |
+} \ |
+/* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ |
+template <typename T, typename Src> \ |
+CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> \ |
+operator OP(const CheckedNumeric<T> &lhs, Src rhs) { \ |
+ typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ |
+ if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ |
+ return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP \ |
+ rhs, lhs.validity()); \ |
+ return CheckedNumeric<Promotion>::cast(lhs) OP \ |
+ CheckedNumeric<Promotion>::cast(rhs); \ |
+} \ |
+/* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \ |
+template <typename T, typename Src> \ |
+CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> \ |
+operator OP(Src lhs, const CheckedNumeric<T> &rhs) { \ |
+ typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ |
+ if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ |
+ return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(), \ |
+ rhs.validity()); \ |
+ return CheckedNumeric<Promotion>::cast(lhs) OP \ |
+ CheckedNumeric<Promotion>::cast(rhs); \ |
+} |
+ |
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=) |
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=) |
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *=) |
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=) |
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=) |
+ |
+#undef BASE_NUMERIC_ARITHMETIC_OPERATORS |
+ |
+} // namespace internal |
+ |
+using internal::CheckedNumeric; |
+ |
+} // namespace base |
+ |
+#endif // BASE_SAFE_MATH_H_ |
+ |