blob: c3bacf0a44ad302d4e51b32e853ba27125d24f03 [file] [log] [blame]
/*
* 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