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

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

Issue 2945433003: Add ClampedNumeric templates (Closed)
Patch Set: final Created 3 years, 5 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/checked_math.h ('k') | base/numerics/clamped_math.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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_CHECKED_MATH_IMPL_H_ 5 #ifndef BASE_NUMERICS_CHECKED_MATH_IMPL_H_
6 #define BASE_NUMERICS_CHECKED_MATH_IMPL_H_ 6 #define BASE_NUMERICS_CHECKED_MATH_IMPL_H_
7 7
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <stdint.h> 9 #include <stdint.h>
10 10
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 (IntegerBitsPlusSign<__typeof__(x * y)>::value == 175 (IntegerBitsPlusSign<__typeof__(x * y)>::value ==
176 IntegerBitsPlusSign<intptr_t>::value && 176 IntegerBitsPlusSign<intptr_t>::value &&
177 std::is_signed<T>::value == std::is_signed<U>::value); 177 std::is_signed<T>::value == std::is_signed<U>::value);
178 #else 178 #else
179 static const bool kUseMaxInt = true; 179 static const bool kUseMaxInt = true;
180 #endif 180 #endif
181 if (kUseMaxInt) 181 if (kUseMaxInt)
182 return !__builtin_mul_overflow(x, y, result); 182 return !__builtin_mul_overflow(x, y, result);
183 #endif 183 #endif
184 using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type; 184 using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
185 // Verify the destination type can hold the result (always true for 0).
186 if (!(IsValueInRangeForNumericType<Promotion>(x) &&
187 IsValueInRangeForNumericType<Promotion>(y)) &&
188 x && y) {
189 return false;
190 }
185 Promotion presult; 191 Promotion presult;
186 // Fail if either operand is out of range for the promoted type. 192 bool is_valid = true;
187 // TODO(jschuh): This could be made to work for a broader range of values.
188 bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
189 IsValueInRangeForNumericType<Promotion>(y);
190
191 if (IsIntegerArithmeticSafe<Promotion, T, U>::value) { 193 if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
192 presult = static_cast<Promotion>(x) * static_cast<Promotion>(y); 194 presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
193 } else { 195 } else {
194 is_valid &= CheckedMulImpl(static_cast<Promotion>(x), 196 is_valid = CheckedMulImpl(static_cast<Promotion>(x),
195 static_cast<Promotion>(y), &presult); 197 static_cast<Promotion>(y), &presult);
196 } 198 }
197 *result = static_cast<V>(presult); 199 *result = static_cast<V>(presult);
198 return is_valid && IsValueInRangeForNumericType<V>(presult); 200 return is_valid && IsValueInRangeForNumericType<V>(presult);
199 } 201 }
200 }; 202 };
201 203
202 // Avoid poluting the namespace once we're done with the macro. 204 // Avoid poluting the namespace once we're done with the macro.
203 #undef USE_OVERFLOW_BUILTINS 205 #undef USE_OVERFLOW_BUILTINS
204 206
205 // Division just requires a check for a zero denominator or an invalid negation 207 // Division just requires a check for a zero denominator or an invalid negation
(...skipping 29 matching lines...) Expand all
235 is_valid &= CheckedDivImpl(static_cast<Promotion>(x), 237 is_valid &= CheckedDivImpl(static_cast<Promotion>(x),
236 static_cast<Promotion>(y), &presult); 238 static_cast<Promotion>(y), &presult);
237 *result = static_cast<V>(presult); 239 *result = static_cast<V>(presult);
238 return is_valid && IsValueInRangeForNumericType<V>(presult); 240 return is_valid && IsValueInRangeForNumericType<V>(presult);
239 } 241 }
240 }; 242 };
241 243
242 template <typename T> 244 template <typename T>
243 bool CheckedModImpl(T x, T y, T* result) { 245 bool CheckedModImpl(T x, T y, T* result) {
244 static_assert(std::is_integral<T>::value, "Type must be integral"); 246 static_assert(std::is_integral<T>::value, "Type must be integral");
245 if (y > 0) { 247 if (y) {
246 *result = static_cast<T>(x % y); 248 *result = static_cast<T>(x % y);
247 return true; 249 return true;
248 } 250 }
249 return false; 251 return false;
250 } 252 }
251 253
252 template <typename T, typename U, class Enable = void> 254 template <typename T, typename U, class Enable = void>
253 struct CheckedModOp {}; 255 struct CheckedModOp {};
254 256
255 template <typename T, typename U> 257 template <typename T, typename U>
(...skipping 20 matching lines...) Expand all
276 // of bits in the promoted type are undefined. Shifts of negative values 278 // of bits in the promoted type are undefined. Shifts of negative values
277 // are undefined. Otherwise it is defined when the result fits. 279 // are undefined. Otherwise it is defined when the result fits.
278 template <typename T, typename U> 280 template <typename T, typename U>
279 struct CheckedLshOp<T, 281 struct CheckedLshOp<T,
280 U, 282 U,
281 typename std::enable_if<std::is_integral<T>::value && 283 typename std::enable_if<std::is_integral<T>::value &&
282 std::is_integral<U>::value>::type> { 284 std::is_integral<U>::value>::type> {
283 using result_type = T; 285 using result_type = T;
284 template <typename V> 286 template <typename V>
285 static bool Do(T x, U shift, V* result) { 287 static bool Do(T x, U shift, V* result) {
286 using ShiftType = typename std::make_unsigned<T>::type;
287 static const ShiftType kBitWidth = IntegerBitsPlusSign<T>::value;
288 const ShiftType real_shift = static_cast<ShiftType>(shift);
289 // Signed shift is not legal on negative values. 288 // Signed shift is not legal on negative values.
290 if (!IsValueNegative(x) && real_shift < kBitWidth) { 289 if (!IsValueNegative(x) &&
290 as_unsigned(shift) < IntegerBitsPlusSign<T>::value) {
291 // Just use a multiplication because it's easy. 291 // Just use a multiplication because it's easy.
292 // TODO(jschuh): This could probably be made more efficient. 292 // TODO(jschuh): This could probably be made more efficient.
293 if (!std::is_signed<T>::value || real_shift != kBitWidth - 1) 293 if (!std::is_signed<T>::value ||
294 return CheckedMulOp<T, T>::Do(x, static_cast<T>(1) << shift, result); 294 as_unsigned(shift) < std::numeric_limits<T>::digits)
295 return CheckedMulOp<T, T>::Do(x, T(1) << shift, result);
296 *result = 0;
295 return !x; // Special case zero for a full width signed shift. 297 return !x; // Special case zero for a full width signed shift.
296 } 298 }
297 return false; 299 return false;
298 } 300 }
299 }; 301 };
300 302
301 template <typename T, typename U, class Enable = void> 303 template <typename T, typename U, class Enable = void>
302 struct CheckedRshOp {}; 304 struct CheckedRshOp {};
303 305
304 // Right shift. Shifts less than 0 or greater than or equal to the number 306 // Right shift. Shifts less than 0 or greater than or equal to the number
305 // of bits in the promoted type are undefined. Otherwise, it is always defined, 307 // of bits in the promoted type are undefined. Otherwise, it is always defined,
306 // but a right shift of a negative value is implementation-dependent. 308 // but a right shift of a negative value is implementation-dependent.
307 template <typename T, typename U> 309 template <typename T, typename U>
308 struct CheckedRshOp<T, 310 struct CheckedRshOp<T,
309 U, 311 U,
310 typename std::enable_if<std::is_integral<T>::value && 312 typename std::enable_if<std::is_integral<T>::value &&
311 std::is_integral<U>::value>::type> { 313 std::is_integral<U>::value>::type> {
312 using result_type = T; 314 using result_type = T;
313 template <typename V> 315 template <typename V>
314 static bool Do(T x, U shift, V* result) { 316 static bool Do(T x, U shift, V* result) {
315 // Use the type conversion push negative values out of range. 317 // Use the type conversion push negative values out of range.
316 using ShiftType = typename std::make_unsigned<T>::type; 318 if (as_unsigned(shift) < IntegerBitsPlusSign<T>::value) {
317 if (static_cast<ShiftType>(shift) < IntegerBitsPlusSign<T>::value) {
318 T tmp = x >> shift; 319 T tmp = x >> shift;
319 *result = static_cast<V>(tmp); 320 *result = static_cast<V>(tmp);
320 return IsValueInRangeForNumericType<V>(tmp); 321 return IsValueInRangeForNumericType<V>(tmp);
321 } 322 }
322 return false; 323 return false;
323 } 324 }
324 }; 325 };
325 326
326 template <typename T, typename U, class Enable = void> 327 template <typename T, typename U, class Enable = void>
327 struct CheckedAndOp {}; 328 struct CheckedAndOp {};
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
564 return value_ <= std::numeric_limits<T>::max() && 565 return value_ <= std::numeric_limits<T>::max() &&
565 value_ >= std::numeric_limits<T>::lowest(); 566 value_ >= std::numeric_limits<T>::lowest();
566 } 567 }
567 constexpr T value() const { return value_; } 568 constexpr T value() const { return value_; }
568 }; 569 };
569 570
570 } // namespace internal 571 } // namespace internal
571 } // namespace base 572 } // namespace base
572 573
573 #endif // BASE_NUMERICS_CHECKED_MATH_IMPL_H_ 574 #endif // BASE_NUMERICS_CHECKED_MATH_IMPL_H_
OLDNEW
« no previous file with comments | « base/numerics/checked_math.h ('k') | base/numerics/clamped_math.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698