Skip to content
Snippets Groups Projects
Commit 3d295fbf authored by Nat Goodspeed's avatar Nat Goodspeed
Browse files
parents 82b1b1bc 286342f7
No related branches found
No related tags found
No related merge requests found
...@@ -35,14 +35,15 @@ ...@@ -35,14 +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;
} }
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,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>
...@@ -37,10 +38,40 @@ ...@@ -37,10 +38,40 @@
#include <boost/iterator/transform_iterator.hpp> #include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/indirect_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 class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
{ {
protected: protected:
static void * & getInstances(std::type_info const & info); /// 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 /// 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 ...@@ -50,8 +81,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>
{ {
...@@ -61,12 +99,12 @@ class LLInstanceTracker : public LLInstanceTrackerBase ...@@ -61,12 +99,12 @@ class LLInstanceTracker : public LLInstanceTrackerBase
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;
} }
...@@ -95,18 +133,18 @@ class LLInstanceTracker : public LLInstanceTrackerBase ...@@ -95,18 +133,18 @@ class LLInstanceTracker : public LLInstanceTrackerBase
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;
} }
...@@ -159,8 +197,8 @@ class LLInstanceTracker : public LLInstanceTrackerBase ...@@ -159,8 +197,8 @@ class LLInstanceTracker : public LLInstanceTrackerBase
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); }
virtual const KEY& getKey() const { return mInstanceKey; } virtual const KEY& getKey() const { return mInstanceKey; }
...@@ -176,31 +214,24 @@ class LLInstanceTracker : public LLInstanceTrackerBase ...@@ -176,31 +214,24 @@ class LLInstanceTracker : public LLInstanceTrackerBase
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
...@@ -213,18 +244,18 @@ class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase ...@@ -213,18 +244,18 @@ class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
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:
...@@ -250,13 +281,13 @@ class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase ...@@ -250,13 +281,13 @@ class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
protected: protected:
LLInstanceTracker() 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)); getSet_().insert(static_cast<T*>(this));
} }
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));
} }
...@@ -264,20 +295,6 @@ class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase ...@@ -264,20 +295,6 @@ class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
{ {
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
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
// other Linden headers // other Linden headers
#include "../test/lltut.h" #include "../test/lltut.h"
#include "wrapllerrs.h"
struct Keyed: public LLInstanceTracker<Keyed, std::string> struct Keyed: public LLInstanceTracker<Keyed, std::string>
{ {
...@@ -165,4 +166,67 @@ namespace tut ...@@ -165,4 +166,67 @@ namespace tut
ensure_equals("unreported instance", instances.size(), 0); ensure_equals("unreported instance", instances.size(), 0);
} }
template<> template<>
void object::test<5>()
{
set_test_name("delete Keyed with outstanding instance_iter");
std::string what;
Keyed* keyed = new Keyed("one");
{
WrapLL_ERRS wrapper;
Keyed::instance_iter i(Keyed::beginInstances());
try
{
delete keyed;
}
catch (const WrapLL_ERRS::FatalException& e)
{
what = e.what();
}
}
ensure(! what.empty());
}
template<> template<>
void object::test<6>()
{
set_test_name("delete Keyed with outstanding key_iter");
std::string what;
Keyed* keyed = new Keyed("one");
{
WrapLL_ERRS wrapper;
Keyed::key_iter i(Keyed::beginKeys());
try
{
delete keyed;
}
catch (const WrapLL_ERRS::FatalException& e)
{
what = e.what();
}
}
ensure(! what.empty());
}
template<> template<>
void object::test<7>()
{
set_test_name("delete Unkeyed with outstanding instance_iter");
std::string what;
Unkeyed* unkeyed = new Unkeyed;
{
WrapLL_ERRS wrapper;
Unkeyed::instance_iter i(Unkeyed::beginInstances());
try
{
delete unkeyed;
}
catch (const WrapLL_ERRS::FatalException& e)
{
what = e.what();
}
}
ensure(! what.empty());
}
} // namespace tut } // namespace tut
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment