 Chromium Code Reviews
 Chromium Code Reviews Issue 2931323002:
  Split out code to be shared between CheckedNumeric and ClampedNumeric  (Closed)
    
  
    Issue 2931323002:
  Split out code to be shared between CheckedNumeric and ClampedNumeric  (Closed) 
  | OLD | NEW | 
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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_ | 
| OLD | NEW |