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

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

Issue 2585043002: Improve saturated_cast performance (Closed)
Patch Set: fix comment nit 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 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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_
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