Просмотр исходного кода

Added base classes for Vector, PODVector, Set & Map to allow fast swapping, and to remove some redundant code.

Lasse Öörni 14 лет назад
Родитель
Сommit
6665749d63

+ 1 - 5
Engine/Core/CoreString.cpp

@@ -23,6 +23,7 @@
 
 #include "Precompiled.h"
 #include "CoreString.h"
+#include "Swap.h"
 
 char String::endZero = 0;
 
@@ -409,8 +410,3 @@ void String::Replace(unsigned pos, unsigned length, const char* srcStart, unsign
     
     CopyChars(buffer_ + pos, srcStart, srcLength);
 }
-
-template<> void Swap<String>(String& first, String& second)
-{
-    first.Swap(second);
-}

+ 1 - 2
Engine/Core/CoreString.h

@@ -24,7 +24,6 @@
 #pragma once
 
 #include "Iterator.h"
-#include "Swap.h"
 
 #include <cstring>
 #include <ctype.h>
@@ -54,7 +53,7 @@ public:
     }
     
     /// Construct from a C string
-    explicit String(const char* str) :
+    String(const char* str) :
         length_(0),
         capacity_(0),
         buffer_(&endZero)

+ 0 - 76
Engine/Core/Iterator.h

@@ -102,79 +102,3 @@ private:
     /// Pointer
     const T* ptr_;
 };
-
-/// List node base
-struct ListNodeBase
-{
-    ListNodeBase() :
-        prev_(0),
-        next_(0)
-    {
-    }
-    
-    /// Previous node
-    ListNodeBase* prev_;
-    /// Next node
-    ListNodeBase* next_;
-};
-
-/// Skip list node base
-struct SkipListNodeBase : public ListNodeBase
-{
-    /// Node height
-    unsigned height_;
-    /// Skip list pointers for heights > 1
-    SkipListNodeBase** levels_;
-    
-    /// Return next node on a specific height
-    SkipListNodeBase* GetNext(unsigned height) const
-    {
-        if (!height)
-            return static_cast<SkipListNodeBase*>(next_);
-        else
-            return levels_[height - 1];
-    }
-    
-    /// Return previous node
-    SkipListNodeBase* GetPrev() const { return static_cast<SkipListNodeBase*>(prev_); }
-    
-    // Set next node on a specific height
-    void SetNext(unsigned height, SkipListNodeBase* node)
-    {
-        if (!height)
-            next_ = node;
-        else
-            levels_[height - 1] = node;
-    }
-    
-    /// Set previous node
-    void SetPrev(SkipListNodeBase* node) { prev_ = node; }
-};
-
-/// List iterator base class
-class ListIteratorBase
-{
-public:
-    /// Test for equality with another iterator
-    bool operator == (const ListIteratorBase& rhs) const { return ptr_ == rhs.ptr_; }
-    /// Test for inequality with another iterator
-    bool operator != (const ListIteratorBase& rhs) const { return ptr_ != rhs.ptr_; }
-    
-    /// Go to the next node
-    void operator ++ ()
-    {
-        if (ptr_->next_)
-            ptr_ = ptr_->next_;
-    }
-    
-    /// Go to the previous node
-    void operator -- ()
-    {
-        if (ptr_->prev_)
-            ptr_ = ptr_->prev_;
-    }
-    
-protected:
-    /// Node pointer
-    ListNodeBase* ptr_;
-};

+ 176 - 0
Engine/Core/ListBase.h

