| 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 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> | 120 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> |
| 121 PositionOfSignBit<T>::value); | 121 PositionOfSignBit<T>::value); |
| 122 } | 122 } |
| 123 | 123 |
| 124 // This wrapper undoes the standard integer promotions. | 124 // This wrapper undoes the standard integer promotions. |
| 125 template <typename T> | 125 template <typename T> |
| 126 constexpr T BinaryComplement(T x) { | 126 constexpr T BinaryComplement(T x) { |
| 127 return static_cast<T>(~x); | 127 return static_cast<T>(~x); |
| 128 } | 128 } |
| 129 | 129 |
| 130 // Return if a numeric value is negative regardless of type. |
| 131 template <typename T, |
| 132 typename std::enable_if<std::is_arithmetic<T>::value && |
| 133 std::is_signed<T>::value>::type* = nullptr> |
| 134 constexpr bool IsNegative(T x) { |
| 135 return x < 0; |
| 136 } |
| 137 |
| 138 template <typename T, |
| 139 typename std::enable_if<std::is_arithmetic<T>::value && |
| 140 !std::is_signed<T>::value>::type* = nullptr> |
| 141 constexpr bool IsNegative(T x) { |
| 142 return false; |
| 143 } |
| 144 |
| 130 enum ArithmeticPromotionCategory { | 145 enum ArithmeticPromotionCategory { |
| 131 LEFT_PROMOTION, // Use the type of the left-hand argument. | 146 LEFT_PROMOTION, // Use the type of the left-hand argument. |
| 132 RIGHT_PROMOTION, // Use the type of the right-hand argument. | 147 RIGHT_PROMOTION, // Use the type of the right-hand argument. |
| 133 MAX_EXPONENT_PROMOTION, // Use the type supporting the largest exponent. | 148 MAX_EXPONENT_PROMOTION, // Use the type supporting the largest exponent. |
| 134 BIG_ENOUGH_PROMOTION // Attempt to find a big enough type. | 149 BIG_ENOUGH_PROMOTION // Attempt to find a big enough type. |
| 135 }; | 150 }; |
| 136 | 151 |
| 137 template <ArithmeticPromotionCategory Promotion, | 152 template <ArithmeticPromotionCategory Promotion, |
| 138 typename Lhs, | 153 typename Lhs, |
| 139 typename Rhs = Lhs> | 154 typename Rhs = Lhs> |
| (...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 CheckedMod(T x, U y, V* result) { | 470 CheckedMod(T x, U y, V* result) { |
| 456 using Promotion = | 471 using Promotion = |
| 457 typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; | 472 typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; |
| 458 Promotion presult; | 473 Promotion presult; |
| 459 bool is_valid = CheckedModImpl(static_cast<Promotion>(x), | 474 bool is_valid = CheckedModImpl(static_cast<Promotion>(x), |
| 460 static_cast<Promotion>(y), &presult); | 475 static_cast<Promotion>(y), &presult); |
| 461 *result = static_cast<V>(presult); | 476 *result = static_cast<V>(presult); |
| 462 return is_valid && IsValueInRangeForNumericType<V>(presult); | 477 return is_valid && IsValueInRangeForNumericType<V>(presult); |
| 463 } | 478 } |
| 464 | 479 |
| 480 // Left shift. Shifts less than 0 or greater than or equal to the number |
| 481 // of bits in the promoted type are undefined. Shifts of negative values |
| 482 // are undefined. Otherwise it is defined when the result fits. |
| 483 template <typename T, typename U, typename V> |
| 484 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 485 std::numeric_limits<U>::is_integer && |
| 486 std::numeric_limits<V>::is_integer, |
| 487 bool>::type |
| 488 CheckedLeftShift(T x, U shift, V* result) { |
| 489 using ShiftType = typename UnsignedIntegerForSize<T>::type; |
| 490 static const ShiftType kBitWidth = CHAR_BIT * sizeof(T); |
| 491 const ShiftType real_shift = static_cast<ShiftType>(shift); |
| 492 // Signed shift is not legal on negative values. |
| 493 if (!IsNegative(x) && real_shift < kBitWidth) { |
| 494 // Just use a multiplication because it's easy. |
| 495 // TODO(jschuh): This could probably be made more efficient. |
| 496 if (!std::is_signed<T>::value || real_shift != kBitWidth - 1) |
| 497 return CheckedMul(x, static_cast<T>(1) << shift, result); |
| 498 return !x; // Special case zero for a full width signed shift. |
| 499 } |
| 500 return false; |
| 501 } |
| 502 |
| 503 // Right shift. Shifts less than 0 or greater than or equal to the number |
| 504 // of bits in the promoted type are undefined. Otherwise, it is always defined, |
| 505 // but a right shift of a negative value is implementation-dependent. |
| 506 template <typename T, typename U, typename V> |
| 507 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 508 std::numeric_limits<U>::is_integer && |
| 509 std::numeric_limits<V>::is_integer, |
| 510 bool>::type |
| 511 CheckedRightShift(T x, U shift, V* result) { |
| 512 // Use the type conversion push negative values out of range. |
| 513 using ShiftType = typename UnsignedIntegerForSize<T>::type; |
| 514 if (static_cast<ShiftType>(shift) < (CHAR_BIT * sizeof(T))) { |
| 515 T tmp = x >> shift; |
| 516 *result = static_cast<V>(tmp); |
| 517 return IsValueInRangeForNumericType<unsigned>(tmp); |
| 518 } |
| 519 return false; |
| 520 } |
| 521 |
| 465 template <typename T> | 522 template <typename T> |
| 466 typename std::enable_if<std::numeric_limits<T>::is_integer && | 523 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 467 std::numeric_limits<T>::is_signed, | 524 std::numeric_limits<T>::is_signed, |
| 468 bool>::type | 525 bool>::type |
| 469 CheckedNeg(T value, T* result) { | 526 CheckedNeg(T value, T* result) { |
| 470 // The negation of signed min is min, so catch that one. | 527 // The negation of signed min is min, so catch that one. |
| 471 if (value != std::numeric_limits<T>::min()) { | 528 if (value != std::numeric_limits<T>::min()) { |
| 472 *result = static_cast<T>(-value); | 529 *result = static_cast<T>(-value); |
| 473 return true; | 530 return true; |
| 474 } | 531 } |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 675 : value_(static_cast<T>(rhs.value())) {} | 732 : value_(static_cast<T>(rhs.value())) {} |
| 676 | 733 |
| 677 bool is_valid() const { return std::isfinite(value_); } | 734 bool is_valid() const { return std::isfinite(value_); } |
| 678 T value() const { return value_; } | 735 T value() const { return value_; } |
| 679 }; | 736 }; |
| 680 | 737 |
| 681 } // namespace internal | 738 } // namespace internal |
| 682 } // namespace base | 739 } // namespace base |
| 683 | 740 |
| 684 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 741 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
| OLD | NEW |