瀏覽代碼

Fixed bugs in Map.
Added HashSet & HashMap classes.
Use HashSet in performance-critical parts of the Renderer library.

Lasse Öörni 14 年之前
父節點
當前提交
f899c2f7ca

+ 177 - 0
Engine/Container/HashBase.h

@@ -0,0 +1,177 @@
+//
+// Urho3D Engine
+// Copyright (c) 2008-2011 Lasse Öörni
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "Allocator.h"
+#include "Swap.h"
+
+/// Pointer hash function
+template <class T> unsigned MakeHash(T* value)
+{
+    return (unsigned)value;
+}
+
+/// Const pointer hash function
+template <class T> unsigned MakeHash(const T* value)
+{
+    return (unsigned)value;
+}
+
+/// Generic hash function
+template <class T> unsigned MakeHash(const T& value)
+{
+    return value.ToHash();
+}
+
+/// Int hash function
+template<> inline unsigned MakeHash(const int& value)
+{
+    return value;
+}
+
+/// Unsigned hash function
+template<> inline unsigned MakeHash(const unsigned& value)
+{
+    return value;
+}
+
+/// Short hash function
+template<> inline unsigned MakeHash(const short& value)
+{
+    return value;
+}
+
+/// Unsigned short hash function
+template<> inline unsigned MakeHash(const unsigned short& value)
+{
+    return value;
+}
+
+/// Char hash function
+template<> inline unsigned MakeHash(const char& value)
+{
+    return value;
+}
+
+/// Unsigned char hash function
+template<> inline unsigned MakeHash(const unsigned char& value)
+{
+    return value;
+}
+
+/// Hash node base
+struct HashNodeBase
+{
+    /// Construct
+    HashNodeBase() :
+        prev_(0),
+        next_(0),
+        down_(0)
+    {
+    }
+    
+    /// Previous node
+    HashNodeBase* prev_;
+    /// Next node
+    HashNodeBase* next_;
+    /// Next node in the bucket
+    HashNodeBase* down_;
+};
+
+/// Hash iterator base class
+class HashIteratorBase
+{
+public:
+    /// Construct
+    explicit HashIteratorBase(HashNodeBase* ptr) :
+        ptr_(ptr)
+    {
+    }
+
+    /// Test for equality with another iterator
+    bool operator == (const HashIteratorBase& rhs) const { return ptr_ == rhs.ptr_; }
+    /// Test for inequality with another iterator
+    bool operator != (const HashIteratorBase& rhs) const { return ptr_ != rhs.ptr_; }
+
+    /// Go to the next node
+    void GotoNext()
+    {
+        if (ptr_)
+            ptr_ = ptr_->next_;
+    }
+
+    /// Go to the previous node
+    void GotoPrev()
+    {
+        if (ptr_)
+            ptr_ = ptr_->prev_;
+    }
+
+    /// Node pointer
+    HashNodeBase* ptr_;
+};
+
+/// Hash set/map base class
+class HashBase
+{
+public:
+    /// Initial amount of buckets
+    static const unsigned MIN_BUCKETS = 8;
+    /// Maximum load factor
+    static const unsigned MAX_LOAD_FACTOR = 4;
+    
+    /// Construct
+    HashBase() :
+        ptrs_(0),
+        allocator_(0),
+        size_(0),
+        numBuckets_(0)
+    {
+    }
+
+    /// Swap with another hash set or map
+    void Swap(HashBase& rhs)
+    {
+        ::Swap(head_, rhs.head_);
+        ::Swap(tail_, rhs.tail_);
+        ::Swap(ptrs_, rhs.ptrs_);
+        ::Swap(allocator_, rhs.allocator_);
+        ::Swap(size_, rhs.size_);
+        ::Swap(numBuckets_, rhs.numBuckets_);
+    }
+
+protected:
+    /// List head node pointer
+    HashNodeBase* head_;
+    /// List tail node pointer
+    HashNodeBase* tail_;
+    /// Bucket head pointers
+    HashNodeBase** ptrs_;
+    /// Node allocator
+    AllocatorBlock* allocator_;
+    /// Number of nodes
+    unsigned size_;
+    /// Number of buckets
+    unsigned numBuckets_;
+};

+ 508 - 0
Engine/Container/HashMap.h