@@ -0,0 +1,176 @@
+//
+// 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 "Swap.h"
+
+#include <cstdlib>
+
+/// List node base
+struct ListNodeBase
+{
+    ListNodeBase() :
+        prev_(0),
+        next_(0)
+    {
+    }
+    
+    /// Previous node
+    ListNodeBase* prev_;
+    /// Next node
+    ListNodeBase* next_;
+};
+
+/// List iterator base class
+class ListIteratorBase
+{
+public:
+    /// Test for equality with another iterator
+    bool operator == (const ListIteratorBase& rhs) const { return ptr_ == rhs.ptr_; }
+    /// Test for inequality with another iterator
+    bool operator != (const ListIteratorBase& rhs) const { return ptr_ != rhs.ptr_; }
+    
+    /// Go to the next node
+    void operator ++ ()
+    {
+        if (ptr_->next_)
+            ptr_ = ptr_->next_;
+    }
+    
+    /// Go to the previous node
+    void operator -- ()
+    {
+        if (ptr_->prev_)
+            ptr_ = ptr_->prev_;
+    }
+    
+protected:
+    /// Node pointer
+    ListNodeBase* ptr_;
+};
+
+/// Skip list node base
+struct SkipListNodeBase : public ListNodeBase
+{
+    /// Node height
+    unsigned height_;
+    /// Skip list pointers for heights > 1
+    SkipListNodeBase** levels_;
+    
+    /// Return next node on a specific height
+    SkipListNodeBase* GetNext(unsigned height) const
+    {
+        if (!height)
+            return static_cast<SkipListNodeBase*>(next_);
+        else
+            return levels_[height - 1];
+    }
+    
+    /// Return previous node
+    SkipListNodeBase* GetPrev() const { return static_cast<SkipListNodeBase*>(prev_); }
+    
+    // Set next node on a specific height
+    void SetNext(unsigned height, SkipListNodeBase* node)
+    {
+        if (!height)
+            next_ = node;
+        else
+            levels_[height - 1] = node;
+    }
+    
+    /// Set previous node
+    void SetPrev(SkipListNodeBase* node) { prev_ = node; }
+};
+
+/// Skip list base class
+class SkipListBase
+{
+public:
+    SkipListBase(unsigned maxHeight = MAX_HEIGHT) :
+        maxHeight_(maxHeight < MAX_HEIGHT ? maxHeight : MAX_HEIGHT),
+        height_(0),
+        size_(0),
+        bitsLeft_(0)
+    {
+    }
+    
+    /// Swap with another skip list
+    void Swap(SkipListBase& rhs)
+    {
+        ::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;
+    
+protected:
+    /// Generate a random height for a new node
+    unsigned GetHeight()
+    {
+        unsigned height = 1;
+        while ((height < maxHeight_) && (GetBit()))
+            ++height;
+        
+        return height;
+    }
+    
+    /// Return a random true/false result
+    bool GetBit()
+    {
+        if (!bitsLeft_)
+        {
+            random_ = rand();
+            bitsLeft_ = 15;
+        }
+        
+        bool ret = (random_ & 1) != 0;
+        random_ >>= 1;
+        --bitsLeft_;
+        
+        return ret;
+    }
+    
+    /// 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
+    unsigned size_;
+    /// Random bits
+    unsigned short random_;
+    /// Random bits remaining
+    unsigned short bitsLeft_;
+};

+ 63 - 92
Engine/Core/Map.h

@@ -23,15 +23,15 @@
 
 #pragma once
 
+#include "ListBase.h"
 #include "Pair.h"
 
-#include <cstdlib>
 #include <new>
 
 // Based on http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_skip.aspx
 
 /// Map template class using a skip list
-template <class T, class U> class Map
+template <class T, class U> class Map : public SkipListBase
 {
 public:
     /// Map key-value pair with const key
@@ -111,22 +111,21 @@ public:
     
     /// Construct empty
     Map(unsigned maxHeight = MAX_HEIGHT) :
-        maxHeight_(maxHeight < MAX_HEIGHT ? maxHeight : MAX_HEIGHT),
-        height_(0),
-        size_(0),
-        bitsLeft_(0)
+        SkipListBase(maxHeight)
     {
         // Allocate the head and tail nodes and zero the next pointers
         head_ = AllocateNode(maxHeight_, T());
         tail_ = AllocateNode(maxHeight_, T());
+        Node* head = GetHead();
+        Node* tail = GetTail();
         for (unsigned i = 0; i < maxHeight_; ++i)
         {
-            head_->SetNext(i, tail_);
-            tail_->SetNext(i, 0);
+            head->SetNext(i, tail);
+            tail->SetNext(i, 0);
         }
         
         // Allocate the fixup pointers
-        fix_ = new Node*[maxHeight_];
+        fix_ = reinterpret_cast<void**>(new Node*[maxHeight_]);
     }
     
     /// Construct from another map
@@ -139,14 +138,16 @@ public:
         // Allocate the head and tail nodes and zero the next pointers
         head_ = AllocateNode(maxHeight_, T());
         tail_ = AllocateNode(maxHeight_, T());
+        Node* head = GetHead();
+        Node* tail = GetTail();
         for (unsigned i = 0; i < maxHeight_; ++i)
         {
-            head_->SetNext(i, tail_);
-            tail_->SetNext(i, 0);
+            head->SetNext(i, tail);
+            tail->SetNext(i, 0);
         }
-
+        
         // Allocate the fixup pointers
-        fix_ = new Node*[maxHeight_];
+        fix_ = reinterpret_cast<void**>(new Node*[maxHeight_]);
         
         // Then assign the another map
         *this = map;
@@ -156,9 +157,9 @@ public:
     ~Map()
     {
         Clear();
-        DeleteNode(head_);
-        DeleteNode(tail_);
-        delete[] fix_;
+        DeleteNode(GetHead());
+        DeleteNode(GetTail());
+        delete[] GetFix();
     }
     
     /// Assign from another map
@@ -167,7 +168,7 @@ public:
         Clear();
         
         // Insert the nodes with same heights
-        for (Node* i = rhs.head_->next_[0]; i; i = i->next_[0])
+        for (Node* i = rhs.GetHead()->GetNext(0); i != rhs.GetTail(); i = i->GetNext(0))
             InsertNode(i->pair_, i->height_);
         
         return *this;
@@ -183,9 +184,7 @@ public:
     /// Add-assign a map
     Map& operator += (const Map<T, U>& rhs)
     {
-        for (Iterator i = rhs.Begin(); i != rhs.End(); ++i)
-            Insert(*i);
-        
+        Insert(rhs.Begin(), rhs.End());
         return *this;
     }
     
@@ -270,14 +269,17 @@ public:
     /// Erase a key from the map. Return true if was found and erased
     bool Erase(const T& key)
     {
-        Node* i = head_;
+        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_))
+                if ((next) && (next != tail) && (key > next->pair_.first_))
                     i = next;
                 else
                     break;
@@ -287,29 +289,29 @@ public:
         
         // Check if key does not exist
         Node* toRemove = i->GetNext(0);
-        if ((!toRemove) || (toRemove == tail_) || (toRemove->pair_.first_ != key))
+        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);
+            next->SetPrev(prev != head ? prev : 0);
         
         // Fix the next links
         for (unsigned j = 0; j < height_; ++j)
         {
-            Node* fixNext = fix_[j]->GetNext(j);
+            Node* fixNext = fix[j]->GetNext(j);
             if (fixNext)
-                fix_[j]->SetNext(j, fixNext->GetNext(j));
+                fix[j]->SetNext(j, fixNext->GetNext(j));
         }
         
         // Check if height should be changed
         while (height_ > 0)
         {
-            if (head_->GetNext(height_ - 1))
+            if (head->GetNext(height_ - 1))
                 break;
-            head_->SetNext(--height_, 0);
+            head->SetNext(--height_, 0);
         }
         
         DeleteNode(toRemove);
