initial
This commit is contained in:
586
public/tier1/utlhandletable.h
Normal file
586
public/tier1/utlhandletable.h
Normal file
@@ -0,0 +1,586 @@
|
||||
//====== Copyright <20> 1996-2004, 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 : 32 - 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
|
||||
|
||||
Reference in New Issue
Block a user