blob: 4e08d560ea3370932fff1c44a5954bcd49f88f03 [file] [log] [blame] [edit]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef RANGE_INTERVAL_TREE_H_
#define RANGE_INTERVAL_TREE_H_
#include <zircon/assert.h>
#include <map>
#include <utility>
#include <range/range.h>
namespace range {
// An associative container which holds ranges of values.
// IntervalTree is capable of holding these ranges of values, but indexing by individual
// values, instead of by range.
//
// This class is thread-compatible.
template <typename Range>
class IntervalTree {
public:
using RangeType = Range;
using KeyType = typename Range::KeyType;
using MapType = std::map<KeyType, RangeType>;
using IterType = typename MapType::iterator;
using ConstIterType = typename MapType::const_iterator;
IntervalTree() = default;
// Inserts a range of values into the tree. If they overlap with existing ranges, they
// are combined with those existing ranges. If this range cannot be combined with
// existing ranges, an error is returned.
//
// Returns true if the range is inserted successfully.
// Returns false if the insertion was unsuccessful (This is only possible with an error
// propagated from |Range::Container::Update|).
//
// Runtime: O(log(number of ranges))
template <typename RangeType>
bool try_insert(RangeType&& range) {
// Special case: Set is empty, range is inserted as-is.
if (map_.empty()) {
map_.insert({range.Start(), std::forward<RangeType>(range)});
return true;
}
auto next = map_.upper_bound(range.Start());
auto prior = next;
// Merge with the subsequent elements, if possible.
while (next != map_.end()) {
zx_status_t status = range.Merge(next->second);
if (status != ZX_OK && range::Overlap(next->second, range)) {
// The ranges needed to merge (due to overlap), but could not.
return status == ZX_OK;
}
if (status == ZX_OK) {
// The ranges merged.
++next;
} else {
// The ranges did not (and don't need to) merge.
break;
}
}
// Merge with the prior elements, if possible.
while (prior != map_.begin()) {
prior--;
zx_status_t status = range.Merge(prior->second);
if (status != ZX_OK && range::Overlap(prior->second, range)) {
// The ranges needed to merge (due to overlap), but could not.
return status == ZX_OK;
}
if (status == ZX_OK) {
// The ranges merged.
continue;
}
// The ranges did not (and don't need to) merge.
// Make sure prior only points to things we do need to erase.
prior++;
break;
}
if (prior != next) {
map_.erase(prior, next);
}
map_.insert({range.Start(), std::forward<RangeType>(range)});
return true;
}
// Inserts |range| of values into the tree.
//
// Precondition: |range| must be either mergeable with overlapping intervals in the tree, or must
// not overlap. Callers which cannot satisfy these preconditions should consider |try_insert|
// instead.
template <typename RangeType>
void insert(RangeType&& range) {
ZX_ASSERT(try_insert(std::forward<RangeType>(range)));
}
// Erases a single value from the tree. If this value is only part of a range, that
// range is split into multiple parts.
//
// Runtime: O(log(number of ranges))
void erase(const KeyType& value) {
auto iter = find(value);
if (iter == map_.end()) {
return;
}
// Remove the entire range containing the value.
RangeType range = iter->second;
map_.erase(iter);
// If we cut a range in pieces, put the remaining valid pieces back.
typename RangeType::Container prior_container = range.container();
ZX_ASSERT(RangeType::ContainerTraits::Update(nullptr, range.Start(), value, &prior_container) ==
ZX_OK);
RangeType prior(prior_container);
ZX_DEBUG_ASSERT(range.Start() == prior.Start());
ZX_DEBUG_ASSERT(value == prior.End());
if (prior.Length()) {
map_.insert({prior.Start(), prior});
}
typename RangeType::Container next_container = range.container();
ZX_ASSERT(RangeType::ContainerTraits::Update(nullptr, value + 1, range.End(),
&next_container) == ZX_OK);
RangeType next(next_container);
ZX_DEBUG_ASSERT(value + 1 == next.Start());
ZX_DEBUG_ASSERT(range.End() == next.End());
if (next.Length()) {
map_.insert({next.Start(), next});
}
}
// Erases a range from the tree. If this range partially overlaps with ranges present in the
// tree, those ranges are split into multiple parts.
void erase(const RangeType& value) {
IterType iter;
while ((iter = find(value)) != map_.end()) {
RangeType range = iter->second;
// Remove the entire overlapping in-tree range.
map_.erase(iter);
// If we cut a range in pieces, put the remaining valid pieces back.
if (range.Start() < value.Start()) {
typename RangeType::Container prior_container = range.container();
ZX_ASSERT(RangeType::ContainerTraits::Update(nullptr, range.Start(), value.Start(),
&prior_container) == ZX_OK);
RangeType prior(prior_container);
map_.insert({prior.Start(), prior});
}
if (value.End() < range.End()) {
typename RangeType::Container next_container = range.container();
ZX_ASSERT(RangeType::ContainerTraits::Update(nullptr, value.End(), range.End(),
&next_container) == ZX_OK);
RangeType next(next_container);
map_.insert({next.Start(), next});
}
}
}
// Returns an iterator to the range which contains the value.
// If no such range exists, returns |end()|.
//
// Runtime: O(log(number of ranges))
IterType find(const KeyType& value) {
if (map_.empty()) {
return map_.end();
}
auto iter = map_.upper_bound(value);
if (iter == map_.begin()) {
// |value| is less than the first valid element.
return map_.end();
}
iter--;
if (iter == map_.end()) {
return map_.end();
}
if (iter->second.Start() <= value && value < iter->second.End()) {
return iter;
}
return map_.end();
}
// Returns an iterator to the first range which overlaps with a provided range.
// If no such range exists, returns |end()|.
IterType find(const RangeType& range) {
if (map_.empty()) {
return map_.end();
}
// Return the first element strictly after the start of the range.
//
// As long as this isn't the first element of |map_|, move back to the prior element.
// This is necessary for using a single-element indexing scheme into a range-based
// structure.
auto iter = map_.upper_bound(range.Start());
if (iter != map_.begin()) {
iter--;
}
while (iter != map_.end() && iter->second.Start() < range.End()) {
if (Overlap(iter->second, range)) {
return iter;
}
iter++;
}
return map_.end();
}
void clear() { map_.clear(); }
[[nodiscard]] bool empty() const { return map_.empty(); }
[[nodiscard]] size_t size() const { return map_.size(); }
IterType begin() { return map_.begin(); }
ConstIterType begin() const { return map_.begin(); }
IterType end() { return map_.end(); }
ConstIterType end() const { return map_.end(); }
private:
MapType map_;
};
} // namespace range
#endif // RANGE_INTERVAL_TREE_H_