| 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 SAFE_MATH_IMPL_H_ | 5 #ifndef SAFE_MATH_IMPL_H_ |
| 6 #define SAFE_MATH_IMPL_H_ | 6 #define SAFE_MATH_IMPL_H_ |
| 7 | 7 |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <cmath> | 10 #include <cmath> |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 T>::type | 166 T>::type |
| 167 CheckedMul(T x, T y, RangeConstraint* validity) { | 167 CheckedMul(T x, T y, RangeConstraint* validity) { |
| 168 typedef typename TwiceWiderInteger<T>::type IntermediateType; | 168 typedef typename TwiceWiderInteger<T>::type IntermediateType; |
| 169 IntermediateType tmp = | 169 IntermediateType tmp = |
| 170 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); | 170 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); |
| 171 *validity = DstRangeRelationToSrcRange<T>(tmp); | 171 *validity = DstRangeRelationToSrcRange<T>(tmp); |
| 172 return static_cast<T>(tmp); | 172 return static_cast<T>(tmp); |
| 173 } | 173 } |
| 174 | 174 |
| 175 template <typename T> | 175 template <typename T> |
| 176 typename enable_if<std::numeric_limits<T>::is_integer&& std::numeric_limits< | 176 typename enable_if< |
| 177 T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)), | 177 std::numeric_limits<T>::is_integer && |
| 178 T>::type | 178 std::numeric_limits<T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)), |
| 179 T>::type |
| 179 CheckedMul(T x, T y, RangeConstraint* validity) { | 180 CheckedMul(T x, T y, RangeConstraint* validity) { |
| 180 // if either side is zero then the result will be zero. | 181 // if either side is zero then the result will be zero. |
| 181 if (!(x || y)) { | 182 if (!(x || y)) { |
| 182 return RANGE_VALID; | 183 return RANGE_VALID; |
| 183 | 184 |
| 184 } else if (x > 0) { | 185 } else if (x > 0) { |
| 185 if (y > 0) | 186 if (y > 0) |
| 186 *validity = | 187 *validity = |
| 187 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; | 188 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; |
| 188 else | 189 else |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 225 *validity = RANGE_OVERFLOW; | 226 *validity = RANGE_OVERFLOW; |
| 226 return std::numeric_limits<T>::min(); | 227 return std::numeric_limits<T>::min(); |
| 227 } | 228 } |
| 228 | 229 |
| 229 *validity = RANGE_VALID; | 230 *validity = RANGE_VALID; |
| 230 return x / y; | 231 return x / y; |
| 231 } | 232 } |
| 232 | 233 |
| 233 template <typename T> | 234 template <typename T> |
| 234 typename enable_if< | 235 typename enable_if< |
| 235 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 236 std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed, |
| 236 T>::type | 237 T>::type |
| 237 CheckedMod(T x, T y, RangeConstraint* validity) { | 238 CheckedMod(T x, T y, RangeConstraint* validity) { |
| 238 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; | 239 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; |
| 239 return x % y; | 240 return x % y; |
| 240 } | 241 } |
| 241 | 242 |
| 242 template <typename T> | 243 template <typename T> |
| 243 typename enable_if< | 244 typename enable_if< |
| 244 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 245 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, |
| 245 T>::type | 246 T>::type |
| 246 CheckedMod(T x, T y, RangeConstraint* validity) { | 247 CheckedMod(T x, T y, RangeConstraint* validity) { |
| 247 *validity = RANGE_VALID; | 248 *validity = RANGE_VALID; |
| 248 return x % y; | 249 return x % y; |
| 249 } | 250 } |
| 250 | 251 |
| 251 template <typename T> | 252 template <typename T> |
| 252 typename enable_if< | 253 typename enable_if< |
| 253 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 254 std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed, |
| 254 T>::type | 255 T>::type |
| 255 CheckedNeg(T value, RangeConstraint* validity) { | 256 CheckedNeg(T value, RangeConstraint* validity) { |
| 256 *validity = | 257 *validity = |
| 257 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 258 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; |
| 258 // The negation of signed min is min, so catch that one. | 259 // The negation of signed min is min, so catch that one. |
| 259 return -value; | 260 return -value; |
| 260 } | 261 } |
| 261 | 262 |
| 262 template <typename T> | 263 template <typename T> |
| 263 typename enable_if< | 264 typename enable_if< |
| 264 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 265 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, |
| 265 T>::type | 266 T>::type |
| 266 CheckedNeg(T value, RangeConstraint* validity) { | 267 CheckedNeg(T value, RangeConstraint* validity) { |
| 267 // The only legal unsigned negation is zero. | 268 // The only legal unsigned negation is zero. |
| 268 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; | 269 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; |
| 269 return static_cast<T>( | 270 return static_cast<T>( |
| 270 -static_cast<typename SignedIntegerForSize<T>::type>(value)); | 271 -static_cast<typename SignedIntegerForSize<T>::type>(value)); |
| 271 } | 272 } |
| 272 | 273 |
| 273 template <typename T> | 274 template <typename T> |
| 274 typename enable_if< | 275 typename enable_if< |
| 275 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 276 std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed, |
| 276 T>::type | 277 T>::type |
| 277 CheckedAbs(T value, RangeConstraint* validity) { | 278 CheckedAbs(T value, RangeConstraint* validity) { |
| 278 *validity = | 279 *validity = |
| 279 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 280 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; |
| 280 return std::abs(value); | 281 return std::abs(value); |
| 281 } | 282 } |
| 282 | 283 |
| 283 template <typename T> | 284 template <typename T> |
| 284 typename enable_if< | 285 typename enable_if< |
| 285 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 286 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, |
| 286 T>::type | 287 T>::type |
| 287 CheckedAbs(T value, RangeConstraint* validity) { | 288 CheckedAbs(T value, RangeConstraint* validity) { |
| 288 // Absolute value of a positive is just its identiy. | 289 // Absolute value of a positive is just its identiy. |
| 289 *validity = RANGE_VALID; | 290 *validity = RANGE_VALID; |
| 290 return value; | 291 return value; |
| 291 } | 292 } |
| 292 | 293 |
| 293 // These are the floating point stubs that the compiler needs to see. Only the | 294 // These are the floating point stubs that the compiler needs to see. Only the |
| 294 // negation operation is ever called. | 295 // negation operation is ever called. |
| 295 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ | 296 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ |
| 296 template <typename T> \ | 297 template <typename T> \ |
| 297 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type \ | 298 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type \ |
| 298 Checked##NAME(T, T, RangeConstraint*) { \ | 299 Checked##NAME(T, T, RangeConstraint*) { \ |
| 299 NOTREACHED(); \ | 300 NOTREACHED(); \ |
| 300 return 0; \ | 301 return 0; \ |
| 301 } | 302 } |
| 302 | 303 |
| 303 BASE_FLOAT_ARITHMETIC_STUBS(Add) | 304 BASE_FLOAT_ARITHMETIC_STUBS(Add) |
| 304 BASE_FLOAT_ARITHMETIC_STUBS(Sub) | 305 BASE_FLOAT_ARITHMETIC_STUBS(Sub) |
| 305 BASE_FLOAT_ARITHMETIC_STUBS(Mul) | 306 BASE_FLOAT_ARITHMETIC_STUBS(Mul) |
| 306 BASE_FLOAT_ARITHMETIC_STUBS(Div) | 307 BASE_FLOAT_ARITHMETIC_STUBS(Div) |
| 307 BASE_FLOAT_ARITHMETIC_STUBS(Mod) | 308 BASE_FLOAT_ARITHMETIC_STUBS(Mod) |
| 308 | 309 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 333 | 334 |
| 334 template <typename NumericType> | 335 template <typename NumericType> |
| 335 struct GetNumericRepresentation { | 336 struct GetNumericRepresentation { |
| 336 static const NumericRepresentation value = | 337 static const NumericRepresentation value = |
| 337 std::numeric_limits<NumericType>::is_integer | 338 std::numeric_limits<NumericType>::is_integer |
| 338 ? NUMERIC_INTEGER | 339 ? NUMERIC_INTEGER |
| 339 : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING | 340 : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING |
| 340 : NUMERIC_UNKNOWN); | 341 : NUMERIC_UNKNOWN); |
| 341 }; | 342 }; |
| 342 | 343 |
| 343 template <typename T, NumericRepresentation type = | 344 template <typename T, |
| 344 GetNumericRepresentation<T>::value> | 345 NumericRepresentation type = GetNumericRepresentation<T>::value> |
| 345 class CheckedNumericState {}; | 346 class CheckedNumericState {}; |
| 346 | 347 |
| 347 // Integrals require quite a bit of additional housekeeping to manage state. | 348 // Integrals require quite a bit of additional housekeeping to manage state. |
| 348 template <typename T> | 349 template <typename T> |
| 349 class CheckedNumericState<T, NUMERIC_INTEGER> { | 350 class CheckedNumericState<T, NUMERIC_INTEGER> { |
| 350 private: | 351 private: |
| 351 T value_; | 352 T value_; |
| 352 RangeConstraint validity_; | 353 RangeConstraint validity_; |
| 353 | 354 |
| 354 public: | 355 public: |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 456 | 457 |
| 457 template <typename Lhs, | 458 template <typename Lhs, |
| 458 typename Rhs = Lhs, | 459 typename Rhs = Lhs, |
| 459 ArithmeticPromotionCategory Promotion = | 460 ArithmeticPromotionCategory Promotion = |
| 460 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) | 461 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) |
| 461 ? (MaxExponent<Lhs>::value > MaxExponent<int>::value | 462 ? (MaxExponent<Lhs>::value > MaxExponent<int>::value |
| 462 ? LEFT_PROMOTION | 463 ? LEFT_PROMOTION |
| 463 : DEFAULT_PROMOTION) | 464 : DEFAULT_PROMOTION) |
| 464 : (MaxExponent<Rhs>::value > MaxExponent<int>::value | 465 : (MaxExponent<Rhs>::value > MaxExponent<int>::value |
| 465 ? RIGHT_PROMOTION | 466 ? RIGHT_PROMOTION |
| 466 : DEFAULT_PROMOTION) > | 467 : DEFAULT_PROMOTION) > struct ArithmeticPromotion; |
| 467 struct ArithmeticPromotion; | |
| 468 | 468 |
| 469 template <typename Lhs, typename Rhs> | 469 template <typename Lhs, typename Rhs> |
| 470 struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> { | 470 struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> { |
| 471 typedef Lhs type; | 471 typedef Lhs type; |
| 472 }; | 472 }; |
| 473 | 473 |
| 474 template <typename Lhs, typename Rhs> | 474 template <typename Lhs, typename Rhs> |
| 475 struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> { | 475 struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> { |
| 476 typedef Rhs type; | 476 typedef Rhs type; |
| 477 }; | 477 }; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 493 sizeof(T) >= (2 * sizeof(Lhs)) && | 493 sizeof(T) >= (2 * sizeof(Lhs)) && |
| 494 StaticDstRangeRelationToSrcRange<T, Rhs>::value != | 494 StaticDstRangeRelationToSrcRange<T, Rhs>::value != |
| 495 NUMERIC_RANGE_CONTAINED && | 495 NUMERIC_RANGE_CONTAINED && |
| 496 sizeof(T) >= (2 * sizeof(Rhs)); | 496 sizeof(T) >= (2 * sizeof(Rhs)); |
| 497 }; | 497 }; |
| 498 | 498 |
| 499 } // namespace internal | 499 } // namespace internal |
| 500 } // namespace base | 500 } // namespace base |
| 501 | 501 |
| 502 #endif // SAFE_MATH_IMPL_H_ | 502 #endif // SAFE_MATH_IMPL_H_ |
| OLD | NEW |