Chromium Code Reviews| 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 |