// // Urho3D Engine // Copyright (c) 2008-2011 Lasse Öörni // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // #pragma once #include "Allocator.h" #include "Swap.h" // Based on Red Black Trees by Julienne Walker // http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx /// Red-black tree node base. struct TreeNodeBase { /// Construct. TreeNodeBase() : parent_(0), isRed_(true) { link_[0] = 0; link_[1] = 0; } /// %Set a child link, adjusting the child's parent as necessary. void SetChild(unsigned dir, TreeNodeBase* newChild) { link_[dir] = newChild; if (newChild) newChild->parent_ = this; } /// Parent node. TreeNodeBase* parent_; /// Child links. TreeNodeBase* link_[2]; /// Color flag. bool isRed_; }; /// Red-black tree iterator base class. class TreeIteratorBase { public: /// Construct. TreeIteratorBase() : ptr_(0), prev_(0) { } /// Construct with a node pointer. explicit TreeIteratorBase(TreeNodeBase* ptr) : ptr_(ptr), prev_(0) { } /// Test for equality with another iterator. bool operator == (const TreeIteratorBase& rhs) const { return ptr_ == rhs.ptr_; } /// Test for inequality with another iterator. bool operator != (const TreeIteratorBase& rhs) const { return ptr_ != rhs.ptr_; } /// Go to the next node. void GotoNext() { if (!ptr_) return; prev_ = ptr_; if (!ptr_->link_[1]) { while (ptr_->parent_ && ptr_->parent_->link_[1] == ptr_) ptr_ = ptr_->parent_; ptr_ = ptr_->parent_; return; } ptr_ = ptr_->link_[1]; while (ptr_->link_[0]) ptr_ = ptr_->link_[0]; } /// Go to the previous node. void GotoPrev() { if (!ptr_) { ptr_ = prev_; prev_ = 0; return; } prev_ = 0; if (!ptr_->link_[0]) { while (ptr_->parent_ && ptr_->parent_->link_[0] == ptr_) ptr_ = ptr_->parent_; ptr_ = ptr_->parent_; return; } ptr_ = ptr_->link_[0]; while (ptr_->link_[1]) ptr_ = ptr_->link_[1]; } /// Current node pointer. TreeNodeBase* ptr_; /// Previous node pointer, needed to go back from the end. TreeNodeBase* prev_; }; /// Red-black tree base class. class TreeBase { public: /// Construct. TreeBase() : root_(0), allocator_(0), size_(0) { } /// Swap with another tree. void Swap(TreeBase& rhs) { ::Swap(root_, rhs.root_); ::Swap(allocator_, rhs.allocator_); ::Swap(size_, rhs.size_); } protected: /// Check whether a node is red. bool IsRed(TreeNodeBase* node) const { return node && node->isRed_; } /// Single rotation. TreeNodeBase* RotateSingle(TreeNodeBase* node, unsigned dir) { TreeNodeBase* save = node->link_[!dir]; node->SetChild(!dir, save->link_[dir]); save->SetChild(dir, node); node->isRed_ = true; save->isRed_ = false; return save; } /// Double rotation. TreeNodeBase* RotateDouble(TreeNodeBase* node, unsigned dir) { node->SetChild(!dir, RotateSingle(node->link_[!dir], !dir)); return RotateSingle(node, dir); } /// Root node. TreeNodeBase* root_; /// Node allocator. AllocatorBlock* allocator_; /// Number of nodes. unsigned size_; };