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. | |
133 template <typename Dst, | 113 template <typename Dst, |
134 template <typename> | 114 template <typename> |
135 class SaturationHandler = SaturatedCastDefaultHandler, | 115 class SaturationHandler = SaturatedCastDefaultHandler, |
136 typename Src> | 116 typename Src> |
137 constexpr Dst saturated_cast(Src value) { | 117 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. |
138 using SrcType = typename UnderlyingType<Src>::type; | 125 using SrcType = typename UnderlyingType<Src>::type; |
139 return saturated_cast_impl<SaturationHandler, Dst>( | 126 return IsGreaterOrEqual<SrcType, Dst>::Test( |
140 static_cast<SrcType>(value), | 127 value, NarrowingRange<Dst, SrcType, SaturationHandler>::lowest()) |
141 DstRangeRelationToSrcRange<Dst, SaturationHandler, SrcType>(value)); | 128 ? (IsLessOrEqual<SrcType, Dst>::Test( |
| 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 |