Browse Source

Tidied up Container code.
Added more asserts to shared/weak pointers.
Store per-object event handlers into a linked list instead of a map.

Lasse Öörni 13 years ago
parent
commit
54c7de95d8

+ 39 - 10
Engine/Container/ArrayPtr.h

@@ -45,7 +45,10 @@ public:
         refCount_(rhs.refCount_)
     {
         if (refCount_)
+        {
+            assert(refCount_->refs_ >= 0);
             ++(refCount_->refs_);
+        }
     }
     
     /// Construct from a raw pointer.
@@ -73,7 +76,10 @@ public:
         ptr_ = rhs.ptr_;
         refCount_ = rhs.refCount_;
         if (refCount_)
+        {
+            assert(refCount_->refs_ >= 0);
             ++(refCount_->refs_);
+        }
         
         return *this;
     }
@@ -137,7 +143,10 @@ public:
         {
             refCount_ = rhs.RefCountPtr();
             if (refCount_)
+            {
+                assert(refCount_->refs_ >= 0);
                 ++(refCount_->refs_);
+            }
         }
         else
             refCount_ = 0;
@@ -150,9 +159,9 @@ public:
     /// Return the raw pointer.
     T* Get() const { return ptr_; }
     /// Return the array's reference count, or 0 if the pointer is null.
-    unsigned Refs() const { return refCount_ ? refCount_->refs_ : 0; }
+    int Refs() const { return refCount_ ? refCount_->refs_ : 0; }
     /// Return the array's weak reference count, or 0 if the pointer is null.
-    unsigned WeakRefs() const { return refCount_ ? refCount_->weakRefs_ : 0; }
+    int WeakRefs() const { return refCount_ ? refCount_->weakRefs_ : 0; }
     /// Return pointer to the RefCount structure.
     RefCount* RefCountPtr() const { return refCount_; }
     /// Return hash value for HashSet & HashMap.
@@ -169,15 +178,16 @@ private:
         {
             if (refCount_->refs_)
             {
+                assert(refCount_->refs_ > 0);
                 --(refCount_->refs_);
                 if (!refCount_->refs_)
                 {
-                    refCount_->expired_ = true;
+                    refCount_->refs_ = -1;
                     delete[] ptr_;
                 }
             }
             
-            if (!refCount_->refs_ && !refCount_->weakRefs_)
+            if (refCount_->refs_ < 0 && !refCount_->weakRefs_)
                 delete refCount_;
         }
         
@@ -224,7 +234,10 @@ public:
         refCount_(rhs.RefCountPtr())
     {
         if (refCount_)
+        {
+            assert(refCount_->weakRefs_ >= 0);
             ++(refCount_->weakRefs_);
+        }
     }
     
     /// Copy-construct from another weak array pointer.
@@ -233,7 +246,10 @@ public:
         refCount_(rhs.refCount_)
     {
         if (refCount_)
+        {
+            assert(refCount_->weakRefs_ >= 0);
             ++(refCount_->weakRefs_);
+        }
     }
     
     /// Destruct. Release the weak reference to the array.
@@ -253,8 +269,10 @@ public:
         ptr_ = rhs.Get();
         refCount_ = rhs.RefCountPtr();
         if (refCount_)
+        {
+            assert(refCount_->weakRefs_ >= 0);
             ++(refCount_->weakRefs_);
-        
+        }
         return *this;
     }
     
@@ -269,7 +287,10 @@ public:
         ptr_ = rhs.ptr_;
         refCount_ = rhs.refCount_;
         if (refCount_)
+        {
+            assert(refCount_->weakRefs_ >= 0);
             ++(refCount_->weakRefs_);
+        }
         
         return *this;
     }
@@ -338,7 +359,10 @@ public:
         ptr_ = static_cast<T*>(rhs.Get());
         refCount_ = rhs.refCount_;
         if (refCount_)
+        {
+            assert(refCount_->weakRefs_ >= 0);
             ++(refCount_->weakRefs_);
+        }
     }
     
     /// Perform a dynamic cast from a weak array pointer of another type.
@@ -351,7 +375,10 @@ public:
         {
             refCount_ = rhs.refCount_;
             if (refCount_)
+            {
+                assert(refCount_->weakRefs_ >= 0);
                 ++(refCount_->weakRefs_);
+            }
         }
         else
             refCount_ = 0;
@@ -362,11 +389,11 @@ public:
     /// Check if the pointer is not null.
     bool NotNull() const { return refCount_ != 0; }
     /// Return the array's reference count, or 0 if null pointer or if array is expired.
-    unsigned Refs() const { return refCount_ ? refCount_->refs_ : 0; }
+    int Refs() const { return refCount_ ? refCount_->refs_ : 0; }
     /// Return the array's weak reference count.
