summaryrefslogtreecommitdiff
path: root/indra/llcommon/llinstancetracker.h
diff options
context:
space:
mode:
authorRichard Linden <none@none>2014-02-12 10:32:02 -0800
committerRichard Linden <none@none>2014-02-12 10:32:02 -0800
commit5866bb7ef09b786f8f195770a70dc4289d183ca0 (patch)
tree0be3b5e63506bf30edd3748f9e31740ae9ebbaa8 /indra/llcommon/llinstancetracker.h
parent413be91cf5044889ade97dcbec4b17fceff122e3 (diff)
parenta8192fbf60540e42dcff5f1efb8bf8cafbfac484 (diff)
merge with release
Diffstat (limited to 'indra/llcommon/llinstancetracker.h')
-rwxr-xr-xindra/llcommon/llinstancetracker.h109
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));
}