| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * 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 GAPIC_INTERVAL_LIST_H |
| #define GAPIC_INTERVAL_LIST_H |
| |
| #include <algorithm> |
| #include <vector> |
| |
| namespace gapic { |
| |
| // Interval represents a single interval range of type T. |
| template <typename T> |
| struct Interval { |
| T start; // The index of the first item in the interval range. |
| T end; // The index of the one-past the last item in the interval range. |
| }; |
| |
| // Interval equality operator. |
| template <typename T> |
| inline bool operator == (const Interval<T>& lhs, const Interval<T>& rhs) { |
| return lhs.start == rhs.start && lhs.end == rhs.end; |
| } |
| |
| // IntervalList holds a ascendingly-sorted list of Intervals. |
| // Intervals can be added to the list using merge(), where they may be merged |
| // with existing intervals if the spans are within the specified merge-threshold. |
| // IntervalList supports for-range looping. |
| template <typename T> |
| class IntervalList { |
| public: |
| typedef Interval<T> value_type; |
| typedef const Interval<T>* const_iterator; |
| |
| // Constructs an IntervalList with a default merge threshold of 1. |
| inline IntervalList(); |
| |
| // merge adds the interval i to this list, merging any overlapping intervals. |
| inline void merge(const Interval<T>& i); |
| |
| // setMergeThreshold sets the edge-distance threshold for merging intervals when |
| // calling merge(). Intervals will merge if: edge-distance < threshold. |
| // Examples: |
| // • A threshold of 0 will require intervals to overlap before they are merged. |
| // • A threshold of 1 will merge intervals if they overlap or touch edges. |
| // • A threshold of 2 will merge intervals as described above, and those with a |
| // single unit gap. |
| // Changing the merge thresholds will not affect any existing intervals in the list. |
| inline void setMergeThreshold(T threshold); |
| |
| // clear removes all intervals from the list. |
| inline void clear(); |
| |
| // count returns the number of intervals in the list. |
| inline uint32_t count() const; |
| |
| // begin() returns the pointer to the first interval in the list. |
| inline const Interval<T>* begin() const; |
| |
| // end() returns the pointer to one-past the last interval in the list. |
| inline const Interval<T>* end() const; |
| |
| protected: |
| // mergeStart returns the index of the first interval to use in a merge. |
| inline size_t mergeStart(const Interval<T>& i); |
| |
| // mergeEnd returns the index of one-past the last interval to use in a merge. |
| inline size_t mergeEnd(const Interval<T>& i); |
| |
| std::vector< Interval<T> > mIntervals; |
| T mMergeBias; |
| }; |
| |
| template<typename T> |
| IntervalList<T>::IntervalList() : mMergeBias(0) {} |
| |
| template<typename T> |
| inline void IntervalList<T>::merge(const Interval<T>& i) { |
| if (count() == 0) { |
| mIntervals.push_back(i); |
| } else { |
| auto start = mIntervals.begin() + mergeStart(i); |
| auto end = mIntervals.begin() + mergeEnd(i); |
| if (start <= end) { |
| auto low = std::min(start->start, i.start); |
| auto high = std::max(end->end, i.end); |
| mIntervals.erase(start, end); |
| *start = Interval<T>{low, high}; |
| } else { |
| mIntervals.insert(start, i); |
| } |
| } |
| } |
| |
| template<typename T> |
| inline void IntervalList<T>::setMergeThreshold(T threshold) { |
| mMergeBias = threshold - 1; |
| } |
| |
| template<typename T> |
| inline void IntervalList<T>::clear() { |
| mIntervals.clear(); |
| } |
| |
| template<typename T> |
| inline uint32_t IntervalList<T>::count() const { |
| return mIntervals.size(); |
| } |
| |
| template<typename T> |
| inline const Interval<T>* IntervalList<T>::begin() const { |
| if (count() > 0) { |
| return &mIntervals[0]; |
| } else { |
| return nullptr; |
| } |
| } |
| |
| template<typename T> |
| inline const Interval<T>* IntervalList<T>::end() const { |
| size_t c = mIntervals.size(); |
| if (c > 0) { |
| return &mIntervals[c]; |
| } else { |
| return nullptr; |
| } |
| } |
| |
| template<typename T> |
| inline size_t IntervalList<T>::mergeStart(const Interval<T>& i) { |
| size_t l = 0; |
| size_t h = mIntervals.size(); |
| while (l != h) { |
| size_t m = (l + h) / 2; |
| if (mIntervals[m].end + mMergeBias >= i.start) { |
| h = m; |
| } else { |
| l = m + 1; |
| } |
| } |
| return l; |
| } |
| |
| template<typename T> |
| inline size_t IntervalList<T>::mergeEnd(const Interval<T>& i) { |
| size_t l = -1; |
| size_t h = mIntervals.size() - 1; |
| while (l != h) { |
| size_t m = (l + h + 1) / 2; |
| if (mIntervals[m].start <= i.end + mMergeBias) { |
| l = m; |
| } else { |
| h = m - 1; |
| } |
| } |
| return l; |
| } |
| |
| } // namespace gapic |
| |
| #endif // GAPIC_INTERVAL_LIST_H |