Files
mlpack/fastlib/col/rangeset.h
T

136 lines
2.6 KiB
C++

/**
* @file rangeset.h
*
* Sets of contiguous ranges.
*/
#ifndef COL_RANGESET_H
#define COL_RANGESET_H
#include "arraylist.h"
/**
* A set containing a union of [start,end) ranges that are automatically
* sorted and merged when possible.
*
* The copy constructor and inequality operators must be defined of the
* template class.
*
* This is O(N) insertion, so not efficient for large sets.
*/
template<typename TBoundary>
class RangeSet {
public:
typedef TBoundary Boundary;
public:
struct Range {
Boundary begin;
Boundary end;
OT_DEF_BASIC(Range) {
OT_MY_OBJECT(begin);
OT_MY_OBJECT(end);
}
};
private:
ArrayList<Range> ranges_;
OT_DEF(RangeSet) {
OT_MY_OBJECT(ranges_);
}
public:
/**
* Creates an empty set of ranges.
*/
void Init() {
ranges_.Init();
}
/**
* Reinitializes to an empty set of ranges.
*/
void Reset() {
ranges_.Clear();
}
/**
* Unions this with a particular range.
*
* This will automatically merge with any surrounding ranges.
*/
void Union(const Boundary& begin, const Boundary& end);
const ArrayList<Range>& ranges() const {
return ranges_;
}
/**
* Gets a constant range element.
*/
const Range& operator[] (index_t i) const {
return ranges_[i];
}
/**
* Gets the number of discrete ranges.
*/
index_t size() const {
return ranges_.size();
}
};
template<typename TBoundary>
void RangeSet<TBoundary>::Union(
const Boundary& begin, const Boundary& end) {
if (unlikely(!(begin < end))) {
// Merging with empty range?
return;
}
// Not really efficient, but easy to follow.
ArrayList<Range> new_list;
index_t i;
new_list.Init();
i = 0;
// add everything that strictly precedes the new one to add
while (i < ranges_.size() && !(begin <= ranges_[i].end)) {
new_list.AddBackItem(ranges_[i]);
i++;
}
// merge everything that overlaps
const Boundary *selected_end = &end;
const Boundary *selected_begin = &begin;
while (i < ranges_.size() && end >= ranges_[i].begin) {
if (ranges_[i].begin < *selected_begin) {
selected_begin = &ranges_[i].begin;
}
if (ranges_[i].end > *selected_end) {
selected_end = &ranges_[i].end;
}
i++;
}
Range *new_range = new_list.AddBackUnconstructed();
new(&new_range->begin)Boundary(*selected_begin);
new(&new_range->end)Boundary(*selected_end);
// add everything that comes after
for (; i < ranges_.size(); i++) {
new_list.AddBackItem(ranges_[i]);
}
// replace the list
ranges_.Swap(&new_list);
}
#endif