| OLD | NEW |
| 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 Loading... |
| 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_ |
| OLD | NEW |