Chromium Code Reviews| 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<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_ |
| OLD | NEW |