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 <limits> | 10 #include <limits> |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 ? std::numeric_limits<T>::infinity() * -1 | 103 ? std::numeric_limits<T>::infinity() * -1 |
104 : std::numeric_limits<T>::lowest(); | 104 : std::numeric_limits<T>::lowest(); |
105 } | 105 } |
106 }; | 106 }; |
107 | 107 |
108 namespace internal { | 108 namespace internal { |
109 // saturated_cast<> is analogous to static_cast<> for numeric types, except | 109 // saturated_cast<> is analogous to static_cast<> for numeric types, except |
110 // that the specified numeric conversion will saturate by default rather than | 110 // that the specified numeric conversion will saturate by default rather than |
111 // overflow or underflow, and NaN assignment to an integral will return 0. | 111 // overflow or underflow, and NaN assignment to an integral will return 0. |
112 // All boundary condition behaviors can be overriden with a custom handler. | 112 // All boundary condition behaviors can be overriden with a custom handler. |
| 113 template <template <typename> |
| 114 class SaturationHandler = SaturatedCastDefaultHandler, |
| 115 typename Dst, |
| 116 typename Src> |
| 117 constexpr Dst saturated_cast_impl(const Src value, |
| 118 const RangeConstraint constraint) { |
| 119 return constraint.IsValid() |
| 120 ? static_cast<Dst>(value) |
| 121 : (constraint.IsOverflow() |
| 122 ? SaturationHandler<Dst>::HandleOverflow() |
| 123 // Skip this check for integral Src, which cannot be NaN. |
| 124 : (std::is_integral<Src>::value || constraint.IsUnderflow() |
| 125 ? SaturationHandler<Dst>::HandleUnderflow() |
| 126 : SaturationHandler<Dst>::HandleNaN())); |
| 127 } |
| 128 |
| 129 // saturated_cast<> is analogous to static_cast<> for numeric types, except |
| 130 // that the specified numeric conversion will saturate by default rather than |
| 131 // overflow or underflow, and NaN assignment to an integral will return 0. |
| 132 // All boundary condition behaviors can be overriden with a custom handler. |
113 template <typename Dst, | 133 template <typename Dst, |
114 template <typename> | 134 template <typename> |
115 class SaturationHandler = SaturatedCastDefaultHandler, | 135 class SaturationHandler = SaturatedCastDefaultHandler, |
116 typename Src> | 136 typename Src> |
117 constexpr Dst saturated_cast(Src value) { | 137 constexpr Dst saturated_cast(Src value) { |
118 static_assert( | |
119 SaturationHandler<Dst>::lowest() < SaturationHandler<Dst>::max(), ""); | |
120 // While this looks like a lot of code, it's all constexpr and all but | |
121 // one variable are compile-time constants (enforced by a static_assert). | |
122 // So, it should evaluate to the minimum number of comparisons required | |
123 // for the range check, which is 0-3, depending on the exact source and | |
124 // destination types, and whatever custom range is specified. | |
125 using SrcType = typename UnderlyingType<Src>::type; | 138 using SrcType = typename UnderlyingType<Src>::type; |
126 return IsGreaterOrEqual<SrcType, Dst>::Test( | 139 return saturated_cast_impl<SaturationHandler, Dst>( |
127 value, NarrowingRange<Dst, SrcType, SaturationHandler>::lowest()) | 140 static_cast<SrcType>(value), |
128 ? (IsLessOrEqual<SrcType, Dst>::Test( | 141 DstRangeRelationToSrcRange<Dst, SaturationHandler, SrcType>(value)); |
129 value, | |
130 NarrowingRange<Dst, SrcType, SaturationHandler>::max()) | |
131 ? static_cast<Dst>(value) | |
132 : SaturationHandler<Dst>::HandleOverflow()) | |
133 // This last branch is a little confusing. It's specifically to | |
134 // catch NaN when converting from float to integral. | |
135 : (std::is_integral<SrcType>::value || | |
136 std::is_floating_point<Dst>::value || | |
137 IsLessOrEqual<SrcType, Dst>::Test( | |
138 value, NarrowingRange<Dst, SrcType, | |
139 SaturationHandler>::max()) | |
140 ? SaturationHandler<Dst>::HandleUnderflow() | |
141 : SaturationHandler<Dst>::HandleNaN()); | |
142 } | 142 } |
143 | 143 |
144 // strict_cast<> is analogous to static_cast<> for numeric types, except that | 144 // strict_cast<> is analogous to static_cast<> for numeric types, except that |
145 // it will cause a compile failure if the destination type is not large enough | 145 // it will cause a compile failure if the destination type is not large enough |
146 // to contain any value in the source type. It performs no runtime checking. | 146 // to contain any value in the source type. It performs no runtime checking. |
147 template <typename Dst, typename Src> | 147 template <typename Dst, typename Src> |
148 constexpr Dst strict_cast(Src value) { | 148 constexpr Dst strict_cast(Src value) { |
149 using SrcType = typename UnderlyingType<Src>::type; | 149 using SrcType = typename UnderlyingType<Src>::type; |
150 static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric."); | 150 static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric."); |
151 static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric."); | 151 static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric."); |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
270 using internal::StrictNumeric; | 270 using internal::StrictNumeric; |
271 using internal::MakeStrictNum; | 271 using internal::MakeStrictNum; |
272 using internal::IsValueNegative; | 272 using internal::IsValueNegative; |
273 | 273 |
274 // Explicitly make a shorter size_t alias for convenience. | 274 // Explicitly make a shorter size_t alias for convenience. |
275 using SizeT = StrictNumeric<size_t>; | 275 using SizeT = StrictNumeric<size_t>; |
276 | 276 |
277 } // namespace base | 277 } // namespace base |
278 | 278 |
279 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_ | 279 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_ |
OLD | NEW |