Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

389 lines
11 KiB

  1. //========== Copyright � 2005, Valve Corporation, All rights reserved. ========
  2. //
  3. // Purpose: Tools for correctly implementing & handling reference counted
  4. // objects
  5. //
  6. //=============================================================================
  7. #ifndef REFCOUNT_H
  8. #define REFCOUNT_H
  9. #include "tier0/threadtools.h"
  10. #if defined( _WIN32 )
  11. #pragma once
  12. #endif
  13. //-----------------------------------------------------------------------------
  14. // Purpose: Implement a standard reference counted interface. Use of this
  15. // is optional insofar as all the concrete tools only require
  16. // at compile time that the function signatures match.
  17. //-----------------------------------------------------------------------------
  18. class IRefCounted
  19. {
  20. public:
  21. virtual int AddRef() = 0;
  22. virtual int Release() = 0;
  23. };
  24. //-----------------------------------------------------------------------------
  25. // Purpose: Release a pointer and mark it NULL
  26. //-----------------------------------------------------------------------------
  27. template <class REFCOUNTED_ITEM_PTR>
  28. inline int SafeRelease( REFCOUNTED_ITEM_PTR &pRef )
  29. {
  30. // Use funny syntax so that this works on "auto pointers"
  31. REFCOUNTED_ITEM_PTR *ppRef = &pRef;
  32. if ( *ppRef )
  33. {
  34. int result = (*ppRef)->Release();
  35. *ppRef = NULL;
  36. return result;
  37. }
  38. return 0;
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Purpose: Maintain a reference across a scope
  42. //-----------------------------------------------------------------------------
  43. template <class T = IRefCounted>
  44. class CAutoRef
  45. {
  46. public:
  47. CAutoRef( T *pRef )
  48. : m_pRef( pRef )
  49. {
  50. if ( m_pRef )
  51. m_pRef->AddRef();
  52. }
  53. ~CAutoRef()
  54. {
  55. if (m_pRef)
  56. m_pRef->Release();
  57. }
  58. private:
  59. T *m_pRef;
  60. };
  61. //-----------------------------------------------------------------------------
  62. // Purpose: Do a an inline AddRef then return the pointer, useful when
  63. // returning an object from a function
  64. //-----------------------------------------------------------------------------
  65. #define RetAddRef( p ) ( (p)->AddRef(), (p) )
  66. #define InlineAddRef( p ) ( (p)->AddRef(), (p) )
  67. //-----------------------------------------------------------------------------
  68. // Purpose: A class to both hold a pointer to an object and its reference.
  69. // Base exists to support other cleanup models
  70. //-----------------------------------------------------------------------------
  71. template <class T>
  72. class CBaseAutoPtr
  73. {
  74. public:
  75. CBaseAutoPtr() : m_pObject(0) {}
  76. CBaseAutoPtr(T *pFrom) : m_pObject(pFrom) {}
  77. operator const void *() const { return m_pObject; }
  78. operator void *() { return m_pObject; }
  79. operator const T *() const { return m_pObject; }
  80. operator const T *() { return m_pObject; }
  81. operator T *() { return m_pObject; }
  82. int operator=( int i ) { AssertMsg( i == 0, "Only NULL allowed on integer assign" ); m_pObject = 0; return 0; }
  83. T * operator=( T *p ) { m_pObject = p; return p; }
  84. bool operator !() const { return ( !m_pObject ); }
  85. bool operator!=( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (m_pObject != NULL); }
  86. bool operator==( const void *p ) const { return ( m_pObject == p ); }
  87. bool operator!=( const void *p ) const { return ( m_pObject != p ); }
  88. bool operator==( T *p ) const { return operator==( (void *)p ); }
  89. bool operator!=( T *p ) const { return operator!=( (void *)p ); }
  90. bool operator==( const CBaseAutoPtr<T> &p ) const { return operator==( (const void *)p ); }
  91. bool operator!=( const CBaseAutoPtr<T> &p ) const { return operator!=( (const void *)p ); }
  92. T * operator->() { return m_pObject; }
  93. T & operator *() { return *m_pObject; }
  94. T ** operator &() { return &m_pObject; }
  95. const T * operator->() const { return m_pObject; }
  96. const T & operator *() const { return *m_pObject; }
  97. T * const * operator &() const { return &m_pObject; }
  98. protected:
  99. CBaseAutoPtr( const CBaseAutoPtr<T> &from ) : m_pObject( from.m_pObject ) {}
  100. void operator=( const CBaseAutoPtr<T> &from ) { m_pObject = from.m_pObject; }
  101. T *m_pObject;
  102. };
  103. //---------------------------------------------------------
  104. template <class T>
  105. class CRefPtr : public CBaseAutoPtr<T>
  106. {
  107. typedef CBaseAutoPtr<T> BaseClass;
  108. public:
  109. CRefPtr() {}
  110. CRefPtr( T *pInit ) : BaseClass( pInit ) {}
  111. CRefPtr( const CRefPtr<T> &from ) : BaseClass( from ) {}
  112. ~CRefPtr() { if ( BaseClass::m_pObject ) BaseClass::m_pObject->Release(); }
  113. void operator=( const CRefPtr<T> &from ) { BaseClass::operator=( from ); }
  114. int operator=( int i ) { return BaseClass::operator=( i ); }
  115. T *operator=( T *p ) { return BaseClass::operator=( p ); }
  116. operator bool() const { return !BaseClass::operator!(); }
  117. operator bool() { return !BaseClass::operator!(); }
  118. void SafeRelease() { if ( BaseClass::m_pObject ) BaseClass::m_pObject->Release(); BaseClass::m_pObject = 0; }
  119. void AssignAddRef( T *pFrom ) { if (pFrom) pFrom->AddRef(); SafeRelease(); BaseClass::m_pObject = pFrom; }
  120. void AddRefAssignTo( T *&pTo ) { if ( BaseClass::m_pObject ) BaseClass::m_pObject->AddRef(); ::SafeRelease( pTo ); pTo = BaseClass::m_pObject; }
  121. };
  122. //-----------------------------------------------------------------------------
  123. // Purpose: Traits classes defining reference count threading model
  124. //-----------------------------------------------------------------------------
  125. class CRefMT
  126. {
  127. public:
  128. static int Increment( int *p) { return ThreadInterlockedIncrement( (int32 *)p ); }
  129. static int Decrement( int *p) { return ThreadInterlockedDecrement( (int32 *)p ); }
  130. };
  131. class CRefST
  132. {
  133. public:
  134. static int Increment( int *p) { return ++(*p); }
  135. static int Decrement( int *p) { return --(*p); }
  136. };
  137. //-----------------------------------------------------------------------------
  138. // Purpose: Actual reference counting implementation. Pulled out to reduce
  139. // code bloat.
  140. //-----------------------------------------------------------------------------
  141. template <const bool bSelfDelete, typename CRefThreading = CRefMT>
  142. class NO_VTABLE CRefCountServiceBase
  143. {
  144. protected:
  145. CRefCountServiceBase()
  146. : m_iRefs( 1 )
  147. {
  148. }
  149. virtual ~CRefCountServiceBase()
  150. {
  151. }
  152. virtual bool OnFinalRelease()
  153. {
  154. return true;
  155. }
  156. int GetRefCount() const
  157. {
  158. return m_iRefs;
  159. }
  160. int DoAddRef()
  161. {
  162. return CRefThreading::Increment( &m_iRefs );
  163. }
  164. int DoRelease()
  165. {
  166. int result = CRefThreading::Decrement( &m_iRefs );
  167. if ( result )
  168. return result;
  169. if ( OnFinalRelease() && bSelfDelete )
  170. delete this;
  171. return 0;
  172. }
  173. private:
  174. int m_iRefs;
  175. };
  176. class CRefCountServiceNull
  177. {
  178. protected:
  179. static int DoAddRef() { return 1; }
  180. static int DoRelease() { return 1; }
  181. };
  182. template <typename CRefThreading = CRefMT>
  183. class NO_VTABLE CRefCountServiceDestruct
  184. {
  185. protected:
  186. CRefCountServiceDestruct()
  187. : m_iRefs( 1 )
  188. {
  189. }
  190. virtual ~CRefCountServiceDestruct()
  191. {
  192. }
  193. int GetRefCount() const
  194. {
  195. return m_iRefs;
  196. }
  197. int DoAddRef()
  198. {
  199. return CRefThreading::Increment( &m_iRefs );
  200. }
  201. int DoRelease()
  202. {
  203. int result = CRefThreading::Decrement( &m_iRefs );
  204. if ( result )
  205. return result;
  206. this->~CRefCountServiceDestruct();
  207. return 0;
  208. }
  209. private:
  210. int m_iRefs;
  211. };
  212. typedef CRefCountServiceBase<true, CRefST> CRefCountServiceST;
  213. typedef CRefCountServiceBase<false, CRefST> CRefCountServiceNoDeleteST;
  214. typedef CRefCountServiceBase<true, CRefMT> CRefCountServiceMT;
  215. typedef CRefCountServiceBase<false, CRefMT> CRefCountServiceNoDeleteMT;
  216. // Default to threadsafe
  217. typedef CRefCountServiceNoDeleteMT CRefCountServiceNoDelete;
  218. typedef CRefCountServiceMT CRefCountService;
  219. //-----------------------------------------------------------------------------
  220. // Purpose: Base classes to implement reference counting
  221. //-----------------------------------------------------------------------------
  222. template < class REFCOUNT_SERVICE = CRefCountService >
  223. class NO_VTABLE CRefCounted : public REFCOUNT_SERVICE
  224. {
  225. public:
  226. virtual ~CRefCounted() {}
  227. int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
  228. int Release() { return REFCOUNT_SERVICE::DoRelease(); }
  229. };
  230. //-------------------------------------
  231. template < class BASE1, class REFCOUNT_SERVICE = CRefCountService >
  232. class NO_VTABLE CRefCounted1 : public BASE1,
  233. public REFCOUNT_SERVICE
  234. {
  235. public:
  236. virtual ~CRefCounted1() {}
  237. int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
  238. int Release() { return REFCOUNT_SERVICE::DoRelease(); }
  239. };
  240. //-------------------------------------
  241. template < class BASE1, class BASE2, class REFCOUNT_SERVICE = CRefCountService >
  242. class NO_VTABLE CRefCounted2 : public BASE1, public BASE2,
  243. public REFCOUNT_SERVICE
  244. {
  245. public:
  246. virtual ~CRefCounted2() {}
  247. int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
  248. int Release() { return REFCOUNT_SERVICE::DoRelease(); }
  249. };
  250. //-------------------------------------
  251. template < class BASE1, class BASE2, class BASE3, class REFCOUNT_SERVICE = CRefCountService >
  252. class NO_VTABLE CRefCounted3 : public BASE1, public BASE2, public BASE3,
  253. public REFCOUNT_SERVICE
  254. {
  255. virtual ~CRefCounted3() {}
  256. int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
  257. int Release() { return REFCOUNT_SERVICE::DoRelease(); }
  258. };
  259. //-------------------------------------
  260. template < class BASE1, class BASE2, class BASE3, class BASE4, class REFCOUNT_SERVICE = CRefCountService >
  261. class NO_VTABLE CRefCounted4 : public BASE1, public BASE2, public BASE3, public BASE4,
  262. public REFCOUNT_SERVICE
  263. {
  264. public:
  265. virtual ~CRefCounted4() {}
  266. int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
  267. int Release() { return REFCOUNT_SERVICE::DoRelease(); }
  268. };
  269. //-------------------------------------
  270. template < class BASE1, class BASE2, class BASE3, class BASE4, class BASE5, class REFCOUNT_SERVICE = CRefCountService >
  271. class NO_VTABLE CRefCounted5 : public BASE1, public BASE2, public BASE3, public BASE4, public BASE5,
  272. public REFCOUNT_SERVICE
  273. {
  274. public:
  275. virtual ~CRefCounted5() {}
  276. int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
  277. int Release() { return REFCOUNT_SERVICE::DoRelease(); }
  278. };
  279. //-----------------------------------------------------------------------------
  280. // Purpose: Class to throw around a reference counted item to debug
  281. // referencing problems
  282. //-----------------------------------------------------------------------------
  283. #if defined( __clang__ )
  284. template <class BASE_REFCOUNTED, int FINAL_REFS, const char *pszName>
  285. #else
  286. template <class BASE_REFCOUNTED, int FINAL_REFS = 0, const char *pszName = (const char *)NULL>
  287. #endif
  288. class CRefDebug : public BASE_REFCOUNTED
  289. {
  290. public:
  291. #ifdef _DEBUG
  292. CRefDebug()
  293. {
  294. AssertMsg( this->GetRefCount() == 1, "Expected initial ref count of 1" );
  295. DevMsg( "%s:create 0x%x\n", ( pszName ) ? pszName : "", this );
  296. }
  297. virtual ~CRefDebug()
  298. {
  299. AssertDevMsg( this->GetRefCount() == FINAL_REFS, "Object still referenced on destroy?" );
  300. DevMsg( "%s:destroy 0x%x\n", ( pszName ) ? pszName : "", this );
  301. }
  302. int AddRef()
  303. {
  304. DevMsg( "%s:(0x%x)->AddRef() --> %d\n", ( pszName ) ? pszName : "", this, this->GetRefCount() + 1 );
  305. return BASE_REFCOUNTED::AddRef();
  306. }
  307. int Release()
  308. {
  309. DevMsg( "%s:(0x%x)->Release() --> %d\n", ( pszName ) ? pszName : "", this, this->GetRefCount() - 1 );
  310. Assert( this->GetRefCount() > 0 );
  311. return BASE_REFCOUNTED::Release();
  312. }
  313. #endif
  314. };
  315. //-----------------------------------------------------------------------------
  316. #endif // REFCOUNT_H