//========= Copyright Valve Corporation, All rights reserved. ============// // // $Revision: $ // $NoKeywords: $ //===========================================================================// #ifndef UTLOBJECTREFERENCE_H #define UTLOBJECTREFERENCE_H #ifdef _WIN32 #pragma once #endif #include "mathlib/mathlib.h" #include "tier1/utlintrusivelist.h" // Purpose: class for keeping track of all the references that exist to an // object. When the object being referenced is freed, all of the references // pointing at it will become null. // // To Use: // Add a DECLARE_REFERENCED_CLASS to the class that you want to use // CutlReferences with. Replace pointers to that class with CUtlReferences. // Check these references for null in appropriate places. // // NOTE : You can still happily use pointers instead of references where you // want to - these pointers will not magically become null like references // would, but if you know no one is going to delete the underlying object // during a partcular section of code, it doesn't matter. Basically, // CUtlReferences don't rely on every use of an object using one. template class CUtlReference { public: FORCEINLINE CUtlReference(void) { m_pNext = m_pPrev = NULL; m_pObject = NULL; } FORCEINLINE CUtlReference(T *pObj) { m_pNext = m_pPrev = NULL; AddRef(pObj); } FORCEINLINE ~CUtlReference(void) { KillRef(); } FORCEINLINE void Set(T *pObj) { if (m_pObject != pObj) { KillRef(); AddRef(pObj); } } FORCEINLINE T *operator()(void) const { return m_pObject; } FORCEINLINE operator T *() { return m_pObject; } FORCEINLINE operator const T *() const { return m_pObject; } FORCEINLINE T *operator->() { return m_pObject; } FORCEINLINE const T *operator->() const { return m_pObject; } FORCEINLINE CUtlReference &operator=(const CUtlReference &otherRef) { Set(otherRef.m_pObject); return *this; } FORCEINLINE CUtlReference &operator=(T *pObj) { Set(pObj); return *this; } FORCEINLINE bool operator==(const CUtlReference &o) const { return (o.m_pObject == m_pObject); } public: CUtlReference *m_pNext; CUtlReference *m_pPrev; T *m_pObject; FORCEINLINE void AddRef(T *pObj) { m_pObject = pObj; if (pObj) { pObj->m_References.AddToHead(this); } } FORCEINLINE void KillRef(void) { if (m_pObject) { m_pObject->m_References.RemoveNode(this); m_pObject = NULL; } } }; template class CUtlReferenceList : public CUtlIntrusiveDList > { public: ~CUtlReferenceList(void) { CUtlReference *i = CUtlIntrusiveDList >::m_pHead; while (i) { CUtlReference *n = i->m_pNext; i->m_pNext = NULL; i->m_pPrev = NULL; i->m_pObject = NULL; i = n; } CUtlIntrusiveDList >::m_pHead = NULL; } }; //----------------------------------------------------------------------------- // Put this macro in classes that are referenced by CUtlReference //----------------------------------------------------------------------------- #define DECLARE_REFERENCED_CLASS(_className) \ private: \ CUtlReferenceList<_className> m_References; \ template \ friend class CUtlReference; #endif