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_IMPL_H_ | 5 #ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
7 | 7 |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 #include <stdint.h> | 9 #include <stdint.h> |
10 | 10 |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
198 template <typename T> | 198 template <typename T> |
199 typename std::enable_if<std::numeric_limits<T>::is_integer && | 199 typename std::enable_if<std::numeric_limits<T>::is_integer && |
200 std::numeric_limits<T>::is_signed && | 200 std::numeric_limits<T>::is_signed && |
201 (sizeof(T) * 2 > sizeof(uintmax_t)), | 201 (sizeof(T) * 2 > sizeof(uintmax_t)), |
202 T>::type | 202 T>::type |
203 CheckedMul(T x, T y, RangeConstraint* validity) { | 203 CheckedMul(T x, T y, RangeConstraint* validity) { |
204 // If either side is zero then the result will be zero. | 204 // If either side is zero then the result will be zero. |
205 if (!x || !y) { | 205 if (!x || !y) { |
206 *validity = RANGE_VALID; | 206 *validity = RANGE_VALID; |
207 return static_cast<T>(0); | 207 return static_cast<T>(0); |
208 | 208 } |
209 } else if (x > 0) { | 209 if (x > 0) { |
210 if (y > 0) | 210 if (y > 0) { |
211 *validity = | 211 *validity = |
212 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; | 212 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; |
213 else | 213 } else { |
214 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID | 214 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID |
215 : RANGE_UNDERFLOW; | 215 : RANGE_UNDERFLOW; |
216 | 216 } |
217 } else { | 217 } else { |
218 if (y > 0) | 218 if (y > 0) { |
219 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID | 219 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID |
220 : RANGE_UNDERFLOW; | 220 : RANGE_UNDERFLOW; |
221 else | 221 } else { |
222 *validity = | 222 *validity = |
223 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; | 223 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; |
224 } | |
224 } | 225 } |
jschuh
2016/11/01 17:21:55
Could you move this out to another CL, since it's
| |
225 | |
226 return static_cast<T>(*validity == RANGE_VALID ? x * y : 0); | 226 return static_cast<T>(*validity == RANGE_VALID ? x * y : 0); |
227 } | 227 } |
228 | 228 |
229 template <typename T> | 229 template <typename T> |
230 typename std::enable_if<std::numeric_limits<T>::is_integer && | 230 typename std::enable_if<std::numeric_limits<T>::is_integer && |
231 !std::numeric_limits<T>::is_signed && | 231 !std::numeric_limits<T>::is_signed && |
232 (sizeof(T) * 2 > sizeof(uintmax_t)), | 232 (sizeof(T) * 2 > sizeof(uintmax_t)), |
233 T>::type | 233 T>::type |
234 CheckedMul(T x, T y, RangeConstraint* validity) { | 234 CheckedMul(T x, T y, RangeConstraint* validity) { |
235 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) | 235 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) |
236 ? RANGE_VALID | 236 ? RANGE_VALID |
237 : RANGE_OVERFLOW; | 237 : RANGE_OVERFLOW; |
238 return static_cast<T>(*validity == RANGE_VALID ? x * y : 0); | 238 return static_cast<T>(*validity == RANGE_VALID ? x * y : 0); |
239 } | 239 } |
240 | 240 |
241 // Division just requires a check for an invalid negation on signed min/-1. | 241 // Division just requires a check for a zero denominator or an invalid negation |
242 // on signed min/-1. | |
242 template <typename T> | 243 template <typename T> |
243 T CheckedDiv(T x, | 244 T CheckedDiv(T x, |
244 T y, | 245 T y, |
245 RangeConstraint* validity, | 246 RangeConstraint* validity, |
246 typename std::enable_if<std::numeric_limits<T>::is_integer, | 247 typename std::enable_if<std::numeric_limits<T>::is_integer, |
247 int>::type = 0) { | 248 int>::type = 0) { |
249 if (y == 0) { | |
250 *validity = RANGE_INVALID; | |
251 return static_cast<T>(0); | |
252 } | |
248 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && | 253 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && |
249 y == static_cast<T>(-1)) { | 254 y == static_cast<T>(-1)) { |
250 *validity = RANGE_OVERFLOW; | 255 *validity = RANGE_OVERFLOW; |
251 return std::numeric_limits<T>::min(); | 256 return std::numeric_limits<T>::min(); |
252 } | 257 } |
253 | 258 |
254 *validity = RANGE_VALID; | 259 *validity = RANGE_VALID; |
255 return static_cast<T>(x / y); | 260 return static_cast<T>(x / y); |
256 } | 261 } |
257 | 262 |
258 template <typename T> | 263 template <typename T> |
259 typename std::enable_if<std::numeric_limits<T>::is_integer && | 264 typename std::enable_if<std::numeric_limits<T>::is_integer && |
260 std::numeric_limits<T>::is_signed, | 265 std::numeric_limits<T>::is_signed, |
261 T>::type | 266 T>::type |
262 CheckedMod(T x, T y, RangeConstraint* validity) { | 267 CheckedMod(T x, T y, RangeConstraint* validity) { |
263 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; | 268 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; |
264 return static_cast<T>(*validity == RANGE_VALID ? x % y: 0); | 269 return static_cast<T>(*validity == RANGE_VALID ? x % y: 0); |
265 } | 270 } |
266 | 271 |
267 template <typename T> | 272 template <typename T> |
268 typename std::enable_if<std::numeric_limits<T>::is_integer && | 273 typename std::enable_if<std::numeric_limits<T>::is_integer && |
269 !std::numeric_limits<T>::is_signed, | 274 !std::numeric_limits<T>::is_signed, |
270 T>::type | 275 T>::type |
271 CheckedMod(T x, T y, RangeConstraint* validity) { | 276 CheckedMod(T x, T y, RangeConstraint* validity) { |
272 *validity = RANGE_VALID; | 277 *validity = y != 0 ? RANGE_VALID : RANGE_INVALID; |
273 return static_cast<T>(x % y); | 278 return static_cast<T>(*validity == RANGE_VALID ? x % y: 0); |
274 } | 279 } |
275 | 280 |
276 template <typename T> | 281 template <typename T> |
277 typename std::enable_if<std::numeric_limits<T>::is_integer && | 282 typename std::enable_if<std::numeric_limits<T>::is_integer && |
278 std::numeric_limits<T>::is_signed, | 283 std::numeric_limits<T>::is_signed, |
279 T>::type | 284 T>::type |
280 CheckedNeg(T value, RangeConstraint* validity) { | 285 CheckedNeg(T value, RangeConstraint* validity) { |
281 *validity = | 286 *validity = |
282 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 287 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; |
283 // The negation of signed min is min, so catch that one. | 288 // The negation of signed min is min, so catch that one. |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
523 sizeof(T) >= (2 * sizeof(Lhs)) && | 528 sizeof(T) >= (2 * sizeof(Lhs)) && |
524 StaticDstRangeRelationToSrcRange<T, Rhs>::value != | 529 StaticDstRangeRelationToSrcRange<T, Rhs>::value != |
525 NUMERIC_RANGE_CONTAINED && | 530 NUMERIC_RANGE_CONTAINED && |
526 sizeof(T) >= (2 * sizeof(Rhs)); | 531 sizeof(T) >= (2 * sizeof(Rhs)); |
527 }; | 532 }; |
528 | 533 |
529 } // namespace internal | 534 } // namespace internal |
530 } // namespace base | 535 } // namespace base |
531 | 536 |
532 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 537 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
OLD | NEW |