//===== Copyright © 1996-2006, 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" #include "tier1/utlvector.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( const CUtlReference& other ) { CUtlReference(); if ( other.IsValid() ) { AddRef( (T*)( other.GetObject() ) ); } } 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 bool IsValid( void) const { return ( m_pObject != NULL ); } FORCEINLINE operator T*() { return m_pObject; } FORCEINLINE operator const T*() const { return m_pObject; } FORCEINLINE T * GetObject( void ) { return m_pObject; } FORCEINLINE const T* GetObject( void ) 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==( T const *pOther ) const { return ( pOther == m_pObject ); } FORCEINLINE bool operator==( T *pOther ) const { return ( pOther == m_pObject ); } 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; template < class T > class CUtlReferenceVector : public CUtlBlockVector< CUtlReference< T > > { public: void RemoveAll() { for ( int i = 0; i < Count(); i++ ) { Element( i ).KillRef(); } CUtlBlockVector::RemoveAll(); } void FastRemove( int elem ) { Assert( IsValidIndex(elem) ); if (m_Size > 0) { if ( elem != m_Size -1 ) { Element(elem).Set( Element(m_Size-1).GetObject() ); } Destruct( &Element(m_Size-1) ); --m_Size; } } bool FindAndFastRemove( const CUtlReference< T >& src ) { int elem = Find( src ); if ( elem != -1 ) { FastRemove( elem ); return true; } return false; } void Remove( int elem ) { Assert( IsValidIndex(elem) ); if (m_Size > 0) { for ( int i = elem; i < ( m_Size - 1 ); i++ ) { Element( i ).Set( Element( i + 1 ).GetObject() ); } Destruct( &Element(m_Size-1) ); --m_Size; } } bool FindAndRemove( const CUtlReference< T >& src ) { int elem = Find( src ); if ( elem != -1 ) { Remove( elem ); return true; } return false; } private: // // Disallow methods of CUtlBlockVector that can cause element addresses to change, thus // breaking assumptions of CUtlReference. If any of these becomes needed just add a safe // implementation to the public section. // void RemoveMultiple( int elem, int num ); void RemoveMultipleFromHead(int num); void RemoveMultipleFromTail(int num); void Swap( CUtlReferenceVector< T > &vec ); void Purge(); void PurgeAndDeleteElements(); void Compact(); }; #endif