//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //============================================================================= #ifndef UTLHANDLETABLE_H #define UTLHANDLETABLE_H #ifdef _WIN32 #pragma once #endif #include "tier1/utlvector.h" #include "tier1/utlqueue.h" //----------------------------------------------------------------------------- // Handles are 32 bits. Invalid handles are all 1s //----------------------------------------------------------------------------- typedef unsigned int UtlHandle_t; #define UTLHANDLE_INVALID ((UtlHandle_t)~0) //----------------------------------------------------------------------------- // Purpose: This is a table used to allocate handles // HandleBits specifies the max # of simultaneously allocated handles. // An extra bit is used for the validity state // The rest of the 32 bits are used for a serial number //----------------------------------------------------------------------------- template< class T, int HandleBits > class CUtlHandleTable { public: CUtlHandleTable(); // Allocate, deallocate handles UtlHandle_t AddHandle(); void RemoveHandle( UtlHandle_t h ); // Set/get handle values void SetHandle( UtlHandle_t h, T *pData ); T *GetHandle( UtlHandle_t h ) const; T *GetHandle( UtlHandle_t h, bool checkValidity ) const; // Is a handle valid? bool IsHandleValid( UtlHandle_t h ) const; // Iterate over handles; they may not be valid unsigned int GetValidHandleCount() const; unsigned int GetHandleCount() const; UtlHandle_t GetHandleFromIndex( int i ) const; int GetIndexFromHandle( UtlHandle_t h ) const; void MarkHandleInvalid( UtlHandle_t h ); void MarkHandleValid( UtlHandle_t h ); private: struct HandleType_t { HandleType_t( unsigned int i, unsigned int s ) : nIndex( i ), nSerial( s ) { Assert( i < ( 1 << HandleBits ) ); Assert( s < ( 1 << ( 31 - HandleBits ) ) ); } unsigned int nIndex : HandleBits; unsigned int nSerial : 31 - HandleBits; }; struct EntryType_t { EntryType_t() : m_nSerial( 0 ), nInvalid( 0 ), m_pData( 0 ) {} unsigned int m_nSerial : 31; unsigned int nInvalid : 1; T *m_pData; }; static unsigned int GetSerialNumber( UtlHandle_t handle ); static unsigned int GetListIndex( UtlHandle_t handle ); static UtlHandle_t CreateHandle( unsigned int nSerial, unsigned int nIndex ); const EntryType_t *GetEntry( UtlHandle_t handle, bool checkValidity ) const; unsigned int m_nValidHandles; CUtlVector< EntryType_t > m_list; CUtlQueue< int > m_unused; }; //----------------------------------------------------------------------------- // Constructor, destructor //----------------------------------------------------------------------------- template< class T, int HandleBits > CUtlHandleTable::CUtlHandleTable() : m_nValidHandles( 0 ) { } //----------------------------------------------------------------------------- // Allocate, deallocate handles //----------------------------------------------------------------------------- template< class T, int HandleBits > UtlHandle_t CUtlHandleTable::AddHandle() { unsigned int nIndex = ( m_unused.Count() > 0 ) ? m_unused.RemoveAtHead() : m_list.AddToTail(); EntryType_t &entry = m_list[ nIndex ]; entry.nInvalid = 0; entry.m_pData = NULL; ++m_nValidHandles; return CreateHandle( entry.m_nSerial, nIndex ); } template< class T, int HandleBits > void CUtlHandleTable::RemoveHandle( UtlHandle_t handle ) { unsigned int nIndex = GetListIndex( handle ); Assert( nIndex < ( unsigned int )m_list.Count() ); if ( nIndex >= ( unsigned int )m_list.Count() ) return; EntryType_t &entry = m_list[ nIndex ]; ++entry.m_nSerial; // mark old serial# invalid if ( !entry.nInvalid ) { entry.nInvalid = 1; --m_nValidHandles; } entry.m_pData = NULL; // If a handle has been used this many times, then we need to take it out of service, otherwise if the // serial # wraps around we'll possibly revalidate old handles and they'll start to point at the wrong objects. Unlikely, but possible. bool bStopUsing = ( entry.m_nSerial >= ( (1 << ( 31 - HandleBits ) ) - 1 ) ); if ( !bStopUsing ) { m_unused.Insert( nIndex ); } } //----------------------------------------------------------------------------- // Set/get handle values //----------------------------------------------------------------------------- template< class T, int HandleBits > void CUtlHandleTable::SetHandle( UtlHandle_t handle, T *pData ) { EntryType_t *entry = const_cast< EntryType_t* >( GetEntry( handle, false ) ); Assert( entry ); if ( entry == NULL ) return; // Validate the handle if ( entry->nInvalid ) { ++m_nValidHandles; entry->nInvalid = 0; } entry->m_pData = pData; } template< class T, int HandleBits > T *CUtlHandleTable::GetHandle( UtlHandle_t handle ) const { const EntryType_t *entry = GetEntry( handle, true ); return entry ? entry->m_pData : NULL; } template< class T, int HandleBits > T *CUtlHandleTable::GetHandle( UtlHandle_t handle, bool checkValidity ) const { const EntryType_t *entry = GetEntry( handle, checkValidity ); return entry ? entry->m_pData : NULL; } //----------------------------------------------------------------------------- // Is a handle valid? //----------------------------------------------------------------------------- template< class T, int HandleBits > bool CUtlHandleTable::IsHandleValid( UtlHandle_t handle ) const { if ( handle == UTLHANDLE_INVALID ) return false; unsigned int nIndex = GetListIndex( handle ); AssertOnce( nIndex < ( unsigned int )m_list.Count() ); if ( nIndex >= ( unsigned int )m_list.Count() ) return false; const EntryType_t &entry = m_list[ nIndex ]; if ( entry.m_nSerial != GetSerialNumber( handle ) ) return false; if ( 1 == entry.nInvalid ) return false; return true; } //----------------------------------------------------------------------------- // Current max handle //----------------------------------------------------------------------------- template< class T, int HandleBits > unsigned int CUtlHandleTable::GetValidHandleCount() const { return m_nValidHandles; } template< class T, int HandleBits > unsigned int CUtlHandleTable::GetHandleCount() const { return m_list.Count(); } template< class T, int HandleBits > UtlHandle_t CUtlHandleTable::GetHandleFromIndex( int i ) const { if ( m_list[i].m_pData ) return CreateHandle( m_list[i].m_nSerial, i ); return UTLHANDLE_INVALID; } template< class T, int HandleBits > int CUtlHandleTable::GetIndexFromHandle( UtlHandle_t h ) const { if ( h == UTLHANDLE_INVALID ) return -1; return GetListIndex( h ); } //----------------------------------------------------------------------------- // Cracking handles into indices + serial numbers //----------------------------------------------------------------------------- template< class T, int HandleBits > unsigned int CUtlHandleTable::GetSerialNumber( UtlHandle_t handle ) { return ( ( HandleType_t* )&handle )->nSerial; } template< class T, int HandleBits > unsigned int CUtlHandleTable::GetListIndex( UtlHandle_t handle ) { return ( ( HandleType_t* )&handle )->nIndex; } template< class T, int HandleBits > UtlHandle_t CUtlHandleTable::CreateHandle( unsigned int nSerial, unsigned int nIndex ) { HandleType_t h( nIndex, nSerial ); return *( UtlHandle_t* )&h; } //----------------------------------------------------------------------------- // Looks up a entry by handle //----------------------------------------------------------------------------- template< class T, int HandleBits > const typename CUtlHandleTable::EntryType_t *CUtlHandleTable::GetEntry( UtlHandle_t handle, bool checkValidity ) const { if ( handle == UTLHANDLE_INVALID ) return NULL; unsigned int nIndex = GetListIndex( handle ); Assert( nIndex < ( unsigned int )m_list.Count() ); if ( nIndex >= ( unsigned int )m_list.Count() ) return NULL; const EntryType_t &entry = m_list[ nIndex ]; if ( entry.m_nSerial != GetSerialNumber( handle ) ) return NULL; if ( checkValidity && ( 1 == entry.nInvalid ) ) return NULL; return &entry; } template< class T, int HandleBits > void CUtlHandleTable::MarkHandleInvalid( UtlHandle_t handle ) { if ( handle == UTLHANDLE_INVALID ) return; unsigned int nIndex = GetListIndex( handle ); Assert( nIndex < ( unsigned int )m_list.Count() ); if ( nIndex >= ( unsigned int )m_list.Count() ) return; EntryType_t &entry = m_list[ nIndex ]; if ( entry.m_nSerial != GetSerialNumber( handle ) ) return; if ( !entry.nInvalid ) { --m_nValidHandles; entry.nInvalid = 1; } } template< class T, int HandleBits > void CUtlHandleTable::MarkHandleValid( UtlHandle_t handle ) { if ( handle == UTLHANDLE_INVALID ) return; unsigned int nIndex = GetListIndex( handle ); Assert( nIndex < ( unsigned int )m_list.Count() ); if ( nIndex >= ( unsigned int )m_list.Count() ) return; EntryType_t &entry = m_list[ nIndex ]; if ( entry.m_nSerial != GetSerialNumber( handle ) ) return; if ( entry.nInvalid ) { ++m_nValidHandles; entry.nInvalid = 0; } } //----------------------------------------------------------------------------- // Handle wrapper. Assumes 2 things // 1) That class T has a non-static method called GetHandle which returns a UtlHandle_t // 2) That class T has a static method called GetPtrFromHandle which returns a T* given a UtlHandle_t // 3) That class T has a static method called IsHandleValid which accepts a UtlHandle_t //----------------------------------------------------------------------------- template< class T > class CUtlHandle { public: // Constructors CUtlHandle(); explicit CUtlHandle( T *pObject ); CUtlHandle( UtlHandle_t h ); CUtlHandle( const CUtlHandle &h ); // Assignment void Set( T *pObject ); void Set( UtlHandle_t h ); const CUtlHandle &operator=( UtlHandle_t h ); const CUtlHandle &operator=( T *pObject ); // Retrieval T *Get(); const T* Get() const; // Is the handle valid? bool IsValid() const; // Casting operator T*(); operator UtlHandle_t(); operator bool(); T* operator->(); const T* operator->() const; // Equality bool operator==( CUtlHandle h ) const; bool operator==( T *pObject ) const; bool operator==( UtlHandle_t h ) const; bool operator!=( CUtlHandle h ) const; bool operator!=( T *pObject ) const; bool operator!=( UtlHandle_t h ) const; private: UtlHandle_t m_handle; }; //----------------------------------------------------------------------------- // Constructors //----------------------------------------------------------------------------- template< class T > CUtlHandle::CUtlHandle() : m_handle( UTLHANDLE_INVALID ) { } template< class T > CUtlHandle::CUtlHandle( T *pObject ) { Set( pObject ); } template< class T > CUtlHandle::CUtlHandle( UtlHandle_t h ) { m_handle = h; } template< class T > CUtlHandle::CUtlHandle( const CUtlHandle &h ) { m_handle = h.m_handle; } //----------------------------------------------------------------------------- // Assignment //----------------------------------------------------------------------------- template< class T > void CUtlHandle::Set( T *pObject ) { // Assumes T has a member function GetHandle m_handle = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID; } template< class T > void CUtlHandle::Set( UtlHandle_t h ) { m_handle = h; } template< class T > const CUtlHandle &CUtlHandle::operator=( UtlHandle_t h ) { Set( h ); return *this; } template< class T > const CUtlHandle &CUtlHandle::operator=( T *pObject ) { Set( pObject ); return *this; } //----------------------------------------------------------------------------- // Is the handle valid? //----------------------------------------------------------------------------- template< class T > bool CUtlHandle::IsValid() const { // Assumes T has a static member function IsHandleValid return T::IsHandleValid( m_handle ); } //----------------------------------------------------------------------------- // Retrieval //----------------------------------------------------------------------------- template< class T > T *CUtlHandle::Get() { // Assumes T has a static member function GetPtrFromHandle return T::GetPtrFromHandle( m_handle ); } template< class T > const T* CUtlHandle::Get() const { // Assumes T has a static member function GetPtrFromHandle return T::GetPtrFromHandle( m_handle ); } //----------------------------------------------------------------------------- // Casting //----------------------------------------------------------------------------- template< class T > CUtlHandle::operator T*() { return Get(); } template< class T > CUtlHandle::operator UtlHandle_t() { return m_handle; } template< class T > T* CUtlHandle::operator->() { return Get(); } template< class T > const T* CUtlHandle::operator->() const { return Get(); } template< class T > CUtlHandle::operator bool() { return m_handle != UTLHANDLE_INVALID; } //----------------------------------------------------------------------------- // Equality //----------------------------------------------------------------------------- template< class T > bool CUtlHandle::operator==( CUtlHandle h ) const { return m_handle == h.m_handle; } template< class T > bool CUtlHandle::operator==( T *pObject ) const { UtlHandle_t h = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID; return m_handle == h; } template< class T > bool CUtlHandle::operator==( UtlHandle_t h ) const { return m_handle == h; } template< class T > bool CUtlHandle::operator!=( CUtlHandle h ) const { return m_handle != h.m_handle; } template< class T > bool CUtlHandle::operator!=( T *pObject ) const { UtlHandle_t h = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID; return m_handle != h; } template< class T > bool CUtlHandle::operator!=( UtlHandle_t h ) const { return m_handle != h; } //----------------------------------------------------------------------------- // Add this macro to a class definition to hook in handles for it! //----------------------------------------------------------------------------- #define DECLARE_HANDLES( _className, _handleBitCount ) \ public: \ UtlHandle_t GetHandle() \ { \ return m_Handle; \ } \ static _className* GetPtrFromHandle( UtlHandle_t h ) \ { \ return m_HandleTable.GetHandle( h ); \ } \ static bool IsHandleValid( UtlHandle_t h ) \ { \ return m_HandleTable.IsHandleValid( h ); \ } \ private: \ UtlHandle_t m_Handle; \ static CUtlHandleTable< _className, _handleBitCount > m_HandleTable //----------------------------------------------------------------------------- // Add this macro to a .cpp file to hook in handles for it! //----------------------------------------------------------------------------- #define IMPLEMENT_HANDLES( _className, _handleBitCount ) \ CUtlHandleTable< _className, _handleBitCount > _className::m_HandleTable; //----------------------------------------------------------------------------- // Add these macro to the class constructor + destructor //----------------------------------------------------------------------------- #define CONSTRUCT_HANDLE( ) \ m_Handle = m_HandleTable.AddHandle(); \ m_HandleTable.SetHandle( m_Handle, this ) #define DESTRUCT_HANDLE() \ m_HandleTable.RemoveHandle( m_Handle ); \ m_Handle = UTLHANDLE_INVALID #endif // UTLHANDLETABLE_H