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_CONVERSIONS_H_ | 5 #ifndef BASE_NUMERICS_SAFE_CONVERSIONS_H_ |
| 6 #define BASE_NUMERICS_SAFE_CONVERSIONS_H_ | 6 #define BASE_NUMERICS_SAFE_CONVERSIONS_H_ |
| 7 | 7 |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 | 9 |
| 10 #include <cassert> | |
| 10 #include <limits> | 11 #include <limits> |
| 11 #include <type_traits> | 12 #include <type_traits> |
| 12 | 13 |
| 13 #include "base/logging.h" | |
| 14 #include "base/numerics/safe_conversions_impl.h" | 14 #include "base/numerics/safe_conversions_impl.h" |
| 15 | 15 |
| 16 namespace base { | 16 namespace base { |
| 17 | 17 |
| 18 // Convenience function that returns true if the supplied value is in range | 18 // Convenience function that returns true if the supplied value is in range |
| 19 // for the destination type. | 19 // for the destination type. |
| 20 template <typename Dst, typename Src> | 20 template <typename Dst, typename Src> |
| 21 constexpr bool IsValueInRangeForNumericType(Src value) { | 21 constexpr bool IsValueInRangeForNumericType(Src value) { |
| 22 return internal::DstRangeRelationToSrcRange<Dst>(value) == | 22 return internal::DstRangeRelationToSrcRange<Dst>(value) == |
| 23 internal::RANGE_VALID; | 23 internal::RANGE_VALID; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 34 } | 34 } |
| 35 | 35 |
| 36 template <typename T> | 36 template <typename T> |
| 37 constexpr typename std::enable_if<!std::numeric_limits<T>::is_signed, | 37 constexpr typename std::enable_if<!std::numeric_limits<T>::is_signed, |
| 38 bool>::type IsValueNegative(T) { | 38 bool>::type IsValueNegative(T) { |
| 39 static_assert(std::numeric_limits<T>::is_specialized, | 39 static_assert(std::numeric_limits<T>::is_specialized, |
| 40 "Argument must be numeric."); | 40 "Argument must be numeric."); |
| 41 return false; | 41 return false; |
| 42 } | 42 } |
| 43 | 43 |
| 44 // Just fires a CHECK(false). Used for numeric boundary errors. | 44 // Forces a crash, like a CHECK(false). Used for numeric boundary errors. |
| 45 struct CheckOnFailure { | 45 struct CheckOnFailure { |
| 46 template <typename T> | 46 template <typename T> |
| 47 static T HandleFailure() { | 47 static T HandleFailure() { |
| 48 CHECK(false); | 48 #if defined(__GNUC__) || defined(__clang__) |
| 49 __builtin_trap(); | |
| 50 #else | |
| 51 ((void)(*(volatile char*)0 = 0)); | |
|
Tom Sepez
2016/11/22 18:17:31
I thought we had an issue with some compiler pulli
jschuh
2016/11/22 18:27:52
This is exactly what base/logging.h uses for a CHE
| |
| 52 #endif | |
| 49 return T(); | 53 return T(); |
| 50 } | 54 } |
| 51 }; | 55 }; |
| 52 | 56 |
| 53 // checked_cast<> is analogous to static_cast<> for numeric types, | 57 // checked_cast<> is analogous to static_cast<> for numeric types, |
| 54 // except that it CHECKs that the specified numeric conversion will not | 58 // except that it CHECKs that the specified numeric conversion will not |
| 55 // overflow or underflow. NaN source will always trigger a CHECK. | 59 // overflow or underflow. NaN source will always trigger a CHECK. |
| 56 template <typename Dst, | 60 template <typename Dst, |
| 57 class CheckHandler = CheckOnFailure, | 61 class CheckHandler = CheckOnFailure, |
| 58 typename Src> | 62 typename Src> |
| 59 constexpr Dst checked_cast(Src value) { | 63 constexpr Dst checked_cast(Src value) { |
| 60 // This throws a compile-time error on evaluating the constexpr if it can be | 64 // This throws a compile-time error on evaluating the constexpr if it can be |
| 61 // determined at compile-time as failing, otherwise it will CHECK at runtime. | 65 // determined at compile-time as failing, otherwise it will CHECK at runtime. |
| 62 return IsValueInRangeForNumericType<Dst>(value) | 66 return IsValueInRangeForNumericType<Dst>(value) |
| 63 ? static_cast<Dst>(value) | 67 ? static_cast<Dst>(value) |
| 64 : CheckHandler::template HandleFailure<Dst>(); | 68 : CheckHandler::template HandleFailure<Dst>(); |
| 65 } | 69 } |
| 66 | 70 |
| 67 // HandleNaN will return 0 in this case. | 71 // HandleNaN will return 0 in this case. |
| 68 struct SaturatedCastNaNBehaviorReturnZero { | 72 struct SaturatedCastNaNBehaviorReturnZero { |
| 69 template <typename T> | 73 template <typename T> |
| 70 static constexpr T HandleFailure() { | 74 static constexpr T HandleFailure() { |
| 71 return T(); | 75 return T(); |
| 72 } | 76 } |
| 73 }; | 77 }; |
| 74 | 78 |
| 75 namespace internal { | 79 namespace internal { |
| 76 // This wrapper is used for C++11 constexpr support by avoiding the declaration | 80 // This wrapper is used for C++11 constexpr support by avoiding the declaration |
| 77 // of local variables in the saturated_cast template function. | 81 // of local variables in the saturated_cast template function. |
| 82 // TODO(jschuh): convert this back to a switch once we support C++14. | |
| 78 template <typename Dst, class NaNHandler, typename Src> | 83 template <typename Dst, class NaNHandler, typename Src> |
| 79 constexpr Dst saturated_cast_impl(const Src value, | 84 constexpr Dst saturated_cast_impl(const Src value, |
| 80 const RangeConstraint constraint) { | 85 const RangeConstraint constraint) { |
| 81 return constraint == RANGE_VALID | 86 return constraint == RANGE_VALID |
| 82 ? static_cast<Dst>(value) | 87 ? static_cast<Dst>(value) |
| 83 : (constraint == RANGE_UNDERFLOW | 88 : (constraint == RANGE_UNDERFLOW |
| 84 ? std::numeric_limits<Dst>::min() | 89 ? std::numeric_limits<Dst>::min() |
| 85 : (constraint == RANGE_OVERFLOW | 90 : (constraint == RANGE_OVERFLOW |
| 86 ? std::numeric_limits<Dst>::max() | 91 ? std::numeric_limits<Dst>::max() |
| 87 : (constraint == RANGE_INVALID | 92 : (constraint == RANGE_INVALID |
| 88 ? NaNHandler::template HandleFailure<Dst>() | 93 ? NaNHandler::template HandleFailure<Dst>() |
| 89 : (NOTREACHED(), static_cast<Dst>(value))))); | 94 : (assert(false), static_cast<Dst>(value))))); |
| 90 } | 95 } |
| 91 } // namespace internal | 96 } // namespace internal |
| 92 | 97 |
| 93 // saturated_cast<> is analogous to static_cast<> for numeric types, except | 98 // saturated_cast<> is analogous to static_cast<> for numeric types, except |
| 94 // that the specified numeric conversion will saturate rather than overflow or | 99 // that the specified numeric conversion will saturate rather than overflow or |
| 95 // underflow. NaN assignment to an integral will defer the behavior to a | 100 // underflow. NaN assignment to an integral will defer the behavior to a |
| 96 // specified class. By default, it will return 0. | 101 // specified class. By default, it will return 0. |
| 97 template <typename Dst, | 102 template <typename Dst, |
| 98 class NaNHandler = SaturatedCastNaNBehaviorReturnZero, | 103 class NaNHandler = SaturatedCastNaNBehaviorReturnZero, |
| 99 typename Src> | 104 typename Src> |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 162 private: | 167 private: |
| 163 const T value_; | 168 const T value_; |
| 164 }; | 169 }; |
| 165 | 170 |
| 166 // Explicitly make a shorter size_t typedef for convenience. | 171 // Explicitly make a shorter size_t typedef for convenience. |
| 167 typedef StrictNumeric<size_t> SizeT; | 172 typedef StrictNumeric<size_t> SizeT; |
| 168 | 173 |
| 169 } // namespace base | 174 } // namespace base |
| 170 | 175 |
| 171 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_ | 176 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_ |
| OLD | NEW |