/* * rbtree.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 RBTREE_HH_ #define RBTREE_HH_ #include #include class rb_invariant_error : public std::exception { public: rb_invariant_error() { } virtual const char* what() const throw() { return "Red-black tree invariant violation!"; } }; enum colour_t { RED = true, BLACK = false }; template class node_t { template friend class rbtree; friend class RBTreeTest; public: node_t(const K& key, const V& value) : key(key), value(value), colour(RED), parent(nullptr) { } const K key; V value; private: colour_t colour; node_t* parent; std::unique_ptr left; std::unique_ptr right; }; template > class rbtree { friend class RBTreeTest; friend class IntervalTreeTest; protected: static std::unique_ptr make_node(const K& key, const V& value) { return std::unique_ptr(new N(key, value)); } static void swap_right_child(std::unique_ptr& node, std::unique_ptr& successor) { std::swap(node->colour, successor->colour); // first do the obvious std::swap(node->left, successor->left); if (node->left) { node->left->parent = node.get(); } if (successor->left) { successor->left->parent = successor.get(); } // now gather remaining pointers N* p = node->parent; N* n = node.release(); N* s = successor.release(); N* s_right = s->right.release(); // and finally reassign those pointers s->parent = p; node.reset(s); s->right.reset(n); n->parent = s; n->right.reset(s_right); if (s_right) { s_right->parent = n; } } static void swap_successor(std::unique_ptr& node, std::unique_ptr& successor) { // first check if successor is a direct child of node, // since it is the in-order successor it can be only // the right child if (node->right.get() == successor.get()) { // it is the right child swap_right_child(node, successor); return; } // swap colour std::swap(node->colour, successor->colour); // swap parents std::swap(node, successor); std::swap(node->parent, successor->parent); // swap left std::swap(node->left, successor->left); if (node->left) { node->left->parent = node.get(); } if (successor->left) { successor->left->parent = successor.get(); } // swap right std::swap(node->right, successor->right); if (node->right) { node->right->parent = node.get(); } if (successor->right) { successor->right->parent = successor.get(); } } static std::unique_ptr null_node; // this class is just used in rb_erase_case# methods as // they need to accept a leaf (null) node as an argument // that can return its parent and is BLACK struct leaf_node_t { leaf_node_t(N* parent) : colour(BLACK), parent(parent) { } leaf_node_t(const leaf_node_t& leaf) : colour(leaf.colour), parent(leaf.parent) { } leaf_node_t& operator=(const leaf_node_t& leaf) { colour = leaf.colour; parent = leaf.parent; return *this; } leaf_node_t* operator->() { return this; } leaf_node_t& operator*() { return *this; } operator bool() const { return true; } bool operator==(N* node) const { return node == nullptr; } colour_t colour; N* parent; }; public: class iterator { public: iterator(N* node = 0) : node(node) { } N* operator->() { return node; } N& operator*() { return *node; } const N* operator->() const { return node; } const N& operator*() const { return *node; } operator bool() const { return bool(node); } iterator& operator++() { if (!node) { return *this; } if (node->right) { node = node->right.get(); while (node->left) { node = node->left.get(); } return *this; } N* parent = node->parent; while (parent && is_right(node)) { node = parent; parent = node->parent; } node = parent; return *this; } bool operator!=(const iterator& itr) { return node != itr.node; } private: N* node; }; rbtree() : tree_size(0) { } virtual ~rbtree() { } void insert(const K& key, const V& value) { insert_into(key, value, tree_root); } void erase(const K& key) { std::unique_ptr& node = find_in(key, tree_root); erase_node(node); } void clear() { tree_root.reset(); tree_size = 0; } iterator find(const K& key) { const std::unique_ptr& n = find_in(key, tree_root); return iterator(n.get()); } const iterator find(const K& key) const { const std::unique_ptr& n = find_in(key, tree_root); return iterator(n.get()); } size_t size() const { return tree_size; } bool empty() const { return !tree_root; } iterator begin() { N* node = tree_root.get(); if (!node) { return iterator(); } while (node->left) { node = node->left.get(); } return iterator(node); } iterator end() { return iterator(); } protected: void insert_into(const K& key, const V& value, std::unique_ptr& node, N* parent = nullptr) { if (!node) { node = make_node(key, value); node->parent = parent; ++tree_size; rb_insert_case1(node.get()); return; } if (key == node->key) { return; } if (key < node->key) { insert_into(key, value, node->left, node.get()); } else { insert_into(key, value, node->right, node.get()); } } void erase_node(std::unique_ptr& node) { if (!node) { return; } if (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 = find_successor(node); swap_successor(node, successor); // 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' // unique 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()); --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(); } 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(); } } template // make it a template so it works both for constant and mutable pointers static PTR& find_in(const K& key, PTR& node) { if (!node) { return null_node; } if (key == node->key) { return node; } if (key < node->key) { return find_in(key, node->left); } else { return find_in(key, node->right); } } template // make it a template so it works both for constant and mutable pointers static PTR& find_min(PTR& node) { if (!node) { return null_node; } if (node->left) { return find_min(node->left); } return node; } template // make it a template so it works both for constant and mutable pointers static PTR& find_successor(PTR& node) { if (!node) { return null_node; } return find_min(node->right); } static bool has_two(const N* node) { return node->left && node->right; } //////////////////////////////////////////////////////////////////////////////////////////////////////////// static void replace(std::unique_ptr& ptr, N* node) { ptr.release(); ptr.reset(node); } virtual void right_rotation(N* node) { if (!node) { return; } N* parent = node->parent; N* left_child = node->left.release(); bool is_left = (parent && parent->left.get() == node) ? true : false; node->left.reset(left_child->right.release()); if (node->left) { node->left->parent = node; } left_child->right.reset(node); if (left_child->right) { left_child->right->parent = left_child; } left_child->parent = parent; if (!parent) { replace(tree_root, left_child); } else if (is_left) { replace(parent->left, left_child); } else { replace(parent->right, left_child); } } virtual void left_rotation(N* node) { if (!node) { return; } N* parent = node->parent; N* right_child = node->right.release(); bool is_left = (parent && parent->left.get() == node) ? true : false; node->right.reset(right_child->left.release()); if (node->right) { node->right->parent = node; } right_child->left.reset(node); if (right_child->left) { right_child->left->parent = right_child; } right_child->parent = parent; if (!parent) { replace(tree_root, right_child); } else if (is_left) { replace(parent->left, right_child); } else { replace(parent->right, right_child); } } //////////////////////////////////////////////////////////////////////////////////////////////////////////// N* get_grandparent(N* node) { if (!node || !node->parent) { return nullptr; } return node->parent->parent; } N* get_uncle(N* node) { N* grandparent = get_grandparent(node); if (!grandparent) { return nullptr; } if (grandparent->left.get() == node->parent) { return grandparent->right.get(); } else { return grandparent->left.get(); } } void rb_insert_case1(N* node) { if (node->parent == nullptr) { // it is the root node->colour = BLACK; } else { rb_insert_case2(node); } } void rb_insert_case2(N* node) { if (node->parent->colour == BLACK) { return; // the invariant is OK } else { rb_insert_case3(node); } } void rb_insert_case3(N* node) { N* uncle = get_uncle(node); if (uncle && uncle->colour == RED) { node->parent->colour = BLACK; uncle->colour = BLACK; N* grandparent = get_grandparent(node); grandparent->colour = RED; rb_insert_case1(grandparent); } else { rb_insert_case4(node); } } void rb_insert_case4(N* node) { N* grandparent = get_grandparent(node); if ((node == node->parent->right.get()) && (node->parent == grandparent->left.get())) { left_rotation(grandparent->left.get()); node = node->left.get(); } else if ((node == node->parent->left.get()) && (node->parent == grandparent->right.get())) { right_rotation(grandparent->right.get()); node = node->right.get(); } rb_insert_case5(node); } void rb_insert_case5(N* node) { N* grandparent = get_grandparent(node); node->parent->colour = BLACK; grandparent->colour = RED; if (node == node->parent->left.get()) { right_rotation(grandparent); } else { left_rotation(grandparent); } } //////////////////////////////////////////////////////////////////////////////////////////////////////////// template static bool is_left(NODE node) { return node == node->parent->left.get(); } template static bool is_right(NODE node) { return node == node->parent->right.get(); } template N* get_sibling(NODE node) { if (!node || !node->parent) { return nullptr; } if (is_left(node)) { return node->parent->right.get(); } else { return node->parent->left.get(); } } template void rb_erase_case1(NODE node) { if (node->parent != nullptr) { rb_erase_case2(node); } } template void rb_erase_case2(NODE node) { N* sibling = get_sibling(node); if (!sibling) { throw rb_invariant_error(); } if (sibling->colour == RED) { node->parent->colour = RED; sibling->colour = BLACK; if (is_left(node)) { left_rotation(node->parent); } else { right_rotation(node->parent); } } rb_erase_case3(node); } template void rb_erase_case3(NODE node) { N* sibling = get_sibling(node); if (!sibling) { throw rb_invariant_error(); } colour_t sibling_left_colour = sibling->left ? sibling->left->colour : BLACK; colour_t sibling_right_colour = sibling->right ? sibling->right->colour : BLACK; if (node->parent->colour == BLACK && sibling->colour == BLACK && sibling_left_colour == BLACK && sibling_right_colour == BLACK) { sibling->colour = RED; rb_erase_case1(node->parent); } else { rb_erase_case4(node); } } template void rb_erase_case4(NODE node) { N* sibling = get_sibling(node); if (!sibling) { throw rb_invariant_error(); } colour_t sibling_left_colour = sibling->left ? sibling->left->colour : BLACK; colour_t sibling_right_colour = sibling->right ? sibling->right->colour : BLACK; if (node->parent->colour == RED && sibling->colour == BLACK && sibling_left_colour == BLACK && sibling_right_colour == BLACK) { sibling->colour = RED; node->parent->colour = BLACK; } else { rb_erase_case5(node); } } template void rb_erase_case5(NODE node) { N* sibling = get_sibling(node); if (!sibling) { throw rb_invariant_error(); } colour_t sibling_left_colour = sibling->left ? sibling->left->colour : BLACK; colour_t sibling_right_colour = sibling->right ? sibling->right->colour : BLACK; if (sibling->colour == BLACK) { if (is_left(node) && sibling_right_colour == BLACK && sibling_left_colour == RED) { sibling->colour = RED; if (sibling->left) { sibling->left->colour = BLACK; } right_rotation(sibling); } else if (is_right(node) && sibling_left_colour == BLACK && sibling_right_colour == RED) { sibling->colour = RED; if (sibling->right) { sibling->right->colour = BLACK; } left_rotation(sibling); } } rb_erase_case6(node); } template void rb_erase_case6(NODE node) { N* sibling = get_sibling(node); if (!sibling) { throw rb_invariant_error(); } sibling->colour = node->parent->colour; node->parent->colour = BLACK; if (is_left(node)) { if (sibling->right) { sibling->right->colour = BLACK; } left_rotation(node->parent); } else { if (sibling->left) { sibling->left->colour = BLACK; } right_rotation(node->parent); } } std::unique_ptr tree_root; size_t tree_size; }; template std::unique_ptr rbtree::null_node; #endif /* RBTREE_HH_ */