| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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_CHECKED_MATH_IMPL_H_ | 5 #ifndef BASE_NUMERICS_CHECKED_MATH_IMPL_H_ |
| 6 #define BASE_NUMERICS_CHECKED_MATH_IMPL_H_ | 6 #define BASE_NUMERICS_CHECKED_MATH_IMPL_H_ |
| 7 | 7 |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <stdint.h> | 9 #include <stdint.h> |
| 10 | 10 |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 (IntegerBitsPlusSign<__typeof__(x * y)>::value == | 175 (IntegerBitsPlusSign<__typeof__(x * y)>::value == |
| 176 IntegerBitsPlusSign<intptr_t>::value && | 176 IntegerBitsPlusSign<intptr_t>::value && |
| 177 std::is_signed<T>::value == std::is_signed<U>::value); | 177 std::is_signed<T>::value == std::is_signed<U>::value); |
| 178 #else | 178 #else |
| 179 static const bool kUseMaxInt = true; | 179 static const bool kUseMaxInt = true; |
| 180 #endif | 180 #endif |
| 181 if (kUseMaxInt) | 181 if (kUseMaxInt) |
| 182 return !__builtin_mul_overflow(x, y, result); | 182 return !__builtin_mul_overflow(x, y, result); |
| 183 #endif | 183 #endif |
| 184 using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type; | 184 using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type; |
| 185 // Verify the destination type can hold the result (always true for 0). |
| 186 if (!(IsValueInRangeForNumericType<Promotion>(x) && |
| 187 IsValueInRangeForNumericType<Promotion>(y)) && |
| 188 x && y) { |
| 189 return false; |
| 190 } |
| 185 Promotion presult; | 191 Promotion presult; |
| 186 // Fail if either operand is out of range for the promoted type. | 192 bool is_valid = true; |
| 187 // TODO(jschuh): This could be made to work for a broader range of values. | |
| 188 bool is_valid = IsValueInRangeForNumericType<Promotion>(x) && | |
| 189 IsValueInRangeForNumericType<Promotion>(y); | |
| 190 | |
| 191 if (IsIntegerArithmeticSafe<Promotion, T, U>::value) { | 193 if (IsIntegerArithmeticSafe<Promotion, T, U>::value) { |
| 192 presult = static_cast<Promotion>(x) * static_cast<Promotion>(y); | 194 presult = static_cast<Promotion>(x) * static_cast<Promotion>(y); |
| 193 } else { | 195 } else { |
| 194 is_valid &= CheckedMulImpl(static_cast<Promotion>(x), | 196 is_valid = CheckedMulImpl(static_cast<Promotion>(x), |
| 195 static_cast<Promotion>(y), &presult); | 197 static_cast<Promotion>(y), &presult); |
| 196 } | 198 } |
| 197 *result = static_cast<V>(presult); | 199 *result = static_cast<V>(presult); |
| 198 return is_valid && IsValueInRangeForNumericType<V>(presult); | 200 return is_valid && IsValueInRangeForNumericType<V>(presult); |
| 199 } | 201 } |
| 200 }; | 202 }; |
| 201 | 203 |
| 202 // Avoid poluting the namespace once we're done with the macro. | 204 // Avoid poluting the namespace once we're done with the macro. |
| 203 #undef USE_OVERFLOW_BUILTINS | 205 #undef USE_OVERFLOW_BUILTINS |
| 204 | 206 |
| 205 // Division just requires a check for a zero denominator or an invalid negation | 207 // Division just requires a check for a zero denominator or an invalid negation |
| (...skipping 29 matching lines...) Expand all Loading... |
| 235 is_valid &= CheckedDivImpl(static_cast<Promotion>(x), | 237 is_valid &= CheckedDivImpl(static_cast<Promotion>(x), |
| 236 static_cast<Promotion>(y), &presult); | 238 static_cast<Promotion>(y), &presult); |
| 237 *result = static_cast<V>(presult); | 239 *result = static_cast<V>(presult); |
| 238 return is_valid && IsValueInRangeForNumericType<V>(presult); | 240 return is_valid && IsValueInRangeForNumericType<V>(presult); |
| 239 } | 241 } |
| 240 }; | 242 }; |
| 241 | 243 |
| 242 template <typename T> | 244 template <typename T> |
| 243 bool CheckedModImpl(T x, T y, T* result) { | 245 bool CheckedModImpl(T x, T y, T* result) { |
| 244 static_assert(std::is_integral<T>::value, "Type must be integral"); | 246 static_assert(std::is_integral<T>::value, "Type must be integral"); |
| 245 if (y > 0) { | 247 if (y) { |
| 246 *result = static_cast<T>(x % y); | 248 *result = static_cast<T>(x % y); |
| 247 return true; | 249 return true; |
| 248 } | 250 } |
| 249 return false; | 251 return false; |
| 250 } | 252 } |
| 251 | 253 |
| 252 template <typename T, typename U, class Enable = void> | 254 template <typename T, typename U, class Enable = void> |
| 253 struct CheckedModOp {}; | 255 struct CheckedModOp {}; |
| 254 | 256 |
| 255 template <typename T, typename U> | 257 template <typename T, typename U> |
| (...skipping 20 matching lines...) Expand all Loading... |
| 276 // of bits in the promoted type are undefined. Shifts of negative values | 278 // of bits in the promoted type are undefined. Shifts of negative values |
| 277 // are undefined. Otherwise it is defined when the result fits. | 279 // are undefined. Otherwise it is defined when the result fits. |
| 278 template <typename T, typename U> | 280 template <typename T, typename U> |
| 279 struct CheckedLshOp<T, | 281 struct CheckedLshOp<T, |
| 280 U, | 282 U, |
| 281 typename std::enable_if<std::is_integral<T>::value && | 283 typename std::enable_if<std::is_integral<T>::value && |
| 282 std::is_integral<U>::value>::type> { | 284 std::is_integral<U>::value>::type> { |
| 283 using result_type = T; | 285 using result_type = T; |
| 284 template <typename V> | 286 template <typename V> |
| 285 static bool Do(T x, U shift, V* result) { | 287 static bool Do(T x, U shift, V* result) { |
| 286 using ShiftType = typename std::make_unsigned<T>::type; | |
| 287 static const ShiftType kBitWidth = IntegerBitsPlusSign<T>::value; | |
| 288 const ShiftType real_shift = static_cast<ShiftType>(shift); | |
| 289 // Signed shift is not legal on negative values. | 288 // Signed shift is not legal on negative values. |
| 290 if (!IsValueNegative(x) && real_shift < kBitWidth) { | 289 if (!IsValueNegative(x) && |
| 290 as_unsigned(shift) < IntegerBitsPlusSign<T>::value) { |
| 291 // Just use a multiplication because it's easy. | 291 // Just use a multiplication because it's easy. |
| 292 // TODO(jschuh): This could probably be made more efficient. | 292 // TODO(jschuh): This could probably be made more efficient. |
| 293 if (!std::is_signed<T>::value || real_shift != kBitWidth - 1) | 293 if (!std::is_signed<T>::value || |
| 294 return CheckedMulOp<T, T>::Do(x, static_cast<T>(1) << shift, result); | 294 as_unsigned(shift) < std::numeric_limits<T>::digits) |
| 295 return CheckedMulOp<T, T>::Do(x, T(1) << shift, result); |
| 296 *result = 0; |
| 295 return !x; // Special case zero for a full width signed shift. | 297 return !x; // Special case zero for a full width signed shift. |
| 296 } | 298 } |
| 297 return false; | 299 return false; |
| 298 } | 300 } |
| 299 }; | 301 }; |
| 300 | 302 |
| 301 template <typename T, typename U, class Enable = void> | 303 template <typename T, typename U, class Enable = void> |
| 302 struct CheckedRshOp {}; | 304 struct CheckedRshOp {}; |
| 303 | 305 |
| 304 // Right shift. Shifts less than 0 or greater than or equal to the number | 306 // Right shift. Shifts less than 0 or greater than or equal to the number |
| 305 // of bits in the promoted type are undefined. Otherwise, it is always defined, | 307 // of bits in the promoted type are undefined. Otherwise, it is always defined, |
| 306 // but a right shift of a negative value is implementation-dependent. | 308 // but a right shift of a negative value is implementation-dependent. |
| 307 template <typename T, typename U> | 309 template <typename T, typename U> |
| 308 struct CheckedRshOp<T, | 310 struct CheckedRshOp<T, |
| 309 U, | 311 U, |
| 310 typename std::enable_if<std::is_integral<T>::value && | 312 typename std::enable_if<std::is_integral<T>::value && |
| 311 std::is_integral<U>::value>::type> { | 313 std::is_integral<U>::value>::type> { |
| 312 using result_type = T; | 314 using result_type = T; |
| 313 template <typename V> | 315 template <typename V> |
| 314 static bool Do(T x, U shift, V* result) { | 316 static bool Do(T x, U shift, V* result) { |
| 315 // Use the type conversion push negative values out of range. | 317 // Use the type conversion push negative values out of range. |
| 316 using ShiftType = typename std::make_unsigned<T>::type; | 318 if (as_unsigned(shift) < IntegerBitsPlusSign<T>::value) { |
| 317 if (static_cast<ShiftType>(shift) < IntegerBitsPlusSign<T>::value) { | |
| 318 T tmp = x >> shift; | 319 T tmp = x >> shift; |
| 319 *result = static_cast<V>(tmp); | 320 *result = static_cast<V>(tmp); |
| 320 return IsValueInRangeForNumericType<V>(tmp); | 321 return IsValueInRangeForNumericType<V>(tmp); |
| 321 } | 322 } |
| 322 return false; | 323 return false; |
| 323 } | 324 } |
| 324 }; | 325 }; |
| 325 | 326 |
| 326 template <typename T, typename U, class Enable = void> | 327 template <typename T, typename U, class Enable = void> |
| 327 struct CheckedAndOp {}; | 328 struct CheckedAndOp {}; |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 564 return value_ <= std::numeric_limits<T>::max() && | 565 return value_ <= std::numeric_limits<T>::max() && |
| 565 value_ >= std::numeric_limits<T>::lowest(); | 566 value_ >= std::numeric_limits<T>::lowest(); |
| 566 } | 567 } |
| 567 constexpr T value() const { return value_; } | 568 constexpr T value() const { return value_; } |
| 568 }; | 569 }; |
| 569 | 570 |
| 570 } // namespace internal | 571 } // namespace internal |
| 571 } // namespace base | 572 } // namespace base |
| 572 | 573 |
| 573 #endif // BASE_NUMERICS_CHECKED_MATH_IMPL_H_ | 574 #endif // BASE_NUMERICS_CHECKED_MATH_IMPL_H_ |
| OLD | NEW |