| 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 |