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 <cassert> |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 99 | 99 |
| 100 // HandleNaN will return 0 in this case. | 100 // HandleNaN will return 0 in this case. |
| 101 struct SaturatedCastNaNBehaviorReturnZero { | 101 struct SaturatedCastNaNBehaviorReturnZero { |
| 102 template <typename T> | 102 template <typename T> |
| 103 static constexpr T HandleFailure() { | 103 static constexpr T HandleFailure() { |
| 104 return T(); | 104 return T(); |
| 105 } | 105 } |
| 106 }; | 106 }; |
| 107 | 107 |
| 108 namespace internal { | 108 namespace internal { |
| 109 // This wrapper is used for C++11 constexpr support by avoiding the declaration | 109 // These wrappers are used for C++11 constexpr support by avoiding both the |
| 110 // of local variables in the saturated_cast template function. | 110 // declaration of local variables and invalid evaluation resulting from the |
| 111 // TODO(jschuh): convert this back to a switch once we support C++14. | 111 // lack of "constexpr if" support in the saturated_cast template function. |
| 112 template <typename Dst, class NaNHandler, typename Src> | 112 // TODO(jschuh): Convert to single function with a switch once we support C++14. |
| 113 template < | |
| 114 typename Dst, | |
| 115 class NaNHandler, | |
| 116 typename Src, | |
| 117 typename std::enable_if<std::is_integral<Dst>::value>::type* = nullptr> | |
| 113 constexpr Dst saturated_cast_impl(const Src value, | 118 constexpr Dst saturated_cast_impl(const Src value, |
| 114 const RangeConstraint constraint) { | 119 const RangeConstraint constraint) { |
| 115 return constraint == RANGE_VALID | 120 return constraint == RANGE_VALID |
| 116 ? static_cast<Dst>(value) | 121 ? static_cast<Dst>(value) |
| 117 : (constraint == RANGE_UNDERFLOW | 122 : (constraint == RANGE_UNDERFLOW |
| 118 ? std::numeric_limits<Dst>::lowest() | 123 ? std::numeric_limits<Dst>::lowest() |
| 119 : (constraint == RANGE_OVERFLOW | 124 : (constraint == RANGE_OVERFLOW |
| 120 ? std::numeric_limits<Dst>::max() | 125 ? std::numeric_limits<Dst>::max() |
| 121 : NaNHandler::template HandleFailure<Dst>())); | 126 : NaNHandler::template HandleFailure<Dst>())); |
| 122 } | 127 } |
| 123 | 128 |
| 129 template <typename Dst, | |
| 130 class NaNHandler, | |
| 131 typename Src, | |
| 132 typename std::enable_if<std::is_floating_point<Dst>::value>::type* = | |
| 133 nullptr> | |
| 134 constexpr Dst saturated_cast_impl(const Src value, | |
| 135 const RangeConstraint constraint) { | |
| 136 return constraint == RANGE_VALID | |
| 137 ? static_cast<Dst>(value) | |
| 138 : (constraint == RANGE_UNDERFLOW | |
| 139 ? -std::numeric_limits<Dst>::infinity() | |
|
Nico
2016/12/06 14:03:37
I'm assuming you're static_assert()ing somewhere t
jschuh
2016/12/06 15:07:55
We have a ton of tests that would fail if they did
| |
| 140 : (constraint == RANGE_OVERFLOW | |
| 141 ? std::numeric_limits<Dst>::infinity() | |
| 142 : std::numeric_limits<Dst>::quiet_NaN())); | |
| 143 } | |
| 144 | |
| 124 // saturated_cast<> is analogous to static_cast<> for numeric types, except | 145 // saturated_cast<> is analogous to static_cast<> for numeric types, except |
| 125 // that the specified numeric conversion will saturate rather than overflow or | 146 // that the specified numeric conversion will saturate rather than overflow or |
| 126 // underflow. NaN assignment to an integral will defer the behavior to a | 147 // underflow. NaN assignment to an integral will defer the behavior to a |
| 127 // specified class. By default, it will return 0. | 148 // specified class. By default, it will return 0. |
| 128 template <typename Dst, | 149 template <typename Dst, |
| 129 class NaNHandler = SaturatedCastNaNBehaviorReturnZero, | 150 class NaNHandler = SaturatedCastNaNBehaviorReturnZero, |
| 130 typename Src> | 151 typename Src> |
| 131 constexpr Dst saturated_cast(Src value) { | 152 constexpr Dst saturated_cast(Src value) { |
| 132 using SrcType = typename UnderlyingType<Src>::type; | 153 using SrcType = typename UnderlyingType<Src>::type; |
| 133 return std::is_floating_point<Dst>::value | 154 return internal::saturated_cast_impl<Dst, NaNHandler>( |
| 134 ? static_cast<Dst>( | 155 value, internal::DstRangeRelationToSrcRange<Dst, SrcType>(value)); |
| 135 static_cast<SrcType>(value)) // Floating point optimization. | |
| 136 : internal::saturated_cast_impl<Dst, NaNHandler>( | |
| 137 value, | |
| 138 internal::DstRangeRelationToSrcRange<Dst, SrcType>(value)); | |
| 139 } | 156 } |
| 140 | 157 |
| 141 // strict_cast<> is analogous to static_cast<> for numeric types, except that | 158 // strict_cast<> is analogous to static_cast<> for numeric types, except that |
| 142 // it will cause a compile failure if the destination type is not large enough | 159 // it will cause a compile failure if the destination type is not large enough |
| 143 // to contain any value in the source type. It performs no runtime checking. | 160 // to contain any value in the source type. It performs no runtime checking. |
| 144 template <typename Dst, typename Src> | 161 template <typename Dst, typename Src> |
| 145 constexpr Dst strict_cast(Src value) { | 162 constexpr Dst strict_cast(Src value) { |
| 146 using SrcType = typename UnderlyingType<Src>::type; | 163 using SrcType = typename UnderlyingType<Src>::type; |
| 147 static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric."); | 164 static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric."); |
| 148 static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric."); | 165 static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric."); |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 265 using internal::saturated_cast; | 282 using internal::saturated_cast; |
| 266 using internal::StrictNumeric; | 283 using internal::StrictNumeric; |
| 267 using internal::MakeStrictNum; | 284 using internal::MakeStrictNum; |
| 268 | 285 |
| 269 // Explicitly make a shorter size_t alias for convenience. | 286 // Explicitly make a shorter size_t alias for convenience. |
| 270 using SizeT = StrictNumeric<size_t>; | 287 using SizeT = StrictNumeric<size_t>; |
| 271 | 288 |
| 272 } // namespace base | 289 } // namespace base |
| 273 | 290 |
| 274 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_ | 291 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_ |
| OLD | NEW |