@@ -0,0 +1,508 @@
+//
+// 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 "HashBase.h"
+#include "Pair.h"
+
+/// Hash-based map template class
+template <class T, class U> class HashMap : public HashBase
+{
+public:
+    /// Hash map key-value pair with const key
+    class KeyValue
+    {
+    public:
+        /// Construct with default key
+        KeyValue() :
+            first_(T())
+        {
+        }
+        
+        /// Construct with key and value
+        KeyValue(const T& first, const U& second) :
+            first_(first),
+            second_(second)
+        {
+        }
+        
+        /// Test for equality with another pair
+        bool operator == (const KeyValue& rhs) const { return (first_ == rhs.first_) && (second_ == rhs.second_); }
+        /// Test for inequality with another pair
+        bool operator != (const KeyValue& rhs) const { return (first_ != rhs.first_) || (second_ != rhs.second_); }
+        
+        const T first_;
+        U second_;
+    };
+    
+    /// Hash map node
+    struct Node : public HashNodeBase
+    {
+        /// Construct undefined
+        Node()
+        {
+        }
+        
+        /// Construct with key and value
+        Node(const T& key, const U& value) :
+            pair_(key, value)
+        {
+        }
+        
+        /// Key-value pair
+        KeyValue pair_;
+        
+        /// Return next node
+        Node* Next() const { return static_cast<Node*>(next_); }
+        /// Return previous node
+        Node* Prev() const { return static_cast<Node*>(prev_); }
+        /// Return next node in the bucket
+        Node* Down() const { return static_cast<Node*>(down_); }
+    };
+    
+    /// Hash map node iterator
+    class Iterator : public HashIteratorBase
+    {
+    public:
+        /// Construct
+        Iterator(Node* ptr) :
+            HashIteratorBase(ptr)
+        {
+        }
+        
+        /// Preincrement the pointer
+        Iterator& operator ++ () { GotoNext(); return *this; }
+        /// Postincrement the pointer
+        Iterator operator ++ (int) { Iterator it = *this; GotoNext(); return it; }
+        /// Predecrement the pointer
+        Iterator& operator -- () { GotoPrev(); return *this; }
+        /// Postdecrement the pointer
+        Iterator operator -- (int) { Iterator it = *this; GotoPrev(); return it; }
+        
+        /// Point to the pair
+        KeyValue* operator -> () const { return &(static_cast<Node*>(ptr_))->pair_; }
+        /// Dereference the pair
+        KeyValue& operator * () const { return (static_cast<Node*>(ptr_))->pair_; }
+    };
+    
+    /// Hash map node const iterator
+    class ConstIterator : public HashIteratorBase
+    {
+    public:
+        /// Construct
+        ConstIterator(Node* ptr) :
+            HashIteratorBase(ptr)
+        {
+        }
+        
+        /// Construct from a non-const iterator
+        ConstIterator(const Iterator& rhs) :
+            HashIteratorBase(rhs.ptr_)
+        {
+        }
+        
+        /// Assign from a non-const iterator
+        ConstIterator& operator = (const Iterator& rhs) { ptr_ = rhs.ptr_; return *this; }
+        /// Preincrement the pointer
+        Iterator& operator ++ () { GotoNext(); return *this; }
+        /// Postincrement the pointer
+        Iterator operator ++ (int) { Iterator it = *this; GotoNext(); return it; }
+        /// Predecrement the pointer
+        Iterator& operator -- () { GotoPrev(); return *this; }
+        /// Postdecrement the pointer
+        Iterator operator -- (int) { Iterator it = *this; GotoPrev(); return it; }
+        
+        /// Point to the pair
+        const KeyValue* operator -> () const { return &(static_cast<Node*>(ptr_))->pair_; }
+        /// Dereference the pair
+        const KeyValue& operator * () const { return (static_cast<Node*>(ptr_))->pair_; }
+    };
+    
+    /// Construct empty
+    HashMap()
+    {
+        // Reserve the tail node
+        allocator_ = AllocatorInitialize(sizeof(Node));
+        head_ = tail_ = ReserveNode();
+    }
+    
+    /// Construct from another hash map
+    HashMap(const HashMap<T, U>& map)
+    {
+        // Reserve the tail node
+        allocator_ = AllocatorInitialize(sizeof(Node));
+        head_ = tail_ = ReserveNode();
+        
+        *this = map;
+    }
+    
+    /// Destruct
+    ~HashMap()
+    {
+        Clear();
+        FreeNode(Tail());
+        AllocatorUninitialize(allocator_);
+        delete[] ptrs_;
+    }
+    
+    /// Assign a hash map
+    HashMap& operator = (const HashMap<T, U>& rhs)
+    {
+        Clear();
+        Insert(rhs);
+        
+        return *this;
+    }
+    
+    /// Add-assign a pair
+    HashMap& operator += (const Pair<T, U>& rhs)
+    {
+        Insert(rhs);
+        return *this;
+    }
+    
+    /// Add-assign a hash map
+    HashMap& operator += (const HashMap<T, U>& rhs)
+    {
+        Insert(rhs);
+        return *this;
+    }
+    
+    /// Index the map. Create a new pair if key not found
+    U& operator [] (const T& key)
+    {
+        if (!numBuckets_)
+        {
+            Node* newNode = InsertNode(Tail(), key, U());
+            return newNode->pair_.second_;
+        }
+        
+        unsigned hashKey = MakeHash(key) & (numBuckets_ - 1);
+        
+        Node* node = FindNode(key);
+        if (node)
+            return node->pair_.second_;
+        else
+        {
+            node = InsertNode(Tail(), key, U());
+            return node->pair_.second_;
+        }
+    }
+    
+    /// Insert a pair. Return an iterator to it
+    Iterator Insert(const Pair<T, U>& pair)
+    {
+        // If no pointers yet, allocate with minimum bucket count
+        if (!ptrs_)
+        {
+            numBuckets_ = MIN_BUCKETS;
+            Rehash();
+        }
+        
+        unsigned hashKey = MakeHash(pair.first_) & (numBuckets_ - 1);
+        
+        // If exists, just change the value
+        Node* existing = FindNode(pair.first_, hashKey);
+        if (existing)
+        {
+            existing->pair_.second_ = pair.second_;
+            return Iterator(existing);
+        }
+        
+        Node** ptrs = Ptrs();
+        Node* newNode = InsertNode(Tail(), pair.first_, pair.second_);
+        newNode->down_ = ptrs[hashKey];
+        ptrs[hashKey] = newNode;
+        
+        // Rehash if the maximum load factor has been exceeded
+        if (size_ > numBuckets_ * MAX_LOAD_FACTOR)
+        {
+            numBuckets_ <<= 1;
+            Rehash();
+        }
+        
+        return Iterator(newNode);
+    }
+    
+    /// Insert a map
+    void Insert(const HashMap<T, U>& map)
+    {
+        Insert(map.Begin(), map.End());
+    }
+    
+    /// Insert a key by iterator. Return iterator to the value
+    Iterator Insert(const ConstIterator& it)
+    {
+        return Iterator(InsertNode(*it));
+    }
+    
+    /// Insert a range by iterators
+    void Insert(const ConstIterator& start, const ConstIterator& end)
+    {
+        ConstIterator it = start;
+        while (it != end)
+            InsertNode(*it++);
+    }
+    
+    /// Erase a pair by key. Return true if was found
+    bool Erase(const T& key)
+    {
+        if (!numBuckets_)
+            return false;
+        
+        unsigned hashKey = MakeHash(key) & (numBuckets_ - 1);
+        
+        Node* previous;
+        Node* node = FindNode(key, hashKey, previous);
+        if (!node)
+            return false;
+        
+        if (previous)
+            previous->next_ = node->next_;
+        else
+            ptrs_[hashKey] = node->next_;
+        EraseNode(node);
+        
+        return true;
+    }
+    
+    /// Erase a pair by iterator
+    void Erase(const Iterator& it)
+    {
+        return Erase(it->first_);
+    }
+    
+    /// Erase a range by iterators
+    void Erase(const Iterator& start, const Iterator& end)
+    {
+        Iterator it = start;
+        while (it != end)
+        {
+            Iterator current = it++;
+            Erase(current->first_);
+        }
+    }
+    
+    /// Clear the map
+    void Clear()
+    {
+        while (size_)
+            EraseNode(Head());
+        
+        // Reset bucket pointers
+        for (unsigned i = 0; i < numBuckets_; ++i)
+            ptrs_[i] = 0;
+    }
+    
+    /// Return iterator to the pair with key, or end iterator if not found
+    Iterator Find(const T& key)
+    {
+        if (!numBuckets_)
+            return End();
+        
+        unsigned hashKey = MakeHash(key) & (numBuckets_ - 1);
+        Node* node = FindNode(key, hashKey);
+        if (node)
+            return Iterator(node);
+        else
+            return End();
+    }
+    
+    /// Return const iterator to the pair with key, or end iterator if not found
+    ConstIterator Find(const T& key) const
+    {
+        if (!numBuckets_)
+            return End();
+        
+        unsigned hashKey = MakeHash(key) & (numBuckets_ - 1);
+        Node* node = FindNode(key, hashKey);
+        if (node)
+            return ConstIterator(node);
+        else
+            return End();
+    }
+    
+    /// Return whether contains a pair with key
+    bool Contains(const T& key) const
+    {
+        if (!numBuckets_)
+            return false;
+        
+        unsigned hashKey = MakeHash(key) & (numBuckets_ - 1);
+        return FindNode(key, hashKey) != 0;
+    }
+    
+    /// Return iterator to the beginning
+    Iterator Begin() { return Iterator(Head()); }
+    /// Return iterator to the beginning
+    ConstIterator Begin() const { return ConstIterator(Head()); }
+    /// Return iterator to the end
+    Iterator End() { return Iterator(Tail()); }
+    /// Return iterator to the end
+    ConstIterator End() const { return ConstIterator(Tail()); }
+    /// Return first key
+    const T& Front() const { return *Begin(); }
+    /// Return last key
+    const T& Back() const { return *(--End()); }
+    /// Return number of keys
+    unsigned Size() const { return size_; }
+    /// Return whether set is empty
+    bool Empty() const { return size_ == 0; }
+    
+private:
+    /// Return the head pointer with correct type
+    Node* Head() const { return reinterpret_cast<Node*>(head_); }
+    /// Return the tail pointer with correct type
+    Node* Tail() const { return reinterpret_cast<Node*>(tail_); }
+    /// Return the bucket pointers with correct type
+    Node** Ptrs() const { return reinterpret_cast<Node**>(ptrs_); }
+    
+    /// Find a node from the buckets
+    Node* FindNode(const T& key, unsigned hashKey) const
+    {
+        Node** ptrs = Ptrs();
+        if (!ptrs)
+            return 0;
+        
+        Node* node = ptrs[hashKey];
+        while (node)
+        {
+            if (node->pair_.first_ == key)
+                return node;
+            node = node->Down();
+        }
+        
+        return 0;
+    }
+    
+    /// Find a node and the previous node from the buckets
+    Node* FindNode(const T& key, unsigned hashKey, Node*& previous) const
+    {
+        previous = 0;
+        
+        Node** ptrs = Ptrs();
+        if (!ptrs)
+            return 0;
+        
+        Node* node = ptrs[hashKey];
+        while (node)
+        {
+            if (node->pair_.key_ == key)
+                return node;
+            previous = node;
+            node = node->Down();
+        }
+        
+        return 0;
+    }
+    
+    /// Insert a node into the list. Return the new node
+    Node* InsertNode(Node* dest, const T& key, const U& value)
+    {
+        if (!dest)
+            return 0;
+        
+        Node* newNode = ReserveNode(key, value);
+        Node* prev = dest->Prev();
+        newNode->next_ = dest;
+        newNode->prev_ = prev;
+        if (prev)
+            prev->next_ = newNode;
+        dest->prev_ = newNode;
+        
+        // Reassign the head node if necessary
+        if (dest == Head())
+            head_ = newNode;
+        
+        ++size_;
+        
+        return newNode;
+    }
+    
+    /// Erase a node from the list. Return pointer to the next element, or to the end if could not erase
+    Node* EraseNode(Node* toRemove)
+    {
+        // The tail node can not be removed
+        if ((!toRemove) || (toRemove == tail_))
+            return Tail();
+        
+        Node* prev = toRemove->Prev();
+        Node* next = toRemove->Next();
+        if (prev)
+            prev->next_ = next;
+        next->prev_ = prev;
+        
+        // Reassign the head node if necessary
+        if (toRemove == Head())
+            head_ = next;
+        
+        FreeNode(toRemove);
+        --size_;
+        
+        return next;
+    }
+    
+    /// Reserve a node
+    Node* ReserveNode()
+    {
+        Node* newNode = static_cast<Node*>(AllocatorReserve(allocator_));
+        new(newNode) Node();
+        return newNode;
+    }
+    
+    /// Reserve a node with specified key and value
+    Node* ReserveNode(const T& key, const U& value)
+    {
+        if (!allocator_)
+            allocator_ = AllocatorInitialize(sizeof(Node));
+        Node* newNode = static_cast<Node*>(AllocatorReserve(allocator_));
+        new(newNode) Node(key, value);
+        return newNode;
+    }
+    
+    /// Free a node
+    void FreeNode(Node* node)
+    {
+        (node)->~Node();
+        AllocatorFree(allocator_, node);
+    }
+    
+    /// Reallocate and rehash the buckets
+    void Rehash()
+    {
+        delete[] ptrs_;
+        
+        ptrs_ = new HashNodeBase*[numBuckets_];
+        for (unsigned i = 0; i < numBuckets_; ++i)
+            ptrs_[i] = 0;
+        
+        for (Iterator i = Begin(); i != End(); ++i)
+        {
+            Node* node = reinterpret_cast<Node*>(i.ptr_);
+            unsigned hashKey = MakeHash(i->first_) & (numBuckets_ - 1);
+            node->down_ = ptrs_[hashKey];
+            ptrs_[hashKey] = node;
+        }
+    }
+};

