Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(306)

Side by Side Diff: base/numerics/safe_conversions.h

Issue 2582063002: Revert of Support saturation overrides in saturated_cast (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | base/numerics/safe_conversions_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 // the supplied arithmetic or StrictNumeric type. 48 // the supplied arithmetic or StrictNumeric type.
49 49
50 // Convenience function that returns true if the supplied value is in range 50 // Convenience function that returns true if the supplied value is in range
51 // for the destination type. 51 // for the destination type.
52 template <typename Dst, typename Src> 52 template <typename Dst, typename Src>
53 constexpr bool IsValueInRangeForNumericType(Src value) { 53 constexpr bool IsValueInRangeForNumericType(Src value) {
54 return internal::DstRangeRelationToSrcRange<Dst>(value) == 54 return internal::DstRangeRelationToSrcRange<Dst>(value) ==
55 internal::RANGE_VALID; 55 internal::RANGE_VALID;
56 } 56 }
57 57
58 // Convenience function for determining if a numeric value is negative without
59 // throwing compiler warnings on: unsigned(value) < 0.
60 template <typename T,
61 typename std::enable_if<std::is_signed<T>::value>::type* = nullptr>
62 constexpr bool IsValueNegative(T value) {
63 static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
64 return value < 0;
65 }
66
67 template <typename T,
68 typename std::enable_if<!std::is_signed<T>::value>::type* = nullptr>
69 constexpr bool IsValueNegative(T) {
70 static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
71 return false;
72 }
73
58 // Forces a crash, like a CHECK(false). Used for numeric boundary errors. 74 // Forces a crash, like a CHECK(false). Used for numeric boundary errors.
59 struct CheckOnFailure { 75 struct CheckOnFailure {
60 template <typename T> 76 template <typename T>
61 static T HandleFailure() { 77 static T HandleFailure() {
62 #if defined(__GNUC__) || defined(__clang__) 78 #if defined(__GNUC__) || defined(__clang__)
63 __builtin_trap(); 79 __builtin_trap();
64 #else 80 #else
65 ((void)(*(volatile char*)0 = 0)); 81 ((void)(*(volatile char*)0 = 0));
66 #endif 82 #endif
67 return T(); 83 return T();
68 } 84 }
69 }; 85 };
70 86
71 // checked_cast<> is analogous to static_cast<> for numeric types, 87 // checked_cast<> is analogous to static_cast<> for numeric types,
72 // except that it CHECKs that the specified numeric conversion will not 88 // except that it CHECKs that the specified numeric conversion will not
73 // overflow or underflow. NaN source will always trigger a CHECK. 89 // overflow or underflow. NaN source will always trigger a CHECK.
74 template <typename Dst, 90 template <typename Dst,
75 class CheckHandler = CheckOnFailure, 91 class CheckHandler = CheckOnFailure,
76 typename Src> 92 typename Src>
77 constexpr Dst checked_cast(Src value) { 93 constexpr Dst checked_cast(Src value) {
78 // This throws a compile-time error on evaluating the constexpr if it can be 94 // This throws a compile-time error on evaluating the constexpr if it can be
79 // determined at compile-time as failing, otherwise it will CHECK at runtime. 95 // determined at compile-time as failing, otherwise it will CHECK at runtime.
80 using SrcType = typename internal::UnderlyingType<Src>::type; 96 using SrcType = typename internal::UnderlyingType<Src>::type;
81 return IsValueInRangeForNumericType<Dst, SrcType>(value) 97 return IsValueInRangeForNumericType<Dst, SrcType>(value)
82 ? static_cast<Dst>(static_cast<SrcType>(value)) 98 ? static_cast<Dst>(static_cast<SrcType>(value))
83 : CheckHandler::template HandleFailure<Dst>(); 99 : CheckHandler::template HandleFailure<Dst>();
84 } 100 }
85 101
86 // Default boundaries for integral/float: max/infinity, lowest/-infinity, 0/NaN. 102 // HandleNaN will return 0 in this case.
87 template <typename T> 103 struct SaturatedCastNaNBehaviorReturnZero {
88 struct SaturatedCastDefaultHandler { 104 template <typename T>
89 static constexpr T HandleNaN() { 105 static constexpr T HandleFailure() {
90 return std::numeric_limits<T>::has_quiet_NaN 106 return T();
91 ? std::numeric_limits<T>::quiet_NaN()
92 : T();
93 }
94 static constexpr T max() { return std::numeric_limits<T>::max(); }
95 static constexpr T HandleOverflow() {
96 return std::numeric_limits<T>::has_infinity
97 ? std::numeric_limits<T>::infinity()
98 : std::numeric_limits<T>::max();
99 }
100 static constexpr T lowest() { return std::numeric_limits<T>::lowest(); }
101 static constexpr T HandleUnderflow() {
102 return std::numeric_limits<T>::has_infinity
103 ? std::numeric_limits<T>::infinity() * -1
104 : std::numeric_limits<T>::lowest();
105 } 107 }
106 }; 108 };
107 109
108 namespace internal { 110 namespace internal {
111 // These wrappers are used for C++11 constexpr support by avoiding both the
112 // declaration of local variables and invalid evaluation resulting from the
113 // lack of "constexpr if" support in the saturated_cast template function.
114 // TODO(jschuh): Convert to single function with a switch once we support C++14.
115 template <
116 typename Dst,
117 class NaNHandler,
118 typename Src,
119 typename std::enable_if<std::is_integral<Dst>::value>::type* = nullptr>
120 constexpr Dst saturated_cast_impl(const Src value,
121 const RangeConstraint constraint) {
122 return constraint == RANGE_VALID
123 ? static_cast<Dst>(value)
124 : (constraint == RANGE_UNDERFLOW
125 ? std::numeric_limits<Dst>::lowest()
126 : (constraint == RANGE_OVERFLOW
127 ? std::numeric_limits<Dst>::max()
128 : NaNHandler::template HandleFailure<Dst>()));
129 }
130
131 template <typename Dst,
132 class NaNHandler,
133 typename Src,
134 typename std::enable_if<std::is_floating_point<Dst>::value>::type* =
135 nullptr>
136 constexpr Dst saturated_cast_impl(const Src value,
137 const RangeConstraint constraint) {
138 return constraint == RANGE_VALID
139 ? static_cast<Dst>(value)
140 : (constraint == RANGE_UNDERFLOW
141 ? -std::numeric_limits<Dst>::infinity()
142 : (constraint == RANGE_OVERFLOW
143 ? std::numeric_limits<Dst>::infinity()
144 : std::numeric_limits<Dst>::quiet_NaN()));
145 }
146
109 // saturated_cast<> is analogous to static_cast<> for numeric types, except 147 // saturated_cast<> is analogous to static_cast<> for numeric types, except
110 // that the specified numeric conversion will saturate by default rather than 148 // that the specified numeric conversion will saturate rather than overflow or
111 // overflow or underflow, and NaN assignment to an integral will return 0. 149 // underflow. NaN assignment to an integral will defer the behavior to a
112 // All boundary condition behaviors can be overriden with a custom handler. 150 // specified class. By default, it will return 0.
113 template <typename Dst, 151 template <typename Dst,
114 template <typename> 152 class NaNHandler = SaturatedCastNaNBehaviorReturnZero,
115 class SaturationHandler = SaturatedCastDefaultHandler,
116 typename Src> 153 typename Src>
117 constexpr Dst saturated_cast(Src value) { 154 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; 155 using SrcType = typename UnderlyingType<Src>::type;
126 return IsGreaterOrEqual<SrcType, Dst>::Test( 156 return internal::saturated_cast_impl<Dst, NaNHandler>(
127 value, NarrowingRange<Dst, SrcType, SaturationHandler>::lowest()) 157 value, internal::DstRangeRelationToSrcRange<Dst, 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 } 158 }
143 159
144 // strict_cast<> is analogous to static_cast<> for numeric types, except that 160 // 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 161 // 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. 162 // to contain any value in the source type. It performs no runtime checking.
147 template <typename Dst, typename Src> 163 template <typename Dst, typename Src>
148 constexpr Dst strict_cast(Src value) { 164 constexpr Dst strict_cast(Src value) {
149 using SrcType = typename UnderlyingType<Src>::type; 165 using SrcType = typename UnderlyingType<Src>::type;
150 static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric."); 166 static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric.");
151 static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric."); 167 static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric.");
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 STRICT_COMPARISON_OP(IsNotEqual, !=); 278 STRICT_COMPARISON_OP(IsNotEqual, !=);
263 279
264 #undef STRICT_COMPARISON_OP 280 #undef STRICT_COMPARISON_OP
265 }; 281 };
266 282
267 using internal::strict_cast; 283 using internal::strict_cast;
268 using internal::saturated_cast; 284 using internal::saturated_cast;
269 using internal::SafeUnsignedAbs; 285 using internal::SafeUnsignedAbs;
270 using internal::StrictNumeric; 286 using internal::StrictNumeric;
271 using internal::MakeStrictNum; 287 using internal::MakeStrictNum;
272 using internal::IsValueNegative;
273 288
274 // Explicitly make a shorter size_t alias for convenience. 289 // Explicitly make a shorter size_t alias for convenience.
275 using SizeT = StrictNumeric<size_t>; 290 using SizeT = StrictNumeric<size_t>;
276 291
277 } // namespace base 292 } // namespace base
278 293
279 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_ 294 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_
OLDNEW
« no previous file with comments | « no previous file | base/numerics/safe_conversions_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698