@@ -349,12 +351,14 @@ public:
     void Clear()
     {
         // Let the head and tails node remain, but reset the next pointers
-        Node* node = head_->GetNext(0);
+        Node* head = GetHead();
+        Node* tail = GetTail();
+        Node* node = head->GetNext(0);
+        
         for (unsigned i = 0; i < maxHeight_; ++i)
         {
-            head_->SetNext(i, tail_);
-            tail_->SetNext(i, 0);
-            tail_->SetPrev(0);
+            head->SetNext(i, tail);
+            tail->SetPrev(0);
         }
         
         // Then remove all the key nodes
@@ -374,13 +378,13 @@ public:
     /// Return const iterator to the node with key, or null iterator if not found
     ConstIterator Find(const T& key) const { return ConstIterator(FindNode(key)); }
     /// Return iterator to the first actual node
-    Iterator Begin() { return Iterator(head_->next_[0]); }
+    Iterator Begin() { return Iterator(GetHead()->GetNext(0)); }
     /// Return iterator to the first actual node
-    ConstIterator Begin() const { return ConstIterator(head_->next_[0]); }
+    ConstIterator Begin() const { return ConstIterator(GetHead()->GetNext(0)); }
     /// Return iterator to the end
-    Iterator End() { return Iterator(tail_); }
+    Iterator End() { return Iterator(GetTail()); }
     /// Return iterator to the end
-    ConstIterator End() const { return ConstIterator(tail_); }
+    ConstIterator End() const { return ConstIterator(GetTail()); }
     /// Return whether contains a key
     bool Contains(const T& key) const { return FindNode(key) != 0; }
     /// Return number of keys
@@ -390,19 +394,26 @@ public:
     /// Return whether map is empty
     bool Empty() const { return size_ == 0; }
     
-    static const unsigned MAX_HEIGHT = 15;
-    
 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_); }
+    
     /// Find a key from the map. Return null if not found
     Node* FindNode(const T& key) const
     {
-        Node* i = head_;
+        Node* i = GetHead();
+        Node* tail = GetTail();
+        
         for (unsigned j = height_ - 1; j < MAX_HEIGHT; --j)
         {
             for (;;)
             {
                 Node* next = i->GetNext(j);
-                if ((next) && (next != tail_) && (key > next->pair_.first_)) 
+                if ((next) && (next != tail) && (key > next->pair_.first_)) 
                     i = next;
                 else
                     break;
@@ -410,7 +421,7 @@ private:
         }
         
         Node* next = i->GetNext(0);
-        if ((next) && (next != tail_) && (next->pair_.first_ == key))
+        if ((next) && (next != tail) && (next->pair_.first_ == key))
             return next;
         else
             return 0;
@@ -419,24 +430,27 @@ private:
     /// Insert into the map with a specific height. Zero height will randomize. Return the node
     Node* InsertNode(const Pair<T, U>& pair, unsigned height)
     {
-        Node* i = head_;
+        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_) && (pair.first_ > next->pair_.first_))
+                if ((next) && (next != tail) && (pair.first_ > next->pair_.first_))
                     i = next;
                 else
                     break;
             }
-            fix_[j] = i;
+            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 ((next) && (next != tail) && (next->pair_.first_ == pair.first_))
         {
             next->pair_.second_ = pair.second_;
             return next;
@@ -449,50 +463,24 @@ private:
         newNode->pair_.second_ = pair.second_;
         
         // Fix the previous link, however do not set the head node as previous
-        if (i != head_)
+        if (i != head)
             newNode->SetPrev(i);
         if (next)
             next->SetPrev(newNode);
         
         while (newNode->height_ > height_)
-            fix_[height_++] = head_;
+            fix[height_++] = head;
         
         for (unsigned h = 0; h < newNode->height_; ++h)
         {
-            newNode->SetNext(h, fix_[h]->GetNext(h));
-            fix_[h]->SetNext(h, newNode);
+            newNode->SetNext(h, fix[h]->GetNext(h));
+            fix[h]->SetNext(h, newNode);
         }
         
         ++size_;
         return newNode;
     }
     
-    /// Generate a random height for a new node
-    unsigned GetHeight()
-    {
-        unsigned height = 1;
-        while ((height < maxHeight_) && (GetBit()))
-            ++height;
-        
-        return height;
-    }
-    
-    /// Return a random true/false result
-    bool GetBit()
-    {
-        if (!bitsLeft_)
-        {
-            random_ = rand();
-            bitsLeft_ = 15;
-        }
-        
-        bool ret = (random_ & 1) != 0;
-        random_ >>= 1;
-        --bitsLeft_;
-        
-        return ret;
-    }
-    
     /// Allocate a node and its next pointers
     Node* AllocateNode(unsigned height, const T& key)
     {
@@ -517,21 +505,4 @@ private:
         (&node->pair_)->~KeyValue();
         delete[] reinterpret_cast<unsigned char*>(node);
     }
