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

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

Issue 2612443002: Convert CheckedNumeric unary operators to constexpr (Closed)
Patch Set: docs Created 3 years, 11 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_math.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 454 matching lines...) Expand 10 before | Expand all | Expand 10 after
465 std::is_arithmetic<U>::value>::type> { 465 std::is_arithmetic<U>::value>::type> {
466 using result_type = typename LowestValuePromotion<T, U>::type; 466 using result_type = typename LowestValuePromotion<T, U>::type;
467 template <typename V = result_type> 467 template <typename V = result_type>
468 static bool Do(T x, U y, V* result) { 468 static bool Do(T x, U y, V* result) {
469 *result = IsLess<T, U>::Test(x, y) ? static_cast<result_type>(x) 469 *result = IsLess<T, U>::Test(x, y) ? static_cast<result_type>(x)
470 : static_cast<result_type>(y); 470 : static_cast<result_type>(y);
471 return true; 471 return true;
472 } 472 }
473 }; 473 };
474 474
475 template <typename T,
476 typename std::enable_if<std::is_integral<T>::value &&
477 std::is_signed<T>::value>::type* = nullptr>
478 bool CheckedNeg(T value, T* result) {
479 // The negation of signed min is min, so catch that one.
480 if (value != std::numeric_limits<T>::lowest()) {
481 *result = static_cast<T>(-value);
482 return true;
483 }
484 return false;
485 }
486
487 template <typename T,
488 typename std::enable_if<std::is_integral<T>::value &&
489 !std::is_signed<T>::value>::type* = nullptr>
490 bool CheckedNeg(T value, T* result) {
491 if (!value) {
492 *result = static_cast<T>(0);
493 return true;
494 }
495 return false;
496 }
497
498 template <typename T,
499 typename std::enable_if<std::is_integral<T>::value &&
500 !std::is_signed<T>::value>::type* = nullptr>
501 bool CheckedInv(T value, T* result) {
502 *result = ~value;
503 return true;
504 }
505
506 template <typename T,
507 typename std::enable_if<std::is_integral<T>::value &&
508 std::is_signed<T>::value>::type* = nullptr>
509 bool CheckedAbs(T value, T* result) {
510 *result = static_cast<T>(SafeUnsignedAbs(value));
511 return *result != std::numeric_limits<T>::lowest();
512 }
513
514 template <typename T,
515 typename std::enable_if<std::is_integral<T>::value &&
516 !std::is_signed<T>::value>::type* = nullptr>
517 bool CheckedAbs(T value, T* result) {
518 // T is unsigned, so |value| must already be positive.
519 *result = value;
520 return true;
521 }
522
523 // This is just boilerplate that wraps the standard floating point arithmetic. 475 // This is just boilerplate that wraps the standard floating point arithmetic.
524 // A macro isn't the nicest solution, but it beats rewriting these repeatedly. 476 // A macro isn't the nicest solution, but it beats rewriting these repeatedly.
525 #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \ 477 #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \
526 template <typename T, typename U> \ 478 template <typename T, typename U> \
527 struct Checked##NAME##Op< \ 479 struct Checked##NAME##Op< \
528 T, U, typename std::enable_if<std::is_floating_point<T>::value || \ 480 T, U, typename std::enable_if<std::is_floating_point<T>::value || \
529 std::is_floating_point<U>::value>::type> { \ 481 std::is_floating_point<U>::value>::type> { \
530 using result_type = typename MaxExponentPromotion<T, U>::type; \ 482 using result_type = typename MaxExponentPromotion<T, U>::type; \
531 template <typename V> \ 483 template <typename V> \
532 static bool Do(T x, U y, V* result) { \ 484 static bool Do(T x, U y, V* result) { \
533 using Promotion = typename MaxExponentPromotion<T, U>::type; \ 485 using Promotion = typename MaxExponentPromotion<T, U>::type; \
534 Promotion presult = x OP y; \ 486 Promotion presult = x OP y; \
535 *result = static_cast<V>(presult); \ 487 *result = static_cast<V>(presult); \
536 return IsValueInRangeForNumericType<V>(presult); \ 488 return IsValueInRangeForNumericType<V>(presult); \
537 } \ 489 } \
538 }; 490 };
539 491
540 BASE_FLOAT_ARITHMETIC_OPS(Add, +) 492 BASE_FLOAT_ARITHMETIC_OPS(Add, +)
541 BASE_FLOAT_ARITHMETIC_OPS(Sub, -) 493 BASE_FLOAT_ARITHMETIC_OPS(Sub, -)
542 BASE_FLOAT_ARITHMETIC_OPS(Mul, *) 494 BASE_FLOAT_ARITHMETIC_OPS(Mul, *)
543 BASE_FLOAT_ARITHMETIC_OPS(Div, /) 495 BASE_FLOAT_ARITHMETIC_OPS(Div, /)
544 496
545 #undef BASE_FLOAT_ARITHMETIC_OPS 497 #undef BASE_FLOAT_ARITHMETIC_OPS
546 498
547 template < 499 // Wrap the unary operations to allow SFINAE when instantiating integrals versus
548 typename T, 500 // floating points. These don't perform any overflow checking. Rather, they
549 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> 501 // exhibit well-defined overflow semantics and rely on the caller to detect
550 bool CheckedNeg(T value, T* result) { 502 // if an overflow occured.
551 *result = static_cast<T>(-value); 503
552 return true; 504 template <typename T,
505 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
506 constexpr T NegateWrapper(T value) {
507 using UnsignedT = typename std::make_unsigned<T>::type;
508 // This will compile to a NEG on Intel, and is normal negation on ARM.
509 return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
553 } 510 }
554 511
555 template < 512 template <
556 typename T, 513 typename T,
557 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> 514 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
558 bool CheckedAbs(T value, T* result) { 515 constexpr T NegateWrapper(T value) {
559 *result = static_cast<T>(std::abs(value)); 516 return -value;
560 return true; 517 }
518
519 template <typename T,
520 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
521 constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
522 return ~value;
523 }
524
525 template <typename T,
526 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
527 constexpr T AbsWrapper(T value) {
528 return static_cast<T>(SafeUnsignedAbs(value));
529 }
530
531 template <
532 typename T,
533 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
534 constexpr T AbsWrapper(T value) {
535 return value < 0 ? -value : value;
561 } 536 }
562 537
563 // Floats carry around their validity state with them, but integers do not. So, 538 // Floats carry around their validity state with them, but integers do not. So,
564 // we wrap the underlying value in a specialization in order to hide that detail 539 // we wrap the underlying value in a specialization in order to hide that detail
565 // and expose an interface via accessors. 540 // and expose an interface via accessors.
566 enum NumericRepresentation { 541 enum NumericRepresentation {
567 NUMERIC_INTEGER, 542 NUMERIC_INTEGER,
568 NUMERIC_FLOATING, 543 NUMERIC_FLOATING,
569 NUMERIC_UNKNOWN 544 NUMERIC_UNKNOWN
570 }; 545 };
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
687 using math = M<typename UnderlyingType<L>::type, 662 using math = M<typename UnderlyingType<L>::type,
688 typename UnderlyingType<R>::type, 663 typename UnderlyingType<R>::type,
689 void>; 664 void>;
690 using type = typename math::result_type; 665 using type = typename math::result_type;
691 }; 666 };
692 667
693 } // namespace internal 668 } // namespace internal
694 } // namespace base 669 } // namespace base
695 670
696 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ 671 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_
OLDNEW
« no previous file with comments | « base/numerics/safe_math.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698