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
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;
}

View File

@@ -36,6 +36,7 @@
#define LL_LLINSTANCETRACKER_H
#include <map>
#include <typeinfo>
#include "string_table.h"
#include <boost/utility.hpp>
@@ -48,6 +49,30 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
{
protected:
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
@@ -57,8 +82,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>
{
@@ -68,12 +100,12 @@ public:
instance_iter(const typename InstanceMap::iterator& it)
: mIterator(it)
{
++sIterationNestDepth;
++getStatic().sIterationNestDepth;
}
~instance_iter()
{
--sIterationNestDepth;
--getStatic().sIterationNestDepth;
}
@@ -102,18 +134,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;
}
@@ -166,8 +198,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_always(getStatic().sIterationNestDepth == 0);
remove_();
}
virtual void setKey(KEY key) { remove_(); add_(key); }
virtual const KEY& getKey() const { return mInstanceKey; }
@@ -183,31 +215,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
@@ -220,18 +245,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:
@@ -263,7 +288,7 @@ protected:
virtual ~LLInstanceTracker()
{
// 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));
}
@@ -271,20 +296,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

View File

@@ -114,8 +114,7 @@ private:
~SingletonInstanceData()
{
SingletonInstanceData& data = getData();
if (data.mInitState != DELETED)
if (mInitState != DELETED)
{
deleteSingleton();
}
@@ -130,7 +129,26 @@ public:
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()
{
delete getData().mSingletonInstance;