PageRenderTime 47ms CodeModel.GetById 15ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/llinstancetracker.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 306 lines | 212 code | 46 blank | 48 comment | 7 complexity | 87a5e6d4642c0001b1a726878d813d93 MD5 | raw file
  1/** 
  2 * @file llinstancetracker.h
  3 * @brief LLInstanceTracker is a mixin class that automatically tracks object
  4 *        instances with or without an associated key
  5 *
  6 * $LicenseInfo:firstyear=2000&license=viewerlgpl$
  7 * Second Life Viewer Source Code
  8 * Copyright (C) 2010, Linden Research, Inc.
  9 * 
 10 * This library is free software; you can redistribute it and/or
 11 * modify it under the terms of the GNU Lesser General Public
 12 * License as published by the Free Software Foundation;
 13 * version 2.1 of the License only.
 14 * 
 15 * This library is distributed in the hope that it will be useful,
 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 18 * Lesser General Public License for more details.
 19 * 
 20 * You should have received a copy of the GNU Lesser General Public
 21 * License along with this library; if not, write to the Free Software
 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 23 * 
 24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 25 * $/LicenseInfo$
 26 */
 27
 28#ifndef LL_LLINSTANCETRACKER_H
 29#define LL_LLINSTANCETRACKER_H
 30
 31#include <map>
 32#include <typeinfo>
 33
 34#include "string_table.h"
 35#include <boost/utility.hpp>
 36#include <boost/function.hpp>
 37#include <boost/bind.hpp>
 38#include <boost/iterator/transform_iterator.hpp>
 39#include <boost/iterator/indirect_iterator.hpp>
 40
 41/**
 42 * Base class manages "class-static" data that must actually have singleton
 43 * semantics: one instance per process, rather than one instance per module as
 44 * sometimes happens with data simply declared static.
 45 */
 46class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
 47{
 48protected:
 49	/// Get a process-unique void* pointer slot for the specified type_info
 50	static void * & getInstances(std::type_info const & info);
 51
 52	/// Find or create a STATICDATA instance for the specified TRACKED class.
 53	/// STATICDATA must be default-constructible.
 54	template<typename STATICDATA, class TRACKED>
 55	static STATICDATA& getStatic()
 56	{
 57		void *& instances = getInstances(typeid(TRACKED));
 58		if (! instances)
 59		{
 60			instances = new STATICDATA;
 61		}
 62		return *static_cast<STATICDATA*>(instances);
 63	}
 64
 65    /// It's not essential to derive your STATICDATA (for use with
 66    /// getStatic()) from StaticBase; it's just that both known
 67    /// implementations do.
 68    struct StaticBase
 69    {
 70        StaticBase():
 71            sIterationNestDepth(0)
 72        {}
 73        S32 sIterationNestDepth;
 74    };
 75};
 76
 77/// This mix-in class adds support for tracking all instances of the specified class parameter T
 78/// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
 79/// If KEY is not provided, then instances are stored in a simple set
 80/// @NOTE: see explicit specialization below for default KEY==T* case
 81template<typename T, typename KEY = T*>
 82class LLInstanceTracker : public LLInstanceTrackerBase
 83{
 84	typedef LLInstanceTracker<T, KEY> MyT;
 85	typedef typename std::map<KEY, T*> InstanceMap;
 86	struct StaticData: public StaticBase
 87	{
 88		InstanceMap sMap;
 89	};
 90	static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
 91	static InstanceMap& getMap_() { return getStatic().sMap; }
 92
 93public:
 94	class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
 95	{
 96	public:
 97		typedef boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> super_t;
 98		
 99		instance_iter(const typename InstanceMap::iterator& it)
100		:	mIterator(it)
101		{
102			++getStatic().sIterationNestDepth;
103		}
104
105		~instance_iter()
106		{
107			--getStatic().sIterationNestDepth;
108		}
109
110
111	private:
112		friend class boost::iterator_core_access;
113
114		void increment() { mIterator++; }
115		bool equal(instance_iter const& other) const
116		{
117			return mIterator == other.mIterator;
118		}
119
120		T& dereference() const
121		{
122			return *(mIterator->second);
123		}
124
125		typename InstanceMap::iterator mIterator;
126	};
127
128	class key_iter : public boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag>
129	{
130	public:
131		typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t;
132
133		key_iter(typename InstanceMap::iterator it)
134			:	mIterator(it)
135		{
136			++getStatic().sIterationNestDepth;
137		}
138
139		key_iter(const key_iter& other)
140			:	mIterator(other.mIterator)
141		{
142			++getStatic().sIterationNestDepth;
143		}
144
145		~key_iter()
146		{
147			--getStatic().sIterationNestDepth;
148		}
149
150
151	private:
152		friend class boost::iterator_core_access;
153
154		void increment() { mIterator++; }
155		bool equal(key_iter const& other) const
156		{
157			return mIterator == other.mIterator;
158		}
159
160		KEY& dereference() const
161		{
162			return const_cast<KEY&>(mIterator->first);
163		}
164
165		typename InstanceMap::iterator mIterator;
166	};
167
168	static T* getInstance(const KEY& k)
169	{
170		typename InstanceMap::const_iterator found = getMap_().find(k);
171		return (found == getMap_().end()) ? NULL : found->second;
172	}
173
174	static instance_iter beginInstances() 
175	{	
176		return instance_iter(getMap_().begin()); 
177	}
178
179	static instance_iter endInstances() 
180	{
181		return instance_iter(getMap_().end());
182	}
183
184	static S32 instanceCount() { return getMap_().size(); }
185
186	static key_iter beginKeys()
187	{
188		return key_iter(getMap_().begin());
189	}
190	static key_iter endKeys()
191	{
192		return key_iter(getMap_().end());
193	}
194
195protected:
196	LLInstanceTracker(KEY key) 
197	{ 
198		// make sure static data outlives all instances
199		getStatic();
200		add_(key); 
201	}
202	virtual ~LLInstanceTracker() 
203	{ 
204		// it's unsafe to delete instances of this type while all instances are being iterated over.
205		llassert_always(getStatic().sIterationNestDepth == 0);
206		remove_();		
207	}
208	virtual void setKey(KEY key) { remove_(); add_(key); }
209	virtual const KEY& getKey() const { return mInstanceKey; }
210
211private:
212	void add_(KEY key) 
213	{ 
214		mInstanceKey = key; 
215		getMap_()[key] = static_cast<T*>(this); 
216	}
217	void remove_()
218	{
219		getMap_().erase(mInstanceKey);
220	}
221
222private:
223	KEY mInstanceKey;
224};
225
226/// explicit specialization for default case where KEY is T*
227/// use a simple std::set<T*>
228template<typename T>
229class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
230{
231	typedef LLInstanceTracker<T, T*> MyT;
232	typedef typename std::set<T*> InstanceSet;
233	struct StaticData: public StaticBase
234	{
235		InstanceSet sSet;
236	};
237	static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
238	static InstanceSet& getSet_() { return getStatic().sSet; }
239
240public:
241
242	/// for completeness of analogy with the generic implementation
243	static T* getInstance(T* k) { return k; }
244	static S32 instanceCount() { return getSet_().size(); }
245
246	class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
247	{
248	public:
249		instance_iter(const typename InstanceSet::iterator& it)
250		:	mIterator(it)
251		{
252			++getStatic().sIterationNestDepth;
253		}
254
255		instance_iter(const instance_iter& other)
256		:	mIterator(other.mIterator)
257		{
258			++getStatic().sIterationNestDepth;
259		}
260
261		~instance_iter()
262		{
263			--getStatic().sIterationNestDepth;
264		}
265
266	private:
267		friend class boost::iterator_core_access;
268
269		void increment() { mIterator++; }
270		bool equal(instance_iter const& other) const
271		{
272			return mIterator == other.mIterator;
273		}
274
275		T& dereference() const
276		{
277			return **mIterator;
278		}
279
280		typename InstanceSet::iterator mIterator;
281	};
282
283	static instance_iter beginInstances() {	return instance_iter(getSet_().begin()); }
284	static instance_iter endInstances() { return instance_iter(getSet_().end()); }
285
286protected:
287	LLInstanceTracker()
288	{
289		// make sure static data outlives all instances
290		getStatic();
291		getSet_().insert(static_cast<T*>(this));
292	}
293	virtual ~LLInstanceTracker()
294	{
295		// it's unsafe to delete instances of this type while all instances are being iterated over.
296		llassert_always(getStatic().sIterationNestDepth == 0);
297		getSet_().erase(static_cast<T*>(this));
298	}
299
300	LLInstanceTracker(const LLInstanceTracker& other)
301	{
302		getSet_().insert(static_cast<T*>(this));
303	}
304};
305
306#endif