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 | |
83 // This performs a safe, non-branching absolute value via unsigned overflow. | 53 // This performs a safe, non-branching absolute value via unsigned overflow. |
84 template <typename T> | 54 template <typename T> |
85 constexpr T SafeUnsignedAbsImpl(T value, T sign_mask) { | 55 constexpr T SafeUnsignedAbsImpl(T value, T sign_mask) { |
86 static_assert(!std::is_signed<T>::value, "Types must be unsigned."); | 56 static_assert(!std::is_signed<T>::value, "Types must be unsigned."); |
87 return (value ^ sign_mask) - sign_mask; | 57 return (value ^ sign_mask) - sign_mask; |
88 } | 58 } |
89 | 59 |
90 template <typename T, | 60 template <typename T, |
91 typename std::enable_if<std::is_integral<T>::value && | 61 typename std::enable_if<std::is_integral<T>::value && |
92 std::is_signed<T>::value>::type* = nullptr> | 62 std::is_signed<T>::value>::type* = nullptr> |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 // value, a range check will erroneously pass. | 174 // value, a range check will erroneously pass. |
205 // Example: (4294967296f <= 4294967295u) // This is true due to a precision | 175 // Example: (4294967296f <= 4294967295u) // This is true due to a precision |
206 // // loss in rounding up to float. | 176 // // loss in rounding up to float. |
207 // 3. When the floating point value is then converted to an integral, the | 177 // 3. When the floating point value is then converted to an integral, the |
208 // resulting value is out of range for the target integral type and | 178 // resulting value is out of range for the target integral type and |
209 // thus is implementation defined. | 179 // thus is implementation defined. |
210 // Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0. | 180 // Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0. |
211 // To fix this bug we manually truncate the maximum value when the destination | 181 // To fix this bug we manually truncate the maximum value when the destination |
212 // type is an integral of larger precision than the source floating-point type, | 182 // type is an integral of larger precision than the source floating-point type, |
213 // such that the resulting maximum is represented exactly as a floating point. | 183 // such that the resulting maximum is represented exactly as a floating point. |
214 template <typename Dst, | 184 template <typename Dst, typename Src> |
215 typename Src, | |
216 template <typename> class Bounds = std::numeric_limits> | |
217 struct NarrowingRange { | 185 struct NarrowingRange { |
218 using SrcLimits = typename std::numeric_limits<Src>; | 186 using SrcLimits = typename std::numeric_limits<Src>; |
219 using DstLimits = typename std::numeric_limits<Dst>; | 187 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; |
220 | 197 |
221 // Computes the mask required to make an accurate comparison between types. | 198 static constexpr Dst max() { |
222 static const int kShift = | 199 // We use UINTMAX_C below to avoid compiler warnings about shifting floating |
223 (MaxExponent<Src>::value > MaxExponent<Dst>::value && | 200 // points. Since it's a compile time calculation, it shouldn't have any |
224 SrcLimits::digits < DstLimits::digits) | 201 // performance impact. |
225 ? (DstLimits::digits - SrcLimits::digits) | 202 return DstLimits::max() - static_cast<Dst>((UINTMAX_C(1) << shift) - 1); |
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)), | |
238 IsValueNegative(value))); | |
239 } | 203 } |
240 | 204 |
241 template <typename T, | 205 static constexpr Dst lowest() { return DstLimits::lowest(); } |
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()); } | |
252 }; | 206 }; |
253 | 207 |
254 template <typename Dst, | 208 template <typename Dst, |
255 typename Src, | 209 typename Src, |
256 IntegerRepresentation DstSign = std::is_signed<Dst>::value | 210 IntegerRepresentation DstSign = std::is_signed<Dst>::value |
257 ? INTEGER_REPRESENTATION_SIGNED | 211 ? INTEGER_REPRESENTATION_SIGNED |
258 : INTEGER_REPRESENTATION_UNSIGNED, | 212 : INTEGER_REPRESENTATION_UNSIGNED, |
259 IntegerRepresentation SrcSign = std::is_signed<Src>::value | 213 IntegerRepresentation SrcSign = std::is_signed<Src>::value |
260 ? INTEGER_REPRESENTATION_SIGNED | 214 ? INTEGER_REPRESENTATION_SIGNED |
261 : INTEGER_REPRESENTATION_UNSIGNED, | 215 : INTEGER_REPRESENTATION_UNSIGNED, |
(...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
694 static_cast<BigType>(static_cast<L>(lhs)), | 648 static_cast<BigType>(static_cast<L>(lhs)), |
695 static_cast<BigType>(static_cast<R>(rhs))) | 649 static_cast<BigType>(static_cast<R>(rhs))) |
696 // Let the template functions figure it out for mixed types. | 650 // Let the template functions figure it out for mixed types. |
697 : C<L, R>::Test(lhs, rhs); | 651 : C<L, R>::Test(lhs, rhs); |
698 }; | 652 }; |
699 | 653 |
700 } // namespace internal | 654 } // namespace internal |
701 } // namespace base | 655 } // namespace base |
702 | 656 |
703 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ | 657 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ |
OLD | NEW |