LLInstanceTracker and LLSingleton updated yet again.
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user