OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef BASE_NUMERICS_SAFE_MATH_H_ | 5 #ifndef BASE_NUMERICS_SAFE_MATH_H_ |
6 #define BASE_NUMERICS_SAFE_MATH_H_ | 6 #define BASE_NUMERICS_SAFE_MATH_H_ |
7 | 7 |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 | 9 |
10 #include <limits> | 10 #include <limits> |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 T ValueUnsafe() const { return state_.value(); } | 112 T ValueUnsafe() const { return state_.value(); } |
113 | 113 |
114 // Prototypes for the supported arithmetic operator overloads. | 114 // Prototypes for the supported arithmetic operator overloads. |
115 template <typename Src> CheckedNumeric& operator+=(Src rhs); | 115 template <typename Src> CheckedNumeric& operator+=(Src rhs); |
116 template <typename Src> CheckedNumeric& operator-=(Src rhs); | 116 template <typename Src> CheckedNumeric& operator-=(Src rhs); |
117 template <typename Src> CheckedNumeric& operator*=(Src rhs); | 117 template <typename Src> CheckedNumeric& operator*=(Src rhs); |
118 template <typename Src> CheckedNumeric& operator/=(Src rhs); | 118 template <typename Src> CheckedNumeric& operator/=(Src rhs); |
119 template <typename Src> CheckedNumeric& operator%=(Src rhs); | 119 template <typename Src> CheckedNumeric& operator%=(Src rhs); |
120 | 120 |
121 CheckedNumeric operator-() const { | 121 CheckedNumeric operator-() const { |
122 bool is_valid; | |
123 T value = CheckedNeg(state_.value(), &is_valid); | |
124 // Negation is always valid for floating point. | 122 // Negation is always valid for floating point. |
125 if (std::numeric_limits<T>::is_iec559) | 123 T value = 0; |
126 return CheckedNumeric<T>(value); | 124 bool is_valid = (std::numeric_limits<T>::is_iec559 || IsValid()) && |
127 | 125 CheckedNeg(state_.value(), &value); |
128 is_valid &= state_.is_valid(); | |
129 return CheckedNumeric<T>(value, is_valid); | 126 return CheckedNumeric<T>(value, is_valid); |
130 } | 127 } |
131 | 128 |
132 CheckedNumeric Abs() const { | 129 CheckedNumeric Abs() const { |
133 bool is_valid; | |
134 T value = CheckedAbs(state_.value(), &is_valid); | |
135 // Absolute value is always valid for floating point. | 130 // Absolute value is always valid for floating point. |
136 if (std::numeric_limits<T>::is_iec559) | 131 T value = 0; |
137 return CheckedNumeric<T>(value); | 132 bool is_valid = (std::numeric_limits<T>::is_iec559 || IsValid()) && |
138 | 133 CheckedAbs(state_.value(), &value); |
139 is_valid &= state_.is_valid(); | |
140 return CheckedNumeric<T>(value, is_valid); | 134 return CheckedNumeric<T>(value, is_valid); |
141 } | 135 } |
142 | 136 |
143 // This function is available only for integral types. It returns an unsigned | 137 // This function is available only for integral types. It returns an unsigned |
144 // integer of the same width as the source type, containing the absolute value | 138 // integer of the same width as the source type, containing the absolute value |
145 // of the source, and properly handling signed min. | 139 // of the source, and properly handling signed min. |
146 CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> UnsignedAbs() const { | 140 CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> UnsignedAbs() const { |
147 return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>( | 141 return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>( |
148 CheckedUnsignedAbs(state_.value()), state_.is_valid()); | 142 SafeUnsignedAbs(state_.value()), state_.is_valid()); |
149 } | 143 } |
150 | 144 |
151 CheckedNumeric& operator++() { | 145 CheckedNumeric& operator++() { |
152 *this += 1; | 146 *this += 1; |
153 return *this; | 147 return *this; |
154 } | 148 } |
155 | 149 |
156 CheckedNumeric operator++(int) { | 150 CheckedNumeric operator++(int) { |
157 CheckedNumeric value = *this; | 151 CheckedNumeric value = *this; |
158 *this += 1; | 152 *this += 1; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 // TODO(jschuh): extract these out into templates. | 207 // TODO(jschuh): extract these out into templates. |
214 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ | 208 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ |
215 /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ | 209 /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ |
216 template <typename T> \ | 210 template <typename T> \ |
217 CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP( \ | 211 CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP( \ |
218 const CheckedNumeric<T>& lhs, const CheckedNumeric<T>& rhs) { \ | 212 const CheckedNumeric<T>& lhs, const CheckedNumeric<T>& rhs) { \ |
219 typedef typename ArithmeticPromotion<T>::type Promotion; \ | 213 typedef typename ArithmeticPromotion<T>::type Promotion; \ |
220 /* Floating point always takes the fast path */ \ | 214 /* Floating point always takes the fast path */ \ |
221 if (std::numeric_limits<T>::is_iec559) \ | 215 if (std::numeric_limits<T>::is_iec559) \ |
222 return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \ | 216 return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \ |
| 217 if (!rhs.IsValid() || !lhs.IsValid()) \ |
| 218 return CheckedNumeric<Promotion>(0, false); \ |
223 if (IsIntegerArithmeticSafe<Promotion, T, T>::value) \ | 219 if (IsIntegerArithmeticSafe<Promotion, T, T>::value) \ |
224 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ | 220 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() \ |
225 rhs.IsValid() && lhs.IsValid()); \ | 221 OP rhs.ValueUnsafe()); \ |
226 bool is_valid = true; \ | 222 Promotion result = 0; \ |
227 T result = static_cast<T>( \ | 223 bool is_valid = \ |
228 Checked##NAME(static_cast<Promotion>(lhs.ValueUnsafe()), \ | 224 Checked##NAME(static_cast<Promotion>(lhs.ValueUnsafe()), \ |
229 static_cast<Promotion>(rhs.ValueUnsafe()), &is_valid)); \ | 225 static_cast<Promotion>(rhs.ValueUnsafe()), &result); \ |
230 return CheckedNumeric<Promotion>( \ | 226 return CheckedNumeric<Promotion>(result, is_valid); \ |
231 result, is_valid && lhs.IsValid() && rhs.IsValid()); \ | |
232 } \ | 227 } \ |
233 /* Assignment arithmetic operator implementation from CheckedNumeric. */ \ | 228 /* Assignment arithmetic operator implementation from CheckedNumeric. */ \ |
234 template <typename T> \ | 229 template <typename T> \ |
235 template <typename Src> \ | 230 template <typename Src> \ |
236 CheckedNumeric<T>& CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) { \ | 231 CheckedNumeric<T>& CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) { \ |
237 *this = CheckedNumeric<T>::cast(*this) \ | 232 *this = CheckedNumeric<T>::cast(*this) \ |
238 OP CheckedNumeric<typename UnderlyingType<Src>::type>::cast(rhs); \ | 233 OP CheckedNumeric<typename UnderlyingType<Src>::type>::cast(rhs); \ |
239 return *this; \ | 234 return *this; \ |
240 } \ | 235 } \ |
241 /* Binary arithmetic operator for CheckedNumeric of different type. */ \ | 236 /* Binary arithmetic operator for CheckedNumeric of different type. */ \ |
242 template <typename T, typename Src> \ | 237 template <typename T, typename Src> \ |
243 CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ | 238 CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ |
244 const CheckedNumeric<Src>& lhs, const CheckedNumeric<T>& rhs) { \ | 239 const CheckedNumeric<Src>& lhs, const CheckedNumeric<T>& rhs) { \ |
245 typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ | 240 typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ |
| 241 if (!rhs.IsValid() || !lhs.IsValid()) \ |
| 242 return CheckedNumeric<Promotion>(0, false); \ |
246 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ | 243 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ |
247 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ | 244 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe());\ |
248 rhs.IsValid() && lhs.IsValid()); \ | |
249 return CheckedNumeric<Promotion>::cast(lhs) \ | 245 return CheckedNumeric<Promotion>::cast(lhs) \ |
250 OP CheckedNumeric<Promotion>::cast(rhs); \ | 246 OP CheckedNumeric<Promotion>::cast(rhs); \ |
251 } \ | 247 } \ |
252 /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ | 248 /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ |
253 template <typename T, typename Src, \ | 249 template <typename T, typename Src, \ |
254 typename std::enable_if<std::is_arithmetic<Src>::value>::type* = \ | 250 typename std::enable_if<std::is_arithmetic<Src>::value>::type* = \ |
255 nullptr> \ | 251 nullptr> \ |
256 CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ | 252 CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ |
257 const CheckedNumeric<T>& lhs, Src rhs) { \ | 253 const CheckedNumeric<T>& lhs, Src rhs) { \ |
258 typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ | 254 typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ |
(...skipping 25 matching lines...) Expand all Loading... |
284 | 280 |
285 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS | 281 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS |
286 | 282 |
287 } // namespace internal | 283 } // namespace internal |
288 | 284 |
289 using internal::CheckedNumeric; | 285 using internal::CheckedNumeric; |
290 | 286 |
291 } // namespace base | 287 } // namespace base |
292 | 288 |
293 #endif // BASE_NUMERICS_SAFE_MATH_H_ | 289 #endif // BASE_NUMERICS_SAFE_MATH_H_ |
OLD | NEW |