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 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 static constexpr T lowest() { return std::numeric_limits<T>::lowest(); } | 99 static constexpr T lowest() { return std::numeric_limits<T>::lowest(); } |
100 static constexpr T Underflow() { | 100 static constexpr T Underflow() { |
101 return std::numeric_limits<T>::has_infinity | 101 return std::numeric_limits<T>::has_infinity |
102 ? std::numeric_limits<T>::infinity() * -1 | 102 ? std::numeric_limits<T>::infinity() * -1 |
103 : std::numeric_limits<T>::lowest(); | 103 : std::numeric_limits<T>::lowest(); |
104 } | 104 } |
105 }; | 105 }; |
106 | 106 |
107 namespace internal { | 107 namespace internal { |
108 | 108 |
109 template <typename T, template <typename> class S> | 109 template <typename Dst, template <typename> class S, typename Src> |
110 struct IsDefaultIntegralBounds { | |
111 static const bool value = | |
112 std::is_integral<T>::value && | |
113 S<T>::max() == SaturationDefaultHandler<T>::max() && | |
114 S<T>::lowest() == SaturationDefaultHandler<T>::lowest(); | |
115 }; | |
116 | |
117 // Integral to integral conversions have a special optimization for the | |
118 // standard bounds. | |
119 template <typename Dst, | |
120 template <typename> class S, | |
121 typename Src, | |
122 typename std::enable_if< | |
123 std::is_integral<Src>::value && | |
124 IsDefaultIntegralBounds<Dst, S>::value>::type* = nullptr> | |
125 constexpr Dst saturated_cast_impl(Src value, RangeCheck constraint) { | |
126 using UnsignedDst = typename std::make_unsigned<Dst>::type; | |
127 // The member fields in this class are lined up such that the compiler | |
128 // can saturate without branching in this case by adding the register | |
129 // with the bitfields directly to the integral max. | |
130 return constraint.IsValid() | |
131 ? static_cast<Dst>(value) | |
132 : static_cast<Dst>(UnsignedDst(constraint.IsUnderflowFlagSet()) + | |
133 std::numeric_limits<Dst>::max()); | |
134 } | |
135 | |
136 template <typename Dst, | |
137 template <typename> class S, | |
138 typename Src, | |
139 typename std::enable_if< | |
140 !std::is_integral<Src>::value || | |
141 !IsDefaultIntegralBounds<Dst, S>::value>::type* = nullptr> | |
142 constexpr Dst saturated_cast_impl(Src value, RangeCheck constraint) { | 110 constexpr Dst saturated_cast_impl(Src value, RangeCheck constraint) { |
143 // For some reason clang generates much better code when the branch is | 111 // For some reason clang generates much better code when the branch is |
144 // structured exactly this way, rather than a sequence of checks. | 112 // structured exactly this way, rather than a sequence of checks. |
145 return !constraint.IsOverflowFlagSet() | 113 return !constraint.IsOverflowFlagSet() |
146 ? (!constraint.IsUnderflowFlagSet() ? static_cast<Dst>(value) | 114 ? (!constraint.IsUnderflowFlagSet() ? static_cast<Dst>(value) |
147 : S<Dst>::Underflow()) | 115 : S<Dst>::Underflow()) |
148 // Skip this check for integral Src, which cannot be NaN. | 116 // Skip this check for integral Src, which cannot be NaN. |
149 : (std::is_integral<Src>::value || !constraint.IsUnderflowFlagSet() | 117 : (std::is_integral<Src>::value || !constraint.IsUnderflowFlagSet() |
150 ? S<Dst>::Overflow() | 118 ? S<Dst>::Overflow() |
151 : S<Dst>::NaN()); | 119 : S<Dst>::NaN()); |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 using internal::StrictNumeric; | 263 using internal::StrictNumeric; |
296 using internal::MakeStrictNum; | 264 using internal::MakeStrictNum; |
297 using internal::IsValueNegative; | 265 using internal::IsValueNegative; |
298 | 266 |
299 // Explicitly make a shorter size_t alias for convenience. | 267 // Explicitly make a shorter size_t alias for convenience. |
300 using SizeT = StrictNumeric<size_t>; | 268 using SizeT = StrictNumeric<size_t>; |
301 | 269 |
302 } // namespace base | 270 } // namespace base |
303 | 271 |
304 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_ | 272 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_ |
OLD | NEW |