diff options
author | Richard Linden <none@none> | 2014-02-12 10:32:02 -0800 |
---|---|---|
committer | Richard Linden <none@none> | 2014-02-12 10:32:02 -0800 |
commit | 5866bb7ef09b786f8f195770a70dc4289d183ca0 (patch) | |
tree | 0be3b5e63506bf30edd3748f9e31740ae9ebbaa8 /indra/llcommon/llinstancetracker.h | |
parent | 413be91cf5044889ade97dcbec4b17fceff122e3 (diff) | |
parent | a8192fbf60540e42dcff5f1efb8bf8cafbfac484 (diff) |
merge with release
Diffstat (limited to 'indra/llcommon/llinstancetracker.h')
-rwxr-xr-x | indra/llcommon/llinstancetracker.h | 109 |
1 files changed, 71 insertions, 38 deletions
diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 55187d8325..9783644e66 100755 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -31,10 +31,7 @@ #include <map> #include <typeinfo> -#include "string_table.h" -#include <boost/utility.hpp> -#include <boost/function.hpp> -#include <boost/bind.hpp> +#include "llstringtable.h" #include <boost/iterator/transform_iterator.hpp> #include <boost/iterator/indirect_iterator.hpp> @@ -46,8 +43,6 @@ class LL_COMMON_API LLInstanceTrackerBase { protected: - - /// It's not essential to derive your STATICDATA (for use with /// getStatic()) from StaticBase; it's just that both known /// implementations do. @@ -56,31 +51,39 @@ protected: StaticBase(): sIterationNestDepth(0) {} - S32 sIterationNestDepth; + + void incrementDepth(); + void decrementDepth(); + U32 getDepth(); + private: + U32 sIterationNestDepth; }; }; LL_COMMON_API void assert_main_thread(); +enum EInstanceTrackerAllowKeyCollisions +{ + LLInstanceTrackerErrorOnCollision, + LLInstanceTrackerReplaceOnCollision +}; + /// This mix-in class adds support for tracking all instances of the specified class parameter T /// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup /// If KEY is not provided, then instances are stored in a simple set -/// @NOTE: see explicit specialization below for default KEY==T* case -template<typename T, typename KEY = T*> +/// @NOTE: see explicit specialization below for default KEY==void case +/// @NOTE: this class is not thread-safe unless used as read-only +template<typename T, typename KEY = void, EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR = LLInstanceTrackerErrorOnCollision> class LLInstanceTracker : public LLInstanceTrackerBase { typedef LLInstanceTracker<T, KEY> self_t; - typedef typename std::map<KEY, T*> InstanceMap; + typedef typename std::multimap<KEY, T*> InstanceMap; struct StaticData: public StaticBase { InstanceMap sMap; }; static StaticData& getStatic() { static StaticData sData; return sData;} - static InstanceMap& getMap_() - { - // assert_main_thread(); fwiw this class is not thread safe, and it used by multiple threads. Bad things happen. - return getStatic().sMap; - } + static InstanceMap& getMap_() { return getStatic().sMap; } public: class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> @@ -91,12 +94,12 @@ public: instance_iter(const typename InstanceMap::iterator& it) : mIterator(it) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } ~instance_iter() { - --getStatic().sIterationNestDepth; + getStatic().decrementDepth(); } @@ -123,20 +126,20 @@ public: typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t; key_iter(typename InstanceMap::iterator it) - : mIterator(it) + : mIterator(it) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } key_iter(const key_iter& other) - : mIterator(other.mIterator) + : mIterator(other.mIterator) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } ~key_iter() { - --getStatic().sIterationNestDepth; + getStatic().decrementDepth(); } @@ -174,7 +177,10 @@ public: return instance_iter(getMap_().end()); } - static S32 instanceCount() { return getMap_().size(); } + static S32 instanceCount() + { + return getMap_().size(); + } static key_iter beginKeys() { @@ -186,7 +192,7 @@ public: } protected: - LLInstanceTracker(KEY key) + LLInstanceTracker(const KEY& key) { // make sure static data outlives all instances getStatic(); @@ -195,7 +201,7 @@ protected: virtual ~LLInstanceTracker() { // it's unsafe to delete instances of this type while all instances are being iterated over. - llassert_always(getStatic().sIterationNestDepth == 0); + llassert_always(getStatic().getDepth() == 0); remove_(); } virtual void setKey(KEY key) { remove_(); add_(key); } @@ -205,17 +211,44 @@ private: LLInstanceTracker( const LLInstanceTracker& ); const LLInstanceTracker& operator=( const LLInstanceTracker& ); - void add_(KEY key) + void add_(const KEY& key) { mInstanceKey = key; - getMap_()[key] = static_cast<T*>(this); + InstanceMap& map = getMap_(); + typename InstanceMap::iterator insertion_point_it = map.lower_bound(key); + if (insertion_point_it != map.end() + && insertion_point_it->first == key) + { // found existing entry with that key + switch(KEY_COLLISION_BEHAVIOR) + { + case LLInstanceTrackerErrorOnCollision: + { + // use assert here instead of LL_ERRS(), otherwise the error will be ignored since this call is made during global object initialization + llassert_always_msg(false, "Instance with this same key already exists!"); + break; + } + case LLInstanceTrackerReplaceOnCollision: + { + // replace pointer, but leave key (should have compared equal anyway) + insertion_point_it->second = static_cast<T*>(this); + break; + } + default: + break; + } + } + else + { // new key + map.insert(insertion_point_it, std::make_pair(key, static_cast<T*>(this))); + } } void remove_() { - typename InstanceMap::iterator iter = getMap_().find(mInstanceKey); - if (iter != getMap_().end()) + InstanceMap& map = getMap_(); + typename InstanceMap::iterator iter = map.find(mInstanceKey); + if (iter != map.end()) { - getMap_().erase(iter); + map.erase(iter); } } @@ -223,12 +256,12 @@ private: KEY mInstanceKey; }; -/// explicit specialization for default case where KEY is T* +/// explicit specialization for default case where KEY is void /// use a simple std::set<T*> -template<typename T> -class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase +template<typename T, EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR> +class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR> : public LLInstanceTrackerBase { - typedef LLInstanceTracker<T, T*> self_t; + typedef LLInstanceTracker<T, void> self_t; typedef typename std::set<T*> InstanceSet; struct StaticData: public StaticBase { @@ -261,18 +294,18 @@ public: instance_iter(const typename InstanceSet::iterator& it) : mIterator(it) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } instance_iter(const instance_iter& other) : mIterator(other.mIterator) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } ~instance_iter() { - --getStatic().sIterationNestDepth; + getStatic().decrementDepth(); } private: @@ -305,7 +338,7 @@ protected: virtual ~LLInstanceTracker() { // it's unsafe to delete instances of this type while all instances are being iterated over. - llassert_always(getStatic().sIterationNestDepth == 0); + llassert_always(getStatic().getDepth() == 0); getSet_().erase(static_cast<T*>(this)); } |