//========= Copyright Valve Corporation, All rights reserved. ============// // // $Revision: $ // $NoKeywords: $ //===========================================================================// #ifndef UTLOBJECTREFERENCE_H #define UTLOBJECTREFERENCE_H #ifdef _WIN32 #pragma once #endif #include "tier1/utlintrusivelist.h" #include "mathlib/mathlib.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< CUtlReference > { 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