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.
165 lines
3.2 KiB
165 lines
3.2 KiB
//========= 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 T> 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 T> class CUtlReferenceList : public CUtlIntrusiveDList< CUtlReference<T> > |
|
{ |
|
public: |
|
~CUtlReferenceList( void ) |
|
{ |
|
CUtlReference<T> *i = CUtlIntrusiveDList<CUtlReference<T> >::m_pHead; |
|
while( i ) |
|
{ |
|
CUtlReference<T> *n = i->m_pNext; |
|
i->m_pNext = NULL; |
|
i->m_pPrev = NULL; |
|
i->m_pObject = NULL; |
|
i = n; |
|
} |
|
CUtlIntrusiveDList<CUtlReference<T> >::m_pHead = NULL; |
|
} |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Put this macro in classes that are referenced by CUtlReference |
|
//----------------------------------------------------------------------------- |
|
#define DECLARE_REFERENCED_CLASS( _className ) \ |
|
private: \ |
|
CUtlReferenceList< _className > m_References; \ |
|
template<class T> friend class CUtlReference; |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|