-    
-    /// Head node pointer
-    Node* head_;
-    /// Tail node pointer
-    Node* tail_;
-    /// Fixup pointers for insert & erase
-    Node** fix_;
-    /// Maximum height
-    unsigned maxHeight_;
-    /// Current height
-    unsigned height_;
-    /// Number of keys
-    unsigned size_;
-    /// Random bits
-    unsigned short random_;
-    /// Random bits remaining
-    unsigned short bitsLeft_;
 };

+ 32 - 40
Engine/Core/PODVector.h

@@ -24,38 +24,30 @@
 #pragma once
 
 #include "Iterator.h"
+#include "VectorBase.h"
 
 #include <cstring>
 
 /// Vector template class for POD types. Does not call constructors or destructors and uses block move
-template <class T> class PODVector
+template <class T> class PODVector : public VectorBase
 {
 public:
     typedef RandomAccessIterator<T> Iterator;
     typedef RandomAccessConstIterator<T> ConstIterator;
     
     /// Construct empty
-    PODVector() :
-        size_(0),
-        capacity_(0),
-        buffer_(0)
+    PODVector()
     {
     }
     
     /// Construct with initial size
-    explicit PODVector(unsigned size) :
-        size_(0),
-        capacity_(0),
-        buffer_(0)
+    explicit PODVector(unsigned size)
     {
         Resize(size);
     }
     
     /// Construct from another vector
-    PODVector(const PODVector<T>& vector) :
-        size_(0),
-        capacity_(0),
-        buffer_(0)
+    PODVector(const PODVector<T>& vector)
     {
         *this = vector;
     }
@@ -70,7 +62,7 @@ public:
     PODVector<T>& operator = (const PODVector<T>& rhs)
     {
         Resize(rhs.size_);
-        CopyElements(buffer_, rhs.buffer_, rhs.size_);
+        CopyElements(GetBuffer(), rhs.GetBuffer(), rhs.size_);
         
         return *this;
     }
@@ -113,9 +105,11 @@ public:
         if (rhs.size_ != size_)
             return false;
         
+        T* buffer = GetBuffer();
+        T* rhsBuffer = rhs.GetBuffer();
         for (unsigned i = 0; i < size_; ++i)
         {
-            if (buffer_[i] != rhs.buffer_[i])
+            if (buffer[i] != rhsBuffer[i])
                 return false;
         }
         
@@ -128,9 +122,11 @@ public:
         if (rhs.size_ != size_)
             return true;
         
+        T* buffer = GetBuffer();
+        T* rhsBuffer = rhs.GetBuffer();
         for (unsigned i = 0; i < size_; ++i)
         {
-            if (buffer_[i] != rhs.buffer_[i])
+            if (buffer[i] != rhsBuffer[i])
                 return true;
         }
         
@@ -138,16 +134,16 @@ public:
     }
     
     /// Return element at index
-    T& operator [] (unsigned index) { return buffer_[index]; }
+    T& operator [] (unsigned index) { return GetBuffer()[index]; }
     /// Return const element at index
-    const T& operator [] (unsigned index) const { return buffer_[index]; }
+    const T& operator [] (unsigned index) const { return GetBuffer()[index]; }
     
     /// Add an element at the end
     void Push(const T& value)
     {
         unsigned oldSize = size_;
         Resize(size_ + 1);
-        buffer_[oldSize] = value;
+        GetBuffer()[oldSize] = value;
     }
     
     /// Add another vector at the end
@@ -158,7 +154,7 @@ public:
         
         unsigned oldSize = size_;
         Resize(size_ + vector.size_);
-        CopyElements(buffer_ + oldSize, vector.buffer_, vector.size_);
+        CopyElements(GetBuffer() + oldSize, vector.GetBuffer(), vector.size_);
     }
     
     /// Remove the last element
@@ -183,7 +179,7 @@ public:
         unsigned oldSize = size_;
         Resize(size_ + 1);
         MoveRange(pos + 1, pos, oldSize - pos);
-        buffer_[pos] = value;
+        GetBuffer()[pos] = value;
     }
     
     /// Insert another vector at position
@@ -204,7 +200,7 @@ public:
         unsigned oldSize = size_;
         Resize(size_ + vector.size_);
         MoveRange(pos + vector.size_, pos, oldSize - pos);
-        CopyElements(buffer_ + pos, vector.buffer_, vector.size_);
+        CopyElements(GetBuffer() + pos, vector.GetBuffer(), vector.size_);
     }
     
     /// Insert an element using an iterator
@@ -239,7 +235,7 @@ public:
         Resize(size_ + length);
         MoveRange(pos + length, pos, size_ - pos - length);
         
-        T* destPtr = buffer_ + pos;
+        T* destPtr = GetBuffer() + pos;
         for (Iterator i = start; i != end; ++i)
             *destPtr++ = *i;
         
@@ -311,7 +307,7 @@ public:
             // Move the data into the new buffer and delete the old
             if (buffer_)
             {
-                CopyElements(newBuffer, buffer_, size_);
+                CopyElements(newBuffer, GetBuffer(), size_);
                 delete[] reinterpret_cast<unsigned char*>(buffer_);
             }
             buffer_ = newBuffer;
