| // Copyright 2014 The Crashpad Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef CRASHPAD_UTIL_NUMERIC_CHECKED_RANGE_H_ |
| #define CRASHPAD_UTIL_NUMERIC_CHECKED_RANGE_H_ |
| |
| #include <limits> |
| #include <tuple> |
| |
| #include "base/logging.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "base/numerics/safe_math.h" |
| #include "util/misc/implicit_cast.h" |
| |
| namespace crashpad { |
| |
| //! \brief Ensures that a range, composed of a base and size, does not overflow |
| //! its data type. |
| template <typename ValueType, typename SizeType = ValueType> |
| class CheckedRange { |
| public: |
| CheckedRange(ValueType base, SizeType size) { |
| static_assert(!std::numeric_limits<SizeType>::is_signed, |
| "SizeType must be unsigned"); |
| SetRange(base, size); |
| } |
| |
| //! \brief Sets the range’s base and size to \a base and \a size, |
| //! respectively. |
| void SetRange(ValueType base, SizeType size) { |
| base_ = base; |
| size_ = size; |
| } |
| |
| //! \brief The range’s base. |
| ValueType base() const { return base_; } |
| |
| //! \brief The range’s size. |
| SizeType size() const { return size_; } |
| |
| //! \brief The range’s end (its base plus its size). |
| ValueType end() const { return base_ + size_; } |
| |
| //! \brief Returns the validity of the range. |
| //! |
| //! \return `true` if the range is valid, `false` otherwise. |
| //! |
| //! A range is valid if its size can be converted to the range’s data type |
| //! without data loss, and if its end (base plus size) can be computed without |
| //! overflowing its data type. |
| bool IsValid() const { |
| if (!base::IsValueInRangeForNumericType<ValueType, SizeType>(size_)) { |
| return false; |
| } |
| base::CheckedNumeric<ValueType> checked_end(base_); |
| checked_end += implicit_cast<ValueType>(size_); |
| return checked_end.IsValid(); |
| } |
| |
| //! \brief Returns whether the range contains another value. |
| //! |
| //! \param[in] value The (possibly) contained value. |
| //! |
| //! \return `true` if the range contains \a value, `false` otherwise. |
| //! |
| //! A range contains a value if the value is greater than or equal to its |
| //! base, and less than its end (base plus size). |
| //! |
| //! This method must only be called if IsValid() would return `true`. |
| bool ContainsValue(ValueType value) const { |
| DCHECK(IsValid()); |
| |
| return value >= base() && value < end(); |
| } |
| |
| //! \brief Returns whether the range contains another range. |
| //! |
| //! \param[in] that The (possibly) contained range. |
| //! |
| //! \return `true` if `this` range, the containing range, contains \a that, |
| //! the contained range. `false` otherwise. |
| //! |
| //! A range contains another range when the contained range’s base is greater |
| //! than or equal to the containing range’s base, and the contained range’s |
| //! end is less than or equal to the containing range’s end. |
| //! |
| //! This method must only be called if IsValid() would return `true` for both |
| //! CheckedRange objects involved. |
| bool ContainsRange(const CheckedRange<ValueType, SizeType>& that) const { |
| DCHECK(IsValid()); |
| DCHECK(that.IsValid()); |
| |
| return that.base() >= base() && that.end() <= end(); |
| } |
| |
| //! \brief Returns whether the range overlaps another range. |
| //! |
| //! \param[in] that The (possibly) overlapping range. |
| //! |
| //! \return `true` if `this` range, the first range, overlaps \a that, |
| //! the provided range. `false` otherwise. |
| //! |
| //! Ranges are considered to be closed-open [base, end) for this test. Zero |
| //! length ranges are never considered to overlap another range. |
| //! |
| //! This method must only be called if IsValid() would return `true` for both |
| //! CheckedRange objects involved. |
| bool OverlapsRange(const CheckedRange<ValueType, SizeType>& that) const { |
| DCHECK(IsValid()); |
| DCHECK(that.IsValid()); |
| |
| if (size() == 0 || that.size() == 0) |
| return false; |
| |
| return base() < that.end() && that.base() < end(); |
| } |
| |
| bool operator<(const CheckedRange& other) const { |
| return std::tie(base_, size_) < std::tie(other.base_, other.size_); |
| } |
| |
| private: |
| ValueType base_; |
| SizeType size_; |
| }; |
| |
| } // namespace crashpad |
| |
| #endif // CRASHPAD_UTIL_NUMERIC_CHECKED_RANGE_H_ |