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

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

Issue 2554803002: Cleanup some undefined floating point behavior in base/numerics (Closed)
Patch Set: fixed 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
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<Src>::value || is_valid) ? static_cast<T>(value)
644 : static_cast<T>(0);
645 }
646
638 public: 647 public:
639 template <typename Src, NumericRepresentation type> 648 template <typename Src, NumericRepresentation type>
640 friend class CheckedNumericState; 649 friend class CheckedNumericState;
641 650
642 constexpr CheckedNumericState() : is_valid_(true), value_(0) {} 651 constexpr CheckedNumericState() : is_valid_(true), value_(0) {}
643 652
644 template <typename Src> 653 template <typename Src>
645 constexpr CheckedNumericState(Src value, bool is_valid) 654 constexpr CheckedNumericState(Src value, bool is_valid)
646 : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)), 655 : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)),
647 value_(is_valid_ ? static_cast<T>(value) : 0) { 656 value_(WellDefinedConversionOrZero(value, is_valid_)) {
648 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); 657 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
649 } 658 }
650 659
651 // Copy constructor. 660 // Copy constructor.
652 template <typename Src> 661 template <typename Src>
653 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs) 662 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
654 : is_valid_(rhs.IsValid()), 663 : is_valid_(rhs.IsValid()),
655 value_(is_valid_ ? static_cast<T>(rhs.value()) : 0) {} 664 value_(WellDefinedConversionOrZero(rhs.value(), is_valid_)) {}
656 665
657 template <typename Src> 666 template <typename Src>
658 constexpr explicit CheckedNumericState(Src value) 667 constexpr explicit CheckedNumericState(Src value)
659 : is_valid_(IsValueInRangeForNumericType<T>(value)), 668 : is_valid_(IsValueInRangeForNumericType<T>(value)),
660 value_(is_valid_ ? static_cast<T>(value) : 0) {} 669 value_(WellDefinedConversionOrZero(value, is_valid_)) {}
661 670
662 constexpr bool is_valid() const { return is_valid_; } 671 constexpr bool is_valid() const { return is_valid_; }
663 constexpr T value() const { return value_; } 672 constexpr T value() const { return value_; }
664 }; 673 };
665 674
666 // Floating points maintain their own validity, but need translation wrappers. 675 // Floating points maintain their own validity, but need translation wrappers.
667 template <typename T> 676 template <typename T>
668 class CheckedNumericState<T, NUMERIC_FLOATING> { 677 class CheckedNumericState<T, NUMERIC_FLOATING> {
669 private: 678 private:
670 T value_; 679 T value_;
671 680
681 // Ensures that a type conversion does not trigger undefined behavior.
682 template <typename Src>
683 static constexpr T WellDefinedConversionOrNaN(const Src value,
684 const bool is_valid) {
685 using SrcType = typename internal::UnderlyingType<Src>::type;
686 return (StaticDstRangeRelationToSrcRange<T, SrcType>::value ==
687 NUMERIC_RANGE_CONTAINED ||
688 is_valid)
689 ? static_cast<T>(value)
690 : static_cast<T>(std::numeric_limits<T>::quiet_NaN());
Nico 2016/12/06 17:15:50 Do you need the cast here? numeric_limits<T>::quie
jschuh 2016/12/06 17:33:59 I do not, and that's what I get for hurriedly rewr
691 }
692
672 public: 693 public:
673 template <typename Src, NumericRepresentation type> 694 template <typename Src, NumericRepresentation type>
674 friend class CheckedNumericState; 695 friend class CheckedNumericState;
675 696
676 constexpr CheckedNumericState() : value_(0.0) {} 697 constexpr CheckedNumericState() : value_(0.0) {}
677 698
678 template <typename Src> 699 template <typename Src>
679 constexpr CheckedNumericState(Src value, bool is_valid) 700 constexpr CheckedNumericState(Src value, bool is_valid)
680 : value_((is_valid && IsValueInRangeForNumericType<T>(value)) 701 : value_(WellDefinedConversionOrNaN(value, is_valid)) {}
681 ? static_cast<T>(value)
682 : std::numeric_limits<T>::quiet_NaN()) {}
683 702
684 template <typename Src> 703 template <typename Src>
685 constexpr explicit CheckedNumericState(Src value) 704 constexpr explicit CheckedNumericState(Src value)
686 : value_(static_cast<T>(value)) {} 705 : value_(WellDefinedConversionOrNaN(
706 value,
707 IsValueInRangeForNumericType<T>(value))) {}
687 708
688 // Copy constructor. 709 // Copy constructor.
689 template <typename Src> 710 template <typename Src>
690 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs) 711 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
691 : value_(static_cast<T>(rhs.value())) {} 712 : value_(WellDefinedConversionOrNaN(
713 rhs.value(),
714 rhs.is_valid() && IsValueInRangeForNumericType<T>(rhs.value()))) {}
692 715
693 constexpr bool is_valid() const { 716 constexpr bool is_valid() const {
694 // Written this way because std::isfinite is not reliably constexpr. 717 // Written this way because std::isfinite is not reliably constexpr.
695 // TODO(jschuh): Fix this if the libraries ever get fixed. 718 // TODO(jschuh): Fix this if the libraries ever get fixed.
696 return value_ <= std::numeric_limits<T>::max() && 719 return value_ <= std::numeric_limits<T>::max() &&
697 value_ >= std::numeric_limits<T>::lowest(); 720 value_ >= std::numeric_limits<T>::lowest();
698 } 721 }
699 constexpr T value() const { return value_; } 722 constexpr T value() const { return value_; }
700 }; 723 };
701 724
702 template <template <typename, typename, typename> class M, 725 template <template <typename, typename, typename> class M,
703 typename L, 726 typename L,
704 typename R> 727 typename R>
705 struct MathWrapper { 728 struct MathWrapper {
706 using math = M<typename UnderlyingType<L>::type, 729 using math = M<typename UnderlyingType<L>::type,
707 typename UnderlyingType<R>::type, 730 typename UnderlyingType<R>::type,
708 void>; 731 void>;
709 using type = typename math::result_type; 732 using type = typename math::result_type;
710 }; 733 };
711 734
712 } // namespace internal 735 } // namespace internal
713 } // namespace base 736 } // namespace base
714 737
715 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ 738 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_
OLDNEW
« base/numerics/safe_conversions.h ('K') | « base/numerics/safe_conversions.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698