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_IMPL_H_ | 5 #ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ |
6 #define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ | 6 #define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ |
7 | 7 |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <limits> | 10 #include <limits> |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
43 return !!(static_cast<typename std::make_unsigned<T>::type>(x) >> | 43 return !!(static_cast<typename std::make_unsigned<T>::type>(x) >> |
44 PositionOfSignBit<T>::value); | 44 PositionOfSignBit<T>::value); |
45 } | 45 } |
46 | 46 |
47 // This wrapper undoes the standard integer promotions. | 47 // This wrapper undoes the standard integer promotions. |
48 template <typename T> | 48 template <typename T> |
49 constexpr T BinaryComplement(T x) { | 49 constexpr T BinaryComplement(T x) { |
50 return static_cast<T>(~x); | 50 return static_cast<T>(~x); |
51 } | 51 } |
52 | 52 |
53 // Determines if a numeric value is negative without throwing compiler | |
54 // warnings on: unsigned(value) < 0. | |
55 template <typename T, | |
56 typename std::enable_if<std::is_signed<T>::value>::type* = nullptr> | |
57 constexpr bool IsValueNegative(T value) { | |
58 static_assert(std::is_arithmetic<T>::value, "Argument must be numeric."); | |
59 return value < 0; | |
60 } | |
61 | |
62 template <typename T, | |
63 typename std::enable_if<!std::is_signed<T>::value>::type* = nullptr> | |
64 constexpr bool IsValueNegative(T) { | |
65 static_assert(std::is_arithmetic<T>::value, "Argument must be numeric."); | |
66 return false; | |
67 } | |
68 | |
69 // This performs a fast negation, returning a signed value. It works on unsigned | |
70 // arguments, but probably doesn't do what you want for any unsigned value | |
71 // larger than max / 2 + 1 (i.e. signed min cast to unsigned). | |
72 template <typename T> | |
73 constexpr typename std::make_signed<T>::type ConditionalNegate( | |
74 T x, | |
75 bool is_negative) { | |
76 static_assert(std::is_integral<T>::value, "Type must be integral"); | |
77 using SignedT = typename std::make_signed<T>::type; | |
78 using UnsignedT = typename std::make_unsigned<T>::type; | |
79 return static_cast<SignedT>( | |
80 (static_cast<UnsignedT>(x) ^ -SignedT(is_negative)) + is_negative); | |
81 } | |
82 | |
53 // This performs a safe, non-branching absolute value via unsigned overflow. | 83 // This performs a safe, non-branching absolute value via unsigned overflow. |
54 template <typename T> | 84 template <typename T> |
55 constexpr T SafeUnsignedAbsImpl(T value, T sign_mask) { | 85 constexpr T SafeUnsignedAbsImpl(T value, T sign_mask) { |
56 static_assert(!std::is_signed<T>::value, "Types must be unsigned."); | 86 static_assert(!std::is_signed<T>::value, "Types must be unsigned."); |
57 return (value ^ sign_mask) - sign_mask; | 87 return (value ^ sign_mask) - sign_mask; |
58 } | 88 } |
59 | 89 |
60 template <typename T, | 90 template <typename T, |
61 typename std::enable_if<std::is_integral<T>::value && | 91 typename std::enable_if<std::is_integral<T>::value && |
62 std::is_signed<T>::value>::type* = nullptr> | 92 std::is_signed<T>::value>::type* = nullptr> |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
174 // value, a range check will erroneously pass. | 204 // value, a range check will erroneously pass. |
175 // Example: (4294967296f <= 4294967295u) // This is true due to a precision | 205 // Example: (4294967296f <= 4294967295u) // This is true due to a precision |
176 // // loss in rounding up to float. | 206 // // loss in rounding up to float. |
177 // 3. When the floating point value is then converted to an integral, the | 207 // 3. When the floating point value is then converted to an integral, the |
178 // resulting value is out of range for the target integral type and | 208 // resulting value is out of range for the target integral type and |
179 // thus is implementation defined. | 209 // thus is implementation defined. |
180 // Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0. | 210 // Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0. |
181 // To fix this bug we manually truncate the maximum value when the destination | 211 // To fix this bug we manually truncate the maximum value when the destination |
182 // type is an integral of larger precision than the source floating-point type, | 212 // type is an integral of larger precision than the source floating-point type, |
183 // such that the resulting maximum is represented exactly as a floating point. | 213 // such that the resulting maximum is represented exactly as a floating point. |
184 template <typename Dst, typename Src> | 214 template <typename Dst, |
215 typename Src, | |
216 template <typename> class Bounds = std::numeric_limits> | |
185 struct NarrowingRange { | 217 struct NarrowingRange { |
186 using SrcLimits = typename std::numeric_limits<Src>; | 218 using SrcLimits = typename std::numeric_limits<Src>; |
187 using DstLimits = typename std::numeric_limits<Dst>; | 219 using DstLimits = typename std::numeric_limits<Dst>; |
188 // The following logic avoids warnings where the max function is | |
189 // instantiated with invalid values for a bit shift (even though | |
190 // such a function can never be called). | |
191 static const int shift = (MaxExponent<Src>::value > MaxExponent<Dst>::value && | |
192 SrcLimits::digits < DstLimits::digits && | |
193 SrcLimits::is_iec559 && | |
194 DstLimits::is_integer) | |
195 ? (DstLimits::digits - SrcLimits::digits) | |
196 : 0; | |
197 | 220 |
198 static constexpr Dst max() { | 221 // Computes the mask required to make an accurate comparison between types. |
199 // We use UINTMAX_C below to avoid compiler warnings about shifting floating | 222 static const int kShift = |
200 // points. Since it's a compile time calculation, it shouldn't have any | 223 (MaxExponent<Src>::value > MaxExponent<Dst>::value && |
201 // performance impact. | 224 SrcLimits::digits < DstLimits::digits) |
202 return DstLimits::max() - static_cast<Dst>((UINTMAX_C(1) << shift) - 1); | 225 ? (DstLimits::digits - SrcLimits::digits) |
226 : 0; | |
227 template < | |
228 typename T, | |
229 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> | |
230 | |
231 // Masks out the integer bits that are beyond the precision of the | |
232 // intermediate type used for comparison. | |
233 static constexpr T Adjust(T value) { | |
234 static_assert(std::is_same<T, Dst>::value, ""); | |
235 static_assert(kShift < DstLimits::digits, ""); | |
236 return static_cast<T>( | |
237 ConditionalNegate(SafeUnsignedAbs(value) & ~((T(1) << kShift) - T(1)), | |
eae
2016/12/15 23:07:46
Nice!
| |
238 IsValueNegative(value))); | |
203 } | 239 } |
204 | 240 |
205 static constexpr Dst lowest() { return DstLimits::lowest(); } | 241 template <typename T, |
242 typename std::enable_if<std::is_floating_point<T>::value>::type* = | |
243 nullptr> | |
244 static constexpr T Adjust(T value) { | |
245 static_assert(std::is_same<T, Dst>::value, ""); | |
246 static_assert(kShift == 0, ""); | |
247 return value; | |
248 } | |
249 | |
250 static constexpr Dst max() { return Adjust(Bounds<Dst>::max()); } | |
251 static constexpr Dst lowest() { return Adjust(Bounds<Dst>::lowest()); } | |
206 }; | 252 }; |
207 | 253 |
208 template <typename Dst, | 254 template <typename Dst, |
209 typename Src, | 255 typename Src, |
210 IntegerRepresentation DstSign = std::is_signed<Dst>::value | 256 IntegerRepresentation DstSign = std::is_signed<Dst>::value |
211 ? INTEGER_REPRESENTATION_SIGNED | 257 ? INTEGER_REPRESENTATION_SIGNED |
212 : INTEGER_REPRESENTATION_UNSIGNED, | 258 : INTEGER_REPRESENTATION_UNSIGNED, |
213 IntegerRepresentation SrcSign = std::is_signed<Src>::value | 259 IntegerRepresentation SrcSign = std::is_signed<Src>::value |
214 ? INTEGER_REPRESENTATION_SIGNED | 260 ? INTEGER_REPRESENTATION_SIGNED |
215 : INTEGER_REPRESENTATION_UNSIGNED, | 261 : INTEGER_REPRESENTATION_UNSIGNED, |
(...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
648 static_cast<BigType>(static_cast<L>(lhs)), | 694 static_cast<BigType>(static_cast<L>(lhs)), |
649 static_cast<BigType>(static_cast<R>(rhs))) | 695 static_cast<BigType>(static_cast<R>(rhs))) |
650 // Let the template functions figure it out for mixed types. | 696 // Let the template functions figure it out for mixed types. |
651 : C<L, R>::Test(lhs, rhs); | 697 : C<L, R>::Test(lhs, rhs); |
652 }; | 698 }; |
653 | 699 |
654 } // namespace internal | 700 } // namespace internal |
655 } // namespace base | 701 } // namespace base |
656 | 702 |
657 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ | 703 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ |
OLD | NEW |