diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2011-09-06 22:07:49 -0400 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2011-09-06 22:07:49 -0400 |
commit | 8c6f752982e83a50e328b9c83f762721f38836d7 (patch) | |
tree | 6954c6e48896ed78d98e7a91c6ee35e98647a965 | |
parent | 0ab6eee0996c78d32b722157140cea5a21a5e460 (diff) |
STORM-1541: Hoist LLInstanceTracker::getMap_() to base getStatic().
Generalize the notion of getting some chunk of "static" storage: introduce
LLInstanceTrackerBase::getStatic() template method. Define StaticData struct
containing the InstanceMap (or InstanceSet, for that specialization) along
with the S32 that caused the VS2010 linker so much grief. Completely eliminate
that S32 as an actual class-static member, qualifying all references with the
struct returned by getStatic().
In LLInstanceTrackerBase::getInstances(), use one std::map lookup instead of
three.
-rw-r--r-- | indra/llcommon/llinstancetracker.cpp | 19 | ||||
-rw-r--r-- | indra/llcommon/llinstancetracker.h | 105 |
2 files changed, 71 insertions, 53 deletions
diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp index f576204511..5dc3ea5d7b 100644 --- a/indra/llcommon/llinstancetracker.cpp +++ b/indra/llcommon/llinstancetracker.cpp @@ -35,14 +35,15 @@ //static void * & LLInstanceTrackerBase::getInstances(std::type_info const & info) { - static std::map<std::string, void *> instances; + typedef std::map<std::string, void *> InstancesMap; + static InstancesMap instances; - std::string k = info.name(); - if(instances.find(k) == instances.end()) - { - instances[k] = NULL; - } - - return instances[k]; + // std::map::insert() is just what we want here. You attempt to insert a + // (key, value) pair. If the specified key doesn't yet exist, it inserts + // the pair and returns a std::pair of (iterator, true). If the specified + // key DOES exist, insert() simply returns (iterator, false). One lookup + // handles both cases. + return instances.insert(InstancesMap::value_type(info.name(), + InstancesMap::mapped_type())) + .first->second; } - diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index afb714c71c..936bef850a 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -29,6 +29,7 @@ #define LL_LLINSTANCETRACKER_H #include <map> +#include <typeinfo> #include "string_table.h" #include <boost/utility.hpp> @@ -37,10 +38,40 @@ #include <boost/iterator/transform_iterator.hpp> #include <boost/iterator/indirect_iterator.hpp> +/** + * Base class manages "class-static" data that must actually have singleton + * semantics: one instance per process, rather than one instance per module as + * sometimes happens with data simply declared static. + */ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable { - protected: - static void * & getInstances(std::type_info const & info); +protected: + /// Get a process-unique void* pointer slot for the specified type_info + static void * & getInstances(std::type_info const & info); + + /// Find or create a STATICDATA instance for the specified TRACKED class. + /// STATICDATA must be default-constructible. + template<typename STATICDATA, class TRACKED> + static STATICDATA& getStatic() + { + void *& instances = getInstances(typeid(TRACKED)); + if (! instances) + { + instances = new STATICDATA; + } + return *static_cast<STATICDATA*>(instances); + } + + /// It's not essential to derive your STATICDATA (for use with + /// getStatic()) from StaticBase; it's just that both known + /// implementations do. + struct StaticBase + { + StaticBase(): + sIterationNestDepth(0) + {} + S32 sIterationNestDepth; + }; }; /// This mix-in class adds support for tracking all instances of the specified class parameter T @@ -50,8 +81,15 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable template<typename T, typename KEY = T*> class LLInstanceTracker : public LLInstanceTrackerBase { - typedef typename std::map<KEY, T*> InstanceMap; typedef LLInstanceTracker<T, KEY> MyT; + typedef typename std::map<KEY, T*> InstanceMap; + struct StaticData: public StaticBase + { + InstanceMap sMap; + }; + static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); } + static InstanceMap& getMap_() { return getStatic().sMap; } + public: class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> { @@ -61,12 +99,12 @@ public: instance_iter(const typename InstanceMap::iterator& it) : mIterator(it) { - ++sIterationNestDepth; + ++getStatic().sIterationNestDepth; } ~instance_iter() { - --sIterationNestDepth; + --getStatic().sIterationNestDepth; } @@ -95,18 +133,18 @@ public: key_iter(typename InstanceMap::iterator it) : mIterator(it) { - ++sIterationNestDepth; + ++getStatic().sIterationNestDepth; } key_iter(const key_iter& other) : mIterator(other.mIterator) { - ++sIterationNestDepth; + ++getStatic().sIterationNestDepth; } ~key_iter() { - --sIterationNestDepth; + --getStatic().sIterationNestDepth; } @@ -159,8 +197,8 @@ protected: virtual ~LLInstanceTracker() { // it's unsafe to delete instances of this type while all instances are being iterated over. - llassert(sIterationNestDepth == 0); - remove_(); + llassert(getStatic().sIterationNestDepth == 0); + remove_(); } virtual void setKey(KEY key) { remove_(); add_(key); } virtual const KEY& getKey() const { return mInstanceKey; } @@ -176,31 +214,24 @@ private: getMap_().erase(mInstanceKey); } - static InstanceMap& getMap_() - { - void * & instances = getInstances(typeid(MyT)); - if (! instances) - { - instances = new InstanceMap; - } - return * static_cast<InstanceMap*>(instances); - } - private: - KEY mInstanceKey; - static S32 sIterationNestDepth; }; -template <typename T, typename KEY> S32 LLInstanceTracker<T, KEY>::sIterationNestDepth = 0; - /// explicit specialization for default case where KEY is T* /// use a simple std::set<T*> template<typename T> class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase { - typedef typename std::set<T*> InstanceSet; typedef LLInstanceTracker<T, T*> MyT; + typedef typename std::set<T*> InstanceSet; + struct StaticData: public StaticBase + { + InstanceSet sSet; + }; + static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); } + static InstanceSet& getSet_() { return getStatic().sSet; } + public: /// for completeness of analogy with the generic implementation @@ -213,18 +244,18 @@ public: instance_iter(const typename InstanceSet::iterator& it) : mIterator(it) { - ++sIterationNestDepth; + ++getStatic().sIterationNestDepth; } instance_iter(const instance_iter& other) : mIterator(other.mIterator) { - ++sIterationNestDepth; + ++getStatic().sIterationNestDepth; } ~instance_iter() { - --sIterationNestDepth; + --getStatic().sIterationNestDepth; } private: @@ -250,13 +281,13 @@ public: protected: LLInstanceTracker() { - // it's safe but unpredictable to create instances of this type while all instances are being iterated over. I hate unpredictable. This assert will probably be turned on early in the next development cycle. + // it's safe but unpredictable to create instances of this type while all instances are being iterated over. I hate unpredictable. This assert will probably be turned on early in the next development cycle. getSet_().insert(static_cast<T*>(this)); } virtual ~LLInstanceTracker() { // it's unsafe to delete instances of this type while all instances are being iterated over. - llassert(sIterationNestDepth == 0); + llassert(getStatic().sIterationNestDepth == 0); getSet_().erase(static_cast<T*>(this)); } @@ -264,20 +295,6 @@ protected: { getSet_().insert(static_cast<T*>(this)); } - - static InstanceSet& getSet_() - { - void * & instances = getInstances(typeid(MyT)); - if (! instances) - { - instances = new InstanceSet; - } - return * static_cast<InstanceSet *>(instances); - } - - static S32 sIterationNestDepth; }; -template <typename T> S32 LLInstanceTracker<T, T*>::sIterationNestDepth = 0; - #endif |