Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(273)

Side by Side Diff: base/numerics/safe_math_impl.h

Issue 2600853004: Minor base/numerics cleanup (Closed)
Patch Set: Created 3 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/numerics/safe_conversions_impl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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_
OLDNEW
« no previous file with comments | « base/numerics/safe_conversions_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698