diff options
Diffstat (limited to 'public/tier1/utlhandletable.h')
| -rw-r--r-- | public/tier1/utlhandletable.h | 586 |
1 files changed, 586 insertions, 0 deletions
diff --git a/public/tier1/utlhandletable.h b/public/tier1/utlhandletable.h new file mode 100644 index 0000000..22f5435 --- /dev/null +++ b/public/tier1/utlhandletable.h @@ -0,0 +1,586 @@ +//========= 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<T, HandleBits>::CUtlHandleTable() : m_nValidHandles( 0 ) +{ +} + + +//----------------------------------------------------------------------------- +// Allocate, deallocate handles +//----------------------------------------------------------------------------- +template< class T, int HandleBits > +UtlHandle_t CUtlHandleTable<T, HandleBits>::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<T, HandleBits>::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<T, HandleBits>::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<T, HandleBits>::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<T, HandleBits>::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<T, HandleBits>::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<T, HandleBits>::GetValidHandleCount() const +{ + return m_nValidHandles; +} + +template< class T, int HandleBits > +unsigned int CUtlHandleTable<T, HandleBits>::GetHandleCount() const +{ + return m_list.Count(); +} + +template< class T, int HandleBits > +UtlHandle_t CUtlHandleTable<T, HandleBits>::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<T, HandleBits>::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<T, HandleBits>::GetSerialNumber( UtlHandle_t handle ) +{ + return ( ( HandleType_t* )&handle )->nSerial; +} + +template< class T, int HandleBits > +unsigned int CUtlHandleTable<T, HandleBits>::GetListIndex( UtlHandle_t handle ) +{ + return ( ( HandleType_t* )&handle )->nIndex; +} + +template< class T, int HandleBits > +UtlHandle_t CUtlHandleTable<T, HandleBits>::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<T, HandleBits>::EntryType_t *CUtlHandleTable<T, HandleBits>::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<T, HandleBits>::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<T, HandleBits>::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<T> &h ); + + // Assignment + void Set( T *pObject ); + void Set( UtlHandle_t h ); + const CUtlHandle<T> &operator=( UtlHandle_t h ); + const CUtlHandle<T> &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<T> h ) const; + bool operator==( T *pObject ) const; + bool operator==( UtlHandle_t h ) const; + bool operator!=( CUtlHandle<T> h ) const; + bool operator!=( T *pObject ) const; + bool operator!=( UtlHandle_t h ) const; + +private: + UtlHandle_t m_handle; +}; + + +//----------------------------------------------------------------------------- +// Constructors +//----------------------------------------------------------------------------- +template< class T > +CUtlHandle<T>::CUtlHandle() : m_handle( UTLHANDLE_INVALID ) +{ +} + +template< class T > +CUtlHandle<T>::CUtlHandle( T *pObject ) +{ + Set( pObject ); +} + +template< class T > +CUtlHandle<T>::CUtlHandle( UtlHandle_t h ) +{ + m_handle = h; +} + +template< class T > +CUtlHandle<T>::CUtlHandle( const CUtlHandle<T> &h ) +{ + m_handle = h.m_handle; +} + + +//----------------------------------------------------------------------------- +// Assignment +//----------------------------------------------------------------------------- +template< class T > +void CUtlHandle<T>::Set( T *pObject ) +{ + // Assumes T has a member function GetHandle + m_handle = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID; +} + +template< class T > +void CUtlHandle<T>::Set( UtlHandle_t h ) +{ + m_handle = h; +} + +template< class T > +const CUtlHandle<T> &CUtlHandle<T>::operator=( UtlHandle_t h ) +{ + Set( h ); + return *this; +} + +template< class T > +const CUtlHandle<T> &CUtlHandle<T>::operator=( T *pObject ) +{ + Set( pObject ); + return *this; +} + + +//----------------------------------------------------------------------------- +// Is the handle valid? +//----------------------------------------------------------------------------- +template< class T > +bool CUtlHandle<T>::IsValid() const +{ + // Assumes T has a static member function IsHandleValid + return T::IsHandleValid( m_handle ); +} + + +//----------------------------------------------------------------------------- +// Retrieval +//----------------------------------------------------------------------------- +template< class T > +T *CUtlHandle<T>::Get() +{ + // Assumes T has a static member function GetPtrFromHandle + return T::GetPtrFromHandle( m_handle ); +} + +template< class T > +const T* CUtlHandle<T>::Get() const +{ + // Assumes T has a static member function GetPtrFromHandle + return T::GetPtrFromHandle( m_handle ); +} + + +//----------------------------------------------------------------------------- +// Casting +//----------------------------------------------------------------------------- +template< class T > +CUtlHandle<T>::operator T*() +{ + return Get(); +} + +template< class T > +CUtlHandle<T>::operator UtlHandle_t() +{ + return m_handle; +} + +template< class T > +T* CUtlHandle<T>::operator->() +{ + return Get(); +} + +template< class T > +const T* CUtlHandle<T>::operator->() const +{ + return Get(); +} + +template< class T > +CUtlHandle<T>::operator bool() +{ + return m_handle != UTLHANDLE_INVALID; +} + + +//----------------------------------------------------------------------------- +// Equality +//----------------------------------------------------------------------------- +template< class T > +bool CUtlHandle<T>::operator==( CUtlHandle<T> h ) const +{ + return m_handle == h.m_handle; +} + +template< class T > +bool CUtlHandle<T>::operator==( T *pObject ) const +{ + UtlHandle_t h = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID; + return m_handle == h; +} + +template< class T > +bool CUtlHandle<T>::operator==( UtlHandle_t h ) const +{ + return m_handle == h; +} + +template< class T > +bool CUtlHandle<T>::operator!=( CUtlHandle<T> h ) const +{ + return m_handle != h.m_handle; +} + +template< class T > +bool CUtlHandle<T>::operator!=( T *pObject ) const +{ + UtlHandle_t h = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID; + return m_handle != h; +} + +template< class T > +bool CUtlHandle<T>::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 + |