@@ -335,7 +331,7 @@ public:
         {
             newBuffer = reinterpret_cast<T*>(new unsigned char[capacity_ * sizeof(T)]);
             // Move the data into the new buffer
-            CopyElements(newBuffer, buffer_, size_);
+            CopyElements(newBuffer, GetBuffer(), size_);
         }
         
         // Delete the old buffer
@@ -350,21 +346,21 @@ public:
     }
     
     /// Return iterator to the beginning
-    Iterator Begin() { return Iterator(buffer_); }
+    Iterator Begin() { return Iterator(GetBuffer()); }
     /// Return const iterator to the beginning
-    ConstIterator Begin() const { return ConstIterator(buffer_); }
+    ConstIterator Begin() const { return ConstIterator(GetBuffer()); }
     /// Return iterator to the end
-    Iterator End() { return Iterator(buffer_ + size_); }
+    Iterator End() { return Iterator(GetBuffer() + size_); }
     /// Return const iterator to the end
-    ConstIterator End() const { return ConstIterator(buffer_ + size_); }
+    ConstIterator End() const { return ConstIterator(GetBuffer() + size_); }
     /// Return first element
-    T& Front() { return buffer_[0]; }
+    T& Front() { return GetBuffer()[0]; }
     /// Return const first element
-    const T& Front() const { return buffer_[0]; }
+    const T& Front() const { return GetBuffer()[0]; }
     /// Return last element
-    T& Back() { return buffer_[size_ - 1]; }
+    T& Back() { return GetBuffer()[size_ - 1]; }
     /// Return const last element
-    const T& Back() const { return buffer_[size_ - 1]; }
+    const T& Back() const { return GetBuffer()[size_ - 1]; }
     /// Return size of vector
     unsigned Size() const { return size_; }
     /// Return capacity of vector
@@ -376,6 +372,9 @@ public:
     static const unsigned MIN_CAPACITY = 1;
     
 private:
+    /// Return the buffer with right type
+    T* GetBuffer() const { return reinterpret_cast<T*>(buffer_); }
+    
     /// Move a range of elements within the vector
     void MoveRange(unsigned dest, unsigned src, unsigned count)
     {
@@ -389,11 +388,4 @@ private:
         if (count)
             memcpy(dest, src, count * sizeof(T));
     }
-    
-    /// Size of vector
-    unsigned size_;
-    /// Buffer capacity
-    unsigned capacity_;
-    /// Buffer
-    T* buffer_;
 };

+ 65 - 98
Engine/Core/Set.h

@@ -23,15 +23,14 @@
 
 #pragma once
 
-#include "Iterator.h"
+#include "ListBase.h"
 
-#include <cstdlib>
 #include <new>
 
 // Based on http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_skip.aspx
 
 /// Set template class using a skip list
-template <class T> class Set
+template <class T> class Set : public SkipListBase
 {
 public:
     /// Set node
@@ -85,42 +84,40 @@ public:
 
     /// Construct empty
     Set(unsigned maxHeight = MAX_HEIGHT) :
-        maxHeight_(maxHeight < MAX_HEIGHT ? maxHeight : MAX_HEIGHT),
-        height_(0),
-        size_(0),
-        bitsLeft_(0)
+        SkipListBase(maxHeight)
     {
         // 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);
+            head->SetNext(i, tail);
+            tail->SetNext(i, 0);
         }
         
         // Allocate the fixup pointers
-        fix_ = new Node*[maxHeight_];
+        fix_ = reinterpret_cast<void**>(new Node*[maxHeight_]);
     }
     
     /// Construct from another set
     Set(const Set<T>& set) :
-        maxHeight_(set.maxHeight_),
-        height_(0),
-        size_(0),
-        bitsLeft_(0)
+        SkipListBase(maxHeight)
     {
         // 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);
+            head->SetNext(i, tail);
+            tail->SetNext(i, 0);
         }
         
         // Allocate the fixup pointers
-        fix_ = new Node*[maxHeight_];
+        fix_ = reinterpret_cast<void**>(new Node*[maxHeight_]);
         
         // Then assign the another set
         *this = set;
@@ -130,9 +127,9 @@ public:
     ~Set()
     {
         Clear();
-        DeleteNode(head_);
-        DeleteNode(tail_);
-        delete[] fix_;
+        DeleteNode(GetHead());
+        DeleteNode(GetTail());
+        delete[] GetFix();
     }
     
     /// Assign from another set
@@ -141,7 +138,7 @@ public:
         Clear();
         
         // Insert the nodes with same heights
-        for (Node* i = rhs.head_->next_[0]; i; i = i->next_[0])
+        for (Node* i = rhs.GetHead()->GetNext(0); i != rhs.GetTail(); i = i->GetNext(0))
             InsertNode(i->key_, i->height_);
         
         return *this;
@@ -157,9 +154,7 @@ public:
     /// Add-assign a set
     Set& operator += (const Set<T>& rhs)
     {
-        for (Iterator i = rhs.Begin(); i != rhs.End(); ++i)
-            Insert(*i);
-        
+        Insert(rhs.Begin(), rhs.End());
         return *this;
     }
     
@@ -224,46 +219,49 @@ public:
     /// Erase a key from the set. Return true if was found and erased
     bool Erase(const T& key)
     {
-        Node* i = head_;
+        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_))
+                if ((next) && (next != tail) && (key > next->key_))
                     i = next;
                 else
                     break;
             }
