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_MATH_IMPL_H_ | 5 #ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
7 | 7 |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 #include <stdint.h> | 9 #include <stdint.h> |
10 | 10 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 #else | 50 #else |
51 #define USE_OVERFLOW_BUILTINS (0) | 51 #define USE_OVERFLOW_BUILTINS (0) |
52 #endif | 52 #endif |
53 | 53 |
54 template <typename T, | 54 template <typename T, |
55 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> | 55 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> |
56 bool CheckedAddImpl(T x, T y, T* result) { | 56 bool CheckedAddImpl(T x, T y, T* result) { |
57 // Since the value of x+y is undefined if we have a signed type, we compute | 57 // Since the value of x+y is undefined if we have a signed type, we compute |
58 // it using the unsigned type of the same size. | 58 // it using the unsigned type of the same size. |
59 using UnsignedDst = typename std::make_unsigned<T>::type; | 59 using UnsignedDst = typename std::make_unsigned<T>::type; |
| 60 using SignedDst = typename std::make_signed<T>::type; |
60 UnsignedDst ux = static_cast<UnsignedDst>(x); | 61 UnsignedDst ux = static_cast<UnsignedDst>(x); |
61 UnsignedDst uy = static_cast<UnsignedDst>(y); | 62 UnsignedDst uy = static_cast<UnsignedDst>(y); |
62 UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy); | 63 UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy); |
63 *result = static_cast<T>(uresult); | 64 *result = static_cast<T>(uresult); |
64 // Addition is valid if the sign of (x + y) is equal to either that of x or | 65 // Addition is valid if the sign of (x + y) is equal to either that of x or |
65 // that of y. | 66 // that of y. |
66 return (std::is_signed<T>::value) | 67 return (std::is_signed<T>::value) |
67 ? HasSignBit(BinaryComplement( | 68 ? static_cast<SignedDst>((uresult ^ ux) & (uresult ^ uy)) >= 0 |
68 static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy)))) | 69 : uresult >= uy; // Unsigned is either valid or underflow. |
69 : (BinaryComplement(x) >= | |
70 y); // Unsigned is either valid or underflow. | |
71 } | 70 } |
72 | 71 |
73 template <typename T, typename U, class Enable = void> | 72 template <typename T, typename U, class Enable = void> |
74 struct CheckedAddOp {}; | 73 struct CheckedAddOp {}; |
75 | 74 |
76 template <typename T, typename U> | 75 template <typename T, typename U> |
77 struct CheckedAddOp<T, | 76 struct CheckedAddOp<T, |
78 U, | 77 U, |
79 typename std::enable_if<std::is_integral<T>::value && | 78 typename std::enable_if<std::is_integral<T>::value && |
80 std::is_integral<U>::value>::type> { | 79 std::is_integral<U>::value>::type> { |
(...skipping 21 matching lines...) Expand all Loading... |
102 #endif | 101 #endif |
103 } | 102 } |
104 }; | 103 }; |
105 | 104 |
106 template <typename T, | 105 template <typename T, |
107 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> | 106 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> |
108 bool CheckedSubImpl(T x, T y, T* result) { | 107 bool CheckedSubImpl(T x, T y, T* result) { |
109 // Since the value of x+y is undefined if we have a signed type, we compute | 108 // Since the value of x+y is undefined if we have a signed type, we compute |
110 // it using the unsigned type of the same size. | 109 // it using the unsigned type of the same size. |
111 using UnsignedDst = typename std::make_unsigned<T>::type; | 110 using UnsignedDst = typename std::make_unsigned<T>::type; |
| 111 using SignedDst = typename std::make_signed<T>::type; |
112 UnsignedDst ux = static_cast<UnsignedDst>(x); | 112 UnsignedDst ux = static_cast<UnsignedDst>(x); |
113 UnsignedDst uy = static_cast<UnsignedDst>(y); | 113 UnsignedDst uy = static_cast<UnsignedDst>(y); |
114 UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy); | 114 UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy); |
115 *result = static_cast<T>(uresult); | 115 *result = static_cast<T>(uresult); |
116 // Subtraction is valid if either x and y have same sign, or (x-y) and x have | 116 // Subtraction is valid if either x and y have same sign, or (x-y) and x have |
117 // the same sign. | 117 // the same sign. |
118 return (std::is_signed<T>::value) | 118 return (std::is_signed<T>::value) |
119 ? HasSignBit(BinaryComplement( | 119 ? static_cast<SignedDst>((uresult ^ ux) & (ux ^ uy)) >= 0 |
120 static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy)))) | 120 : x >= y; |
121 : (x >= y); | |
122 } | 121 } |
123 | 122 |
124 template <typename T, typename U, class Enable = void> | 123 template <typename T, typename U, class Enable = void> |
125 struct CheckedSubOp {}; | 124 struct CheckedSubOp {}; |
126 | 125 |
127 template <typename T, typename U> | 126 template <typename T, typename U> |
128 struct CheckedSubOp<T, | 127 struct CheckedSubOp<T, |
129 U, | 128 U, |
130 typename std::enable_if<std::is_integral<T>::value && | 129 typename std::enable_if<std::is_integral<T>::value && |
131 std::is_integral<U>::value>::type> { | 130 std::is_integral<U>::value>::type> { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 | 172 |
174 template <typename T, | 173 template <typename T, |
175 typename std::enable_if< | 174 typename std::enable_if< |
176 std::is_integral<T>::value && std::is_signed<T>::value && | 175 std::is_integral<T>::value && std::is_signed<T>::value && |
177 ((IntegerBitsPlusSign<T>::value * 2) > | 176 ((IntegerBitsPlusSign<T>::value * 2) > |
178 IntegerBitsPlusSign<intmax_t>::value)>::type* = nullptr> | 177 IntegerBitsPlusSign<intmax_t>::value)>::type* = nullptr> |
179 bool CheckedMulImpl(T x, T y, T* result) { | 178 bool CheckedMulImpl(T x, T y, T* result) { |
180 // Since the value of x*y is potentially undefined if we have a signed type, | 179 // Since the value of x*y is potentially undefined if we have a signed type, |
181 // we compute it using the unsigned type of the same size. | 180 // we compute it using the unsigned type of the same size. |
182 using UnsignedDst = typename std::make_unsigned<T>::type; | 181 using UnsignedDst = typename std::make_unsigned<T>::type; |
183 const T is_negative = HasSignBit(x) ^ HasSignBit(y); | |
184 const UnsignedDst ux = SafeUnsignedAbs(x); | 182 const UnsignedDst ux = SafeUnsignedAbs(x); |
185 const UnsignedDst uy = SafeUnsignedAbs(y); | 183 const UnsignedDst uy = SafeUnsignedAbs(y); |
186 UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy); | 184 UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy); |
187 // This is a non-branching conditional negation. | 185 // This is a non-branching conditional negation. |
| 186 const T is_negative = (x ^ y) < 0; |
188 *result = static_cast<T>((uresult ^ -is_negative) + is_negative); | 187 *result = static_cast<T>((uresult ^ -is_negative) + is_negative); |
189 // This uses the unsigned overflow check on the absolute value, with a +1 | 188 // This uses the unsigned overflow check on the absolute value, with a +1 |
190 // bound for a negative result. | 189 // bound for a negative result. |
191 return (uy == 0 || | 190 return (uy == 0 || |
192 ux <= (static_cast<UnsignedDst>(std::numeric_limits<T>::max()) + | 191 ux <= (static_cast<UnsignedDst>(std::numeric_limits<T>::max()) + |
193 is_negative) / | 192 is_negative) / |
194 uy); | 193 uy); |
195 } | 194 } |
196 | 195 |
197 template <typename T, | 196 template <typename T, |
(...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
688 using math = M<typename UnderlyingType<L>::type, | 687 using math = M<typename UnderlyingType<L>::type, |
689 typename UnderlyingType<R>::type, | 688 typename UnderlyingType<R>::type, |
690 void>; | 689 void>; |
691 using type = typename math::result_type; | 690 using type = typename math::result_type; |
692 }; | 691 }; |
693 | 692 |
694 } // namespace internal | 693 } // namespace internal |
695 } // namespace base | 694 } // namespace base |
696 | 695 |
697 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 696 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
OLD | NEW |