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

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

Issue 2931323002: Split out code to be shared between CheckedNumeric and ClampedNumeric (Closed)
Patch Set: iwyu Created 3 years, 6 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
OLDNEW
1 // Copyright 2014 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_SAFE_MATH_H_ 5 #ifndef BASE_NUMERICS_CHECKED_MATH_H_
6 #define BASE_NUMERICS_SAFE_MATH_H_ 6 #define BASE_NUMERICS_CHECKED_MATH_H_
7 7
8 #include <stddef.h> 8 #include <stddef.h>
9 9
10 #include <limits> 10 #include <limits>
11 #include <type_traits> 11 #include <type_traits>
12 12
13 #include "base/numerics/safe_math_impl.h" 13 #include "base/numerics/checked_math_impl.h"
14 14
15 namespace base { 15 namespace base {
16 namespace internal { 16 namespace internal {
17 17
18 // CheckedNumeric<> implements all the logic and operators for detecting integer 18 // CheckedNumeric<> implements all the logic and operators for detecting integer
19 // boundary conditions such as overflow, underflow, and invalid conversions. 19 // boundary conditions such as overflow, underflow, and invalid conversions.
20 // The CheckedNumeric type implicitly converts from floating point and integer 20 // The CheckedNumeric type implicitly converts from floating point and integer
21 // data types, and contains overloads for basic arithmetic operations (i.e.: +, 21 // data types, and contains overloads for basic arithmetic operations (i.e.: +,
22 // -, *, / for all types and %, <<, >>, &, |, ^ for integers). Type promotions 22 // -, *, / for all types and %, <<, >>, &, |, ^ for integers). Type promotions
23 // are a slightly modified version of the standard C arithmetic rules with the 23 // are a slightly modified version of the standard C arithmetic rules with the
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 template <template <typename, typename, typename> class M, 292 template <template <typename, typename, typename> class M,
293 typename L, 293 typename L,
294 typename R> 294 typename R>
295 static CheckedNumeric MathOp(const L lhs, const R rhs) { 295 static CheckedNumeric MathOp(const L lhs, const R rhs) {
296 using Math = typename MathWrapper<M, L, R>::math; 296 using Math = typename MathWrapper<M, L, R>::math;
297 T result = 0; 297 T result = 0;
298 bool is_valid = 298 bool is_valid =
299 Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) && 299 Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) &&
300 Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result); 300 Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result);
301 return CheckedNumeric<T>(result, is_valid); 301 return CheckedNumeric<T>(result, is_valid);
302 }; 302 }
brucedawson 2017/06/12 21:09:22 Who *wrote* the previous version? Must have been a
jschuh 2017/06/12 21:19:21 Let's not dwell on that, and instead just be happy
303 303
304 // Assignment arithmetic operations. 304 // Assignment arithmetic operations.
305 template <template <typename, typename, typename> class M, typename R> 305 template <template <typename, typename, typename> class M, typename R>
306 CheckedNumeric& MathOp(const R rhs) { 306 CheckedNumeric& MathOp(const R rhs) {
307 using Math = typename MathWrapper<M, T, R>::math; 307 using Math = typename MathWrapper<M, T, R>::math;
308 T result = 0; // Using T as the destination saves a range check. 308 T result = 0; // Using T as the destination saves a range check.
309 bool is_valid = state_.is_valid() && Wrapper<R>::is_valid(rhs) && 309 bool is_valid = state_.is_valid() && Wrapper<R>::is_valid(rhs) &&
310 Math::Do(state_.value(), Wrapper<R>::value(rhs), &result); 310 Math::Do(state_.value(), Wrapper<R>::value(rhs), &result);
311 *this = CheckedNumeric<T>(result, is_valid); 311 *this = CheckedNumeric<T>(result, is_valid);
312 return *this; 312 return *this;
313 }; 313 }
314 314
315 private: 315 private:
316 CheckedNumericState<T> state_; 316 CheckedNumericState<T> state_;
317 317
318 template <typename Src> 318 template <typename Src>
319 constexpr CheckedNumeric(Src value, bool is_valid) 319 constexpr CheckedNumeric(Src value, bool is_valid)
320 : state_(value, is_valid) {} 320 : state_(value, is_valid) {}
321 321
322 // These wrappers allow us to handle state the same way for both 322 // These wrappers allow us to handle state the same way for both
323 // CheckedNumeric and POD arithmetic types. 323 // CheckedNumeric and POD arithmetic types.
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 return value.template ValueOrDie<Dst>(); 358 return value.template ValueOrDie<Dst>();
359 } 359 }
360 360
361 template <typename Dst, typename Src, typename Default> 361 template <typename Dst, typename Src, typename Default>
362 constexpr StrictNumeric<Dst> ValueOrDefaultForType( 362 constexpr StrictNumeric<Dst> ValueOrDefaultForType(
363 const CheckedNumeric<Src> value, 363 const CheckedNumeric<Src> value,
364 const Default default_value) { 364 const Default default_value) {
365 return value.template ValueOrDefault<Dst>(default_value); 365 return value.template ValueOrDefault<Dst>(default_value);
366 } 366 }
367 367
368 // These variadic templates work out the return types.
369 // TODO(jschuh): Rip all this out once we have C++14 non-trailing auto support.
370 template <template <typename, typename, typename> class M,
371 typename L,
372 typename R,
373 typename... Args>
374 struct ResultType;
375
376 template <template <typename, typename, typename> class M,
377 typename L,
378 typename R>
379 struct ResultType<M, L, R> {
380 using type = typename MathWrapper<M, L, R>::type;
381 };
382
383 template <template <typename, typename, typename> class M,
384 typename L,
385 typename R,
386 typename... Args>
387 struct ResultType {
388 using type =
389 typename ResultType<M, typename ResultType<M, L, R>::type, Args...>::type;
390 };
391
392 // Convience wrapper to return a new CheckedNumeric from the provided arithmetic 368 // Convience wrapper to return a new CheckedNumeric from the provided arithmetic
393 // or CheckedNumericType. 369 // or CheckedNumericType.
394 template <typename T> 370 template <typename T>
395 constexpr CheckedNumeric<typename UnderlyingType<T>::type> MakeCheckedNum( 371 constexpr CheckedNumeric<typename UnderlyingType<T>::type> MakeCheckedNum(
396 const T value) { 372 const T value) {
397 return value; 373 return value;
398 } 374 }
399 375
400 // These implement the variadic wrapper for the math operations. 376 // These implement the variadic wrapper for the math operations.
401 template <template <typename, typename, typename> class M, 377 template <template <typename, typename, typename> class M,
402 typename L, 378 typename L,
403 typename R> 379 typename R>
404 CheckedNumeric<typename MathWrapper<M, L, R>::type> ChkMathOp(const L lhs, 380 CheckedNumeric<typename MathWrapper<M, L, R>::type> ChkMathOp(const L lhs,
405 const R rhs) { 381 const R rhs) {
406 using Math = typename MathWrapper<M, L, R>::math; 382 using Math = typename MathWrapper<M, L, R>::math;
407 return CheckedNumeric<typename Math::result_type>::template MathOp<M>(lhs, 383 return CheckedNumeric<typename Math::result_type>::template MathOp<M>(lhs,
408 rhs); 384 rhs);
409 } 385 }
410 386
411 // General purpose wrapper template for arithmetic operations. 387 // General purpose wrapper template for arithmetic operations.
412 template <template <typename, typename, typename> class M, 388 template <template <typename, typename, typename> class M,
413 typename L, 389 typename L,
414 typename R, 390 typename R,
415 typename... Args> 391 typename... Args>
416 CheckedNumeric<typename ResultType<M, L, R, Args...>::type> 392 CheckedNumeric<typename ResultType<M, L, R, Args...>::type>
417 ChkMathOp(const L lhs, const R rhs, const Args... args) { 393 ChkMathOp(const L lhs, const R rhs, const Args... args) {
418 auto tmp = ChkMathOp<M>(lhs, rhs); 394 auto tmp = ChkMathOp<M>(lhs, rhs);
419 return tmp.IsValid() ? ChkMathOp<M>(tmp, args...) 395 return tmp.IsValid() ? ChkMathOp<M>(tmp, args...)
420 : decltype(ChkMathOp<M>(tmp, args...))(tmp); 396 : decltype(ChkMathOp<M>(tmp, args...))(tmp);
421 }; 397 }
422 398
423 // The following macros are just boilerplate for the standard arithmetic 399 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Add, +, +=)
424 // operator overloads and variadic function templates. A macro isn't the nicest 400 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Sub, -, -=)
425 // solution, but it beats rewriting these over and over again. 401 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Mul, *, *=)
426 #define BASE_NUMERIC_ARITHMETIC_VARIADIC(NAME) \ 402 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Div, /, /=)
427 template <typename L, typename R, typename... Args> \ 403 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Mod, %, %=)
428 CheckedNumeric<typename ResultType<Checked##NAME##Op, L, R, Args...>::type> \ 404 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Lsh, <<, <<=)
429 Check##NAME(const L lhs, const R rhs, const Args... args) { \ 405 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Rsh, >>, >>=)
430 return ChkMathOp<Checked##NAME##Op, L, R, Args...>(lhs, rhs, args...); \ 406 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, And, &, &=)
431 } 407 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Or, |, |=)
432 408 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Xor, ^, ^=)
433 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ 409 BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Max)
434 /* Binary arithmetic operator for all CheckedNumeric operations. */ \ 410 BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Min)
435 template <typename L, typename R, \
436 typename std::enable_if<IsCheckedOp<L, R>::value>::type* = \
437 nullptr> \
438 CheckedNumeric<typename MathWrapper<Checked##NAME##Op, L, R>::type> \
439 operator OP(const L lhs, const R rhs) { \
440 return decltype(lhs OP rhs)::template MathOp<Checked##NAME##Op>(lhs, rhs); \
441 } \
442 /* Assignment arithmetic operator implementation from CheckedNumeric. */ \
443 template <typename L> \
444 template <typename R> \
445 CheckedNumeric<L>& CheckedNumeric<L>::operator COMPOUND_OP(const R rhs) { \
446 return MathOp<Checked##NAME##Op>(rhs); \
447 } \
448 /* Variadic arithmetic functions that return CheckedNumeric. */ \
449 BASE_NUMERIC_ARITHMETIC_VARIADIC(NAME)
450
451 BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=)
452 BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=)
453 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *=)
454 BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=)
455 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=)
456 BASE_NUMERIC_ARITHMETIC_OPERATORS(Lsh, <<, <<=)
457 BASE_NUMERIC_ARITHMETIC_OPERATORS(Rsh, >>, >>=)
458 BASE_NUMERIC_ARITHMETIC_OPERATORS(And, &, &=)
459 BASE_NUMERIC_ARITHMETIC_OPERATORS(Or, |, |=)
460 BASE_NUMERIC_ARITHMETIC_OPERATORS(Xor, ^, ^=)
461 BASE_NUMERIC_ARITHMETIC_VARIADIC(Max)
462 BASE_NUMERIC_ARITHMETIC_VARIADIC(Min)
463
464 #undef BASE_NUMERIC_ARITHMETIC_VARIADIC
465 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS
466 411
467 // These are some extra StrictNumeric operators to support simple pointer 412 // These are some extra StrictNumeric operators to support simple pointer
468 // arithmetic with our result types. Since wrapping on a pointer is always 413 // arithmetic with our result types. Since wrapping on a pointer is always
469 // bad, we trigger the CHECK condition here. 414 // bad, we trigger the CHECK condition here.
470 template <typename L, typename R> 415 template <typename L, typename R>
471 L* operator+(L* lhs, const StrictNumeric<R> rhs) { 416 L* operator+(L* lhs, const StrictNumeric<R> rhs) {
472 uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs), 417 uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs),
473 CheckMul(sizeof(L), static_cast<R>(rhs))) 418 CheckMul(sizeof(L), static_cast<R>(rhs)))
474 .template ValueOrDie<uintptr_t>(); 419 .template ValueOrDie<uintptr_t>();
475 return reinterpret_cast<L*>(result); 420 return reinterpret_cast<L*>(result);
(...skipping 22 matching lines...) Expand all
498 using internal::CheckDiv; 443 using internal::CheckDiv;
499 using internal::CheckMod; 444 using internal::CheckMod;
500 using internal::CheckLsh; 445 using internal::CheckLsh;
501 using internal::CheckRsh; 446 using internal::CheckRsh;
502 using internal::CheckAnd; 447 using internal::CheckAnd;
503 using internal::CheckOr; 448 using internal::CheckOr;
504 using internal::CheckXor; 449 using internal::CheckXor;
505 450
506 } // namespace base 451 } // namespace base
507 452
508 #endif // BASE_NUMERICS_SAFE_MATH_H_ 453 #endif // BASE_NUMERICS_CHECKED_MATH_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698