LLInstanceTracker and LLSingleton updated yet again.

This commit is contained in:
Shyotl
2011-09-20 22:09:45 -05:00
parent 244e30297f
commit cce1395876
3 changed files with 83 additions and 52 deletions

View File

@@ -35,13 +35,15 @@
//static //static
void * & LLInstanceTrackerBase::getInstances(std::type_info const & info) 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(); // std::map::insert() is just what we want here. You attempt to insert a
if(instances.find(k) == instances.end()) // (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
instances[k] = NULL; // key DOES exist, insert() simply returns (iterator, false). One lookup
} // handles both cases.
return instances.insert(InstancesMap::value_type(info.name(),
return instances[k]; InstancesMap::mapped_type()))
.first->second;
} }

View File

@@ -36,6 +36,7 @@
#define LL_LLINSTANCETRACKER_H #define LL_LLINSTANCETRACKER_H
#include <map> #include <map>
#include <typeinfo>
#include "string_table.h" #include "string_table.h"
#include <boost/utility.hpp> #include <boost/utility.hpp>
@@ -48,6 +49,30 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
{ {
protected: protected:
static void * & getInstances(std::type_info const & 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 /// This mix-in class adds support for tracking all instances of the specified class parameter T
@@ -57,8 +82,15 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
template<typename T, typename KEY = T*> template<typename T, typename KEY = T*>
class LLInstanceTracker : public LLInstanceTrackerBase class LLInstanceTracker : public LLInstanceTrackerBase
{ {
typedef typename std::map<KEY, T*> InstanceMap;
typedef LLInstanceTracker<T, KEY> MyT; 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: public:
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
{ {
@@ -68,12 +100,12 @@ public:
instance_iter(const typename InstanceMap::iterator& it) instance_iter(const typename InstanceMap::iterator& it)
: mIterator(it) : mIterator(it)
{ {
++sIterationNestDepth; ++getStatic().sIterationNestDepth;
} }
~instance_iter() ~instance_iter()
{ {
--sIterationNestDepth; --getStatic().sIterationNestDepth;
} }
@@ -102,18 +134,18 @@ public:
key_iter(typename InstanceMap::iterator it) key_iter(typename InstanceMap::iterator it)
: mIterator(it) : mIterator(it)
{ {
++sIterationNestDepth; ++getStatic().sIterationNestDepth;
} }
key_iter(const key_iter& other) key_iter(const key_iter& other)
: mIterator(other.mIterator) : mIterator(other.mIterator)
{ {
++sIterationNestDepth; ++getStatic().sIterationNestDepth;
} }
~key_iter() ~key_iter()
{ {
--sIterationNestDepth; --getStatic().sIterationNestDepth;
} }
@@ -166,7 +198,7 @@ protected:
virtual ~LLInstanceTracker() virtual ~LLInstanceTracker()
{ {
// it's unsafe to delete instances of this type while all instances are being iterated over. // it's unsafe to delete instances of this type while all instances are being iterated over.
llassert(sIterationNestDepth == 0); llassert_always(getStatic().sIterationNestDepth == 0);
remove_(); remove_();
} }
virtual void setKey(KEY key) { remove_(); add_(key); } virtual void setKey(KEY key) { remove_(); add_(key); }
@@ -183,31 +215,24 @@ private:
getMap_().erase(mInstanceKey); getMap_().erase(mInstanceKey);
} }
static InstanceMap& getMap_()
{
void * & instances = getInstances(typeid(MyT));
if (! instances)
{
instances = new InstanceMap;
}
return * static_cast<InstanceMap*>(instances);
}
private: private:
KEY mInstanceKey; 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* /// explicit specialization for default case where KEY is T*
/// use a simple std::set<T*> /// use a simple std::set<T*>
template<typename T> template<typename T>
class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
{ {
typedef typename std::set<T*> InstanceSet;
typedef LLInstanceTracker<T, T*> MyT; 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: public:
/// for completeness of analogy with the generic implementation /// for completeness of analogy with the generic implementation
@@ -220,18 +245,18 @@ public:
instance_iter(const typename InstanceSet::iterator& it) instance_iter(const typename InstanceSet::iterator& it)
: mIterator(it) : mIterator(it)
{ {
++sIterationNestDepth; ++getStatic().sIterationNestDepth;
} }
instance_iter(const instance_iter& other) instance_iter(const instance_iter& other)
: mIterator(other.mIterator) : mIterator(other.mIterator)
{ {
++sIterationNestDepth; ++getStatic().sIterationNestDepth;
} }
~instance_iter() ~instance_iter()
{ {
--sIterationNestDepth; --getStatic().sIterationNestDepth;
} }
private: private:
@@ -263,7 +288,7 @@ protected:
virtual ~LLInstanceTracker() virtual ~LLInstanceTracker()
{ {
// it's unsafe to delete instances of this type while all instances are being iterated over. // it's unsafe to delete instances of this type while all instances are being iterated over.
llassert(sIterationNestDepth == 0); llassert_always(getStatic().sIterationNestDepth == 0);
getSet_().erase(static_cast<T*>(this)); getSet_().erase(static_cast<T*>(this));
} }
@@ -271,20 +296,6 @@ protected:
{ {
getSet_().insert(static_cast<T*>(this)); 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 #endif

View File

@@ -114,8 +114,7 @@ private:
~SingletonInstanceData() ~SingletonInstanceData()
{ {
SingletonInstanceData& data = getData(); if (mInitState != DELETED)
if (data.mInitState != DELETED)
{ {
deleteSingleton(); deleteSingleton();
} }
@@ -130,7 +129,26 @@ public:
data.mInitState = DELETED; data.mInitState = DELETED;
} }
// Can be used to control when the singleton is deleted. Not normally needed. /**
* @brief Immediately delete the singleton.
*
* A subsequent call to LLProxy::getInstance() will construct a new
* instance of the class.
*
* LLSingletons are normally destroyed after main() has exited and the C++
* runtime is cleaning up statically-constructed objects. Some classes
* derived from LLSingleton have objects that are part of a runtime system
* that is terminated before main() exits. Calling the destructor of those
* objects after the termination of their respective systems can cause
* crashes and other problems during termination of the project. Using this
* method to destroy the singleton early can prevent these crashes.
*
* An example where this is needed is for a LLSingleton that has an APR
* object as a member that makes APR calls on destruction. The APR system is
* shut down explicitly before main() exits. This causes a crash on exit.
* Using this method before the call to apr_terminate() and NOT calling
* getInstance() again will prevent the crash.
*/
static void deleteSingleton() static void deleteSingleton()
{ {
delete getData().mSingletonInstance; delete getData().mSingletonInstance;