-            fix_[j] = i;
+            fix[j] = i;
         }
         
         // Check if key does not exist
         Node* toRemove = i->GetNext(0);
-        if ((!toRemove) || (toRemove == tail_) || (toRemove->key_ != key))
+        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);
+            next->SetPrev(prev != head ? prev : 0);
         
         // Fix the next links
         for (unsigned j = 0; j < height_; ++j)
         {
-            Node* fixNext = fix_[j]->GetNext(j);
+            Node* fixNext = fix[j]->GetNext(j);
             if (fixNext)
-                fix_[j]->SetNext(j, fixNext->GetNext(j));
+                fix[j]->SetNext(j, fixNext->GetNext(j));
         }
         
         // Check if height should be changed
         while (height_ > 0)
         {
-            if (head_->GetNext(height_ - 1))
+            if (head->GetNext(height_ - 1))
                 break;
-            head_->SetNext(--height_, 0);
+            head->SetNext(--height_, 0);
         }
         
         DeleteNode(toRemove);
@@ -303,16 +301,18 @@ public:
     void Clear()
     {
         // Let the head and tails node remain, but reset the next pointers
-        Node* node = head_->GetNext(0);
+        Node* head = GetHead();
+        Node* tail = GetTail();
+        Node* node = head->GetNext(0);
+        
         for (unsigned i = 0; i < maxHeight_; ++i)
         {
-            head_->SetNext(i, tail_);
-            tail_->SetNext(i, 0);
-            tail_->SetPrev(0);
+            head->SetNext(i, tail);
+            tail->SetPrev(0);
         }
         
         // Then remove all the key nodes
-        while (node != tail_)
+        while (node != tail)
         {
             Node* current = node;
             node = node->GetNext(0);
@@ -328,13 +328,13 @@ public:
     /// Return const iterator to the node with key, or null iterator if not found
     ConstIterator Find(const T& key) const { return ConstIterator(FindNode(key)); }
     /// Return iterator to the first actual node
-    Iterator Begin() { return Iterator(head_->next_[0]); }
+    Iterator Begin() { return Iterator(GetHead()->GetNext(0)); }
     /// Return iterator to the first actual node
-    ConstIterator Begin() const { return ConstIterator(head_->next_[0]); }
+    ConstIterator Begin() const { return ConstIterator(GetHead()->GetNext(0)); }
     /// Return iterator to the end
-    Iterator End() { return Iterator(tail_); }
+    Iterator End() { return Iterator(GetTail()); }
     /// Return iterator to the end
-    ConstIterator End() const { return ConstIterator(tail_); }
+    ConstIterator End() const { return ConstIterator(GetTail()); }
     /// Return whether contains a key
     bool Contains(const T& key) const { return FindNode(key) != 0; }
     /// Return number of keys
@@ -344,19 +344,26 @@ public:
     /// Return whether set is empty
     bool Empty() const { return size_ == 0; }
     
-    static const unsigned MAX_HEIGHT = 15;
-    
 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_); }
+    
     /// Find a key from the set. Return null if not found
     Node* FindNode(const T& key) const
     {
-        Node* i = head_;
+        Node* i = GetHead();
+        Node* tail = GetTail();
+        
         for (unsigned j = height_ - 1; j < MAX_HEIGHT; --j)
         {
             for (;;)
             {
                 Node* next = i->GetNext(j);
-                if ((next) && (next != tail_) && (key > next->key_)) 
+                if ((next) && (next != tail) && (key > next->key_)) 
                     i = next;
                 else
                     break;
@@ -364,7 +371,7 @@ private:
         }
         
         Node* next = i->GetNext(0);
-        if ((next) && (next != tail_) && (next->key_ == key))
+        if ((next) && (next != tail) && (next->key_ == key))
             return next;
         else
             return 0;
@@ -373,24 +380,27 @@ private:
     /// Insert into the set with a specific height. Zero height will randomize
     bool InsertNode(const T& key, unsigned height)
     {
-        Node* i = head_;
+        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_))
+                if ((next) && (next != tail) && (key > next->key_))
                     i = next;
                 else
                     break;
             }
-            fix_[j] = i;
+            fix[j] = i;
         }
         
         // Check if key already exists
         Node* next = i->GetNext(0);
-        if ((next) && (next != tail_) && (next->key_ == key))
+        if ((next) && (next != tail) && (next->key_ == key))
             return false;
         
         // Create new node, assign height and key
@@ -400,50 +410,24 @@ private:
         newNode->key_ = key;
         
         // Fix the previous link, however do not set the head node as previous
-        if (i != head_)
+        if (i != head)
             newNode->SetPrev(i);
         if (next)
             next->SetPrev(newNode);
         
         while (newNode->height_ > height_)
-            fix_[height_++] = head_;
+            fix[height_++] = head;
         
         for (unsigned h = 0; h < newNode->height_; ++h)
         {
-            newNode->SetNext(h, fix_[h]->GetNext(h));
-            fix_[h]->SetNext(h, newNode);
+            newNode->SetNext(h, fix[h]->GetNext(h));
+            fix[h]->SetNext(h, newNode);
         }
         
         ++size_;
         return true;
     }
     
