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

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

Issue 2554803002: Cleanup some undefined floating point behavior in base/numerics (Closed)
Patch Set: 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 ||
Nico 2016/12/06 14:03:37 Nice!
644 StaticDstRangeRelationToSrcRange<T, SrcType>::value ==
645 NUMERIC_RANGE_CONTAINED ||
Nico 2016/12/06 14:03:38 Isn't the is_integral check on Src stronger than t
jschuh 2016/12/06 15:07:55 Weird. Somehow I posted this in an incomplete stat
646 is_valid)
647 ? static_cast<T>(value)
648 : static_cast<T>(0);
649 }
650
638 public: 651 public:
639 template <typename Src, NumericRepresentation type> 652 template <typename Src, NumericRepresentation type>
640 friend class CheckedNumericState; 653 friend class CheckedNumericState;
641 654
642 constexpr CheckedNumericState() : is_valid_(true), value_(0) {} 655 constexpr CheckedNumericState() : is_valid_(true), value_(0) {}
643 656
644 template <typename Src> 657 template <typename Src>
645 constexpr CheckedNumericState(Src value, bool is_valid) 658 constexpr CheckedNumericState(Src value, bool is_valid)
646 : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)), 659 : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)),
647 value_(is_valid_ ? static_cast<T>(value) : 0) { 660 value_(WellDefinedConversionOrZero(value, is_valid_)) {
648 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); 661 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
649 } 662 }
650 663
651 // Copy constructor. 664 // Copy constructor.
652 template <typename Src> 665 template <typename Src>
653 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs) 666 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
654 : is_valid_(rhs.IsValid()), 667 : is_valid_(rhs.IsValid()),
655 value_(is_valid_ ? static_cast<T>(rhs.value()) : 0) {} 668 value_(WellDefinedConversionOrZero(rhs.value(), is_valid_)) {}
656 669
657 template <typename Src> 670 template <typename Src>
658 constexpr explicit CheckedNumericState(Src value) 671 constexpr explicit CheckedNumericState(Src value)
659 : is_valid_(IsValueInRangeForNumericType<T>(value)), 672 : is_valid_(IsValueInRangeForNumericType<T>(value)),
660 value_(is_valid_ ? static_cast<T>(value) : 0) {} 673 value_(WellDefinedConversionOrZero(value, is_valid_)) {}
661 674
662 constexpr bool is_valid() const { return is_valid_; } 675 constexpr bool is_valid() const { return is_valid_; }
663 constexpr T value() const { return value_; } 676 constexpr T value() const { return value_; }
664 }; 677 };
665 678
666 // Floating points maintain their own validity, but need translation wrappers. 679 // Floating points maintain their own validity, but need translation wrappers.
667 template <typename T> 680 template <typename T>
668 class CheckedNumericState<T, NUMERIC_FLOATING> { 681 class CheckedNumericState<T, NUMERIC_FLOATING> {
669 private: 682 private:
670 T value_; 683 T value_;
671 684
672 public: 685 public:
673 template <typename Src, NumericRepresentation type> 686 template <typename Src, NumericRepresentation type>
674 friend class CheckedNumericState; 687 friend class CheckedNumericState;
675 688
676 constexpr CheckedNumericState() : value_(0.0) {} 689 constexpr CheckedNumericState() : value_(0.0) {}
677 690
678 template <typename Src> 691 template <typename Src>
679 constexpr CheckedNumericState(Src value, bool is_valid) 692 constexpr CheckedNumericState(Src value, bool is_valid)
680 : value_((is_valid && IsValueInRangeForNumericType<T>(value)) 693 : value_((is_valid && IsValueInRangeForNumericType<T>(value))
Nico 2016/12/06 14:03:37 Did you mean to replace these with saturating_cast
jschuh 2016/12/06 17:11:13 Not exactly, but you were totally correct that the
681 ? static_cast<T>(value) 694 ? static_cast<T>(value)
682 : std::numeric_limits<T>::quiet_NaN()) {} 695 : std::numeric_limits<T>::quiet_NaN()) {}
683 696
684 template <typename Src> 697 template <typename Src>
685 constexpr explicit CheckedNumericState(Src value) 698 constexpr explicit CheckedNumericState(Src value)
686 : value_(static_cast<T>(value)) {} 699 : value_(static_cast<T>(value)) {}
Nico 2016/12/06 14:03:37 ditto
687 700
688 // Copy constructor. 701 // Copy constructor.
689 template <typename Src> 702 template <typename Src>
690 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs) 703 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
691 : value_(static_cast<T>(rhs.value())) {} 704 : value_(static_cast<T>(rhs.value())) {}
Nico 2016/12/06 14:03:38 ditto
692 705
693 constexpr bool is_valid() const { 706 constexpr bool is_valid() const {
694 // Written this way because std::isfinite is not reliably constexpr. 707 // Written this way because std::isfinite is not reliably constexpr.
695 // TODO(jschuh): Fix this if the libraries ever get fixed. 708 // TODO(jschuh): Fix this if the libraries ever get fixed.
696 return value_ <= std::numeric_limits<T>::max() && 709 return value_ <= std::numeric_limits<T>::max() &&
697 value_ >= std::numeric_limits<T>::lowest(); 710 value_ >= std::numeric_limits<T>::lowest();
698 } 711 }
699 constexpr T value() const { return value_; } 712 constexpr T value() const { return value_; }
700 }; 713 };
701 714
702 template <template <typename, typename, typename> class M, 715 template <template <typename, typename, typename> class M,
703 typename L, 716 typename L,
704 typename R> 717 typename R>
705 struct MathWrapper { 718 struct MathWrapper {
706 using math = M<typename UnderlyingType<L>::type, 719 using math = M<typename UnderlyingType<L>::type,
707 typename UnderlyingType<R>::type, 720 typename UnderlyingType<R>::type,
708 void>; 721 void>;
709 using type = typename math::result_type; 722 using type = typename math::result_type;
710 }; 723 };
711 724
712 } // namespace internal 725 } // namespace internal
713 } // namespace base 726 } // namespace base
714 727
715 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ 728 #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