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

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

Issue 2554803002: Cleanup some undefined floating point behavior in base/numerics (Closed)
Patch Set: compile fix Created 4 years 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.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 617 matching lines...) Expand 10 before | Expand all | Expand 10 after
628 // Integrals require quite a bit of additional housekeeping to manage state. 628 // Integrals require quite a bit of additional housekeeping to manage state.
629 template <typename T> 629 template <typename T>
630 class CheckedNumericState<T, NUMERIC_INTEGER> { 630 class CheckedNumericState<T, NUMERIC_INTEGER> {
631 private: 631 private:
632 // is_valid_ precedes value_ because member intializers in the constructors 632 // is_valid_ precedes value_ because member intializers in the constructors
633 // are evaluated in field order, and is_valid_ must be read when initializing 633 // are evaluated in field order, and is_valid_ must be read when initializing
634 // value_. 634 // value_.
635 bool is_valid_; 635 bool is_valid_;
636 T value_; 636 T value_;
637 637
638 // Ensures that a type conversion does not trigger undefined behavior.
639 template <typename Src>
640 static constexpr T WellDefinedConversionOrZero(const Src value,
641 const bool is_valid) {
642 using SrcType = typename internal::UnderlyingType<Src>::type;
643 return (std::is_integral<SrcType>::value || is_valid)
644 ? static_cast<T>(value)
645 : static_cast<T>(0);
646 }
647
638 public: 648 public:
639 template <typename Src, NumericRepresentation type> 649 template <typename Src, NumericRepresentation type>
640 friend class CheckedNumericState; 650 friend class CheckedNumericState;
641 651
642 constexpr CheckedNumericState() : is_valid_(true), value_(0) {} 652 constexpr CheckedNumericState() : is_valid_(true), value_(0) {}
643 653
644 template <typename Src> 654 template <typename Src>
645 constexpr CheckedNumericState(Src value, bool is_valid) 655 constexpr CheckedNumericState(Src value, bool is_valid)
646 : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)), 656 : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)),
647 value_(is_valid_ ? static_cast<T>(value) : 0) { 657 value_(WellDefinedConversionOrZero(value, is_valid_)) {
648 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); 658 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
649 } 659 }
650 660
651 // Copy constructor. 661 // Copy constructor.
652 template <typename Src> 662 template <typename Src>
653 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs) 663 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
654 : is_valid_(rhs.IsValid()), 664 : is_valid_(rhs.IsValid()),
655 value_(is_valid_ ? static_cast<T>(rhs.value()) : 0) {} 665 value_(WellDefinedConversionOrZero(rhs.value(), is_valid_)) {}
656 666
657 template <typename Src> 667 template <typename Src>
658 constexpr explicit CheckedNumericState(Src value) 668 constexpr explicit CheckedNumericState(Src value)
659 : is_valid_(IsValueInRangeForNumericType<T>(value)), 669 : is_valid_(IsValueInRangeForNumericType<T>(value)),
660 value_(is_valid_ ? static_cast<T>(value) : 0) {} 670 value_(WellDefinedConversionOrZero(value, is_valid_)) {}
661 671
662 constexpr bool is_valid() const { return is_valid_; } 672 constexpr bool is_valid() const { return is_valid_; }
663 constexpr T value() const { return value_; } 673 constexpr T value() const { return value_; }
664 }; 674 };
665 675
666 // Floating points maintain their own validity, but need translation wrappers. 676 // Floating points maintain their own validity, but need translation wrappers.
667 template <typename T> 677 template <typename T>
668 class CheckedNumericState<T, NUMERIC_FLOATING> { 678 class CheckedNumericState<T, NUMERIC_FLOATING> {
669 private: 679 private:
670 T value_; 680 T value_;
671 681
682 // Ensures that a type conversion does not trigger undefined behavior.
683 template <typename Src>
684 static constexpr T WellDefinedConversionOrNaN(const Src value,
685 const bool is_valid) {
686 using SrcType = typename internal::UnderlyingType<Src>::type;
687 return (StaticDstRangeRelationToSrcRange<T, SrcType>::value ==
688 NUMERIC_RANGE_CONTAINED ||
689 is_valid)
690 ? static_cast<T>(value)
691 : std::numeric_limits<T>::quiet_NaN();
692 }
693
672 public: 694 public:
673 template <typename Src, NumericRepresentation type> 695 template <typename Src, NumericRepresentation type>
674 friend class CheckedNumericState; 696 friend class CheckedNumericState;
675 697
676 constexpr CheckedNumericState() : value_(0.0) {} 698 constexpr CheckedNumericState() : value_(0.0) {}
677 699
678 template <typename Src> 700 template <typename Src>
679 constexpr CheckedNumericState(Src value, bool is_valid) 701 constexpr CheckedNumericState(Src value, bool is_valid)
680 : value_((is_valid && IsValueInRangeForNumericType<T>(value)) 702 : value_(WellDefinedConversionOrNaN(value, is_valid)) {}
681 ? static_cast<T>(value)
682 : std::numeric_limits<T>::quiet_NaN()) {}
683 703
684 template <typename Src> 704 template <typename Src>
685 constexpr explicit CheckedNumericState(Src value) 705 constexpr explicit CheckedNumericState(Src value)
686 : value_(static_cast<T>(value)) {} 706 : value_(WellDefinedConversionOrNaN(
707 value,
708 IsValueInRangeForNumericType<T>(value))) {}
687 709
688 // Copy constructor. 710 // Copy constructor.
689 template <typename Src> 711 template <typename Src>
690 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs) 712 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
691 : value_(static_cast<T>(rhs.value())) {} 713 : value_(WellDefinedConversionOrNaN(
714 rhs.value(),
715 rhs.is_valid() && IsValueInRangeForNumericType<T>(rhs.value()))) {}
692 716
693 constexpr bool is_valid() const { 717 constexpr bool is_valid() const {
694 // Written this way because std::isfinite is not reliably constexpr. 718 // Written this way because std::isfinite is not reliably constexpr.
695 // TODO(jschuh): Fix this if the libraries ever get fixed. 719 // TODO(jschuh): Fix this if the libraries ever get fixed.
696 return value_ <= std::numeric_limits<T>::max() && 720 return value_ <= std::numeric_limits<T>::max() &&
697 value_ >= std::numeric_limits<T>::lowest(); 721 value_ >= std::numeric_limits<T>::lowest();
698 } 722 }
699 constexpr T value() const { return value_; } 723 constexpr T value() const { return value_; }
700 }; 724 };
701 725
702 template <template <typename, typename, typename> class M, 726 template <template <typename, typename, typename> class M,
703 typename L, 727 typename L,
704 typename R> 728 typename R>
705 struct MathWrapper { 729 struct MathWrapper {
706 using math = M<typename UnderlyingType<L>::type, 730 using math = M<typename UnderlyingType<L>::type,
707 typename UnderlyingType<R>::type, 731 typename UnderlyingType<R>::type,
708 void>; 732 void>;
709 using type = typename math::result_type; 733 using type = typename math::result_type;
710 }; 734 };
711 735
712 } // namespace internal 736 } // namespace internal
713 } // namespace base 737 } // namespace base
714 738
715 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ 739 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_
OLDNEW
« no previous file with comments | « base/numerics/safe_conversions.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698