MuseScore/thirdparty/intervaltree/IntervalTree.h
2020-12-17 15:04:40 +02:00

221 lines
5.9 KiB
C++

#ifndef __INTERVAL_TREE_H
#define __INTERVAL_TREE_H
#include <vector>
#include <algorithm>
#include <iostream>
namespace interval_tree {
template <class T, typename K = int>
class Interval {
public:
K start;
K stop;
T value;
Interval(K s, K e, const T& v)
: start(s)
, stop(e)
, value(v)
{ }
};
template <class T, typename K>
int intervalStart(const Interval<T,K>& i) {
return i.start;
}
template <class T, typename K>
int intervalStop(const Interval<T,K>& i) {
return i.stop;
}
template <class T, typename K>
std::ostream& operator<<(std::ostream& out, Interval<T,K>& i) {
out << "Interval(" << i.start << ", " << i.stop << "): " << i.value;
return out;
}
template <class T, typename K = int>
class IntervalStartSorter {
public:
bool operator() (const Interval<T,K>& a, const Interval<T,K>& b) {
return a.start < b.start;
}
};
template <class T, typename K = int>
class IntervalTree {
public:
typedef Interval<T,K> interval;
typedef std::vector<interval> intervalVector;
typedef IntervalTree<T,K> intervalTree;
intervalVector intervals;
intervalTree* left;
intervalTree* right;
int center;
IntervalTree<T,K>(void)
: left(NULL)
, right(NULL)
, center(0)
{ }
IntervalTree<T,K>(const intervalTree& other) {
center = other.center;
intervals = other.intervals;
if (other.left) {
left = (intervalTree*) malloc(sizeof(intervalTree));
*left = *other.left;
} else {
left = NULL;
}
if (other.right) {
right = new intervalTree();
*right = *other.right;
} else {
right = NULL;
}
}
IntervalTree<T,K>& operator=(const intervalTree& other) {
center = other.center;
intervals = other.intervals;
if (other.left) {
left = new intervalTree();
*left = *other.left;
} else {
left = NULL;
}
if (other.right) {
right = new intervalTree();
*right = *other.right;
} else {
right = NULL;
}
return *this;
}
IntervalTree<T,K>(
intervalVector& ivals,
unsigned int depth = 16,
unsigned int minbucket = 64,
int leftextent = 0,
int rightextent = 0,
unsigned int maxbucket = 512
)
: left(NULL)
, right(NULL)
{
--depth;
IntervalStartSorter<T,K> intervalStartSorter;
if (depth == 0 || (ivals.size() < minbucket && ivals.size() < maxbucket)) {
sort(ivals.begin(), ivals.end(), intervalStartSorter);
intervals = ivals;
} else {
if (leftextent == 0 && rightextent == 0) {
// sort intervals by start
sort(ivals.begin(), ivals.end(), intervalStartSorter);
}
int leftp = 0;
int rightp = 0;
int centerp = 0;
if (leftextent || rightextent) {
leftp = leftextent;
rightp = rightextent;
} else {
leftp = ivals.front().start;
std::vector<K> stops;
stops.resize(ivals.size());
transform(ivals.begin(), ivals.end(), stops.begin(), intervalStop<T,K>);
rightp = *max_element(stops.begin(), stops.end());
}
//centerp = ( leftp + rightp ) / 2;
centerp = ivals.at(ivals.size() / 2).start;
center = centerp;
intervalVector lefts;
intervalVector rights;
for (typename intervalVector::iterator i = ivals.begin(); i != ivals.end(); ++i) {
interval& interval = *i;
if (interval.stop < center) {
lefts.push_back(interval);
} else if (interval.start > center) {
rights.push_back(interval);
} else {
intervals.push_back(interval);
}
}
if (!lefts.empty()) {
left = new intervalTree(lefts, depth, minbucket, leftp, centerp);
}
if (!rights.empty()) {
right = new intervalTree(rights, depth, minbucket, centerp, rightp);
}
}
}
void findOverlapping(K start, K stop, intervalVector& overlapping) {
if (!intervals.empty() && ! (stop < intervals.front().start)) {
for (typename intervalVector::iterator i = intervals.begin(); i != intervals.end(); ++i) {
interval& interval = *i;
if (interval.stop >= start && interval.start <= stop) {
overlapping.push_back(interval);
}
}
}
if (left && start <= center) {
left->findOverlapping(start, stop, overlapping);
}
if (right && stop >= center) {
right->findOverlapping(start, stop, overlapping);
}
}
void findContained(K start, K stop, intervalVector& contained) {
if (!intervals.empty() && ! (stop < intervals.front().start)) {
for (typename intervalVector::iterator i = intervals.begin(); i != intervals.end(); ++i) {
interval& interval = *i;
if (interval.start >= start && interval.stop <= stop) {
contained.push_back(interval);
}
}
}
if (left && start <= center) {
left->findContained(start, stop, contained);
}
if (right && stop >= center) {
right->findContained(start, stop, contained);
}
}
~IntervalTree(void) {
// traverse the left and right
// delete them all the way down
if (left) {
delete left;
}
if (right) {
delete right;
}
}
};
}
#endif