Team Fortress 2 Source Code as on 22/4/2020
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.

419 lines
12 KiB

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