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 24 matching lines...) Expand all Loading... | |
| 35 template <typename Numeric> | 35 template <typename Numeric> |
| 36 struct UnsignedOrFloatForSize<Numeric, true, false> { | 36 struct UnsignedOrFloatForSize<Numeric, true, false> { |
| 37 using type = typename std::make_unsigned<Numeric>::type; | 37 using type = typename std::make_unsigned<Numeric>::type; |
| 38 }; | 38 }; |
| 39 | 39 |
| 40 template <typename Numeric> | 40 template <typename Numeric> |
| 41 struct UnsignedOrFloatForSize<Numeric, false, true> { | 41 struct UnsignedOrFloatForSize<Numeric, false, true> { |
| 42 using type = Numeric; | 42 using type = Numeric; |
| 43 }; | 43 }; |
| 44 | 44 |
| 45 // Helper templates for integer manipulations. | |
| 46 | |
| 47 template <typename T> | |
| 48 constexpr bool HasSignBit(T x) { | |
| 49 // Cast to unsigned since right shift on signed is undefined. | |
| 50 return !!(static_cast<typename std::make_unsigned<T>::type>(x) >> | |
| 51 PositionOfSignBit<T>::value); | |
| 52 } | |
| 53 | |
| 54 // This wrapper undoes the standard integer promotions. | |
| 55 template <typename T> | |
| 56 constexpr T BinaryComplement(T x) { | |
| 57 return static_cast<T>(~x); | |
| 58 } | |
| 59 | |
| 60 // Probe for builtin math overflow support on Clang and version check on GCC. | 45 // Probe for builtin math overflow support on Clang and version check on GCC. |
| 61 #if defined(__has_builtin) | 46 #if defined(__has_builtin) |
| 62 #define USE_OVERFLOW_BUILTINS (__has_builtin(__builtin_add_overflow)) | 47 #define USE_OVERFLOW_BUILTINS (__has_builtin(__builtin_add_overflow)) |
| 63 #elif defined(__GNUC__) | 48 #elif defined(__GNUC__) |
| 64 #define USE_OVERFLOW_BUILTINS (__GNUC__ >= 5) | 49 #define USE_OVERFLOW_BUILTINS (__GNUC__ >= 5) |
| 65 #else | 50 #else |
| 66 #define USE_OVERFLOW_BUILTINS (0) | 51 #define USE_OVERFLOW_BUILTINS (0) |
| 67 #endif | 52 #endif |
| 68 | 53 |
| 69 template <typename T, | 54 template <typename T, |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 185 *result = static_cast<T>(tmp); | 170 *result = static_cast<T>(tmp); |
| 186 return DstRangeRelationToSrcRange<T>(tmp) == RANGE_VALID; | 171 return DstRangeRelationToSrcRange<T>(tmp) == RANGE_VALID; |
| 187 } | 172 } |
| 188 | 173 |
| 189 template <typename T, | 174 template <typename T, |
| 190 typename std::enable_if< | 175 typename std::enable_if< |
| 191 std::is_integral<T>::value && std::is_signed<T>::value && | 176 std::is_integral<T>::value && std::is_signed<T>::value && |
| 192 ((IntegerBitsPlusSign<T>::value * 2) > | 177 ((IntegerBitsPlusSign<T>::value * 2) > |
| 193 IntegerBitsPlusSign<intmax_t>::value)>::type* = nullptr> | 178 IntegerBitsPlusSign<intmax_t>::value)>::type* = nullptr> |
| 194 bool CheckedMulImpl(T x, T y, T* result) { | 179 bool CheckedMulImpl(T x, T y, T* result) { |
| 195 if (x && y) { | 180 // Since the value of x*y is potentially undefined if we have a signed type, |
| 196 if (x > 0) { | 181 // we compute it using the unsigned type of the same size. |
| 197 if (y > 0) { | 182 using UnsignedDst = typename std::make_unsigned<T>::type; |
| 198 if (x > std::numeric_limits<T>::max() / y) | 183 const T is_negative = HasSignBit(x) ^ HasSignBit(y); |
| 199 return false; | 184 const UnsignedDst ux = SafeUnsignedAbs(x); |
| 200 } else { | 185 const UnsignedDst uy = SafeUnsignedAbs(y); |
| 201 if (y < std::numeric_limits<T>::lowest() / x) | 186 UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy); |
| 202 return false; | 187 // This is a non-branching conditional negation. |
| 203 } | 188 *result = static_cast<T>((uresult ^ -is_negative) + is_negative); |
|
scottmg
2016/12/10 01:01:31
I would have moved that before this line instead,
| |
| 204 } else { | 189 // This uses the unsigned overflow check on the absolute value, with a +1 |
| 205 if (y > 0) { | 190 // bound for a negative result. |
| 206 if (x < std::numeric_limits<T>::lowest() / y) | 191 return (uy == 0 || |
| 207 return false; | 192 ux <= (static_cast<UnsignedDst>(std::numeric_limits<T>::max()) + |
| 208 } else { | 193 is_negative) / |
| 209 if (y < std::numeric_limits<T>::max() / x) | 194 uy); |
| 210 return false; | |
| 211 } | |
| 212 } | |
| 213 } | |
| 214 *result = x * y; | |
| 215 return true; | |
| 216 } | 195 } |
| 217 | 196 |
| 218 template <typename T, | 197 template <typename T, |
| 219 typename std::enable_if< | 198 typename std::enable_if< |
| 220 std::is_integral<T>::value && !std::is_signed<T>::value && | 199 std::is_integral<T>::value && !std::is_signed<T>::value && |
| 221 ((IntegerBitsPlusSign<T>::value * 2) > | 200 ((IntegerBitsPlusSign<T>::value * 2) > |
| 222 IntegerBitsPlusSign<uintmax_t>::value)>::type* = nullptr> | 201 IntegerBitsPlusSign<uintmax_t>::value)>::type* = nullptr> |
| 223 bool CheckedMulImpl(T x, T y, T* result) { | 202 bool CheckedMulImpl(T x, T y, T* result) { |
| 224 *result = x * y; | 203 *result = x * y; |
| 225 return (y == 0 || x <= std::numeric_limits<T>::max() / y); | 204 return (y == 0 || x <= std::numeric_limits<T>::max() / y); |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 522 !std::is_signed<T>::value>::type* = nullptr> | 501 !std::is_signed<T>::value>::type* = nullptr> |
| 523 bool CheckedInv(T value, T* result) { | 502 bool CheckedInv(T value, T* result) { |
| 524 *result = ~value; | 503 *result = ~value; |
| 525 return true; | 504 return true; |
| 526 } | 505 } |
| 527 | 506 |
| 528 template <typename T, | 507 template <typename T, |
| 529 typename std::enable_if<std::is_integral<T>::value && | 508 typename std::enable_if<std::is_integral<T>::value && |
| 530 std::is_signed<T>::value>::type* = nullptr> | 509 std::is_signed<T>::value>::type* = nullptr> |
| 531 bool CheckedAbs(T value, T* result) { | 510 bool CheckedAbs(T value, T* result) { |
| 532 if (value != std::numeric_limits<T>::lowest()) { | 511 *result = static_cast<T>(SafeUnsignedAbs(value)); |
| 533 *result = std::abs(value); | 512 return *result != std::numeric_limits<T>::lowest(); |
| 534 return true; | |
| 535 } | |
| 536 return false; | |
| 537 } | 513 } |
| 538 | 514 |
| 539 template <typename T, | 515 template <typename T, |
| 540 typename std::enable_if<std::is_integral<T>::value && | 516 typename std::enable_if<std::is_integral<T>::value && |
| 541 !std::is_signed<T>::value>::type* = nullptr> | 517 !std::is_signed<T>::value>::type* = nullptr> |
| 542 bool CheckedAbs(T value, T* result) { | 518 bool CheckedAbs(T value, T* result) { |
| 543 // T is unsigned, so |value| must already be positive. | 519 // T is unsigned, so |value| must already be positive. |
| 544 *result = value; | 520 *result = value; |
| 545 return true; | 521 return true; |
| 546 } | 522 } |
| 547 | 523 |
| 548 template <typename T, | |
| 549 typename std::enable_if<std::is_integral<T>::value && | |
| 550 std::is_signed<T>::value>::type* = nullptr> | |
| 551 constexpr typename std::make_unsigned<T>::type SafeUnsignedAbs(T value) { | |
| 552 using UnsignedT = typename std::make_unsigned<T>::type; | |
| 553 return value == std::numeric_limits<T>::lowest() | |
| 554 ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1 | |
| 555 : static_cast<UnsignedT>(std::abs(value)); | |
| 556 } | |
| 557 | |
| 558 template <typename T, | |
| 559 typename std::enable_if<std::is_integral<T>::value && | |
| 560 !std::is_signed<T>::value>::type* = nullptr> | |
| 561 constexpr T SafeUnsignedAbs(T value) { | |
| 562 // T is unsigned, so |value| must already be positive. | |
| 563 return static_cast<T>(value); | |
| 564 } | |
| 565 | |
| 566 // This is just boilerplate that wraps the standard floating point arithmetic. | 524 // This is just boilerplate that wraps the standard floating point arithmetic. |
| 567 // A macro isn't the nicest solution, but it beats rewriting these repeatedly. | 525 // A macro isn't the nicest solution, but it beats rewriting these repeatedly. |
| 568 #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \ | 526 #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \ |
| 569 template <typename T, typename U> \ | 527 template <typename T, typename U> \ |
| 570 struct Checked##NAME##Op< \ | 528 struct Checked##NAME##Op< \ |
| 571 T, U, typename std::enable_if<std::is_floating_point<T>::value || \ | 529 T, U, typename std::enable_if<std::is_floating_point<T>::value || \ |
| 572 std::is_floating_point<U>::value>::type> { \ | 530 std::is_floating_point<U>::value>::type> { \ |
| 573 using result_type = typename MaxExponentPromotion<T, U>::type; \ | 531 using result_type = typename MaxExponentPromotion<T, U>::type; \ |
| 574 template <typename V> \ | 532 template <typename V> \ |
| 575 static bool Do(T x, U y, V* result) { \ | 533 static bool Do(T x, U y, V* result) { \ |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 730 using math = M<typename UnderlyingType<L>::type, | 688 using math = M<typename UnderlyingType<L>::type, |
| 731 typename UnderlyingType<R>::type, | 689 typename UnderlyingType<R>::type, |
| 732 void>; | 690 void>; |
| 733 using type = typename math::result_type; | 691 using type = typename math::result_type; |
| 734 }; | 692 }; |
| 735 | 693 |
| 736 } // namespace internal | 694 } // namespace internal |
| 737 } // namespace base | 695 } // namespace base |
| 738 | 696 |
| 739 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 697 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
| OLD | NEW |