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