/** Adds a new number range. The range describes a mapping from c to v(c), where * \f$c \in [cmin,cmax]\f$ and \f$v(cmin):=vmin, v(c):=vmin+c-cmin\f$. * @param[in] cmin smallest number in the range * @param[in] cmax largest number in the range * @param[in] vmin map value of cmin */ void RangeMap::addRange (UInt32 cmin, UInt32 cmax, UInt32 vmin) { if (cmin > cmax) swap(cmin, cmax); Range range(cmin, cmax, vmin); if (_ranges.empty()) _ranges.push_back(range); else { // check for simple cases that can be handled pretty fast Range &lrange = *_ranges.begin(); Range &rrange = *_ranges.rbegin(); if (cmin > rrange.max()) { // non-overlapping range at end of vector? if (!rrange.join(range)) _ranges.push_back(range); } else if (cmax < lrange.min()) { // non-overlapping range at begin of vector? if (!lrange.join(range)) _ranges.insert(_ranges.begin(), range); } else { // ranges overlap and/or must be inserted somewhere inside the vector Ranges::iterator it = lower_bound(_ranges.begin(), _ranges.end(), range); const bool at_end = (it == _ranges.end()); if (at_end) --it; if (!it->join(range) && (it == _ranges.begin() || !(it-1)->join(range))) { if (it->min() < cmin && it->max() > cmax) { // new range completely inside an existing range? //split existing range UInt32 itmax = it->max(); it->max(cmin-1); it = _ranges.insert(it+1, Range(cmax+1, itmax, it->valueAt(cmax+1))); } else if (at_end) // does new range overlap right side of last range in vector? it = _ranges.end(); // => append new range at end of vector it = _ranges.insert(it, range); } adaptNeighbors(it); // resolve overlaps } } }
/** Adapts the left and right neighbor elements of a newly inserted range. * The new range could overlap ranges in the neighborhood so that those must be * adapted or removed. All ranges in the range vector are ordered ascendingly, i.e. * [min_1, max_1],...,[min_n, max_n] where min_i < min_j for all i < j. * @param[in] it pointer to the newly inserted range */ void RangeMap::adaptNeighbors (Ranges::iterator it) { if (it != _ranges.end()) { // adapt left neighbor Ranges::iterator lit = it-1; // points to left neighbor if (it != _ranges.begin() && it->min() <= lit->max()) { bool left_neighbor_valid = (it->min() > 0 && it->min()-1 >= lit->min()); if (left_neighbor_valid) // is adapted left neighbor valid? lit->max(it->min()-1); // => assign new max value if (!left_neighbor_valid || it->join(*lit)) it = _ranges.erase(lit); } // remove right neighbors completely overlapped by *it Ranges::iterator rit = it+1; // points to right neighbor while (rit != _ranges.end() && it->max() >= rit->max()) { // complete overlap? _ranges.erase(rit); rit = it+1; } // adapt rightmost range partially overlapped by *it if (rit != _ranges.end()) { if (it->max() >= rit->min()) rit->setMinAndAdaptValue(it->max()+1); // try to merge right neighbor into *this if (it->join(*rit)) _ranges.erase(rit); // remove merged neighbor } } }