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 |