-    unsigned WeakRefs() const { return refCount_ ? refCount_->weakRefs_ : 0; }
+    int WeakRefs() const { return refCount_ ? refCount_->weakRefs_ : 0; }
     /// Return whether the array has expired. If null pointer, always return true.
-    bool Expired() const { return refCount_ ? refCount_->expired_ : true; }
+    bool Expired() const { return refCount_ ? refCount_->refs_ < 0 : true; }
     /// Return pointer to RefCount structure.
     RefCount* RefCountPtr() const { return refCount_; }
     /// Return hash value for HashSet & HashMap.
@@ -381,10 +408,12 @@ private:
     {
         if (refCount_)
         {
-            if (refCount_->weakRefs_)
+            assert(refCount_->weakRefs_ >= 0);
+            
+            if (refCount_->weakRefs_ > 0)
                 --(refCount_->weakRefs_);
             
-            if (!refCount_->refs_ && !refCount_->weakRefs_)
+            if (Expired() && !refCount_->weakRefs_)
                 delete refCount_;
         }
         

+ 6 - 7
Engine/Container/HashBase.h

@@ -27,7 +27,7 @@
 #include "Hash.h"
 #include "Swap.h"
 
-/// Hash set/map node base.
+/// Hash set/map node base class.
 struct HashNodeBase
 {
     /// Construct.
@@ -47,9 +47,8 @@ struct HashNodeBase
 };
 
 /// Hash set/map iterator base class.
-class HashIteratorBase
+struct HashIteratorBase
 {
-public:
     /// Construct.
     HashIteratorBase() :
         ptr_(0)
@@ -61,26 +60,26 @@ public:
         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_;
 };

+ 2 - 4
Engine/Container/HashMap.h

@@ -84,9 +84,8 @@ public:
     };
     
     /// Hash map node iterator.
