Fix teh Singletons to have a global registry
This commit is contained in:
@@ -28,4 +28,5 @@
|
|||||||
|
|
||||||
#include "llsingleton.h"
|
#include "llsingleton.h"
|
||||||
|
|
||||||
|
std::map<std::string, void*>* LLSingletonRegistry::sSingletonMap = NULL;
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,33 @@
|
|||||||
|
|
||||||
#include "llerror.h" // *TODO: eliminate this
|
#include "llerror.h" // *TODO: eliminate this
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
|
|
||||||
|
/// @brief A global registry of all singletons to prevent duplicate allocations
|
||||||
|
/// across shared library boundaries
|
||||||
|
class LL_COMMON_API LLSingletonRegistry
|
||||||
|
{
|
||||||
|
typedef std::map<std::string, void *> TypeMap;
|
||||||
|
static TypeMap* sSingletonMap;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename T> static void * & get()
|
||||||
|
{
|
||||||
|
std::string name(typeid(T).name());
|
||||||
|
if (!sSingletonMap) sSingletonMap = new TypeMap();
|
||||||
|
|
||||||
|
// the first entry of the pair returned by insert will be either the existing
|
||||||
|
// iterator matching our key, or the newly inserted NULL initialized entry
|
||||||
|
// see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
|
||||||
|
TypeMap::iterator result =
|
||||||
|
sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first;
|
||||||
|
|
||||||
|
return result->second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// LLSingleton implements the getInstance() method part of the Singleton
|
// LLSingleton implements the getInstance() method part of the Singleton
|
||||||
// pattern. It can't make the derived class constructors protected, though, so
|
// pattern. It can't make the derived class constructors protected, though, so
|
||||||
// you have to do that yourself.
|
// you have to do that yourself.
|
||||||
@@ -73,6 +97,8 @@ private:
|
|||||||
return new DERIVED_TYPE();
|
return new DERIVED_TYPE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SingletonData;
|
||||||
|
|
||||||
// stores pointer to singleton instance
|
// stores pointer to singleton instance
|
||||||
struct SingletonLifetimeManager
|
struct SingletonLifetimeManager
|
||||||
{
|
{
|
||||||
@@ -83,6 +109,7 @@ private:
|
|||||||
|
|
||||||
static void construct()
|
static void construct()
|
||||||
{
|
{
|
||||||
|
SingletonData& sData(getData());
|
||||||
sData.mInitState = CONSTRUCTING;
|
sData.mInitState = CONSTRUCTING;
|
||||||
sData.mInstance = constructSingleton();
|
sData.mInstance = constructSingleton();
|
||||||
sData.mInitState = INITIALIZING;
|
sData.mInitState = INITIALIZING;
|
||||||
@@ -90,6 +117,7 @@ private:
|
|||||||
|
|
||||||
~SingletonLifetimeManager()
|
~SingletonLifetimeManager()
|
||||||
{
|
{
|
||||||
|
SingletonData& sData(getData());
|
||||||
if (sData.mInitState != DELETED)
|
if (sData.mInitState != DELETED)
|
||||||
{
|
{
|
||||||
deleteSingleton();
|
deleteSingleton();
|
||||||
@@ -100,6 +128,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
virtual ~LLSingleton()
|
virtual ~LLSingleton()
|
||||||
{
|
{
|
||||||
|
SingletonData& sData(getData());
|
||||||
sData.mInstance = NULL;
|
sData.mInstance = NULL;
|
||||||
sData.mInitState = DELETED;
|
sData.mInitState = DELETED;
|
||||||
}
|
}
|
||||||
@@ -126,15 +155,31 @@ public:
|
|||||||
*/
|
*/
|
||||||
static void deleteSingleton()
|
static void deleteSingleton()
|
||||||
{
|
{
|
||||||
|
SingletonData& sData(getData());
|
||||||
delete sData.mInstance;
|
delete sData.mInstance;
|
||||||
sData.mInstance = NULL;
|
sData.mInstance = NULL;
|
||||||
sData.mInitState = DELETED;
|
sData.mInitState = DELETED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SingletonData& getData()
|
||||||
|
{
|
||||||
|
// this is static to cache the lookup results
|
||||||
|
static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>();
|
||||||
|
|
||||||
|
// *TODO - look into making this threadsafe
|
||||||
|
if (!registry)
|
||||||
|
{
|
||||||
|
static SingletonData data;
|
||||||
|
registry = &data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *static_cast<SingletonData *>(registry);
|
||||||
|
}
|
||||||
|
|
||||||
static DERIVED_TYPE* getInstance()
|
static DERIVED_TYPE* getInstance()
|
||||||
{
|
{
|
||||||
static SingletonLifetimeManager sLifeTimeMgr;
|
static SingletonLifetimeManager sLifeTimeMgr;
|
||||||
|
SingletonData& sData(getData());
|
||||||
|
|
||||||
switch (sData.mInitState)
|
switch (sData.mInitState)
|
||||||
{
|
{
|
||||||
@@ -168,6 +213,7 @@ public:
|
|||||||
|
|
||||||
static DERIVED_TYPE* getIfExists()
|
static DERIVED_TYPE* getIfExists()
|
||||||
{
|
{
|
||||||
|
SingletonData& sData(getData());
|
||||||
return sData.mInstance;
|
return sData.mInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,6 +228,7 @@ public:
|
|||||||
// Use this to avoid accessing singletons before the can safely be constructed
|
// Use this to avoid accessing singletons before the can safely be constructed
|
||||||
static bool instanceExists()
|
static bool instanceExists()
|
||||||
{
|
{
|
||||||
|
SingletonData& sData(getData());
|
||||||
return sData.mInitState == INITIALIZED;
|
return sData.mInitState == INITIALIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +236,7 @@ public:
|
|||||||
// Use this to avoid accessing singletons from a static object's destructor
|
// Use this to avoid accessing singletons from a static object's destructor
|
||||||
static bool destroyed()
|
static bool destroyed()
|
||||||
{
|
{
|
||||||
|
SingletonData& sData(getData());
|
||||||
return sData.mInitState == DELETED;
|
return sData.mInitState == DELETED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,10 +251,6 @@ private:
|
|||||||
EInitState mInitState;
|
EInitState mInitState;
|
||||||
DERIVED_TYPE* mInstance;
|
DERIVED_TYPE* mInstance;
|
||||||
};
|
};
|
||||||
static SingletonData sData;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename LLSingleton<T>::SingletonData LLSingleton<T>::sData;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user