-    /// Generate a random height for a new node
-    unsigned GetHeight()
-    {
-        unsigned height = 1;
-        while ((height < maxHeight_) && (GetBit()))
-            ++height;
-        
-        return height;
-    }
-    
-    /// Return a random true/false result
-    bool GetBit()
-    {
-        if (!bitsLeft_)
-        {
-            random_ = rand();
-            bitsLeft_ = 15;
-        }
-        
-        bool ret = (random_ & 1) != 0;
-        random_ >>= 1;
-        --bitsLeft_;
-        
-        return ret;
-    }
-    
     /// Allocate a node and its next pointers
     Node* AllocateNode(unsigned height)
     {
@@ -468,21 +452,4 @@ private:
         (&node->key_)->~T();
         delete[] reinterpret_cast<unsigned char*>(node);
     }
-    
-    /// Head node pointer
-    Node* head_;
-    /// Tail node pointer
-    Node* tail_;
-    /// Fixup pointers for insert & erase
-    Node** fix_;
-    /// Maximum height
-    unsigned maxHeight_;
-    /// Current height
-    unsigned height_;
-    /// Number of keys
-    unsigned size_;
-    /// Random bits
-    unsigned short random_;
-    /// Random bits remaining
-    unsigned short bitsLeft_;
 };

+ 19 - 0
Engine/Core/Swap.cpp

@@ -0,0 +1,19 @@
+#include "Precompiled.h"
+#include "CoreString.h"
+#include "ListBase.h"
+#include "VectorBase.h"
+
+template<> void Swap<String>(String& first, String& second)
+{
+    first.Swap(second);
+}
+
+template<> void Swap<VectorBase>(VectorBase& first, VectorBase& second)
+{
+    first.Swap(second);
+}
+
+template<> void Swap<SkipListBase>(SkipListBase& first, SkipListBase& second)
+{
+    first.Swap(second);
+}

+ 4 - 0
Engine/Core/Swap.h

@@ -23,7 +23,9 @@
 
 #pragma once
 
+class SkipListBase;
 class String;
+class VectorBase;
 
 /// Swap two values
 template<class T> inline void Swap(T& first, T& second)
@@ -34,3 +36,5 @@ 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<SkipListBase>(SkipListBase& first, SkipListBase& second);

+ 38 - 45
Engine/Core/Vector.h

@@ -24,38 +24,30 @@
 #pragma once
 
 #include "Iterator.h"
+#include "VectorBase.h"
 
 #include <cstring>
 
 /// Vector template class
-template <class T> class Vector
+template <class T> class Vector : public VectorBase
 {
 public:
     typedef RandomAccessIterator<T> Iterator;
     typedef RandomAccessConstIterator<T> ConstIterator;
     
     /// Construct empty
-    Vector() :
-        size_(0),
-        capacity_(0),
-        buffer_(0)
+    Vector()
     {
     }
     
     /// Construct with initial size
-    explicit Vector(unsigned size) :
-        size_(0),
-        capacity_(0),
-        buffer_(0)
+    explicit Vector(unsigned size)
     {
         Resize(size);
     }
     
     /// Construct from another vector
-    Vector(const Vector<T>& vector) :
-        size_(0),
-        capacity_(0),
-        buffer_(0)
+    Vector(const Vector<T>& vector)
     {
         *this = vector;
     }
@@ -63,14 +55,14 @@ public:
     /// Destruct
     ~Vector()
     {
-        delete[] buffer_;
+        delete[] GetBuffer();
     }
     
     /// Assign from another vector
     Vector<T>& operator = (const Vector<T>& rhs)
     {
         Resize(rhs.size_);
-        CopyElements(buffer_, rhs.buffer_, rhs.size_);
+        CopyElements(GetBuffer(), rhs.GetBuffer(), rhs.size_);
         
         return *this;
     }
@@ -113,9 +105,11 @@ public:
         if (rhs.size_ != size_)
             return false;
         
+        T* buffer = GetBuffer();
+        T* rhsBuffer = rhs.GetBuffer();
         for (unsigned i = 0; i < size_; ++i)
         {
-            if (buffer_[i] != rhs.buffer_[i])
+            if (buffer[i] != rhsBuffer[i])
                 return false;
         }
         
@@ -128,9 +122,11 @@ public:
         if (rhs.size_ != size_)
             return true;
         
+        T* buffer = GetBuffer();
+        T* rhsBuffer = rhs.GetBuffer();
         for (unsigned i = 0; i < size_; ++i)
         {
-            if (buffer_[i] != rhs.buffer_[i])
+            if (buffer[i] != rhsBuffer[i])
                 return true;
         }
         
@@ -138,16 +134,16 @@ public:
     }
     
     /// Return element at index
-    T& operator [] (unsigned index) { return buffer_[index]; }
+    T& operator [] (unsigned index) { return GetBuffer()[index]; }
     /// Return const element at index
-    const T& operator [] (unsigned index) const { return buffer_[index]; }
+    const T& operator [] (unsigned index) const { return GetBuffer()[index]; }
     
     /// Add an element at the end
     void Push(const T& value)
     {
         unsigned oldSize = size_;
         Resize(size_ + 1);
-        buffer_[oldSize] = value;
+        GetBuffer()[oldSize] = value;
     }
     
     /// Add another vector at the end
@@ -158,7 +154,7 @@ public:
         
         unsigned oldSize = size_;
         Resize(size_ + vector.size_);