-    class Iterator : public HashIteratorBase
+    struct Iterator : public HashIteratorBase
     {
-    public:
         /// Construct.
         Iterator()
         {
@@ -114,9 +113,8 @@ public:
     };
     
     /// Hash map node const iterator.
-    class ConstIterator : public HashIteratorBase
+    struct ConstIterator : public HashIteratorBase
     {
-    public:
         /// Construct.
         ConstIterator()
         {

+ 2 - 4
Engine/Container/HashSet.h

@@ -55,9 +55,8 @@ public:
     };
     
     /// Hash set node iterator.
-    class Iterator : public HashIteratorBase
+    struct Iterator : public HashIteratorBase
     {
-    public:
         /// Construct.
         Iterator()
         {
@@ -85,9 +84,8 @@ public:
     };
     
     /// Hash set node const iterator.
-    class ConstIterator : public HashIteratorBase
+    struct ConstIterator : public HashIteratorBase
     {
-    public:
         /// Construct.
         ConstIterator()
         {

+ 167 - 0
Engine/Container/LinkedList.h

@@ -0,0 +1,167 @@
+//
+// Urho3D Engine
+// Copyright (c) 2008-2012 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
+
+/// Singly-linked list node base class.
+struct LinkedListNode
+{
+    /// Construct.
+    LinkedListNode() :
+        next_(0)
+    {
+    }
+    
+    /// Pointer to next node.
+    LinkedListNode* next_;
+};
+
+/// Singly-linked list template class. Elements must inherit from LinkedListNode.
+template <class T> class LinkedList
+{
+public:
+    /// Construct empty.
+    LinkedList() :
+        head_(0)
+    {
+    }
+    
+    /// Destruct.
+    ~LinkedList()
+    {
+        Clear();
+    }
+    
+    /// Remove all elements.
+    void Clear()
+    {
+        T* element = head_;
+        while (element)
+        {
+            T* next = Next(element);
+            delete element;
+            element = next;
+        }
+    }
+    
+    /// Insert an element at the beginning.
+    void InsertFront(T* element)
+    {
+        if (element)
+        {
+            element->next_ = head_;
+            head_ = element;
+        }
+    }
+    
+    /// Insert an element at the end.
+    void Insert(T* element)
+    {
+        if (head_)
+        {
+            T* tail = Last();
+            element->next_ = tail->next_;
+            tail->next_ = element;
+        }
+        else
+        {
+            element->next_ = head_;
+            head_ = element;
+        }
+    }
+    
+    /// Erase an element. Return true if successful.
+    bool Erase(T* element)
+    {
+        if (element && head_)
+        {
+            if (element == head_)
+            {
+                head_ = Next(element);
+                delete element;
+                return true;
+            }
+            else
+            {
+                T* tail = head_;
+                while (tail && tail->next_ != element)
+                    tail = Next(tail);
+                if (tail)
+                {
+                    tail->next_ = element->next_;
+                    delete element;
+                    return true;
+                }
+            }
+        }
+        
+        return false;
+    }
+    
+    /// Erase an element when the previous element is known (optimization.) Return true if successful.
+    bool Erase(T* element, T* previous)
+    {
+        if (previous && previous->next_ == element)
+        {
+            previous->next_ = element->next_;
+            delete element;
+            return true;
+        }
+        else if (!previous)
+        {
+            if (head_ == element)
+            {
+                head_ = Next(element);
+                delete element;
+                return true;
+            }
+        }
+        
+        return false;
+    }
+    
+    /// Return first element, or null if empty.
+    T* First() const { return head_; }
+    
+    /// Return last element, or null if empty.
+    T* Last() const
+    {
+        T* element = head_;
+        if (element)
+        {
+            while (element->next_)
+                element = Next(element);
+        }
+        return element;
+    }
+    
+    /// Return next element, or null if no more elements.
+    T* Next(T* element) const { return element ? static_cast<T*>(element->next_) : 0; }
+    
+    /// Return whether is empty.
+    bool Empty() const { return head_ == 0; }
+    
+private:
+    /// First element.
+    T* head_;
+};

+ 3 - 5
Engine/Container/List.h

@@ -25,7 +25,7 @@
 
 #include "ListBase.h"
 
-/// Linked list template class.
+/// Doubly-linked list template class.
 template <class T> class List : public ListBase
 {
 public:
@@ -53,9 +53,8 @@ public:
     };
     
     /// %List iterator.
-    class Iterator : public ListIteratorBase
+    struct Iterator : public ListIteratorBase
     {
-    public:
         /// Construct.
         Iterator()
         {
@@ -83,9 +82,8 @@ public:
     };
     
     /// %List const iterator.
-    class ConstIterator : public ListIteratorBase
+    struct ConstIterator : public ListIteratorBase
     {
-    public:
         /// Construct.
         ConstIterator()
         {

+ 4 - 5
Engine/Container/ListBase.h

@@ -26,7 +26,7 @@
 #include "Allocator.h"
 #include "Swap.h"
 
-/// %List node base.
+/// Doubly-linked list node base class.
 struct ListNodeBase
 {
     /// Construct.
@@ -42,10 +42,9 @@ struct ListNodeBase
     ListNodeBase* next_;
 };
 
-/// %List iterator base class.
-class ListIteratorBase
+/// Doubly-linked list iterator base class.
+struct ListIteratorBase
 {
-public:
     /// Construct.
     ListIteratorBase() :
         ptr_(0)
@@ -81,7 +80,7 @@ public:
     ListNodeBase* ptr_;
 };
 
-/// Linked list base class.
+/// Doubly-linked list base class.
 class ListBase
 {
 public:

+ 2 - 4
Engine/Container/Map.h

@@ -85,9 +85,8 @@ public:
     };
     
     /// %Map iterator.
-    class Iterator : public TreeIteratorBase
+    struct Iterator : public TreeIteratorBase
     {
-    public:
         /// Construct.
         Iterator()
         {
@@ -115,9 +114,8 @@ public:
     };
     
     /// %Map const iterator.
-    class ConstIterator : public TreeIteratorBase
+    struct ConstIterator : public TreeIteratorBase
     {
-    public:
         /// Construct.
         ConstIterator()
         {

+ 32 - 8
Engine/Container/Ptr.h

@@ -136,9 +136,9 @@ public:
     /// Return the raw pointer.
     T* Get() const { return ptr_; }
     /// Return the object's reference count, or 0 if the pointer is null.
-    unsigned Refs() const { return ptr_ ? ptr_->Refs() : 0; }
+    int Refs() const { return ptr_ ? ptr_->Refs() : 0; }
     /// Return the object's weak reference count, or 0 if the pointer is null.
-    unsigned WeakRefs() const { return ptr_ ? ptr_->WeakRefs() : 0; }
+    int WeakRefs() const { return ptr_ ? ptr_->WeakRefs() : 0; }
     /// Return pointer to the RefCount structure.
     RefCount* RefCountPtr() const { return ptr_ ? ptr_->RefCountPtr() : 0; }
     /// Return hash value for HashSet & HashMap.
@@ -195,7 +195,10 @@ public:
         refCount_(rhs.RefCountPtr())
     {
         if (refCount_)
+        {
+            assert(refCount_->weakRefs_ >= 0);
             ++(refCount_->weakRefs_);
+        }
     }
     
     /// Copy-construct from another weak pointer.
@@ -204,7 +207,10 @@ public:
         refCount_(rhs.refCount_)
     {
         if (refCount_)
+        {
+            assert(refCount_->weakRefs_ >= 0);
             ++(refCount_->weakRefs_);
+        }
     }
     
     /// Construct from a raw pointer.
@@ -213,7 +219,10 @@ public:
         refCount_(ptr ? ptr->RefCountPtr() : 0)
     {
         if (refCount_)
+        {
+            assert(refCount_->weakRefs_ >= 0);
             ++(refCount_->weakRefs_);
+        }
     }
     
     /// Destruct. Release the weak reference to the object.
@@ -233,7 +242,10 @@ public:
         ptr_ = rhs.Get();
         refCount_ = rhs.RefCountPtr();
         if (refCount_)
+        {
+            assert(refCount_->weakRefs_ >= 0);
             ++(refCount_->weakRefs_);
+        }
         
         return *this;
     }
@@ -249,7 +261,10 @@ public:
         ptr_ = rhs.ptr_;
         refCount_ = rhs.refCount_;
         if (refCount_)
+        {
+            assert(refCount_->weakRefs_ >= 0);
             ++(refCount_->weakRefs_);
+        }
         
         return *this;
     }
@@ -267,7 +282,10 @@ public:
         ptr_ = ptr;
         refCount_ = refCount;
         if (refCount_)
+        {
+            assert(refCount_->weakRefs_ >= 0);
             ++(refCount_->weakRefs_);
+        }
         
         return *this;
     }
@@ -336,7 +354,10 @@ public:
         ptr_ = static_cast<T*>(rhs.Get());
         refCount_ = rhs.refCount_;
         if (refCount_)
+        {
+            assert(refCount_->weakRefs_ >= 0);
             ++(refCount_->weakRefs_);
+        }
     }
     
     /// Perform a dynamic cast from a weak pointer of another type.
@@ -349,7 +370,10 @@ public:
         {
             refCount_ = rhs.refCount_;
             if (refCount_)
+            {
+                assert(refCount_->weakRefs_ >= 0);
                 ++(refCount_->weakRefs_);
+            }
         }
         else
             refCount_ = 0;
@@ -360,10 +384,10 @@ public:
     /// Check if the pointer is not null. It does not matter whether the object has expired or not.
     bool NotNull() const { return refCount_ != 0; }
     /// Return the object's reference count, or 0 if null pointer or if object is expired.
-    unsigned Refs() const { return refCount_ ? refCount_->refs_ : 0; }
+    int Refs() const { return refCount_ ? refCount_->refs_ : 0; }
     
     /// Return the object's weak reference count.
-    unsigned WeakRefs() const
+    int WeakRefs() const
     {
         if (!Expired())
             return ptr_->WeakRefs();
@@ -372,7 +396,7 @@ public:
     }
     
     /// Return whether the object has expired. If null pointer, always return true.
-    bool Expired() const { return refCount_ ? refCount_->expired_ : true; }
+    bool Expired() const { return refCount_ ? refCount_->refs_ < 0 : true; }
     /// Return pointer to the RefCount structure.
     RefCount* RefCountPtr() const { return refCount_; }
     /// Return hash value for HashSet & HashMap.
@@ -387,10 +411,10 @@ private:
     {
         if (refCount_)
         {
-            if (refCount_->weakRefs_)
-                --(refCount_->weakRefs_);
+            assert(refCount_->weakRefs_ > 0);
+            --(refCount_->weakRefs_);
             
-            if (!refCount_->refs_ && !refCount_->weakRefs_)
+            if (Expired() && !refCount_->weakRefs_)
                 delete refCount_;
         }
         

+ 5 - 4
Engine/Container/RefCounted.cpp

@@ -36,9 +36,10 @@ RefCounted::~RefCounted()
 {
     assert(refCount_);
     assert(refCount_->refs_ == 0);
+    assert(refCount_->weakRefs_ > 0);
     
     // Mark object as expired, release the self weak ref and delete the refcount if no other weak refs exist
-    refCount_->expired_ = true;
+    refCount_->refs_ = -1;
     --(refCount_->weakRefs_);
     if (!refCount_->weakRefs_)
         delete refCount_;
@@ -48,24 +49,24 @@ RefCounted::~RefCounted()
 
 void RefCounted::AddRef()
 {
+    assert(refCount_->refs_ >= 0);
     ++(refCount_->refs_);
 }
 
 void RefCounted::ReleaseRef()
 {
     assert(refCount_->refs_ > 0);
-    
     --(refCount_->refs_);
     if (!refCount_->refs_)
         delete this;
 }
 
-unsigned RefCounted::Refs() const
+int RefCounted::Refs() const
 {
     return refCount_->refs_;
 }
 
-unsigned RefCounted::WeakRefs() const
+int RefCounted::WeakRefs() const
 {
     // Subtract one to not return the internally held reference
     return refCount_->weakRefs_ - 1;

+ 14 - 9
Engine/Container/RefCounted.h

@@ -29,17 +29,22 @@ struct RefCount
     /// Construct.
     RefCount() :
         refs_(0),
-        weakRefs_(0),
-        expired_(false)
+        weakRefs_(0)
     {
     }
     
-    /// Reference count.
-    unsigned refs_;
+    /// Destruct.
+    ~RefCount()
+    {
+        // Set reference counts below zero to fire asserts if this object is still accessed
+        refs_ = -1;
+        weakRefs_ = -1;
+    }
+    
+    /// Reference count. If below zero, the object has been destroyed.
+    int refs_;
     /// Weak reference count.
-    unsigned weakRefs_;
-    /// Expired status for the object.
-    bool expired_;
+    int weakRefs_;
 };
 
 /// Base class for intrusively reference-counted objects. These are noncopyable and non-assignable.
@@ -56,9 +61,9 @@ public:
     /// Decrement reference count and delete self if no more references. Can also be called outside of a SharedPtr for traditional reference counting.
     void ReleaseRef();
     /// Return reference count.
-    unsigned Refs() const;
+    int Refs() const;
     /// Return weak reference count.
-    unsigned WeakRefs() const;
+    int WeakRefs() const;
     /// Return pointer to the reference count structure.
     RefCount* RefCountPtr() { return refCount_; }
     

+ 2 - 4
Engine/Container/Set.h

@@ -56,9 +56,8 @@ public:
     };
     
     /// %Set iterator.
-    class Iterator : public TreeIteratorBase
+    struct Iterator : public TreeIteratorBase
     {
-    public:
         /// Construct.
         Iterator()
         {
@@ -86,9 +85,8 @@ public:
     };
     
     /// %Set const iterator.
-    class ConstIterator : public TreeIteratorBase
+    struct ConstIterator : public TreeIteratorBase
     {
-    public:
         /// Construct.
         ConstIterator()
         {

+ 2 - 3
Engine/Container/TreeBase.h

@@ -29,7 +29,7 @@
 // Based on Red Black Trees by Julienne Walker
 // http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx
 
-/// Red-black tree node base.
+/// Red-black tree node base class.
 struct TreeNodeBase
 {
     /// Construct.
@@ -58,9 +58,8 @@ struct TreeNodeBase
 };
 
 /// Red-black tree iterator base class.
-class TreeIteratorBase
+struct TreeIteratorBase
 {
-public:
     /// Construct.
     TreeIteratorBase() :
         ptr_(0),

+ 2 - 4
Engine/Container/VectorBase.h

@@ -26,9 +26,8 @@
 #include "Swap.h"
 
 /// Random access iterator.
-template <class T> class RandomAccessIterator
+template <class T> struct RandomAccessIterator
 {
-public:
     /// Construct.
     RandomAccessIterator() :
         ptr_(0)
@@ -81,9 +80,8 @@ public:
 };
 
 /// Random access const iterator.
-template <class T> class RandomAccessConstIterator
+template <class T> struct RandomAccessConstIterator
 {
-public:
     /// Construct.
     RandomAccessConstIterator() :
         ptr_(0)

+ 2 - 1
Engine/Core/Context.h

@@ -25,6 +25,7 @@
 
 #include "Attribute.h"
 #include "Object.h"
+#include "HashMap.h"
 #include "HashSet.h"
 
 /// Urho3D execution context. Provides access to subsystems, object factories and attributes, and event receivers.
@@ -141,7 +142,7 @@ private:
     /// Event sender stack.
     PODVector<Object*> eventSenders_;
     /// Active event handler. Not stored in a stack for performance reasons; is needed only in esoteric cases.
-    WeakPtr<EventHandler> eventHandler_;
+    EventHandler* eventHandler_;
 };
 
 template <class T> void Context::RegisterFactory() { RegisterFactory(new ObjectFactoryImpl<T>(this)); }

+ 168 - 57
Engine/Core/Object.cpp

@@ -42,24 +42,38 @@ void Object::OnEvent(Object* sender, bool broadcast, StringHash eventType, Varia
 {
     // Make a copy of the context pointer in case the object is destroyed during event handler invocation
     Context* context = context_;
+    EventHandler* specific = 0;
+    EventHandler* nonSpecific = 0;
     
-    // Check first the specific event handlers, which have priority
-    Map<Pair<Object*, StringHash>, SharedPtr<EventHandler> >::ConstIterator i = eventHandlers_.Find(
-        MakePair(sender, eventType));
-    if (i != eventHandlers_.End())
+    EventHandler* handler = eventHandlers_.First();
+    while (handler)
     {
-        context->SetEventHandler(i->second_);
-        i->second_->Invoke(eventType, eventData);
+        if (handler->GetEventType() == eventType)
+        {
+            if (!handler->GetSender())
+                nonSpecific = handler;
+            else if (handler->GetSender() == sender)
+            {
+                specific = handler;
+                break;
+            }
+        }
+        handler = eventHandlers_.Next(handler);
+    }
+    
+    // Specific event handlers have priority, so if found, invoke first
+    if (specific)
+    {
+        context->SetEventHandler(specific);
+        specific->Invoke(eventData);
         context->SetEventHandler(0);
         return;
     }
     
-    // Then check non-specific (null sender pointer)
-    i = eventHandlers_.Find(MakePair((Object*)0, eventType));
-    if (i != eventHandlers_.End())
+    if (nonSpecific)
     {
-        context->SetEventHandler(i->second_);
-        i->second_->Invoke(eventType, eventData);
+        context->SetEventHandler(nonSpecific);
+        nonSpecific->Invoke(eventData);
         context->SetEventHandler(0);
     }
 }
@@ -69,9 +83,15 @@ void Object::SubscribeToEvent(StringHash eventType, EventHandler* handler)
     if (!handler)
         return;
     
-    Pair<Object*, StringHash> combination((Object*)0, eventType);
+    handler->SetSenderAndEventType(0, eventType);
+    // Remove old event handler first
+    EventHandler* previous;
+    EventHandler* oldHandler = FindSpecificEventHandler(0, eventType, &previous);
+    if (oldHandler)
+        eventHandlers_.Erase(oldHandler, previous);
+    
+    eventHandlers_.InsertFront(handler);
     
-    eventHandlers_[combination] = handler;
     context_->AddEventReceiver(this, eventType);
 }
 
@@ -80,38 +100,48 @@ void Object::SubscribeToEvent(Object* sender, StringHash eventType, EventHandler
     if (!sender || !handler)
         return;
     
-    Pair<Object*, StringHash> combination(sender, eventType);
+    handler->SetSenderAndEventType(sender, eventType);
+    // Remove old event handler first
+    EventHandler* previous;
+    EventHandler* oldHandler = FindSpecificEventHandler(sender, eventType, &previous);
+    if (oldHandler)
+        eventHandlers_.Erase(oldHandler, previous);
+    
+    eventHandlers_.InsertFront(handler);
     
-    eventHandlers_[combination] = handler;
     context_->AddEventReceiver(this, sender, eventType);
 }
 
 void Object::UnsubscribeFromEvent(StringHash eventType)
 {
-    for (Map<Pair<Object*, StringHash>, SharedPtr<EventHandler> >::Iterator i = eventHandlers_.Begin();
-        i != eventHandlers_.End();)
+    for (;;)
     {
-        Map<Pair<Object*, StringHash>, SharedPtr<EventHandler> >::Iterator current = i++;
-        if (current->first_.second_ == eventType)
+        EventHandler* previous;
+        EventHandler* handler = FindEventHandler(eventType, &previous);
+        if (handler)
         {
-            if (current->first_.first_)
-                context_->RemoveEventReceiver(this, current->first_.first_, current->first_.second_);
+            if (handler->GetSender())
+                context_->RemoveEventReceiver(this, handler->GetSender(), eventType);
             else
-                context_->RemoveEventReceiver(this, current->first_.second_);
-            eventHandlers_.Erase(current);
+                context_->RemoveEventReceiver(this, eventType);
+            eventHandlers_.Erase(handler, previous);
         }
+        else
+            break;
     }
 }
 
 void Object::UnsubscribeFromEvent(Object* sender, StringHash eventType)
 {
-    Pair<Object*, StringHash> combination(sender, eventType);
+    if (!sender)
+        return;
     
-    Map<Pair<Object*, StringHash>, SharedPtr<EventHandler> >::Iterator i = eventHandlers_.Find(combination);
-    if (i != eventHandlers_.End())
+    EventHandler* previous;
+    EventHandler* handler = FindSpecificEventHandler(sender, eventType, &previous);
+    if (handler)
     {
-        context_->RemoveEventReceiver(this, i->first_.first_, i->first_.second_);
-        eventHandlers_.Erase(i);
+        context_->RemoveEventReceiver(this, handler->GetSender(), eventType);
+        eventHandlers_.Erase(handler, previous);
     }
 }
 
@@ -120,48 +150,61 @@ void Object::UnsubscribeFromEvents(Object* sender)
     if (!sender)
         return;
     
-    for (Map<Pair<Object*, StringHash>, SharedPtr<EventHandler> >::Iterator i = eventHandlers_.Begin();
-        i != eventHandlers_.End();)
+    for (;;)
     {
-        Map<Pair<Object*, StringHash>, SharedPtr<EventHandler> >::Iterator current = i++;
-        if (current->first_.first_ == sender)
+        EventHandler* previous;
+        EventHandler* handler = FindSpecificEventHandler(sender, &previous);
+        if (handler)
         {
-            context_->RemoveEventReceiver(this, current->first_.first_, current->first_.second_);
-            eventHandlers_.Erase(current);
+            context_->RemoveEventReceiver(this, handler->GetSender(), handler->GetEventType());
+            eventHandlers_.Erase(handler, previous);
         }
+        else
+            break;
     }
 }
 
 void Object::UnsubscribeFromAllEvents()
 {
-    for (Map<Pair<Object*, StringHash>, SharedPtr<EventHandler> >::Iterator i = eventHandlers_.Begin();
-        i != eventHandlers_.End(); ++i)
+    for (;;)
     {
-        if (i->first_.first_)
-            context_->RemoveEventReceiver(this, i->first_.first_, i->first_.second_);
+        EventHandler* handler = eventHandlers_.First();
+        if (handler)
+        {
+            if (handler->GetSender())
+                context_->RemoveEventReceiver(this, handler->GetSender(), handler->GetEventType());
+            else
+                context_->RemoveEventReceiver(this, handler->GetEventType());
+            eventHandlers_.Erase(handler);
+        }
         else
-            context_->RemoveEventReceiver(this, i->first_.second_);
+            break;
     }
-    
-    eventHandlers_.Clear();
 }
 
 void Object::UnsubscribeFromAllEventsWithUserData()
 {
-    for (Map<Pair<Object*, StringHash>, SharedPtr<EventHandler> >::Iterator i = eventHandlers_.Begin();
-        i != eventHandlers_.End(); )
+    EventHandler* handler = eventHandlers_.First();
+    EventHandler* previous = 0;
+    
+    while (handler)
     {
-        if (i->second_->GetUserData())
+        if (handler->GetUserData())
         {
-            Map<Pair<Object*, StringHash>, SharedPtr<EventHandler> >::Iterator current = i++;
-            if (current->first_.first_)
-                context_->RemoveEventReceiver(this, current->first_.first_, current->first_.second_);
+            if (handler->GetSender())
+                context_->RemoveEventReceiver(this, handler->GetSender(), handler->GetEventType());
             else
-                context_->RemoveEventReceiver(this, current->first_.second_);
-            eventHandlers_.Erase(current);
+                context_->RemoveEventReceiver(this, handler->GetEventType());
+            
+            EventHandler* next = eventHandlers_.Next(handler);
+            eventHandlers_.Erase(handler, previous);
+            handler = next;
         }
         else
-            ++i;
+        {
+            previous = handler;
+            handler = eventHandlers_.Next(handler);
+        }
     }
 }
 
@@ -313,21 +356,89 @@ EventHandler* Object::GetEventHandler() const
 
 bool Object::HasSubscribedToEvent(StringHash eventType) const
 {
-    return eventHandlers_.Find(MakePair((Object*)0, eventType)) != eventHandlers_.End();
+    return FindEventHandler(eventType) != 0;
 }
 
 bool Object::HasSubscribedToEvent(Object* sender, StringHash eventType) const
 {
-    return eventHandlers_.Find(MakePair(sender, eventType)) != eventHandlers_.End();
+    if (!sender)
+        return false;
+    else
+        return FindSpecificEventHandler(sender, eventType) != 0;
+}
+
+EventHandler* Object::FindEventHandler(StringHash eventType, EventHandler** previous) const
+{
+    EventHandler* handler = eventHandlers_.First();
+    if (previous)
+        *previous = 0;
+    
+    while (handler)
+    {
+        if (handler->GetEventType() == eventType)
+            return handler;
+        if (previous)
+            *previous = handler;
+        handler = eventHandlers_.Next(handler);
+    }
+    
+    return 0;
+}
+
+EventHandler* Object::FindSpecificEventHandler(Object* sender, EventHandler** previous) const
+{
+    EventHandler* handler = eventHandlers_.First();
+    if (previous)
+        *previous = 0;
+    
+    while (handler)
+    {
+        if (handler->GetSender() == sender)
+            return handler;
+        if (previous)
+            *previous = handler;
+        handler = eventHandlers_.Next(handler);
+    }
+    
+    return 0;
+}
+
+EventHandler* Object::FindSpecificEventHandler(Object* sender, StringHash eventType, EventHandler** previous) const
+{
+    EventHandler* handler = eventHandlers_.First();
+    if (previous)
+        *previous = 0;
+    
+    while (handler)
+    {
+        if (handler->GetSender() == sender && handler->GetEventType() == eventType)
+            return handler;
+        if (previous)
+            *previous = handler;
+        handler = eventHandlers_.Next(handler);
+    }
+    
+    return 0;
 }
 
 void Object::RemoveEventSender(Object* sender)
 {
-    for (Map<Pair<Object*, StringHash>, SharedPtr<EventHandler> >::Iterator i = eventHandlers_.Begin();
-        i != eventHandlers_.End();)
+    EventHandler* handler = eventHandlers_.First();
+    EventHandler* previous = 0;
+    
+    while (handler)
     {
-        Map<Pair<Object*, StringHash>, SharedPtr<EventHandler> >::Iterator current = i++;
-        if (current->first_.first_ == sender)
-            eventHandlers_.Erase(current);
+        if (handler->GetSender() == sender)
+        {
+            context_->RemoveEventReceiver(this, handler->GetSender(), handler->GetEventType());
+            EventHandler* next = eventHandlers_.Next(handler);
+            eventHandlers_.Erase(handler, previous);
+            handler = next;
+        }
+        else
+        {
+            previous = handler;
+            handler = eventHandlers_.Next(handler);
+        }
     }
 }

+ 29 - 7
Engine/Core/Object.h

@@ -23,8 +23,7 @@
 
 #pragma once
 
-#include "HashMap.h"
-#include "Map.h"
+#include "LinkedList.h"
 #include "Ptr.h"
 #include "Variant.h"
 
@@ -92,11 +91,17 @@ protected:
     Context* context_;
     
 private:
+    /// Find the first event handler with no specific sender.
+    EventHandler* FindEventHandler(StringHash eventType, EventHandler** previous = 0) const;
+    /// Find the first event handler with specific sender.
+    EventHandler* FindSpecificEventHandler(Object* sender, EventHandler** previous = 0) const;
+    /// Find the first event handler with specific sender and event type.
+    EventHandler* FindSpecificEventHandler(Object* sender, StringHash eventType, EventHandler** previous = 0) const;
     /// Remove event handlers related to a specific sender.
     void RemoveEventSender(Object* sender);
     
     /// Event handlers. Sender is null for non-specific handlers.
-    Map<Pair<Object*, StringHash>, SharedPtr<EventHandler> > eventHandlers_;
+    LinkedList<EventHandler> eventHandlers_;
 };
 
 template <class T> T* Object::GetSubsystem() const { return static_cast<T*>(GetSubsystem(T::GetTypeStatic())); }
@@ -148,12 +153,13 @@ public:
 };
 
 /// Internal helper class for invoking event handler functions.
-class EventHandler : public RefCounted
+class EventHandler : public LinkedListNode
 {
 public:
     /// Construct with specified receiver.
     EventHandler(Object* receiver) :
         receiver_(receiver),
+        sender_(0),
         userData_(0)
     {
         assert(receiver_);
@@ -162,6 +168,7 @@ public:
     /// Construct with specified receiver and userdata.
     EventHandler(Object* receiver, void* userData) :
         receiver_(receiver),
+        sender_(0),
         userData_(userData)
     {
         assert(receiver_);
@@ -170,17 +177,32 @@ public:
     /// Destruct.
     virtual ~EventHandler() {}
     
+    /// Set sender and event type.
+    void SetSenderAndEventType(Object* sender, StringHash eventType)
+    {
+        sender_ = sender;
+        eventType_ = eventType;
+    }
+    
     /// Invoke event handler function.
-    virtual void Invoke(StringHash eventType, VariantMap& eventData) = 0;
+    virtual void Invoke(VariantMap& eventData) = 0;
     
     /// Return event receiver.
     Object* GetReceiver() const { return receiver_; }
+    /// Return event sender. Null if the handler is non-specific.
+    Object* GetSender() const { return sender_; }
+    /// Return event type.
+    const StringHash& GetEventType() const { return eventType_; }
     /// Return userdata.
     void* GetUserData() const { return userData_; }
     
 protected:
     /// Event receiver.
     Object* receiver_;
+    /// Event sender.
+    Object* sender_;
+    /// Event type.
+    StringHash eventType_;
     /// Userdata.
     void* userData_;
 };
@@ -208,10 +230,10 @@ public:
     }
     
     /// Invoke event handler function.
-    virtual void Invoke(StringHash eventType, VariantMap& eventData)
+    virtual void Invoke(VariantMap& eventData)
     {
         T* receiver = static_cast<T*>(receiver_);
-        (receiver->*function_)(eventType, eventData);
+        (receiver->*function_)(eventType_, eventData);
     }
     
 private:

+ 1 - 0
Engine/Graphics/Direct3D9/D3D9Graphics.h

@@ -24,6 +24,7 @@
 #pragma once
 
 #include "Color.h"
+#include "HashMap.h"
 #include "Object.h"
 #include "Rect.h"
 #include "GraphicsDefs.h"

+ 1 - 0
Engine/Graphics/Material.h

@@ -24,6 +24,7 @@
 #pragma once
 
 #include "GraphicsDefs.h"
+#include "HashMap.h"
 #include "Resource.h"
 #include "Vector4.h"
 

+ 1 - 0
Engine/Graphics/PostProcess.h

@@ -24,6 +24,7 @@
 #pragma once
 
 #include "GraphicsDefs.h"
+#include "HashMap.h"
 #include "Object.h"
 
 class Texture2D;

+ 1 - 0
Engine/IO/PackageFile.h

@@ -23,6 +23,7 @@
 
 #pragma once
 
+#include "HashMap.h"
 #include "Object.h"
 
 /// %File entry within the package file.

+ 2 - 0
Engine/Scene/Scene.h

@@ -23,6 +23,8 @@
 
 #pragma once
 
+#include "HashMap.h"
+#include "HashSet.h"
 #include "Mutex.h"
 #include "Node.h"
 #include "SceneResolver.h"

+ 1 - 0
Engine/UI/Font.h

@@ -24,6 +24,7 @@
 #pragma once
 
 #include "ArrayPtr.h"
+#include "HashMap.h"
 #include "Resource.h"
 
 class Graphics;