/*
* interval_tree.hh
*
* Created on: Mar 6, 2017
* Author: Michal Simon
*
************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2016 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
#ifndef INTERVALTREE_HH_
#define INTERVALTREE_HH_
#include "rbtree.hh"
#include
#include
#include
#include
#include
#include
template
class interval_node_t
{
public:
template friend class interval_tree;
template friend class rbtree;
friend class IntervalTreeTest;
public:
interval_node_t(I low, I high, const V& value) :
low(low), high(high), value(value), key(this->low), max(high), colour(RED),
parent(nullptr) { }
const I low;
const I high;
V value;
private:
const I& key;
I max;
colour_t colour;
interval_node_t* parent;
std::unique_ptr left;
std::unique_ptr right;
};
template
class interval_tree : public rbtree< I, V, interval_node_t >
{
private:
typedef interval_node_t N;
typedef typename rbtree::leaf_node_t leaf_node_t;
std::unique_ptr make_node(I low, I high, const V& value)
{
return std::unique_ptr(new N(low, high, value));
}
public:
typedef typename rbtree::iterator iterator;
struct less {
bool operator()(const iterator& x, const iterator& y) const
{
return x->low < y->low;
}
};
virtual ~interval_tree() { }
void insert(I low, I high, const V& value)
{
insert_into(low, high, value, this->tree_root);
}
void erase(I low, I high)
{
std::unique_ptr& node = this->find_in(low, this->tree_root);
if (!node || node->low != low || node->high != high) {
return;
}
this->erase_node(node);
}
std::set query(I low, I high)
{
std::set result;
query(low, high, this->tree_root, result);
return result;
}
private:
using rbtree::insert;
using rbtree::erase;
using rbtree::find;
static bool overlaps(I low, I high, const N* node)
{
int64_t s1 = low + high;
int64_t d1 = high - low;
int64_t s2 = node->low + node->high;
int64_t d2 = node->high - node->low;
return std::abs(s2 - s1) < d1 + d2;
}
static void query(I low, I high, std::unique_ptr& node,
std::set& result)
{
// base case
if (!node) {
return;
}
// the interval is to the right of the rightmost point of any interval
if (low > node->max) {
return;
}
// check if the interval overlaps fully with current node
if (overlaps(low, high, node.get())) {
result.insert(iterator(node.get()));
}
// check the left subtree
query(low, high, node->left, result);
// Do we need to check the right subtree?
if (high > node->low) {
query(low, high, node->right, result);
}
}
void insert_into(I low, I high, const V& value, std::unique_ptr& node,
N* parent = nullptr)
{
if (!node) {
node = make_node(low, high, value);
node->parent = parent;
++this->tree_size;
update_max(node->parent, node->max);
this->rb_insert_case1(node.get());
return;
}
if (low == node->low) {
return;
}
if (low < node->low) {
insert_into(low, high, value, node->left, node.get());
} else {
insert_into(low, high, value, node->right, node.get());
}
}
void erase_node(std::unique_ptr& node)
{
if (!node) {
return;
}
if (this->has_two(node.get())) {
// in this case:
// 1. look for the in-order successor
// 2. replace the node with the in-order successor
// 3. erase the in-order successor
N* n = node.get();
std::unique_ptr& successor = this->find_successor(node);
this->swap_successor(node, successor);
// we don't update max since in erase_node we
// will do it after removing respective node
// we swapped the node with successor and the
// 'successor' unique pointer holds now the node
if (successor.get() == n) {
erase_node(successor);
}// otherwise the successor was the right child of node,
// hence node should be now the right child of 'node'
// unoique pointer
else if (node->right.get() == n) {
erase_node(node->right);
}// there are no other cases so anything else is wrong
else {
throw std::logic_error("Bad rbtree swap.");
}
return;
}
// node has at most one child
// in this case simply replace the node with the
// single child or null if there are no children
N* parent = node->parent;
std::unique_ptr& child = node->left ? node->left : node->right;
colour_t old_colour = node->colour;
if (child) {
child->parent = node->parent;
}
node.reset(child.release());
update_max(parent);
--this->tree_size;
if (old_colour == BLACK) {
if (node && node->colour == RED) {
node->colour = BLACK;
} else {
// if we are here the node is null because a BLACK
// node that has at most one non-leaf child must
// have two null children (null children are BLACK)
if (node) {
throw rb_invariant_error();
}
this->rb_erase_case1(leaf_node_t(parent));
}
} else if (node)
// if the node was red it has to have two BLACK children
// and since at most one of those children is a non-leaf
// child actually both have to be leafs (null) in order
// to satisfy the red-black tree invariant
{
throw rb_invariant_error();
}
}
void update_max(N* node, I new_high)
{
while (node) {
if (new_high > node->max) {
node->max = new_high;
node = node->parent;
} else {
break;
}
}
}
void update_max(N* node)
{
while (node) {
set_max(node);
node = node->parent;
}
}
void set_max(N* node)
{
if (!node->left && !node->right) {
node->max = node->high;
return;
}
if (!node->left || !node->right) {
node->max = std::max(node->high,
(node->left ? node->left->max : node->right->max));
return;
}
node->max = std::max(node->high, std::max(node->left->max, node->right->max));
}
virtual void right_rotation(N* node)
{
N* pivot = node->left.get();
rbtree::right_rotation(node);
set_max(node); // set first max for node since now it's lower in the tree
set_max(pivot);
}
virtual void left_rotation(N* node)
{
N* pivot = node->right.get();
rbtree::left_rotation(node);
set_max(node); // set first max for node since now it's lower in the tree
set_max(pivot);
}
};
#endif /* INTERVALTREE_HH_ */