+ 456 - 0
Engine/Container/HashSet.h

@@ -0,0 +1,456 @@
+//
+// 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 "HashBase.h"
+
+/// Hash-based set template class
+template <class T> class HashSet : public HashBase
+{
+public:
+    /// Hash set node
+    struct Node : public HashNodeBase
+    {
+        // Construct undefined
+        Node()
+        {
+        }
+        
+        /// Construct with key
+        Node(const T& key) :
+            key_(key)
+        {
+        }
+        
+        /// Key
+        T key_;
+        
+        /// Return next node
+        Node* Next() const { return static_cast<Node*>(next_); }
+        /// Return previous node
+        Node* Prev() const { return static_cast<Node*>(prev_); }
+        /// Return next node in the bucket
+        Node* Down() const { return static_cast<Node*>(down_); }
+    };
+    
+    /// Hash set node iterator
+    class Iterator : public HashIteratorBase
+    {
+    public:
+        /// Construct
+        Iterator(Node* ptr) :
+            HashIteratorBase(ptr)
+        {
+        }
+        
+        /// Preincrement the pointer
+        Iterator& operator ++ () { GotoNext(); return *this; }
+        /// Postincrement the pointer
+        Iterator operator ++ (int) { Iterator it = *this; GotoNext(); return it; }
+        /// Predecrement the pointer
+        Iterator& operator -- () { GotoPrev(); return *this; }
+        /// Postdecrement the pointer
+        Iterator operator -- (int) { Iterator 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_; }
+    };
+    
+    /// Hash set node const iterator
+    class ConstIterator : public HashIteratorBase
+    {
+    public:
+        /// Construct
+        ConstIterator(Node* ptr) :
+            HashIteratorBase(ptr)
+        {
+        }
+        
+        /// Construct from a non-const iterator
+        ConstIterator(const Iterator& rhs) :
+            HashIteratorBase(rhs.ptr_)
+        {
+        }
+        
+        /// Assign from a non-const iterator
+        ConstIterator& operator = (const Iterator& rhs) { ptr_ = rhs.ptr_; return *this; }
+        /// Preincrement the pointer
+        Iterator& operator ++ () { GotoNext(); return *this; }
+        /// Postincrement the pointer
+        Iterator operator ++ (int) { Iterator it = *this; GotoNext(); return it; }
+        /// Predecrement the pointer
+        Iterator& operator -- () { GotoPrev(); return *this; }
+        /// Postdecrement the pointer
+        Iterator operator -- (int) { Iterator 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
+    HashSet()
+    {
+        // Reserve the tail node
+        allocator_ = AllocatorInitialize(sizeof(Node));
+        head_ = tail_ = ReserveNode();
+    }
+    
+    /// Construct from another hash set
+    HashSet(const HashSet<T>& set)
+    {
+        // Reserve the tail node
+        allocator_ = AllocatorInitialize(sizeof(Node));
+        head_ = tail_ = ReserveNode();
+        
+        *this = set;
+    }
+    
+    /// Destruct
+    ~HashSet()
+    {
+        Clear();
+        FreeNode(Tail());
+        AllocatorUninitialize(allocator_);
+        delete[] ptrs_;
+    }
+    
+    /// Assign a hash set
+    HashSet& operator = (const HashSet<T>& rhs)
+    {
+        Clear();
+        Insert(rhs.Begin(), rhs.End());
+        
+        return *this;
+    }
+    
+    /// Add-assign a value
+    HashSet& operator += (const T& rhs)
+    {
+        Insert(rhs);
+        return *this;
+    }
+    
+    /// Add-assign a hash set
+    HashSet& operator += (const HashSet<T>& rhs)
+    {
+        Insert(rhs.Begin(), rhs.End());
+        return *this;
+    }
+    
+    /// Insert a key. Return an iterator to it
+    Iterator Insert(const T& key)
+    {
+        // If no pointers yet, allocate with minimum bucket count
+        if (!ptrs_)
+        {
+            numBuckets_ = MIN_BUCKETS;
+            Rehash();
+        }
+        
+        unsigned hashKey = MakeHash(key) & (numBuckets_ - 1);
+        
+        Node* existing = FindNode(key, hashKey);
+        if (existing)
+            return Iterator(existing);
+        
+        Node** ptrs = Ptrs();
+        Node* newNode = InsertNode(Tail(), key);
+        newNode->down_ = ptrs[hashKey];
+        ptrs[hashKey] = newNode;
+        
+        // Rehash if the maximum load factor has been exceeded
+        if (size_ > numBuckets_ * MAX_LOAD_FACTOR)
+        {
+            numBuckets_ <<= 1;
+            Rehash();
+        }
+        
+        return Iterator(newNode);
+    }
+    
+    /// Insert a set
+    void Insert(const HashSet<T>& set)
+    {
+        Insert(set.Begin(), set.End());
+    }
+    
+    /// Insert a key by iterator. Return iterator to the value
+    Iterator Insert(const ConstIterator& it)
+    {
+        return Iterator(InsertNode(*it));
+    }
+    
+    /// Insert a range by iterators
+    void Insert(const ConstIterator& start, const ConstIterator& end)
+    {
+        ConstIterator it = start;
+        while (it != end)
+            InsertNode(*it++);
+    }
+    
+    /// Erase a key. Return true if was found
+    bool Erase(const T& key)
+    {
+        if (!numBuckets_)
+            return false;
+        
+        unsigned hashKey = MakeHash(key) & (numBuckets_ - 1);
+        
+        Node* previous;
+        Node* node = FindNode(key, hashKey, previous);
+        if (!node)
+            return false;
+        
+        if (previous)
+            previous->next_ = node->next_;
+        else
+            ptrs_[hashKey] = node->next_;
+        EraseNode(node);
+        
+        return true;
+    }
+    
+    /// Erase a key by iterator
+    void Erase(const Iterator& it)
+    {
+        return Erase(*it);
+    }
+    
+    /// Erase a range by iterators
+    void Erase(const Iterator& start, const Iterator& end)
+    {
+        Iterator it = start;
+        while (it != end)
+        {
+            Iterator current = it++;
+            Erase(current);
+        }
+    }
+    
+    /// Clear the set
+    void Clear()
+    {
+        while (size_)
+            EraseNode(Head());
+        
+        // Reset bucket pointers
+        for (unsigned i = 0; i < numBuckets_; ++i)
+            ptrs_[i] = 0;
+    }
+    
+    /// Return iterator to the key, or end iterator if not found
+    Iterator Find(const T& key)
+    {
+        if (!numBuckets_)
+            return End();
+        
+        unsigned hashKey = MakeHash(key) & (numBuckets_ - 1);
+        Node* node = FindNode(key, hashKey);
+        if (node)
+            return Iterator(node);
+        else
+            return End();
+    }
+    
+    /// Return const iterator to the key, or end iterator if not found
+    ConstIterator Find(const T& key) const
+    {
+        if (!numBuckets_)
+            return End();
+        
+        unsigned hashKey = MakeHash(key) & (numBuckets_ - 1);
+        Node* node = FindNode(key, hashKey);
+        if (node)
+            return ConstIterator(node);
+        else
+            return End();
+    }
+    
+    /// Return whether contains a key
+    bool Contains(const T& key) const
+    {
+        if (!numBuckets_)
+            return false;
+        
+        unsigned hashKey = MakeHash(key) & (numBuckets_ - 1);
+        return FindNode(key, hashKey) != 0;
+    }
+    
+    /// Return iterator to the beginning
+    Iterator Begin() { return Iterator(Head()); }
+    /// Return iterator to the beginning
+    ConstIterator Begin() const { return ConstIterator(Head()); }
+    /// Return iterator to the end
+    Iterator End() { return Iterator(Tail()); }
+    /// Return iterator to the end
+    ConstIterator End() const { return ConstIterator(Tail()); }
+    /// Return first key
+    const T& Front() const { return *Begin(); }
+    /// Return last key
+    const T& Back() const { return *(--End()); }
+    /// Return number of keys
+    unsigned Size() const { return size_; }
+    /// Return whether set is empty
+    bool Empty() const { return size_ == 0; }
+    
+private:
+    /// Return the head pointer with correct type
+    Node* Head() const { return reinterpret_cast<Node*>(head_); }
+    /// Return the tail pointer with correct type
+    Node* Tail() const { return reinterpret_cast<Node*>(tail_); }
+    /// Return the bucket pointers with correct type
+    Node** Ptrs() const { return reinterpret_cast<Node**>(ptrs_); }
+    
+    /// Find a node from the buckets
+    Node* FindNode(const T& key, unsigned hashKey) const
+    {
+        Node** ptrs = Ptrs();
+        if (!ptrs)
+            return 0;
+        
+        Node* node = ptrs[hashKey];
+        while (node)
+        {
+            if (node->key_ == key)
+                return node;
+            node = node->Down();
+        }
+        
+        return 0;
+    }
+    
+    /// Find a node and the previous node from the buckets
+    Node* FindNode(const T& key, unsigned hashKey, Node*& previous) const
+    {
+        previous = 0;
+        
+        Node** ptrs = Ptrs();
+        if (!ptrs)
+            return 0;
+        
+        Node* node = ptrs[hashKey];
+        while (node)
+        {
+            if (node->key_ == key)
+                return node;
+            previous = node;
+            node = node->Down();
+        }
+        
+        return 0;
+    }
+    
+    /// Insert a node into the list. Return the new node
+    Node* InsertNode(Node* dest, const T& key)
+    {
+        if (!dest)
+            return 0;
+        
+        Node* newNode = ReserveNode(key);
+        Node* prev = dest->Prev();
+        newNode->next_ = dest;
+        newNode->prev_ = prev;
+        if (prev)
+            prev->next_ = newNode;
+        dest->prev_ = newNode;
+        
+        // Reassign the head node if necessary
+        if (dest == Head())
+            head_ = newNode;
+        
+        ++size_;
+        
+        return newNode;
+    }
+    
+    /// Erase a node from the list. Return pointer to the next element, or to the end if could not erase
+    Node* EraseNode(Node* toRemove)
+    {
+        // The tail node can not be removed
+        if ((!toRemove) || (toRemove == tail_))
+            return Tail();
+        
+        Node* prev = toRemove->Prev();
+        Node* next = toRemove->Next();
+        if (prev)
+            prev->next_ = next;
+        next->prev_ = prev;
+        
+        // Reassign the head node if necessary
+        if (toRemove == Head())
+            head_ = next;
+        
+        FreeNode(toRemove);
+        --size_;
+        
+        return next;
+    }
+    
+    /// Reserve a node
+    Node* ReserveNode()
+    {
+        Node* newNode = static_cast<Node*>(AllocatorReserve(allocator_));
+        new(newNode) Node();
+        return newNode;
+    }
+    
+    /// Reserve a node with specified key
+    Node* ReserveNode(const T& key)
+    {
+        if (!allocator_)
+            allocator_ = AllocatorInitialize(sizeof(Node));
+        Node* newNode = static_cast<Node*>(AllocatorReserve(allocator_));
+        new(newNode) Node(key);
+        return newNode;
+    }
+    
+    /// Free a node
+    void FreeNode(Node* node)
+    {
+        (node)->~Node();
+        AllocatorFree(allocator_, node);
+    }
+    
+    /// Reallocate and rehash the buckets
+    void Rehash()
+    {
+        delete[] ptrs_;
+        
+        ptrs_ = new HashNodeBase*[numBuckets_];
+        for (unsigned i = 0; i < numBuckets_; ++i)
+            ptrs_[i] = 0;
+        
+        for (Iterator i = Begin(); i != End(); ++i)
+        {
+            Node* node = reinterpret_cast<Node*>(i.ptr_);
+            unsigned hashKey = MakeHash(*i) & (numBuckets_ - 1);
+            node->down_ = ptrs_[hashKey];
+            ptrs_[hashKey] = node;
+        }
+    }
+};

+ 45 - 39
Engine/Container/List.h

@@ -47,13 +47,12 @@ public:
         T value_;
         
         /// Return next node
-        Node* GetNext() const { return static_cast<Node*>(next_); }
-        
+        Node* Next() const { return static_cast<Node*>(next_); }
         /// Return previous node
-        Node* GetPrev() { return static_cast<Node*>(prev_); }
+        Node* Prev() { return static_cast<Node*>(prev_); }
     };
     
-    /// List node iterator
+    /// List iterator
     class Iterator : public ListIteratorBase
     {
     public:
@@ -78,7 +77,7 @@ public:
         T& operator * () const { return (static_cast<Node*>(ptr_))->value_; }
     };
     
-    /// List node const iterator
+    /// List const iterator
     class ConstIterator : public ListIteratorBase
     {
     public:
@@ -112,8 +111,7 @@ public:
     };
 
     /// Construct empty
-    List() :
-        ListBase()
+    List()
     {
         // Reserve the tail node
         allocator_ = AllocatorInitialize(sizeof(Node));
@@ -121,8 +119,7 @@ public:
     }
     
     /// Construct from another list
-    List(const List<T>& list) :
-        ListBase()
+    List(const List<T>& list)
     {
         // Reserve the tail node
         allocator_ = AllocatorInitialize(sizeof(Node));
@@ -136,7 +133,7 @@ public:
     ~List()
     {
         Clear();
-        FreeNode(GetTail());
+        FreeNode(Tail());
         AllocatorUninitialize(allocator_);
     }
     
@@ -145,12 +142,12 @@ public:
     {
         // Clear, then insert the nodes of the other list
         Clear();
-        Insert(End(), rhs.Begin(), rhs.End());
+        Insert(End(), rhs);
         
         return *this;
     }
     
-    /// Add-assign a value
+    /// Add-assign an element
     List& operator += (const T& rhs)
     {
         Push(rhs);
@@ -160,7 +157,7 @@ public:
     /// Add-assign a list
     List& operator += (const List<T>& rhs)
     {
-        Insert(End(), rhs.Begin(), rhs.End());
+        Insert(End(), rhs);
         return *this;
     }
     
@@ -202,19 +199,29 @@ public:
         return false;
     }
     
-    /// Insert a value at the end
+    /// Insert an element the end
     void Push(const T& value)
     {
-        InsertNode(GetTail(), value);
+        InsertNode(Tail(), value);
     }
     
-    /// Insert a value into the list
+    /// Insert an element at position
     void Insert(const Iterator& dest, const T& value)
     {
         InsertNode(static_cast<Node*>(dest.ptr_), value);
     }
     
-    /// Insert a range by iterators
+    /// Insert a list at position
+    void Insert(const Iterator& dest, const List<T>& list)
+    {
+        Node* destNode = static_cast<Node*>(dest.ptr_);
+        Iterator it = list.Begin();
+        Iterator end = list.End();
+        while (it != end)
+            InsertNode(destNode, *it++);
+    }
+    
+    /// Insert elements by iterators
     void Insert(const Iterator& dest, const Iterator& start, const Iterator& end)
     {
         Node* destNode = static_cast<Node*>(dest.ptr_);
@@ -223,20 +230,20 @@ public:
             InsertNode(destNode, *it++);
     }
     
-    /// Erase the last node
+    /// Erase the last element
     void Pop()
     {
         if (size_)
             Erase(--End());
     }
     
-    /// Erase a node from the list. Return an iterator to the next element
+    /// Erase an element. Return an iterator to the next element
     Iterator Erase(Iterator it)
     {
         return Iterator(EraseNode(static_cast<Node*>(it.ptr_)));
     }
     
-    /// Erase a range of nodes from the list. Return an iterator to the next element
+    /// Erase a range by iterators. Return an iterator to the next element
     Iterator Erase(const Iterator& start, const Iterator& end)
     {
         Iterator it = start;
@@ -250,69 +257,68 @@ public:
     void Clear()
     {
         while (size_)
-            EraseNode(GetHead());
+            EraseNode(Head());
     }
     
-    /// Return iterator to the first node
-    Iterator Begin() { return Iterator(GetHead()); }
-    /// Return iterator to the first node
-    ConstIterator Begin() const { return ConstIterator(GetHead()); }
+    /// Return iterator to the first element
+    Iterator Begin() { return Iterator(Head()); }
+    /// Return iterator to the first element
+    ConstIterator Begin() const { return ConstIterator(Head()); }
     /// Return iterator to the end
-    Iterator End() { return Iterator(GetTail()); }
+    Iterator End() { return Iterator(Tail()); }
     /// Return iterator to the end
-    ConstIterator End() const { return ConstIterator(GetTail()); }
+    ConstIterator End() const { return ConstIterator(Tail()); }
     /// Return first value
     const T& Front() const { return *Begin(); }
     /// Return last value
     const T& Back() const { return *(--End()); }
-    /// Return number of value
+    /// Return number of values
     unsigned Size() const { return size_; }
     /// Return whether list is empty
     bool Empty() const { return size_ == 0; }
     
 private:
     /// Return the head pointer with correct type
-    Node* GetHead() const { return reinterpret_cast<Node*>(head_); }
+    Node* Head() const { return reinterpret_cast<Node*>(head_); }
     /// Return the tail pointer with correct type
-    Node* GetTail() const { return reinterpret_cast<Node*>(tail_); }
+    Node* Tail() const { return reinterpret_cast<Node*>(tail_); }
     
-    /// Insert a value into the list
+    /// Allocate and insert a node into the list
     void InsertNode(Node* dest, const T& value)
     {
         if (!dest)
             return;
         
         Node* newNode = ReserveNode(value);
-        Node* prev = dest->GetPrev();
+        Node* prev = dest->Prev();
         newNode->next_ = dest;
         newNode->prev_ = prev;
         if (prev)
             prev->next_ = newNode;
         dest->prev_ = newNode;
         
-        
         // Reassign the head node if necessary
-        if (dest == GetHead())
+        if (dest == Head())
             head_ = newNode;
         
         ++size_;
     }
     
-    /// Erase a node from the list. Return pointer to the next element, or to the end if could not erase
+    /// Erase and free a node. Return pointer to the next node, or to the end if could not erase
     Node* EraseNode(Node* toRemove)
     {
         // The tail node can not be removed
         if ((!toRemove) || (toRemove == tail_))
-            return GetTail();
+            return Tail();
         
-        Node* prev = toRemove->GetPrev();
-        Node* next = toRemove->GetNext();
+        Node* prev = toRemove->Prev();
+        Node* next = toRemove->Next();
         if (prev)
             prev->next_ = next;
         next->prev_ = prev;
         
         // Reassign the head node if necessary
-        if (toRemove == GetHead())
+        if (toRemove == Head())
             head_ = next;
         
         FreeNode(toRemove);

+ 3 - 0
Engine/Container/ListBase.h

@@ -29,6 +29,7 @@
 /// List node base
 struct ListNodeBase
 {
+    /// Construct
     ListNodeBase() :
         prev_(0),
         next_(0)
@@ -45,6 +46,7 @@ struct ListNodeBase
 class ListIteratorBase
 {
 public:
+    /// Construct
     explicit ListIteratorBase(ListNodeBase* ptr) :
         ptr_(ptr)
     {
@@ -77,6 +79,7 @@ public:
 class ListBase
 {
 public:
+    /// Construct
     ListBase() :
         allocator_(0),
         size_(0)

+ 32 - 33
Engine/Container/Map.h

@@ -43,12 +43,6 @@ public:
         {
         }
         
-        /// Construct with key
-        KeyValue(const T& first) :
-            first_(first)
-        {
-        }
-        
         /// Construct with key and value
         KeyValue(const T& first, const U& second) :
             first_(first),
@@ -73,12 +67,6 @@ public:
         {
         }
         
-        /// Construct with key
-        Node(const T& key) :
-            pair_(key)
-        {
-        }
-        
         /// Construct with key and value
         Node(const T& key, const U& value) :
             pair_(key, value)
@@ -94,7 +82,7 @@ public:
         Node* Child(unsigned dir) const { return static_cast<Node*>(link_[dir]); }
     };
     
-    /// Map node iterator
+    /// Map iterator
     class Iterator : public TreeIteratorBase
     {
     public:
@@ -119,7 +107,7 @@ public:
         KeyValue& operator * () const { return (static_cast<Node*>(ptr_))->pair_; }
     };
     
-    /// Map node const iterator
+    /// Map const iterator
     class ConstIterator : public TreeIteratorBase
     {
     public:
@@ -172,10 +160,10 @@ public:
     }
     
     /// Assign a map
-    Map<T, U>& operator = (const Map<T, U>& map)
+    Map<T, U>& operator = (const Map<T, U>& rhs)
     {
         Clear();
-        Insert(map.Begin(), map.End());
+        Insert(rhs);
         
         return *this;
     }
@@ -190,7 +178,7 @@ public:
     /// Add-assign a map
     Map<T, U>& operator += (const Map<T, U>& rhs)
     {
-        Insert(rhs.Begin(), rhs.End());
+        Insert(rhs);
         return *this;
     }
     
@@ -232,7 +220,7 @@ public:
         return false;
     }
     
-    /// Index the map. Create new node if key not found
+    /// Index the map. Create a new pair if key not found
     U& operator [] (const T& key)
     {
         Node* node = FindNode(key);
@@ -267,16 +255,16 @@ public:
         Insert(map.Begin(), map.End());
     }
     
-    /// Insert a key by iterator. Return iterator to the value
+    /// Insert a pair by iterator. Return iterator to the value
     Iterator Insert(const ConstIterator& it)
     {
         return Iterator(InsertNode(it->first_, it->second_));
     }
     
-    /// Insert by a range of iterators
-    void Insert(const ConstIterator& begin, const ConstIterator& end)
+    /// Insert a range by iterators
+    void Insert(const ConstIterator& start, const ConstIterator& end)
     {
-        ConstIterator it = begin;
+        ConstIterator it = start;
         while (it != end)
         {
             InsertNode(it->first_, it->second_);
@@ -284,27 +272,38 @@ public:
         }
     }
     
-    /// Erase a key. Return true if was found
+    /// Erase a pair by key. Return true if was found
     bool Erase(const T& key)
     {
         return EraseNode(key);
     }
     
-    /// Erase a key by iterator. Return true if was found
-    bool Erase(const Iterator& it)
+    /// Erase a pair by iterator
+    void Erase(const Iterator& it)
+    {
+        EraseNode(it->first_);
+    }
+    
+    /// Erase a range by iterators
+    void Erase(const Iterator& start, const Iterator& end)
     {
-        return EraseNode(it->first_);
+        Iterator it = start;
+        while (it != end)
+        {
+            Iterator current = it++;
+            Erase(current);
+        }
     }
     
-    /// Return whether contains a key
+    /// Return whether contains a pair with key
     bool Contains(const T& key)
     {
         return FindNode(key) != 0;
     }
     
-    /// Return iterator to the node with key, or end iterator if not found
+    /// Return iterator to the pair, 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
+    /// Return const iterator to the pair, 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 beginning
     Iterator Begin() { return Iterator(FindFirst()); }
@@ -370,7 +369,7 @@ private:
         
         if (!root_)
         {
-            root_ = ret = new Node(key, value);
+            root_ = ret = ReserveNode(key, value);
             ++size_;
         }
         else
@@ -390,7 +389,7 @@ private:
             {
                 if (!q)
                 {
-                    p->SetChild(dir, q = ret = new Node(key, value));
+                    p->SetChild(dir, q = ret = ReserveNode(key, value));
                     ++size_;
                 }
                 else if ((IsRed(q->link_[0])) && (IsRed(q->link_[1])))
@@ -504,7 +503,7 @@ private:
             const_cast<T&>(f->pair_.first_) = q->pair_.first_;
             f->pair_.second_ = q->pair_.second_;
             p->SetChild(p->Child(1) == q, q->link_[q->Child(0) == 0]);
-            delete q;
+            FreeNode(q);
             --size_;
             removed = true;
         }
@@ -524,7 +523,7 @@ private:
     {
         Node* left = node->Child(0);
         Node* right = node->Child(1);
-        delete node;
+        FreeNode(node);
         --size_;
         
         if (left)

+ 21 - 10
Engine/Container/Set.h

@@ -55,7 +55,7 @@ public:
         Node* Child(unsigned dir) const { return static_cast<Node*>(link_[dir]); }
     };
     
-    /// Set node iterator
+    /// Set iterator
     class Iterator : public TreeIteratorBase
     {
     public:
@@ -80,7 +80,7 @@ public:
         const T& operator * () const { return (static_cast<Node*>(ptr_))->key_; }
     };
     
-    /// Set node const iterator
+    /// Set const iterator
     class ConstIterator : public TreeIteratorBase
     {
     public:
@@ -136,7 +136,7 @@ public:
     Set& operator = (const Set<T>& set)
     {
         Clear();
-        Insert(set.Begin(), set.End());
+        Insert(set);
         
         return *this;
     }
@@ -151,7 +151,7 @@ public:
     /// Add-assign a set
     Set& operator += (const Set<T>& rhs)
     {
-        Insert(rhs.Begin(), rhs.End());
+        Insert(rhs);
         return *this;
     }
     
@@ -221,10 +221,10 @@ public:
         return Iterator(InsertNode(*it));
     }
     
-    /// Insert by a range of iterators
-    void Insert(const ConstIterator& begin, const ConstIterator& end)
+    /// Insert a range by iterators
+    void Insert(const ConstIterator& start, const ConstIterator& end)
     {
-        ConstIterator it = begin;
+        ConstIterator it = start;
         while (it != end)
             InsertNode(*it++);
     }
@@ -235,10 +235,21 @@ public:
         return EraseNode(key);
     }
     
-    /// Erase a key by iterator. Return true if was found
-    bool Erase(const Iterator& it)
+    /// Erase a key by iterator
+    void Erase(const Iterator& it)
+    {
+        EraseNode(*it);
+    }
+    
+    /// Erase a range by iterators
+    void Erase(const Iterator& start, const Iterator& end)
     {
-        return EraseNode(*it);
+        Iterator it = start;
+        while (it != end)
+        {
+            Iterator current = it++;
+            Erase(current);
+        }
     }
     
     /// Return whether contains a key

+ 18 - 4
Engine/Container/StringBase.h

@@ -277,7 +277,7 @@ public:
     void Replace(const String& replaceThis, const String& replaceWith);
     /// Replace a substring
     void Replace(unsigned pos, unsigned length, const String& replaceWith);
-    /// Replace a substring using iterators
+    /// Replace a substring by iterators
     Iterator Replace(const Iterator& start, const Iterator& end, const String& replaceWith);
     /// Insert a string
     void Insert(unsigned pos, const String& str);
@@ -285,15 +285,15 @@ public:
     void Insert(unsigned pos, char c);
     /// Insert a string using an iterator
     Iterator Insert(const Iterator& dest, const String& str);
-    /// Insert a string partially using iterators
+    /// Insert a string partially by iterators
     Iterator Insert(const Iterator& dest, const Iterator& start, const Iterator& end);
     /// Insert a character using an iterator
     Iterator Insert(const Iterator& dest, char c);
     /// Erase a substring
     void Erase(unsigned pos, unsigned length = 1);
-    /// Erase a character using an iterator
+    /// Erase a character by iterator
     Iterator Erase(const Iterator& it);
-    /// Erase a substring using iterators
+    /// Erase a substring by iterators
     Iterator Erase(const Iterator& start, const Iterator& end);
     /// Resize the string
     void Resize(unsigned newLength);
@@ -347,6 +347,20 @@ public:
     /// Return whether the string is empty
     bool Empty() const { return length_ == 0; }
     
+    /// Return hash value for HashSet & HashMap
+    unsigned ToHash() const
+    {
+        unsigned hash = 0;
+        const char* ptr = buffer_;
+        while (*ptr)
+        {
+            hash = *ptr + (hash << 6) + (hash << 16) - hash;
+            ++ptr;
+        }
+        
+        return hash;
+    }
+    
     /// Position for "not found"
     static const unsigned NPOS = 0xffffffff;
     /// Initial dynamic allocation size

+ 6 - 0
Engine/Container/Swap.cpp

@@ -21,6 +21,7 @@
 // THE SOFTWARE.
 //
 
+#include "HashBase.h"
 #include "ListBase.h"
 #include "StringBase.h"
 #include "TreeBase.h"
@@ -54,3 +55,8 @@ template<> void Swap<TreeBase>(TreeBase& first, TreeBase& second)
 {
     first.Swap(second);
 }
+
+template<> void Swap<HashBase>(HashBase& first, HashBase& second)
+{
+    first.Swap(second);
+}

+ 2 - 0
Engine/Container/Swap.h

@@ -23,6 +23,7 @@
 
 #pragma once
 
+class HashBase;
 class ListBase;
 class String;
 class TreeBase;
@@ -40,3 +41,4 @@ 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<TreeBase>(TreeBase& first, TreeBase& second);
+template<> void Swap<HashBase>(HashBase& first, HashBase& second);

+ 4 - 0
Engine/Container/TreeBase.h

@@ -61,12 +61,14 @@ struct TreeNodeBase
 class TreeIteratorBase
 {
 public:
+    /// Construct
     TreeIteratorBase() :
         ptr_(0),
         prev_(0)
     {
     }
     
+    /// Construct with a node pointer
     TreeIteratorBase(TreeNodeBase* ptr) :
         ptr_(ptr),
         prev_(0)
@@ -78,6 +80,7 @@ public:
     /// Test for inequality with another iterator
     bool operator != (const TreeIteratorBase& rhs) const { return ptr_ != rhs.ptr_; }
     
+    /// Go to the next node
     void GotoNext()
     {
         if (!ptr_)
@@ -102,6 +105,7 @@ public:
             ptr_ = ptr_->link_[0];
     }
     
+    /// Go to the previous node
     void GotoPrev()
     {
         if (!ptr_)

+ 5 - 5
Engine/Container/Vector.h

@@ -208,7 +208,7 @@ public:
         return Begin() + pos;
     }
     
-    /// Insert a vector partially using iterators
+    /// Insert a vector partially by iterators
     Iterator Insert(const Iterator& dest, const Iterator& start, const Iterator& end)
     {
         unsigned pos = dest - Begin();
@@ -236,7 +236,7 @@ public:
         Resize(size_ - length, 0);
     }
     
-    /// Erase an element using an iterator
+    /// Erase an element by iterator
     Iterator Erase(const Iterator& it)
     {
         unsigned pos = it - Begin();
@@ -247,7 +247,7 @@ public:
         return Begin() + pos;
     }
     
-    /// Erase a range of values using iterators
+    /// Erase a range by iterators
     Iterator Erase(const Iterator& start, const Iterator& end)
     {
         unsigned pos = start - Begin();
@@ -597,7 +597,7 @@ public:
         return Begin() + pos;
     }
     
-    /// Insert a vector partially using iterators
+    /// Insert a vector partially by iterators
     Iterator Insert(const Iterator& dest, const Iterator& start, const Iterator& end)
     {
         unsigned pos = dest - Begin();
@@ -633,7 +633,7 @@ public:
         return Begin() + pos;
     }
     
-    /// Erase a range of values using iterators
+    /// Erase a range by iterators
     Iterator Erase(const Iterator& start, const Iterator& end)
     {
         unsigned pos = start - Begin();

+ 5 - 0
Engine/Core/SharedArrayPtr.h

@@ -23,6 +23,7 @@
 
 #pragma once
 
+#include "HashBase.h"
 #include "RefCounted.h"
 
 /// Shared array pointer template class. Uses non-intrusive reference counting
@@ -155,6 +156,8 @@ public:
     unsigned GetWeakRefCount() const { return refCount_ ? refCount_->weakRefs_ : 0; }
     /// Return pointer to the RefCount structure
     RefCount* GetRefCountPtr() const { return refCount_; }
+    /// Return hash value for HashSet & HashMap
+    unsigned ToHash() const { return (unsigned)ptr_; }
     
 private:
     /// Prevent direct assignment from a shared array pointer of different type
@@ -364,6 +367,8 @@ public:
     bool IsExpired() const { return refCount_ ? refCount_->expired_ : true; }
     /// Return pointer to RefCount structure
     RefCount* GetRefCountPtr() const { return refCount_; }
+    /// Return hash value for HashSet & HashMap
+    unsigned ToHash() const { return (unsigned)ptr_; }
     
 private:
     /// Prevent direct assignment from a weak array pointer of different type

+ 4 - 0
Engine/Core/SharedPtr.h

@@ -142,6 +142,8 @@ public:
     unsigned GetWeakRefCount() const { return ptr_ ? ptr_->GetWeakRefCount() : 0; }
     /// Return pointer to the RefCount structure
     RefCount* GetRefCountPtr() const { return ptr_ ? ptr_->GetRefCountPtr() : 0; }
+    /// Return hash value for HashSet & HashMap
+    unsigned ToHash() const { return (unsigned)ptr_; }
     
 private:
     /// Prevent direct assignment from a shared pointer of another type
@@ -371,6 +373,8 @@ public:
     bool IsExpired() const { return refCount_ ? refCount_->expired_ : true; }
     /// Return pointer to the RefCount structure
     RefCount* GetRefCountPtr() const { return refCount_; }
+    /// Return hash value for HashSet & HashMap
+    unsigned ToHash() const { return (unsigned)ptr_; }
     
 private:
     /// Prevent direct assignment from a weak pointer of different type

+ 1 - 0
Engine/Core/StringHash.h

@@ -49,6 +49,7 @@ public:
     
     /// Construct from a C string case-insensitively
     explicit StringHash(const char* str);
+    
     /// Construct from a string case-insensitively
     explicit StringHash(const String& str);
     

+ 0 - 1
Engine/Engine/APITemplates.h

@@ -37,7 +37,6 @@
 
 #include <angelscript.h>
 #include <cstring>
-#include "Set.h"
 
 /// Template function for dynamic cast between two script classes
 template <class T, class U> U* RefCast(T* t)

+ 0 - 1
Engine/Graphics/AnimatedModel.h

@@ -24,7 +24,6 @@
 #pragma once
 
 #include "Model.h"
-#include "Set.h"
 #include "Skeleton.h"
 #include "StaticModel.h"
 

+ 1 - 1
Engine/Graphics/Drawable.cpp

@@ -209,7 +209,7 @@ void Drawable::AddLight(Light* light)
 
 void Drawable::LimitLights()
 {
-    Set<Light*> uniqueLights;
+    HashSet<Light*> uniqueLights;
     
     const Vector3& worldPos = GetWorldPosition();
     for (unsigned i = 0; i < lights_.Size(); ++i)

+ 2 - 2
Engine/Graphics/Octree.cpp

@@ -330,7 +330,7 @@ void Octree::Update(const FrameInfo& frame)
         PROFILE(UpdateDrawables);
         
         // Let drawables update themselves before reinsertion
-        for (Set<Drawable*>::Iterator i = drawableUpdates_.Begin(); i != drawableUpdates_.End(); ++i)
+        for (HashSet<Drawable*>::Iterator i = drawableUpdates_.Begin(); i != drawableUpdates_.End(); ++i)
             (*i)->Update(frame);
     }
     
@@ -338,7 +338,7 @@ void Octree::Update(const FrameInfo& frame)
         PROFILE(ReinsertDrawables);
         
         // Reinsert drawables into the octree
-        for (Set<Drawable*>::Iterator i = drawableReinsertions_.Begin(); i != drawableReinsertions_.End(); ++i)
+        for (HashSet<Drawable*>::Iterator i = drawableReinsertions_.Begin(); i != drawableReinsertions_.End(); ++i)
         {
             Drawable* drawable = *i;
             Octant* octant = drawable->GetOctant();

+ 3 - 3
Engine/Graphics/Octree.h

@@ -24,7 +24,7 @@
 #pragma once
 
 #include "Drawable.h"
-#include "Set.h"
+#include "HashSet.h"
 
 class Drawable;
 class Octree;
@@ -186,9 +186,9 @@ public:
     
 private:
     /// Set of drawable objects that require update
-    Set<Drawable*> drawableUpdates_;
+    HashSet<Drawable*> drawableUpdates_;
     /// Set of drawable objects that require reinsertion
-    Set<Drawable*> drawableReinsertions_;
+    HashSet<Drawable*> drawableReinsertions_;
     /// Subdivision level
     unsigned numLevels_;
 };

+ 1 - 0
Engine/Graphics/Precompiled.h

@@ -23,6 +23,7 @@
 
 #pragma once
 
+#include "HashSet.h"
 #include "Map.h"
 #include "Set.h"
 #include "Sort.h"

+ 2 - 2
Engine/Graphics/Renderer.cpp

@@ -637,8 +637,8 @@ void Renderer::DrawDebugGeometry(bool depthTest)
     PROFILE(RendererDrawDebug);
     
     /// \todo Because debug geometry is per-scene, if two cameras show views of the same area, occlusion is not shown correctly
-    Set<Drawable*> processedGeometries;
-    Set<Light*> processedLights;
+    HashSet<Drawable*> processedGeometries;
+    HashSet<Light*> processedLights;
     
     for (unsigned i = 0; i < numViews_; ++i)
     {

+ 3 - 3
Engine/Graphics/Renderer.h

@@ -26,8 +26,8 @@
 #include "Batch.h"
 #include "Color.h"
 #include "Drawable.h"
+#include "HashSet.h"
 #include "RenderSurface.h"
-#include "Set.h"
 
 class DebugRenderer;
 class Geometry;
@@ -354,9 +354,9 @@ private:
     /// Views
     Vector<SharedPtr<View> > views_;
     /// Octrees that have been updated during the frame
-    Set<Octree*> updateOctrees_;
+    HashSet<Octree*> updateOctrees_;
     /// Techniques for which missing shader error has been displayed
-    Set<Technique*> shaderErrorDisplayed_;
+    HashSet<Technique*> shaderErrorDisplayed_;
     /// Vertex shader format
     String vsFormat_;
     /// Pixel shader format

+ 6 - 6
Engine/Graphics/View.cpp

@@ -382,8 +382,8 @@ void View::GetDrawables()
 
 void View::GetBatches()
 {
-    Set<LitTransparencyCheck> litTransparencies;
-    Set<Drawable*> maxLightsDrawables;
+    HashSet<LitTransparencyCheck> litTransparencies;
+    HashSet<Drawable*> maxLightsDrawables;
     Map<Light*, unsigned> lightQueueIndex;
     
     PassType gBufferPass = PASS_DEFERRED;
@@ -518,7 +518,7 @@ void View::GetBatches()
     {
         PROFILE(GetMaxLightsBatches);
         
-        for (Set<Drawable*>::Iterator i = maxLightsDrawables.Begin(); i != maxLightsDrawables.End(); ++i)
+        for (HashSet<Drawable*>::Iterator i = maxLightsDrawables.Begin(); i != maxLightsDrawables.End(); ++i)
         {
             Drawable* drawable = *i;
             drawable->LimitLights();
@@ -632,7 +632,7 @@ void View::GetBatches()
 }
 
 void View::GetLitBatches(Drawable* drawable, Light* light, Light* SplitLight, LightBatchQueue* lightQueue,
-    Set<LitTransparencyCheck>& litTransparencies, PassType gBufferPass)
+    HashSet<LitTransparencyCheck>& litTransparencies, PassType gBufferPass)
 {
     bool splitPointLight = SplitLight->GetLightType() == LIGHT_SPLITPOINT;
     // Whether to allow shadows for transparencies, or for forward lit objects in deferred mode
@@ -1363,7 +1363,7 @@ unsigned View::ProcessLight(Light* light)
         if (numSplits > 1)
         {
             // Make sure there are no duplicates
-            Set<Drawable*> allLitGeometries;
+            HashSet<Drawable*> allLitGeometries;
             for (unsigned i = 0; i < numSplits; ++i)
             {
                 for (Vector<Drawable*>::Iterator j = litGeometries_[i].Begin(); j != litGeometries_[i].End(); ++j)
@@ -1372,7 +1372,7 @@ unsigned View::ProcessLight(Light* light)
             
             litGeometries_[0].Resize(allLitGeometries.Size());
             unsigned index = 0;
-            for (Set<Drawable*>::Iterator i = allLitGeometries.Begin(); i != allLitGeometries.End(); ++i)
+            for (HashSet<Drawable*>::Iterator i = allLitGeometries.Begin(); i != allLitGeometries.End(); ++i)
                 litGeometries_[0][index++] = *i;
         }
         

+ 4 - 29
Engine/Graphics/View.h

@@ -24,6 +24,7 @@
 #pragma once
 
 #include "Batch.h"
+#include "HashSet.h"
 #include "Object.h"
 
 class Camera;
@@ -64,34 +65,8 @@ struct LitTransparencyCheck
     bool operator == (const LitTransparencyCheck& rhs) const { return (light_ == rhs.light_) && (drawable_ == rhs.drawable_) && (batchIndex_ == rhs.batchIndex_); }
     /// Test for inequality with another lit transparency check
     bool operator != (const LitTransparencyCheck& rhs) const { return (light_ != rhs.light_) || (drawable_ != rhs.drawable_) || (batchIndex_ != rhs.batchIndex_); }
-    
-    /// Test if less than another lit transparency check
-    bool operator < (const LitTransparencyCheck& rhs) const
-    {
-        if (light_ == rhs.light_)
-        {
-            if (drawable_ == rhs.drawable_)
-                return batchIndex_ < rhs.batchIndex_;
-            else
-                return drawable_ < rhs.drawable_;
-        }
-        else
-            return light_ < rhs.light_;
-    }
-    
-    /// Test if greater than another lit transparency check
-    bool operator > (const LitTransparencyCheck& rhs) const
-    {
-        if (light_ == rhs.light_)
-        {
-            if (drawable_ == rhs.drawable_)
-                return batchIndex_ > rhs.batchIndex_;
-            else
-                return drawable_ > rhs.drawable_;
-        }
-        else
-            return light_ > rhs.light_;
-    }
+    /// Return hash value for HashSet & HashMap
+    unsigned ToHash() const { return (unsigned)light_ + (unsigned)drawable_ + batchIndex_; }
     
     Light* light_;
     Drawable* drawable_;
@@ -143,7 +118,7 @@ private:
     /// Construct batches from the scene nodes
     void GetBatches();
     /// Get lit batches for a certain light and drawable
-    void GetLitBatches(Drawable* drawable, Light* light, Light* SplitLight, LightBatchQueue* lightQueue, Set<LitTransparencyCheck>& litTransparencies, PassType gBufferPass);
+    void GetLitBatches(Drawable* drawable, Light* light, Light* SplitLight, LightBatchQueue* lightQueue, HashSet<LitTransparencyCheck>& litTransparencies, PassType gBufferPass);
     /// Render batches, forward mode
     void RenderBatcheforward();
     /// Render batches, deferred mode

+ 1 - 1
Tools/AssetImporter/AssetImporter.cpp

@@ -45,13 +45,13 @@
 #include "Zone.h"
 
 #include "Sort.h"
-#include <cstring>
 #include "Map.h"
 #include "Set.h"
 
 #include <assimp.hpp>
 #include <aiScene.h>
 #include <aiPostProcess.h>
+#include <cstring>
 
 #include "DebugNew.h"