-        CopyElements(buffer_ + oldSize, vector.buffer_, vector.size_);
+        CopyElements(GetBuffer() + oldSize, vector.GetBuffer(), vector.size_);
     }
     
     /// Remove the last element
@@ -183,7 +179,7 @@ public:
         unsigned oldSize = size_;
         Resize(size_ + 1);
         MoveRange(pos + 1, pos, oldSize - pos);
-        buffer_[pos] = value;
+        GetBuffer()[pos] = value;
     }
     
     /// Insert another vector at position
@@ -204,7 +200,7 @@ public:
         unsigned oldSize = size_;
         Resize(size_ + vector.size_);
         MoveRange(pos + vector.size_, pos, oldSize - pos);
-        CopyElements(buffer_ + pos, vector.buffer_, vector.size_);
+        CopyElements(GetBuffer() + pos, vector.GetBuffer(), vector.size_);
     }
     
     /// Insert an element using an iterator
@@ -239,7 +235,7 @@ public:
         Resize(size_ + length);
         MoveRange(pos + length, pos, size_ - pos - length);
         
-        T* destPtr = buffer_ + pos;
+        T* destPtr = GetBuffer() + pos;
         for (Iterator i = start; i != end; ++i)
             *destPtr++ = *i;
         
@@ -311,8 +307,8 @@ public:
             // Move the data into the new buffer and delete the old
             if (buffer_)
             {
-                CopyElements(newBuffer, buffer_, size_);
-                delete[] buffer_;
+                CopyElements(newBuffer, GetBuffer(), size_);
+                delete[] GetBuffer();
             }
             buffer_ = newBuffer;
         }
@@ -335,11 +331,11 @@ public:
         {
             newBuffer = new T[capacity_];
             // Move the data into the new buffer
-            CopyElements(newBuffer, buffer_, size_);
+            CopyElements(newBuffer, GetBuffer(), size_);
         }
         
         // Delete the old buffer
-        delete[] buffer_;
+        delete[] GetBuffer();
         buffer_ = newBuffer;
     }
     
@@ -350,21 +346,21 @@ public:
     }
     
     /// Return iterator to the beginning
-    Iterator Begin() { return Iterator(buffer_); }
+    Iterator Begin() { return Iterator(GetBuffer()); }
     /// Return const iterator to the beginning
-    ConstIterator Begin() const { return ConstIterator(buffer_); }
+    ConstIterator Begin() const { return ConstIterator(GetBuffer()); }
     /// Return iterator to the end
-    Iterator End() { return Iterator(buffer_ + size_); }
+    Iterator End() { return Iterator(GetBuffer() + size_); }
     /// Return const iterator to the end
-    ConstIterator End() const { return ConstIterator(buffer_ + size_); }
+    ConstIterator End() const { return ConstIterator(GetBuffer() + size_); }
     /// Return first element
-    T& Front() { return buffer_[0]; }
+    T& Front() { return GetBuffer()[0]; }
     /// Return const first element
-    const T& Front() const { return buffer_[0]; }
+    const T& Front() const { return GetBuffer()[0]; }
     /// Return last element
-    T& Back() { return buffer_[size_ - 1]; }
+    T& Back() { return GetBuffer()[size_ - 1]; }
     /// Return const last element
-    const T& Back() const { return buffer_[size_ - 1]; }
+    const T& Back() const { return GetBuffer()[size_ - 1]; }
     /// Return size of vector
     unsigned Size() const { return size_; }
     /// Return capacity of vector
@@ -376,18 +372,22 @@ public:
     static const unsigned MIN_CAPACITY = 1;
     
 private:
+    /// Return the buffer with right type
+    T* GetBuffer() const { return reinterpret_cast<T*>(buffer_); }
+    
     /// Move a range of elements within the vector
     void MoveRange(unsigned dest, unsigned src, unsigned count)
     {
+        T* buffer = GetBuffer();
         if (src < dest)
         {
             for (unsigned i = count - 1; i < count; --i)
-                buffer_[dest + i] = buffer_[src + i];
+                buffer[dest + i] = buffer[src + i];
         }
         if (src > dest)
         {
             for (unsigned i = 0; i < count; ++i)
-                buffer_[dest + i] = buffer_[src + i];
+                buffer[dest + i] = buffer[src + i];
         }
     }
     
@@ -397,11 +397,4 @@ private:
         for (unsigned i = 0; i < count; ++i)
             dest[i] = src[i];
     }
-    
-    /// Size of vector
-    unsigned size_;
-    /// Buffer capacity
-    unsigned capacity_;
-    /// Buffer
-    T* buffer_;
 };

+ 55 - 0
Engine/Core/VectorBase.h

@@ -0,0 +1,55 @@
+//
+// 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 "Swap.h"
+
+/// Vector base class
+class VectorBase
+{
+public:
+    /// Construct
+    VectorBase() :
+        size_(0),
+        capacity_(0),
+        buffer_(0)
+    {
+    }
+    
+    /// Swap with another vector
+    void Swap(VectorBase& rhs)
+    {
+        ::Swap(size_, rhs.size_);
+        ::Swap(capacity_, rhs.capacity_);
+        ::Swap(buffer_, rhs.buffer_);
+    }
+    
+protected:
+    /// Size of vector
+    unsigned size_;
+    /// Buffer capacity
+    unsigned capacity_;
+    /// Buffer
+    void* buffer_;
+};