Browse Source

Switched skip lists to red-black trees instead.

Lasse Öörni 14 năm trước cách đây
mục cha
commit
4c94e77887
6 tập tin đã thay đổi với 664 bổ sung649 xóa
  1. 1 1
      Docs/Urho3D.dox
  2. 107 73
      Engine/Container/ListBase.h
  3. 285 299
      Engine/Container/Map.h
  4. 259 273
      Engine/Container/Set.h
  5. 10 1
      Engine/Container/Swap.cpp
  6. 2 2
      Engine/Container/Swap.h

+ 1 - 1
Docs/Urho3D.dox

@@ -49,7 +49,7 @@ Urho3D is greatly inspired by OGRE (http://www.ogre3d.org/) and Horde3D (http://
 - Software rasterization of triangles based on Chris Hecker's Perspective %Texture Mapping series in the Game Developer magazine (http://chrishecker.com/Miscellaneous_Technical_Articles)
 - Networked Physics by Glenn Fiedler (http://gafferongames.com/game-physics/networked-physics/)
 - Euler Angle Formulas by David Eberly (http://www.geometrictools.com/Documentation/EulerAngles.pdf)
-- Skip Lists by Julienne Walker (http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_skip.aspx)
+- Red Black Trees by Julienne Walker (http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx)
 - Comparison of several sorting algorithms by Juha Nieminen (http://warp.povusers.org/SortComparison/)
 
 Urho3D uses the following third-party libraries:

+ 107 - 73
Engine/Container/ListBase.h

@@ -100,107 +100,141 @@ protected:
     unsigned size_;
 };
 
-/// Skip list node base
-struct SkipListNodeBase : public ListNodeBase
+// Based on http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx
+
+/// Red-black tree node base
+struct TreeNodeBase
 {
-    /// Node height
-    unsigned height_;
-    /// Skip list pointers for heights > 1
-    SkipListNodeBase** levels_;
-    
-    /// Return next node on a specific height
-    SkipListNodeBase* GetNext(unsigned height) const
+    /// Construct
+    TreeNodeBase() :
+        parent_(0),
+        isRed_(true)
     {
-        if (!height)
-            return static_cast<SkipListNodeBase*>(next_);
-        else
-            return levels_[height - 1];
+        link_[0] = 0;
+        link_[1] = 0;
     }
     
-    /// Return previous node
-    SkipListNodeBase* GetPrev() const { return static_cast<SkipListNodeBase*>(prev_); }
-    
-    // Set next node on a specific height
-    void SetNext(unsigned height, SkipListNodeBase* node)
+    /// Set a child link, adjusting the child's parent as necessary
+    void SetChild(unsigned dir, TreeNodeBase* newChild)
     {
-        if (!height)
-            next_ = node;
-        else
-            levels_[height - 1] = node;
+        link_[dir] = newChild;
+        if (newChild)
+            newChild->parent_ = this;
     }
     
-    /// Set previous node
-    void SetPrev(SkipListNodeBase* node) { prev_ = node; }
+    /// Parent node
+    TreeNodeBase* parent_;
+    /// Child links
+    TreeNodeBase* link_[2];
+    /// Color flag
+    bool isRed_;
 };
 
-/// Skip list base class
-class SkipListBase
+/// Red-black tree iterator base class
+class TreeIteratorBase
 {
 public:
-    SkipListBase(unsigned maxHeight = MAX_HEIGHT) :
-        maxHeight_(maxHeight < MAX_HEIGHT ? maxHeight : MAX_HEIGHT),
-        height_(0),
-        size_(0),
-        bitsLeft_(0)
+    TreeIteratorBase() :
+        ptr_(0)
     {
     }
     
-    /// Swap with another skip list
-    void Swap(SkipListBase& rhs)
+    TreeIteratorBase(TreeNodeBase* ptr) :
+        ptr_(ptr)
     {
-        ::Swap(head_, rhs.head_);
-        ::Swap(tail_, rhs.tail_);
-        ::Swap(fix_, rhs.fix_);
-        ::Swap(maxHeight_, rhs.maxHeight_);
-        ::Swap(height_, rhs.height_);
-        ::Swap(size_, rhs.size_);
-        ::Swap(random_, rhs.random_);
-        ::Swap(bitsLeft_, rhs.bitsLeft_);
     }
     
-    static const unsigned MAX_HEIGHT = 15;
+    /// 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_; }
     
-protected:
-    /// Generate a random height for a new node
-    unsigned GetHeight()
+    void GotoNext()
     {
-        unsigned height = 1;
-        while ((height < maxHeight_) && (GetBit()))
-            ++height;
+        if (!ptr_)
+            return;
         
-        return height;
+        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];
     }
     
-    /// Return a random true/false result
-    bool GetBit()
+    void GotoPrev()
     {
-        if (!bitsLeft_)
+        if (!ptr_)
+            return;
+        
+        if (!ptr_->link_[0])
         {
-            random_ = rand();
-            bitsLeft_ = 15;
+            while ((ptr_->parent_) && (ptr_->parent_->link_[0] == ptr_))
+                ptr_ = ptr_->parent_;
+            
+            ptr_ = ptr_->parent_;
+            return;
         }
         
-        bool ret = (random_ & 1) != 0;
-        random_ >>= 1;
-        --bitsLeft_;
+        ptr_ = ptr_->link_[0];
+        while (ptr_->link_[1])
+            ptr_ = ptr_->link_[1];
+    }
+    
+    TreeNodeBase* ptr_;
+};
+
+/// Red-black tree base class
+class TreeBase
+{
+public:
+    /// Construct
+    TreeBase() :
+        root_(0),
+        size_(0)
+    {
+    }
+    
+    /// Swap with another tree
+    void Swap(TreeBase& rhs)
+    {
+        ::Swap(root_, rhs.root_);
+        ::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);
         
-        return ret;
+        node->isRed_ = true;
+        save->isRed_ = false;
+        
+        return save;
     }
     
-    /// Head node pointer
-    void* head_;
-    /// Tail node pointer
-    void* tail_;
-    /// Fixup pointers for insert & erase
-    void** fix_;
-    /// Maximum height
-    unsigned maxHeight_;
-    /// Current height
-    unsigned height_;
-    /// Number of keys
+    /// Double rotation
+    TreeNodeBase* RotateDouble(TreeNodeBase* node, unsigned dir)
+    {
+        node->SetChild(!dir, RotateSingle(node->link_[!dir], !dir));
+        return RotateSingle(node, dir);
+    }
+    
+    /// Root node
+    TreeNodeBase* root_;
+    /// Number of nodes
     unsigned size_;
-    /// Random bits
-    unsigned short random_;
-    /// Random bits remaining
-    unsigned short bitsLeft_;
 };

+ 285 - 299
Engine/Container/Map.h

@@ -28,16 +28,22 @@
 
 #include <new>
 
-// Based on http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_skip.aspx
+// Based on http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx
 
-/// Map template class using a skip list
-template <class T, class U> class Map : public SkipListBase
+/// Map template class using a red-black tree
+template <class T, class U> class Map : public TreeBase
 {
 public:
     /// Map key-value pair with const key
     class KeyValue
     {
     public:
+        /// Construct with default key
+        KeyValue() :
+            first_(T())
+        {
+        }
+        
         /// Construct with key
         KeyValue(const T& first) :
             first_(first)
@@ -61,31 +67,41 @@ public:
     };
     
     /// Map node
-    struct Node : public SkipListNodeBase
+    struct Node : public TreeNodeBase
     {
-        /// Key-value pair
-        KeyValue pair_;
+        // Construct undefined
+        Node()
+        {
+        }
         
-        /// Return next node on a specific height
-        Node* GetNext(unsigned height) const
+        // Construct with key
+        Node(const T& key) :
+            pair_(key)
         {
-            if (!height)
-                return static_cast<Node*>(next_);
-            else
-                return static_cast<Node*>(levels_[height - 1]);
         }
         
-        /// Return previous node
-        Node* GetPrev() { return static_cast<Node*>(prev_); }
+        // Construct with key and value
+        Node(const T& key, const U& value) :
+            pair_(key, value)
+        {
+        }
+        
+        /// Key-value pair
+        KeyValue pair_;
+        
+        /// Return parent node
+        Node* GetParent() const { return static_cast<Node*>(parent_); }
+        /// Return the left or right child
+        Node* GetChild(unsigned dir) const { return static_cast<Node*>(link_[dir]); }
     };
     
     /// Map node iterator
-    class Iterator : public ListIteratorBase
+    class Iterator : public TreeIteratorBase
     {
     public:
-        /// Construct
-        explicit Iterator(Node* ptr) :
-            ListIteratorBase(ptr)
+        // Construct
+        Iterator(Node* ptr) :
+            TreeIteratorBase(ptr)
         {
         }
         
@@ -105,18 +121,18 @@ public:
     };
     
     /// Set node const iterator
-    class ConstIterator : public ListIteratorBase
+    class ConstIterator : public TreeIteratorBase
     {
     public:
-        /// Construct
-        explicit ConstIterator(Node* ptr) :
-            ListIteratorBase(ptr)
+        // Construct
+        ConstIterator(Node* ptr) :
+            TreeIteratorBase(ptr)
         {
         }
         
-        /// Construct from a non-const iterator
-        ConstIterator(const Iterator& rhs) :
-            ListIteratorBase(rhs.ptr_)
+        // Construct from a non-const iterator
+        ConstIterator(const Iterator& it) :
+            TreeIteratorBase(it.ptr_)
         {
         }
         
@@ -125,11 +141,11 @@ public:
         /// Preincrement the pointer
         ConstIterator& operator ++ () { GotoNext(); return *this; }
         /// Postincrement the pointer
-        ConstIterator operator ++ (int) { Iterator it = *this; GotoNext(); return it; }
+        ConstIterator operator ++ (int) { ConstIterator it = *this; GotoNext(); return it; }
         /// Predecrement the pointer
         ConstIterator& operator -- () { GotoPrev(); return *this; }
         /// Postdecrement the pointer
-        ConstIterator operator -- (int) { Iterator it = *this; GotoPrev(); return it; }
+        ConstIterator operator -- (int) { ConstIterator it = *this; GotoPrev(); return it; }
         
         /// Point to the pair
         const KeyValue* operator -> () const { return &(static_cast<Node*>(ptr_))->pair_; }
@@ -137,96 +153,39 @@ public:
         const KeyValue& operator * () const { return (static_cast<Node*>(ptr_))->pair_; }
     };
     
-    /// Construct empty
-    Map(unsigned maxHeight = MAX_HEIGHT) :
-        SkipListBase(maxHeight)
+    /// Construct empty map
+    Map()
     {
-        // Allocate the head and tail nodes and zero the next pointers
-        head_ = AllocateNode(maxHeight_);
-        tail_ = AllocateNode(maxHeight_);
-        Node* head = GetHead();
-        Node* tail = GetTail();
-        for (unsigned i = 0; i < maxHeight_; ++i)
-        {
-            head->SetNext(i, tail);
-            tail->SetNext(i, 0);
-        }
-        
-        // Allocate the fixup pointers
-        fix_ = reinterpret_cast<void**>(new Node*[maxHeight_]);
     }
     
-    /// Construct from another map
-    Map(const Map<T, U>& map) :
-        SkipListBase(map.maxHeight_)
+    /// Construct with another map
+    Map(const Map<T, U>& map)
     {
-        // Allocate the head and tail nodes and zero the next pointers
-        head_ = AllocateNode(maxHeight_);
-        tail_ = AllocateNode(maxHeight_);
-        Node* head = GetHead();
-        Node* tail = GetTail();
-        for (unsigned i = 0; i < maxHeight_; ++i)
-        {
-            head->SetNext(i, tail);
-            tail->SetNext(i, 0);
-        }
-        
-        // Allocate the fixup pointers
-        fix_ = reinterpret_cast<void**>(new Node*[maxHeight_]);
-        
-        // Then assign the other map
         *this = map;
     }
     
-    /// Destruct
+    /// Destruct the set
     ~Map()
     {
         Clear();
-        DeleteNode(GetHead());
-        DeleteNode(GetTail());
-        delete[] GetFix();
     }
     
-    /// Assign from another map
-    Map& operator = (const Map<T, U>& rhs)
+    /// Assign a map
+    Map<T, U>& operator = (const Map<T, U>& map)
     {
         Clear();
-        
-        // Insert the nodes with same heights
-        for (Node* i = rhs.GetHead()->GetNext(0); i != rhs.GetTail(); i = i->GetNext(0))
-            InsertNode(Pair<T, U>(i->pair_.first_, i->pair_.second_), i->height_);
+        Insert(map.Begin(), map.End());
         
         return *this;
     }
     
-    /// Add-assign a pair
+    /// Add-assign a value
     Map& operator += (const Pair<T, U>& rhs)
     {
         Insert(rhs);
         return *this;
     }
     
-    /// Add-assign a map
-    Map& operator += (const Map<T, U>& rhs)
-    {
-        Insert(rhs.Begin(), rhs.End());
-        return *this;
-    }
-    
-    /// Index the map
-    U& operator [] (const T& key)
-    {
-        Node* node = FindNode(key);
-        if (node)
-            return node->pair_.second_;
-        else
-        {
-            // If node did not exist, insert a node with default value, then return the value
-            node = InsertNode(Pair<T, U>(key, U()), 0);
-            return node->pair_.second_;
-        }
-    }
-    
     /// Test for equality with another map
     bool operator == (const Map<T, U>& rhs) const
     {
@@ -265,278 +224,305 @@ public:
         return false;
     }
     
-    /// Insert into the map
-    void Insert(const T& key, const U& value)
+    /// Add-assign a map
+    Map<T, U>& operator += (const Map<T, U>& rhs)
+    {
+        Insert(rhs.Begin(), rhs.End());
+        return *this;
+    }
+    
+    /// Clear the map
+    void Clear()
+    {
+        Node* root = GetRoot();
+        if (!root)
+            return;
+        EraseNodes(root);
+        root_ = 0;
+    }
+    
+    /// Insert a pair and return iterator to it
+    Iterator Insert(const Pair<T, U>& pair)
+    {
+        return Iterator(InsertNode(pair.first_, pair.second_));
+    }
+    
+    /// Insert a map
+    void Insert(const Map<T, U>& map)
     {
-        InsertNode(MakePair(key, value), 0);
+        Insert(map.Begin(), map.End());
     }
     
-    /// Insert into the map
-    void Insert(const Pair<T, U>& pair)
+    /// Insert a key by iterator. Return iterator to the value
+    Iterator Insert(const ConstIterator& it)
     {
-        InsertNode(pair, 0);
+        return Iterator(InsertNode(it->first_, it->second_));
     }
     
-    /// Insert a range by iterators
-    void Insert(const Iterator& start, const Iterator& end)
+    /// Insert by a range of iterators
+    void Insert(const ConstIterator& begin, const ConstIterator& end)
     {
-        Iterator it = start;
+        ConstIterator it = begin;
         while (it != end)
         {
-            Iterator current = it++;
-            Insert(*current);
-            // Break if the iterator got stuck
-            if (it == current)
-                break;
+            InsertNode(it->first_, it->second_);
+            ++it;
         }
     }
     
-    /// Erase a key from the map. Return true if was found and erased
+    /// Erase a key. Return true if was found
     bool Erase(const T& key)
     {
-        Node* head = GetHead();
-        Node* tail = GetTail();
-        Node** fix = GetFix();
-        Node* i = head;
-        
-        for (unsigned j = height_ - 1; j < MAX_HEIGHT; --j)
-        {
-            for (;;)
-            {
-                Node* next = i->GetNext(j);
-                if ((next) && (next != tail) && (key > next->pair_.first_))
-                    i = next;
-                else
-                    break;
-            }
-            fix_[j] = i;
-        }
-        
-        // Check if key does not exist
-        Node* toRemove = i->GetNext(0);
-        if ((!toRemove) || (toRemove == tail) || (toRemove->pair_.first_ != key))
-            return false;
-        
-        // Fix the previous link. However, do not set the head node as a previous link
-        Node* prev = toRemove->GetPrev();
-        Node* next = toRemove->GetNext(0);
-        if (next)
-            next->SetPrev(prev != head ? prev : 0);
-        
-        // Fix the next links
-        for (unsigned j = 0; j < height_; ++j)
-        {
-            Node* fixNext = fix[j]->GetNext(j);
-            if (fixNext)
-                fix[j]->SetNext(j, fixNext->GetNext(j));
-        }
-        
-        // Check if height should be changed
-        while (height_ > 0)
-        {
-            if (head->GetNext(height_ - 1))
-                break;
-            head->SetNext(--height_, 0);
-        }
-        
-        DeleteNode(toRemove);
-        --size_;
-        return true;
+        return EraseNode(key);
     }
     
-    /// Erase by an iterator. Return an iterator to the next element
-    Iterator Erase(Iterator it)
+    /// Erase a key by iterator. Return true if was found
+    bool Erase(const Iterator& it)
     {
-        if (it != End())
-        {
-            Iterator current = it++;
-            Erase(current->first_);
-        }
-        
-        return it;
+        return EraseNode(it->first_);
     }
     
-    /// Erase by a range of iterators. Return the end iterator
-    Iterator Erase(const Iterator& start, const Iterator& end)
+    /// Return whether contains a key
+    bool Contains(const T& key)
     {
-        Iterator it = start;
-        while (it != end)
-        {
-            Iterator current = it++;
-            // Break if the iterator got stuck
-            if (it == current)
-                break;
-            Erase(current->first_);
-        }
-        
-        return it;
+        return FindNode(key) != 0;
     }
     
-    /// Clear the map
-    void Clear()
+    /// Index the map. Create new node if key not found
+    U& operator [] (const T& key)
     {
-        // Let the head and tails node remain, but reset the next pointers
-        Node* head = GetHead();
-        Node* tail = GetTail();
-        Node* node = head->GetNext(0);
-        
-        for (unsigned i = 0; i < maxHeight_; ++i)
-        {
-            head->SetNext(i, tail);
-            tail->SetPrev(0);
-        }
-        
-        // Then remove all the key nodes
-        while (node != tail_)
+        Node* node = FindNode(key);
+        if (node)
+            return node->pair_.second_;
+        else
         {
-            Node* current = node;
-            node = node->GetNext(0);
-            DeleteNode(current);
+            node = InsertNode(key, U());
+            return node->pair_.second_;
         }
-        
-        height_ = 0;
-        size_ = 0;
     }
     
     /// Return iterator to the node with key, or end iterator if not found
     Iterator Find(const T& key) { Node* node = FindNode(key); return node ? Iterator(node) : End(); }
     /// Return const iterator to the node with key, or null iterator if not found
     ConstIterator Find(const T& key) const { Node* node = FindNode(key); return node ? ConstIterator(node) : End(); }
-    /// Return iterator to the first actual node
-    Iterator Begin() { return Iterator(GetHead()->GetNext(0)); }
-    /// Return iterator to the first actual node
-    ConstIterator Begin() const { return ConstIterator(GetHead()->GetNext(0)); }
-    /// Return iterator to the end
-    Iterator End() { return Iterator(GetTail()); }
+    /// Return iterator to the beginning
+    Iterator Begin() { return Iterator(FindFirst()); }
+    /// Return const iterator to the beginning
+    ConstIterator Begin() const { return ConstIterator(FindFirst()); }
     /// Return iterator to the end
-    ConstIterator End() const { return ConstIterator(GetTail()); }
-    /// Return first pair
-    KeyValue& Front() { return *Begin(); }
-    /// Return const first pair
-    const KeyValue& Front() const { return *Begin(); }
-    /// Return last pair
-    const KeyValue& Back() { return *(--End()); }
-    /// Return const last pair
-    const KeyValue& Back() const { return *(--End()); }
-    
-    /// Return whether contains a key
-    bool Contains(const T& key) const { return FindNode(key) != 0; }
+    Iterator End() { return ++Iterator(FindLast()); }
+    /// Return const iterator to the end
+    ConstIterator End() const { return ++ConstIterator(FindLast()); }
+    /// Return first key
+    const T& Front() { return FindFirst()->key_; }
+    /// Return last key
+    const T& Back() { return FindLast()->key_; }
     /// Return number of keys
     unsigned Size() const { return size_; }
-    /// Return current height
-    unsigned Height() const { return height_; }
-    /// Return whether map is empty
+    /// Return whether the set is empty
     bool Empty() const { return size_ == 0; }
     
 private:
-    /// Return the head pointer with correct type
-    Node* GetHead() const { return reinterpret_cast<Node*>(head_); }
-    /// Return the tail pointer with correct type
-    Node* GetTail() const { return reinterpret_cast<Node*>(tail_); }
-    /// Return the fixup array with correct type
-    Node** GetFix() const { return reinterpret_cast<Node**>(fix_); }
+    /// Return the root pointer with correct type
+    Node* GetRoot() const { return reinterpret_cast<Node*>(root_); }
     
-    /// Find a key from the map. Return null if not found
+    /// Find the node with smallest key
+    Node* FindFirst() const
+    {
+        Node* node = GetRoot();
+        while ((node) && (node->link_[0]))
+            node = node->GetChild(0);
+        return node;
+    }
+    
+    /// Find the node with largest key
+    Node* FindLast() const
+    {
+        Node* node = GetRoot();
+        while ((node) && (node->link_[1]))
+            node = node->GetChild(1);
+        return node;
+    }
+    
+    /// Find a node with key. Return null if not found
     Node* FindNode(const T& key) const
     {
-        Node* i = GetHead();
-        Node* tail = GetTail();
+        Node* node = GetRoot();
+        while (node)
+        {
+            if (node->pair_.first_ == key)
+                return node;
+            else
+                node = node->GetChild(node->pair_.first_ < key);
+        }
+        return 0;
+    }
+    
+    /// Insert a node and return pointer to it
+    Node* InsertNode(const T& key, const U& value)
+    {
+        Node* ret = 0;
         
-        for (unsigned j = height_ - 1; j < MAX_HEIGHT; --j)
+        if (!root_)
         {
+            root_ = ret = new Node(key, value);
+            ++size_;
+        }
+        else
+        {
+            Node head;
+            Node* g, * t, * p, * q;
+            
+            unsigned dir = 0;
+            unsigned last;
+            
+            t = &head;
+            g = p = 0;
+            q = GetRoot();
+            t->SetChild(1, GetRoot());
+            
             for (;;)
             {
-                Node* next = i->GetNext(j);
-                if ((next) && (next != tail) && (key > next->pair_.first_)) 
-                    i = next;
-                else
+                if (!q)
+                {
+                    p->SetChild(dir, q = ret = new Node(key, value));
+                    ++size_;
+                }
+                else if ((isRed(q->link_[0])) && (isRed(q->link_[1])))
+                {
+                    q->isRed_ = true;
+                    q->link_[0]->isRed_ = false;
+                    q->link_[1]->isRed_ = false;
+                }
+                
+                if ((isRed(q)) && (isRed(p)))
+                {
+                    unsigned dir2 = (t->link_[1] == g);
+                    if (q == p->link_[last])
+                        t->SetChild(dir2, RotateSingle(g, !last));
+                    else
+                        t->SetChild(dir2, RotateDouble(g, !last));
+                }
+                
+                if (q->pair_.first_ == key)
+                {
+                    ret = q;
+                    ret->pair_.second_ = value;
                     break;
+                }
+                
+                last = dir;
+                dir = q->pair_.first_ < key;
+                
+                if (g)
+                    t = g;
+                g = p;
+                p = q;
+                q = q->GetChild(dir);
             }
+            
+            root_ = head.GetChild(1);
         }
         
-        Node* next = i->GetNext(0);
-        if ((next) && (next != tail) && (next->pair_.first_ == key))
-            return next;
-        else
-            return 0;
+        root_->isRed_ = false;
+        root_->parent_ = 0;
+        
+        return ret;
     }
     
-    /// Insert into the map with a specific height. Zero height will randomize. Return the node
-    Node* InsertNode(const Pair<T, U>& pair, unsigned height)
+    /// Erase a node. Return true if was erased
+    bool EraseNode(const T& key)
     {
-        Node* head = GetHead();
-        Node* tail = GetTail();
-        Node** fix = GetFix();
-        Node* i = head;
+        if (!root_)
+            return false;
+        
+        Node head;
+        Node* q, * p, *g;
+        Node* f = 0;
+        unsigned dir = 1;
+        bool removed = false;
+        
+        q = &head;
+        g = p = 0;
+        q->SetChild(1, GetRoot());
         
-        for (unsigned j = height_ - 1; j < MAX_HEIGHT; --j)
+        while (q->link_[dir])
         {
-            for (;;)
+            unsigned last = dir;
+            g = p;
+            p = q;
+            q = q->GetChild(dir);
+            dir = q->pair_.first_ < key;
+            
+            if (q->pair_.first_ == key)
+                f = q;
+             
+            if ((!isRed(q)) && (!isRed(q->GetChild(dir))))
             {
-                Node* next = i->GetNext(j);
-                if ((next) && (next != tail) && (pair.first_ > next->pair_.first_))
-                    i = next;
-                else
-                    break;
+                if (isRed(q->GetChild(!dir)))
+                {
+                    p->SetChild(last, RotateSingle(q, dir));
+                    p = p->GetChild(last);
+                }
+                else if (!isRed(q->GetChild(!dir)))
+                {
+                    Node* s = p->GetChild(!last);
+                    
+                    if (s)
+                    {
+                        if ((!isRed(s->GetChild(!last))) && (!isRed(s->GetChild(last))))
+                        {
+                            p->isRed_ = false;
+                            s->isRed_ = true;
+                            q->isRed_ = true;
+                        }
+                        else
+                        {
+                            int dir2 = (g->GetChild(1) == p);
+                            if (isRed(s->GetChild(last)))
+                                g->SetChild(dir2, RotateDouble(p, last));
+                            else if (isRed(s->GetChild(!last)))
+                                g->SetChild(dir2, RotateSingle(p, last));
+                            q->isRed_ = g->GetChild(dir2)->isRed_ = true;
+                            g->GetChild(dir2)->GetChild(0)->isRed_ = false;
+                            g->GetChild(dir2)->GetChild(1)->isRed_ = false;
+                        }
+                    }
+                }
             }
-            fix[j] = i;
         }
         
-        // Check if key already exists, in that case only modify the value
-        Node* next = i->GetNext(0);
-        if ((next) && (next != tail) && (next->pair_.first_ == pair.first_))
+        if (f)
         {
-            next->pair_.second_ = pair.second_;
-            return next;
+            const_cast<T&>(f->pair_.first_) = q->pair_.first_;
+            f->pair_.second_ = q->pair_.second_;
+            p->SetChild(p->GetChild(1) == q, q->link_[q->GetChild(0) == 0]);
+            delete q;
+            --size_;
+            removed = true;
         }
         
-        // Create new node, assign height and key
-        if (!height)
-            height = GetHeight();
-        Node* newNode = AllocateNode(height, pair.first_);
-        newNode->pair_.second_ = pair.second_;
-        
-        // Fix the previous link, however do not set the head node as previous
-        if (i != head)
-            newNode->SetPrev(i);
-        if (next)
-            next->SetPrev(newNode);
-        
-        while (newNode->height_ > height_)
-            fix[height_++] = head;
-        
-        for (unsigned h = 0; h < newNode->height_; ++h)
+        root_ = head.GetChild(1);
+        if (root_)
         {
-            newNode->SetNext(h, fix[h]->GetNext(h));
-            fix[h]->SetNext(h, newNode);
+            root_->isRed_ = false;
+            root_->parent_ = 0;
         }
         
-        ++size_;
-        return newNode;
+        return removed;
     }
     
-    /// Allocate a node and its next pointers
-    Node* AllocateNode(unsigned height, const T& key = T())
+    /// Erase the nodes recursively
+    void EraseNodes(Node* node)
     {
-        unsigned char* block = new unsigned char[sizeof(Node) + (height - 1) * sizeof(Node*)];
-        Node* newNode = reinterpret_cast<Node*>(block);
-        
-        // Construct the pair with placement new and map the next pointers' address
-        new(&newNode->pair_) KeyValue(key);
-        newNode->height_ = height;
-        if (height > 1)
-            newNode->levels_ = reinterpret_cast<SkipListNodeBase**>(block + sizeof(Node));
-        else
-            newNode->levels_ = 0;
+        Node* left = node->GetChild(0);
+        Node* right = node->GetChild(1);
+        delete node;
+        --size_;
         
-        return newNode;
-    }
-    
-    /// Delete a node
-    void DeleteNode(Node* node)
-    {
-        // Destruct the pair, then delete the memory block
-        (&node->pair_)->~KeyValue();
-        delete[] reinterpret_cast<unsigned char*>(node);
+        if (left)
+            EraseNodes(left);
+        if (right)
+            EraseNodes(right);
     }
 };

+ 259 - 273
Engine/Container/Set.h

@@ -27,38 +27,42 @@
 
 #include <new>
 
-// Based on http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_skip.aspx
+// Based on http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx
 
-/// Set template class using a skip list
-template <class T> class Set : public SkipListBase
+/// Set template class using a red-black tree
+template <class T> class Set : public TreeBase
 {
 public:
     /// Set node
-    struct Node : public SkipListNodeBase
+    struct Node : public TreeNodeBase
     {
-        /// Key
-        T key_;
+        // Construct undefined
+        Node()
+        {
+        }
         
-        /// Return next node on a specific height
-        Node* GetNext(unsigned height) const
+        // Construct with key
+        Node(const T& key) :
+            key_(key)
         {
-            if (!height)
-                return static_cast<Node*>(next_);
-            else
-                return static_cast<Node*>(levels_[height - 1]);
         }
         
-        /// Return previous node
-        Node* GetPrev() { return static_cast<Node*>(prev_); }
+        /// Key
+        T key_;
+        
+        /// Return parent node
+        Node* GetParent() const { return static_cast<Node*>(parent_); }
+        /// Return the left or right child
+        Node* GetChild(unsigned dir) const { return static_cast<Node*>(link_[dir]); }
     };
     
     /// Set node iterator
-    class Iterator : public ListIteratorBase
+    class Iterator : public TreeIteratorBase
     {
     public:
-        /// Construct
-        explicit Iterator(Node* ptr) :
-            ListIteratorBase(ptr)
+        // Construct
+        Iterator(Node* ptr) :
+            TreeIteratorBase(ptr)
         {
         }
         
@@ -78,18 +82,18 @@ public:
     };
     
     /// Set node const iterator
-    class ConstIterator : public ListIteratorBase
+    class ConstIterator : public TreeIteratorBase
     {
     public:
-        /// Construct
-        explicit ConstIterator(Node* ptr) :
-            ListIteratorBase(ptr)
+        // Construct
+        ConstIterator(Node* ptr) :
+            TreeIteratorBase(ptr)
         {
         }
         
-        /// Construct from a non-const iterator
-        ConstIterator(const Iterator& rhs) :
-            ListIteratorBase(rhs.ptr_)
+        // Construct from a non-const iterator
+        ConstIterator(const Iterator& it) :
+            TreeIteratorBase(it.ptr_)
         {
         }
         
@@ -98,81 +102,45 @@ public:
         /// Preincrement the pointer
         ConstIterator& operator ++ () { GotoNext(); return *this; }
         /// Postincrement the pointer
-        ConstIterator operator ++ (int) { Iterator it = *this; GotoNext(); return it; }
+        ConstIterator operator ++ (int) { ConstIterator it = *this; GotoNext(); return it; }
         /// Predecrement the pointer
         ConstIterator& operator -- () { GotoPrev(); return *this; }
         /// Postdecrement the pointer
-        ConstIterator operator -- (int) { Iterator it = *this; GotoPrev(); return it; }
+        ConstIterator operator -- (int) { ConstIterator it = *this; GotoPrev(); return it; }
         
         /// Point to the key
         const T* operator -> () const { return &(static_cast<Node*>(ptr_))->key_; }
         /// Dereference the key
         const T& operator * () const { return (static_cast<Node*>(ptr_))->key_; }
     };
-
-    /// Construct empty
-    Set(unsigned maxHeight = MAX_HEIGHT) :
-        SkipListBase(maxHeight)
+    
+    /// Construct empty set
+    Set()
     {
-        // Allocate the head and tail nodes and zero the next pointers
-        head_ = AllocateNode(maxHeight_);
-        tail_ = AllocateNode(maxHeight_);
-        Node* head = GetHead();
-        Node* tail = GetTail();
-        for (unsigned i = 0; i < maxHeight_; ++i)
-        {
-            head->SetNext(i, tail);
-            tail->SetNext(i, 0);
-        }
-        
-        // Allocate the fixup pointers
-        fix_ = reinterpret_cast<void**>(new Node*[maxHeight_]);
     }
     
-    /// Construct from another set
-    Set(const Set<T>& set) :
-        SkipListBase(set.maxHeight_)
+    /// Construct with another set
+    Set(const Set<T>& set)
     {
-        // Allocate the head and tail nodes and zero the next pointers
-        head_ = AllocateNode(maxHeight_);
-        tail_ = AllocateNode(maxHeight_);
-        Node* head = GetHead();
-        Node* tail = GetTail();
-        for (unsigned i = 0; i < maxHeight_; ++i)
-        {
-            head->SetNext(i, tail);
-            tail->SetNext(i, 0);
-        }
-        
-        // Allocate the fixup pointers
-        fix_ = reinterpret_cast<void**>(new Node*[maxHeight_]);
-        
-        // Then assign the other set
         *this = set;
     }
     
-    /// Destruct
+    /// Destruct the set
     ~Set()
     {
         Clear();
-        DeleteNode(GetHead());
-        DeleteNode(GetTail());
-        delete[] GetFix();
     }
     
-    /// Assign from another set
-    Set& operator = (const Set<T>& rhs)
+    /// Assign a set
+    Set& operator = (const Set<T>& set)
     {
         Clear();
-        
-        // Insert the nodes with same heights
-        for (Node* i = rhs.GetHead()->GetNext(0); i != rhs.GetTail(); i = i->GetNext(0))
-            InsertNode(i->key_, i->height_);
+        Insert(set.Begin(), set.End());
         
         return *this;
     }
     
-    /// Add-assign a key
+    /// Add-assign a value
     Set& operator += (const T& rhs)
     {
         Insert(rhs);
@@ -224,264 +192,282 @@ public:
         return false;
     }
     
-    /// Insert into the set. Return true if did not exist already
-    bool Insert(const T& key)
+
+    
+    /// Clear the set
+    void Clear()
     {
-        return InsertNode(key, 0);
+        Node* root = GetRoot();
+        if (!root)
+            return;
+        EraseNodes(root);
+        root_ = 0;
     }
     
-    /// Insert a range by iterators
-    void Insert(const Iterator& start, const Iterator& end)
+    /// Insert a key. Return iterator to the value
+    Iterator Insert(const T& key)
     {
-        Iterator it = start;
-        while (it != end)
-        {
-            Iterator current = it++;
-            Insert(*current);
-            // Break if the iterator got stuck
-            if (it == current)
-                break;
-        }
+        return Iterator(InsertNode(key));
     }
     
-    /// Erase a key from the set. Return true if was found and erased
-    bool Erase(const T& key)
+    /// Insert a set
+    void Insert(const Set<T>& set)
     {
-        Node* head = GetHead();
-        Node* tail = GetTail();
-        Node** fix = GetFix();
-        Node* i = head;
-        
-        for (unsigned j = height_ - 1; j < MAX_HEIGHT; --j)
-        {
-            for (;;)
-            {
-                Node* next = i->GetNext(j);
-                if ((next) && (next != tail) && (key > next->key_))
-                    i = next;
-                else
-                    break;
-            }
-            fix[j] = i;
-        }
-        
-        // Check if key does not exist
-        Node* toRemove = i->GetNext(0);
-        if ((!toRemove) || (toRemove == tail) || (toRemove->key_ != key))
-            return false;
-        
-        // Fix the previous link. However, do not set the head node as a previous link
-        Node* prev = toRemove->GetPrev();
-        Node* next = toRemove->GetNext(0);
-        if (next)
-            next->SetPrev(prev != head ? prev : 0);
-        
-        // Fix the next links
-        for (unsigned j = 0; j < height_; ++j)
-        {
-            Node* fixNext = fix[j]->GetNext(j);
-            if (fixNext)
-                fix[j]->SetNext(j, fixNext->GetNext(j));
-        }
-        
-        // Check if height should be changed
-        while (height_ > 0)
-        {
-            if (head->GetNext(height_ - 1))
-                break;
-            head->SetNext(--height_, 0);
-        }
-        
-        DeleteNode(toRemove);
-        --size_;
-        return true;
+        Insert(set.Begin(), set.End());
     }
     
-    /// Erase by an iterator. Return an iterator to the next element
-    Iterator Erase(Iterator it)
+    /// Insert a key by iterator. Return iterator to the value
+    Iterator Insert(const ConstIterator& it)
     {
-        if (it != End())
-        {
-            Iterator current = it++;
-            Erase(*current);
-        }
-        
-        return it;
+        return Iterator(InsertNode(*it));
     }
     
-    /// Erase by a range of iterators. Return the end iterator
-    Iterator Erase(const Iterator& start, const Iterator& end)
+    /// Insert by a range of iterators
+    void Insert(const ConstIterator& begin, const ConstIterator& end)
     {
-        Iterator it = start;
+        ConstIterator it = begin;
         while (it != end)
-        {
-            Iterator current = it++;
-            // Break if the iterator got stuck
-            if (it == current)
-                break;
-            Erase(*current);
-        }
-        
-        return it;
+            InsertNode(*it++);
     }
     
-    /// Clear the set
-    void Clear()
+    /// Erase a key. Return true if was found
+    bool Erase(const T& key)
     {
-        // Let the head and tails node remain, but reset the next pointers
-        Node* head = GetHead();
-        Node* tail = GetTail();
-        Node* node = head->GetNext(0);
-        
-        for (unsigned i = 0; i < maxHeight_; ++i)
-        {
-            head->SetNext(i, tail);
-            tail->SetPrev(0);
-        }
-        
-        // Then remove all the key nodes
-        while (node != tail)
-        {
-            Node* current = node;
-            node = node->GetNext(0);
-            DeleteNode(current);
-        }
-        
-        height_ = 0;
-        size_ = 0;
+        return EraseNode(key);
+    }
+    
+    /// Erase a key by iterator. Return true if was found
+    bool Erase(const Iterator& it)
+    {
+        return EraseNode(*it);
+    }
+    
+    /// Return whether contains a key
+    bool Contains(const T& key)
+    {
+        return FindNode(key) != 0;
     }
     
     /// Return iterator to the node with key, or end iterator if not found
     Iterator Find(const T& key) { Node* node = FindNode(key); return node ? Iterator(node) : End(); }
     /// Return const iterator to the node with key, or null iterator if not found
     ConstIterator Find(const T& key) const { Node* node = FindNode(key); return node ? ConstIterator(node) : End(); }
-    /// Return iterator to the first actual node
-    Iterator Begin() { return Iterator(GetHead()->GetNext(0)); }
-    /// Return iterator to the first actual node
-    ConstIterator Begin() const { return ConstIterator(GetHead()->GetNext(0)); }
+    /// Return iterator to the beginning
+    Iterator Begin() { return Iterator(FindFirst()); }
+    /// Return const iterator to the beginning
+    ConstIterator Begin() const { return ConstIterator(FindFirst()); }
     /// Return iterator to the end
-    Iterator End() { return Iterator(GetTail()); }
-    /// Return iterator to the end
-    ConstIterator End() const { return ConstIterator(GetTail()); }
+    Iterator End() { return ++Iterator(FindLast()); }
+    /// Return const iterator to the end
+    ConstIterator End() const { return ++ConstIterator(FindLast()); }
     /// Return first key
-    const T& Front() const { return *Begin(); }
+    const T& Front() { return FindFirst()->key_; }
     /// Return last key
-    const T& Back() const { return *(--End()); }
-    /// Return whether contains a key
-    bool Contains(const T& key) const { return FindNode(key) != 0; }
+    const T& Back() { return FindLast()->key_; }
     /// Return number of keys
     unsigned Size() const { return size_; }
-    /// Return current height
-    unsigned Height() const { return height_; }
-    /// Return whether set is empty
+    /// Return whether the set is empty
     bool Empty() const { return size_ == 0; }
     
 private:
-    /// Return the head pointer with correct type
-    Node* GetHead() const { return reinterpret_cast<Node*>(head_); }
-    /// Return the tail pointer with correct type
-    Node* GetTail() const { return reinterpret_cast<Node*>(tail_); }
-    /// Return the fixup array with correct type
-    Node** GetFix() const { return reinterpret_cast<Node**>(fix_); }
+    /// Return the root pointer with correct type
+    Node* GetRoot() const { return reinterpret_cast<Node*>(root_); }
+    
+    /// Find the node with smallest key
+    Node* FindFirst() const
+    {
+        Node* node = GetRoot();
+        while ((node) && (node->link_[0]))
+            node = node->GetChild(0);
+        return node;
+    }
     
-    /// Find a key from the set. Return null if not found
+    /// Find the node with largest key
+    Node* FindLast() const
+    {
+        Node* node = GetRoot();
+        while ((node) && (node->link_[1]))
+            node = node->GetChild(1);
+        return node;
+    }
+    
+    /// Find a node with key. Return null if not found
     Node* FindNode(const T& key) const
     {
-        Node* i = GetHead();
-        Node* tail = GetTail();
-        
-        for (unsigned j = height_ - 1; j < MAX_HEIGHT; --j)
+        Node* node = GetRoot();
+        while (node)
         {
-            for (;;)
-            {
-                Node* next = i->GetNext(j);
-                if ((next) && (next != tail) && (key > next->key_)) 
-                    i = next;
-                else
-                    break;
-            }
+            if (node->key_ == key)
+                return node;
+            else
+                node = node->GetChild(node->key_ < key);
         }
-        
-        Node* next = i->GetNext(0);
-        if ((next) && (next != tail) && (next->key_ == key))
-            return next;
-        else
-            return 0;
+        return 0;
     }
     
-    /// Insert into the set with a specific height. Zero height will randomize
-    bool InsertNode(const T& key, unsigned height)
+    /// Insert a node and return a pointer to it
+    Node* InsertNode(const T& key)
     {
-        Node* head = GetHead();
-        Node* tail = GetTail();
-        Node** fix = GetFix();
-        Node* i = head;
+        Node* ret = 0;
         
-        for (unsigned j = height_ - 1; j < MAX_HEIGHT; --j)
+        if (!root_)
         {
+            root_ = ret = new Node(key);
+            ++size_;
+        }
+        else
+        {
+            Node head;
+            Node* g, * t, * p, * q;
+            
+            unsigned dir = 0;
+            unsigned last;
+            
+            t = &head;
+            g = p = 0;
+            q = GetRoot();
+            t->SetChild(1, GetRoot());
+            
             for (;;)
             {
-                Node* next = i->GetNext(j);
-                if ((next) && (next != tail) && (key > next->key_))
-                    i = next;
-                else
+                if (!q)
+                {
+                    p->SetChild(dir, q = ret = new Node(key));
+                    ++size_;
+                }
+                else if ((isRed(q->link_[0])) && (isRed(q->link_[1])))
+                {
+                    q->isRed_ = true;
+                    q->link_[0]->isRed_ = false;
+                    q->link_[1]->isRed_ = false;
+                }
+                
+                if ((isRed(q)) && (isRed(p)))
+                {
+                    unsigned dir2 = (t->link_[1] == g);
+                    if (q == p->link_[last])
+                        t->SetChild(dir2, RotateSingle(g, !last));
+                    else
+                        t->SetChild(dir2, RotateDouble(g, !last));
+                }
+                
+                if (q->key_ == key)
+                {
+                    ret = q;
                     break;
+                }
+                
+                last = dir;
+                dir = q->key_ < key;
+                
+                if (g)
+                    t = g;
+                g = p;
+                p = q;
+                q = q->GetChild(dir);
             }
-            fix[j] = i;
+            
+            root_ = head.GetChild(1);
         }
         
-        // Check if key already exists
-        Node* next = i->GetNext(0);
-        if ((next) && (next != tail) && (next->key_ == key))
-            return false;
+        root_->isRed_ = false;
+        root_->parent_ = 0;
         
-        // Create new node, assign height and key
-        if (!height)
-            height = GetHeight();
-        Node* newNode = AllocateNode(height);
-        newNode->key_ = key;
+        return ret;
+    }
+    
+    /// Erase a node. Return true if was erased
+    bool EraseNode(const T& key)
+    {
+        if (!root_)
+            return false;
         
-        // Fix the previous link, however do not set the head node as previous
-        if (i != head)
-            newNode->SetPrev(i);
-        if (next)
-            next->SetPrev(newNode);
+        Node head;
+        Node* q, * p, *g;
+        Node* f = 0;
+        unsigned dir = 1;
+        bool removed = false;
         
-        while (newNode->height_ > height_)
-            fix[height_++] = head;
+        q = &head;
+        g = p = 0;
+        q->SetChild(1, GetRoot());
         
-        for (unsigned h = 0; h < newNode->height_; ++h)
+        while (q->link_[dir])
         {
-            newNode->SetNext(h, fix[h]->GetNext(h));
-            fix[h]->SetNext(h, newNode);
+            unsigned last = dir;
+            g = p;
+            p = q;
+            q = q->GetChild(dir);
+            dir = q->key_ < key;
+            
+            if (q->key_ == key)
+                f = q;
+             
+            if ((!isRed(q)) && (!isRed(q->GetChild(dir))))
+            {
+                if (isRed(q->GetChild(!dir)))
+                {
+                    p->SetChild(last, RotateSingle(q, dir));
+                    p = p->GetChild(last);
+                }
+                else if (!isRed(q->GetChild(!dir)))
+                {
+                    Node* s = p->GetChild(!last);
+                    
+                    if (s)
+                    {
+                        if ((!isRed(s->GetChild(!last))) && (!isRed(s->GetChild(last))))
+                        {
+                            p->isRed_ = false;
+                            s->isRed_ = true;
+                            q->isRed_ = true;
+                        }
+                        else
+                        {
+                            int dir2 = (g->GetChild(1) == p);
+                            if (isRed(s->GetChild(last)))
+                                g->SetChild(dir2, RotateDouble(p, last));
+                            else if (isRed(s->GetChild(!last)))
+                                g->SetChild(dir2, RotateSingle(p, last));
+                            q->isRed_ = g->GetChild(dir2)->isRed_ = true;
+                            g->GetChild(dir2)->GetChild(0)->isRed_ = false;
+                            g->GetChild(dir2)->GetChild(1)->isRed_ = false;
+                        }
+                    }
+                }
+            }
         }
         
-        ++size_;
-        return true;
-    }
-    
-    /// Allocate a node and its next pointers
-    Node* AllocateNode(unsigned height)
-    {
-        unsigned char* block = new unsigned char[sizeof(Node) + (height - 1) * sizeof(Node*)];
-        Node* newNode = reinterpret_cast<Node*>(block);
+        if (f)
+        {
+            f->key_ = q->key_;
+            p->SetChild(p->GetChild(1) == q, q->link_[q->GetChild(0) == 0]);
+            delete q;
+            --size_;
+            removed = true;
+        }
         
-        // Construct the key with placement new and set the next pointers' address
-        new(&newNode->key_) T();
-        newNode->height_ = height;
-        if (height > 1)
-            newNode->levels_ = reinterpret_cast<SkipListNodeBase**>(block + sizeof(Node));
-        else
-            newNode->levels_ = 0;
+        root_ = head.GetChild(1);
+        if (root_)
+        {
+            root_->isRed_ = false;
+            root_->parent_ = 0;
+        }
         
-        return newNode;
+        return removed;
     }
     
-    /// Delete a node
-    void DeleteNode(Node* node)
+    /// Erase the nodes recursively
+    void EraseNodes(Node* node)
     {
-        // Destruct the key, then delete the memory block
-        (&node->key_)->~T();
-        delete[] reinterpret_cast<unsigned char*>(node);
+        Node* left = node->GetChild(0);
+        Node* right = node->GetChild(1);
+        delete node;
+        --size_;
+        
+        if (left)
+            EraseNodes(left);
+        if (right)
+            EraseNodes(right);
     }
 };

+ 10 - 1
Engine/Container/Swap.cpp

@@ -25,6 +25,15 @@
 #include "StringBase.h"
 #include "VectorBase.h"
 
+#include "Set.h"
+
+void Test()
+{
+    Set<int> testSet;
+    testSet.Insert(10);
+    testSet.Erase(10);
+}
+
 template<> void Swap<String>(String& first, String& second)
 {
     first.Swap(second);
@@ -40,7 +49,7 @@ template<> void Swap<ListBase>(ListBase& first, ListBase& second)
     first.Swap(second);
 }
 
-template<> void Swap<SkipListBase>(SkipListBase& first, SkipListBase& second)
+template<> void Swap<TreeBase>(TreeBase& first, TreeBase& second)
 {
     first.Swap(second);
 }

+ 2 - 2
Engine/Container/Swap.h

@@ -24,8 +24,8 @@
 #pragma once
 
 class ListBase;
-class SkipListBase;
 class String;
+class TreeBase;
 class VectorBase;
 
 /// Swap two values
@@ -39,4 +39,4 @@ template<class T> inline void Swap(T& first, T& second)
 template<> void Swap<String>(String& first, String& second);
 template<> void Swap<VectorBase>(VectorBase& first, VectorBase& second);
 template<> void Swap<ListBase>(ListBase& first, ListBase& second);
-template<> void Swap<SkipListBase>(SkipListBase& first, SkipListBase& second);
+template<> void Swap<TreeBase>(TreeBase& first, TreeBase& second);