PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 0ms 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
Possible License(s): LGPL-2.1
  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. #ifndef LL_LLINSTANCETRACKER_H
  28. #define LL_LLINSTANCETRACKER_H
  29. #include <map>
  30. #include <typeinfo>
  31. #include "string_table.h"
  32. #include <boost/utility.hpp>
  33. #include <boost/function.hpp>
  34. #include <boost/bind.hpp>
  35. #include <boost/iterator/transform_iterator.hpp>
  36. #include <boost/iterator/indirect_iterator.hpp>
  37. /**
  38. * Base class manages "class-static" data that must actually have singleton
  39. * semantics: one instance per process, rather than one instance per module as
  40. * sometimes happens with data simply declared static.
  41. */
  42. class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
  43. {
  44. protected:
  45. /// Get a process-unique void* pointer slot for the specified type_info
  46. static void * & getInstances(std::type_info const & info);
  47. /// Find or create a STATICDATA instance for the specified TRACKED class.
  48. /// STATICDATA must be default-constructible.
  49. template<typename STATICDATA, class TRACKED>
  50. static STATICDATA& getStatic()
  51. {
  52. void *& instances = getInstances(typeid(TRACKED));
  53. if (! instances)
  54. {
  55. instances = new STATICDATA;
  56. }
  57. return *static_cast<STATICDATA*>(instances);
  58. }
  59. /// It's not essential to derive your STATICDATA (for use with
  60. /// getStatic()) from StaticBase; it's just that both known
  61. /// implementations do.
  62. struct StaticBase
  63. {
  64. StaticBase():
  65. sIterationNestDepth(0)
  66. {}
  67. S32 sIterationNestDepth;
  68. };
  69. };
  70. /// This mix-in class adds support for tracking all instances of the specified class parameter T
  71. /// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
  72. /// If KEY is not provided, then instances are stored in a simple set
  73. /// @NOTE: see explicit specialization below for default KEY==T* case
  74. template<typename T, typename KEY = T*>
  75. class LLInstanceTracker : public LLInstanceTrackerBase
  76. {
  77. typedef LLInstanceTracker<T, KEY> MyT;
  78. typedef typename std::map<KEY, T*> InstanceMap;
  79. struct StaticData: public StaticBase
  80. {
  81. InstanceMap sMap;
  82. };
  83. static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
  84. static InstanceMap& getMap_() { return getStatic().sMap; }
  85. public:
  86. class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
  87. {
  88. public:
  89. typedef boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> super_t;
  90. instance_iter(const typename InstanceMap::iterator& it)
  91. : mIterator(it)
  92. {
  93. ++getStatic().sIterationNestDepth;
  94. }
  95. ~instance_iter()
  96. {
  97. --getStatic().sIterationNestDepth;
  98. }
  99. private:
  100. friend class boost::iterator_core_access;
  101. void increment() { mIterator++; }
  102. bool equal(instance_iter const& other) const
  103. {
  104. return mIterator == other.mIterator;
  105. }
  106. T& dereference() const
  107. {
  108. return *(mIterator->second);
  109. }
  110. typename InstanceMap::iterator mIterator;
  111. };
  112. class key_iter : public boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag>
  113. {
  114. public:
  115. typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t;
  116. key_iter(typename InstanceMap::iterator it)
  117. : mIterator(it)
  118. {
  119. ++getStatic().sIterationNestDepth;
  120. }
  121. key_iter(const key_iter& other)
  122. : mIterator(other.mIterator)
  123. {
  124. ++getStatic().sIterationNestDepth;
  125. }
  126. ~key_iter()
  127. {
  128. --getStatic().sIterationNestDepth;
  129. }
  130. private:
  131. friend class boost::iterator_core_access;
  132. void increment() { mIterator++; }
  133. bool equal(key_iter const& other) const
  134. {
  135. return mIterator == other.mIterator;
  136. }
  137. KEY& dereference() const
  138. {
  139. return const_cast<KEY&>(mIterator->first);
  140. }
  141. typename InstanceMap::iterator mIterator;
  142. };
  143. static T* getInstance(const KEY& k)
  144. {
  145. typename InstanceMap::const_iterator found = getMap_().find(k);
  146. return (found == getMap_().end()) ? NULL : found->second;
  147. }
  148. static instance_iter beginInstances()
  149. {
  150. return instance_iter(getMap_().begin());
  151. }
  152. static instance_iter endInstances()
  153. {
  154. return instance_iter(getMap_().end());
  155. }
  156. static S32 instanceCount() { return getMap_().size(); }
  157. static key_iter beginKeys()
  158. {
  159. return key_iter(getMap_().begin());
  160. }
  161. static key_iter endKeys()
  162. {
  163. return key_iter(getMap_().end());
  164. }
  165. protected:
  166. LLInstanceTracker(KEY key)
  167. {
  168. // make sure static data outlives all instances
  169. getStatic();
  170. add_(key);
  171. }
  172. virtual ~LLInstanceTracker()
  173. {
  174. // it's unsafe to delete instances of this type while all instances are being iterated over.
  175. llassert_always(getStatic().sIterationNestDepth == 0);
  176. remove_();
  177. }
  178. virtual void setKey(KEY key) { remove_(); add_(key); }
  179. virtual const KEY& getKey() const { return mInstanceKey; }
  180. private:
  181. void add_(KEY key)
  182. {
  183. mInstanceKey = key;
  184. getMap_()[key] = static_cast<T*>(this);
  185. }
  186. void remove_()
  187. {
  188. getMap_().erase(mInstanceKey);
  189. }
  190. private:
  191. KEY mInstanceKey;
  192. };
  193. /// explicit specialization for default case where KEY is T*
  194. /// use a simple std::set<T*>
  195. template<typename T>
  196. class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
  197. {
  198. typedef LLInstanceTracker<T, T*> MyT;
  199. typedef typename std::set<T*> InstanceSet;
  200. struct StaticData: public StaticBase
  201. {
  202. InstanceSet sSet;
  203. };
  204. static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
  205. static InstanceSet& getSet_() { return getStatic().sSet; }
  206. public:
  207. /// for completeness of analogy with the generic implementation
  208. static T* getInstance(T* k) { return k; }
  209. static S32 instanceCount() { return getSet_().size(); }
  210. class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
  211. {
  212. public:
  213. instance_iter(const typename InstanceSet::iterator& it)
  214. : mIterator(it)
  215. {
  216. ++getStatic().sIterationNestDepth;
  217. }
  218. instance_iter(const instance_iter& other)
  219. : mIterator(other.mIterator)
  220. {
  221. ++getStatic().sIterationNestDepth;
  222. }
  223. ~instance_iter()
  224. {
  225. --getStatic().sIterationNestDepth;
  226. }
  227. private:
  228. friend class boost::iterator_core_access;
  229. void increment() { mIterator++; }
  230. bool equal(instance_iter const& other) const
  231. {
  232. return mIterator == other.mIterator;
  233. }
  234. T& dereference() const
  235. {
  236. return **mIterator;
  237. }
  238. typename InstanceSet::iterator mIterator;
  239. };
  240. static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
  241. static instance_iter endInstances() { return instance_iter(getSet_().end()); }
  242. protected:
  243. LLInstanceTracker()
  244. {
  245. // make sure static data outlives all instances
  246. getStatic();
  247. getSet_().insert(static_cast<T*>(this));
  248. }
  249. virtual ~LLInstanceTracker()
  250. {
  251. // it's unsafe to delete instances of this type while all instances are being iterated over.
  252. llassert_always(getStatic().sIterationNestDepth == 0);
  253. getSet_().erase(static_cast<T*>(this));
  254. }
  255. LLInstanceTracker(const LLInstanceTracker& other)
  256. {
  257. getSet_().insert(static_cast<T*>(this));
  258. }
  259. };
  260. #endif