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.
600 lines
16 KiB
600 lines
16 KiB
//========= 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 |
|
{ |
|
// MoeMod : use union to fix strict alias bug |
|
HandleType_t( unsigned int i, unsigned int s ) : nIndex( i ), nSerial( s ) |
|
{ |
|
Assert( i < ( 1 << HandleBits ) ); |
|
Assert( s < ( 1 << ( 31 - HandleBits ) ) ); |
|
} |
|
HandleType_t( UtlHandle_t handle ) : handle(handle) {} |
|
|
|
union { |
|
UtlHandle_t handle; |
|
struct { |
|
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; |
|
//return (handle >> HandleBits) & ((1 << (32 - HandleBits)) - 1); |
|
return HandleType_t(handle).nSerial; |
|
} |
|
|
|
template< class T, int HandleBits > |
|
unsigned int CUtlHandleTable<T, HandleBits>::GetListIndex( UtlHandle_t handle ) |
|
{ |
|
//return ( ( HandleType_t* )&handle )->nIndex; |
|
//return handle & ((1 << HandleBits) - 1); |
|
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; |
|
//return (nIndex & ((1 << HandleBits) - 1)) | (nSerial << HandleBits); |
|
return h.handle; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// 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 |
|
|
|
|