This commit is contained in:
nephacks
2025-06-04 03:22:50 +02:00
parent f234f23848
commit f12416cffd
14243 changed files with 6446499 additions and 26 deletions

185
public/tier1/UtlStringMap.h Normal file
View File

@@ -0,0 +1,185 @@
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#ifndef UTLSTRINGMAP_H
#define UTLSTRINGMAP_H
#ifdef _WIN32
#pragma once
#endif
#include "utlsymbol.h"
template <class T>
class CUtlStringMap
{
public:
typedef UtlSymId_t IndexType_t;
CUtlStringMap( bool caseInsensitive = true, int initsize = 32 ) :
m_SymbolTable( 0, 32, caseInsensitive ),
m_Vector( initsize )
{
}
// Get data by the string itself:
T& operator[]( const char *pString )
{
CUtlSymbol symbol = m_SymbolTable.AddString( pString );
int index = ( int )( UtlSymId_t )symbol;
if( m_Vector.Count() <= index )
{
m_Vector.EnsureCount( index + 1 );
}
return m_Vector[index];
}
// Get data by the string's symbol table ID - only used to retrieve a pre-existing symbol, not create a new one!
T& operator[]( UtlSymId_t n )
{
Assert( n <= m_Vector.Count() );
return m_Vector[n];
}
const T& operator[]( UtlSymId_t n ) const
{
Assert( n <= m_Vector.Count() );
return m_Vector[n];
}
unsigned int Count() const
{
Assert( m_Vector.Count() == m_SymbolTable.GetNumStrings() );
return m_Vector.Count();
}
bool Defined( const char *pString ) const
{
return m_SymbolTable.Find( pString ) != UTL_INVAL_SYMBOL;
}
UtlSymId_t Find( const char *pString ) const
{
return m_SymbolTable.Find( pString );
}
UtlSymId_t AddString( const char *pString )
{
CUtlSymbol symbol = m_SymbolTable.AddString( pString );
int index = ( int )( UtlSymId_t )symbol;
if( m_Vector.Count() <= index )
{
m_Vector.EnsureCount( index + 1 );
}
return symbol;
}
/// Add a string to the map and also insert an item at
/// its location in the same operation. Returns the
/// newly created index (or the one that was just
/// overwritten, if pString already existed.)
UtlSymId_t Insert( const char *pString, const T &item )
{
CUtlSymbol symbol = m_SymbolTable.AddString( pString );
UtlSymId_t index = symbol; // implicit coercion
if ( m_Vector.Count() > index )
{
// this string is already in the dictionary.
}
else if ( m_Vector.Count() == index )
{
// this is the expected case when we've added one more to the tail.
m_Vector.AddToTail( item );
}
else // ( m_Vector.Count() < index )
{
// this is a strange shouldn't-happen case.
AssertMsg( false, "CUtlStringMap insert unexpected entries." );
m_Vector.EnsureCount( index + 1 );
m_Vector[index] = item;
}
return index;
}
/// iterate, not in any particular order.
IndexType_t First() const
{
if ( Count() > 0 )
{
return 0;
}
else
{
return InvalidIndex();
}
}
static UtlSymId_t InvalidIndex()
{
return UTL_INVAL_SYMBOL;
}
// iterators (for uniformity with other map types)
inline UtlSymId_t Head() const
{
return m_SymbolTable.GetNumStrings() > 0 ? 0 : InvalidIndex();
}
inline UtlSymId_t Next( const UtlSymId_t &i ) const
{
UtlSymId_t n = i+1;
return n < m_SymbolTable.GetNumStrings() ? n : InvalidIndex();
}
int GetNumStrings( void ) const
{
return m_SymbolTable.GetNumStrings();
}
const char *String( int n ) const
{
return m_SymbolTable.String( n );
}
// Clear all of the data from the map
void Clear()
{
m_Vector.RemoveAll();
m_SymbolTable.RemoveAll();
}
void Purge()
{
m_Vector.Purge();
m_SymbolTable.RemoveAll();
}
void PurgeAndDeleteElements()
{
m_Vector.PurgeAndDeleteElements();
m_SymbolTable.RemoveAll();
}
private:
CUtlVector<T> m_Vector;
CUtlSymbolTable m_SymbolTable;
};
template< class T >
class CUtlStringMapAutoPurge : public CUtlStringMap < T >
{
public:
~CUtlStringMapAutoPurge( void )
{
this->PurgeAndDeleteElements();
}
};
#endif // UTLSTRINGMAP_H

View File

@@ -0,0 +1,69 @@
// ======= Copyright (c) 2009, Valve Corporation, All rights reserved. =========
//
// appinstance.h
//
// Purpose: Provide a simple way to enforce that only one instance of an
// application is running on a machine at any one time.
//
// Usage: declare a global object of CSingleAppInstance type, with the unique name
// you want to use wrapped in the TEXT( " " ) macro.
//
// upon entering main you can check the IsUniqueInstance() method to determine if another instance is running
// or you can call the CheckForOtherRunningInstances() method to perform the check AND optinally
// pop up a message box to the user, and/or have the program terminate
//
// Example:
//
// CSingleAppInstance g_ThisAppInstance( TEXT("this_source_app") );
//
// void main(int argc,char **argv)
// {
// if ( g_ThisAppInstance.CheckForOtherRunningInstances() ) return;
//
// .. rest of code ..
//
// Notes: Currently this object only works when IsPlatformWindows() is true
// i.e. no Xbox 360, linux, or Mac yet..
// (feel free to impliment)
//
// ===========================================================================
#ifndef APPINSTANCE_H
#define APPINSTANCE_H
#ifdef _WIN32
#pragma once
#endif
// check if handle is defined rather than inlcude another header
#ifndef HANDLE
typedef void *HANDLE;
#endif
class CSingleAppInstance
{
public:
explicit CSingleAppInstance( tchar* InstanceName, bool exitOnNotUnique = false, bool displayMsgIfNotUnique = false );
~CSingleAppInstance();
bool CheckForOtherRunningInstances( bool exitOnNotUnique = false, bool displayMsgIfNotUnique = true );
static bool CheckForRunningInstance( tchar* InstanceName );
bool IsUniqueInstance() { return m_isUniqueInstance; }
HANDLE GetHandle() { return reinterpret_cast< HANDLE >( (intp) m_hMutex ); }
private:
CSingleAppInstance(); // Hidden for a reason. You must specify the instance name
#ifdef OSX
char m_szLockPath[ MAX_PATH ];
int m_hMutex;
#else
HANDLE m_hMutex;
#endif
bool m_isUniqueInstance;
};
#endif

1591
public/tier1/bitbuf.h Normal file

File diff suppressed because it is too large Load Diff

268
public/tier1/byteswap.h Normal file
View File

@@ -0,0 +1,268 @@
//========= Copyright <20> 1996-2006, Valve LLC, All rights reserved. ============
//
// Purpose: Low level byte swapping routines.
//
// $NoKeywords: $
//=============================================================================
#ifndef BYTESWAP_H
#define BYTESWAP_H
#if defined(_WIN32)
#pragma once
#endif
#include "tier0/dbg.h"
#include "datamap.h" // needed for typedescription_t. note datamap.h is tier1 as well.
class CByteswap
{
public:
CByteswap()
{
// Default behavior sets the target endian to match the machine native endian (no swap).
SetTargetBigEndian( IsMachineBigEndian() );
}
//-----------------------------------------------------------------------------
// Write a single field.
//-----------------------------------------------------------------------------
void SwapFieldToTargetEndian( void* pOutputBuffer, void *pData, typedescription_t *pField );
//-----------------------------------------------------------------------------
// Write a block of fields. Works a bit like the saverestore code.
//-----------------------------------------------------------------------------
void SwapFieldsToTargetEndian( void *pOutputBuffer, void *pBaseData, datamap_t *pDataMap );
// Swaps fields for the templated type to the output buffer.
template<typename T> inline void SwapFieldsToTargetEndian( T* pOutputBuffer, void *pBaseData, unsigned int objectCount = 1 )
{
for ( unsigned int i = 0; i < objectCount; ++i, ++pOutputBuffer )
{
SwapFieldsToTargetEndian( (void*)pOutputBuffer, pBaseData, &T::m_DataMap );
pBaseData = (byte*)pBaseData + sizeof(T);
}
}
// Swaps fields for the templated type in place.
template<typename T> inline void SwapFieldsToTargetEndian( T* pOutputBuffer, unsigned int objectCount = 1 )
{
SwapFieldsToTargetEndian<T>( pOutputBuffer, (void*)pOutputBuffer, objectCount );
}
//-----------------------------------------------------------------------------
// True if the current machine is detected as big endian.
// (Endienness is effectively detected at compile time when optimizations are
// enabled)
//-----------------------------------------------------------------------------
static bool IsMachineBigEndian()
{
short nIsBigEndian = 1;
// if we are big endian, the first byte will be a 0, if little endian, it will be a one.
return (bool)(0 == *(char *)&nIsBigEndian );
}
//-----------------------------------------------------------------------------
// Sets the target byte ordering we are swapping to or from.
//
// Braindead Endian Reference:
// x86 is LITTLE Endian
// PowerPC is BIG Endian
//-----------------------------------------------------------------------------
inline void SetTargetBigEndian( bool bigEndian )
{
m_bBigEndian = bigEndian;
m_bSwapBytes = IsMachineBigEndian() != bigEndian;
}
// Changes target endian
inline void FlipTargetEndian( void )
{
m_bSwapBytes = !m_bSwapBytes;
m_bBigEndian = !m_bBigEndian;
}
// Forces byte swapping state, regardless of endianess
inline void ActivateByteSwapping( bool bActivate )
{
SetTargetBigEndian( IsMachineBigEndian() != bActivate );
}
//-----------------------------------------------------------------------------
// Returns true if the target machine is the same as this one in endianness.
//
// Used to determine when a byteswap needs to take place.
//-----------------------------------------------------------------------------
inline bool IsSwappingBytes( void ) // Are bytes being swapped?
{
return m_bSwapBytes;
}
inline bool IsTargetBigEndian( void ) // What is the current target endian?
{
return m_bBigEndian;
}
//-----------------------------------------------------------------------------
// IsByteSwapped()
//
// When supplied with a chunk of input data and a constant or magic number
// (in native format) determines the endienness of the current machine in
// relation to the given input data.
//
// Returns:
// 1 if input is the same as nativeConstant.
// 0 if input is byteswapped relative to nativeConstant.
// -1 if input is not the same as nativeConstant and not byteswapped either.
//
// ( This is useful for detecting byteswapping in magic numbers in structure
// headers for example. )
//-----------------------------------------------------------------------------
template<typename T> inline int SourceIsNativeEndian( T input, T nativeConstant )
{
// If it's the same, it isn't byteswapped:
if( input == nativeConstant )
return 1;
int output;
LowLevelByteSwap<T>( &output, &input );
if( output == nativeConstant )
return 0;
Assert( 0 ); // if we get here, input is neither a swapped nor unswapped version of nativeConstant.
return -1;
}
//-----------------------------------------------------------------------------
// Swaps an input buffer full of type T into the given output buffer.
//
// Swaps [count] items from the inputBuffer to the outputBuffer.
// If inputBuffer is omitted or NULL, then it is assumed to be the same as
// outputBuffer - effectively swapping the contents of the buffer in place.
//-----------------------------------------------------------------------------
template<typename T> inline void SwapBuffer( T* outputBuffer, T* inputBuffer = NULL, int count = 1 )
{
Assert( count >= 0 );
Assert( outputBuffer );
// Fail gracefully in release:
if( count <=0 || !outputBuffer )
return;
// Optimization for the case when we are swapping in place.
if( inputBuffer == NULL )
{
inputBuffer = outputBuffer;
}
// Swap everything in the buffer:
for( int i = 0; i < count; i++ )
{
LowLevelByteSwap<T>( &outputBuffer[i], &inputBuffer[i] );
}
}
//-----------------------------------------------------------------------------
// Swaps an input buffer full of type T into the given output buffer.
//
// Swaps [count] items from the inputBuffer to the outputBuffer.
// If inputBuffer is omitted or NULL, then it is assumed to be the same as
// outputBuffer - effectively swapping the contents of the buffer in place.
//-----------------------------------------------------------------------------
template<typename T> inline void SwapBufferToTargetEndian( T* outputBuffer, T* inputBuffer = NULL, int count = 1 )
{
Assert( count >= 0 );
Assert( outputBuffer );
// Fail gracefully in release:
if( count <=0 || !outputBuffer )
return;
// Optimization for the case when we are swapping in place.
if( inputBuffer == NULL )
{
inputBuffer = outputBuffer;
}
// Are we already the correct endienness? ( or are we swapping 1 byte items? )
if( !m_bSwapBytes || ( sizeof(T) == 1 ) )
{
// If we were just going to swap in place then return.
if( !inputBuffer )
return;
// Otherwise copy the inputBuffer to the outputBuffer:
if ( outputBuffer != inputBuffer )
memcpy( outputBuffer, inputBuffer, count * sizeof( T ) );
return;
}
// Swap everything in the buffer:
for( int i = 0; i < count; i++ )
{
LowLevelByteSwap<T>( &outputBuffer[i], &inputBuffer[i] );
}
}
private:
//-----------------------------------------------------------------------------
// The lowest level byte swapping workhorse of doom. output always contains the
// swapped version of input. ( Doesn't compare machine to target endianness )
//-----------------------------------------------------------------------------
template<typename T> static void LowLevelByteSwap( T *output, T *input )
{
T temp = *output;
#if defined( _X360 )
// Intrinsics need the source type to be fixed-point
DWORD* word = (DWORD*)input;
switch( sizeof(T) )
{
case 8:
{
__storewordbytereverse( *(word+1), 0, &temp );
__storewordbytereverse( *(word+0), 4, &temp );
}
break;
case 4:
__storewordbytereverse( *word, 0, &temp );
break;
case 2:
__storeshortbytereverse( *input, 0, &temp );
break;
case 1:
Q_memcpy( &temp, input, 1 );
break;
default:
Assert( "Invalid size in CByteswap::LowLevelByteSwap" && 0 );
}
#else
for( unsigned int i = 0; i < sizeof(T); i++ )
{
((unsigned char* )&temp)[i] = ((unsigned char*)input)[sizeof(T)-(i+1)];
}
#endif
Q_memcpy( output, &temp, sizeof(T) );
}
#if defined( _X360 )
// specialized for void * to get 360 XDK compile working despite changelist 281331
//-----------------------------------------------------------------------------
// The lowest level byte swapping workhorse of doom. output always contains the
// swapped version of input. ( Doesn't compare machine to target endianness )
//-----------------------------------------------------------------------------
template<> static void LowLevelByteSwap( void **output, void **input )
{
AssertMsgOnce( sizeof(void *) == sizeof(unsigned int) , "void *'s on this platform are not four bytes!" );
__storewordbytereverse( *reinterpret_cast<unsigned int *>(input), 0, output );
}
#endif
unsigned int m_bSwapBytes : 1;
unsigned int m_bBigEndian : 1;
};
#endif /* !BYTESWAP_H */

244
public/tier1/callqueue.h Normal file
View File

@@ -0,0 +1,244 @@
//========== Copyright <20> 2006, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#ifndef CALLQUEUE_H
#define CALLQUEUE_H
#include "tier0/tslist.h"
#include "functors.h"
#include "vstdlib/jobthread.h"
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------
// Avert thy eyes! Imagine rather:
//
// void QueueCall( <function>, [args1, [arg2,]...]
// void QueueCall( <object>, <function>, [args1, [arg2,]...]
// void QueueRefCall( <object>, <<function>, [args1, [arg2,]...]
//-----------------------------------------------------
#define DEFINE_CALLQUEUE_NONMEMBER_QUEUE_CALL(N) \
template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
void QueueCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
QueueFunctorInternal( CreateFunctor( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
}
//-------------------------------------
#define DEFINE_CALLQUEUE_MEMBER_QUEUE_CALL(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
void QueueCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
QueueFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
}
//-------------------------------------
#define DEFINE_CALLQUEUE_CONST_MEMBER_QUEUE_CALL(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
void QueueCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
QueueFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
}
//-------------------------------------
#define DEFINE_CALLQUEUE_REF_COUNTING_MEMBER_QUEUE_CALL(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
void QueueRefCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
QueueFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
}
//-------------------------------------
#define DEFINE_CALLQUEUE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
void QueueRefCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
QueueFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
\
}
#define FUNC_GENERATE_QUEUE_METHODS() \
FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_NONMEMBER_QUEUE_CALL ); \
FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_MEMBER_QUEUE_CALL ); \
FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_CONST_MEMBER_QUEUE_CALL );\
FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_REF_COUNTING_MEMBER_QUEUE_CALL ); \
FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL )
//-----------------------------------------------------
template <typename QUEUE_TYPE = CTSQueue<CFunctor *> >
class CCallQueueT
{
public:
CCallQueueT()
: m_bNoQueue( false )
{
#ifdef _DEBUG
m_nCurSerialNumber = 0;
m_nBreakSerialNumber = (unsigned)-1;
#endif
}
void DisableQueue( bool bDisable )
{
if ( m_bNoQueue == bDisable )
{
return;
}
if ( !m_bNoQueue )
CallQueued();
m_bNoQueue = bDisable;
}
bool IsDisabled() const
{
return m_bNoQueue;
}
int Count()
{
return m_queue.Count();
}
void CallQueued()
{
if ( !m_queue.Count() )
{
return;
}
m_queue.PushItem( NULL );
CFunctor *pFunctor = NULL;
while ( m_queue.PopItem( &pFunctor ) && pFunctor != NULL )
{
#ifdef _DEBUG
if ( pFunctor->m_nUserID == m_nBreakSerialNumber)
{
m_nBreakSerialNumber = (unsigned)-1;
}
#endif
(*pFunctor)();
pFunctor->Release();
}
}
void ParallelCallQueued( IThreadPool *pPool = NULL )
{
if ( ! pPool )
{
pPool = g_pThreadPool;
}
int nNumThreads = 1;
if ( pPool )
{
nNumThreads = MIN( pPool->NumThreads(), MAX( 1, Count() ) );
}
if ( nNumThreads < 2 )
{
CallQueued();
}
else
{
int *pDummy = NULL;
ParallelProcess( pPool, pDummy, nNumThreads, this, &CCallQueueT<>::ExecuteWrapper );
}
}
void QueueFunctor( CFunctor *pFunctor )
{
Assert( pFunctor );
QueueFunctorInternal( RetAddRef( pFunctor ) );
}
void Flush()
{
m_queue.PushItem( NULL );
CFunctor *pFunctor;
while ( m_queue.PopItem( &pFunctor ) && pFunctor != NULL )
{
pFunctor->Release();
}
}
FUNC_GENERATE_QUEUE_METHODS();
private:
void ExecuteWrapper( int &nDummy ) // to match paralell process function template
{
CallQueued();
}
void QueueFunctorInternal( CFunctor *pFunctor )
{
if ( !m_bNoQueue )
{
#ifdef _DEBUG
pFunctor->m_nUserID = m_nCurSerialNumber++;
#endif
m_queue.PushItem( pFunctor );
}
else
{
(*pFunctor)();
pFunctor->Release();
}
}
QUEUE_TYPE m_queue;
bool m_bNoQueue;
unsigned m_nCurSerialNumber;
unsigned m_nBreakSerialNumber;
};
class CCallQueue : public CCallQueueT<>
{
};
//-----------------------------------------------------
// Optional interface that can be bound to concrete CCallQueue
//-----------------------------------------------------
class ICallQueue
{
public:
void QueueFunctor( CFunctor *pFunctor )
{
// [mhansen] If we grab an extra reference here then this functor never gets released.
// That usually isn't too bad because the memory the functor is allocated in is cleared and
// reused every frame. But, if the functor contains a CUtlDataEnvelope with more than
// 4 bytes of data it allocates its own memory and, in that case, we need the destructor to
// be called to free it. So, we don't want to grab the "extra" reference here.
// The net result should be that after this call the pFunctor has a ref count of 1 (which
// is held by the functor it gets nested in, which is stuck in the call queue) and after it
// is executed the owning functor is destructed which causes it to release the reference
// and this functor is then freed. This happens in imatersysteminternal.h:112 where the
// destructor is called explictly for the owning functor: pFunctor->~CFunctor();
//QueueFunctorInternal( RetAddRef( pFunctor ) );
QueueFunctorInternal( pFunctor );
}
FUNC_GENERATE_QUEUE_METHODS();
private:
virtual void QueueFunctorInternal( CFunctor *pFunctor ) = 0;
};
#endif // CALLQUEUE_H

View File

@@ -0,0 +1,43 @@
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose: Shared code for parsing / searching for characters in a string
// using lookup tables
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//===========================================================================//
#ifndef CHARACTERSET_H
#define CHARACTERSET_H
#ifdef _WIN32
#pragma once
#endif
struct characterset_t
{
char set[256];
};
// This is essentially a strpbrk() using a precalculated lookup table
//-----------------------------------------------------------------------------
// Purpose: builds a simple lookup table of a group of important characters
// Input : *pSetBuffer - pointer to the buffer for the group
// *pSetString - list of characters to flag
//-----------------------------------------------------------------------------
extern void CharacterSetBuild( characterset_t *pSetBuffer, const char *pSetString );
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pSetBuffer - pre-build group buffer
// character - character to lookup
// Output : int - 1 if the character was in the set
//-----------------------------------------------------------------------------
#define IN_CHARACTERSET( SetBuffer, character ) ((SetBuffer).set[(character)])
#endif // CHARACTERSET_H

View File

@@ -0,0 +1,59 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Generic CRC functions
//
// $NoKeywords: $
//=============================================================================//
#ifndef CHECKSUM_CRC_H
#define CHECKSUM_CRC_H
#include <tier0/platform.h>
#ifdef _WIN32
#pragma once
#endif
typedef uint32 CRC32_t;
void CRC32_Init( CRC32_t *pulCRC );
void CRC32_ProcessBuffer( CRC32_t *pulCRC, const void *p, int len );
void CRC32_Final( CRC32_t *pulCRC );
CRC32_t CRC32_GetTableEntry( unsigned int slot );
inline CRC32_t CRC32_ProcessSingleBuffer( const void *p, int len )
{
CRC32_t crc;
CRC32_Init( &crc );
CRC32_ProcessBuffer( &crc, p, len );
CRC32_Final( &crc );
return crc;
}
inline unsigned long CRC32_ConvertToUnsignedLong( CRC32_t *pulCRC )
{
return (unsigned long)(*pulCRC);
}
inline CRC32_t CRC32_ConvertFromUnsignedLong( unsigned long ulCRC )
{
return (CRC32_t)(ulCRC);
}
typedef uint64 CRC64_t;
void CRC64_Init( CRC64_t *pCRC );
void CRC64_ProcessBuffer( CRC64_t *pCRC, const void *p, int len );
void CRC64_Final( CRC64_t *pCRC );
inline CRC64_t CRC64_ProcessSingleBuffer( const void *p, int len )
{
CRC64_t crc;
CRC64_Init( &crc );
CRC64_ProcessBuffer( &crc, p, len );
CRC64_Final( &crc );
return crc;
}
#endif // CHECKSUM_CRC_H

View File

@@ -0,0 +1,62 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Generic MD5 hashing algo
//
//=============================================================================//
#ifndef CHECKSUM_MD5_H
#define CHECKSUM_MD5_H
#ifdef _WIN32
#pragma once
#endif
// 16 bytes == 128 bit digest
#define MD5_DIGEST_LENGTH 16
struct MD5Value_t
{
unsigned char bits[MD5_DIGEST_LENGTH];
void Zero();
bool IsZero() const;
bool operator==( const MD5Value_t &src ) const;
bool operator!=( const MD5Value_t &src ) const;
};
// MD5 Hash
typedef struct
{
unsigned int buf[4];
unsigned int bits[2];
unsigned char in[64];
} MD5Context_t;
void MD5Init( MD5Context_t *context );
void MD5Update( MD5Context_t *context, unsigned char const *buf, unsigned int len );
void MD5Final( unsigned char digest[ MD5_DIGEST_LENGTH ], MD5Context_t *context );
char *MD5_Print(unsigned char *digest, int hashlen );
/// Convenience wrapper to calculate the MD5 for a buffer, all in one step, without
/// bothering with the context object.
void MD5_ProcessSingleBuffer( const void *p, int len, MD5Value_t &md5Result );
unsigned int MD5_PseudoRandom(unsigned int nSeed);
/// Returns true if the values match.
bool MD5_Compare( const MD5Value_t &data, const MD5Value_t &compare );
inline bool MD5Value_t::operator==( const MD5Value_t &src ) const
{
return MD5_Compare( *this, src );
}
inline bool MD5Value_t::operator!=( const MD5Value_t &src ) const
{
return !MD5_Compare( *this, src );
}
#endif // CHECKSUM_MD5_H

View File

@@ -0,0 +1,176 @@
//========= Copyright <20> 2005, Valve Inc., All rights reserved. ==========
//
// Purpose: Implementation of SHA-1
//
//=============================================================================
#ifndef CHECKSUM_SHA1_H
#define CHECKSUM_SHA1_H
#if defined( _WIN32 )
#pragma once
#endif
/*
100% free public domain implementation of the SHA-1
algorithm by Dominik Reichl <dominik.reichl@t-online.de>
=== Test Vectors (from FIPS PUB 180-1) ===
SHA1("abc") =
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
SHA1(A million repetitions of "a") =
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
#include "tier0/platform.h"
#if !defined(_MINIMUM_BUILD_)
#include <stdio.h> // Needed for file access
#if defined( _PS3 )
#include <sys/memory.h>
#else
#include <memory.h>
#endif
#include <string.h> // Needed for strcat and strcpy
#endif
// If you're compiling big endian, just comment out the following line
#define SHA1_LITTLE_ENDIAN
typedef union
{
uint8 c[64];
uint32 l[16];
} SHA1_WORKSPACE_BLOCK;
// SHA1 hash
const unsigned int k_cubHash = 20;
const unsigned int k_cchHash = 41; // k_cubHash * 2, plus 1 for terminator
#pragma pack( push, 1 )
typedef uint8 SHADigest_t[ k_cubHash ];
#pragma pack( pop )
#if !defined(_MINIMUM_BUILD_)
class CSHA1
#else
class Minimum_CSHA1
#endif
{
public:
// Two different formats for ReportHash(...)
enum
{
REPORT_HEX = 0,
REPORT_DIGIT = 1
};
// Constructor and Destructor
#if !defined(_MINIMUM_BUILD_)
CSHA1();
virtual ~CSHA1() ;
#else
Minimum_CSHA1() ;
~Minimum_CSHA1() ; // no virtual destructor's in the minimal builds !
#endif
unsigned int m_state[5];
unsigned int m_count[2];
uint8 m_buffer[64];
uint8 m_digest[k_cubHash];
void Reset();
// Update the hash value
void Update( const void *data, unsigned int len );
#if !defined(_MINIMUM_BUILD_)
bool HashFile( const char *szFileName );
#endif
// Finalize hash and report
void Final();
#if !defined(_MINIMUM_BUILD_)
void ReportHash(char *szReport, uint8 uReportType = REPORT_HEX);
#endif
void GetHash(uint8 *uDest);
private:
// Private SHA-1 transformation
void Transform(unsigned int state[5], const uint8 buffer[64]);
// Member variables
uint8 m_workspace[64];
SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above
};
#define GenerateHash( hash, pubData, cubData ) { CSHA1 sha1; sha1.Update( (byte *)pubData, cubData ); sha1.Final(); sha1.GetHash( hash ); }
#if !defined(_MINIMUM_BUILD_)
// hash comparison function, for use with CUtlMap/CUtlRBTree
bool HashLessFunc( SHADigest_t const &lhs, SHADigest_t const &rhs );
// utility class for manipulating SHA1 hashes in their compact form
struct CSHA
{
public:
SHADigest_t m_shaDigest;
CSHA()
{
memset( m_shaDigest, 0, k_cubHash );
}
explicit CSHA( const SHADigest_t rhs )
{
memcpy( m_shaDigest, rhs, k_cubHash );
}
SHADigest_t &SHADigest()
{
return m_shaDigest;
}
bool operator<( const CSHA &rhs ) const
{
return memcmp( m_shaDigest, rhs.m_shaDigest, k_cubHash ) < 0;
}
bool operator==( const CSHA &rhs ) const
{
return memcmp( m_shaDigest, rhs.m_shaDigest, k_cubHash ) == 0;
}
bool operator!=( const CSHA &rhs ) const
{
return !(*this == rhs);
}
bool operator==( const SHADigest_t &rhs ) const
{
return memcmp( m_shaDigest, rhs, k_cubHash ) == 0;
}
bool operator!=( const SHADigest_t &rhs ) const
{
return !(*this == rhs);
}
CSHA &operator=( const SHADigest_t rhs )
{
memcpy( m_shaDigest, rhs, k_cubHash );
return *this;
}
void AssignTo( SHADigest_t rhs ) const
{
memcpy( rhs, m_shaDigest, k_cubHash );
}
};
#endif // _MINIMUM_BUILD_
#endif // CHECKSUM_SHA1_H

View File

@@ -0,0 +1,100 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Defines an interface for circular buffers. Data can be written to
// and read from these buffers as though from a file. When it is
// write-overflowed (you write more data in than the buffer can hold),
// the read pointer is advanced to allow the new data to be written.
// This means old data will be discarded if you write too much data
// into the buffer.
//
// MikeD: Moved all the functions into a class.
// Changed it so when the buffer overflows, the old data
// is discarded rather than the new.
//
//=====================================================================================//
#ifndef CIRCULARBUFFER_H
#define CIRCULARBUFFER_H
#pragma once
#include "tier0/dbg.h"
class CCircularBuffer
{
public:
CCircularBuffer();
CCircularBuffer( int size );
void SetSize( int nSize );
protected:
inline void AssertValid()
{
#ifdef _DEBUG
Assert( this );
Assert( m_nSize > 0 );
Assert( m_nCount >= 0 );
Assert( m_nCount <= m_nSize );
Assert( m_nWrite < m_nSize );
// Verify that m_nCount is correct.
if( m_nRead == m_nWrite )
{
Assert( m_nCount == 0 || m_nCount == m_nSize );
}
else
{
int testCount=0;
if ( m_nRead < m_nWrite )
testCount = m_nWrite - m_nRead;
else
testCount = (m_nSize - m_nRead) + m_nWrite;
Assert( testCount == m_nCount );
}
#endif
}
public:
void Flush();
int GetSize(); // Get the size of the buffer (how much can you write without reading
// before losing data.
int GetWriteAvailable(); // Get the amount available to write without overflowing.
// Note: you can write however much you want, but it may overflow,
// in which case the newest data is kept and the oldest is discarded.
int GetReadAvailable(); // Get the amount available to read.
int Peek(char *pchDest, int nCount);
int Advance(int nCount);
int Read(void *pchDest, int nCount);
int Write(void *pchData, int nCount);
public:
int m_nCount; // Space between the read and write pointers (how much data we can read).
int m_nRead; // Read index into circular buffer
int m_nWrite; // Write index into circular buffer
int m_nSize; // Size of circular buffer in bytes (how much data it can hold).
char m_chData[1]; // Circular buffer holding data
};
// Use this to instantiate a CircularBuffer.
template< int size >
class CSizedCircularBuffer : public CCircularBuffer
{
public:
CSizedCircularBuffer() : CCircularBuffer(size) {}
private:
char myData[size-1];
};
CCircularBuffer *AllocateCircularBuffer( int nSize );
void FreeCircularBuffer( CCircularBuffer *pCircularBuffer );
#endif // CIRCULARBUFFER_H

View File

@@ -0,0 +1,127 @@
//===== Copyright <20> 1996-2006, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//===========================================================================//
#ifndef COMMANDBUFFER_H
#define COMMANDBUFFER_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/platform.h"
#include "tier1/utllinkedlist.h"
#include "tier1/convar.h"
//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
class CUtlBuffer;
//-----------------------------------------------------------------------------
// Invalid command handle
//-----------------------------------------------------------------------------
typedef intp CommandHandle_t;
enum
{
COMMAND_BUFFER_INVALID_COMMAND_HANDLE = 0
};
//-----------------------------------------------------------------------------
// A command buffer class- a queue of argc/argv based commands associated
// with a particular time
//-----------------------------------------------------------------------------
class CCommandBuffer
{
public:
// Constructor, destructor
CCommandBuffer( );
~CCommandBuffer();
// Inserts text into the command buffer
bool AddText( const char *pText, cmd_source_t cmdSource = kCommandSrcUserInput, int nTickDelay = 0 );
// Used to iterate over all commands appropriate for the current time
void BeginProcessingCommands( int nDeltaTicks );
bool DequeueNextCommand( /*out*/ CCommand* pCommand );
void EndProcessingCommands();
// Are we in the middle of processing commands?
bool IsProcessingCommands();
// Delays all queued commands to execute at a later time
void DelayAllQueuedCommands( int nTickDelay );
// Indicates how long to delay when encoutering a 'wait' command
void SetWaitDelayTime( int nTickDelay );
// Returns a handle to the next command to process
// (useful when inserting commands into the buffer during processing
// of commands to force immediate execution of those commands,
// most relevantly, to implement a feature where you stream a file
// worth of commands into the buffer, where the file size is too large
// to entirely contain in the buffer).
CommandHandle_t GetNextCommandHandle();
// Specifies a max limit of the args buffer. For unittesting. Size == 0 means use default
void LimitArgumentBufferSize( int nSize );
void SetWaitEnabled( bool bEnable ) { m_bWaitEnabled = bEnable; }
bool IsWaitEnabled( void ) { return m_bWaitEnabled; }
private:
enum
{
ARGS_BUFFER_LENGTH = 8192,
};
struct Command_t
{
int m_nTick;
int m_nFirstArgS;
int m_nBufferSize;
cmd_source_t m_source;
};
// Insert a command into the command queue at the appropriate time
void InsertCommandAtAppropriateTime( intp hCommand );
// Insert a command into the command queue
// Only happens if it's inserted while processing other commands
void InsertImmediateCommand( intp hCommand );
// Insert a command into the command queue
bool InsertCommand( const char *pArgS, int nCommandSize, int nTick, cmd_source_t cmdSource );
// Returns the length of the next command, as well as the offset to the next command
void GetNextCommandLength( const char *pText, int nMaxLen, int *pCommandLength, int *pNextCommandOffset );
// Compacts the command buffer
void Compact();
// Parses argv0 out of the buffer
bool ParseArgV0( CUtlBuffer &buf, char *pArgv0, int nMaxLen, const char **pArgs );
char m_pArgSBuffer[ ARGS_BUFFER_LENGTH ];
int m_nLastUsedArgSSize;
int m_nArgSBufferSize;
CUtlFixedLinkedList< Command_t > m_Commands;
int m_nCurrentTick;
int m_nLastTickToProcess;
int m_nWaitDelayTicks;
intp m_hNextCommand;
int m_nMaxArgSBufferLength;
bool m_bIsProcessingCommands;
bool m_bWaitEnabled;
};
#endif // COMMANDBUFFER_H

1169
public/tier1/convar.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,53 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Helper class for cvars that have restrictions on their value.
//
//=============================================================================//
#ifndef CONVAR_SERVERBOUNDED_H
#define CONVAR_SERVERBOUNDED_H
#ifdef _WIN32
#pragma once
#endif
// This class is used to virtualize a ConVar's value, so the client can restrict its
// value while connected to a server. When using this across modules, it's important
// to dynamic_cast it to a ConVar_ServerBounded or you won't get the restricted value.
//
// NOTE: FCVAR_USERINFO vars are not virtualized before they are sent to the server
// (we have no way to detect if the virtualized value would change), so
// if you want to use a bounded cvar's value on the server, you must rebound it
// the same way the client does.
class ConVar_ServerBounded : public ConVar
{
public:
ConVar_ServerBounded( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString )
: ConVar( pName, pDefaultValue, flags, pHelpString )
{
}
ConVar_ServerBounded( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, FnChangeCallback_t callback )
: ConVar( pName, pDefaultValue, flags, pHelpString, callback )
{
}
ConVar_ServerBounded( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax )
: ConVar( pName, pDefaultValue, flags, pHelpString, bMin, fMin, bMax, fMax ) {}
// You must implement GetFloat.
virtual float GetFloat() const = 0;
// You can optionally implement these.
virtual int GetInt() const { return (int)GetFloat(); }
virtual bool GetBool() const { return ( GetInt() != 0 ); }
// Use this to get the underlying cvar's value.
float GetBaseFloatValue() const
{
return ConVar::GetFloat();
}
};
#endif // CONVAR_SERVERBOUNDED_H

296
public/tier1/datamanager.h Normal file
View File

@@ -0,0 +1,296 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef RESOURCEMANAGER_H
#define RESOURCEMANAGER_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/threadtools.h"
#include "utlmultilist.h"
#include "utlvector.h"
FORWARD_DECLARE_HANDLE( memhandle_t );
#define INVALID_MEMHANDLE ((memhandle_t)0xffffffff)
class CDataManagerBase
{
public:
// public API
// -----------------------------------------------------------------------------
// memhandle_t CreateResource( params ) // implemented by derived class
void DestroyResource( memhandle_t handle );
// type-safe implementation in derived class
//void *LockResource( memhandle_t handle );
int UnlockResource( memhandle_t handle );
void TouchResource( memhandle_t handle );
void MarkAsStale( memhandle_t handle ); // move to head of LRU
int LockCount( memhandle_t handle );
int BreakLock( memhandle_t handle );
int BreakAllLocks();
// HACKHACK: For convenience - offers no lock protection
// type-safe implementation in derived class
//void *GetResource_NoLock( memhandle_t handle );
unsigned int TargetSize();
unsigned int AvailableSize();
unsigned int UsedSize();
void NotifySizeChanged( memhandle_t handle, unsigned int oldSize, unsigned int newSize );
void SetTargetSize( unsigned int targetSize );
// NOTE: flush is equivalent to Destroy
unsigned int FlushAllUnlocked();
unsigned int FlushToTargetSize();
unsigned int FlushAll();
unsigned int Purge( unsigned int nBytesToPurge );
unsigned int EnsureCapacity( unsigned int size );
// Thread lock
virtual void Lock() {}
virtual bool TryLock() { return true; }
virtual void Unlock() {}
// Iteration
// -----------------------------------------------------------------------------
void SetFreeOnDestruct( bool value ) { m_freeOnDestruct = value; }
// Debugging only!!!!
void GetLRUHandleList( CUtlVector< memhandle_t >& list );
void GetLockHandleList( CUtlVector< memhandle_t >& list );
protected:
// derived class must call these to implement public API
unsigned short CreateHandle( bool bCreateLocked );
memhandle_t StoreResourceInHandle( unsigned short memoryIndex, void *pStore, unsigned int realSize );
void *GetResource_NoLock( memhandle_t handle );
void *GetResource_NoLockNoLRUTouch( memhandle_t handle );
void *LockResource( memhandle_t handle );
void *LockResourceReturnCount( int *pCount, memhandle_t handle );
// NOTE: you must call this from the destructor of the derived class! (will assert otherwise)
void FreeAllLists() { FlushAll(); m_listsAreFreed = true; }
CDataManagerBase( unsigned int maxSize );
virtual ~CDataManagerBase();
inline unsigned int MemTotal_Inline() const { return m_targetMemorySize; }
inline unsigned int MemAvailable_Inline() const { return m_targetMemorySize - m_memUsed; }
inline unsigned int MemUsed_Inline() const { return m_memUsed; }
// Implemented by derived class:
virtual void DestroyResourceStorage( void * ) = 0;
virtual unsigned int GetRealSize( void * ) = 0;
memhandle_t ToHandle( unsigned short index );
unsigned short FromHandle( memhandle_t handle );
void TouchByIndex( unsigned short memoryIndex );
void * GetForFreeByIndex( unsigned short memoryIndex );
// One of these is stored per active allocation
struct resource_lru_element_t
{
resource_lru_element_t()
{
lockCount = 0;
serial = 1;
pStore = 0;
}
unsigned short lockCount;
unsigned short serial;
void *pStore;
};
unsigned int m_targetMemorySize;
unsigned int m_memUsed;
CUtlMultiList< resource_lru_element_t, unsigned short > m_memoryLists;
unsigned short m_lruList;
unsigned short m_lockList;
unsigned short m_freeList;
unsigned short m_listsAreFreed : 1;
unsigned short m_freeOnDestruct : 1;
unsigned short m_unused : 14;
};
template< class STORAGE_TYPE, class CREATE_PARAMS, class LOCK_TYPE = STORAGE_TYPE *, class MUTEX_TYPE = CThreadNullMutex>
class CDataManager : public CDataManagerBase
{
typedef CDataManagerBase BaseClass;
public:
CDataManager<STORAGE_TYPE, CREATE_PARAMS, LOCK_TYPE, MUTEX_TYPE>( unsigned int size = (unsigned)-1 ) : BaseClass(size) {}
~CDataManager<STORAGE_TYPE, CREATE_PARAMS, LOCK_TYPE, MUTEX_TYPE>()
{
// NOTE: This must be called in all implementations of CDataManager
if ( m_freeOnDestruct )
{
FreeAllLists();
}
}
// Use GetData() to translate pointer to LOCK_TYPE
LOCK_TYPE LockResource( memhandle_t hMem )
{
void *pLock = BaseClass::LockResource( hMem );
if ( pLock )
{
return StoragePointer(pLock)->GetData();
}
return NULL;
}
LOCK_TYPE LockResourceReturnCount( int *pCount, memhandle_t hMem )
{
void *pLock = BaseClass::LockResourceReturnCount( pCount, hMem );
if ( pLock )
{
return StoragePointer(pLock)->GetData();
}
return NULL;
}
// Use GetData() to translate pointer to LOCK_TYPE
LOCK_TYPE GetResource_NoLock( memhandle_t hMem )
{
void *pLock = const_cast<void *>(BaseClass::GetResource_NoLock( hMem ));
if ( pLock )
{
return StoragePointer(pLock)->GetData();
}
return NULL;
}
// Use GetData() to translate pointer to LOCK_TYPE
// Doesn't touch the memory LRU
LOCK_TYPE GetResource_NoLockNoLRUTouch( memhandle_t hMem )
{
void *pLock = const_cast<void *>(BaseClass::GetResource_NoLockNoLRUTouch( hMem ));
if ( pLock )
{
return StoragePointer(pLock)->GetData();
}
return NULL;
}
// Wrapper to match implementation of allocation with typed storage & alloc params.
memhandle_t CreateResource( const CREATE_PARAMS &createParams, bool bCreateLocked = false )
{
BaseClass::EnsureCapacity(STORAGE_TYPE::EstimatedSize(createParams));
STORAGE_TYPE *pStore = STORAGE_TYPE::CreateResource( createParams );
AUTO_LOCK_( CDataManagerBase, *this );
unsigned short memoryIndex = BaseClass::CreateHandle( bCreateLocked );
return BaseClass::StoreResourceInHandle( memoryIndex, pStore, pStore->Size() );
}
// Iteration. Must lock first
memhandle_t GetFirstUnlocked()
{
unsigned node = m_memoryLists.Head(m_lruList);
if ( node == m_memoryLists.InvalidIndex() )
{
return INVALID_MEMHANDLE;
}
return ToHandle( node );
}
memhandle_t GetFirstLocked()
{
unsigned node = m_memoryLists.Head(m_lockList);
if ( node == m_memoryLists.InvalidIndex() )
{
return INVALID_MEMHANDLE;
}
return ToHandle( node );
}
memhandle_t GetNext( memhandle_t hPrev )
{
if ( hPrev == INVALID_MEMHANDLE )
{
return INVALID_MEMHANDLE;
}
unsigned short iNext = m_memoryLists.Next( FromHandle( hPrev ) );
if ( iNext == m_memoryLists.InvalidIndex() )
{
return INVALID_MEMHANDLE;
}
return ToHandle( iNext );
}
MUTEX_TYPE &AccessMutex() { return m_mutex; }
virtual void Lock() { m_mutex.Lock(); }
virtual bool TryLock() { return m_mutex.TryLock(); }
virtual void Unlock() { m_mutex.Unlock(); }
private:
STORAGE_TYPE *StoragePointer( void *pMem )
{
return static_cast<STORAGE_TYPE *>(pMem);
}
virtual void DestroyResourceStorage( void *pStore )
{
StoragePointer(pStore)->DestroyResource();
}
virtual unsigned int GetRealSize( void *pStore )
{
return StoragePointer(pStore)->Size();
}
MUTEX_TYPE m_mutex;
};
//-----------------------------------------------------------------------------
inline unsigned short CDataManagerBase::FromHandle( memhandle_t handle )
{
unsigned int fullWord = (unsigned int)reinterpret_cast<uintp>( handle );
unsigned short serial = fullWord>>16;
unsigned short index = fullWord & 0xFFFF;
index--;
if ( m_memoryLists.IsValidIndex(index) && m_memoryLists[index].serial == serial )
return index;
return m_memoryLists.InvalidIndex();
}
inline int CDataManagerBase::LockCount( memhandle_t handle )
{
Lock();
int result = 0;
unsigned short memoryIndex = FromHandle(handle);
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
result = m_memoryLists[memoryIndex].lockCount;
}
Unlock();
return result;
}
#endif // RESOURCEMANAGER_H

99
public/tier1/delegates.h Normal file
View File

@@ -0,0 +1,99 @@
//========== Copyright <20> 2005, Valve Corporation, All rights reserved. ========
//
// Purpose: Simple macros to generate delegation code
//
//=============================================================================
#ifndef DELEGATES_H
#define DELEGATES_H
#if defined( _WIN32 )
#pragma once
#endif
#define DELEGATE_TO_OBJECT_0( RetType, FuncName, pDelegated ) RetType FuncName() { return (pDelegated)->FuncName(); }
#define DELEGATE_TO_OBJECT_0V( FuncName, pDelegated ) void FuncName() { (pDelegated)->FuncName(); }
#define DELEGATE_TO_OBJECT_1( RetType, FuncName, ArgType1, pDelegated ) RetType FuncName( ArgType1 a1 ) { return (pDelegated)->FuncName( a1 ); }
#define DELEGATE_TO_OBJECT_1V( FuncName, ArgType1, pDelegated ) void FuncName( ArgType1 a1 ) { (pDelegated)->FuncName( a1 ); }
#define DELEGATE_TO_OBJECT_2( RetType, FuncName, ArgType1, ArgType2, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2 ) { return (pDelegated)->FuncName( a1, a2 ); }
#define DELEGATE_TO_OBJECT_2V( FuncName, ArgType1, ArgType2, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2 ) { (pDelegated)->FuncName( a1, a2 ); }
#define DELEGATE_TO_OBJECT_3( RetType, FuncName, ArgType1, ArgType2, ArgType3, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) { return (pDelegated)->FuncName( a1, a2, a3 ); }
#define DELEGATE_TO_OBJECT_3V( FuncName, ArgType1, ArgType2, ArgType3, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) { (pDelegated)->FuncName( a1, a2, a3 ); }
#define DELEGATE_TO_OBJECT_4( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) { return (pDelegated)->FuncName( a1, a2, a3, a4 ); }
#define DELEGATE_TO_OBJECT_4V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) { (pDelegated)->FuncName( a1, a2, a3, a4 ); }
#define DELEGATE_TO_OBJECT_5( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5 ); }
#define DELEGATE_TO_OBJECT_5V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5 ); }
#define DELEGATE_TO_OBJECT_6( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6 ); }
#define DELEGATE_TO_OBJECT_6V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6 ); }
#define DELEGATE_TO_OBJECT_7( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
#define DELEGATE_TO_OBJECT_7V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
#define DELEGATE_TO_OBJECT_8( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
#define DELEGATE_TO_OBJECT_8V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
#define DELEGATE_TO_OBJECT_9( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
#define DELEGATE_TO_OBJECT_9V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
#define DELEGATE_TO_OBJECT_11V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, ArgType10, ArgType11, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9, ArgType10 a10, ArgType11 a11 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 ); }
#define DELEGATE_TO_OBJECT_0C( RetType, FuncName, pDelegated ) RetType FuncName() const { return (pDelegated)->FuncName(); }
#define DELEGATE_TO_OBJECT_0VC( FuncName, pDelegated ) void FuncName() const { (pDelegated)->FuncName(); }
#define DELEGATE_TO_OBJECT_1C( RetType, FuncName, ArgType1, pDelegated ) RetType FuncName( ArgType1 a1 ) const { return (pDelegated)->FuncName( a1 ); }
#define DELEGATE_TO_OBJECT_1VC( FuncName, ArgType1, pDelegated ) void FuncName( ArgType1 a1 ) const { (pDelegated)->FuncName( a1 ); }
#define DELEGATE_TO_OBJECT_2C( RetType, FuncName, ArgType1, ArgType2, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2 ) const { return (pDelegated)->FuncName( a1, a2 ); }
#define DELEGATE_TO_OBJECT_2VC( FuncName, ArgType1, ArgType2, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2 ) const { (pDelegated)->FuncName( a1, a2 ); }
#define DELEGATE_TO_OBJECT_3C( RetType, FuncName, ArgType1, ArgType2, ArgType3, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) const { return (pDelegated)->FuncName( a1, a2, a3 ); }
#define DELEGATE_TO_OBJECT_3VC( FuncName, ArgType1, ArgType2, ArgType3, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) const { (pDelegated)->FuncName( a1, a2, a3 ); }
#define DELEGATE_TO_OBJECT_4C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4 ); }
#define DELEGATE_TO_OBJECT_4VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) const { (pDelegated)->FuncName( a1, a2, a3, a4 ); }
#define DELEGATE_TO_OBJECT_5C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5 ); }
#define DELEGATE_TO_OBJECT_5VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5 ); }
#define DELEGATE_TO_OBJECT_6C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6 ); }
#define DELEGATE_TO_OBJECT_6VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6 ); }
#define DELEGATE_TO_OBJECT_7C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
#define DELEGATE_TO_OBJECT_7VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
#define DELEGATE_TO_OBJECT_8C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
#define DELEGATE_TO_OBJECT_8VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
#define DELEGATE_TO_OBJECT_9C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
#define DELEGATE_TO_OBJECT_9VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
#define DELEGATE_TO_BASE_0( RetType, FuncName, BaseClass ) RetType FuncName() { return BaseClass::FuncName(); }
#define DELEGATE_TO_BASE_0V( FuncName, BaseClass ) void FuncName() { BaseClass::FuncName(); }
#define DELEGATE_TO_BASE_1( RetType, FuncName, ArgType1, BaseClass ) RetType FuncName( ArgType1 a1 ) { return BaseClass::FuncName( a1 ); }
#define DELEGATE_TO_BASE_1V( FuncName, ArgType1, BaseClass ) void FuncName( ArgType1 a1 ) { BaseClass::FuncName( a1 ); }
#define DELEGATE_TO_BASE_2( RetType, FuncName, ArgType1, ArgType2, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2 ) { return BaseClass::FuncName( a1, a2 ); }
#define DELEGATE_TO_BASE_2V( FuncName, ArgType1, ArgType2, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2 ) { BaseClass::FuncName( a1, a2 ); }
#define DELEGATE_TO_BASE_3( RetType, FuncName, ArgType1, ArgType2, ArgType3, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) { return BaseClass::FuncName( a1, a2, a3 ); }
#define DELEGATE_TO_BASE_3V( FuncName, ArgType1, ArgType2, ArgType3, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) { BaseClass::FuncName( a1, a2, a3 ); }
#define DELEGATE_TO_BASE_4( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) { return BaseClass::FuncName( a1, a2, a3, a4 ); }
#define DELEGATE_TO_BASE_4V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) { BaseClass::FuncName( a1, a2, a3, a4 ); }
#define DELEGATE_TO_BASE_5( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5 ); }
#define DELEGATE_TO_BASE_5V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) { BaseClass::FuncName( a1, a2, a3, a4, a5 ); }
#define DELEGATE_TO_BASE_6( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6 ); }
#define DELEGATE_TO_BASE_6V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) { BaseClass::FuncName( a1, a2, a3, a4, a5, a6 ); }
#define DELEGATE_TO_BASE_7( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
#define DELEGATE_TO_BASE_7V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
#define DELEGATE_TO_BASE_8( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
#define DELEGATE_TO_BASE_8V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
#define DELEGATE_TO_BASE_9( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
#define DELEGATE_TO_BASE_9V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
#define DELEGATE_TO_BASE_0C( RetType, FuncName, BaseClass ) RetType FuncName() const { return BaseClass::FuncName(); }
#define DELEGATE_TO_BASE_0VC( FuncName, BaseClass ) void FuncName() const { BaseClass::FuncName(); }
#define DELEGATE_TO_BASE_1C( RetType, FuncName, ArgType1, BaseClass ) RetType FuncName( ArgType1 a1 ) const { return BaseClass::FuncName( a1 ); }
#define DELEGATE_TO_BASE_1VC( FuncName, ArgType1, BaseClass ) void FuncName( ArgType1 a1 ) const { BaseClass::FuncName( a1 ); }
#define DELEGATE_TO_BASE_2C( RetType, FuncName, ArgType1, ArgType2, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2 ) const { return BaseClass::FuncName( a1, a2 ); }
#define DELEGATE_TO_BASE_2VC( FuncName, ArgType1, ArgType2, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2 ) const { BaseClass::FuncName( a1, a2 ); }
#define DELEGATE_TO_BASE_3C( RetType, FuncName, ArgType1, ArgType2, ArgType3, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) const { return BaseClass::FuncName( a1, a2, a3 ); }
#define DELEGATE_TO_BASE_3VC( FuncName, ArgType1, ArgType2, ArgType3, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) const { BaseClass::FuncName( a1, a2, a3 ); }
#define DELEGATE_TO_BASE_4C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) const { return BaseClass::FuncName( a1, a2, a3, a4 ); }
#define DELEGATE_TO_BASE_4VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) const { BaseClass::FuncName( a1, a2, a3, a4 ); }
#define DELEGATE_TO_BASE_5C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5 ); }
#define DELEGATE_TO_BASE_5VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5 ); }
#define DELEGATE_TO_BASE_6C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6 ); }
#define DELEGATE_TO_BASE_6VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5, a6 ); }
#define DELEGATE_TO_BASE_7C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
#define DELEGATE_TO_BASE_7VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
#define DELEGATE_TO_BASE_8C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
#define DELEGATE_TO_BASE_8VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
#define DELEGATE_TO_BASE_9C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
#define DELEGATE_TO_BASE_9VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
#endif // DELEGATES_H

29
public/tier1/diff.h Normal file
View File

@@ -0,0 +1,29 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
// Serialization/unserialization buffer
//=============================================================================//
#ifndef DIFF_H
#define DIFF_H
#pragma once
int FindDiffs(uint8 const *NewBlock, uint8 const *OldBlock,
int NewSize, int OldSize, int &DiffListSize,uint8 *Output,uint32 OutSize);
int FindDiffsForLargeFiles(uint8 const *NewBlock, uint8 const *OldBlock,
int NewSize, int OldSize, int &DiffListSize,uint8 *Output,
uint32 OutSize,
int hashsize=65536);
void ApplyDiffs(uint8 const *OldBlock, uint8 const *DiffList,
int OldSize, int DiffListSize, int &ResultListSize,uint8 *Output,uint32 OutSize);
int FindDiffsLowMemory(uint8 const *NewBlock, uint8 const *OldBlock,
int NewSize, int OldSize, int &DiffListSize,uint8 *Output,uint32 OutSize);
#endif

View File

@@ -0,0 +1,74 @@
//===== Copyright <20> 1996-2006, Valve Corporation, All rights reserved. ======//
//
// Purpose: ExprSimplifier builds a binary tree from an infix expression (in the
// form of a character array).
//
//===========================================================================//
#ifndef EXPREVALUATOR_H
#define EXPREVALUATOR_H
#if defined( _WIN32 )
#pragma once
#endif
static const char OR_OP = '|';
static const char AND_OP = '&';
static const char NOT_OP = '!';
#define MAX_IDENTIFIER_LEN 128
enum Kind {CONDITIONAL, NOT, LITERAL};
struct ExprNode
{
ExprNode *left; // left sub-expression
ExprNode *right; // right sub-expression
Kind kind; // kind of node this is
union
{
char cond; // the conditional
bool value; // the value
} data;
};
typedef ExprNode *ExprTree;
// callback to evaluate a $<symbol> during evaluation, return true or false
typedef bool (*GetSymbolProc_t)( const char *pKey );
typedef void (*SyntaxErrorProc_t)( const char *pReason );
class CExpressionEvaluator
{
public:
CExpressionEvaluator();
~CExpressionEvaluator();
bool Evaluate( bool &result, const char *pInfixExpression, GetSymbolProc_t pGetSymbolProc = 0, SyntaxErrorProc_t pSyntaxErrorProc = 0 );
private:
CExpressionEvaluator( CExpressionEvaluator& ); // prevent copy constructor being used
char GetNextToken( void );
void FreeNode( ExprNode *pNode );
ExprNode *AllocateNode( void );
void FreeTree( ExprTree &node );
bool IsConditional( bool &bCondition, const char token );
bool IsNotOp( const char token );
bool IsIdentifierOrConstant( const char token );
bool MakeExprNode( ExprTree &tree, char token, Kind kind, ExprTree left, ExprTree right );
bool MakeFactor( ExprTree &tree );
bool MakeTerm( ExprTree &tree );
bool MakeExpression( ExprTree &tree );
bool BuildExpression( void );
bool SimplifyNode( ExprTree &node );
ExprTree m_ExprTree; // Tree representation of the expression
char m_CurToken; // Current token read from the input expression
const char *m_pExpression; // Array of the expression characters
int m_CurPosition; // Current position in the input expression
char m_Identifier[MAX_IDENTIFIER_LEN]; // Stores the identifier string
GetSymbolProc_t m_pGetSymbolProc;
SyntaxErrorProc_t m_pSyntaxErrorProc;
bool m_bSetup;
};
#endif

243
public/tier1/fileio.h Normal file
View File

@@ -0,0 +1,243 @@
//========= Copyright 1996-2008, Valve Corporation, All rights reserved. ============//
//
// Purpose: A collection of utility classes to simplify file I/O, and
// as much as possible contain portability problems. Here avoiding
// including windows.h.
//
//=============================================================================
#ifndef FILEIO_H
#define FILEIO_H
#if defined (_WIN32)
typedef __time64_t time64_t;
#else
#include <sys/types.h>
#include <sys/stat.h>
typedef int64_t time64_t;
#if !defined( _PS3 )
#include <signal.h>
#endif // _PS3
#endif
#include "tier0/platform.h"
#include "tier0/t0constants.h"
#include "tier1/utlstring.h"
#include "tier1/utllinkedlist.h"
class CPathString
{
public:
// Constructors: Automatically fixes slashes and removes double slashes when the object is
// constructed, and then knows how to append magic \\?\ on Windows for unicode paths
CPathString( const char *pchUTF8Path );
~CPathString();
// Gets the path in UTF8
const char *GetUTF8Path();
// Gets wchar_t based path, with \\?\ pre-pended (allowing long paths on Win32, should only be used with unicode aware filesystem calls)
const wchar_t *GetWCharPathPrePended();
private:
void PopulateWCharPath();
char *m_pchUTF8Path;
wchar_t *m_pwchWideCharPathPrepended;
};
// iterator class, initialize with the path & pattern you want to want files/dirs for.
//
// all string setters and accessors use UTF-8 encoding.
class CDirIterator
{
public:
#if !defined( _PS3 )
CDirIterator( const char *pchSearchPath );
#endif
CDirIterator( const char *pchPath, const char *pchPattern );
~CDirIterator();
bool IsValid() const;
// fetch the next file
bool BNextFile();
// name of the current file - file portion only, not full path
const char *CurrentFileName();
// size of the current file
int64 CurrentFileLength() const;
// creation time of the current file
time64_t CurrentFileCreateTime() const;
// mod time of the current file
time64_t CurrentFileWriteTime() const;
// mode/type checks:
// is the current file actually a directory?
bool BCurrentIsDir() const;
// is the current file hidden?
bool BCurrentIsHidden() const;
// is the current file read-only?
bool BCurrentIsReadOnly() const;
// is the current file a system file?
bool BCurrentIsSystem() const;
// is the current file's archive bit set?
bool BCurrentIsMarkedForArchive() const;
#ifdef DBGFLAG_VALIDATE
void Validate( CValidator &validator, const char *pchName )
{
#if defined( _PS3 )
ValidateObj( m_strPattern );
#else
validator.ClaimMemory( m_pFindData );
#endif
}
#endif
private:
void Init( const char *pchSearchPath );
bool BValidFilename();
bool m_bNoFiles, m_bUsedFirstFile;
#if defined(_PS3)
bool BFindNextPS3();
bool m_bOpenHandle; // don't see an invalid value for the FD returned from OpenDir
int m_hFind;
CellFsDirectoryEntry *m_pDirEntry;
CUtlString m_strPattern;
#elif defined(_WIN32)
HANDLE m_hFind;
struct _WIN32_FIND_DATAW *m_pFindData;
char m_rgchFileName[MAX_PATH * 4];
#else
int64 m_hFind;
struct _finddata_t *m_pFindData;
#endif
};
//-----------------------------------------------------------------------------
// Purpose: Encapsulates buffered async writing to a large file (one that will require multiple write calls)
// calling Close() or destructing this object will block until the file is completely written
//-----------------------------------------------------------------------------
class CFileWriter
{
public:
// Possible seek types
enum ESeekOrigin
{
k_ESeekSet,
k_ESeekCur,
k_ESeekEnd
};
CFileWriter( bool bAsync = false );
virtual ~CFileWriter();
bool BFileOpen();
bool BSetFile( const char *pchFile, bool bAllowOpenExisting = false );
bool Write( const void *pvData, uint32 cubData );
int Printf( char *pDest, int bufferLen, PRINTF_FORMAT_STRING char const *pFormat, ... );
bool Seek( uint64 offset, ESeekOrigin eOrigin );
void Flush();
void Close();
uint64 GetBytesWritten();
#ifdef _WIN32
static void __stdcall ThreadedWriteFileCompletionFunc( unsigned long dwErrorCode, unsigned long dwBytesTransfered, struct _OVERLAPPED *pOverlapped );
#elif defined( _PS3 )
// not implemented on PS3
#elif defined(POSIX)
static void __stdcall ThreadedWriteFileCompletionFunc( sigval sigval );
#else
#error
#endif
void Sleep( uint nMSec ); // system specific sleep call
private:
HANDLE m_hFileDest;
uint64 m_cubWritten;
volatile int m_cubOutstanding;
bool m_bAsync;
bool m_bDefaultAsync;
uint32 m_unThreadID; // main thread for this FileWriter. On this thread we support correct async IO
// if the CFileWriter is called from any other thread, we block until the write is complete
// this is not great but a good enough for log files and we didn't need a full blow IOCP manager for this.
volatile int m_cPendingCallbacksFromOtherThreads;
};
// data accessor
inline uint64 CFileWriter::GetBytesWritten()
{
return m_cubWritten;
}
#if !defined(_PS3)
//-----------------------------------------------------------------------------
// Purpose: Encapsulates watching a directory for file changes
//-----------------------------------------------------------------------------
class CDirWatcher
{
public:
CDirWatcher();
~CDirWatcher();
// only one directory can be watched at a time
void SetDirToWatch( const char *pchDir );
// retrieve any changes
bool GetChangedFile( CUtlString *psFile );
#ifdef DBGFLAG_VALIDATE
void Validate( CValidator &validator, const char *pchName );
#endif
private:
CUtlLinkedList<CUtlString> m_listChangedFiles;
void *m_hFile;
void *m_pOverlapped;
void *m_pFileInfo;
#ifdef OSX
public:
struct timespec m_modTime;
void AddFileToChangeList( const char *pchFile );
CUtlString m_BaseDir;
private:
void *m_WatcherStream;
#endif
friend class CDirWatcherFriend;
#ifdef LINUX
void AddFileToChangeList( const char *pchFile );
#endif
#ifdef WIN32
// used by callback functions to push a file onto the list
void AddFileToChangeList( const char *pchFile );
void PostDirWatch();
#endif
};
#endif // _PS3
bool CreateDirRecursive( const char *pchPathIn );
bool BFileExists( const char *pchFileNameIn );
bool BCreateDirectory( const char *path );
bool BRemoveDirectoryRecursive( const char *pchPath );
#endif // FILEIO_H

368
public/tier1/fmtstr.h Normal file
View File

@@ -0,0 +1,368 @@
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: A simple class for performing safe and in-expression sprintf-style
// string formatting
//
// $NoKeywords: $
//=============================================================================//
#ifndef FMTSTR_H
#define FMTSTR_H
#include <stdarg.h>
#include <stdio.h>
#include "tier0/platform.h"
#include "tier0/dbg.h"
#include "tier1/strtools.h"
#if defined( _WIN32 )
#pragma once
#endif
//=============================================================================
// using macro to be compatable with GCC
#define FmtStrVSNPrintf( szBuf, nBufSize, bQuietTruncation, ppszFormat, nPrevLen, lastArg ) \
do \
{ \
int result; \
va_list arg_ptr; \
bool bTruncated = false; \
static int scAsserted = 0; \
\
va_start(arg_ptr, lastArg); \
result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \
va_end(arg_ptr); \
\
(szBuf)[(nBufSize)-1] = 0; \
if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \
{ \
Warning( "FmtStrVSNPrintf truncated to %d without QUIET_TRUNCATION specified!\n", ( int )( nBufSize ) ); \
AssertMsg( 0, "FmtStrVSNPrintf truncated without QUIET_TRUNCATION specified!\n" ); \
scAsserted++; \
} \
m_nLength = nPrevLen + result; \
} \
while (0)
// using macro to be compatable with GCC
#define FmtStrVSNPrintfNoLengthFixup( szBuf, nBufSize, bQuietTruncation, ppszFormat, nPrevLen, lastArg ) \
do \
{ \
int result; \
va_list arg_ptr; \
bool bTruncated = false; \
static int scAsserted = 0; \
\
va_start(arg_ptr, lastArg); \
result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \
va_end(arg_ptr); \
\
(szBuf)[(nBufSize)-1] = 0; \
if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \
{ \
Warning( "FmtStrVSNPrintf truncated to %d without QUIET_TRUNCATION specified!\n", ( int )( nBufSize ) ); \
AssertMsg( 0, "FmtStrVSNPrintf truncated without QUIET_TRUNCATION specified!\n" ); \
scAsserted++; \
} \
} \
while (0)
//-----------------------------------------------------------------------------
//
// Purpose: String formatter with specified size
//
template <int SIZE_BUF, bool QUIET_TRUNCATION = false >
class CFmtStrN
{
public:
CFmtStrN()
{
InitQuietTruncation();
m_szBuf[0] = 0;
m_nLength = 0;
}
// Standard C formatting
CFmtStrN(PRINTF_FORMAT_STRING const char *pszFormat, ...) FMTFUNCTION( 2, 3 )
{
InitQuietTruncation();
FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
}
// Use this for pass-through formatting
CFmtStrN(const char ** ppszFormat, ...)
{
InitQuietTruncation();
FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat, 0, ppszFormat );
}
// Explicit reformat
const char *sprintf(PRINTF_FORMAT_STRING const char *pszFormat, ...) FMTFUNCTION( 2, 3 )
{
InitQuietTruncation();
FmtStrVSNPrintf(m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
return m_szBuf;
}
// Same as sprintf above, but for compatibility with Steam interface
const char *Format( PRINTF_FORMAT_STRING const char *pszFormat, ... ) FMTFUNCTION( 2, 3 )
{
InitQuietTruncation();
FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
return m_szBuf;
}
// Use this for va_list formatting
const char *sprintf_argv(const char *pszFormat, va_list arg_ptr)
{
int result;
bool bTruncated = false;
static int s_nWarned = 0;
InitQuietTruncation();
result = V_vsnprintfRet( m_szBuf, SIZE_BUF - 1, pszFormat, arg_ptr, &bTruncated );
m_szBuf[SIZE_BUF - 1] = 0;
if ( bTruncated && !m_bQuietTruncation && ( s_nWarned < 5 ) )
{
Warning( "CFmtStr truncated to %d without QUIET_TRUNCATION specified!\n", SIZE_BUF );
AssertMsg( 0, "CFmtStr truncated without QUIET_TRUNCATION specified!\n" );
s_nWarned++;
}
m_nLength = V_strlen( m_szBuf );
return m_szBuf;
}
// Use this for pass-through formatting
void VSprintf(const char **ppszFormat, ...)
{
InitQuietTruncation();
FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat, 0, ppszFormat );
}
// Compatible API with CUtlString for converting to const char*
const char *Get( ) const { return m_szBuf; }
const char *String( ) const { return m_szBuf; }
// Use for access
operator const char *() const { return m_szBuf; }
char *Access() { return m_szBuf; }
// Access template argument
static inline int GetMaxLength() { return SIZE_BUF-1; }
CFmtStrN<SIZE_BUF,QUIET_TRUNCATION> & operator=( const char *pchValue )
{
V_strncpy( m_szBuf, pchValue, SIZE_BUF );
m_nLength = V_strlen( m_szBuf );
return *this;
}
CFmtStrN<SIZE_BUF,QUIET_TRUNCATION> & operator+=( const char *pchValue )
{
Append( pchValue );
return *this;
}
int Length() const { return m_nLength; }
void SetLength( int nLength )
{
m_nLength = Min( nLength, SIZE_BUF - 1 );
m_szBuf[m_nLength] = '\0';
}
void Clear()
{
m_szBuf[0] = 0;
m_nLength = 0;
}
void AppendFormat( PRINTF_FORMAT_STRING const char *pchFormat, ... ) FMTFUNCTION( 2, 3 )
{
char *pchEnd = m_szBuf + m_nLength;
FmtStrVSNPrintf( pchEnd, SIZE_BUF - m_nLength, m_bQuietTruncation, &pchFormat, m_nLength, pchFormat );
}
void AppendFormatV( const char *pchFormat, va_list args );
void Append( const char *pchValue )
{
// This function is close to the metal to cut down on the CPU cost
// of the previous incantation of Append which was implemented as
// AppendFormat( "%s", pchValue ). This implementation, though not
// as easy to read, instead does a strcpy from the existing end
// point of the CFmtStrN. This brings something like a 10-20x speedup
// in my rudimentary tests. It isn't using V_strncpy because that
// function doesn't return the number of characters copied, which
// we need to adjust m_nLength. Doing the V_strncpy with a V_strlen
// afterwards took twice as long as this implementations in tests,
// so V_strncpy's implementation was used to write this method.
char *pDest = m_szBuf + m_nLength;
const int maxLen = SIZE_BUF - m_nLength;
char *pLast = pDest + maxLen - 1;
while ( (pDest < pLast) && (*pchValue != 0) )
{
*pDest = *pchValue;
++pDest; ++pchValue;
}
*pDest = 0;
m_nLength = pDest - m_szBuf;
}
//optimized version of append for just adding a single character
void Append( char ch )
{
if( m_nLength < SIZE_BUF - 1 )
{
m_szBuf[ m_nLength ] = ch;
m_nLength++;
m_szBuf[ m_nLength ] = '\0';
}
}
void AppendIndent( uint32 unCount, char chIndent = '\t' );
void SetQuietTruncation( bool bQuiet ) { m_bQuietTruncation = bQuiet; }
protected:
virtual void InitQuietTruncation()
{
m_bQuietTruncation = QUIET_TRUNCATION;
}
bool m_bQuietTruncation;
private:
char m_szBuf[SIZE_BUF];
int m_nLength;
};
// Version which will not assert if strings are truncated
template < int SIZE_BUF >
class CFmtStrQuietTruncationN : public CFmtStrN<SIZE_BUF, true >
{
};
template< int SIZE_BUF, bool QUIET_TRUNCATION >
void CFmtStrN< SIZE_BUF, QUIET_TRUNCATION >::AppendIndent( uint32 unCount, char chIndent )
{
Assert( Length() + unCount < SIZE_BUF );
if( Length() + unCount >= SIZE_BUF )
unCount = SIZE_BUF - (1+Length());
for ( uint32 x = 0; x < unCount; x++ )
{
m_szBuf[ m_nLength++ ] = chIndent;
}
m_szBuf[ m_nLength ] = '\0';
}
template< int SIZE_BUF, bool QUIET_TRUNCATION >
void CFmtStrN< SIZE_BUF, QUIET_TRUNCATION >::AppendFormatV( const char *pchFormat, va_list args )
{
int cubPrinted = V_vsnprintf( m_szBuf+Length(), SIZE_BUF - Length(), pchFormat, args );
m_nLength += cubPrinted;
}
//-----------------------------------------------------------------------------
//
// Purpose: Default-sized string formatter
//
#define FMTSTR_STD_LEN 256
typedef CFmtStrN<FMTSTR_STD_LEN> CFmtStr;
typedef CFmtStrQuietTruncationN<FMTSTR_STD_LEN> CFmtStrQuietTruncation;
typedef CFmtStrN<32> CFmtStr32;
typedef CFmtStrN<1024> CFmtStr1024;
typedef CFmtStrN<8192> CFmtStrMax;
//-----------------------------------------------------------------------------
// Purpose: Fast-path number-to-string helper (with optional quoting)
// Derived off of the Steam CNumStr but with a few tweaks, such as
// trimming off the in-our-cases-unnecessary strlen calls (by not
// storing the length in the class).
//-----------------------------------------------------------------------------
class CNumStr
{
public:
CNumStr() { m_szBuf[0] = 0; }
explicit CNumStr( bool b ) { SetBool( b ); }
explicit CNumStr( int8 n8 ) { SetInt8( n8 ); }
explicit CNumStr( uint8 un8 ) { SetUint8( un8 ); }
explicit CNumStr( int16 n16 ) { SetInt16( n16 ); }
explicit CNumStr( uint16 un16 ) { SetUint16( un16 ); }
explicit CNumStr( int32 n32 ) { SetInt32( n32 ); }
explicit CNumStr( uint32 un32 ) { SetUint32( un32 ); }
explicit CNumStr( int64 n64 ) { SetInt64( n64 ); }
explicit CNumStr( uint64 un64 ) { SetUint64( un64 ); }
#if defined(COMPILER_GCC) && defined(PLATFORM_64BITS)
explicit CNumStr( lint64 n64 ) { SetInt64( (int64)n64 ); }
explicit CNumStr( ulint64 un64 ) { SetUint64( (uint64)un64 ); }
#endif
explicit CNumStr( double f ) { SetDouble( f ); }
explicit CNumStr( float f ) { SetFloat( f ); }
inline void SetBool( bool b ) { Q_memcpy( m_szBuf, b ? "1" : "0", 2 ); }
#ifdef _WIN32
inline void SetInt8( int8 n8 ) { _itoa( (int32)n8, m_szBuf, 10 ); }
inline void SetUint8( uint8 un8 ) { _itoa( (int32)un8, m_szBuf, 10 ); }
inline void SetInt16( int16 n16 ) { _itoa( (int32)n16, m_szBuf, 10 ); }
inline void SetUint16( uint16 un16 ) { _itoa( (int32)un16, m_szBuf, 10 ); }
inline void SetInt32( int32 n32 ) { _itoa( n32, m_szBuf, 10 ); }
inline void SetUint32( uint32 un32 ) { _i64toa( (int64)un32, m_szBuf, 10 ); }
inline void SetInt64( int64 n64 ) { _i64toa( n64, m_szBuf, 10 ); }
inline void SetUint64( uint64 un64 ) { _ui64toa( un64, m_szBuf, 10 ); }
#else
inline void SetInt8( int8 n8 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)n8 ); }
inline void SetUint8( uint8 un8 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)un8 ); }
inline void SetInt16( int16 n16 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)n16 ); }
inline void SetUint16( uint16 un16 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)un16 ); }
inline void SetInt32( int32 n32 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", n32 ); }
inline void SetUint32( uint32 un32 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%u", un32 ); }
inline void SetInt64( int64 n64 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%lld", n64 ); }
inline void SetUint64( uint64 un64 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%llu", un64 ); }
#endif
inline void SetDouble( double f ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%.18g", f ); }
inline void SetFloat( float f ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%.18g", f ); }
inline void SetHexUint64( uint64 un64 ) { Q_binarytohex( (byte *)&un64, sizeof( un64 ), m_szBuf, sizeof( m_szBuf ) ); }
operator const char *() const { return m_szBuf; }
const char* String() const { return m_szBuf; }
void AddQuotes()
{
Assert( m_szBuf[0] != '"' );
const int nLength = Q_strlen( m_szBuf );
Q_memmove( m_szBuf + 1, m_szBuf, nLength );
m_szBuf[0] = '"';
m_szBuf[nLength + 1] = '"';
m_szBuf[nLength + 2] = 0;
}
protected:
char m_szBuf[28]; // long enough to hold 18 digits of precision, a decimal, a - sign, e+### suffix, and quotes
};
//=============================================================================
const int k_cchFormattedDate = 64;
const int k_cchFormattedTime = 32;
bool BGetLocalFormattedTime( time_t timeVal, char *pchDate, int cubDate, char *pchTime, int cubTime );
#endif // FMTSTR_H

920
public/tier1/functors.h Normal file
View File

@@ -0,0 +1,920 @@
//========== Copyright © 2006, Valve Corporation, All rights reserved. ========
//
// Purpose: Implements a generic infrastucture for functors combining
// a number of techniques to provide transparent parameter type
// deduction and packaging. Supports both member and non-member functions.
//
// See also: http://en.wikipedia.org/wiki/Function_object
//
// Note that getting into the guts of this file is not for the
// feint of heart. The core concept here is that the compiler can
// figure out all the parameter types.
//
// E.g.:
//
// struct CMyClass
// {
// void foo( int i) {}
// };
//
// int bar(int i) { return i; }
//
// CMyClass myInstance;
//
// CFunctor *pFunctor = CreateFunctor( &myInstance, CMyClass::foo, 8675 );
// CFunctor *pFunctor2 = CreateFunctor( &bar, 309 );
//
// void CallEm()
// {
// (*pFunctor)();
// (*pFunctor2)();
// }
//
//=============================================================================
#ifndef FUNCTORS_H
#define FUNCTORS_H
#if defined( _WIN32 )
#pragma once
#endif
#include "tier0/platform.h"
#include "tier1/refcount.h"
#include "tier1/utlenvelope.h"
#include <typeinfo>
//-----------------------------------------------------------------------------
//
// Macros used as basis for template generation. Just ignore the man behind the
// curtain
//
//-----------------------------------------------------------------------------
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_0
#define FUNC_TEMPLATE_ARG_PARAMS_0
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_0
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_0
#define FUNC_ARG_MEMBERS_0
#define FUNC_ARG_FORMAL_PARAMS_0
#define FUNC_PROXY_ARG_FORMAL_PARAMS_0
#define FUNC_CALL_ARGS_INIT_0
#define FUNC_SOLO_CALL_ARGS_INIT_0
#define FUNC_CALL_MEMBER_ARGS_0
#define FUNC_CALL_ARGS_0
#define FUNC_CALL_DATA_ARGS_0( _var )
#define FUNC_FUNCTOR_CALL_ARGS_0
#define FUNC_TEMPLATE_FUNC_PARAMS_0
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_0
#define FUNC_VALIDATION_STRING_0 Q_snprintf( pString, nBufLen, "method( void )" );
#define FUNC_SEPARATOR_0
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_1 typename ARG_TYPE_1
#define FUNC_TEMPLATE_ARG_PARAMS_1 , typename ARG_TYPE_1
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_1 , ARG_TYPE_1
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_1 ARG_TYPE_1
#define FUNC_ARG_MEMBERS_1 ARG_TYPE_1 m_arg1
#define FUNC_ARG_FORMAL_PARAMS_1 , const ARG_TYPE_1 &arg1
#define FUNC_PROXY_ARG_FORMAL_PARAMS_1 const ARG_TYPE_1 &arg1
#define FUNC_CALL_ARGS_INIT_1 , m_arg1( arg1 )
#define FUNC_SOLO_CALL_ARGS_INIT_1 : m_arg1( arg1 )
#define FUNC_CALL_MEMBER_ARGS_1 m_arg1
#define FUNC_CALL_ARGS_1 arg1
#define FUNC_CALL_DATA_ARGS_1( _var ) _var->m_arg1
#define FUNC_FUNCTOR_CALL_ARGS_1 , arg1
#define FUNC_TEMPLATE_FUNC_PARAMS_1 , typename FUNC_ARG_TYPE_1
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_1 FUNC_ARG_TYPE_1
#define FUNC_VALIDATION_STRING_1 Q_snprintf( pString, nBufLen, "method( %s )", typeid( ARG_TYPE_1 ).name() );
#define FUNC_SEPARATOR_1 ,
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_2 typename ARG_TYPE_1, typename ARG_TYPE_2
#define FUNC_TEMPLATE_ARG_PARAMS_2 , typename ARG_TYPE_1, typename ARG_TYPE_2
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_2 , ARG_TYPE_1, ARG_TYPE_2
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_2 ARG_TYPE_1, ARG_TYPE_2
#define FUNC_ARG_MEMBERS_2 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2
#define FUNC_ARG_FORMAL_PARAMS_2 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2
#define FUNC_PROXY_ARG_FORMAL_PARAMS_2 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2
#define FUNC_CALL_ARGS_INIT_2 , m_arg1( arg1 ), m_arg2( arg2 )
#define FUNC_SOLO_CALL_ARGS_INIT_2 : m_arg1( arg1 ), m_arg2( arg2 )
#define FUNC_CALL_MEMBER_ARGS_2 m_arg1, m_arg2
#define FUNC_CALL_ARGS_2 arg1, arg2
#define FUNC_CALL_DATA_ARGS_2( _var ) _var->m_arg1, _var->m_arg2
#define FUNC_FUNCTOR_CALL_ARGS_2 , arg1, arg2
#define FUNC_TEMPLATE_FUNC_PARAMS_2 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_2 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2
#define FUNC_VALIDATION_STRING_2 Q_snprintf( pString, nBufLen, "method( %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name() );
#define FUNC_SEPARATOR_2 ,
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_3 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3
#define FUNC_TEMPLATE_ARG_PARAMS_3 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_3 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_3 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3
#define FUNC_ARG_MEMBERS_3 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3
#define FUNC_ARG_FORMAL_PARAMS_3 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3
#define FUNC_PROXY_ARG_FORMAL_PARAMS_3 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3
#define FUNC_CALL_ARGS_INIT_3 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 )
#define FUNC_SOLO_CALL_ARGS_INIT_3 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 )
#define FUNC_CALL_MEMBER_ARGS_3 m_arg1, m_arg2, m_arg3
#define FUNC_CALL_ARGS_3 arg1, arg2, arg3
#define FUNC_CALL_DATA_ARGS_3( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3
#define FUNC_FUNCTOR_CALL_ARGS_3 , arg1, arg2, arg3
#define FUNC_TEMPLATE_FUNC_PARAMS_3 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_3 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3
#define FUNC_VALIDATION_STRING_3 Q_snprintf( pString, nBufLen, "method( %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name() );
#define FUNC_SEPARATOR_3 ,
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_4 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4
#define FUNC_TEMPLATE_ARG_PARAMS_4 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_4 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_4 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4
#define FUNC_ARG_MEMBERS_4 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4
#define FUNC_ARG_FORMAL_PARAMS_4 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4
#define FUNC_PROXY_ARG_FORMAL_PARAMS_4 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4
#define FUNC_CALL_ARGS_INIT_4 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 )
#define FUNC_SOLO_CALL_ARGS_INIT_4 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 )
#define FUNC_CALL_MEMBER_ARGS_4 m_arg1, m_arg2, m_arg3, m_arg4
#define FUNC_CALL_ARGS_4 arg1, arg2, arg3, arg4
#define FUNC_CALL_DATA_ARGS_4( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4
#define FUNC_FUNCTOR_CALL_ARGS_4 , arg1, arg2, arg3, arg4
#define FUNC_TEMPLATE_FUNC_PARAMS_4 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_4 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4
#define FUNC_VALIDATION_STRING_4 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name() );
#define FUNC_SEPARATOR_4 ,
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_5 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5
#define FUNC_TEMPLATE_ARG_PARAMS_5 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_5 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_5 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5
#define FUNC_ARG_MEMBERS_5 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5
#define FUNC_ARG_FORMAL_PARAMS_5 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5
#define FUNC_PROXY_ARG_FORMAL_PARAMS_5 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5
#define FUNC_CALL_ARGS_INIT_5 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 )
#define FUNC_SOLO_CALL_ARGS_INIT_5 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 )
#define FUNC_CALL_MEMBER_ARGS_5 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5
#define FUNC_CALL_ARGS_5 arg1, arg2, arg3, arg4, arg5
#define FUNC_CALL_DATA_ARGS_5( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5
#define FUNC_FUNCTOR_CALL_ARGS_5 , arg1, arg2, arg3, arg4, arg5
#define FUNC_TEMPLATE_FUNC_PARAMS_5 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_5 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5
#define FUNC_VALIDATION_STRING_5 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name() );
#define FUNC_SEPARATOR_5 ,
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_6 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6
#define FUNC_TEMPLATE_ARG_PARAMS_6 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_6 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_6 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6
#define FUNC_ARG_MEMBERS_6 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6
#define FUNC_ARG_FORMAL_PARAMS_6 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6
#define FUNC_PROXY_ARG_FORMAL_PARAMS_6 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6
#define FUNC_CALL_ARGS_INIT_6 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 )
#define FUNC_SOLO_CALL_ARGS_INIT_6 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 )
#define FUNC_CALL_MEMBER_ARGS_6 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6
#define FUNC_CALL_ARGS_6 arg1, arg2, arg3, arg4, arg5, arg6
#define FUNC_CALL_DATA_ARGS_6( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6
#define FUNC_FUNCTOR_CALL_ARGS_6 , arg1, arg2, arg3, arg4, arg5, arg6
#define FUNC_TEMPLATE_FUNC_PARAMS_6 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_6 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6
#define FUNC_VALIDATION_STRING_6 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name() );
#define FUNC_SEPARATOR_6 ,
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_7 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7
#define FUNC_TEMPLATE_ARG_PARAMS_7 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_7 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_7 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7
#define FUNC_ARG_MEMBERS_7 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7;
#define FUNC_ARG_FORMAL_PARAMS_7 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7
#define FUNC_PROXY_ARG_FORMAL_PARAMS_7 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7
#define FUNC_CALL_ARGS_INIT_7 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 )
#define FUNC_SOLO_CALL_ARGS_INIT_7 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 )
#define FUNC_CALL_MEMBER_ARGS_7 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7
#define FUNC_CALL_ARGS_7 arg1, arg2, arg3, arg4, arg5, arg6, arg7
#define FUNC_CALL_DATA_ARGS_7( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7
#define FUNC_FUNCTOR_CALL_ARGS_7 , arg1, arg2, arg3, arg4, arg5, arg6, arg7
#define FUNC_TEMPLATE_FUNC_PARAMS_7 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_7 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7
#define FUNC_VALIDATION_STRING_7 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name() );
#define FUNC_SEPARATOR_7 ,
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_8 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8
#define FUNC_TEMPLATE_ARG_PARAMS_8 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_8 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_8 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8
#define FUNC_ARG_MEMBERS_8 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8;
#define FUNC_ARG_FORMAL_PARAMS_8 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8
#define FUNC_PROXY_ARG_FORMAL_PARAMS_8 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8
#define FUNC_CALL_ARGS_INIT_8 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 )
#define FUNC_SOLO_CALL_ARGS_INIT_8 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 )
#define FUNC_CALL_MEMBER_ARGS_8 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8
#define FUNC_CALL_ARGS_8 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8
#define FUNC_CALL_DATA_ARGS_8( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8
#define FUNC_FUNCTOR_CALL_ARGS_8 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8
#define FUNC_TEMPLATE_FUNC_PARAMS_8 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_8 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8
#define FUNC_VALIDATION_STRING_8 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name() );
#define FUNC_SEPARATOR_8 ,
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_9 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9
#define FUNC_TEMPLATE_ARG_PARAMS_9 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_9 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_9 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9
#define FUNC_ARG_MEMBERS_9 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9;
#define FUNC_ARG_FORMAL_PARAMS_9 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9
#define FUNC_PROXY_ARG_FORMAL_PARAMS_9 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9
#define FUNC_CALL_ARGS_INIT_9 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 )
#define FUNC_SOLO_CALL_ARGS_INIT_9 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 )
#define FUNC_CALL_MEMBER_ARGS_9 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9
#define FUNC_CALL_ARGS_9 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
#define FUNC_CALL_DATA_ARGS_9( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9
#define FUNC_FUNCTOR_CALL_ARGS_9 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
#define FUNC_TEMPLATE_FUNC_PARAMS_9 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_9 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9
#define FUNC_VALIDATION_STRING_9 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name() );
#define FUNC_SEPARATOR_9 ,
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_10 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10
#define FUNC_TEMPLATE_ARG_PARAMS_10 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_10 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_10 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10
#define FUNC_ARG_MEMBERS_10 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10;
#define FUNC_ARG_FORMAL_PARAMS_10 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10
#define FUNC_PROXY_ARG_FORMAL_PARAMS_10 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10
#define FUNC_CALL_ARGS_INIT_10 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 )
#define FUNC_SOLO_CALL_ARGS_INIT_10 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 )
#define FUNC_CALL_MEMBER_ARGS_10 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10
#define FUNC_CALL_ARGS_10 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10
#define FUNC_CALL_DATA_ARGS_10( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10
#define FUNC_FUNCTOR_CALL_ARGS_10 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10
#define FUNC_TEMPLATE_FUNC_PARAMS_10 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_10 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10
#define FUNC_VALIDATION_STRING_10 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name() );
#define FUNC_SEPARATOR_10 ,
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_11 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11
#define FUNC_TEMPLATE_ARG_PARAMS_11 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_11 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_11 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11
#define FUNC_ARG_MEMBERS_11 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11
#define FUNC_ARG_FORMAL_PARAMS_11 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11
#define FUNC_PROXY_ARG_FORMAL_PARAMS_11 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11
#define FUNC_CALL_ARGS_INIT_11 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 )
#define FUNC_SOLO_CALL_ARGS_INIT_11 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 )
#define FUNC_CALL_MEMBER_ARGS_11 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11
#define FUNC_CALL_ARGS_11 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11
#define FUNC_CALL_DATA_ARGS_11( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10, _var->m_arg11
#define FUNC_FUNCTOR_CALL_ARGS_11 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11
#define FUNC_TEMPLATE_FUNC_PARAMS_11 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_11 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11
#define FUNC_VALIDATION_STRING_11 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name(), typeid( ARG_TYPE_11 ).name() );
#define FUNC_SEPARATOR_11 ,
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_12 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12
#define FUNC_TEMPLATE_ARG_PARAMS_12 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_12 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_12 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12
#define FUNC_ARG_MEMBERS_12 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12
#define FUNC_ARG_FORMAL_PARAMS_12 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12
#define FUNC_PROXY_ARG_FORMAL_PARAMS_12 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12
#define FUNC_CALL_ARGS_INIT_12 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 )
#define FUNC_SOLO_CALL_ARGS_INIT_12 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 )
#define FUNC_CALL_MEMBER_ARGS_12 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12
#define FUNC_CALL_ARGS_12 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12
#define FUNC_CALL_DATA_ARGS_12( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10, _var->m_arg11, _var->m_arg12
#define FUNC_FUNCTOR_CALL_ARGS_12 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12
#define FUNC_TEMPLATE_FUNC_PARAMS_12 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_12 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12
#define FUNC_VALIDATION_STRING_12 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name(), typeid( ARG_TYPE_11 ).name(), typeid( ARG_TYPE_12 ).name() );
#define FUNC_SEPARATOR_12 ,
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_13 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13
#define FUNC_TEMPLATE_ARG_PARAMS_13 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_13 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_13 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13
#define FUNC_ARG_MEMBERS_13 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12; ARG_TYPE_13 m_arg13
#define FUNC_ARG_FORMAL_PARAMS_13 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13
#define FUNC_PROXY_ARG_FORMAL_PARAMS_13 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13
#define FUNC_CALL_ARGS_INIT_13 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 )
#define FUNC_SOLO_CALL_ARGS_INIT_13 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 )
#define FUNC_CALL_MEMBER_ARGS_13 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13
#define FUNC_CALL_ARGS_13 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13
#define FUNC_CALL_DATA_ARGS_13( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10, _var->m_arg11, _var->m_arg12, _var->m_arg13
#define FUNC_FUNCTOR_CALL_ARGS_13 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13
#define FUNC_TEMPLATE_FUNC_PARAMS_13 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12, typename FUNC_ARG_TYPE_13
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_13 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12, FUNC_ARG_TYPE_13
#define FUNC_VALIDATION_STRING_13 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name(), typeid( ARG_TYPE_11 ).name(), typeid( ARG_TYPE_12 ).name(), typeid( ARG_TYPE_13 ).name() );
#define FUNC_SEPARATOR_13 ,
#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_14 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13, typename ARG_TYPE_14
#define FUNC_TEMPLATE_ARG_PARAMS_14 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13, typename ARG_TYPE_14
#define FUNC_BASE_TEMPLATE_ARG_PARAMS_14 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13, ARG_TYPE_14
#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_14 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13, ARG_TYPE_14
#define FUNC_ARG_MEMBERS_14 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12; ARG_TYPE_13 m_arg13; ARG_TYPE_14 m_arg14
#define FUNC_ARG_FORMAL_PARAMS_14 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13, const ARG_TYPE_14 &arg14
#define FUNC_PROXY_ARG_FORMAL_PARAMS_14 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13, const ARG_TYPE_14 &arg14
#define FUNC_CALL_ARGS_INIT_14 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 ), m_arg14( arg14 )
#define FUNC_SOLO_CALL_ARGS_INIT_14 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 ), m_arg14( arg14 )
#define FUNC_CALL_MEMBER_ARGS_14 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14
#define FUNC_CALL_ARGS_14 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14
#define FUNC_CALL_DATA_ARGS_14( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10, _var->m_arg11, _var->m_arg12, _var->m_arg13, _var->m_arg14
#define FUNC_FUNCTOR_CALL_ARGS_14 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14
#define FUNC_TEMPLATE_FUNC_PARAMS_14 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12, typename FUNC_ARG_TYPE_13, typename FUNC_ARG_TYPE_14
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_14 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12, FUNC_ARG_TYPE_13, FUNC_ARG_TYPE_14
#define FUNC_VALIDATION_STRING_14 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name(), typeid( ARG_TYPE_11 ).name(), typeid( ARG_TYPE_12 ).name(), typeid( ARG_TYPE_13 ).name(), typeid( ARG_TYPE_14 ).name() );
#define FUNC_SEPARATOR_14 ,
#define FUNC_GENERATE_ALL_BUT0( INNERMACRONAME ) \
INNERMACRONAME(1); \
INNERMACRONAME(2); \
INNERMACRONAME(3); \
INNERMACRONAME(4); \
INNERMACRONAME(5); \
INNERMACRONAME(6); \
INNERMACRONAME(7); \
INNERMACRONAME(8); \
INNERMACRONAME(9); \
INNERMACRONAME(10);\
INNERMACRONAME(11);\
INNERMACRONAME(12);\
INNERMACRONAME(13);\
INNERMACRONAME(14)
#define FUNC_GENERATE_ALL( INNERMACRONAME ) \
INNERMACRONAME(0); \
FUNC_GENERATE_ALL_BUT0( INNERMACRONAME )
//-----------------------------------------------------------------------------
//
// Purpose: Base class of all function objects
//
//-----------------------------------------------------------------------------
abstract_class CFunctor : public IRefCounted
{
public:
CFunctor()
{
#ifdef DEBUG
m_nUserID = 0;
#endif
}
virtual ~CFunctor() {}
virtual void operator()() = 0;
unsigned m_nUserID; // For debugging
};
//-----------------------------------------------------------------------------
// NOTE: Functor data + functor callback are tied together
// The basic idea is that someone creates the functor data. At a later point,
// the functor data is passed to a functor callback. Validation strings
// are compared in debug builds to ensure the data matches the callback
//-----------------------------------------------------------------------------
abstract_class CFunctorData : public IRefCounted
{
public:
virtual void ComputeValidationString( char *pString, size_t nBufLen ) const = 0;
};
abstract_class CFunctorCallback : public IRefCounted
{
public:
virtual bool IsEqual( CFunctorCallback *pSrc ) const = 0;
virtual void operator()( CFunctorData *pData ) = 0;
virtual void ComputeValidationString( char *pString, size_t nBufLen ) const = 0;
virtual const char *GetImplClassName() const = 0;
virtual const void *GetTarget() const = 0;
};
//-----------------------------------------------------------------------------
// When calling through a functor, care needs to be taken to not pass objects that might go away.
// Since this code determines the type to store in the functor based on the actual arguments,
// this is achieved by changing the point of call.
//
// See also CUtlEnvelope
//-----------------------------------------------------------------------------
// convert a reference to a passable value
template <typename T>
inline T RefToVal(const T &item)
{
return item;
}
//-----------------------------------------------------------------------------
// This class can be used to pass into a functor a proxy object for a pointer
// to be resolved later. For example, you can execute a "call" on a resource
// whose actual value is not known until a later time
//-----------------------------------------------------------------------------
template <typename T>
class CLateBoundPtr
{
public:
CLateBoundPtr( T **ppObject )
: m_ppObject( ppObject )
{
}
T *operator->() { return *m_ppObject; }
T &operator *() { return **m_ppObject; }
operator T *() const { return (T*)(*m_ppObject); }
operator void *() { return *m_ppObject; }
private:
T **m_ppObject;
};
//-----------------------------------------------------------------------------
//
// Purpose: Classes to define memory management policies when operating
// on pointers to members
//
//-----------------------------------------------------------------------------
class CFuncMemPolicyNone
{
public:
static void OnAcquire(void *pObject) {}
static void OnRelease(void *pObject) {}
};
template <class OBJECT_TYPE_PTR = IRefCounted *>
class CFuncMemPolicyRefCount
{
public:
static void OnAcquire(OBJECT_TYPE_PTR pObject) { pObject->AddRef(); }
static void OnRelease(OBJECT_TYPE_PTR pObject) { pObject->Release(); }
};
//-----------------------------------------------------------------------------
//
// Purpose: Function proxy is a generic facility for holding a function
// pointer. Can be used on own, though primarily for use
// by this file
//
//-----------------------------------------------------------------------------
template <class OBJECT_TYPE_PTR, typename FUNCTION_TYPE, class MEM_POLICY = CFuncMemPolicyNone >
class CMemberFuncProxyBase
{
public:
bool operator==( const CMemberFuncProxyBase &src ) const
{
return m_pfnProxied == src.m_pfnProxied && m_pObject == src.m_pObject;
}
const void *GetTarget() const
{
return m_pObject;
}
protected:
CMemberFuncProxyBase( OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied )
: m_pObject( pObject ),
m_pfnProxied( pfnProxied )
{
MEM_POLICY::OnAcquire(m_pObject);
}
~CMemberFuncProxyBase()
{
MEM_POLICY::OnRelease(m_pObject);
}
void Set( OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied )
{
m_pfnProxied = pfnProxied;
m_pObject = pObject;
}
void OnCall()
{
Assert( (void *)m_pObject != NULL );
}
FUNCTION_TYPE m_pfnProxied;
OBJECT_TYPE_PTR m_pObject;
};
#define DEFINE_MEMBER_FUNC_PROXY( N ) \
template <class OBJECT_TYPE_PTR, typename FUNCTION_TYPE FUNC_TEMPLATE_ARG_PARAMS_##N, class MEM_POLICY = CFuncMemPolicyNone> \
class CMemberFuncProxy##N : public CMemberFuncProxyBase<OBJECT_TYPE_PTR, FUNCTION_TYPE, MEM_POLICY> \
{ \
public: \
CMemberFuncProxy##N( OBJECT_TYPE_PTR pObject = NULL, FUNCTION_TYPE pfnProxied = NULL ) \
: CMemberFuncProxyBase<OBJECT_TYPE_PTR, FUNCTION_TYPE, MEM_POLICY >( pObject, pfnProxied ) \
{ \
} \
\
void operator()( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) \
{ \
this->OnCall(); \
((*this->m_pObject).*this->m_pfnProxied)( FUNC_CALL_ARGS_##N ); \
} \
}
FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNC_PROXY );
//-----------------------------------------------------------------------------
//
// The actual functor implementation
//
//-----------------------------------------------------------------------------
#include "tier0/memdbgon.h"
typedef CRefCounted1<CFunctor, CRefCountServiceMT> CFunctorBase;
#define DEFINE_FUNCTOR_TEMPLATE(N) \
template <typename FUNC_TYPE FUNC_TEMPLATE_ARG_PARAMS_##N, class FUNCTOR_BASE = CFunctorBase> \
class CFunctor##N : public CFunctorBase \
{ \
public: \
CFunctor##N( FUNC_TYPE pfnProxied FUNC_ARG_FORMAL_PARAMS_##N ) : m_pfnProxied( pfnProxied ) FUNC_CALL_ARGS_INIT_##N {} \
void operator()() { m_pfnProxied(FUNC_CALL_MEMBER_ARGS_##N); } \
\
private: \
FUNC_TYPE m_pfnProxied; \
FUNC_ARG_MEMBERS_##N; \
}
FUNC_GENERATE_ALL( DEFINE_FUNCTOR_TEMPLATE );
#define DEFINE_MEMBER_FUNCTOR( N ) \
template <class OBJECT_TYPE_PTR, typename FUNCTION_TYPE FUNC_TEMPLATE_ARG_PARAMS_##N, class FUNCTOR_BASE = CFunctorBase, class MEM_POLICY = CFuncMemPolicyNone> \
class CMemberFunctor##N : public FUNCTOR_BASE \
{ \
public: \
CMemberFunctor##N( OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied FUNC_ARG_FORMAL_PARAMS_##N ) : m_Proxy( pObject, pfnProxied ) FUNC_CALL_ARGS_INIT_##N {} \
void operator()() { m_Proxy(FUNC_CALL_MEMBER_ARGS_##N); } \
\
private: \
CMemberFuncProxy##N<OBJECT_TYPE_PTR, FUNCTION_TYPE FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, MEM_POLICY> m_Proxy; \
FUNC_ARG_MEMBERS_##N; \
};
FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR );
typedef CRefCounted1<CFunctorData, CRefCountServiceMT> CFunctorDataBase;
class CFunctorCallbackBase : public CRefCounted1<CFunctorCallback, CRefCountServiceMT>
{
protected:
virtual void ValidateFunctorData( CFunctorData *pData )
{
#ifdef _DEBUG
char pDataString[1024];
char pCallbackString[1024];
ComputeValidationString( pCallbackString, sizeof(pCallbackString) );
pData->ComputeValidationString( pDataString, sizeof(pDataString) );
bool bMatch = !Q_stricmp( pDataString, pCallbackString );
if ( !bMatch )
{
Warning( "Functor doesn't match data!\n\tExpected:\t%s\n\tEncountered:\t%s\n",
pCallbackString, pDataString );
Assert( 0 );
}
#endif
}
};
#define DEFINE_FUNCTOR_DATA_TEMPLATE(N) \
template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \
class CFunctorData##N : public CFunctorDataBase \
{ \
public: \
CFunctorData##N( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) FUNC_SOLO_CALL_ARGS_INIT_##N {} \
virtual void ComputeValidationString( char *pString, size_t nBufLen ) const { FUNC_VALIDATION_STRING_##N } \
FUNC_ARG_MEMBERS_##N; \
}
class CFunctorData0 : public CFunctorDataBase
{
public:
CFunctorData0( ) {}
virtual void ComputeValidationString( char *pString, size_t nBufLen_ ) const { int nBufLen = (int)nBufLen_; FUNC_VALIDATION_STRING_0 }
};
FUNC_GENERATE_ALL_BUT0( DEFINE_FUNCTOR_DATA_TEMPLATE );
#define DEFINE_FUNCTOR_CALLBACK_TEMPLATE(N) \
template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \
class CFunctorCallback##N : public CFunctorCallbackBase \
{ \
typedef void (*Callback_t)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ); \
public: \
CFunctorCallback##N( Callback_t pfnProxied ) : m_pfnProxied( pfnProxied ) {} \
void operator()( CFunctorData *pFunctorDataBase ) \
{ \
ValidateFunctorData( pFunctorDataBase ); \
CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N > *pFunctorData = static_cast< CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N >* >( pFunctorDataBase ); \
m_pfnProxied( FUNC_CALL_DATA_ARGS_##N(pFunctorData) ); \
} \
virtual bool IsEqual( CFunctorCallback *pSrc ) const { return !Q_stricmp( GetImplClassName(), pSrc->GetImplClassName() ) && ( m_pfnProxied == static_cast< CFunctorCallback##N * >( pSrc )->m_pfnProxied ); } \
virtual void ComputeValidationString( char *pString, size_t nBufLen ) const { FUNC_VALIDATION_STRING_##N } \
virtual const char *GetImplClassName() const { return "CFunctorCallback" #N; } \
virtual const void *GetTarget() const { return m_pfnProxied; } \
private: \
Callback_t m_pfnProxied; \
}
class CFunctorCallback0 : public CFunctorCallbackBase
{
typedef void (*Callback_t)( );
public:
CFunctorCallback0( Callback_t pfnProxied ) : m_pfnProxied( pfnProxied ) {}
void operator()( CFunctorData *pFunctorDataBase )
{
ValidateFunctorData( pFunctorDataBase );
m_pfnProxied( );
}
virtual void ComputeValidationString( char *pString, size_t nBufLen_ ) const { int nBufLen = (int)nBufLen_; FUNC_VALIDATION_STRING_0 }
virtual bool IsEqual( CFunctorCallback *pSrc ) const
{
if ( Q_stricmp( GetImplClassName(), pSrc->GetImplClassName() ) )
return false;
return m_pfnProxied == static_cast< CFunctorCallback0* >( pSrc )->m_pfnProxied;
}
virtual const char *GetImplClassName() const { return "CFunctorCallback0"; }
virtual const void *GetTarget() const { return ( void * )m_pfnProxied; }
private:
Callback_t m_pfnProxied;
};
FUNC_GENERATE_ALL_BUT0( DEFINE_FUNCTOR_CALLBACK_TEMPLATE );
#define DEFINE_MEMBER_FUNCTOR_CALLBACK_TEMPLATE( N ) \
template < class FUNCTION_CLASS FUNC_TEMPLATE_ARG_PARAMS_##N, class MEM_POLICY = CFuncMemPolicyNone > \
class CMemberFunctorCallback##N : public CFunctorCallbackBase \
{ \
typedef void (FUNCTION_CLASS::*MemberCallback_t)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ); \
public: \
CMemberFunctorCallback##N( FUNCTION_CLASS *pObject, MemberCallback_t pfnProxied ) : m_Proxy( pObject, pfnProxied ) {} \
void operator()( CFunctorData *pFunctorDataBase ) \
{ \
ValidateFunctorData( pFunctorDataBase ); \
CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N > *pFunctorData = static_cast< CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N >* >( pFunctorDataBase ); \
m_Proxy( FUNC_CALL_DATA_ARGS_##N( pFunctorData ) ); \
} \
virtual void ComputeValidationString( char *pString, size_t nBufLen ) const { FUNC_VALIDATION_STRING_##N } \
virtual bool IsEqual( CFunctorCallback *pSrc ) const { return !Q_stricmp( GetImplClassName(), pSrc->GetImplClassName() ) && ( m_Proxy == static_cast< CMemberFunctorCallback##N* >( pSrc )->m_Proxy ); } \
virtual const char *GetImplClassName() const { return "CMemberFunctorCallback" #N; } \
virtual const void *GetTarget() const { return m_Proxy.GetTarget(); } \
private: \
CMemberFuncProxy##N< FUNCTION_CLASS *, MemberCallback_t FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, MEM_POLICY> m_Proxy; \
}
template < class FUNCTION_CLASS, class MEM_POLICY = CFuncMemPolicyNone >
class CMemberFunctorCallback0 : public CFunctorCallbackBase
{
typedef void (FUNCTION_CLASS::*MemberCallback_t)( );
public:
CMemberFunctorCallback0( FUNCTION_CLASS *pObject, MemberCallback_t pfnProxied ) : m_Proxy( pObject, pfnProxied ) {}
void operator()( CFunctorData *pFunctorDataBase )
{
ValidateFunctorData( pFunctorDataBase );
m_Proxy( );
}
virtual void ComputeValidationString( char *pString, size_t nBufLen ) const { FUNC_VALIDATION_STRING_0 }
virtual bool IsEqual( CFunctorCallback *pSrc ) const
{
if ( Q_stricmp( GetImplClassName(), pSrc->GetImplClassName() ) )
return false;
return m_Proxy == static_cast< CMemberFunctorCallback0 * >( pSrc )->m_Proxy;
}
virtual const char *GetImplClassName() const { return "CMemberFunctorCallback0"; }
virtual const void *GetTarget() const { return m_Proxy.GetTarget(); }
private:
CMemberFuncProxy0< FUNCTION_CLASS *, MemberCallback_t, MEM_POLICY > m_Proxy;
};
FUNC_GENERATE_ALL_BUT0( DEFINE_MEMBER_FUNCTOR_CALLBACK_TEMPLATE );
//-----------------------------------------------------------------------------
//
// The real magic, letting the compiler figure out all the right template parameters
//
//-----------------------------------------------------------------------------
#define DEFINE_NONMEMBER_FUNCTOR_FACTORY(N) \
template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
inline CFunctor *CreateFunctor(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
typedef FUNCTION_RETTYPE (*Func_t)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N); \
return new CFunctor##N<Func_t FUNC_BASE_TEMPLATE_ARG_PARAMS_##N>( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \
}
FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_FACTORY );
//-------------------------------------
#define DEFINE_MEMBER_FUNCTOR_FACTORY(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
return new CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N>(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
}
FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_FACTORY );
//-------------------------------------
#define DEFINE_CONST_MEMBER_FUNCTOR_FACTORY(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
return new CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N>(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
}
FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_FACTORY );
//-------------------------------------
#define DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
inline CFunctor *CreateRefCountingFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
return new CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
}
FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY );
//-------------------------------------
#define DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
inline CFunctor *CreateRefCountingFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
return new CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
}
FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY );
#define DEFINE_FUNCTOR_DATA_FACTORY(N) \
template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \
inline CFunctorData *CreateFunctorData( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) \
{ \
return new CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N >( FUNC_CALL_ARGS_##N ); \
}
inline CFunctorData *CreateFunctorData()
{
return new CFunctorData0();
}
FUNC_GENERATE_ALL_BUT0( DEFINE_FUNCTOR_DATA_FACTORY );
#define DEFINE_FUNCTOR_CALLBACK_FACTORY(N) \
template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \
inline CFunctorCallback *CreateFunctorCallback( void (*pfnProxied)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) ) \
{ \
return new CFunctorCallback##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N >( pfnProxied ); \
}
inline CFunctorCallback *CreateFunctorCallback( void (*pfnProxied)() )
{
return new CFunctorCallback0( pfnProxied );
}
FUNC_GENERATE_ALL_BUT0( DEFINE_FUNCTOR_CALLBACK_FACTORY );
#define DEFINE_MEMBER_FUNCTOR_CALLBACK_FACTORY(N) \
template < typename FUNCTION_CLASS FUNC_TEMPLATE_ARG_PARAMS_##N > \
inline CFunctorCallback *CreateFunctorCallback( FUNCTION_CLASS *pObject, void ( FUNCTION_CLASS::*pfnProxied )( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) ) \
{ \
return new CMemberFunctorCallback##N< FUNCTION_CLASS FUNC_BASE_TEMPLATE_ARG_PARAMS_##N >( pObject, pfnProxied ); \
}
FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_CALLBACK_FACTORY );
//-----------------------------------------------------------------------------
//
// Templates to assist early-out direct call code
//
//-----------------------------------------------------------------------------
#define DEFINE_NONMEMBER_FUNCTOR_DIRECT(N) \
template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
inline void FunctorDirectCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
(*pfnProxied)( FUNC_CALL_ARGS_##N ); \
}
FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_DIRECT );
//-------------------------------------
#define DEFINE_MEMBER_FUNCTOR_DIRECT(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
inline void FunctorDirectCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
((*pObject).*pfnProxied)(FUNC_CALL_ARGS_##N); \
}
FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_DIRECT );
//-------------------------------------
#define DEFINE_CONST_MEMBER_FUNCTOR_DIRECT(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
inline void FunctorDirectCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
((*pObject).*pfnProxied)(FUNC_CALL_ARGS_##N); \
}
FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_DIRECT );
#include "tier0/memdbgoff.h"
//-----------------------------------------------------------------------------
// Factory class useable as templated traits
//-----------------------------------------------------------------------------
class CDefaultFunctorFactory
{
public:
FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_FACTORY );
FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_FACTORY );
FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_FACTORY );
FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY );
FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY );
};
template <class CAllocator, class CCustomFunctorBase = CFunctorBase>
class CCustomizedFunctorFactory
{
public:
void SetAllocator( CAllocator *pAllocator )
{
m_pAllocator = pAllocator;
}
#define DEFINE_NONMEMBER_FUNCTOR_FACTORY_CUSTOM(N) \
template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
inline CFunctor *CreateFunctor( FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
typedef FUNCTION_RETTYPE (*Func_t)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N); \
return new (m_pAllocator->Alloc( sizeof(CFunctor##N<Func_t FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>) )) CFunctor##N<Func_t FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \
}
FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_FACTORY_CUSTOM );
//-------------------------------------
#define DEFINE_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>) )) CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
}
FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_FACTORY_CUSTOM );
//-------------------------------------
#define DEFINE_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
inline CFunctor *CreateFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>) )) CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
}
FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM );
//-------------------------------------
#define DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
inline CFunctor *CreateRefCountingFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >) )) CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
}
FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY_CUSTOM );
//-------------------------------------
#define DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
inline CFunctor *CreateRefCountingFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >) )) CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
}
FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM );
private:
CAllocator *m_pAllocator;
};
//-----------------------------------------------------------------------------
#endif // FUNCTORS_H

141
public/tier1/generichash.h Normal file
View File

@@ -0,0 +1,141 @@
//======= Copyright <20> 2005, , Valve Corporation, All rights reserved. =========
//
// Purpose: Variant Pearson Hash general purpose hashing algorithm described
// by Cargill in C++ Report 1994. Generates a 16-bit result.
//
//=============================================================================
#ifndef GENERICHASH_H
#define GENERICHASH_H
#if defined(_WIN32)
#pragma once
#endif
//-----------------------------------------------------------------------------
unsigned FASTCALL HashString( const char *pszKey );
unsigned FASTCALL HashStringCaseless( const char *pszKey );
unsigned FASTCALL HashStringCaselessConventional( const char *pszKey );
unsigned FASTCALL Hash4( const void *pKey );
unsigned FASTCALL Hash8( const void *pKey );
unsigned FASTCALL Hash12( const void *pKey );
unsigned FASTCALL Hash16( const void *pKey );
unsigned FASTCALL HashBlock( const void *pKey, unsigned size );
unsigned FASTCALL HashInt( const int key );
// hash a uint32 into a uint32
FORCEINLINE uint32 HashIntAlternate( uint32 n)
{
n = ( n + 0x7ed55d16 ) + ( n << 12 );
n = ( n ^ 0xc761c23c ) ^ ( n >> 19 );
n = ( n + 0x165667b1 ) + ( n << 5 );
n = ( n + 0xd3a2646c ) ^ ( n << 9 );
n = ( n + 0xfd7046c5 ) + ( n << 3 );
n = ( n ^ 0xb55a4f09 ) ^ ( n >> 16 );
return n;
}
inline uint64 HashUint64( uint64 s )
{
// Thomas Wang hash, http://www.concentric.net/~ttwang/tech/inthash.htm
s = ( ~s ) + ( s << 21 ); // s = (s << 21) - s - 1;
s = s ^ ( s >> 24 );
s = ( s + ( s << 3 ) ) + ( s << 8 ); // s * 265
s = s ^ ( s >> 14 );
s = ( s + ( s << 2 ) ) + ( s << 4 ); // s * 21
s = s ^ ( s >> 28 );
s = s + ( s << 31 );
return s;
}
inline intp HashIntp( intp s )
{
#ifdef PLATFORM_64BITS
COMPILE_TIME_ASSERT( sizeof( s ) == sizeof( uint64 ) );
return ( intp )HashUint64( ( uint64 )s );
#else
return HashInt( s );
#endif
}
inline unsigned HashIntConventional( const int n ) // faster but less effective
{
// first byte
unsigned hash = 0xAAAAAAAA + (n & 0xFF);
// second byte
hash = ( hash << 5 ) + hash + ( (n >> 8) & 0xFF );
// third byte
hash = ( hash << 5 ) + hash + ( (n >> 16) & 0xFF );
// fourth byte
hash = ( hash << 5 ) + hash + ( (n >> 24) & 0xFF );
return hash;
/* this is the old version, which would cause a load-hit-store on every
line on a PowerPC, and therefore took hundreds of clocks to execute!
byte *p = (byte *)&n;
unsigned hash = 0xAAAAAAAA + *p++;
hash = ( ( hash << 5 ) + hash ) + *p++;
hash = ( ( hash << 5 ) + hash ) + *p++;
return ( ( hash << 5 ) + hash ) + *p;
*/
}
//-----------------------------------------------------------------------------
template <typename T>
inline unsigned HashItem( const T &item )
{
// TODO: Confirm comiler optimizes out unused paths
if ( sizeof(item) == 4 )
return Hash4( &item );
else if ( sizeof(item) == 8 )
return Hash8( &item );
else if ( sizeof(item) == 12 )
return Hash12( &item );
else if ( sizeof(item) == 16 )
return Hash16( &item );
else
return HashBlock( &item, sizeof(item) );
}
template <> inline unsigned HashItem<int>(const int &key )
{
return HashInt( key );
}
template <> inline unsigned HashItem<unsigned>(const unsigned &key )
{
return HashInt( (int)key );
}
template<> inline unsigned HashItem<const char *>(const char * const &pszKey )
{
return HashString( pszKey );
}
template<> inline unsigned HashItem<char *>(char * const &pszKey )
{
return HashString( pszKey );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Murmur hash
//-----------------------------------------------------------------------------
uint32 MurmurHash2( const void * key, int len, uint32 seed );
// return murmurhash2 of a downcased string
uint32 MurmurHash2LowerCase( char const *pString, uint32 nSeed );
uint64 MurmurHash64( const void * key, int len, uint32 seed );
#endif /* !GENERICHASH_H */

148
public/tier1/heapsort.h Normal file
View File

@@ -0,0 +1,148 @@
//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
#ifndef TIER1_HEAP_SORT
#define TIER1_HEAP_SORT
template <typename T, typename LessThan>
inline bool IsHeap( T *pArr, int nCount, const LessThan &lessThan )
{
for ( int i = 1; i < nCount; ++i )
{
if ( lessThan( pArr[ ( i + 1 ) / 2 - 1 ], pArr[ i ] ) )
return false;
}
return true;
}
template <typename T, typename LessThan>
inline void HeapSort( T *pArr, int nCount, const LessThan &lessThan )
{
// heapify
for ( int nEndOfHeap = 1; nEndOfHeap < nCount; ++nEndOfHeap )
{
int nIdx = nEndOfHeap;
do
{
int nParent = ( nIdx + 1 ) / 2 - 1;
if ( lessThan( pArr[ nParent ], pArr[ nIdx ] ) )
{
Swap( pArr[ nParent ], pArr[ nIdx ] );
}
else
{
break;
}
nIdx = nParent;
}
while ( nIdx > 0 );
}
AssertDbg( IsHeap( pArr, nCount, lessThan ) );
// heap sort
for ( int nEndOfHeap = nCount; nEndOfHeap-- > 1; )
{
AssertDbg( !lessThan( pArr[ 0 ], pArr[ nEndOfHeap ] ) );
Swap( pArr[ 0 ], pArr[ nEndOfHeap ] );
// re-heapify the heap
int nIdx = 0;
for ( ;; )
{
int nChild = nIdx * 2 + 1;
if ( nChild >= nEndOfHeap )
break;
if ( nChild + 1 < nEndOfHeap )
{
// we have 2 children to compare against
if ( lessThan( pArr[ nChild ], pArr[ nChild + 1 ] ) )
{
nChild++; // always compare the root against the greater child
}
}
if ( lessThan( pArr[ nIdx ], pArr[ nChild ] ) )
{
Swap( pArr[ nIdx ], pArr[ nChild ] );
nIdx = nChild;
}
else
{
// the root is greater than any children now, we finished re-heapifying
break;
}
}
AssertDbg( IsHeap( pArr, nEndOfHeap, lessThan ) );
}
}
template <typename Array, typename LessThan>
inline void HeapSort( Array& arr, const LessThan &lessThan )
{
HeapSort( arr.Base( ), arr.Count( ), lessThan );
}
template <typename T, typename LessThan>
inline void BubbleSort( T *pArr, int nCount, const LessThan &lessThan )
{
for ( int i = 0; i + 1 < nCount; ++i )
{
for ( int j = i; j < nCount; ++j )
{
if ( lessThan( pArr[ j ], pArr[ i ] ) )
{
Swap( pArr[ j ], pArr[ i ] );
}
}
}
#ifdef DBGFLAG_ASSERT
for ( int i = 1; i < nCount; ++i )
{
Assert( lessThan( pArr[ i - 1 ], pArr[ i ] ) || !lessThan( pArr[ i ], pArr[ i - 1 ] ) );
}
#endif
}
/*
inline void HeapSortUnitTest( )
{
RandomSeed( 1 );
for ( uint i = 0; i < 100000; ++i )
{
CUtlVector< int >arr;
arr.SetCount( RandomInt( 0, 10000 ) );
for ( int j = 0; j < arr.Count( ); ++j )
arr[ j ] = RandomInt( 0, INT_MAX );
HeapSort( arr, [=] ( int a, int b ) ->bool { return a < b; } );
for ( int j = 1; j < arr.Count( ); ++j )
Assert( arr[ j - 1 ] <= arr[ j ] );
}
}
*/
template <typename Array>
inline void RemoveDuplicates( Array &arr )
{
// skip the first unique items
int nUniques = 1;
while ( nUniques < arr.Count( ) && !( arr[ nUniques ] == arr[ nUniques - 1 ] ) )
{
nUniques++;
}
if ( nUniques < arr.Count( ) )
{
// found the first duplicate; start copying unique items back
for ( int i = nUniques + 1; i < arr.Count( ); ++i )
{
if ( !( arr[ nUniques - 1 ] == arr[ i ] ) )
{
arr[ nUniques ] = arr[ i ]; // found another unique item
nUniques++;
}
}
arr.SetCountNonDestructively( nUniques );
}
}
#endif

View File

@@ -0,0 +1,143 @@
//========= Copyright <20> Valve Corporation, All rights reserved. ============//
#ifndef HIERARCHICAL_BIT_VEC_HDR
#define HIERARCHICAL_BIT_VEC_HDR
class CHierarchicalBitVector
{
public:
CHierarchicalBitVector( ){}
CHierarchicalBitVector( int nInitialBitCount )
{
if ( nInitialBitCount > 0 )
{
EnsureBitExists( nInitialBitCount - 1 );
}
}
CHierarchicalBitVector( const CHierarchicalBitVector &other )
{
m_Level0.CopyArray( other.m_Level0.Base( ), other.m_Level0.Count( ) );
m_Level1.CopyArray( other.m_Level1.Base( ), other.m_Level1.Count( ) );
}
void Set( int nBit )
{
m_Level0[ nBit >> 5 ] |= 1 << ( nBit & 31 );
m_Level1[ nBit >> 10 ] |= 1 << ( ( nBit >> 5 ) & 31 );
}
void Reset( int nBit )
{
m_Level0[ nBit >> 5 ] &= ~( 1 << ( nBit & 31 ) );
}
uint32 operator[] ( int nBit ) const
{
uint32 nBitSet = ( m_Level0[ nBit >> 5 ] >> ( nBit & 31 ) ) & 1;
AssertDbg( ( ( m_Level1[ nBit >> 10 ] >> ( ( nBit >> 5 ) & 31 ) ) & 1 ) || !m_Level0[ nBit >> 5 ] );
return nBitSet;
}
const uint32 * Base() const
{
return m_Level0.Base();
}
void Validate()const
{
#ifdef DBGFLAG_ASSERT
for( int i = 0; i < m_Level0.Count(); ++i )
{
uint nLevel0Bits = m_Level0[ i ];
uint nLevel1Bits = m_Level1[ i >> 5 ];
Assert( nLevel1Bits & ( 1 << ( i & 31 ) ) ? nLevel0Bits : !nLevel0Bits );
}
#endif
}
void EnsureBitExists( int nBit ) // reallocate if necessary
{
int nLevel0Size = ( nBit >> 5 ) + 1, nLevel0OldSize = m_Level0.Count();
if( nLevel0OldSize < nLevel0Size )
{
m_Level0.AddMultipleToTail( nLevel0Size - nLevel0OldSize );
for( int i = nLevel0OldSize; i < nLevel0Size; ++i )
{
m_Level0[i] = 0;
}
int nLevel1Size = ( nBit >> 10 ) + 1, nLevel1OldSize = m_Level1.Count();
if( nLevel1OldSize < nLevel1Size )
{
m_Level1.AddMultipleToTail( nLevel1Size - nLevel1OldSize );
for( int i = nLevel1OldSize; i < nLevel1Size; ++i )
{
m_Level1[i] = 0;
}
}
}
}
int Count()
{
return m_Level0.Count() << 5;
}
template < typename Functor >
void ScanBits( Functor functor )
{
for( int nItLevel1 = 0; nItLevel1 < m_Level1.Count(); ++nItLevel1 )
{
uint nLevel1Bits = m_Level1[ nItLevel1 ];
uint nBaseLevel1 = nItLevel1 * 32;
while( nLevel1Bits )
{
#ifdef COMPILER_GCC
uint32 nOffsetLevel1 = __builtin_ctz( nLevel1Bits );
#else
unsigned long nOffsetLevel1;
_BitScanForward( &nOffsetLevel1, nLevel1Bits );
#endif
AssertDbg( nLevel1Bits & ( 1 << nOffsetLevel1 ) );
nLevel1Bits ^= 1 << nOffsetLevel1;
uint nItLevel0 = nBaseLevel1 + nOffsetLevel1;
uint nLevel0Bits = m_Level0[ nItLevel0 ];
if( nLevel0Bits != 0 ) // if the bit is set in level1, it doesn't mean the uint32 in level0 is always non-zero: it may have been reset
{
uint nBaseLevel0 = nItLevel0 * 32;
do
{
#ifdef COMPILER_GCC
uint32 nOffsetLevel0 = __builtin_ctz( nLevel0Bits );
#else
unsigned long nOffsetLevel0;
_BitScanForward( &nOffsetLevel0, nLevel0Bits );
#endif
AssertDbg( nLevel0Bits & ( 1 << nOffsetLevel0 ) );
nLevel0Bits ^= 1 << nOffsetLevel0;
// Perform tree queries for all moving objects
functor( nBaseLevel0 + nOffsetLevel0 );
}
while( nLevel0Bits );
}
}
}
}
void Clear( )
{
m_Level0.FillWithValue( 0 );
m_Level1.FillWithValue( 0 );
}
protected:
CUtlVector< uint32 > m_Level1; // one bit for each 32 bits in m_MoveBufferLevel0
CUtlVector< uint32 > m_Level0; // one bit for each proxy
public:
#ifdef AUTO_SERIALIZE
AUTO_SERIALIZE;
#endif
};
#endif

126
public/tier1/iconvar.h Normal file
View File

@@ -0,0 +1,126 @@
//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $NoKeywords: $
//===========================================================================//
#ifndef ICONVAR_H
#define ICONVAR_H
#if _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
#include "tier0/platform.h"
#include "tier1/strtools.h"
#include "color.h"
//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
class IConVar;
class CCommand;
//-----------------------------------------------------------------------------
// ConVar flags
//-----------------------------------------------------------------------------
// The default, no flags at all
#define FCVAR_NONE 0
// Command to ConVars and ConCommands
// ConVar Systems
#define FCVAR_UNREGISTERED (1<<0) // If this is set, don't add to linked list, etc.
#define FCVAR_DEVELOPMENTONLY (1<<1) // Hidden in released products. Flag is removed automatically if ALLOW_DEVELOPMENT_CVARS is defined.
#define FCVAR_GAMEDLL (1<<2) // defined by the game DLL
#define FCVAR_CLIENTDLL (1<<3) // defined by the client DLL
#define FCVAR_HIDDEN (1<<4) // Hidden. Doesn't appear in find or auto complete. Like DEVELOPMENTONLY, but can't be compiled out.
// ConVar only
#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value
#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server.
#define FCVAR_ARCHIVE (1<<7) // set to cause it to be saved to vars.rc
#define FCVAR_NOTIFY (1<<8) // notifies players when changed
#define FCVAR_USERINFO (1<<9) // changes the client's info string
#define FCVAR_PRINTABLEONLY (1<<10) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ).
#define FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS (1<<10) // When on concommands this allows remote clients to execute this cmd on the server.
// We are changing the default behavior of concommands to disallow execution by remote clients without
// this flag due to the number existing concommands that can lag or crash the server when clients abuse them.
#define FCVAR_UNLOGGED (1<<11) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log
#define FCVAR_NEVER_AS_STRING (1<<12) // never try to print that cvar
// It's a ConVar that's shared between the client and the server.
// At signon, the values of all such ConVars are sent from the server to the client (skipped for local
// client, of course )
// If a change is requested it must come from the console (i.e., no remote client changes)
// If a value is changed while a server is active, it's replicated to all connected clients
#define FCVAR_REPLICATED (1<<13) // server setting enforced on clients, TODO rename to FCAR_SERVER at some time
#define FCVAR_CHEAT (1<<14) // Only useable in singleplayer / debug / multiplayer & sv_cheats
#define FCVAR_SS (1<<15) // causes varnameN where N == 2 through max splitscreen slots for mod to be autogenerated
#define FCVAR_DEMO (1<<16) // record this cvar when starting a demo file
#define FCVAR_DONTRECORD (1<<17) // don't record these command in demofiles
#define FCVAR_SS_ADDED (1<<18) // This is one of the "added" FCVAR_SS variables for the splitscreen players
#define FCVAR_RELEASE (1<<19) // Cvars tagged with this are the only cvars avaliable to customers
#define FCVAR_RELOAD_MATERIALS (1<<20) // If this cvar changes, it forces a material reload
#define FCVAR_RELOAD_TEXTURES (1<<21) // If this cvar changes, if forces a texture reload
#define FCVAR_NOT_CONNECTED (1<<22) // cvar cannot be changed by a client that is connected to a server
#define FCVAR_MATERIAL_SYSTEM_THREAD (1<<23) // Indicates this cvar is read from the material system thread
#define FCVAR_ARCHIVE_GAMECONSOLE (1<<24) // cvar written to config.cfg on the Xbox
#define FCVAR_SERVER_CAN_EXECUTE (1<<28)// the server is allowed to execute this command on clients via ClientCommand/NET_StringCmd/CBaseClientState::ProcessStringCmd.
#define FCVAR_SERVER_CANNOT_QUERY (1<<29)// If this is set, then the server is not allowed to query this cvar's value (via IServerPluginHelpers::StartQueryCvarValue).
#define FCVAR_CLIENTCMD_CAN_EXECUTE (1<<30) // IVEngineClient::ClientCmd is allowed to execute this command.
// Note: IVEngineClient::ClientCmd_Unrestricted can run any client command.
#define FCVAR_ACCESSIBLE_FROM_THREADS (1<<25) // used as a debugging tool necessary to check material system thread convars
// #define FCVAR_AVAILABLE (1<<26)
// #define FCVAR_AVAILABLE (1<<27)
// #define FCVAR_AVAILABLE (1<<31)
#define FCVAR_MATERIAL_THREAD_MASK ( FCVAR_RELOAD_MATERIALS | FCVAR_RELOAD_TEXTURES | FCVAR_MATERIAL_SYSTEM_THREAD )
//-----------------------------------------------------------------------------
// Called when a ConVar changes value
// NOTE: For FCVAR_NEVER_AS_STRING ConVars, pOldValue == NULL
//-----------------------------------------------------------------------------
typedef void ( *FnChangeCallback_t )( IConVar *var, const char *pOldValue, float flOldValue );
//-----------------------------------------------------------------------------
// Abstract interface for ConVars
//-----------------------------------------------------------------------------
abstract_class IConVar
{
public:
// Value set
virtual void SetValue( const char *pValue ) = 0;
virtual void SetValue( float flValue ) = 0;
virtual void SetValue( int nValue ) = 0;
virtual void SetValue( Color value ) = 0;
// Return name of command
virtual const char *GetName( void ) const = 0;
// Return name of command (usually == GetName(), except in case of FCVAR_SS_ADDED vars
virtual const char *GetBaseName( void ) const = 0;
// Accessors.. not as efficient as using GetState()/GetInfo()
// if you call these methods multiple times on the same IConVar
virtual bool IsFlagSet( int nFlag ) const = 0;
virtual int GetSplitScreenPlayerSlot() const = 0;
};
#endif // ICONVAR_H

226
public/tier1/interface.h Normal file
View File

@@ -0,0 +1,226 @@
//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// This header defines the interface convention used in the valve engine.
// To make an interface and expose it:
// 1. The interface must be ALL pure virtuals, and have no data members.
// 2. Define a name for it.
// 3. In its implementation file, use EXPOSE_INTERFACE or EXPOSE_SINGLE_INTERFACE.
// Versioning
// There are two versioning cases that are handled by this:
// 1. You add functions to the end of an interface, so it is binary compatible with the previous interface. In this case,
// you need two EXPOSE_INTERFACEs: one to expose your class as the old interface and one to expose it as the new interface.
// 2. You update an interface so it's not compatible anymore (but you still want to be able to expose the old interface
// for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and
// expose it for the old interface.
// Static Linking:
// Must mimic unique seperate class 'InterfaceReg' constructors per subsystem.
// Each subsystem can then import and export interfaces as expected.
// This is achieved through unique namespacing 'InterfaceReg' via symbol _SUBSYSTEM.
// Static Linking also needs to generate unique symbols per interface so as to
// provide a 'stitching' method whereby these interface symbols can be referenced
// via the lib's primary module (usually the lib's interface exposure)
// therby stitching all of that lib's code/data together for eventual final exe link inclusion.
#ifndef INTERFACE_H
#define INTERFACE_H
#ifdef _WIN32
#pragma once
#endif
// TODO: move interface.cpp into tier0 library.
// Need to include platform.h in case _PS3 and other tokens are not yet defined
#include "tier0/platform.h"
#if defined( POSIX ) && !defined( _PS3 )
#include <dlfcn.h> // dlopen,dlclose, et al
#include <unistd.h>
#define GetProcAddress dlsym
#ifdef _snprintf
#undef _snprintf
#endif
#define _snprintf snprintf
#endif // POSIX && !_PS3
// All interfaces derive from this.
class IBaseInterface
{
public:
virtual ~IBaseInterface() {}
};
#if !defined( _X360 )
#define CREATEINTERFACE_PROCNAME "CreateInterface"
#else
// x360 only allows ordinal exports, .def files export "CreateInterface" at 1
#define CREATEINTERFACE_PROCNAME ((const char*)1)
#endif
typedef void* (*CreateInterfaceFn)(const char *pName, int *pReturnCode);
typedef void* (*InstantiateInterfaceFn)();
// Used internally to register classes.
class InterfaceReg
{
public:
InterfaceReg(InstantiateInterfaceFn fn, const char *pName);
public:
InstantiateInterfaceFn m_CreateFn;
const char *m_pName;
InterfaceReg *m_pNext; // For the global list.
};
// Use this to expose an interface that can have multiple instances.
// e.g.:
// EXPOSE_INTERFACE( CInterfaceImp, IInterface, "MyInterface001" )
// This will expose a class called CInterfaceImp that implements IInterface (a pure class)
// clients can receive a pointer to this class by calling CreateInterface( "MyInterface001" )
//
// In practice, the shared header file defines the interface (IInterface) and version name ("MyInterface001")
// so that each component can use these names/vtables to communicate
//
// A single class can support multiple interfaces through multiple inheritance
//
// Use this if you want to write the factory function.
#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM)
#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \
static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName);
#else
#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \
namespace _SUBSYSTEM \
{ \
static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName); \
}
#endif
#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM)
#define EXPOSE_INTERFACE(className, interfaceName, versionName) \
static void* __Create##className##_interface() {return static_cast<interfaceName *>( new className );} \
static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName );
#else
#define EXPOSE_INTERFACE(className, interfaceName, versionName) \
namespace _SUBSYSTEM \
{ \
static void* __Create##className##_interface() {return static_cast<interfaceName *>( new className );} \
static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); \
}
#endif
// Use this to expose a singleton interface with a global variable you've created.
#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM)
#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \
static void* __Create##className##interfaceName##_interface() {return static_cast<interfaceName *>( &globalVarName );} \
static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName);
#else
#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \
namespace _SUBSYSTEM \
{ \
static void* __Create##className##interfaceName##_interface() {return static_cast<interfaceName *>( &globalVarName );} \
static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); \
}
#endif
// Use this to expose a singleton interface. This creates the global variable for you automatically.
#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM)
#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \
static className __g_##className##_singleton; \
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton)
#else
#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \
namespace _SUBSYSTEM \
{ \
static className __g_##className##_singleton; \
} \
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton)
#endif
// load/unload components
class CSysModule;
// interface return status
enum
{
IFACE_OK = 0,
IFACE_FAILED
};
//-----------------------------------------------------------------------------
// This function is automatically exported and allows you to access any interfaces exposed with the above macros.
// if pReturnCode is set, it will return one of the following values (IFACE_OK, IFACE_FAILED)
// extend this for other error conditions/code
//-----------------------------------------------------------------------------
DLL_EXPORT void* CreateInterface(const char *pName, int *pReturnCode);
#if defined( _X360 )
DLL_EXPORT void *CreateInterfaceThunk( const char *pName, int *pReturnCode );
#endif
//-----------------------------------------------------------------------------
// UNDONE: This is obsolete, use the module load/unload/get instead!!!
//-----------------------------------------------------------------------------
extern CreateInterfaceFn Sys_GetFactory( CSysModule *pModule );
extern CreateInterfaceFn Sys_GetFactory( const char *pModuleName );
extern CreateInterfaceFn Sys_GetFactoryThis( void );
//-----------------------------------------------------------------------------
// Load & Unload should be called in exactly one place for each module
// The factory for that module should be passed on to dependent components for
// proper versioning.
//-----------------------------------------------------------------------------
extern CSysModule *Sys_LoadModule( const char *pModuleName );
extern void Sys_UnloadModule( CSysModule *pModule );
// Determines if current process is running with any debug modules
extern bool Sys_RunningWithDebugModules();
// This is a helper function to load a module, get its factory, and get a specific interface.
// You are expected to free all of these things.
// Returns false and cleans up if any of the steps fail.
bool Sys_LoadInterface(
const char *pModuleName,
const char *pInterfaceVersionName,
CSysModule **pOutModule,
void **pOutInterface );
bool Sys_IsDebuggerPresent();
//-----------------------------------------------------------------------------
// Purpose: Place this as a singleton at module scope (e.g.) and use it to get the factory from the specified module name.
//
// When the singleton goes out of scope (.dll unload if at module scope),
// then it'll call Sys_UnloadModule on the module so that the refcount is decremented
// and the .dll actually can unload from memory.
//-----------------------------------------------------------------------------
class CDllDemandLoader
{
public:
CDllDemandLoader( char const *pchModuleName );
virtual ~CDllDemandLoader();
CreateInterfaceFn GetFactory();
void Unload();
private:
char const *m_pchModuleName;
CSysModule *m_hModule;
bool m_bLoadAttempted;
};
#endif

View File

@@ -0,0 +1,29 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "tier1/interpolatedvar.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// warning C4660: template-class specialization 'CInterpolatedVar<float>' is already instantiated
#pragma warning( disable : 4660 )
template class CInterpolatedVar<float>;
template class CInterpolatedVar<Vector>;
template class CInterpolatedVar<QAngle>;
CInterpolationContext *CInterpolationContext::s_pHead = NULL;
bool CInterpolationContext::s_bAllowExtrapolation = false;
float CInterpolationContext::s_flLastTimeStamp = 0;
float g_flLastPacketTimestamp = 0;
bool g_bHermiteFix = true;
ConVar cl_extrapolate_amount( "cl_extrapolate_amount", "0.25", FCVAR_CHEAT, "Set how many seconds the client will extrapolate entities for." );

File diff suppressed because it is too large Load Diff

549
public/tier1/keyvalues.h Normal file
View File

@@ -0,0 +1,549 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef KEYVALUES_H
#define KEYVALUES_H
#ifdef _WIN32
#pragma once
#endif
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
#include "utlvector.h"
#include "color.h"
#include "exprevaluator.h"
#define FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \
for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() )
#define FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \
for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() )
#define FOR_EACH_VALUE( kvRoot, kvValue ) \
for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() )
class IBaseFileSystem;
class CUtlBuffer;
class Color;
class CKeyValuesTokenReader;
class KeyValues;
class IKeyValuesDumpContext;
typedef void * FileHandle_t;
class CKeyValuesGrowableStringTable;
// single byte identifies a xbox kv file in binary format
// strings are pooled from a searchpath/zip mounted symbol table
#define KV_BINARY_POOLED_FORMAT 0xAA
#define FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \
for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() )
#define FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \
for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() )
#define FOR_EACH_VALUE( kvRoot, kvValue ) \
for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() )
//-----------------------------------------------------------------------------
// Purpose: Simple recursive data access class
// Used in vgui for message parameters and resource files
// Destructor deletes all child KeyValues nodes
// Data is stored in key (string names) - (string/int/float)value pairs called nodes.
//
// About KeyValues Text File Format:
// It has 3 control characters '{', '}' and '"'. Names and values may be quoted or
// not. The quote '"' character must not be used within name or values, only for
// quoting whole tokens. You may use escape sequences wile parsing and add within a
// quoted token a \" to add quotes within your name or token. When using Escape
// Sequence the parser must now that by setting KeyValues::UsesEscapeSequences( true ),
// which it's off by default. Non-quoted tokens ends with a whitespace, '{', '}' and '"'.
// So you may use '{' and '}' within quoted tokens, but not for non-quoted tokens.
// An open bracket '{' after a key name indicates a list of subkeys which is finished
// with a closing bracket '}'. Subkeys use the same definitions recursively.
// Whitespaces are space, return, newline and tabulator. Allowed Escape sequences
// are \n, \t, \\, \n and \". The number character '#' is used for macro purposes
// (eg #include), don't use it as first character in key names.
//-----------------------------------------------------------------------------
class KeyValues
{
friend class CKeyValuesTokenReader;
public:
// By default, the KeyValues class uses a string table for the key names that is
// limited to 4MB. The game will exit in error if this space is exhausted. In
// general this is preferable for game code for performance and memory fragmentation
// reasons.
//
// If this is not acceptable, you can use this call to switch to a table that can grow
// arbitrarily. This call must be made before any KeyValues objects are allocated or it
// will result in undefined behavior. If you use the growable string table, you cannot
// share KeyValues pointers directly with any other module. You can serialize them across
// module boundaries. These limitations are acceptable in the Steam backend code
// this option was written for, but may not be in other situations. Make sure to
// understand the implications before using this.
static void SetUseGrowableStringTable( bool bUseGrowableTable );
explicit KeyValues( const char *setName );
//
// AutoDelete class to automatically free the keyvalues.
// Simply construct it with the keyvalues you allocated and it will free them when falls out of scope.
// When you decide that keyvalues shouldn't be deleted call Assign(NULL) on it.
// If you constructed AutoDelete(NULL) you can later assign the keyvalues to be deleted with Assign(pKeyValues).
//
class AutoDelete
{
public:
explicit inline AutoDelete( KeyValues *pKeyValues ) : m_pKeyValues( pKeyValues ) {}
explicit inline AutoDelete( const char *pchKVName ) : m_pKeyValues( new KeyValues( pchKVName ) ) {}
inline ~AutoDelete( void ) { delete m_pKeyValues; }
inline void Assign( KeyValues *pKeyValues ) { m_pKeyValues = pKeyValues; }
/// behaves more like an auto pointer detach ( flags itself to not delete the contained object, and returns a pointer to it)
inline KeyValues * Detach() { KeyValues *retval = m_pKeyValues; Assign( NULL ); return retval; }
KeyValues *operator->() { return m_pKeyValues; }
operator KeyValues *() { return m_pKeyValues; }
private:
AutoDelete( AutoDelete const &x ); // forbid
AutoDelete & operator= ( AutoDelete const &x ); // forbid
protected:
KeyValues *m_pKeyValues;
};
//
// AutoDeleteInline is useful when you want to hold your keyvalues object inside
// and delete it right after using.
// You can also pass temporary KeyValues object as an argument to a function by wrapping it into KeyValues::AutoDeleteInline
// instance: call_my_function( KeyValues::AutoDeleteInline( new KeyValues( "test" ) ) )
//
class AutoDeleteInline : public AutoDelete
{
public:
explicit inline AutoDeleteInline( KeyValues *pKeyValues ) : AutoDelete( pKeyValues ) {}
inline operator KeyValues *() const { return m_pKeyValues; }
inline KeyValues * Get() const { return m_pKeyValues; }
};
// Quick setup constructors
KeyValues( const char *setName, const char *firstKey, const char *firstValue );
KeyValues( const char *setName, const char *firstKey, const wchar_t *firstValue );
KeyValues( const char *setName, const char *firstKey, int firstValue );
KeyValues( const char *setName, const char *firstKey, const char *firstValue, const char *secondKey, const char *secondValue );
KeyValues( const char *setName, const char *firstKey, int firstValue, const char *secondKey, int secondValue );
// destruct
~KeyValues();
// Section name
const char *GetName() const;
void SetName( const char *setName);
// gets the name as a unique int
int GetNameSymbol() const;
int GetNameSymbolCaseSensitive() const;
// File access. Set UsesEscapeSequences true, if resource file/buffer uses Escape Sequences (eg \n, \t)
void UsesEscapeSequences(bool state); // default false
bool LoadFromFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, GetSymbolProc_t pfnEvaluateSymbolProc = NULL);
bool SaveToFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, bool bWriteEmptySubkeys = false);
// Read from a buffer... Note that the buffer must be null terminated
bool LoadFromBuffer( char const *resourceName, const char *pBuffer, IBaseFileSystem* pFileSystem = NULL, const char *pPathID = NULL, GetSymbolProc_t pfnEvaluateSymbolProc = NULL );
// Read from a utlbuffer...
bool LoadFromBuffer( char const *resourceName, CUtlBuffer &buf, IBaseFileSystem* pFileSystem = NULL, const char *pPathID = NULL, GetSymbolProc_t pfnEvaluateSymbolProc = NULL );
// Find a keyValue, create it if it is not found.
// Set bCreate to true to create the key if it doesn't already exist (which ensures a valid pointer will be returned)
KeyValues *FindKey(const char *keyName, bool bCreate = false);
KeyValues *FindKey(int keySymbol) const;
KeyValues *CreateNewKey(); // creates a new key, with an autogenerated name. name is guaranteed to be an integer, of value 1 higher than the highest other integer key name
void AddSubKey( KeyValues *pSubkey ); // Adds a subkey. Make sure the subkey isn't a child of some other keyvalues
void RemoveSubKey(KeyValues *subKey); // removes a subkey from the list, DOES NOT DELETE IT
void InsertSubKey( int nIndex, KeyValues *pSubKey ); // Inserts the given sub-key before the Nth child location
bool ContainsSubKey( KeyValues *pSubKey ); // Returns true if this key values contains the specified sub key, false otherwise.
void SwapSubKey( KeyValues *pExistingSubKey, KeyValues *pNewSubKey ); // Swaps an existing subkey for a new one, DOES NOT DELETE THE OLD ONE but takes ownership of the new one
void ElideSubKey( KeyValues *pSubKey ); // Removes a subkey but inserts all of its children in its place, in-order (flattens a tree, like firing a manager!)
KeyValues* CreateKey( const char *keyName );
KeyValues* CreatePeerKey( const char *keyName );
// Key iteration.
//
// NOTE: GetFirstSubKey/GetNextKey will iterate keys AND values. Use the functions
// below if you want to iterate over just the keys or just the values.
//
KeyValues *GetFirstSubKey() const; // returns the first subkey in the list
KeyValues *GetNextKey() const; // returns the next subkey
void SetNextKey( KeyValues * pDat);
KeyValues *FindLastSubKey(); // returns the LAST subkey in the list. This requires a linked list iteration to find the key. Returns NULL if we don't have any children
bool BInteriorNode() const
{
return GetFirstSubKey() != NULL;
}
bool BLeafNode() const
{
return GetFirstSubKey() == NULL;
}
//
// These functions can be used to treat it like a true key/values tree instead of
// confusing values with keys.
//
// So if you wanted to iterate all subkeys, then all values, it would look like this:
// for ( KeyValues *pKey = pRoot->GetFirstTrueSubKey(); pKey; pKey = pKey->GetNextTrueSubKey() )
// {
// Msg( "Key name: %s\n", pKey->GetName() );
// }
// for ( KeyValues *pValue = pRoot->GetFirstValue(); pKey; pKey = pKey->GetNextValue() )
// {
// Msg( "Int value: %d\n", pValue->GetInt() ); // Assuming pValue->GetDataType() == TYPE_INT...
// }
KeyValues* GetFirstTrueSubKey();
KeyValues* GetNextTrueSubKey();
KeyValues* GetFirstValue(); // When you get a value back, you can use GetX and pass in NULL to get the value.
KeyValues* GetNextValue();
// Data access
int GetInt( const char *keyName = NULL, int defaultValue = 0 );
uint64 GetUint64( const char *keyName = NULL, uint64 defaultValue = 0 );
float GetFloat( const char *keyName = NULL, float defaultValue = 0.0f );
const char *GetString( const char *keyName = NULL, const char *defaultValue = "" );
const wchar_t *GetWString( const char *keyName = NULL, const wchar_t *defaultValue = L"" );
void *GetPtr( const char *keyName = NULL, void *defaultValue = (void*)0 );
Color GetColor( const char *keyName = NULL , const Color &defaultColor = Color( 0, 0, 0, 0 ) );
bool GetBool( const char *keyName = NULL, bool defaultValue = false ) { return GetInt( keyName, defaultValue ? 1 : 0 ) ? true : false; }
bool IsEmpty(const char *keyName = NULL);
// Data access
int GetInt( int keySymbol, int defaultValue = 0 );
uint64 GetUint64( int keySymbol, uint64 defaultValue = 0 );
float GetFloat( int keySymbol, float defaultValue = 0.0f );
const char *GetString( int keySymbol, const char *defaultValue = "" );
const wchar_t *GetWString( int keySymbol, const wchar_t *defaultValue = L"" );
void *GetPtr( int keySymbol, void *defaultValue = (void*)0 );
Color GetColor( int keySymbol /* default value is all black */);
bool GetBool( int keySymbol, bool defaultValue = false ) { return GetInt( keySymbol, defaultValue ? 1 : 0 ) ? true : false; }
bool IsEmpty( int keySymbol );
// Key writing
void SetWString( const char *keyName, const wchar_t *value );
void SetString( const char *keyName, const char *value );
void SetInt( const char *keyName, int value );
void SetUint64( const char *keyName, uint64 value );
void SetFloat( const char *keyName, float value );
void SetPtr( const char *keyName, void *value );
void SetColor( const char *keyName, Color value);
void SetBool( const char *keyName, bool value ) { SetInt( keyName, value ? 1 : 0 ); }
// Memory allocation (optimized)
void *operator new( size_t iAllocSize );
void *operator new( size_t iAllocSize, int nBlockUse, const char *pFileName, int nLine );
void operator delete( void *pMem );
void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine );
KeyValues& operator=( KeyValues& src );
bool IsEqual( KeyValues *pRHS );
// Adds a chain... if we don't find stuff in this keyvalue, we'll look
// in the one we're chained to.
void ChainKeyValue( KeyValues* pChain );
void RecursiveSaveToFile( CUtlBuffer& buf, int indentLevel );
bool WriteAsBinary( CUtlBuffer &buffer ) const;
bool ReadAsBinary( CUtlBuffer &buffer, int nStackDepth = 0 );
// Same as the other binary functions, but filter out and remove empty keys (like when seralizing to a file )
bool WriteAsBinaryFiltered( CUtlBuffer &buffer );
bool ReadAsBinaryFiltered( CUtlBuffer &buffer, int nStackDepth = 0 );
// Allocate & create a new copy of the keys
KeyValues *MakeCopy( void ) const;
// Make a new copy of all subkeys, add them all to the passed-in keyvalues
void CopySubkeys( KeyValues *pParent ) const;
// Clear out all subkeys, and the current value
void Clear( void );
// Data type
enum types_t
{
TYPE_NONE = 0,
TYPE_STRING,
TYPE_INT,
TYPE_FLOAT,
TYPE_PTR,
TYPE_WSTRING,
TYPE_COLOR,
TYPE_UINT64,
TYPE_COMPILED_INT_BYTE, // hack to collapse 1 byte ints in the compiled format
TYPE_COMPILED_INT_0, // hack to collapse 0 in the compiled format
TYPE_COMPILED_INT_1, // hack to collapse 1 in the compiled format
TYPE_NUMTYPES,
};
types_t GetDataType(const char *keyName = NULL);
types_t GetDataType() const;
// for backward compat
void deleteThis();
void SetStringValue( char const *strValue );
// unpack a key values list into a structure
void UnpackIntoStructure( struct KeyValuesUnpackStructure const *pUnpackTable, void *pDest );
// Process conditional keys for widescreen support.
bool ProcessResolutionKeys( const char *pResString );
// Dump keyvalues recursively into a dump context
bool Dump( IKeyValuesDumpContext *pDump, int nIndentLevel = 0 );
// Merge operations describing how two keyvalues can be combined
enum MergeKeyValuesOp_t
{
MERGE_KV_ALL,
MERGE_KV_UPDATE, // update values are copied into storage, adding new keys to storage or updating existing ones
MERGE_KV_DELETE, // update values specify keys that get deleted from storage
MERGE_KV_BORROW, // update values only update existing keys in storage, keys in update that do not exist in storage are discarded
};
void MergeFrom( KeyValues *kvMerge, MergeKeyValuesOp_t eOp = MERGE_KV_ALL );
// Assign keyvalues from a string
static KeyValues * FromString( char const *szName, char const *szStringVal, char const **ppEndOfParse = NULL );
/// Create a child key, given that we know which child is currently the last child.
/// This avoids the O(N^2) behaviour when adding children in sequence to KV,
/// when CreateKey() wil have to re-locate the end of the list each time. This happens,
/// for example, every time we load any KV file whatsoever.
KeyValues* CreateKeyUsingKnownLastChild( const char *keyName, KeyValues *pLastChild );
void AddSubkeyUsingKnownLastChild( KeyValues *pSubKey, KeyValues *pLastChild );
private:
KeyValues( KeyValues& ); // prevent copy constructor being used
void RecursiveCopyKeyValues( KeyValues& src );
void RemoveEverything();
// void RecursiveSaveToFile( IBaseFileSystem *filesystem, CUtlBuffer &buffer, int indentLevel );
// void WriteConvertedString( CUtlBuffer &buffer, const char *pszString );
// NOTE: If both filesystem and pBuf are non-null, it'll save to both of them.
// If filesystem is null, it'll ignore f.
void RecursiveSaveToFile( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel, bool bWriteEmptySubkeys = false );
void WriteConvertedString( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const char *pszString );
void RecursiveLoadFromBuffer( char const *resourceName, CKeyValuesTokenReader &buf, GetSymbolProc_t pfnEvaluateSymbolProc );
// for handling #include "filename"
void AppendIncludedKeys( CUtlVector< KeyValues * >& includedKeys );
void ParseIncludedKeys( char const *resourceName, const char *filetoinclude,
IBaseFileSystem* pFileSystem, const char *pPathID, CUtlVector< KeyValues * >& includedKeys, GetSymbolProc_t pfnEvaluateSymbolProc );
// For handling #base "filename"
void MergeBaseKeys( CUtlVector< KeyValues * >& baseKeys );
void RecursiveMergeKeyValues( KeyValues *baseKV );
// NOTE: If both filesystem and pBuf are non-null, it'll save to both of them.
// If filesystem is null, it'll ignore f.
void InternalWrite( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const void *pData, int len );
void Init();
void WriteIndents( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel );
void FreeAllocatedValue();
void AllocateValueBlock(int size);
bool ReadAsBinaryPooledFormat( CUtlBuffer &buf, IBaseFileSystem *pFileSystem, unsigned int poolKey, GetSymbolProc_t pfnEvaluateSymbolProc );
bool EvaluateConditional( const char *pExpressionString, GetSymbolProc_t pfnEvaluateSymbolProc );
uint32 m_iKeyName : 24; // keyname is a symbol defined in KeyValuesSystem
uint32 m_iKeyNameCaseSensitive1 : 8; // 1st part of case sensitive symbol defined in KeyValueSystem
// These are needed out of the union because the API returns string pointers
char *m_sValue;
wchar_t *m_wsValue;
// we don't delete these
union
{
int m_iValue;
float m_flValue;
void *m_pValue;
unsigned char m_Color[4];
};
char m_iDataType;
char m_bHasEscapeSequences; // true, if while parsing this KeyValue, Escape Sequences are used (default false)
uint16 m_iKeyNameCaseSensitive2; // 2nd part of case sensitive symbol defined in KeyValueSystem;
KeyValues *m_pPeer; // pointer to next key in list
KeyValues *m_pSub; // pointer to Start of a new sub key list
KeyValues *m_pChain;// Search here if it's not in our list
GetSymbolProc_t m_pExpressionGetSymbolProc;
private:
// Statics to implement the optional growable string table
// Function pointers that will determine which mode we are in
static int (*s_pfGetSymbolForString)( const char *name, bool bCreate );
static const char *(*s_pfGetStringForSymbol)( int symbol );
static CKeyValuesGrowableStringTable *s_pGrowableStringTable;
public:
// Functions that invoke the default behavior
static int GetSymbolForStringClassic( const char *name, bool bCreate = true );
static const char *GetStringForSymbolClassic( int symbol );
// Functions that use the growable string table
static int GetSymbolForStringGrowable( const char *name, bool bCreate = true );
static const char *GetStringForSymbolGrowable( int symbol );
};
typedef KeyValues::AutoDelete KeyValuesAD;
enum KeyValuesUnpackDestinationTypes_t
{
UNPACK_TYPE_FLOAT, // dest is a float
UNPACK_TYPE_VECTOR, // dest is a Vector
UNPACK_TYPE_VECTOR_COLOR, // dest is a vector, src is a color
UNPACK_TYPE_STRING, // dest is a char *. unpacker will allocate.
UNPACK_TYPE_INT, // dest is an int
UNPACK_TYPE_FOUR_FLOATS, // dest is an array of 4 floats. source is a string like "1 2 3 4"
UNPACK_TYPE_TWO_FLOATS, // dest is an array of 2 floats. source is a string like "1 2"
};
#define UNPACK_FIXED( kname, kdefault, dtype, ofs ) { kname, kdefault, dtype, ofs, 0 }
#define UNPACK_VARIABLE( kname, kdefault, dtype, ofs, sz ) { kname, kdefault, dtype, ofs, sz }
#define UNPACK_END_MARKER { NULL, NULL, UNPACK_TYPE_FLOAT, 0 }
struct KeyValuesUnpackStructure
{
char const *m_pKeyName; // null to terminate tbl
char const *m_pKeyDefault; // null ok
KeyValuesUnpackDestinationTypes_t m_eDataType; // UNPACK_TYPE_INT, ..
size_t m_nFieldOffset; // use offsetof to set
size_t m_nFieldSize; // for strings or other variable length
};
//-----------------------------------------------------------------------------
// inline methods
//-----------------------------------------------------------------------------
inline int KeyValues::GetInt( int keySymbol, int defaultValue )
{
KeyValues *dat = FindKey( keySymbol );
return dat ? dat->GetInt( (const char *)NULL, defaultValue ) : defaultValue;
}
inline uint64 KeyValues::GetUint64( int keySymbol, uint64 defaultValue )
{
KeyValues *dat = FindKey( keySymbol );
return dat ? dat->GetUint64( (const char *)NULL, defaultValue ) : defaultValue;
}
inline float KeyValues::GetFloat( int keySymbol, float defaultValue )
{
KeyValues *dat = FindKey( keySymbol );
return dat ? dat->GetFloat( (const char *)NULL, defaultValue ) : defaultValue;
}
inline const char *KeyValues::GetString( int keySymbol, const char *defaultValue )
{
KeyValues *dat = FindKey( keySymbol );
return dat ? dat->GetString( (const char *)NULL, defaultValue ) : defaultValue;
}
inline const wchar_t *KeyValues::GetWString( int keySymbol, const wchar_t *defaultValue )
{
KeyValues *dat = FindKey( keySymbol );
return dat ? dat->GetWString( (const char *)NULL, defaultValue ) : defaultValue;
}
inline void *KeyValues::GetPtr( int keySymbol, void *defaultValue )
{
KeyValues *dat = FindKey( keySymbol );
return dat ? dat->GetPtr( (const char *)NULL, defaultValue ) : defaultValue;
}
inline Color KeyValues::GetColor( int keySymbol )
{
Color defaultValue( 0, 0, 0, 0 );
KeyValues *dat = FindKey( keySymbol );
return dat ? dat->GetColor( ) : defaultValue;
}
inline bool KeyValues::IsEmpty( int keySymbol )
{
KeyValues *dat = FindKey( keySymbol );
return dat ? dat->IsEmpty( ) : true;
}
//
// KeyValuesDumpContext and generic implementations
//
class IKeyValuesDumpContext
{
public:
virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel ) = 0;
virtual bool KvWriteValue( KeyValues *pValue, int nIndentLevel ) = 0;
virtual bool KvEndKey( KeyValues *pKey, int nIndentLevel ) = 0;
};
class IKeyValuesDumpContextAsText : public IKeyValuesDumpContext
{
public:
virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel );
virtual bool KvWriteValue( KeyValues *pValue, int nIndentLevel );
virtual bool KvEndKey( KeyValues *pKey, int nIndentLevel );
public:
virtual bool KvWriteIndent( int nIndentLevel );
virtual bool KvWriteText( char const *szText ) = 0;
};
class CKeyValuesDumpContextAsDevMsg : public IKeyValuesDumpContextAsText
{
public:
// Overrides developer level to dump in DevMsg, zero to dump as Msg
CKeyValuesDumpContextAsDevMsg( int nDeveloperLevel = 1 ) : m_nDeveloperLevel( nDeveloperLevel ) {}
public:
virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel );
virtual bool KvWriteText( char const *szText );
protected:
int m_nDeveloperLevel;
};
inline bool KeyValuesDumpAsDevMsg( KeyValues *pKeyValues, int nIndentLevel = 0, int nDeveloperLevel = 1 )
{
CKeyValuesDumpContextAsDevMsg ctx( nDeveloperLevel );
return pKeyValues->Dump( &ctx, nIndentLevel );
}
#endif // KEYVALUES_H

View File

@@ -0,0 +1,70 @@
//========= Copyright Valve Corporation, All rights reserved. =================//
//
// Read JSON-formatted data into KeyValues
//
//=============================================================================//
#ifndef KEYVALUESJSON_H
#define KEYVALUESJSON_H
#ifdef _WIN32
#pragma once
#endif
#include "keyvalues.h"
class CUtlBuffer;
/// JSON parser. Use this class when you need to customize the parsing.
class KeyValuesJSONParser
{
public:
KeyValuesJSONParser( const CUtlBuffer &buf );
KeyValuesJSONParser( const char *pszText, int cbSize = -1 );
~KeyValuesJSONParser();
/// Parse the whole string. If there's a problem, returns NULL and sets m_nLine,m_szErrMsg with more info.
KeyValues *ParseFile();
/// Error message is returned here, if there is one.
char m_szErrMsg[ 1024 ];
/// Line number of current token during parsing, or of the error, of pasring fails
int m_nLine;
private:
bool ParseObject( KeyValues *pObject );
bool ParseArray( KeyValues *pArray );
bool ParseValue( KeyValues *pValue );
void Init( const char *pszText, int cbSize );
const char *m_cur;
const char *m_end;
enum
{
kToken_Err = -2, // An error has been discovered, don't parse anything else
kToken_EOF = -1,
kToken_String = 1,
kToken_NumberInt = 2,
kToken_NumberFloat = 3,
kToken_True = 4,
kToken_False = 5,
kToken_Null = 6,
};
int m_eToken;
CUtlVectorFixedGrowable<char,1024> m_vecTokenChars;
void NextToken();
void ParseNumberToken();
void ParseStringToken();
const char *GetTokenDebugText();
};
#ifdef _DEBUG
extern void TestKeyValuesJSONParser();
#endif
#endif // KEYVALUESJSON_H

49
public/tier1/kvpacker.h Normal file
View File

@@ -0,0 +1,49 @@
//========= Copyright (c), Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef KVPACKER_H
#define KVPACKER_H
#ifdef _WIN32
#pragma once
#endif
#include "keyvalues.h"
//-----------------------------------------------------------------------------
// Purpose: Handles packing KeyValues binary packing and unpacking in a a
// consistent way across all branches, including Steam. If you change
// this packing format you need to do so in a backward compatible way
// so that the Steam servers and all the various GCs can still talk to
// each other.
//-----------------------------------------------------------------------------
class KVPacker
{
public:
bool WriteAsBinary( KeyValues *pNode, CUtlBuffer &buffer );
bool ReadAsBinary( KeyValues *pNode, CUtlBuffer &buffer );
private:
// These types are used for serialization of KeyValues nodes.
// Do not renumber them or you will break serialization across
// branches.
enum EPackType
{
PACKTYPE_NONE = 0,
PACKTYPE_STRING,
PACKTYPE_INT,
PACKTYPE_FLOAT,
PACKTYPE_PTR,
PACKTYPE_WSTRING,
PACKTYPE_COLOR,
PACKTYPE_UINT64,
PACKTYPE_NULLMARKER, // used to mark the end of a block in the binary format
};
};
#endif // KVPACKER_H

View File

@@ -0,0 +1,170 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef LERP_FUNCTIONS_H
#define LERP_FUNCTIONS_H
#ifdef _WIN32
#pragma once
#endif
template <class T>
inline T LoopingLerp( float flPercent, T flFrom, T flTo )
{
T s = flTo * flPercent + flFrom * (1.0f - flPercent);
return s;
}
template <>
inline float LoopingLerp( float flPercent, float flFrom, float flTo )
{
if ( fabs( flTo - flFrom ) >= 0.5f )
{
if (flFrom < flTo)
flFrom += 1.0f;
else
flTo += 1.0f;
}
float s = flTo * flPercent + flFrom * (1.0f - flPercent);
s = s - (int)(s);
if (s < 0.0f)
s = s + 1.0f;
return s;
}
template <class T>
inline T Lerp_Hermite( const T& /*current*/, float t, const T& p0, const T& p1, const T& p2 )
{
T d1 = p1 - p0;
T d2 = p2 - p1;
T output;
float tSqr = t*t;
float tCube = t*tSqr;
output = p1 * (2*tCube-3*tSqr+1);
output += p2 * (-2*tCube+3*tSqr);
output += d1 * (tCube-2*tSqr+t);
output += d2 * (tCube-tSqr);
return output;
}
template <class T>
inline T Derivative_Hermite( float t, const T& p0, const T& p1, const T& p2 )
{
T d1 = p1 - p0;
T d2 = p2 - p1;
T output;
float tSqr = t*t;
output = p1 * (6*tSqr - 6*t);
output += p2 * (-6*tSqr + 6*t);
output += d1 * (3*tSqr - 4*t + 1);
output += d2 * (3*tSqr - 2*t);
return output;
}
inline void Lerp_Clamp( int val )
{
}
inline void Lerp_Clamp( float val )
{
}
inline void Lerp_Clamp( const Vector &val )
{
}
inline void Lerp_Clamp( const QAngle &val )
{
}
// If we have a range checked var, then we can clamp to its limits.
template< class T, int minValue, int maxValue, int startValue >
inline void Lerp_Clamp( CRangeCheckedVar<T,minValue,maxValue,startValue> &val )
{
val.Clamp();
}
template<>
inline QAngle Lerp_Hermite<QAngle>( const QAngle &/*current*/, float t, const QAngle& p0, const QAngle& p1, const QAngle& p2 )
{
// Can't do hermite with QAngles, get discontinuities, just do a regular interpolation
return Lerp( t, p1, p2 );
}
template <class T>
inline T LoopingLerp_Hermite( T current, float t, T p0, T p1, T p2 )
{
return Lerp_Hermite( current, t, p0, p1, p2 );
}
template <>
inline float LoopingLerp_Hermite( float /*current*/, float t, float p0, float p1, float p2 )
{
if ( fabs( p1 - p0 ) > 0.5f )
{
if ( p0 < p1 )
p0 += 1.0f;
else
p1 += 1.0f;
}
if ( fabs( p2 - p1 ) > 0.5f )
{
if ( p1 < p2 )
{
p1 += 1.0f;
// see if we need to fix up p0
// important for vars that are decreasing from p0->p1->p2 where
// p1 is fixed up relative to p2, eg p0 = 0.2, p1 = 0.1, p2 = 0.9
if ( abs( p1 - p0 ) > 0.5 )
{
if ( p0 < p1 )
p0 += 1.0f;
else
p1 += 1.0f;
}
}
else
{
p2 += 1.0f;
}
}
float s = Lerp_Hermite( /*current*/ 0.0f, t, p0, p1, p2 );
s = s - (int)(s);
if (s < 0.0f)
{
s = s + 1.0f;
}
return s;
}
template< int minValue, int maxValue, int startValue >
inline CRangeCheckedVar<float, minValue, maxValue, startValue> LoopingLerp_Hermite( CRangeCheckedVar<float, minValue, maxValue, startValue> current, float t, CRangeCheckedVar<float, minValue, maxValue, startValue> p0, CRangeCheckedVar<float, minValue, maxValue, startValue> p1, CRangeCheckedVar<float, minValue, maxValue, startValue> p2 )
{
return LoopingLerp_Hermite( (float)current, t, (float)p0, (float)p1, (float)p2 );
}
// NOTE: C_AnimationLayer has its own versions of these functions in animationlayer.h.
#endif // LERP_FUNCTIONS_H

View File

@@ -0,0 +1,44 @@
//========= Copyright <20> 1996-2007, Valve Corporation, All rights reserved. ============//
//
// LZMA Decoder. Designed for run time decoding.
//
// LZMA SDK 4.43 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
// http://www.7-zip.org/
//
//=====================================================================================//
#ifndef _LZMADECODER_H
#define _LZMADECODER_H
#pragma once
#if defined( _X360 ) || defined( _PS3 )
#define LZMA_ID (('L'<<24)|('Z'<<16)|('M'<<8)|('A'))
#else
#define LZMA_ID (('A'<<24)|('M'<<16)|('Z'<<8)|('L'))
#endif
// bind the buffer for correct identification
#pragma pack(1)
struct lzma_header_t
{
unsigned int id;
unsigned int actualSize; // always little endian
unsigned int lzmaSize; // always little endian
unsigned char properties[5];
};
#pragma pack()
typedef void ( *LZMAReadProgressCallbackFunc_t )();
class CLZMA
{
public:
unsigned int Uncompress( unsigned char *pInput, unsigned char *pOutput, LZMAReadProgressCallbackFunc_t pCallback = NULL );
bool IsCompressed( unsigned char *pInput );
unsigned int GetActualSize( unsigned char *pInput );
private:
};
#endif

71
public/tier1/lzss.h Normal file
View File

@@ -0,0 +1,71 @@
//========= Copyright <20> 1996-2007, Valve Corporation, All rights reserved. ============//
//
// LZSS Codec. Designed for fast cheap gametime encoding/decoding. Compression results
// are not aggresive as other alogrithms, but gets 2:1 on most arbitrary uncompressed data.
//
//=====================================================================================//
#ifndef _LZSS_H
#define _LZSS_H
#pragma once
#if defined( PLAT_LITTLE_ENDIAN )
#define LZSS_ID (('S'<<24)|('S'<<16)|('Z'<<8)|('L'))
#else
#define LZSS_ID (('L'<<24)|('Z'<<16)|('S'<<8)|('S'))
#endif
// bind the buffer for correct identification
struct lzss_header_t
{
unsigned int id;
unsigned int actualSize; // always little endian
};
class CUtlBuffer;
#define DEFAULT_LZSS_WINDOW_SIZE 4096
class CLZSS
{
public:
unsigned char* Compress( unsigned char *pInput, int inputlen, unsigned int *pOutputSize );
unsigned char* CompressNoAlloc( unsigned char *pInput, int inputlen, unsigned char *pOutput, unsigned int *pOutputSize );
unsigned int Uncompress( unsigned char *pInput, unsigned char *pOutput );
//unsigned int Uncompress( unsigned char *pInput, CUtlBuffer &buf );
unsigned int SafeUncompress( unsigned char *pInput, unsigned char *pOutput, unsigned int unBufSize );
bool IsCompressed( unsigned char *pInput );
unsigned int GetActualSize( unsigned char *pInput );
// windowsize must be a power of two.
FORCEINLINE CLZSS( int nWindowSize = DEFAULT_LZSS_WINDOW_SIZE );
private:
// expected to be sixteen bytes
struct lzss_node_t
{
unsigned char *pData;
lzss_node_t *pPrev;
lzss_node_t *pNext;
char empty[4];
};
struct lzss_list_t
{
lzss_node_t *pStart;
lzss_node_t *pEnd;
};
void BuildHash( unsigned char *pData );
lzss_list_t *m_pHashTable;
lzss_node_t *m_pHashTarget;
int m_nWindowSize;
};
FORCEINLINE CLZSS::CLZSS( int nWindowSize )
{
m_nWindowSize = nWindowSize;
}
#endif

656
public/tier1/mempool.h Normal file
View File

@@ -0,0 +1,656 @@
//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//===========================================================================//
#ifndef MEMPOOL_H
#define MEMPOOL_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/memalloc.h"
#include "tier0/tslist.h"
#include "tier0/platform.h"
#include "tier1/utlvector.h"
#include "tier1/utlrbtree.h"
//-----------------------------------------------------------------------------
// Purpose: Optimized pool memory allocator
//-----------------------------------------------------------------------------
typedef void (*MemoryPoolReportFunc_t)( PRINTF_FORMAT_STRING char const* pMsg, ... );
class CUtlMemoryPool
{
public:
// Ways the memory pool can grow when it needs to make a new blob.
enum MemoryPoolGrowType_t
{
GROW_NONE=0, // Don't allow new blobs.
GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates
// get larger and larger each time it allocates one).
GROW_SLOW=2 // New blob size is numElements.
};
CUtlMemoryPool( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0 );
~CUtlMemoryPool();
void* Alloc(); // Allocate the element size you specified in the constructor.
void* Alloc( size_t amount );
void* AllocZero(); // Allocate the element size you specified in the constructor, zero the memory before construction
void* AllocZero( size_t amount );
void Free(void *pMem);
// Frees everything
void Clear();
// Error reporting...
static void SetErrorReportFunc( MemoryPoolReportFunc_t func );
// returns number of allocated blocks
int Count() const { return m_BlocksAllocated; }
int PeakCount() const { return m_PeakAlloc; }
int BlockSize() const { return m_BlockSize; }
int Size() const;
bool IsAllocationWithinPool( void *pMem ) const;
protected:
class CBlob
{
public:
CBlob *m_pPrev, *m_pNext;
int m_NumBytes; // Number of bytes in this blob.
char m_Data[1];
char m_Padding[3]; // to int align the struct
};
// Resets the pool
void Init();
void AddNewBlob();
void ReportLeaks();
int m_BlockSize;
int m_BlocksPerBlob;
int m_GrowMode; // GROW_ enum.
int m_BlocksAllocated;
int m_PeakAlloc;
unsigned short m_nAlignment;
unsigned short m_NumBlobs;
// Group up pointers at the end of the class to avoid padding bloat
// FIXME: Change m_ppMemBlob into a growable array?
void *m_pHeadOfFreeList;
const char * m_pszAllocOwner;
// CBlob could be not a multiple of 4 bytes so stuff it at the end here to keep us otherwise aligned
CBlob m_BlobHead;
static MemoryPoolReportFunc_t g_ReportFunc;
};
//-----------------------------------------------------------------------------
// Multi-thread/Thread Safe Memory Class
//-----------------------------------------------------------------------------
class CMemoryPoolMT : public CUtlMemoryPool
{
public:
CMemoryPoolMT( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner, nAlignment ) {}
void* Alloc() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc(); }
void* Alloc( size_t amount ) { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc( amount ); }
void* AllocZero() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::AllocZero(); }
void* AllocZero( size_t amount ) { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::AllocZero( amount ); }
void Free(void *pMem) { AUTO_LOCK( m_mutex ); CUtlMemoryPool::Free( pMem ); }
// Frees everything
void Clear() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Clear(); }
private:
CThreadFastMutex m_mutex; // @TODO: Rework to use tslist (toml 7/6/2007)
};
//-----------------------------------------------------------------------------
// Wrapper macro to make an allocator that returns particular typed allocations
// and construction and destruction of objects.
//-----------------------------------------------------------------------------
template< class T >
class CClassMemoryPool : public CUtlMemoryPool
{
public:
CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = 0 ) :
CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) {}
T* Alloc();
T* AllocZero();
void Free( T *pMem );
void Clear();
};
//-----------------------------------------------------------------------------
// Specialized pool for aligned data management (e.g., Xbox textures)
//-----------------------------------------------------------------------------
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE = false, int COMPACT_THRESHOLD = 4 >
class CAlignedMemPool
{
enum
{
BLOCK_SIZE = COMPILETIME_MAX( ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ), 8 ),
};
public:
CAlignedMemPool();
void *Alloc();
void Free( void *p );
static int __cdecl CompareChunk( void * const *ppLeft, void * const *ppRight );
void Compact();
int NumTotal() { AUTO_LOCK( m_mutex ); return m_Chunks.Count() * ( CHUNK_SIZE / BLOCK_SIZE ); }
int NumAllocated() { AUTO_LOCK( m_mutex ); return NumTotal() - m_nFree; }
int NumFree() { AUTO_LOCK( m_mutex ); return m_nFree; }
int BytesTotal() { AUTO_LOCK( m_mutex ); return NumTotal() * BLOCK_SIZE; }
int BytesAllocated() { AUTO_LOCK( m_mutex ); return NumAllocated() * BLOCK_SIZE; }
int BytesFree() { AUTO_LOCK( m_mutex ); return NumFree() * BLOCK_SIZE; }
int ItemSize() { return ITEM_SIZE; }
int BlockSize() { return BLOCK_SIZE; }
int ChunkSize() { return CHUNK_SIZE; }
private:
struct FreeBlock_t
{
FreeBlock_t *pNext;
byte reserved[ BLOCK_SIZE - sizeof( FreeBlock_t *) ];
};
CUtlVector<void *> m_Chunks; // Chunks are tracked outside blocks (unlike CUtlMemoryPool) to simplify alignment issues
FreeBlock_t * m_pFirstFree;
int m_nFree;
CAllocator m_Allocator;
double m_TimeLastCompact;
CThreadFastMutex m_mutex;
};
//-----------------------------------------------------------------------------
// Pool variant using standard allocation
//-----------------------------------------------------------------------------
template <typename T, int nInitialCount = 0, bool bDefCreateNewIfEmpty = true >
class CObjectPool
{
public:
CObjectPool()
{
int i = nInitialCount;
while ( i-- > 0 )
{
m_AvailableObjects.PushItem( new T );
}
}
~CObjectPool()
{
Purge();
}
int NumAvailable()
{
return m_AvailableObjects.Count();
}
void Purge()
{
T *p = NULL;
while ( m_AvailableObjects.PopItem( &p ) )
{
delete p;
}
}
T *GetObject( bool bCreateNewIfEmpty = bDefCreateNewIfEmpty )
{
T *p = NULL;
if ( !m_AvailableObjects.PopItem( &p ) )
{
p = ( bCreateNewIfEmpty ) ? new T : NULL;
}
return p;
}
void PutObject( T *p )
{
m_AvailableObjects.PushItem( p );
}
private:
CTSList<T *> m_AvailableObjects;
};
//-----------------------------------------------------------------------------
// Fixed budget pool with overflow to malloc
//-----------------------------------------------------------------------------
template <size_t PROVIDED_ITEM_SIZE, int ITEM_COUNT>
class CFixedBudgetMemoryPool
{
public:
CFixedBudgetMemoryPool()
{
m_pBase = m_pLimit = 0;
COMPILE_TIME_ASSERT( ITEM_SIZE % 4 == 0 );
}
bool Owns( void *p )
{
return ( p >= m_pBase && p < m_pLimit );
}
void *Alloc()
{
MEM_ALLOC_CREDIT_CLASS();
#ifndef USE_MEM_DEBUG
if ( !m_pBase )
{
LOCAL_THREAD_LOCK();
if ( !m_pBase )
{
byte *pMemory = m_pBase = (byte *)malloc( ITEM_COUNT * ITEM_SIZE );
m_pLimit = m_pBase + ( ITEM_COUNT * ITEM_SIZE );
for ( int i = 0; i < ITEM_COUNT; i++ )
{
m_freeList.Push( (TSLNodeBase_t *)pMemory );
pMemory += ITEM_SIZE;
}
}
}
void *p = m_freeList.Pop();
if ( p )
return p;
#endif
return malloc( ITEM_SIZE );
}
void Free( void *p )
{
#ifndef USE_MEM_DEBUG
if ( Owns( p ) )
m_freeList.Push( (TSLNodeBase_t *)p );
else
#endif
free( p );
}
void Clear()
{
#ifndef USE_MEM_DEBUG
if ( m_pBase )
{
free( m_pBase );
}
m_pBase = m_pLimit = 0;
Construct( &m_freeList );
#endif
}
bool IsEmpty()
{
#ifndef USE_MEM_DEBUG
if ( m_pBase && m_freeList.Count() != ITEM_COUNT )
return false;
#endif
return true;
}
enum
{
ITEM_SIZE = ALIGN_VALUE( PROVIDED_ITEM_SIZE, TSLIST_NODE_ALIGNMENT )
};
CTSListBase m_freeList;
byte *m_pBase;
byte *m_pLimit;
};
#define BIND_TO_FIXED_BUDGET_POOL( poolName ) \
inline void* operator new( size_t size ) { return poolName.Alloc(); } \
inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { return poolName.Alloc(); } \
inline void operator delete( void* p ) { poolName.Free(p); } \
inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { poolName.Free(p); }
//-----------------------------------------------------------------------------
template< class T >
inline T* CClassMemoryPool<T>::Alloc()
{
T *pRet;
{
MEM_ALLOC_CREDIT_CLASS();
pRet = (T*)CUtlMemoryPool::Alloc();
}
if ( pRet )
{
Construct( pRet );
}
return pRet;
}
template< class T >
inline T* CClassMemoryPool<T>::AllocZero()
{
T *pRet;
{
MEM_ALLOC_CREDIT_CLASS();
pRet = (T*)CUtlMemoryPool::AllocZero();
}
if ( pRet )
{
Construct( pRet );
}
return pRet;
}
template< class T >
inline void CClassMemoryPool<T>::Free(T *pMem)
{
if ( pMem )
{
Destruct( pMem );
}
CUtlMemoryPool::Free( pMem );
}
template< class T >
inline void CClassMemoryPool<T>::Clear()
{
CUtlRBTree<void *, int> freeBlocks;
SetDefLessFunc( freeBlocks );
void *pCurFree = m_pHeadOfFreeList;
while ( pCurFree != NULL )
{
freeBlocks.Insert( pCurFree );
pCurFree = *((void**)pCurFree);
}
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
{
int nElements = pCur->m_NumBytes / this->m_BlockSize;
T *p = ( T * ) AlignValue( pCur->m_Data, this->m_nAlignment );
T *pLimit = p + nElements;
while ( p < pLimit )
{
if ( freeBlocks.Find( p ) == freeBlocks.InvalidIndex() )
{
Destruct( p );
}
p++;
}
}
CUtlMemoryPool::Clear();
}
//-----------------------------------------------------------------------------
// Macros that make it simple to make a class use a fixed-size allocator
// Put DECLARE_FIXEDSIZE_ALLOCATOR in the private section of a class,
// Put DEFINE_FIXEDSIZE_ALLOCATOR in the CPP file
//-----------------------------------------------------------------------------
#define DECLARE_FIXEDSIZE_ALLOCATOR( _class ) \
public: \
inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
inline void operator delete( void* p ) { s_Allocator.Free(p); } \
inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \
private: \
static CUtlMemoryPool s_Allocator
#define DEFINE_FIXEDSIZE_ALLOCATOR( _class, _initsize, _grow ) \
CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool")
#define DEFINE_FIXEDSIZE_ALLOCATOR_ALIGNED( _class, _initsize, _grow, _alignment ) \
CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool", _alignment )
#define DECLARE_FIXEDSIZE_ALLOCATOR_MT( _class ) \
public: \
inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
inline void operator delete( void* p ) { s_Allocator.Free(p); } \
inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \
private: \
static CMemoryPoolMT s_Allocator
#define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \
CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool")
//-----------------------------------------------------------------------------
// Macros that make it simple to make a class use a fixed-size allocator
// This version allows us to use a memory pool which is externally defined...
// Put DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL in the private section of a class,
// Put DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL in the CPP file
//-----------------------------------------------------------------------------
#define DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class ) \
public: \
inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \
inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \
inline void operator delete( void* p ) { s_pAllocator->Free(p); } \
private: \
static CUtlMemoryPool* s_pAllocator
#define DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class, _allocator ) \
CUtlMemoryPool* _class::s_pAllocator = _allocator
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD >
inline CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::CAlignedMemPool()
: m_pFirstFree( 0 ),
m_nFree( 0 ),
m_TimeLastCompact( 0 )
{
// These COMPILE_TIME_ASSERT checks need to be in individual scopes to avoid build breaks
// on MacOS and Linux due to a gcc bug.
{ COMPILE_TIME_ASSERT( sizeof( FreeBlock_t ) >= BLOCK_SIZE ); }
{ COMPILE_TIME_ASSERT( ALIGN_VALUE( sizeof( FreeBlock_t ), ALIGNMENT ) == sizeof( FreeBlock_t ) ); }
}
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD >
inline void *CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::Alloc()
{
AUTO_LOCK( m_mutex );
if ( !m_pFirstFree )
{
if ( !GROWMODE && m_Chunks.Count() )
{
return NULL;
}
FreeBlock_t *pNew = (FreeBlock_t *)m_Allocator.Alloc( CHUNK_SIZE );
Assert( (unsigned)pNew % ALIGNMENT == 0 );
m_Chunks.AddToTail( pNew );
m_nFree = CHUNK_SIZE / BLOCK_SIZE;
m_pFirstFree = pNew;
for ( int i = 0; i < m_nFree - 1; i++ )
{
pNew->pNext = pNew + 1;
pNew++;
}
pNew->pNext = NULL;
}
void *p = m_pFirstFree;
m_pFirstFree = m_pFirstFree->pNext;
m_nFree--;
return p;
}
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD >
inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::Free( void *p )
{
AUTO_LOCK( m_mutex );
// Insertion sort to encourage allocation clusters in chunks
FreeBlock_t *pFree = ((FreeBlock_t *)p);
FreeBlock_t *pCur = m_pFirstFree;
FreeBlock_t *pPrev = NULL;
while ( pCur && pFree > pCur )
{
pPrev = pCur;
pCur = pCur->pNext;
}
pFree->pNext = pCur;
if ( pPrev )
{
pPrev->pNext = pFree;
}
else
{
m_pFirstFree = pFree;
}
m_nFree++;
if ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD )
{
double time = Plat_FloatTime();
double compactTime = ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0;
if ( m_TimeLastCompact > time || m_TimeLastCompact + compactTime < time )
{
Compact();
m_TimeLastCompact = time;
}
}
}
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD >
inline int __cdecl CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::CompareChunk( void * const *ppLeft, void * const *ppRight )
{
return size_cast<int>( (intp)*ppLeft - (intp)*ppRight );
}
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD >
inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::Compact()
{
FreeBlock_t *pCur = m_pFirstFree;
FreeBlock_t *pPrev = NULL;
m_Chunks.Sort( CompareChunk );
#ifdef VALIDATE_ALIGNED_MEM_POOL
{
FreeBlock_t *p = m_pFirstFree;
while ( p )
{
if ( p->pNext && p > p->pNext )
{
__asm { int 3 }
}
p = p->pNext;
}
for ( int i = 0; i < m_Chunks.Count(); i++ )
{
if ( i + 1 < m_Chunks.Count() )
{
if ( m_Chunks[i] > m_Chunks[i + 1] )
{
__asm { int 3 }
}
}
}
}
#endif
int i;
for ( i = 0; i < m_Chunks.Count(); i++ )
{
int nBlocksPerChunk = CHUNK_SIZE / BLOCK_SIZE;
FreeBlock_t *pChunkLimit = ((FreeBlock_t *)m_Chunks[i]) + nBlocksPerChunk;
int nFromChunk = 0;
if ( pCur == m_Chunks[i] )
{
FreeBlock_t *pFirst = pCur;
while ( pCur && pCur >= m_Chunks[i] && pCur < pChunkLimit )
{
pCur = pCur->pNext;
nFromChunk++;
}
pCur = pFirst;
}
while ( pCur && pCur >= m_Chunks[i] && pCur < pChunkLimit )
{
if ( nFromChunk != nBlocksPerChunk )
{
if ( pPrev )
{
pPrev->pNext = pCur;
}
else
{
m_pFirstFree = pCur;
}
pPrev = pCur;
}
else if ( pPrev )
{
pPrev->pNext = NULL;
}
else
{
m_pFirstFree = NULL;
}
pCur = pCur->pNext;
}
if ( nFromChunk == nBlocksPerChunk )
{
m_Allocator.Free( m_Chunks[i] );
m_nFree -= nBlocksPerChunk;
m_Chunks[i] = 0;
}
}
for ( i = m_Chunks.Count() - 1; i >= 0 ; i-- )
{
if ( !m_Chunks[i] )
{
m_Chunks.FastRemove( i );
}
}
}
#endif // MEMPOOL_H

364
public/tier1/memstack.h Normal file
View File

@@ -0,0 +1,364 @@
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose: A fast stack memory allocator that uses virtual memory if available
//
//===========================================================================//
#ifndef MEMSTACK_H
#define MEMSTACK_H
#if defined( _WIN32 )
#pragma once
#endif
#include "tier1/utlvector.h"
#if defined( _WIN32 ) || defined( _PS3 )
#define MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
#endif
//-----------------------------------------------------------------------------
typedef unsigned MemoryStackMark_t;
class CMemoryStack : private IMemoryInfo
{
public:
CMemoryStack();
~CMemoryStack();
bool Init( const char *pszAllocOwner, unsigned maxSize = 0, unsigned commitIncrement = 0, unsigned initialCommit = 0, unsigned alignment = 16 );
#ifdef _GAMECONSOLE
bool InitPhysical( const char *pszAllocOwner, uint size, uint nBaseAddrAlignment, uint alignment = 16, uint32 nAdditionalFlags = 0 );
#endif
void Term();
int GetSize() const;
int GetMaxSize() const ;
int GetUsed() const;
void *Alloc( unsigned bytes, bool bClear = false ) RESTRICT;
MemoryStackMark_t GetCurrentAllocPoint() const;
void FreeToAllocPoint( MemoryStackMark_t mark, bool bDecommit = true );
void FreeAll( bool bDecommit = true );
void Access( void **ppRegion, unsigned *pBytes );
void PrintContents() const;
void *GetBase();
const void *GetBase() const { return const_cast<CMemoryStack *>(this)->GetBase(); }
bool CommitSize( int nBytes );
void SetAllocOwner( const char *pszAllocOwner );
private:
bool CommitTo( byte * ) RESTRICT;
void RegisterAllocation();
void RegisterDeallocation( bool bShouldSpew );
byte *m_pNextAlloc; // Current alloc point (m_pNextAlloc - m_pBase == allocated bytes)
byte *m_pCommitLimit; // The current end of the committed memory. On systems without dynamic commit/decommit this is always m_pAllocLimit
byte *m_pAllocLimit; // The top of the allocated address space (m_pBase + m_maxSize)
// Track the highest alloc limit seen.
byte *m_pHighestAllocLimit;
const char* GetMemoryName() const OVERRIDE; // User friendly name for this stack or pool
size_t GetAllocatedBytes() const OVERRIDE; // Number of bytes currently allocated
size_t GetCommittedBytes() const OVERRIDE; // Bytes committed -- may be greater than allocated.
size_t GetReservedBytes() const OVERRIDE; // Bytes reserved -- may be greater than committed.
size_t GetHighestBytes() const OVERRIDE; // The maximum number of bytes allocated or committed.
byte *m_pBase;
bool m_bRegisteredAllocation;
bool m_bPhysical;
char *m_pszAllocOwner;
unsigned m_maxSize; // m_maxSize stores how big the stack can grow. It measures the reservation size.
unsigned m_alignment;
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
unsigned m_commitIncrement;
unsigned m_minCommit;
#endif
#if defined( MEMSTACK_VIRTUAL_MEMORY_AVAILABLE ) && defined( _PS3 )
IVirtualMemorySection *m_pVirtualMemorySection;
#endif
private:
// Make the assignment operator and copy constructor private and unimplemented.
CMemoryStack& operator=( const CMemoryStack& );
CMemoryStack( const CMemoryStack& );
};
//-------------------------------------
FORCEINLINE void *CMemoryStack::Alloc( unsigned bytes, bool bClear ) RESTRICT
{
Assert( m_pBase );
bytes = MAX( bytes, m_alignment );
bytes = AlignValue( bytes, m_alignment );
void *pResult = m_pNextAlloc;
byte *pNextAlloc = m_pNextAlloc + bytes;
if ( pNextAlloc > m_pCommitLimit )
{
if ( !CommitTo( pNextAlloc ) )
{
return NULL;
}
}
if ( bClear )
{
memset( pResult, 0, bytes );
}
m_pNextAlloc = pNextAlloc;
m_pHighestAllocLimit = Max( m_pNextAlloc, m_pHighestAllocLimit );
return pResult;
}
//-------------------------------------
inline bool CMemoryStack::CommitSize( int nBytes )
{
if ( GetSize() != nBytes )
{
return CommitTo( m_pBase + nBytes );
}
return true;
}
//-------------------------------------
// How big can this memory stack grow? This is equivalent to how many
// bytes are reserved.
inline int CMemoryStack::GetMaxSize() const
{
return m_maxSize;
}
//-------------------------------------
inline int CMemoryStack::GetUsed() const
{
return ( m_pNextAlloc - m_pBase );
}
//-------------------------------------
inline void *CMemoryStack::GetBase()
{
return m_pBase;
}
//-------------------------------------
inline MemoryStackMark_t CMemoryStack::GetCurrentAllocPoint() const
{
return ( m_pNextAlloc - m_pBase );
}
//-----------------------------------------------------------------------------
// The CUtlMemoryStack class:
// A fixed memory class
//-----------------------------------------------------------------------------
template< typename T, typename I, size_t MAX_SIZE, size_t COMMIT_SIZE = 0, size_t INITIAL_COMMIT = 0 >
class CUtlMemoryStack
{
public:
// constructor, destructor
CUtlMemoryStack( int nGrowSize = 0, int nInitSize = 0 ) { m_MemoryStack.Init( "CUtlMemoryStack", MAX_SIZE * sizeof(T), COMMIT_SIZE * sizeof(T), INITIAL_COMMIT * sizeof(T), 4 ); COMPILE_TIME_ASSERT( sizeof(T) % 4 == 0 ); }
CUtlMemoryStack( T* pMemory, int numElements ) { Assert( 0 ); }
// Can we use this index?
bool IsIdxValid( I i ) const { long x=i; return (x >= 0) && (x < m_nAllocated); }
// Specify the invalid ('null') index that we'll only return on failure
static const I INVALID_INDEX = ( I )-1; // For use with COMPILE_TIME_ASSERT
static I InvalidIndex() { return INVALID_INDEX; }
class Iterator_t
{
Iterator_t( I i ) : index( i ) {}
I index;
friend class CUtlMemoryStack<T,I,MAX_SIZE, COMMIT_SIZE, INITIAL_COMMIT>;
public:
bool operator==( const Iterator_t it ) const { return index == it.index; }
bool operator!=( const Iterator_t it ) const { return index != it.index; }
};
Iterator_t First() const { return Iterator_t( m_nAllocated ? 0 : InvalidIndex() ); }
Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( it.index < m_nAllocated ? it.index + 1 : InvalidIndex() ); }
I GetIndex( const Iterator_t &it ) const { return it.index; }
bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; }
bool IsValidIterator( const Iterator_t &it ) const { long x=it.index; return x >= 0 && x < m_nAllocated; }
Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); }
// Gets the base address
T* Base() { return (T*)m_MemoryStack.GetBase(); }
const T* Base() const { return (const T*)m_MemoryStack.GetBase(); }
// element access
T& operator[]( I i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
const T& operator[]( I i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
T& Element( I i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
const T& Element( I i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
// Attaches the buffer to external memory....
void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); }
// Size
int NumAllocated() const { return m_nAllocated; }
int Count() const { return m_nAllocated; }
// Grows the memory, so that at least allocated + num elements are allocated
void Grow( int num = 1 ) { Assert( num > 0 ); m_nAllocated += num; m_MemoryStack.Alloc( num * sizeof(T) ); }
// Makes sure we've got at least this much memory
void EnsureCapacity( int num ) { Assert( num <= MAX_SIZE ); if ( m_nAllocated < num ) Grow( num - m_nAllocated ); }
// Memory deallocation
void Purge() { m_MemoryStack.FreeAll(); m_nAllocated = 0; }
// is the memory externally allocated?
bool IsExternallyAllocated() const { return false; }
// Set the size by which the memory grows
void SetGrowSize( int size ) { Assert( 0 ); }
// Identify the owner of this memory stack's memory
void SetAllocOwner( const char *pszAllocOwner ) { m_MemoryStack.SetAllocOwner( pszAllocOwner ); }
private:
CMemoryStack m_MemoryStack;
int m_nAllocated;
};
#ifdef _X360
//-----------------------------------------------------------------------------
// A memory stack used for allocating physical memory on the 360
// Usage pattern anticipates we usually never go over the initial allocation
// When we do so, we're ok with slightly slower allocation
//-----------------------------------------------------------------------------
class CPhysicalMemoryStack
{
public:
CPhysicalMemoryStack();
~CPhysicalMemoryStack();
// The physical memory stack is allocated in chunks. We will initially
// allocate nInitChunkCount chunks, which will always be in memory.
// When FreeAll() is called, it will free down to the initial chunk count
// but not below it.
bool Init( size_t nChunkSizeInBytes, size_t nAlignment, int nInitialChunkCount, uint32 nAdditionalFlags );
void Term();
size_t GetSize() const;
size_t GetPeakUsed() const;
size_t GetUsed() const;
size_t GetFramePeakUsed() const;
MemoryStackMark_t GetCurrentAllocPoint() const;
void FreeToAllocPoint( MemoryStackMark_t mark, bool bUnused = true ); // bUnused is for interface compat with CMemoryStack
void *Alloc( size_t nSizeInBytes, bool bClear = false ) RESTRICT;
void FreeAll( bool bUnused = true ); // bUnused is for interface compat with CMemoryStack
void PrintContents();
private:
void *AllocFromOverflow( size_t nSizeInBytes );
struct PhysicalChunk_t
{
uint8 *m_pBase;
uint8 *m_pNextAlloc;
uint8 *m_pAllocLimit;
};
PhysicalChunk_t m_InitialChunk;
CUtlVector< PhysicalChunk_t > m_ExtraChunks;
size_t m_nUsage;
size_t m_nFramePeakUsage;
size_t m_nPeakUsage;
size_t m_nAlignment;
size_t m_nChunkSizeInBytes;
int m_nFirstAvailableChunk;
int m_nAdditionalFlags;
PhysicalChunk_t *m_pLastAllocedChunk;
};
//-------------------------------------
FORCEINLINE void *CPhysicalMemoryStack::Alloc( size_t nSizeInBytes, bool bClear ) RESTRICT
{
if ( nSizeInBytes )
{
nSizeInBytes = AlignValue( nSizeInBytes, m_nAlignment );
}
else
{
nSizeInBytes = m_nAlignment;
}
// Can't do an allocation bigger than the chunk size
Assert( nSizeInBytes <= m_nChunkSizeInBytes );
void *pResult = m_InitialChunk.m_pNextAlloc;
uint8 *pNextAlloc = m_InitialChunk.m_pNextAlloc + nSizeInBytes;
if ( pNextAlloc <= m_InitialChunk.m_pAllocLimit )
{
m_InitialChunk.m_pNextAlloc = pNextAlloc;
m_pLastAllocedChunk = &m_InitialChunk;
}
else
{
pResult = AllocFromOverflow( nSizeInBytes );
}
m_nUsage += nSizeInBytes;
m_nFramePeakUsage = MAX( m_nUsage, m_nFramePeakUsage );
m_nPeakUsage = MAX( m_nUsage, m_nPeakUsage );
if ( bClear )
{
memset( pResult, 0, nSizeInBytes );
}
return pResult;
}
//-------------------------------------
inline size_t CPhysicalMemoryStack::GetPeakUsed() const
{
return m_nPeakUsage;
}
//-------------------------------------
inline size_t CPhysicalMemoryStack::GetUsed() const
{
return m_nUsage;
}
inline size_t CPhysicalMemoryStack::GetFramePeakUsed() const
{
return m_nFramePeakUsage;
}
inline MemoryStackMark_t CPhysicalMemoryStack::GetCurrentAllocPoint() const
{
Assert( m_pLastAllocedChunk );
return ( m_pLastAllocedChunk->m_pNextAlloc - m_pLastAllocedChunk->m_pBase );
}
#endif // _X360
#endif // MEMSTACK_H

View File

@@ -0,0 +1,22 @@
//========= Copyright c 2009, Valve Corporation, All rights reserved. ============//
#ifndef TIER1_MINIPROFILER_HASH_HDR
#define TIER1_MINIPROFILER_HASH_HDR
#include "tier0/miniprofiler.h"
#if ENABLE_HARDWARE_PROFILER
extern CLinkedMiniProfiler *HashMiniProfiler( const char *pString ); // may be defined in tier1; not very elegant, but it seems overkill to move this to a new tier1 header
extern CLinkedMiniProfiler *HashMiniProfilerF( const char *pFormat, ... ); // may be defined in tier1; not very elegant, but it seems overkill to move this to a new tier1 header
#define MINI_PROFILE(NAME) CMiniProfilerGuard miniProfilerGuard##__LINE__(HashMiniProfiler(NAME))
#define MINI_PROFILE_F(PRINT,...) CMiniProfilerGuard miniProfilerGuard##__LINE__(HashMiniProfilerF(PRINT,__VA_ARGS__))
#define MINI_PROFILE_CALLS(NAME,NUM_CALLS) CMiniProfilerGuard miniProfilerGuard##__LINE__(HashMiniProfiler(NAME),(NUM_CALLS))
#else
#define MINI_PROFILE(NAME)
#define MINI_PROFILE_F(PRINT,...)
#define MINI_PROFILE_CALLS(NAME,NUM_CALLS)
#endif
#endif

136
public/tier1/netadr.h Normal file
View File

@@ -0,0 +1,136 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// netadr.h
#ifndef NETADR_H
#define NETADR_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/platform.h"
#undef SetPort
class bf_read;
class bf_write;
typedef enum
{
NA_NULL = 0,
NA_LOOPBACK,
NA_BROADCAST,
NA_IP,
} netadrtype_t;
typedef struct netadr_s
{
public:
netadr_s() { SetIP( 0 ); SetPort( 0 ); SetType( NA_IP ); }
netadr_s( uint unIP, uint16 usPort ) { SetIP( unIP ); SetPort( usPort ); SetType( NA_IP ); }
netadr_s( const char *pch ) { SetFromString( pch ); }
void Clear(); // invalids Address
void SetType( netadrtype_t type );
void SetPort( unsigned short port );
bool SetFromSockadr(const struct sockaddr *s);
void SetIP(uint8 b1, uint8 b2, uint8 b3, uint8 b4);
void SetIP(uint unIP); // Sets IP. unIP is in host order (little-endian)
void SetIPAndPort( uint unIP, unsigned short usPort ) { SetIP( unIP ); SetPort( usPort ); }
bool SetFromString(const char *pch, bool bUseDNS = false ); // if bUseDNS is true then do a DNS lookup if needed
bool CompareAdr (const netadr_s &a, bool onlyBase = false) const;
bool CompareClassBAdr (const netadr_s &a) const;
bool CompareClassCAdr (const netadr_s &a) const;
netadrtype_t GetType() const;
unsigned short GetPort() const;
// DON'T CALL THIS
const char* ToString( bool onlyBase = false ) const; // returns xxx.xxx.xxx.xxx:ppppp
void ToString( char *pchBuffer, uint32 unBufferSize, bool onlyBase = false ) const; // returns xxx.xxx.xxx.xxx:ppppp
template< size_t maxLenInChars >
void ToString_safe( char (&pDest)[maxLenInChars], bool onlyBase = false ) const
{
ToString( &pDest[0], maxLenInChars, onlyBase );
}
void ToSockadr(struct sockaddr *s) const;
// Returns 0xAABBCCDD for AA.BB.CC.DD on all platforms, which is the same format used by SetIP().
// (So why isn't it just named GetIP()? Because previously there was a fucntion named GetIP(), and
// it did NOT return back what you put into SetIP(). So we nuked that guy.)
unsigned int GetIPHostByteOrder() const;
// Returns a number that depends on the platform. In most cases, this probably should not be used.
unsigned int GetIPNetworkByteOrder() const;
bool IsLocalhost() const; // true, if this is the localhost IP
bool IsLoopback() const; // true if engine loopback buffers are used
bool IsReservedAdr() const; // true, if this is a private LAN IP
bool IsValid() const; // ip & port != 0
bool IsBaseAdrValid() const; // ip != 0
void SetFromSocket( int hSocket );
bool Unserialize( bf_read &readBuf );
bool Serialize( bf_write &writeBuf );
bool operator==(const netadr_s &netadr) const {return ( CompareAdr( netadr ) );}
bool operator!=(const netadr_s &netadr) const {return !( CompareAdr( netadr ) );}
bool operator<(const netadr_s &netadr) const;
public: // members are public to avoid to much changes
netadrtype_t type;
unsigned char ip[4];
unsigned short port;
} netadr_t;
/// Helper class to render a netadr_t. Use this when formatting a net address
/// in a printf. Don't use adr.ToString()!
class CUtlNetAdrRender
{
public:
CUtlNetAdrRender( const netadr_t &obj, bool bBaseOnly = false )
{
obj.ToString( m_rgchString, sizeof(m_rgchString), bBaseOnly );
}
CUtlNetAdrRender( uint32 unIP )
{
netadr_t addr( unIP, 0 );
addr.ToString( m_rgchString, sizeof(m_rgchString), true );
}
CUtlNetAdrRender( uint32 unIP, uint16 unPort )
{
netadr_t addr( unIP, unPort );
addr.ToString( m_rgchString, sizeof(m_rgchString), false );
}
CUtlNetAdrRender( const struct sockaddr &s )
{
netadr_t addr;
if ( addr.SetFromSockadr( &s ) )
addr.ToString( m_rgchString, sizeof(m_rgchString), false );
else
m_rgchString[0] = '\0';
}
const char * String() const
{
return m_rgchString;
}
private:
char m_rgchString[32];
};
#endif // NETADR_H

564
public/tier1/ns_address.h Normal file
View File

@@ -0,0 +1,564 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// netadr.h
#ifndef NS_ADDRESS_H
#define NS_ADDRESS_H
#pragma once
#include "tier0/platform.h"
#include "tier0/dbg.h"
#include "tier1/netadr.h"
#include "steam/steamclientpublic.h" // for CSteamID
#include "tier1/strtools.h" // V_memset
#if defined( NO_STEAM )
typedef CSteamID uint64;
#endif
enum PeerToPeerAddressType_t
{
P2P_STEAMID,
};
// Build int subchannel types
// FIXME - these really are game specific. I wish we could standardize!
enum SteamPeerToPeerChannel_t
{
STEAM_P2P_GAME_CLIENT = 0,
STEAM_P2P_GAME_SERVER = 1,
STEAM_P2P_LOBBY = 2,
STEAM_P2P_HLTV = 3,
STEAM_P2P_HLTV1 = 4,
};
class CPeerToPeerAddress
{
public:
CPeerToPeerAddress ( void )
: m_AddrType( P2P_STEAMID )
, m_steamChannel( STEAM_P2P_GAME_CLIENT )
{}
void Clear ( void )
{
m_AddrType = P2P_STEAMID;
m_steamID.Clear();
m_steamChannel = STEAM_P2P_GAME_CLIENT;
}
void SetSteamChannel( int nChannel )
{
m_steamChannel = nChannel;
}
int GetSteamChannel() const
{
return m_steamChannel;
}
const CSteamID &GetSteamID() const
{
return m_steamID;
}
CPeerToPeerAddress ( const CSteamID &steamID, int nSteamChannel )
: m_AddrType ( P2P_STEAMID )
, m_steamID ( steamID )
, m_steamChannel( nSteamChannel )
{
}
private:
// disallow since we can't deal with steamchannel
CPeerToPeerAddress &operator=(const CSteamID &steamID);
public:
// Like operator =
CPeerToPeerAddress &SetFromSteamID( const CSteamID &steamID, int nSteamChannel )
{
m_AddrType = P2P_STEAMID;
m_steamID = steamID;
m_steamChannel = nSteamChannel;
return *this;
}
bool IsValid ( void ) const
{
switch ( m_AddrType )
{
case P2P_STEAMID:
return m_steamID.IsValid ( );
};
return false;
}
const char *ToString ( void ) const
{
switch ( m_AddrType )
{
case P2P_STEAMID:
return m_steamID.Render ( );
};
return "";
}
bool CompareAdr ( const CPeerToPeerAddress &other, bool onlyBase = false ) const
{
if ( m_AddrType != -other.m_AddrType )
return false;
switch ( m_AddrType )
{
case P2P_STEAMID:
return ((m_steamID == other.m_steamID) && (m_steamChannel == other.m_steamChannel));
};
return false;
}
bool operator==(const CPeerToPeerAddress &rhs) const
{
return CompareAdr( rhs, false );
}
PeerToPeerAddressType_t GetAddressType ( void ) const
{
return m_AddrType;
}
template <typename T> bool IsType ( void ) const
{
return false;
}
template <typename T> T *Get ( void ) { return NULL; }
template <typename T> const T *Get ( void ) const { return NULL; }
template <typename T> T &AsType ( void ) { static T dummy; return dummy; }
template <typename T> const T &AsType ( void ) const { static T dummy; return dummy; }
private:
CSteamID m_steamID;
int m_steamChannel; // SteamID channel (like a port number to disambiguate multiple connections)
PeerToPeerAddressType_t m_AddrType;
};
template <>
inline bool CPeerToPeerAddress::IsType<CSteamID> ( void ) const
{
return (m_AddrType == P2P_STEAMID);
}
template <>
inline CSteamID * CPeerToPeerAddress::Get<CSteamID> ( void )
{
return IsType<CSteamID> ( ) ? &m_steamID : NULL;
}
template <>
inline const CSteamID * CPeerToPeerAddress::Get<CSteamID> ( void ) const
{
return IsType<CSteamID> ( ) ? &m_steamID : NULL;
}
template <>
inline CSteamID &CPeerToPeerAddress::AsType<CSteamID> ( void )
{
Assert ( IsType<CSteamID> ( ) );
return m_steamID;
}
template <>
inline const CSteamID &CPeerToPeerAddress::AsType<CSteamID> ( void ) const
{
Assert ( IsType<CSteamID> ( ) );
return m_steamID;
}
enum NetworkSystemAddressType_t
{
NSAT_NETADR,
NSAT_P2P,
NSAT_PROXIED_GAMESERVER, // Client proxied through Steam Datagram Transport
NSAT_PROXIED_CLIENT, // Client proxied through Steam Datagram Transport
};
// Used to represent a remote address which can be a network address or SteamID
// Basically if m_steamID.IsValid() then we send to that otherwise we use the m_adr
struct ns_address
{
netadr_t m_adr; // ip:port and network type (NULL/IP/BROADCAST/etc).
CPeerToPeerAddress m_steamID; // SteamID destination
NetworkSystemAddressType_t m_AddrType;
ns_address() : m_AddrType( NSAT_NETADR ){}
~ns_address()
{
Clear();
}
void Clear ( )
{
m_AddrType = NSAT_NETADR;
m_adr.Clear ( );
m_steamID.Clear ( );
}
ns_address ( const netadr_t &other )
: m_AddrType ( NSAT_NETADR )
, m_adr ( other )
{
m_steamID.Clear();
}
ns_address& operator=(const netadr_t &other)
{
Clear ( );
m_AddrType = NSAT_NETADR;
m_adr = other;
return *this;
}
ns_address ( const CPeerToPeerAddress &steamID )
: m_AddrType ( NSAT_P2P )
, m_steamID ( steamID )
{
m_adr.Clear ( );
}
ns_address& operator=(const CPeerToPeerAddress &steamID)
{
Clear ( );
m_AddrType = NSAT_P2P;
m_steamID = steamID;
return *this;
}
ns_address &SetFromSteamID ( const CSteamID &steamID, int nSteamChannel )
{
Clear ( );
m_AddrType = NSAT_P2P;
m_steamID.SetFromSteamID( steamID, nSteamChannel );
return *this;
}
bool IsLoopback ( void ) const
{
return (m_AddrType == NSAT_NETADR) && m_adr.IsLoopback ( );
}
bool IsLocalhost ( void ) const
{
return (m_AddrType == NSAT_NETADR) && m_adr.IsLocalhost ( );
}
bool IsBroadcast( void ) const
{
return (m_AddrType == NSAT_NETADR) && m_adr.GetType() == NA_BROADCAST;
}
bool IsReservedAdr( void ) const
{
return (m_AddrType == NSAT_NETADR) && m_adr.IsReservedAdr();
}
bool IsNull ( void ) const
{
switch ( m_AddrType )
{
case NSAT_NETADR:
return m_adr.GetType ( ) == NA_NULL;
case NSAT_P2P:
case NSAT_PROXIED_GAMESERVER:
case NSAT_PROXIED_CLIENT:
return !m_steamID.IsValid ( );
};
return true;
}
bool IsValid ( ) const
{
switch ( m_AddrType )
{
case NSAT_NETADR:
return m_adr.IsValid ( );
case NSAT_P2P:
case NSAT_PROXIED_GAMESERVER:
case NSAT_PROXIED_CLIENT:
return m_steamID.IsValid ( );
};
return false;
}
bool CompareAdr ( const ns_address &other, bool onlyBase = false ) const
{
if ( m_AddrType != other.m_AddrType )
return false;
switch ( m_AddrType )
{
case NSAT_NETADR:
return m_adr.CompareAdr ( other.m_adr, onlyBase );
case NSAT_P2P:
case NSAT_PROXIED_GAMESERVER:
case NSAT_PROXIED_CLIENT:
return m_steamID.CompareAdr( other.m_steamID, onlyBase );
};
return false;
}
bool operator==( const ns_address &rhs ) const
{
return CompareAdr( rhs, false );
}
bool operator!=( const ns_address &rhs ) const
{
return !CompareAdr( rhs, false );
}
NetworkSystemAddressType_t GetAddressType ( void ) const
{
return m_AddrType;
}
void SetAddrType( NetworkSystemAddressType_t type )
{
Clear();
m_AddrType = type;
}
bool SetFromSockadr ( const struct sockaddr * s )
{
m_AddrType = NSAT_NETADR;
m_steamID.Clear ( );
return m_adr.SetFromSockadr ( s );
}
unsigned int GetIP ( void ) const
{
return (m_AddrType == NSAT_NETADR) ? m_adr.GetIPHostByteOrder( ) : 0;
}
unsigned short GetPort ( void ) const
{
return (m_AddrType == NSAT_NETADR) ? m_adr.GetPort ( ) : 0;
}
template <typename T> bool IsType ( void ) const
{
//defer to subtype
switch ( m_AddrType )
{
case NSAT_P2P:
return m_steamID.IsType<T> ( );
};
return false;
}
template <typename T> T *Get ( void )
{
//defer to subtype
switch ( m_AddrType )
{
case NSAT_P2P:
return m_steamID.Get<T> ( );
};
return NULL;
}
template <typename T> const T *Get ( void ) const
{
//defer to subtype
switch ( m_AddrType )
{
case NSAT_P2P:
return m_steamID.Get<T> ( );
};
return NULL;
}
template <typename T> T &AsType ( void )
{
//defer to subtype
switch ( m_AddrType )
{
case NSAT_P2P:
return m_steamID.AsType<T> ( );
};
Assert ( false );
static T dummy;
return dummy;
}
template <typename T> const T &AsType ( void ) const
{
//defer to subtype
switch ( m_AddrType )
{
case NSAT_P2P:
return m_steamID.AsType<T> ( );
};
Assert ( false );
static T dummy;
return dummy;
}
bool SetFromString( const char *s )
{
Clear();
if ( !s )
return false;
bool bProxied = false;
if ( *s == '=' )
{
++s;
bProxied = true;
}
if ( *s == '[' )
{
CSteamID tempSteamID( s );
if ( !tempSteamID.IsValid() )
return false;
if ( bProxied && tempSteamID.BGameServerAccount() )
{
m_AddrType = NSAT_PROXIED_GAMESERVER;
m_steamID.SetFromSteamID( tempSteamID, STEAM_P2P_GAME_SERVER );
}
else
{
m_AddrType = bProxied ? NSAT_PROXIED_CLIENT : NSAT_P2P;
m_steamID.SetFromSteamID( tempSteamID, STEAM_P2P_GAME_CLIENT );
}
s = strchr( s, ']' );
int nChannel = -1;
if ( s && s[1] == ':' && sscanf( s+2, "%d", &nChannel ) == 1 && nChannel >= 0 )
{
m_steamID.SetSteamChannel( nChannel );
}
return true;
}
if ( !bProxied && m_adr.SetFromString( s, true ) )
{
m_AddrType = NSAT_NETADR;
return true;
}
return false;
}
};
template <>
inline bool ns_address::IsType<netadr_t> ( void ) const
{
return (m_AddrType == NSAT_NETADR);
}
template <>
inline bool ns_address::IsType<CPeerToPeerAddress> ( void ) const
{
return (m_AddrType == NSAT_P2P);
}
template <>
inline netadr_t *ns_address::Get<netadr_t> ( void )
{
return IsType<netadr_t> ( ) ? &m_adr : NULL;
}
template <>
inline const netadr_t *ns_address::Get<netadr_t> ( void ) const
{
return IsType<netadr_t> ( ) ? &m_adr : NULL;
}
template <>
inline CPeerToPeerAddress *ns_address::Get<CPeerToPeerAddress> ( void )
{
return IsType<CPeerToPeerAddress> ( ) ? &m_steamID : NULL;
}
template <>
inline const CPeerToPeerAddress *ns_address::Get<CPeerToPeerAddress> ( void ) const
{
return IsType<CPeerToPeerAddress> ( ) ? &m_steamID : NULL;
}
template <>
inline netadr_t &ns_address::AsType<netadr_t> ( void )
{
Assert ( IsType<netadr_t> ( ) );
return m_adr;
}
template <>
inline const netadr_t &ns_address::AsType<netadr_t> ( void ) const
{
Assert ( IsType<netadr_t> ( ) );
return m_adr;
}
template <>
inline CPeerToPeerAddress &ns_address::AsType<CPeerToPeerAddress> ( void )
{
Assert ( IsType<CPeerToPeerAddress> ( ) );
return m_steamID;
}
template <>
inline const CPeerToPeerAddress &ns_address::AsType<CPeerToPeerAddress> ( void ) const
{
Assert ( IsType<CPeerToPeerAddress> ( ) );
return m_steamID;
}
/// Utility class used to render an address
class ns_address_render
{
char m_buf[64];
public:
ns_address_render( const ns_address &a )
{
switch ( a.m_AddrType )
{
case NSAT_NETADR:
a.m_adr.ToString( m_buf, sizeof( m_buf ) );
break;
case NSAT_P2P:
V_sprintf_safe( m_buf, "%s:%d", a.m_steamID.ToString(), a.m_steamID.GetSteamChannel() );
break;
case NSAT_PROXIED_CLIENT:
case NSAT_PROXIED_GAMESERVER:
V_sprintf_safe( m_buf, "=%s:%d", a.m_steamID.ToString(), a.m_steamID.GetSteamChannel() );
break;
default:
m_buf[0] = '\0';
};
}
const char *String() const { return m_buf; }
};
#endif // NS_ADDRESS_H

View File

@@ -0,0 +1,94 @@
//========= Copyright <20> 2005, Valve Inc., All rights reserved. ==========
//
// Purpose: Cryptographic hash agility helper definitions
//
//=============================================================================
#ifndef PASSWORDHASH_H
#define PASSWORDHASH_H
#if defined( _WIN32 )
#pragma once
#endif
#include "checksum_sha1.h"
typedef unsigned char BigPasswordHash_t[32];
typedef unsigned char PBKDF2Hash_t[32];
//
// A union of all the possible password hash types.
// When adding to this, if the maximum size of the
// structure has changed then the Account table and
// the AccountSecurityHistory table need to be manually
// revised using something like the following SQL:
//
// ALTER TABLE Account ALTER COLUMN PasswordHash binary(32)
// ALTER TABLE AccountSecurityHistory ALTER COLUMN PasswordHashOld binary(32)
// ALTER TABLE AccountSecurityHistory ALTER COLUMN PasswordHashNew binary(32)
//
// Replace 32 with the new size of PasswordHash_t.
//
// If the width of those columns does not match sizeof(PasswordHash_t), many
// database operations will fail.
//
// Note that while this query was correct at the time this code was checked in,
// it may not be sufficient at the time you actually change the size of the
// type, so look around.
//
typedef union
{
SHADigest_t sha;
BigPasswordHash_t bigpassword;
PBKDF2Hash_t pbkdf2;
} PasswordHash_t;
//
// Enum of all available password hash algorithms. These should
// be consecutive and ordinals should never be reused.
//
// k_EHashSHA1: A salted SHA-1 hash, width 20 bytes.
// k_EHashBigPassword: For testing purposes, a salted SHA-1 hash extended to 32 bytes, with 6 bytes of 0x1 on either side.
// k_EHashPBKDF2_1000: A PKCS#5 v2.0 Password-Based Key Derivation Function hash (PBKDF2-HMAC-SHA256) with 1,000 iterations.
// The digest width is 32 bytes.
// k_EHashPBKDF2_5000: A PKCS#5 v2.0 Password-Based Key Derivation Function hash (PBKDF2-HMAC-SHA256) with 5,000 iterations.
// k_EHashPBKDF2_10000: A PKCS#5 v2.0 Password-Based Key Derivation Function hash (PBKDF2-HMAC-SHA256) with 10,000 iterations.
// k_EHashSHA1WrappedWithPBKDF2_10000: A SHA-1 hash which is then further hashed with PBKDF2 at 10,000 rounds. Used for
// strengthening old hashes in the database that haven't been logged in in a long time.
//
// Make sure to update k_EHashMax when adding new hash types. Also add the length into the k_HashLengths array below.
enum EPasswordHashAlg
{
k_EHashSHA1 = 0,
k_EHashBigPassword = 1,
k_EHashPBKDF2_1000 = 2,
k_EHashPBKDF2_5000 = 3,
k_EHashPBKDF2_10000 = 4,
k_EHashSHA1WrappedWithPBKDF2_10000 = 5,
k_EHashMax = 5,
};
//
// Hash sizes for the various available hash algorithms,
// indexed by EPasswordHashAlg.
const uint k_HashLengths[] = {
sizeof(SHADigest_t),
sizeof(BigPasswordHash_t),
sizeof(PBKDF2Hash_t),
sizeof(PBKDF2Hash_t),
sizeof(PBKDF2Hash_t),
sizeof(PBKDF2Hash_t),
};
#if defined(C_ASSERT)
//
// If you're hitting this assert at compile time, it means that you've added a new
// hash type and properly updated k_EHashMax, but you forgot to add the length
// of the new hash type into k_HashLengths. So do that.
//
C_ASSERT( ( ( sizeof(k_HashLengths) / sizeof(uint) ) == k_EHashMax + 1 ) );
#endif
#endif // PASSWORDHASH_H

View File

@@ -0,0 +1,12 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: functions to expose CPU capabilities
//
// $NoKeywords: $
//=============================================================================//
bool CheckMMXTechnology(void);
bool CheckSSETechnology(void);
bool CheckSSE2Technology(void);
bool Check3DNowTechnology(void);

View File

@@ -0,0 +1,113 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef RANGECHECKEDVAR_H
#define RANGECHECKEDVAR_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
#include "tier0/threadtools.h"
#include "mathlib/vector.h"
#include <float.h>
// Use this to disable range checks within a scope.
class CDisableRangeChecks
{
public:
CDisableRangeChecks();
~CDisableRangeChecks();
};
template< class T >
inline void RangeCheck( const T &value, int minValue, int maxValue )
{
#ifdef _DEBUG
extern bool g_bDoRangeChecks;
if ( ThreadInMainThread() && g_bDoRangeChecks )
{
// Ignore the min/max stuff for now.. just make sure it's not a NAN.
Assert( IsFinite( value ) );
}
#endif
}
inline void RangeCheck( const Vector &value, int minValue, int maxValue )
{
#ifdef _DEBUG
RangeCheck( value.x, minValue, maxValue );
RangeCheck( value.y, minValue, maxValue );
RangeCheck( value.z, minValue, maxValue );
#endif
}
template< class T, int minValue, int maxValue, int startValue >
class CRangeCheckedVar
{
public:
inline CRangeCheckedVar()
{
m_Val = startValue;
}
inline CRangeCheckedVar( const T &value )
{
*this = value;
}
// Clamp the value to its limits. Interpolation code uses this after interpolating.
inline void Clamp()
{
if ( m_Val < minValue )
m_Val = minValue;
else if ( m_Val > maxValue )
m_Val = maxValue;
}
inline operator const T&() const
{
return m_Val;
}
inline CRangeCheckedVar<T, minValue, maxValue, startValue>& operator=( const T &value )
{
RangeCheck( value, minValue, maxValue );
m_Val = value;
return *this;
}
inline CRangeCheckedVar<T, minValue, maxValue, startValue>& operator+=( const T &value )
{
return (*this = m_Val + value);
}
inline CRangeCheckedVar<T, minValue, maxValue, startValue>& operator-=( const T &value )
{
return (*this = m_Val - value);
}
inline CRangeCheckedVar<T, minValue, maxValue, startValue>& operator*=( const T &value )
{
return (*this = m_Val * value);
}
inline CRangeCheckedVar<T, minValue, maxValue, startValue>& operator/=( const T &value )
{
return (*this = m_Val / value);
}
private:
T m_Val;
};
#endif // RANGECHECKEDVAR_H

389
public/tier1/refcount.h Normal file
View File

@@ -0,0 +1,389 @@
//========== Copyright <20> 2005, Valve Corporation, All rights reserved. ========
//
// Purpose: Tools for correctly implementing & handling reference counted
// objects
//
//=============================================================================
#ifndef REFCOUNT_H
#define REFCOUNT_H
#include "tier0/threadtools.h"
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
// Purpose: Implement a standard reference counted interface. Use of this
// is optional insofar as all the concrete tools only require
// at compile time that the function signatures match.
//-----------------------------------------------------------------------------
class IRefCounted
{
public:
virtual int AddRef() = 0;
virtual int Release() = 0;
};
//-----------------------------------------------------------------------------
// Purpose: Release a pointer and mark it NULL
//-----------------------------------------------------------------------------
template <class REFCOUNTED_ITEM_PTR>
inline int SafeRelease( REFCOUNTED_ITEM_PTR &pRef )
{
// Use funny syntax so that this works on "auto pointers"
REFCOUNTED_ITEM_PTR *ppRef = &pRef;
if ( *ppRef )
{
int result = (*ppRef)->Release();
*ppRef = NULL;
return result;
}
return 0;
}
//-----------------------------------------------------------------------------
// Purpose: Maintain a reference across a scope
//-----------------------------------------------------------------------------
template <class T = IRefCounted>
class CAutoRef
{
public:
CAutoRef( T *pRef )
: m_pRef( pRef )
{
if ( m_pRef )
m_pRef->AddRef();
}
~CAutoRef()
{
if (m_pRef)
m_pRef->Release();
}
private:
T *m_pRef;
};
//-----------------------------------------------------------------------------
// Purpose: Do a an inline AddRef then return the pointer, useful when
// returning an object from a function
//-----------------------------------------------------------------------------
#define RetAddRef( p ) ( (p)->AddRef(), (p) )
#define InlineAddRef( p ) ( (p)->AddRef(), (p) )
//-----------------------------------------------------------------------------
// Purpose: A class to both hold a pointer to an object and its reference.
// Base exists to support other cleanup models
//-----------------------------------------------------------------------------
template <class T>
class CBaseAutoPtr
{
public:
CBaseAutoPtr() : m_pObject(0) {}
CBaseAutoPtr(T *pFrom) : m_pObject(pFrom) {}
operator const void *() const { return m_pObject; }
operator void *() { return m_pObject; }
operator const T *() const { return m_pObject; }
operator const T *() { return m_pObject; }
operator T *() { return m_pObject; }
int operator=( int i ) { AssertMsg( i == 0, "Only NULL allowed on integer assign" ); m_pObject = 0; return 0; }
T * operator=( T *p ) { m_pObject = p; return p; }
bool operator !() const { return ( !m_pObject ); }
bool operator!=( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (m_pObject != NULL); }
bool operator==( const void *p ) const { return ( m_pObject == p ); }
bool operator!=( const void *p ) const { return ( m_pObject != p ); }
bool operator==( T *p ) const { return operator==( (void *)p ); }
bool operator!=( T *p ) const { return operator!=( (void *)p ); }
bool operator==( const CBaseAutoPtr<T> &p ) const { return operator==( (const void *)p ); }
bool operator!=( const CBaseAutoPtr<T> &p ) const { return operator!=( (const void *)p ); }
T * operator->() { return m_pObject; }
T & operator *() { return *m_pObject; }
T ** operator &() { return &m_pObject; }
const T * operator->() const { return m_pObject; }
const T & operator *() const { return *m_pObject; }
T * const * operator &() const { return &m_pObject; }
protected:
CBaseAutoPtr( const CBaseAutoPtr<T> &from ) : m_pObject( from.m_pObject ) {}
void operator=( const CBaseAutoPtr<T> &from ) { m_pObject = from.m_pObject; }
T *m_pObject;
};
//---------------------------------------------------------
template <class T>
class CRefPtr : public CBaseAutoPtr<T>
{
typedef CBaseAutoPtr<T> BaseClass;
public:
CRefPtr() {}
CRefPtr( T *pInit ) : BaseClass( pInit ) {}
CRefPtr( const CRefPtr<T> &from ) : BaseClass( from ) {}
~CRefPtr() { if ( BaseClass::m_pObject ) BaseClass::m_pObject->Release(); }
void operator=( const CRefPtr<T> &from ) { BaseClass::operator=( from ); }
int operator=( int i ) { return BaseClass::operator=( i ); }
T *operator=( T *p ) { return BaseClass::operator=( p ); }
operator bool() const { return !BaseClass::operator!(); }
operator bool() { return !BaseClass::operator!(); }
void SafeRelease() { if ( BaseClass::m_pObject ) BaseClass::m_pObject->Release(); BaseClass::m_pObject = 0; }
void AssignAddRef( T *pFrom ) { if (pFrom) pFrom->AddRef(); SafeRelease(); BaseClass::m_pObject = pFrom; }
void AddRefAssignTo( T *&pTo ) { if ( BaseClass::m_pObject ) BaseClass::m_pObject->AddRef(); ::SafeRelease( pTo ); pTo = BaseClass::m_pObject; }
};
//-----------------------------------------------------------------------------
// Purpose: Traits classes defining reference count threading model
//-----------------------------------------------------------------------------
class CRefMT
{
public:
static int Increment( int *p) { return ThreadInterlockedIncrement( (int32 *)p ); }
static int Decrement( int *p) { return ThreadInterlockedDecrement( (int32 *)p ); }
};
class CRefST
{
public:
static int Increment( int *p) { return ++(*p); }
static int Decrement( int *p) { return --(*p); }
};
//-----------------------------------------------------------------------------
// Purpose: Actual reference counting implementation. Pulled out to reduce
// code bloat.
//-----------------------------------------------------------------------------
template <const bool bSelfDelete, typename CRefThreading = CRefMT>
class NO_VTABLE CRefCountServiceBase
{
protected:
CRefCountServiceBase()
: m_iRefs( 1 )
{
}
virtual ~CRefCountServiceBase()
{
}
virtual bool OnFinalRelease()
{
return true;
}
int GetRefCount() const
{
return m_iRefs;
}
int DoAddRef()
{
return CRefThreading::Increment( &m_iRefs );
}
int DoRelease()
{
int result = CRefThreading::Decrement( &m_iRefs );
if ( result )
return result;
if ( OnFinalRelease() && bSelfDelete )
delete this;
return 0;
}
private:
int m_iRefs;
};
class CRefCountServiceNull
{
protected:
static int DoAddRef() { return 1; }
static int DoRelease() { return 1; }
};
template <typename CRefThreading = CRefMT>
class NO_VTABLE CRefCountServiceDestruct
{
protected:
CRefCountServiceDestruct()
: m_iRefs( 1 )
{
}
virtual ~CRefCountServiceDestruct()
{
}
int GetRefCount() const
{
return m_iRefs;
}
int DoAddRef()
{
return CRefThreading::Increment( &m_iRefs );
}
int DoRelease()
{
int result = CRefThreading::Decrement( &m_iRefs );
if ( result )
return result;
this->~CRefCountServiceDestruct();
return 0;
}
private:
int m_iRefs;
};
typedef CRefCountServiceBase<true, CRefST> CRefCountServiceST;
typedef CRefCountServiceBase<false, CRefST> CRefCountServiceNoDeleteST;
typedef CRefCountServiceBase<true, CRefMT> CRefCountServiceMT;
typedef CRefCountServiceBase<false, CRefMT> CRefCountServiceNoDeleteMT;
// Default to threadsafe
typedef CRefCountServiceNoDeleteMT CRefCountServiceNoDelete;
typedef CRefCountServiceMT CRefCountService;
//-----------------------------------------------------------------------------
// Purpose: Base classes to implement reference counting
//-----------------------------------------------------------------------------
template < class REFCOUNT_SERVICE = CRefCountService >
class NO_VTABLE CRefCounted : public REFCOUNT_SERVICE
{
public:
virtual ~CRefCounted() {}
int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
int Release() { return REFCOUNT_SERVICE::DoRelease(); }
};
//-------------------------------------
template < class BASE1, class REFCOUNT_SERVICE = CRefCountService >
class NO_VTABLE CRefCounted1 : public BASE1,
public REFCOUNT_SERVICE
{
public:
virtual ~CRefCounted1() {}
int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
int Release() { return REFCOUNT_SERVICE::DoRelease(); }
};
//-------------------------------------
template < class BASE1, class BASE2, class REFCOUNT_SERVICE = CRefCountService >
class NO_VTABLE CRefCounted2 : public BASE1, public BASE2,
public REFCOUNT_SERVICE
{
public:
virtual ~CRefCounted2() {}
int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
int Release() { return REFCOUNT_SERVICE::DoRelease(); }
};
//-------------------------------------
template < class BASE1, class BASE2, class BASE3, class REFCOUNT_SERVICE = CRefCountService >
class NO_VTABLE CRefCounted3 : public BASE1, public BASE2, public BASE3,
public REFCOUNT_SERVICE
{
virtual ~CRefCounted3() {}
int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
int Release() { return REFCOUNT_SERVICE::DoRelease(); }
};
//-------------------------------------
template < class BASE1, class BASE2, class BASE3, class BASE4, class REFCOUNT_SERVICE = CRefCountService >
class NO_VTABLE CRefCounted4 : public BASE1, public BASE2, public BASE3, public BASE4,
public REFCOUNT_SERVICE
{
public:
virtual ~CRefCounted4() {}
int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
int Release() { return REFCOUNT_SERVICE::DoRelease(); }
};
//-------------------------------------
template < class BASE1, class BASE2, class BASE3, class BASE4, class BASE5, class REFCOUNT_SERVICE = CRefCountService >
class NO_VTABLE CRefCounted5 : public BASE1, public BASE2, public BASE3, public BASE4, public BASE5,
public REFCOUNT_SERVICE
{
public:
virtual ~CRefCounted5() {}
int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
int Release() { return REFCOUNT_SERVICE::DoRelease(); }
};
//-----------------------------------------------------------------------------
// Purpose: Class to throw around a reference counted item to debug
// referencing problems
//-----------------------------------------------------------------------------
#if defined( __clang__ )
template <class BASE_REFCOUNTED, int FINAL_REFS, const char *pszName>
#else
template <class BASE_REFCOUNTED, int FINAL_REFS = 0, const char *pszName = (const char *)NULL>
#endif
class CRefDebug : public BASE_REFCOUNTED
{
public:
#ifdef _DEBUG
CRefDebug()
{
AssertMsg( this->GetRefCount() == 1, "Expected initial ref count of 1" );
DevMsg( "%s:create 0x%x\n", ( pszName ) ? pszName : "", this );
}
virtual ~CRefDebug()
{
AssertDevMsg( this->GetRefCount() == FINAL_REFS, "Object still referenced on destroy?" );
DevMsg( "%s:destroy 0x%x\n", ( pszName ) ? pszName : "", this );
}
int AddRef()
{
DevMsg( "%s:(0x%x)->AddRef() --> %d\n", ( pszName ) ? pszName : "", this, this->GetRefCount() + 1 );
return BASE_REFCOUNTED::AddRef();
}
int Release()
{
DevMsg( "%s:(0x%x)->Release() --> %d\n", ( pszName ) ? pszName : "", this, this->GetRefCount() - 1 );
Assert( this->GetRefCount() > 0 );
return BASE_REFCOUNTED::Release();
}
#endif
};
//-----------------------------------------------------------------------------
#endif // REFCOUNT_H

279
public/tier1/smartptr.h Normal file
View File

@@ -0,0 +1,279 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef SMARTPTR_H
#define SMARTPTR_H
#ifdef _WIN32
#pragma once
#endif
class CRefCountAccessor
{
public:
template< class T >
static void AddRef( T *pObj )
{
pObj->AddRef();
}
template< class T >
static void Release( T *pObj )
{
pObj->Release();
}
};
// This can be used if your objects use AddReference/ReleaseReference function names.
class CRefCountAccessorLongName
{
public:
template< class T >
static void AddRef( T *pObj )
{
pObj->AddReference();
}
template< class T >
static void Release( T *pObj )
{
pObj->ReleaseReference();
}
};
//
// CPlainAutoPtr
// is a smart wrapper for a pointer on the stack that performs "delete" upon destruction.
//
// No reference counting is performed, copying is prohibited "s_p2.Attach( s_p1.Detach() )" should be used
// for readability and ease of maintenance.
//
// Auto pointer supports an "arrow" operator for invoking methods on the pointee and a "dereference" operator
// for getting a pointee reference.
//
// No automatic casting to bool/ptrtype is performed to avoid bugs and problems (read on "safe bool idiom"
// if casting to bool or pointer happens to be useful).
//
// Test for validity with "IsValid", get the pointer with "Get".
//
template < typename T >
class CPlainAutoPtr
{
public:
explicit CPlainAutoPtr( T *p = NULL ) : m_p( p ) {}
~CPlainAutoPtr( void ) { Delete(); }
public:
void Delete( void ) { delete Detach(); }
private: // Disallow copying, use Detach() instead to avoid ambiguity
CPlainAutoPtr( CPlainAutoPtr const &x );
CPlainAutoPtr & operator = ( CPlainAutoPtr const &x );
public:
void Attach( T *p ) { m_p = p; }
T * Detach( void ) { T * p( m_p ); m_p = NULL; return p; }
public:
bool IsValid( void ) const { return m_p != NULL; }
T * Get( void ) const { return m_p; }
T * operator -> ( void ) const { return Get(); }
T & operator * ( void ) const { return *Get(); }
private:
T * m_p;
};
//
// CArrayAutoPtr
// is a smart wrapper for an array pointer on the stack that performs "delete []" upon destruction.
//
// No reference counting is performed, copying is prohibited "s_p2.Attach( s_p1.Detach() )" should be used
// for readability and ease of maintenance.
//
// Auto pointer supports an "indexing" operator for accessing array elements.
//
// No automatic casting to bool/ptrtype is performed to avoid bugs and problems (read on "safe bool idiom"
// if casting to bool or pointer happens to be useful).
//
// Test for validity with "IsValid", get the array pointer with "Get".
//
template < typename T >
class CArrayAutoPtr : public CPlainAutoPtr < T > // Warning: no polymorphic destructor (delete on base class will be a mistake)
{
public:
explicit CArrayAutoPtr( T *p = NULL ) { this->Attach( p ); }
~CArrayAutoPtr( void ) { Delete(); }
public:
void Delete( void ) { delete [] this->Detach(); }
public:
T & operator [] ( int k ) const { return this->Get()[ k ]; }
};
// Smart pointers can be used to automatically free an object when nobody points
// at it anymore. Things contained in smart pointers must implement AddRef and Release
// functions. If those functions are private, then the class must make
// CRefCountAccessor a friend.
template<class T, class RefCountAccessor=CRefCountAccessor>
class CSmartPtr
{
public:
CSmartPtr();
CSmartPtr( T *pObj );
CSmartPtr( const CSmartPtr<T,RefCountAccessor> &other );
~CSmartPtr();
T* operator=( T *pObj );
void operator=( const CSmartPtr<T,RefCountAccessor> &other );
const T* operator->() const;
T* operator->();
bool operator!() const;
bool operator==( const T *pOther ) const;
bool IsValid() const; // Tells if the pointer is valid.
T* GetObject() const; // Get temporary object pointer, don't store it for later reuse!
void MarkDeleted();
private:
T *m_pObj;
};
template< class T, class RefCountAccessor >
inline CSmartPtr<T,RefCountAccessor>::CSmartPtr()
{
m_pObj = NULL;
}
template< class T, class RefCountAccessor >
inline CSmartPtr<T,RefCountAccessor>::CSmartPtr( T *pObj )
{
m_pObj = NULL;
*this = pObj;
}
template< class T, class RefCountAccessor >
inline CSmartPtr<T,RefCountAccessor>::CSmartPtr( const CSmartPtr<T,RefCountAccessor> &other )
{
m_pObj = NULL;
*this = other;
}
template< class T, class RefCountAccessor >
inline CSmartPtr<T,RefCountAccessor>::~CSmartPtr()
{
if ( m_pObj )
{
RefCountAccessor::Release( m_pObj );
}
}
template< class T, class RefCountAccessor >
inline T* CSmartPtr<T,RefCountAccessor>::operator=( T *pObj )
{
if ( pObj == m_pObj )
return pObj;
if ( pObj )
{
RefCountAccessor::AddRef( pObj );
}
if ( m_pObj )
{
RefCountAccessor::Release( m_pObj );
}
m_pObj = pObj;
return pObj;
}
template< class T, class RefCountAccessor >
inline void CSmartPtr<T,RefCountAccessor>::MarkDeleted()
{
m_pObj = NULL;
}
template< class T, class RefCountAccessor >
inline void CSmartPtr<T,RefCountAccessor>::operator=( const CSmartPtr<T,RefCountAccessor> &other )
{
*this = other.m_pObj;
}
template< class T, class RefCountAccessor >
inline const T* CSmartPtr<T,RefCountAccessor>::operator->() const
{
return m_pObj;
}
template< class T, class RefCountAccessor >
inline T* CSmartPtr<T,RefCountAccessor>::operator->()
{
return m_pObj;
}
template< class T, class RefCountAccessor >
inline bool CSmartPtr<T,RefCountAccessor>::operator!() const
{
return !m_pObj;
}
template< class T, class RefCountAccessor >
inline bool CSmartPtr<T,RefCountAccessor>::operator==( const T *pOther ) const
{
return m_pObj == pOther;
}
template< class T, class RefCountAccessor >
inline bool CSmartPtr<T,RefCountAccessor>::IsValid() const
{
return m_pObj != NULL;
}
template< class T, class RefCountAccessor >
inline T* CSmartPtr<T,RefCountAccessor>::GetObject() const
{
return m_pObj;
}
//
// CAutoPushPop
// allows you to set value of a variable upon construction and destruction.
// Constructors:
// CAutoPushPop x( myvar )
// saves the value and restores upon destruction.
// CAutoPushPop x( myvar, newvalue )
// saves the value, assigns new value upon construction, restores saved value upon destruction.
// CAutoPushPop x( myvar, newvalue, restorevalue )
// assigns new value upon construction, assignes restorevalue upon destruction.
//
template < typename T >
class CAutoPushPop
{
public:
explicit CAutoPushPop( T& var ) : m_rVar( var ), m_valPop( var ) {}
CAutoPushPop( T& var, T const &valPush ) : m_rVar( var ), m_valPop( var ) { m_rVar = valPush; }
CAutoPushPop( T& var, T const &valPush, T const &valPop ) : m_rVar( var ), m_valPop( var ) { m_rVar = valPush; }
~CAutoPushPop() { m_rVar = m_valPop; }
private: // forbid copying
CAutoPushPop( CAutoPushPop const &x );
CAutoPushPop & operator = ( CAutoPushPop const &x );
public:
T & Get() { return m_rVar; }
private:
T &m_rVar;
T m_valPop;
};
#endif // SMARTPTR_H

123
public/tier1/sparsematrix.h Normal file
View File

@@ -0,0 +1,123 @@
//===== Copyright <20> 1996-2011, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// A class allowing storage of a sparse NxN matirx as an array of sparse rows
//===========================================================================//
#ifndef SPARSEMATRIX_H
#define SPARSEMATRIX_H
#include "tier1/utlvector.h"
/// CSparseMatrix is a matrix which compresses each row individually, not storing the zeros. NOte,
/// that while you can randomly set any element in a CSparseMatrix, you really want to do it top to
/// bottom or you will have bad perf as data is moved around to insert new elements.
class CSparseMatrix
{
public:
struct NonZeroValueDescriptor_t
{
int m_nColumnNumber;
float m_flValue;
};
struct RowDescriptor_t
{
int m_nNonZeroCount; // number of non-zero elements in the row
int m_nDataIndex; // index of NonZeroValueDescriptor_t for the first non-zero value
};
int m_nNumRows;
int m_nNumCols;
CUtlVector<RowDescriptor_t> m_rowDescriptors;
CUtlVector<NonZeroValueDescriptor_t> m_entries;
int m_nHighestRowAppendedTo;
void AdjustAllRowIndicesAfter( int nStartRow, int nDelta );
public:
FORCEINLINE float Element( int nRow, int nCol ) const;
void SetElement( int nRow, int nCol, float flValue );
void SetDimensions( int nNumRows, int nNumCols );
void AppendElement( int nRow, int nCol, float flValue );
void FinishedAppending( void );
FORCEINLINE int Height( void ) const { return m_nNumRows; }
FORCEINLINE int Width( void ) const { return m_nNumCols; }
};
FORCEINLINE float CSparseMatrix::Element( int nRow, int nCol ) const
{
Assert( nCol < m_nNumCols );
int nCount = m_rowDescriptors[nRow].m_nNonZeroCount;
if ( nCount )
{
NonZeroValueDescriptor_t const *pValue = &(m_entries[m_rowDescriptors[nRow].m_nDataIndex]);
do
{
int nIdx = pValue->m_nColumnNumber;
if ( nIdx == nCol )
{
return pValue->m_flValue;
}
if ( nIdx > nCol )
{
break;
}
pValue++;
} while( --nCount );
}
return 0;
}
// type-specific overrides of matrixmath template for special case sparse routines
namespace MatrixMath
{
/// sparse * dense matrix x matrix multiplication
template<class BTYPE, class OUTTYPE>
void MatrixMultiply( CSparseMatrix const &matA, BTYPE const &matB, OUTTYPE *pMatrixOut )
{
Assert( matA.Width() == matB.Height() );
pMatrixOut->SetDimensions( matA.Height(), matB.Width() );
for( int i = 0; i < matA.Height(); i++ )
{
for( int j = 0; j < matB.Width(); j++ )
{
// compute inner product efficiently because of sparsity
int nCnt = matA.m_rowDescriptors[i].m_nNonZeroCount;
int nDataIdx = matA.m_rowDescriptors[i].m_nDataIndex;
float flDot = 0.0;
for( int nIdx = 0; nIdx < nCnt; nIdx++ )
{
float flAValue = matA.m_entries[nIdx + nDataIdx].m_flValue;
int nCol = matA.m_entries[nIdx + nDataIdx].m_nColumnNumber;
flDot += flAValue * matB.Element( nCol, j );
}
pMatrixOut->SetElement( i, j, flDot );
}
}
}
FORCEINLINE void AppendElement( CSparseMatrix &matrix, int nRow, int nCol, float flValue )
{
matrix.AppendElement( nRow, nCol, flValue ); // default implementation
}
FORCEINLINE void FinishedAppending( CSparseMatrix &matrix )
{
matrix.FinishedAppending();
}
};
#endif // SPARSEMATRIX_H

511
public/tier1/stringpool.h Normal file
View File

@@ -0,0 +1,511 @@
//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef STRINGPOOL_H
#define STRINGPOOL_H
#if defined( _WIN32 )
#pragma once
#endif
#include "utlrbtree.h"
#include "utlvector.h"
#include "utlbuffer.h"
#include "generichash.h"
//-----------------------------------------------------------------------------
// Purpose: Allocates memory for strings, checking for duplicates first,
// reusing exising strings if duplicate found.
//-----------------------------------------------------------------------------
enum StringPoolCase_t
{
StringPoolCaseInsensitive,
StringPoolCaseSensitive
};
class CStringPool
{
public:
CStringPool( StringPoolCase_t caseSensitivity = StringPoolCaseInsensitive );
~CStringPool();
unsigned int Count() const;
const char * Allocate( const char *pszValue );
// This feature is deliberately not supported because it's pretty dangerous
// given current uses of CStringPool, which assume they can copy string pointers without
// any refcounts.
//void Free( const char *pszValue );
void FreeAll();
// searches for a string already in the pool
const char * Find( const char *pszValue );
protected:
typedef CUtlRBTree<const char *, unsigned short> CStrSet;
CStrSet m_Strings;
};
//-----------------------------------------------------------------------------
// Purpose: A reference counted string pool.
//
// Elements are stored more efficiently than in the conventional string pool,
// quicker to look up, and storage is tracked via reference counts.
//
// At some point this should replace CStringPool
//-----------------------------------------------------------------------------
template<class T>
class CCountedStringPoolBase
{
public: // HACK, hash_item_t structure should not be public.
struct hash_item_t
{
char* pString;
T nNextElement;
unsigned char nReferenceCount;
unsigned char pad;
};
enum
{
INVALID_ELEMENT = 0,
MAX_REFERENCE = 0xFF,
HASH_TABLE_SIZE = 1024
};
CUtlVector<T> m_HashTable; // Points to each element
CUtlVector<hash_item_t> m_Elements;
T m_FreeListStart;
StringPoolCase_t m_caseSensitivity;
public:
CCountedStringPoolBase( StringPoolCase_t caseSensitivity = StringPoolCaseInsensitive );
virtual ~CCountedStringPoolBase();
void FreeAll();
char *FindString( const char* pIntrinsic );
char *ReferenceString( const char* pIntrinsic );
void DereferenceString( const char* pIntrinsic );
// These are only reliable if there are less than 64k strings in your string pool
T FindStringHandle( const char* pIntrinsic );
T ReferenceStringHandle( const char* pIntrinsic );
char *HandleToString( T handle );
void SpewStrings();
unsigned Hash( const char *pszKey );
bool SaveToBuffer( CUtlBuffer &buffer );
bool RestoreFromBuffer( CUtlBuffer &buffer );
// Debug helper method to validate that we didn't overflow
void VerifyNotOverflowed( unsigned int value );
};
typedef CCountedStringPoolBase<unsigned short> CCountedStringPool;
template<class T>
inline CCountedStringPoolBase<T>::CCountedStringPoolBase( StringPoolCase_t caseSensitivity )
{
MEM_ALLOC_CREDIT();
m_HashTable.EnsureCount(HASH_TABLE_SIZE);
for( int i = 0; i < m_HashTable.Count(); i++ )
{
m_HashTable[i] = INVALID_ELEMENT;
}
m_FreeListStart = INVALID_ELEMENT;
m_Elements.AddToTail();
m_Elements[0].pString = NULL;
m_Elements[0].nReferenceCount = 0;
m_Elements[0].nNextElement = INVALID_ELEMENT;
m_caseSensitivity = caseSensitivity;
}
template<class T>
inline CCountedStringPoolBase<T>::~CCountedStringPoolBase()
{
FreeAll();
}
template<class T>
inline void CCountedStringPoolBase<T>::FreeAll()
{
int i;
// Reset the hash table:
for( i = 0; i < m_HashTable.Count(); i++ )
{
m_HashTable[i] = INVALID_ELEMENT;
}
// Blow away the free list:
m_FreeListStart = INVALID_ELEMENT;
for( i = 0; i < m_Elements.Count(); i++ )
{
if( m_Elements[i].pString )
{
delete [] m_Elements[i].pString;
m_Elements[i].pString = NULL;
m_Elements[i].nReferenceCount = 0;
m_Elements[i].nNextElement = INVALID_ELEMENT;
}
}
// Remove all but the invalid element:
m_Elements.RemoveAll();
m_Elements.AddToTail();
m_Elements[0].pString = NULL;
m_Elements[0].nReferenceCount = 0;
m_Elements[0].nNextElement = INVALID_ELEMENT;
}
template<class T>
inline unsigned CCountedStringPoolBase<T>::Hash( const char *pszKey )
{
if ( m_caseSensitivity == StringPoolCaseInsensitive )
{
return HashStringCaseless( pszKey );
}
return HashString( pszKey );
}
template<class T>
inline T CCountedStringPoolBase<T>::FindStringHandle( const char* pIntrinsic )
{
if( pIntrinsic == NULL )
return INVALID_ELEMENT;
T nHashBucketIndex = ( Hash( pIntrinsic ) %HASH_TABLE_SIZE);
T nCurrentBucket = m_HashTable[ nHashBucketIndex ];
// Does the bucket already exist?
if( nCurrentBucket != INVALID_ELEMENT )
{
for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
{
if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
{
return nCurrentBucket;
}
}
}
return 0;
}
template<class T>
inline char* CCountedStringPoolBase<T>::FindString( const char* pIntrinsic )
{
if( pIntrinsic == NULL )
return NULL;
// Yes, this will be NULL on failure.
return m_Elements[FindStringHandle(pIntrinsic)].pString;
}
template<class T>
inline T CCountedStringPoolBase<T>::ReferenceStringHandle( const char* pIntrinsic )
{
if( pIntrinsic == NULL )
return INVALID_ELEMENT;
T nHashBucketIndex = ( Hash( pIntrinsic ) % HASH_TABLE_SIZE);
T nCurrentBucket = m_HashTable[ nHashBucketIndex ];
// Does the bucket already exist?
if( nCurrentBucket != INVALID_ELEMENT )
{
for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
{
if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
{
// Anyone who hits 65k references is permanant
if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE )
{
m_Elements[nCurrentBucket].nReferenceCount ++ ;
}
return nCurrentBucket;
}
}
}
if( m_FreeListStart != INVALID_ELEMENT )
{
nCurrentBucket = m_FreeListStart;
m_FreeListStart = m_Elements[nCurrentBucket].nNextElement;
}
else
{
unsigned int newElement = m_Elements.AddToTail();
VerifyNotOverflowed( newElement );
nCurrentBucket = newElement;
}
m_Elements[nCurrentBucket].nReferenceCount = 1;
// Insert at the beginning of the bucket:
m_Elements[nCurrentBucket].nNextElement = m_HashTable[ nHashBucketIndex ];
m_HashTable[ nHashBucketIndex ] = nCurrentBucket;
m_Elements[nCurrentBucket].pString = new char[Q_strlen( pIntrinsic ) + 1];
Q_strcpy( m_Elements[nCurrentBucket].pString, pIntrinsic );
return nCurrentBucket;
}
template<>
inline void CCountedStringPoolBase<unsigned short>::VerifyNotOverflowed( unsigned int value ) { Assert( value < 0xffff ); }
template<>
inline void CCountedStringPoolBase<unsigned int>::VerifyNotOverflowed( unsigned int value ) {}
template<class T>
inline char* CCountedStringPoolBase<T>::ReferenceString( const char* pIntrinsic )
{
if(!pIntrinsic)
return NULL;
return m_Elements[ReferenceStringHandle( pIntrinsic)].pString;
}
template<class T>
inline void CCountedStringPoolBase<T>::DereferenceString( const char* pIntrinsic )
{
// If we get a NULL pointer, just return
if (!pIntrinsic)
return;
T nHashBucketIndex = (Hash( pIntrinsic ) % m_HashTable.Count());
T nCurrentBucket = m_HashTable[ nHashBucketIndex ];
// If there isn't anything in the bucket, just return.
if ( nCurrentBucket == INVALID_ELEMENT )
return;
for( T previous = INVALID_ELEMENT; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
{
if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
{
// Anyone who hits 65k references is permanant
if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE )
{
m_Elements[nCurrentBucket].nReferenceCount --;
}
if( m_Elements[nCurrentBucket].nReferenceCount == 0 )
{
if( previous == INVALID_ELEMENT )
{
m_HashTable[nHashBucketIndex] = m_Elements[nCurrentBucket].nNextElement;
}
else
{
m_Elements[previous].nNextElement = m_Elements[nCurrentBucket].nNextElement;
}
delete [] m_Elements[nCurrentBucket].pString;
m_Elements[nCurrentBucket].pString = NULL;
m_Elements[nCurrentBucket].nReferenceCount = 0;
m_Elements[nCurrentBucket].nNextElement = m_FreeListStart;
m_FreeListStart = nCurrentBucket;
break;
}
}
previous = nCurrentBucket;
}
}
template<class T>
inline char* CCountedStringPoolBase<T>::HandleToString( T handle )
{
return m_Elements[handle].pString;
}
template<class T>
inline void CCountedStringPoolBase<T>::SpewStrings()
{
int i;
for ( i = 0; i < m_Elements.Count(); i++ )
{
char* string = m_Elements[i].pString;
Msg("String %d: ref:%d %s\n", i, m_Elements[i].nReferenceCount, string == NULL? "EMPTY - ok for slot zero only!" : string);
}
Msg("\n%d total counted strings.", m_Elements.Count());
}
#define STRING_POOL_VERSION MAKEID( 'C', 'S', 'P', '1' )
#define MAX_STRING_SAVE 1024
template<>
inline bool CCountedStringPoolBase<unsigned short>::SaveToBuffer( CUtlBuffer &buffer )
{
if ( m_Elements.Count() <= 1 )
{
// pool is empty, saving nothing
// caller can check put position of buffer to detect
return true;
}
// signature/version
buffer.PutInt( STRING_POOL_VERSION );
buffer.PutUnsignedShort( m_FreeListStart );
buffer.PutInt( m_HashTable.Count() );
for ( int i = 0; i < m_HashTable.Count(); i++ )
{
buffer.PutUnsignedShort( m_HashTable[i] );
}
buffer.PutInt( m_Elements.Count() );
for ( int i = 1; i < m_Elements.Count(); i++ )
{
buffer.PutUnsignedShort( m_Elements[i].nNextElement );
buffer.PutUnsignedChar( m_Elements[i].nReferenceCount );
const char *pString = m_Elements[i].pString;
if ( strlen( pString ) >= MAX_STRING_SAVE )
{
return false;
}
buffer.PutString( pString ? pString : "" );
}
return buffer.IsValid();
}
template<>
inline bool CCountedStringPoolBase<unsigned short>::RestoreFromBuffer( CUtlBuffer &buffer )
{
int signature = buffer.GetInt();
if ( signature != STRING_POOL_VERSION )
{
// wrong version
return false;
}
FreeAll();
m_FreeListStart = buffer.GetUnsignedShort();
int hashCount = buffer.GetInt();
m_HashTable.SetCount( hashCount );
for ( int i = 0; i < hashCount; i++ )
{
m_HashTable[i] = buffer.GetUnsignedShort();
}
int tableCount = buffer.GetInt();
if ( tableCount > 1 )
{
m_Elements.AddMultipleToTail( tableCount-1 );
}
char tempString[MAX_STRING_SAVE];
for ( int i = 1; i < tableCount; i++ )
{
m_Elements[i].nNextElement = buffer.GetUnsignedShort();
m_Elements[i].nReferenceCount = buffer.GetUnsignedChar();
buffer.GetString( tempString, sizeof( tempString ) );
m_Elements[i].pString = strdup( tempString );
}
return buffer.IsValid();
}
template<>
inline bool CCountedStringPoolBase<unsigned int>::SaveToBuffer( CUtlBuffer &buffer )
{
if ( m_Elements.Count() <= 1 )
{
// pool is empty, saving nothing
// caller can check put position of buffer to detect
return true;
}
// signature/version
buffer.PutInt( STRING_POOL_VERSION );
buffer.PutUnsignedInt( m_FreeListStart );
buffer.PutInt( m_HashTable.Count() );
for ( int i = 0; i < m_HashTable.Count(); i++ )
{
buffer.PutUnsignedInt( m_HashTable[i] );
}
buffer.PutInt( m_Elements.Count() );
for ( int i = 1; i < m_Elements.Count(); i++ )
{
buffer.PutUnsignedInt( m_Elements[i].nNextElement );
buffer.PutUnsignedChar( m_Elements[i].nReferenceCount );
const char *pString = m_Elements[i].pString;
if ( strlen( pString ) >= MAX_STRING_SAVE )
{
return false;
}
buffer.PutString( pString ? pString : "" );
}
return buffer.IsValid();
}
template<>
inline bool CCountedStringPoolBase<unsigned int>::RestoreFromBuffer( CUtlBuffer &buffer )
{
int signature = buffer.GetInt();
if ( signature != STRING_POOL_VERSION )
{
// wrong version
return false;
}
FreeAll();
m_FreeListStart = buffer.GetUnsignedInt();
int hashCount = buffer.GetInt();
m_HashTable.SetCount( hashCount );
for ( int i = 0; i < hashCount; i++ )
{
m_HashTable[i] = buffer.GetUnsignedInt();
}
int tableCount = buffer.GetInt();
if ( tableCount > 1 )
{
m_Elements.AddMultipleToTail( tableCount-1 );
}
char tempString[MAX_STRING_SAVE];
for ( int i = 1; i < tableCount; i++ )
{
m_Elements[i].nNextElement = buffer.GetUnsignedInt();
m_Elements[i].nReferenceCount = buffer.GetUnsignedChar();
buffer.GetString( tempString, sizeof( tempString ) );
m_Elements[i].pString = strdup( tempString );
}
return buffer.IsValid();
}
#endif // STRINGPOOL_H

1483
public/tier1/strtools.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,106 @@
#ifndef TIER1_STRTOOLS_INLINES_H
#define TIER1_STRTOOLS_INLINES_H
inline int _V_strlen_inline( const char *str )
{
#ifdef POSIX
if ( !str )
return 0;
#endif
return strlen( str );
}
inline char *_V_strrchr_inline( const char *s, char c )
{
int len = _V_strlen_inline(s);
s += len;
while (len--)
if (*--s == c) return (char *)s;
return 0;
}
inline int _V_wcscmp_inline( const wchar_t *s1, const wchar_t *s2 )
{
while (1)
{
if (*s1 != *s2)
return -1; // strings not equal
if (!*s1)
return 0; // strings are equal
s1++;
s2++;
}
return -1;
}
#define STRTOOLS_TOLOWERC( x ) (( ( x >= 'A' ) && ( x <= 'Z' ) )?( x + 32 ) : x )
inline int _V_stricmp_inline( const char *s1, const char *s2 )
{
#ifdef POSIX
if ( s1 == NULL && s2 == NULL )
return 0;
if ( s1 == NULL )
return -1;
if ( s2 == NULL )
return 1;
return stricmp( s1, s2 );
#else
// THIS BLOCK ISN'T USED ON THE PS3 SINCE IT IS POSIX!!! Would be a code bloat concern otherwise.
uint8 const *pS1 = ( uint8 const * ) s1;
uint8 const *pS2 = ( uint8 const * ) s2;
for(;;)
{
int c1 = *( pS1++ );
int c2 = *( pS2++ );
if ( c1 == c2 )
{
if ( !c1 ) return 0;
}
else
{
if ( ! c2 )
{
return c1 - c2;
}
c1 = TOLOWERC( c1 );
c2 = TOLOWERC( c2 );
if ( c1 != c2 )
{
return c1 - c2;
}
}
c1 = *( pS1++ );
c2 = *( pS2++ );
if ( c1 == c2 )
{
if ( !c1 ) return 0;
}
else
{
if ( ! c2 )
{
return c1 - c2;
}
c1 = STRTOOLS_TOLOWERC( c1 );
c2 = STRTOOLS_TOLOWERC( c2 );
if ( c1 != c2 )
{
return c1 - c2;
}
}
}
#endif
}
inline char *_V_strstr_inline( const char *s1, const char *search )
{
#if defined( _X360 )
return (char *)strstr( (char *)s1, search );
#else
return (char *)strstr( s1, search );
#endif
}
#endif // TIER1_STRTOOLS_INLINES_H

698
public/tier1/thash.h Normal file
View File

@@ -0,0 +1,698 @@
//========= Copyright 1996-2004, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#ifndef THASH_H
#define THASH_H
#ifdef _WIN32
#pragma once
#endif
#include <typeinfo>
//#define DBGFLAG_THASH // Perform extra sanity checks on the THash
// THash
// This is a heavyweight, templatized version of DHash.
// It differs from DHash in the following ways:
// - It's templetized, and automatically constructs and destructs its records as appropriate
// - It provides a scheduling service, which can be used to touch every record in the table
// at a specified interval. The scheduler is low-overhead, and provides a very smooth
// distribution of touches across frames.
// Template arguments:
// Data: the class to be stored in the hash table
// I: the type of the primary key (uint32 by default)
template<class Data, typename I=uint32>
class CTHash
{
private:
// RecHdr
// We insert one of these at the beginning of every record. It's used for
// keeping the records in a linked list.
typedef struct RecHdr_t
{
RecHdr_t *m_pRecHdrNext; // Next item in our linked list
RecHdr_t *m_pRecHdrPrev; // Previous item in our linked list
I m_unKey; // Key of this item
int m_iBucket; // The bucket we're in
int m_nRunRatio; // We want to run 1 cycle out of every m_nRunRatio
// cycles (not at all if 0).
#ifdef DBGFLAG_THASH
uint m_iCycleLast; // Last cycle we were visited (whether or not we ran)
#endif
} RecHdr_t;
// Bucket
// Each hash bucket is represented by a Bucket structure, which points to the
// first record with the bucket's hash.
typedef struct Bucket_t
{
RecHdr_t *m_pRecHdrFirst; // First record in our list
} Bucket_t;
public:
// Constructors & destructors
CTHash( int cFramesPerCycle );
~CTHash();
// Initializer
void Init( int cRecordInit, int cBuckets );
// Insert a record into the table
Data *PvRecordInsert( I unKey );
// Insert a record into the table and set the allocated object's pointer as the hash key
Data *PvRecordInsertAutoKey();
// Changes the key for a previously inserted item
void ChangeKey( Data * pvRecord, I unOldKey, I unNewKey );
// Remove a record
void Remove( I unKey );
// Remove a record
void Remove( Data * pvRecord );
// Remove all records
void RemoveAll();
// Find a record
Data *PvRecordFind( I unKey ) const;
// How many records do we have
int Count() const { return m_cRecordInUse; }
// Iterate through our members
Data *PvRecordFirst() const;
Data *PvRecordNext( Data *pvRecordCur ) const;
// We provide a scheduling service. Call StartFrameSchedule when you want to start running
// records in a given frame, and repeatedly call PvRecordRun until it returns NULL (or you
// run our of time).
void SetRunRatio( Data *pvRecord, int nRunRatio );
void SetMicroSecPerCycle( int cMicroSecPerCycle, int cMicroSecPerFrame ) { m_cFramesPerCycle = cMicroSecPerCycle / cMicroSecPerFrame; }
void StartFrameSchedule( bool bNewFrame );
Data *PvRecordRun();
bool BCompletedPass();
#ifdef DBGFLAG_VALIDATE
virtual void Validate( CValidator &validator, const char *pchName );
#endif // DBGFLAG_VALIDATE
private:
// Insert a record into the table
Data *PvRecordInsertInternal( RecHdr_t *pRecHdr, I unKey );
// Get the record associated with a THashHdr
Data *PvRecordFromPRecHdr( RecHdr_t *pRecHdr ) const { return ( Data * ) ( ( ( uint8 * ) pRecHdr + sizeof( RecHdr_t ) ) ); }
// Get the RecHdr preceding a PvRecord
RecHdr_t *PRecHdrFromPvRecord( Data *pvRecord ) const { return ( ( ( RecHdr_t * ) pvRecord ) - 1 ); }
// Get the hash bucket corresponding to a key
int IBucket( I unKey ) const;
void InsertIntoHash( RecHdr_t *pRecHdr, I unKey );
void RemoveFromHash( Data * pvRecord );
int m_cBucket; // # of hash buckets we have
Bucket_t *m_pBucket; // Big array of hash buckets
CUtlMemoryPool *m_pMemoryPoolRecord; // All our data records
int m_cRecordInUse; // # of records in use
RecHdr_t m_RecHdrHead; // Head of our linked list
RecHdr_t m_RecHdrTail; // Tail of our linked list
int m_cFramesPerCycle; // Run each of our records once every m_cFramesPerCycle frames
RecHdr_t *m_pRecHdrRunNext; // Next record to run (be careful-- this is more complicated than it sounds)
int m_iBucketRunMax; // Stop running when we get to this bucket
uint m_iCycleCur; // Current cycle (ie, how many times we've made a complete scheduler pass)
uint m_iCycleLast; // Our previous cycle
uint m_iFrameCur; // Our current frame (incremented once each StartFrameSchedule)
uint m_iCycleLastReported; // Last cycle checked by BCompletedPass()
};
//-----------------------------------------------------------------------------
// Purpose: Constructor
// Input: cMicroSecRunInterval - How often we want the scheduler to run each of our records
//-----------------------------------------------------------------------------
template<class Data, class I>
CTHash<Data,I>::CTHash( int cFramesPerCycle )
{
m_cBucket = 0;
m_pBucket = NULL;
m_pMemoryPoolRecord = NULL;
m_cRecordInUse = 0;
m_cFramesPerCycle = cFramesPerCycle;
m_pRecHdrRunNext = &m_RecHdrTail; // This will make us start at the beginning on our first frame
m_iBucketRunMax = 0;
m_iCycleCur = 0;
m_iCycleLast = 0;
m_iFrameCur = 0;
m_iCycleLastReported = 0;
m_RecHdrHead.m_pRecHdrPrev = NULL;
m_RecHdrHead.m_pRecHdrNext = &m_RecHdrTail;
m_RecHdrHead.m_iBucket = -1;
m_RecHdrTail.m_pRecHdrPrev = &m_RecHdrHead;
m_RecHdrTail.m_pRecHdrNext = NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
template<class Data, class I>
CTHash<Data,I>::~CTHash()
{
RemoveAll();
if ( NULL != m_pBucket )
FreePv( m_pBucket );
m_pBucket = NULL;
if ( NULL != m_pMemoryPoolRecord )
delete( m_pMemoryPoolRecord );
m_pMemoryPoolRecord = NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Initializer. Allocate our various arrays, and set up the free
// list.
// Input: cRecordInit - Initial # of data records we can contain
// cBucket - # of hash buckets we should use
//-----------------------------------------------------------------------------
template<class Data, class I>
void CTHash<Data,I>::Init( int cRecordInit, int cBucket )
{
Assert( cRecordInit > 0 ); // need to init with non-zero value or memory pool will never grow
// Copy our parameters
m_cBucket = cBucket;
// Alloc our arrays
m_pBucket = ( Bucket_t * ) PvAlloc( sizeof( Bucket_t ) * m_cBucket );
m_pMemoryPoolRecord = new CUtlMemoryPool( sizeof( Data ) + sizeof( RecHdr_t ), cRecordInit,
CUtlMemoryPool::GROW_SLOW );
// Init the hash buckets
for ( int iBucket = 0; iBucket < m_cBucket; iBucket++ )
m_pBucket[iBucket].m_pRecHdrFirst = NULL;
// Make the tail have an illegally large bucket
m_RecHdrTail.m_iBucket = m_cBucket + 1;
}
//-----------------------------------------------------------------------------
// Purpose: Inserts a new record into the table
// Input: unKey - Primary key of the new record
// Output: Pointer to the new record
//-----------------------------------------------------------------------------
template<class Data, class I>
Data *CTHash<Data,I>::PvRecordInsert( I unKey )
{
Assert( PvRecordFind( unKey ) == NULL ); // keys are unique; no record with this key may exist
// Find a free record
RecHdr_t *pRecHdr = ( RecHdr_t * ) m_pMemoryPoolRecord->Alloc();
return PvRecordInsertInternal( pRecHdr, unKey );
}
//-----------------------------------------------------------------------------
// Purpose: Inserts a new record into the table and sets its key to the pointer
// value of the record
// Output: Pointer to the new record
//-----------------------------------------------------------------------------
template<class Data, class I>
Data *CTHash<Data,I>::PvRecordInsertAutoKey()
{
// Find a free record
RecHdr_t *pRecHdr = ( RecHdr_t * ) m_pMemoryPoolRecord->Alloc();
return PvRecordInsertInternal( pRecHdr, (I) PvRecordFromPRecHdr( pRecHdr ) );
}
//-----------------------------------------------------------------------------
// Purpose: Inserts an allocated record into the hash table with specified key
// and calls the constructor of the allocated object
// Input: pRecHdr - record to insert
// unKey - hash key to use for record
// Output: Pointer to the new record
//-----------------------------------------------------------------------------
template<class Data, class I>
Data *CTHash<Data,I>::PvRecordInsertInternal( RecHdr_t *pRecHdr, I unKey )
{
InsertIntoHash( pRecHdr, unKey );
// assert that we don't have too many items per bucket
static bool s_bPerfWarning = false;
if ( !s_bPerfWarning && Count() >= ( 5 * m_cBucket ) )
{
s_bPerfWarning = true;
AssertMsg( false, "Performance warning: too many items, not enough buckets" );
Msg( "not enough buckets in thash class %s (%d records, %d buckets)\n",
#ifdef _WIN32
typeid(*this).raw_name(),
#else
typeid(*this).name(),
#endif
Count(), m_cBucket );
}
// Construct ourselves
Data *pData = PvRecordFromPRecHdr( pRecHdr );
Construct<Data>( pData );
return pData;
}
//-----------------------------------------------------------------------------
// Purpose: Changes key on previously inserted item
// Input: pvRecord - record to change key for
// unOldKey - old key (not strictly needed, but helpful consistency check)
// unNewKey - new key to use
//-----------------------------------------------------------------------------
template<class Data, class I>
void CTHash<Data,I>::ChangeKey( Data * pvRecord, I unOldKey, I unNewKey )
{
Data * pvRecordFound = PvRecordFind( unOldKey );
Assert( pvRecordFound == pvRecord );
if ( pvRecordFound == pvRecord )
{
RemoveFromHash( pvRecord );
InsertIntoHash( PRecHdrFromPvRecord( pvRecord), unNewKey );
}
}
//-----------------------------------------------------------------------------
// Purpose: Removes the entry with a specified key from the table
// Input: unKey - Key of the entry to remove
//-----------------------------------------------------------------------------
template<class Data, class I>
void CTHash<Data,I>::Remove( I unKey )
{
Data *pvRemove = ( Data * ) PvRecordFind( unKey );
Assert( pvRemove );
if ( !pvRemove )
return;
Remove( pvRemove );
}
//-----------------------------------------------------------------------------
// Purpose: Removes the specified entry from the table
// Input: pvRemove - Pointer to the entry to remove
//-----------------------------------------------------------------------------
template<class Data, class I>
void CTHash<Data,I>::Remove( Data * pvRemove )
{
// Destruct the record we're removing
Destruct<Data>( pvRemove );
RemoveFromHash( pvRemove );
m_pMemoryPoolRecord->Free( PRecHdrFromPvRecord( pvRemove ) );
}
//-----------------------------------------------------------------------------
// Purpose: Removes all entries from the table
//-----------------------------------------------------------------------------
template<class Data, class I>
void CTHash<Data,I>::RemoveAll()
{
Data * pvRecord = PvRecordFirst();
while ( pvRecord )
{
Data *pvRecordNext = PvRecordNext( pvRecord );
Remove( pvRecord );
pvRecord = pvRecordNext;
}
}
//-----------------------------------------------------------------------------
// Purpose: Finds the entry with a specified key
// Input: unKey - Key to find
//-----------------------------------------------------------------------------
template<class Data, class I>
Data *CTHash<Data,I>::PvRecordFind( I unKey ) const
{
// Find our hash bucket
int iBucket = IBucket( unKey );
// Walk the bucket's list looking for an exact match
for ( RecHdr_t *pRecHdr = m_pBucket[iBucket].m_pRecHdrFirst;
NULL != pRecHdr && pRecHdr->m_iBucket == iBucket;
pRecHdr = pRecHdr->m_pRecHdrNext )
{
if ( unKey == pRecHdr->m_unKey )
return PvRecordFromPRecHdr( pRecHdr );
}
// Didn't find a match
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Finds our first record
// Output: Pointer to our first record
//-----------------------------------------------------------------------------
template<class Data, class I>
Data *CTHash<Data,I>::PvRecordFirst() const
{
if ( &m_RecHdrTail != m_RecHdrHead.m_pRecHdrNext )
return PvRecordFromPRecHdr( m_RecHdrHead.m_pRecHdrNext );
else
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Iterates to the record after a given record
// Input: Pointer to a current record
// Output: Pointer to the next record
//-----------------------------------------------------------------------------
template<class Data, class I>
Data *CTHash<Data,I>::PvRecordNext( Data *pvRecordCur ) const
{
RecHdr_t *pRecHdr = PRecHdrFromPvRecord( pvRecordCur );
if ( &m_RecHdrTail == pRecHdr->m_pRecHdrNext )
return NULL;
return PvRecordFromPRecHdr( pRecHdr->m_pRecHdrNext );
}
//-----------------------------------------------------------------------------
// Purpose: Sets the run ratio of a particular record in the hash table.
// The record will be run 1 cycle out of every nRunRatio cycles.
// Input: pvRecord - The record we're setting
// nRunRatio - The run ratio for this record
//-----------------------------------------------------------------------------
template<class Data, class I>
void CTHash<Data,I>::SetRunRatio( Data *pvRecord, int nRunRatio )
{
PRecHdrFromPvRecord( pvRecord )->m_nRunRatio = nRunRatio;
}
//-----------------------------------------------------------------------------
// Purpose: Prepares us to run all records that are due to be run this frame.
// Records are run at a particular time dependent on their hash bucket,
// regardless of when they were last run.
// Input: bNewFrame - True if this is a new frame. If false, we've run
// off the end of the list and are checking whether
// we need to keep going at the beginning.
//-----------------------------------------------------------------------------
template<class Data, class I>
void CTHash<Data,I>::StartFrameSchedule( bool bNewFrame )
{
// Calculate our current frame and cycle cycle
if ( bNewFrame )
{
m_iCycleLast = m_iCycleCur;
m_iFrameCur++;
m_iCycleCur = m_iFrameCur / m_cFramesPerCycle;
}
// Calculate the last bucket to run
int iFrameInCycle = m_iFrameCur % m_cFramesPerCycle;
m_iBucketRunMax = ( int ) ( ( ( int64 ) ( iFrameInCycle + 1 ) * ( int64 ) m_cBucket )
/ ( int64 ) m_cFramesPerCycle );
AssertFatal( m_iBucketRunMax >= 0 && m_iBucketRunMax <= m_cBucket );
// Are we starting a new cycle?
if ( m_iCycleCur > m_iCycleLast )
{
#ifdef DBGFLAG_THASH
Assert( m_iCycleCur == m_iCycleLast + 1 );
#endif
// Did we finish the last cycle?
if ( &m_RecHdrTail == m_pRecHdrRunNext )
{
m_pRecHdrRunNext = m_RecHdrHead.m_pRecHdrNext;
}
// No-- finish it up before moving on
else
{
m_iBucketRunMax = m_cBucket + 1;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Returns the next record to run, if any
// Output: Pointer to the next record that needs to run (NULL if we're done)
//-----------------------------------------------------------------------------
template<class Data, class I>
Data *CTHash<Data,I>::PvRecordRun()
{
// Loop until we find a record to run, or until we pass m_iBucketRunMax
for ( ; ; )
{
// Are we past our stopping point?
if ( m_pRecHdrRunNext->m_iBucket >= m_iBucketRunMax )
{
// If this cycle ran to the very end, see if we need to start over
if ( m_iBucketRunMax > m_cBucket )
{
StartFrameSchedule( false );
continue;
}
return NULL;
}
#ifdef DBGFLAG_THASH
Assert( m_pRecHdrRunNext->m_iBucket >= m_iBucketRunFirst );
if ( 0 != m_pRecHdrRunNext->m_iCycleLast )
{
if ( m_pRecHdrRunNext->m_iCycleLast == m_iCycleCur )
{
DMsg( SPEW_CONSOLE, 1, "Double cycle: hdr = 0x%x, last frame = %d, curFrame = %d, first = %d, last = %d, bucket = %d\n",
m_pRecHdrRunNext, m_pRecHdrRunNext->m_iFrameLast, m_iFrame,
m_iBucketRunFirst, m_iBucketRunMax, m_pRecHdrRunNext->m_iBucket );
}
else if ( m_pRecHdrRunNext->m_iCycleLast != m_iCycleCur - 1 )
{
DMsg( SPEW_CONSOLE, 1, "Skipped cycle: hdr = 0x%x, cycleLast = %u, cycleCur = %u (missed %u cycles)\n",
m_pRecHdrRunNext, m_pRecHdrRunNext->m_iCycleLast, m_iCycleCur,
m_iCycleCur - m_pRecHdrRunNext->m_iCycleLast );
Assert( false );
}
}
m_pRecHdrRunNext->m_iCycleLast = m_iCycleCur;
m_pRecHdrRunNext->m_iFrameLast = m_iFrame;
#endif
// Set up the record to run next time
RecHdr_t *pRecHdrCur = m_pRecHdrRunNext;
m_pRecHdrRunNext = m_pRecHdrRunNext->m_pRecHdrNext;
// Does this record need to run?
if ( 0 == pRecHdrCur->m_nRunRatio )
continue;
if ( 0 == m_iCycleCur % pRecHdrCur->m_nRunRatio )
return PvRecordFromPRecHdr( pRecHdrCur );
}
}
//-----------------------------------------------------------------------------
// Purpose: Return true if we've completed a scheduler pass since last called
//-----------------------------------------------------------------------------
template<class Data, class I>
bool CTHash<Data,I>::BCompletedPass()
{
if ( m_iCycleCur != m_iCycleLastReported )
{
m_iCycleLastReported = m_iCycleCur;
return true;
}
return false;
}
extern const unsigned char g_CTHashRandomValues[256]; // definition lives in globals.cpp
//-----------------------------------------------------------------------------
// Purpose: Returns the index of the hash bucket corresponding to a particular key
// Input: unKey - Key to find
// Output: Index of the hash bucket corresponding to unKey
//-----------------------------------------------------------------------------
template<class Data, class I>
int CTHash<Data,I>::IBucket( I unKey ) const
{
AssertFatal( m_cBucket > 0 );
// This is a pearsons hash variant that returns a maximum of 32 bits
size_t size = sizeof(I);
const uint8 * k = (const uint8 *) &unKey;
uint32 byte_one = 0, byte_two = 0, byte_three = 0, byte_four = 0, n;
while (size)
{
--size;
n = *k++;
byte_one = g_CTHashRandomValues[byte_one ^ n];
if (size)
{
--size;
n = *k++;
byte_two = g_CTHashRandomValues[byte_two ^ n];
}
else
break;
if (size)
{
--size;
n = *k++;
byte_three = g_CTHashRandomValues[byte_three ^ n];
}
else
break;
if (size)
{
--size;
n = *k++;
byte_four = g_CTHashRandomValues[byte_four ^ n];
}
else
break;
}
uint32 idx = ( byte_four << 24 ) | ( byte_three << 16 ) | ( byte_two << 8 ) | byte_one;
idx = idx % m_cBucket;
return ( (int) idx );
}
#ifdef DBGFLAG_VALIDATE
//-----------------------------------------------------------------------------
// Purpose: Run a global validation pass on all of our data structures and memory
// allocations.
// Input: validator - Our global validator object
// pchName - Our name (typically a member var in our container)
//-----------------------------------------------------------------------------
template<class Data, class I>
void CTHash<Data,I>::Validate( CValidator &validator, const char *pchName )
{
VALIDATE_SCOPE();
validator.ClaimMemory( m_pBucket );
ValidatePtr( m_pMemoryPoolRecord );
#if defined( _DEBUG )
// first verify m_cRecordInUse
Data * pvRecord = PvRecordFirst();
int cItems = 0;
while ( pvRecord )
{
Data *pvRecordNext = PvRecordNext( pvRecord );
cItems++;
pvRecord = pvRecordNext;
}
Assert( m_cRecordInUse == cItems );
// then ask the mempool to verify this
if ( m_pMemoryPoolRecord )
m_pMemoryPoolRecord->LeakCheck( cItems );
#endif // _DEBUG
}
#endif // DBGFLAG_VALIDATE
//-----------------------------------------------------------------------------
// Purpose: Inserts a new record into the table
// Input: unKey - Primary key of the new record
// Output: Pointer to the new record
//-----------------------------------------------------------------------------
template<class Data, class I>
void CTHash<Data,I>::InsertIntoHash( RecHdr_t *pRecHdr, I unKey )
{
m_cRecordInUse++;
// Init the RecHdr
pRecHdr->m_unKey = unKey;
pRecHdr->m_nRunRatio = 1;
// Find our hash bucket
int iBucket = IBucket( unKey );
pRecHdr->m_iBucket = iBucket;
#ifdef DBGFLAG_THASH
pRecHdr->m_iCycleLast = 0;
#endif
// Find where to insert ourselves in the linked list
RecHdr_t *pRecHdrInsertBefore = &m_RecHdrTail;
// Find the first bucket with anything in it that's at or after our bucket
for ( int iBucketT = iBucket; iBucketT < m_cBucket; iBucketT++ )
{
if ( NULL != m_pBucket[iBucketT].m_pRecHdrFirst )
{
pRecHdrInsertBefore = m_pBucket[iBucketT].m_pRecHdrFirst;
break;
}
}
// Insert ourselves
pRecHdr->m_pRecHdrNext = pRecHdrInsertBefore;
pRecHdr->m_pRecHdrPrev = pRecHdrInsertBefore->m_pRecHdrPrev;
pRecHdrInsertBefore->m_pRecHdrPrev = pRecHdr;
pRecHdr->m_pRecHdrPrev->m_pRecHdrNext = pRecHdr;
// Our bucket should point to us
m_pBucket[iBucket].m_pRecHdrFirst = pRecHdr;
}
//-----------------------------------------------------------------------------
// Purpose: Removes the specified entry from the table
// Input: pvRemove - Pointer to the entry to remove
//-----------------------------------------------------------------------------
template<class Data, class I>
void CTHash<Data,I>::RemoveFromHash( Data * pvRemove )
{
// Find our RecHdr
RecHdr_t *pRecHdr = PRecHdrFromPvRecord( pvRemove );
// If our bucket points to us, point it to the next record (or else NULL)
int iBucket = IBucket( pRecHdr->m_unKey );
if ( pRecHdr == m_pBucket[iBucket].m_pRecHdrFirst )
{
if ( pRecHdr->m_pRecHdrNext->m_iBucket == iBucket )
m_pBucket[iBucket].m_pRecHdrFirst = pRecHdr->m_pRecHdrNext;
else
m_pBucket[iBucket].m_pRecHdrFirst = NULL;
}
// Remove us from the linked list
pRecHdr->m_pRecHdrPrev->m_pRecHdrNext = pRecHdr->m_pRecHdrNext;
pRecHdr->m_pRecHdrNext->m_pRecHdrPrev = pRecHdr->m_pRecHdrPrev;
// Are we the next record to run?
if ( pRecHdr == m_pRecHdrRunNext )
m_pRecHdrRunNext = pRecHdr->m_pRecHdrNext;
m_cRecordInUse--;
}
#endif // THASH_H

85
public/tier1/tier1.h Normal file
View File

@@ -0,0 +1,85 @@
//===== Copyright <20> 2005-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose: A higher level link library for general use in the game and tools.
//
//===========================================================================//
#ifndef TIER1_H
#define TIER1_H
#if defined( _WIN32 )
#pragma once
#endif
#include "appframework/iappsystem.h"
#include "tier1/convar.h"
//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Call this to connect to/disconnect from all tier 1 libraries.
// It's up to the caller to check the globals it cares about to see if ones are missing
//-----------------------------------------------------------------------------
void ConnectTier1Libraries( CreateInterfaceFn *pFactoryList, int nFactoryCount );
void DisconnectTier1Libraries();
//-----------------------------------------------------------------------------
// Helper empty implementation of an IAppSystem for tier2 libraries
//-----------------------------------------------------------------------------
template< class IInterface, int ConVarFlag = 0 >
class CTier1AppSystem : public CTier0AppSystem< IInterface >
{
typedef CTier0AppSystem< IInterface > BaseClass;
public:
virtual bool Connect( CreateInterfaceFn factory )
{
if ( !BaseClass::Connect( factory ) )
return false;
ConnectTier1Libraries( &factory, 1 );
return true;
}
virtual void Disconnect()
{
DisconnectTier1Libraries();
BaseClass::Disconnect();
}
virtual InitReturnVal_t Init()
{
InitReturnVal_t nRetVal = BaseClass::Init();
if ( nRetVal != INIT_OK )
return nRetVal;
if ( g_pCVar )
{
ConVar_Register( ConVarFlag );
}
return INIT_OK;
}
virtual void Shutdown()
{
if ( g_pCVar )
{
ConVar_Unregister( );
}
BaseClass::Shutdown( );
}
virtual AppSystemTier_t GetTier()
{
return APP_SYSTEM_TIER1;
}
};
#endif // TIER1_H

View File

@@ -0,0 +1,32 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
// Tier1 logging helpers.
//
//===============================================================================
#ifndef TIER1_LOGGING_H
#define TIER1_LOGGING_H
#if defined( COMPILER_MSVC )
#pragma once
#endif
#include "logging.h"
#include "utlbuffer.h"
#include "color.h"
class CBufferedLoggingListener : public ILoggingListener
{
public:
CBufferedLoggingListener();
virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage );
void EmitBufferedSpew();
private:
CUtlBuffer m_StoredSpew;
};
#endif // TIER1_LOGGING_H

173
public/tier1/timeutils.h Normal file
View File

@@ -0,0 +1,173 @@
//====== Copyright <20> 1996-2004, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#ifndef TIMEUTILS_H
#define TIMEUTILS_H
#ifdef _WIN32
#pragma once
#endif
#include <limits.h>
#include <math.h>
#include "tier0/dbg.h"
enum RoundStyle_t
{
ROUND_NEAREST,
ROUND_DOWN,
ROUND_UP,
};
class DmeTime_t;
class DmeFramerate_t
{
public:
DmeFramerate_t( float fps );
DmeFramerate_t( int fps = 0 );
DmeFramerate_t( const DmeFramerate_t& src ) : m_num( src.m_num ), m_den( src.m_den ) {}
void SetFramerate( float flFrameRate );
void SetFramerate( int fps );
// other (uncommon) options besides 30(29.97 - ntsc video) are 24 (23.976 - ntsc film) and 60 (59.94 - ntsc progressive)
void SetFramerateNTSC( int multiplier = 30 );
float GetFramesPerSecond() const;
DmeTime_t GetTimePerFrame() const;
bool operator==( DmeFramerate_t f ) const { return m_num == f.m_num && m_den == f.m_den; }
bool operator!=( DmeFramerate_t f ) const { return m_num != f.m_num && m_den != f.m_den; }
bool operator< ( DmeFramerate_t f ) const { return m_num * ( int )f.m_den < f.m_num * ( int )m_den; }
bool operator> ( DmeFramerate_t f ) const { return m_num * ( int )f.m_den > f.m_num * ( int )m_den; }
bool operator<=( DmeFramerate_t f ) const { return m_num * ( int )f.m_den <= f.m_num * ( int )m_den; }
bool operator>=( DmeFramerate_t f ) const { return m_num * ( int )f.m_den >= f.m_num * ( int )m_den; }
DmeFramerate_t operator*( int i ) const { return DmeFramerate_t( m_num * i, m_den ); }
DmeFramerate_t operator/( int i ) const { return DmeFramerate_t( m_num, m_den * i ); }
DmeFramerate_t operator*=( int i ) { Assert( abs( m_num * i ) <= USHRT_MAX ); m_num *= ( unsigned short )i; return *this; }
DmeFramerate_t operator/=( int i ) { Assert( abs( m_den * i ) <= USHRT_MAX ); m_den *= ( unsigned short )i; return *this; }
private:
DmeFramerate_t( int nNumerator, int nDenominator );
unsigned short m_num;
unsigned short m_den;
friend class DmeTime_t;
};
#define DMETIME_ZERO DmeTime_t(0)
#define DMETIME_MINDELTA DmeTime_t::MinTimeDelta()
#define DMETIME_MINTIME DmeTime_t::MinTime()
#define DMETIME_MAXTIME DmeTime_t::MaxTime()
#define DMETIME_INVALID DmeTime_t::InvalidTime()
class DmeTime_t
{
public:
DmeTime_t() : m_tms( INT_MIN ) {} // invalid time
explicit DmeTime_t( int tms ) : m_tms( tms ) {}
explicit DmeTime_t( float sec ) : m_tms( RoundSecondsToTMS( sec ) ) {}
explicit DmeTime_t( double sec ) : m_tms( RoundSecondsToTMS( sec ) ) {}
DmeTime_t( int frame, DmeFramerate_t framerate );
// time operators
friend bool operator==( DmeTime_t a, DmeTime_t b ) { return a.m_tms == b.m_tms; }
friend bool operator!=( DmeTime_t a, DmeTime_t b ) { return a.m_tms != b.m_tms; }
friend bool operator< ( DmeTime_t a, DmeTime_t b ) { return a.m_tms < b.m_tms; }
friend bool operator> ( DmeTime_t a, DmeTime_t b ) { return a.m_tms > b.m_tms; }
friend bool operator<=( DmeTime_t a, DmeTime_t b ) { return a.m_tms <= b.m_tms; }
friend bool operator>=( DmeTime_t a, DmeTime_t b ) { return a.m_tms >= b.m_tms; }
friend DmeTime_t operator%( DmeTime_t a, DmeTime_t b ) { return DmeTime_t( a.m_tms % b.m_tms ); }
friend DmeTime_t operator+( DmeTime_t a, DmeTime_t b ) { return DmeTime_t( a.m_tms + b.m_tms ); }
friend DmeTime_t operator-( DmeTime_t a, DmeTime_t b ) { return DmeTime_t( a.m_tms - b.m_tms ); }
DmeTime_t operator-() const { return DmeTime_t( -m_tms ); }
DmeTime_t operator+=( DmeTime_t t ) { m_tms += t.m_tms; return *this; }
DmeTime_t operator-=( DmeTime_t t ) { m_tms -= t.m_tms; return *this; }
// float operators - comment these out to find potentially incorrect uses of DmeTime_t
friend DmeTime_t operator*( DmeTime_t t, float f ) { t *= f; return t; }
friend DmeTime_t operator*( float f, DmeTime_t t ) { t *= f; return t; }
friend DmeTime_t operator/( DmeTime_t t, float f ) { t /= f; return t; }
friend float operator/( DmeTime_t n, DmeTime_t d ) { return float( n.m_tms / double( d.m_tms ) ); }
DmeTime_t operator*=( float f );
DmeTime_t operator/=( float f );
DmeTime_t operator++() { ++m_tms; return *this; }
DmeTime_t operator--() { --m_tms; return *this; }
DmeTime_t operator++( int ) { DmeTime_t t = *this; ++m_tms; return t; } // postfix version..
DmeTime_t operator--( int ) { DmeTime_t t = *this; --m_tms; return t; } // postfix version..
// limits, special values and validity
bool IsValid() const { return m_tms != INT_MIN; }
static DmeTime_t InvalidTime() { return DmeTime_t( INT_MIN ); }
static DmeTime_t MinTime() { return DmeTime_t( INT_MIN + 1 ); }
static DmeTime_t MaxTime() { return DmeTime_t( INT_MAX ); }
static DmeTime_t MinTimeDelta() { return DmeTime_t( 1 ); }
// conversions between other time representations
int GetTenthsOfMS() const { return m_tms; }
float GetSeconds() const { return m_tms * 0.0001f; }
void SetTenthsOfMS( int tms ) { m_tms = tms; }
void SetSeconds( float sec ) { m_tms = RoundSecondsToTMS( sec ); }
// helper methods
void Clamp( DmeTime_t lo, DmeTime_t hi );
bool IsInRange( DmeTime_t lo, DmeTime_t hi ) const;
// helper functions
friend float GetFractionOfTimeBetween( DmeTime_t t, DmeTime_t start, DmeTime_t end, bool bClamp );
friend float GetFractionOfTime( DmeTime_t t, DmeTime_t duration, bool bClamp );
friend int FrameForTime( DmeTime_t t, DmeFramerate_t framerate );
// standard arithmetic methods
friend DmeTime_t abs( DmeTime_t t ) { return t.m_tms >= 0 ? t : -t; }
// framerate-dependent conversions to/from frames
int CurrentFrame( DmeFramerate_t framerate, RoundStyle_t roundStyle = ROUND_DOWN ) const;
DmeTime_t TimeAtCurrentFrame( DmeFramerate_t framerate, RoundStyle_t roundStyle = ROUND_DOWN ) const;
DmeTime_t TimeAtNextFrame( DmeFramerate_t framerate ) const;
DmeTime_t TimeAtPrevFrame( DmeFramerate_t framerate ) const;
private:
explicit DmeTime_t( int64 tms ) : m_tms( int( tms ) ) {}
// conversion helper methods - implementation
static int RoundSecondsToTMS( float sec );
static int RoundSecondsToTMS( double sec );
int m_tms;
};
float GetFractionOfTimeBetween( DmeTime_t t, DmeTime_t start, DmeTime_t end, bool bClamp = false );
float GetFractionOfTime( DmeTime_t t, DmeTime_t duration, bool bClamp = false );
class CUtlBuffer;
bool Serialize( CUtlBuffer &buf, const DmeTime_t &src );
bool Unserialize( CUtlBuffer &buf, DmeTime_t &dest );
#endif // TIMEUTILS_H

122
public/tier1/tokenset.h Normal file
View File

@@ -0,0 +1,122 @@
//========= Copyright <20> 2008, Valve Corporation, All rights reserved. ============//
#ifndef __TOKENSET_H
#define __TOKENSET_H
#ifdef _WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
//
// This class is a handy way to match a series of values to stings and vice
// versa. It should be initalized as static like an array, for example:
//
// const tokenset_t<int> tokens[] = {
// { "token1", 1 },
// { "token2", 2 },
// { "token3", 3 },
// { NULL, -1 }
// };
//
// Then you can call the operators on it by using:
//
// int t = tokens->GetToken( s );
//
// If s is "token1" it returns 1, etc. Invalid string returns the last NULL
// value. GetNameByToken() returns "__UNKNOWN__" when passed a mismatched
// token. GetNameByToken() returns szMismatchResult when passed a mismatched
// token and a string to return in case of mismatch.
//
//-----------------------------------------------------------------------------
template <class _T>
struct tokenset_t
{
const char *name;
_T token;
_T GetToken( const char *s ) const;
_T GetTokenI( const char *s ) const;
const char *GetNameByToken( _T token ) const;
const char *GetNameByToken( _T token, const char *szMismatchResult ) const;
};
template <class _T>
inline _T tokenset_t< _T >::GetToken( const char *s ) const
{
const tokenset_t< _T > *c;
for ( c = this; c->name; ++c )
{
if ( !s )
{
continue; // Loop to the last NULL value
}
if ( Q_strcmp( s, c->name ) == 0 )
{
return c->token;
}
}
return c->token; // c points to the last NULL value
}
template <class _T>
inline _T tokenset_t< _T >::GetTokenI( const char *s ) const
{
const tokenset_t< _T > *c;
for ( c = this; c->name; ++c )
{
if ( !s )
{
continue; // Loop to the last NULL value
}
if ( Q_stricmp( s, c->name ) == 0 )
{
return c->token;
}
}
return c->token; // c points to the last NULL value
}
template <class _T>
inline const char *tokenset_t< _T >::GetNameByToken( _T token ) const
{
static const char *unknown = "__UNKNOWN__";
const tokenset_t< _T > *c;
for ( c = this; c->name; ++c )
{
if ( c->token == token )
{
return c->name;
}
}
return unknown;
}
template <class _T>
inline const char *tokenset_t< _T >::GetNameByToken( _T token, char const *szMismatchResult ) const
{
const tokenset_t< _T > *c;
for ( c = this; c->name; ++c )
{
if ( c->token == token )
{
return c->name;
}
}
return szMismatchResult;
}
#endif //__TOKENSET_H

56
public/tier1/uniqueid.h Normal file
View File

@@ -0,0 +1,56 @@
//====== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. =======//
//
// Purpose:
//
// $NoKeywords: $
//
// Utilities for globally unique IDs
//=============================================================================//
#ifndef UNIQUEID_H
#define UNIQUEID_H
#ifdef _WIN32
#pragma once
#endif
#include "tier1/utlvector.h"
//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
struct UniqueId_t;
class CUtlBuffer;
//-----------------------------------------------------------------------------
// Defines a globally unique ID
//-----------------------------------------------------------------------------
struct UniqueId_t
{
unsigned char m_Value[16];
};
//-----------------------------------------------------------------------------
// Methods related to unique ids
//-----------------------------------------------------------------------------
void CreateUniqueId( UniqueId_t *pDest );
void InvalidateUniqueId( UniqueId_t *pDest );
bool IsUniqueIdValid( const UniqueId_t &id );
bool IsUniqueIdEqual( const UniqueId_t &id1, const UniqueId_t &id2 );
void UniqueIdToString( const UniqueId_t &id, char *pBuf, int nMaxLen );
bool UniqueIdFromString( UniqueId_t *pDest, const char *pBuf, int nMaxLen = 0 );
void CopyUniqueId( const UniqueId_t &src, UniqueId_t *pDest );
bool Serialize( CUtlBuffer &buf, const UniqueId_t &src );
bool Unserialize( CUtlBuffer &buf, UniqueId_t &dest );
inline bool operator ==( const UniqueId_t& lhs, const UniqueId_t& rhs )
{
return !Q_memcmp( (void *)&lhs.m_Value[ 0 ], (void *)&rhs.m_Value[ 0 ], sizeof( lhs.m_Value ) );
}
#endif // UNIQUEID_H

View File

@@ -0,0 +1,134 @@
//====== Copyright <20> 1996-2010, Valve Corporation, All rights reserved. =======
//
// Purpose:
// The CUtlAllocation class:
// A single allocation in the style of CUtlMemory/CUtlString/CUtlBuffer
// as compact as possible, no virtuals or extraneous data
// to be used primarily to replace CUtlBuffer
//=============================================================================
#ifndef UTLALLOCATION_H
#define UTLALLOCATION_H
#ifdef _WIN32
#pragma once
#endif
#include "tier1/utlmemory.h"
class CUtlAllocation
{
public:
// constructor, destructor
CUtlAllocation()
{
m_pMemory = NULL;
}
CUtlAllocation( const void *pMemory, int cub )
{
m_pMemory = NULL;
Copy( pMemory, cub );
}
CUtlAllocation( CUtlAllocation const &src )
{
m_pMemory = NULL;
Copy( src );
}
~CUtlAllocation()
{
Purge();
}
CUtlAllocation &operator=( CUtlAllocation const &src )
{
Copy( src );
return *this;
}
bool operator==( CUtlAllocation const &src )
{
if ( Count() != src.Count() )
return false;
return Q_memcmp( Base(), src.Base(), Count() ) == 0;
}
void Copy( const void *pMemory, int cub )
{
if ( cub == 0 || pMemory == NULL )
{
Purge();
return;
}
if ( cub != Count() )
{
Purge();
m_pMemory = (ActualMemory_t *)malloc( cub + sizeof( int ) );
m_pMemory->cub = cub;
}
Q_memcpy( Base(), pMemory, cub );
}
// Gets the base address
uint8* Base()
{
if ( m_pMemory == NULL )
return NULL;
return m_pMemory->rgub;
}
const uint8* Base() const
{
if ( m_pMemory == NULL )
return NULL;
return m_pMemory->rgub;
}
// Size
int Count() const
{
if ( m_pMemory == NULL )
return 0;
return m_pMemory->cub;
}
// Memory deallocation
void Purge()
{
if ( m_pMemory )
free(m_pMemory);
m_pMemory = NULL;
}
void Copy( const CUtlAllocation &alloc )
{
Copy( alloc.Base(), alloc.Count() );
}
void Swap( CUtlAllocation &alloc )
{
ActualMemory_t *pTemp = m_pMemory;
m_pMemory = alloc.m_pMemory;
alloc.m_pMemory = pTemp;
}
void Alloc( int cub )
{
Purge();
m_pMemory = (ActualMemory_t *)malloc( cub + sizeof( int ) );
m_pMemory->cub = cub;
}
private:
struct ActualMemory_t
{
int cub;
uint8 rgub[4]; // i'd prefer to make this 0 but the compiler whines when i do
};
ActualMemory_t *m_pMemory;
};
#endif // UTLALLOCATION_H

293
public/tier1/utlarray.h Normal file
View File

@@ -0,0 +1,293 @@
//====== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. =======//
//
// Purpose:
//
// $NoKeywords: $
//
// A growable array class that maintains a free list and keeps elements
// in the same location
//=============================================================================//
#ifndef UTLARRAY_H
#define UTLARRAY_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/platform.h"
#include "tier0/dbg.h"
#include "vstdlib/random.h"
#define FOR_EACH_ARRAY( vecName, iteratorName ) \
for ( int iteratorName = 0; (vecName).IsUtlArray && iteratorName < (vecName).Count(); iteratorName++ )
#define FOR_EACH_ARRAY_BACK( vecName, iteratorName ) \
for ( int iteratorName = (vecName).Count()-1; (vecName).IsUtlArray && iteratorName >= 0; iteratorName-- )
// utlarray derives from this so we can do the type check above
struct base_array_t
{
public:
enum { IsUtlArray = true }; // Used to match this at compiletime
};
//-----------------------------------------------------------------------------
template< class T, size_t MAX_SIZE >
class CUtlArray : public base_array_t
{
public:
typedef T ElemType_t;
CUtlArray();
CUtlArray( T* pMemory, size_t count );
~CUtlArray();
CUtlArray<T, MAX_SIZE>& operator=( const CUtlArray<T, MAX_SIZE> &other );
CUtlArray( CUtlArray const& vec );
// element access
T& operator[]( int i );
const T& operator[]( int i ) const;
T& Element( int i );
const T& Element( int i ) const;
T& Random();
const T& Random() const;
T* Base();
const T* Base() const;
// Returns the number of elements in the array, NumAllocated() is included for consistency with UtlVector
int Count() const;
int NumAllocated() const;
// Is element index valid?
bool IsValidIndex( int i ) const;
static int InvalidIndex();
void CopyArray( const T *pArray, size_t count );
void Swap( CUtlArray< T, MAX_SIZE > &vec );
// Finds an element (element needs operator== defined)
int Find( const T& src ) const;
void FillWithValue( const T& src );
bool HasElement( const T& src ) const;
// calls delete on each element in it.
void DeleteElements();
void Sort( int (__cdecl *pfnCompare)(const T *, const T *) );
protected:
T m_Memory[ MAX_SIZE ];
};
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
template< typename T, size_t MAX_SIZE >
inline CUtlArray<T, MAX_SIZE>::CUtlArray()
{
}
template< typename T, size_t MAX_SIZE >
inline CUtlArray<T, MAX_SIZE>::CUtlArray( T* pMemory, size_t count )
{
CopyArray( pMemory, count );
}
template< typename T, size_t MAX_SIZE >
inline CUtlArray<T, MAX_SIZE>::~CUtlArray()
{
}
template< typename T, size_t MAX_SIZE >
inline CUtlArray<T, MAX_SIZE>& CUtlArray<T, MAX_SIZE>::operator=( const CUtlArray<T, MAX_SIZE> &other )
{
if ( this != &other )
{
for ( size_t n = 0; n < MAX_SIZE; ++n )
{
m_Memory[n] = other.m_Memory[n];
}
}
return *this;
}
template< typename T, size_t MAX_SIZE >
inline CUtlArray<T, MAX_SIZE>::CUtlArray( CUtlArray const& vec )
{
for ( size_t n = 0; n < MAX_SIZE; ++n )
{
m_Memory[n] = vec.m_Memory[n];
}
}
template< typename T, size_t MAX_SIZE >
inline T *CUtlArray<T, MAX_SIZE>::Base()
{
return &m_Memory[0];
}
template< typename T, size_t MAX_SIZE >
inline const T *CUtlArray<T, MAX_SIZE>::Base() const
{
return &m_Memory[0];
}
//-----------------------------------------------------------------------------
// element access
//-----------------------------------------------------------------------------
template< typename T, size_t MAX_SIZE >
inline T& CUtlArray<T, MAX_SIZE>::operator[]( int i )
{
Assert( IsValidIndex( i ) );
return m_Memory[ i ];
}
template< typename T, size_t MAX_SIZE >
inline const T& CUtlArray<T, MAX_SIZE>::operator[]( int i ) const
{
Assert( IsValidIndex( i ) );
return m_Memory[ i ];
}
template< typename T, size_t MAX_SIZE >
inline T& CUtlArray<T, MAX_SIZE>::Element( int i )
{
Assert( IsValidIndex( i ) );
return m_Memory[ i ];
}
template< typename T, size_t MAX_SIZE >
inline const T& CUtlArray<T, MAX_SIZE>::Element( int i ) const
{
Assert( IsValidIndex( i ) );
return m_Memory[ i ];
}
template< typename T, size_t MAX_SIZE >
inline T& CUtlArray<T, MAX_SIZE>::Random()
{
Assert( MAX_SIZE > 0 );
return m_Memory[ RandomInt( 0, MAX_SIZE - 1 ) ];
}
template< typename T, size_t MAX_SIZE >
inline const T& CUtlArray<T, MAX_SIZE>::Random() const
{
Assert( MAX_SIZE > 0 );
return m_Memory[ RandomInt( 0, MAX_SIZE - 1 ) ];
}
//-----------------------------------------------------------------------------
// Count
//-----------------------------------------------------------------------------
template< typename T, size_t MAX_SIZE >
inline int CUtlArray<T, MAX_SIZE>::Count() const
{
return (int)MAX_SIZE;
}
//-----------------------------------------------------------------------------
template< typename T, size_t MAX_SIZE >
inline int CUtlArray<T, MAX_SIZE>::NumAllocated() const
{
return (int)MAX_SIZE;
}
//-----------------------------------------------------------------------------
// Is element index valid?
//-----------------------------------------------------------------------------
template< typename T, size_t MAX_SIZE >
inline bool CUtlArray<T, MAX_SIZE>::IsValidIndex( int i ) const
{
return (i >= 0) && (i < MAX_SIZE);
}
//-----------------------------------------------------------------------------
// Returns in invalid index
//-----------------------------------------------------------------------------
template< typename T, size_t MAX_SIZE >
inline int CUtlArray<T, MAX_SIZE>::InvalidIndex()
{
return -1;
}
//-----------------------------------------------------------------------------
// Sorts the vector
//-----------------------------------------------------------------------------
template< typename T, size_t MAX_SIZE >
void CUtlArray<T, MAX_SIZE>::Sort( int (__cdecl *pfnCompare)(const T *, const T *) )
{
typedef int (__cdecl *QSortCompareFunc_t)(const void *, const void *);
if ( Count() <= 1 )
return;
qsort( Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare) );
}
template< typename T, size_t MAX_SIZE >
void CUtlArray<T, MAX_SIZE>::CopyArray( const T *pArray, size_t count )
{
Assert( count < MAX_SIZE );
for ( size_t n = 0; n < count; ++n )
{
m_Memory[n] = pArray[n];
}
}
template< typename T, size_t MAX_SIZE >
void CUtlArray<T, MAX_SIZE>::Swap( CUtlArray< T, MAX_SIZE > &vec )
{
for ( size_t n = 0; n < MAX_SIZE; ++n )
{
V_swap( m_Memory[n], vec.m_Memory[n] );
}
}
//-----------------------------------------------------------------------------
// Finds an element (element needs operator== defined)
//-----------------------------------------------------------------------------
template< typename T, size_t MAX_SIZE >
int CUtlArray<T, MAX_SIZE>::Find( const T& src ) const
{
for ( int i = 0; i < Count(); ++i )
{
if (Element(i) == src)
return i;
}
return -1;
}
template< typename T, size_t MAX_SIZE >
void CUtlArray<T, MAX_SIZE>::FillWithValue( const T& src )
{
for ( int i = 0; i < Count(); i++ )
{
Element(i) = src;
}
}
template< typename T, size_t MAX_SIZE >
bool CUtlArray<T, MAX_SIZE>::HasElement( const T& src ) const
{
return ( Find(src) >= 0 );
}
template< typename T, size_t MAX_SIZE >
inline void CUtlArray<T, MAX_SIZE>::DeleteElements()
{
for( int i=0; i < MAX_SIZE; i++ )
{
delete Element(i);
}
}
#endif // UTLARRAY_H

View File

@@ -0,0 +1,394 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Bi-directional set. A Bucket knows about the elements that lie
// in it, and the elements know about the buckets they lie in.
//
// $Revision: $
// $NoKeywords: $
//=============================================================================//
#ifndef UTLBIDIRECTIONALSET_H
#define UTLBIDIRECTIONALSET_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
#include "utllinkedlist.h"
//-----------------------------------------------------------------------------
// Templatized helper class to deal with the kinds of things that spatial
// partition code always seems to have; buckets with lists of lots of elements
// and elements that live in lots of buckets. This makes it really quick to
// add and remove elements, and to iterate over all elements in a bucket.
//
// For this to work, you must initialize the set with two functions one that
// maps from bucket to the index of the first element in that bucket, and one
// that maps from element to the index of the first bucket that element lies in.
// The set will completely manage the index, it's just expected that those
// indices will be stored outside the set.
//
// S is the storage type of the index; it is the type that you may use to
// save indices into memory. I is the local iterator type, which you should
// use in any local scope (eg, inside a for() loop.) The reason for this is
// that you may wish to use unsigned shorts inside the structs you are
// saving with a CBidirectionalSet; but 16-bit arithmetic is catastrophically
// slow on a PowerPC -- during testing we saw CBidirectionalSet:: operations
// consume as much as 8% of the frame.
//
// For this reason, on the 360, the handles have been typedef'd to native
// register types (U32) which are accepted as parameters by the functions.
// The implicit assumption is that CBucketHandle and CElementHandle can
// be safely cast to ints! You can increase to U64 without performance
// penalty if necessary; the PowerPC is a 64-bit processor.
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I = S >
class CBidirectionalSet
{
public:
// Install methods to get at the first bucket given a element
// and vice versa...
typedef S& (*FirstElementFunc_t)(CBucketHandle);
typedef S& (*FirstBucketFunc_t)(CElementHandle);
#ifdef _X360
typedef uint32 CBucketHandlePram;
typedef uint32 CElementHandlePram;
#else
typedef CBucketHandle CBucketHandlePram;
typedef CElementHandle CElementHandlePram;
#endif
// Constructor
CBidirectionalSet();
// Call this before using the set
void Init( FirstElementFunc_t elemFunc, FirstBucketFunc_t bucketFunc );
// Add an element to a particular bucket
void AddElementToBucket( CBucketHandlePram bucket, CElementHandlePram element );
// Prevalidate an add to a particular bucket
// NOTE: EXPENSIVE!!!
void ValidateAddElementToBucket( CBucketHandlePram bucket, CElementHandlePram element );
// Test if an element is in a particular bucket.
// NOTE: EXPENSIVE!!!
bool IsElementInBucket( CBucketHandlePram bucket, CElementHandlePram element );
// Remove an element from a particular bucket
void RemoveElementFromBucket( CBucketHandlePram bucket, CElementHandlePram element );
// Remove an element from all buckets
void RemoveElement( CElementHandlePram element );
void RemoveBucket( CBucketHandlePram element );
// Used to iterate elements in a bucket; I is the iterator
I FirstElement( CBucketHandlePram bucket ) const;
I NextElement( I idx ) const;
CElementHandle Element( I idx ) const;
// Used to iterate buckets associated with an element; I is the iterator
I FirstBucket( CElementHandlePram bucket ) const;
I NextBucket( I idx ) const;
CBucketHandle Bucket( I idx ) const;
static S InvalidIndex();
// Ensure capacity
void EnsureCapacity( int count );
// Deallocate....
void Purge();
int NumAllocated( void ) const;
private:
struct BucketListInfo_t
{
CElementHandle m_Element;
S m_BucketListIndex; // what's the m_BucketsUsedByElement index of the entry?
};
struct ElementListInfo_t
{
CBucketHandle m_Bucket;
S m_ElementListIndex; // what's the m_ElementsInBucket index of the entry?
};
// Maintains a list of all elements in a particular bucket
CUtlLinkedList< BucketListInfo_t, S, true, I > m_ElementsInBucket;
// Maintains a list of all buckets a particular element lives in
CUtlLinkedList< ElementListInfo_t, S, true, I > m_BucketsUsedByElement;
FirstBucketFunc_t m_FirstBucket;
FirstElementFunc_t m_FirstElement;
};
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I >
CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::CBidirectionalSet( )
{
m_FirstBucket = NULL;
m_FirstElement = NULL;
}
//-----------------------------------------------------------------------------
// Call this before using the set
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I >
void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::Init( FirstElementFunc_t elemFunc, FirstBucketFunc_t bucketFunc )
{
m_FirstBucket = bucketFunc;
m_FirstElement = elemFunc;
}
//-----------------------------------------------------------------------------
// Adds an element to the bucket
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I >
void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::ValidateAddElementToBucket( CBucketHandlePram bucket, CElementHandlePram element )
{
#ifdef _DEBUG
// Make sure that this element doesn't already exist in the list of elements in the bucket
I elementInBucket = m_FirstElement( bucket );
while( elementInBucket != m_ElementsInBucket.InvalidIndex() )
{
// If you hit an Assert here, fix the calling code. It's too expensive to ensure
// that each item only shows up once here. Hopefully you can do something better
// outside of here.
Assert( m_ElementsInBucket[elementInBucket].m_Element != element );
elementInBucket = m_ElementsInBucket.Next( elementInBucket );
}
// Make sure that this bucket doesn't already exist in the element's list of buckets.
I bucketInElement = m_FirstBucket( element );
while( bucketInElement != m_BucketsUsedByElement.InvalidIndex() )
{
// If you hit an Assert here, fix the calling code. It's too expensive to ensure
// that each item only shows up once here. Hopefully you can do something better
// outside of here.
Assert( m_BucketsUsedByElement[bucketInElement].m_Bucket != bucket );
bucketInElement = m_BucketsUsedByElement.Next( bucketInElement );
}
#endif
}
//-----------------------------------------------------------------------------
// Adds an element to the bucket
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I >
void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::AddElementToBucket( CBucketHandlePram bucket, CElementHandlePram element )
{
Assert( m_FirstBucket && m_FirstElement );
// Allocate new element + bucket entries
I idx = m_ElementsInBucket.Alloc(true);
I list = m_BucketsUsedByElement.Alloc( true );
// Store off the element data
m_ElementsInBucket[idx].m_Element = element;
m_ElementsInBucket[idx].m_BucketListIndex = list;
// Here's the bucket data
m_BucketsUsedByElement[list].m_Bucket = bucket;
m_BucketsUsedByElement[list].m_ElementListIndex = idx;
// Insert the element into the list of elements in the bucket
S& firstElementInBucket = m_FirstElement( bucket );
if ( firstElementInBucket != m_ElementsInBucket.InvalidIndex() )
m_ElementsInBucket.LinkBefore( firstElementInBucket, idx );
firstElementInBucket = idx;
// Insert the bucket into the element's list of buckets
S& firstBucketInElement = m_FirstBucket( element );
if ( firstBucketInElement != m_BucketsUsedByElement.InvalidIndex() )
m_BucketsUsedByElement.LinkBefore( firstBucketInElement, list );
firstBucketInElement = list;
}
//-----------------------------------------------------------------------------
// Test if an element is in a particular bucket.
// NOTE: EXPENSIVE!!!
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I >
bool CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::IsElementInBucket( CBucketHandlePram bucket, CElementHandlePram element )
{
// Search through all elements in this bucket to see if element is in there.
I elementInBucket = m_FirstElement( bucket );
while( elementInBucket != m_ElementsInBucket.InvalidIndex() )
{
if( m_ElementsInBucket[elementInBucket].m_Element == element )
{
return true;
}
elementInBucket = m_ElementsInBucket.Next( elementInBucket );
}
return false;
}
//-----------------------------------------------------------------------------
// Remove an element from a particular bucket
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I >
void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::RemoveElementFromBucket( CBucketHandlePram bucket, CElementHandlePram element )
{
// FIXME: Implement me!
Assert(0);
}
//-----------------------------------------------------------------------------
// Removes an element from all buckets
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I >
void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::RemoveElement( CElementHandlePram element )
{
Assert( m_FirstBucket && m_FirstElement );
// Iterate over the list of all buckets the element is in
I i = m_FirstBucket( element );
while (i != m_BucketsUsedByElement.InvalidIndex())
{
CBucketHandlePram bucket = m_BucketsUsedByElement[i].m_Bucket;
I elementListIndex = m_BucketsUsedByElement[i].m_ElementListIndex;
// Unhook the element from the bucket's list of elements
if (elementListIndex == m_FirstElement(bucket))
m_FirstElement(bucket) = m_ElementsInBucket.Next(elementListIndex);
m_ElementsInBucket.Free(elementListIndex);
I prevNode = i;
i = m_BucketsUsedByElement.Next(i);
m_BucketsUsedByElement.Free(prevNode);
}
// Mark the list as empty
m_FirstBucket( element ) = m_BucketsUsedByElement.InvalidIndex();
}
//-----------------------------------------------------------------------------
// Removes a bucket from all elements
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I >
void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::RemoveBucket( CBucketHandlePram bucket )
{
// Iterate over the list of all elements in the bucket
I i = m_FirstElement( bucket );
while (i != m_ElementsInBucket.InvalidIndex())
{
CElementHandlePram element = m_ElementsInBucket[i].m_Element;
I bucketListIndex = m_ElementsInBucket[i].m_BucketListIndex;
// Unhook the bucket from the element's list of buckets
if (bucketListIndex == m_FirstBucket(element))
m_FirstBucket(element) = m_BucketsUsedByElement.Next(bucketListIndex);
m_BucketsUsedByElement.Free(bucketListIndex);
// Remove the list element
I prevNode = i;
i = m_ElementsInBucket.Next(i);
m_ElementsInBucket.Free(prevNode);
}
// Mark the bucket list as empty
m_FirstElement( bucket ) = m_ElementsInBucket.InvalidIndex();
}
//-----------------------------------------------------------------------------
// Ensure capacity
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I >
void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::EnsureCapacity( int count )
{
m_ElementsInBucket.EnsureCapacity( count );
m_BucketsUsedByElement.EnsureCapacity( count );
}
//-----------------------------------------------------------------------------
// Deallocate....
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I >
void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::Purge()
{
m_ElementsInBucket.Purge( );
m_BucketsUsedByElement.Purge( );
}
//-----------------------------------------------------------------------------
// Number of elements allocated in each linked list (should be the same)
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I >
int CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::NumAllocated( void ) const
{
Assert( m_ElementsInBucket.NumAllocated() == m_BucketsUsedByElement.NumAllocated() );
return m_ElementsInBucket.NumAllocated();
}
//-----------------------------------------------------------------------------
// Invalid index for iteration..
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I >
inline S CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::InvalidIndex()
{
return CUtlLinkedList< CElementHandle, I >::InvalidIndex();
}
//-----------------------------------------------------------------------------
// Used to iterate elements in a bucket; I is the iterator
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I >
inline I CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::FirstElement( CBucketHandlePram bucket ) const
{
Assert( m_FirstElement );
return m_FirstElement(bucket);
}
template< class CBucketHandle, class CElementHandle, class S, class I >
inline I CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::NextElement( I idx ) const
{
return m_ElementsInBucket.Next(idx);
}
template< class CBucketHandle, class CElementHandle, class S, class I >
inline CElementHandle CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::Element( I idx ) const
{
return m_ElementsInBucket[idx].m_Element;
}
//-----------------------------------------------------------------------------
// Used to iterate buckets an element lies in; I is the iterator
//-----------------------------------------------------------------------------
template< class CBucketHandle, class CElementHandle, class S, class I >
inline I CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::FirstBucket( CElementHandlePram element ) const
{
Assert( m_FirstBucket );
return m_FirstBucket(element);
}
template< class CBucketHandle, class CElementHandle, class S, class I >
inline I CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::NextBucket( I idx ) const
{
return m_BucketsUsedByElement.Next(idx);
}
template< class CBucketHandle, class CElementHandle, class S, class I >
inline CBucketHandle CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::Bucket( I idx ) const
{
return m_BucketsUsedByElement[idx].m_Bucket;
}
#endif // UTLBIDIRECTIONALSET_H

View File

@@ -0,0 +1,349 @@
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//
// A growable memory class.
//===========================================================================//
#ifndef UTLBLOCKMEMORY_H
#define UTLBLOCKMEMORY_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
#include "tier0/platform.h"
#include "mathlib/mathlib.h"
#include "tier0/memalloc.h"
#include "tier0/memdbgon.h"
#pragma warning (disable:4100)
#pragma warning (disable:4514)
//-----------------------------------------------------------------------------
#ifdef UTBLOCKLMEMORY_TRACK
#define UTLBLOCKMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "||Sum of all UtlBlockMemory||", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
#define UTLBLOCKMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "||Sum of all UtlBlockMemory||", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
#else
#define UTLBLOCKMEMORY_TRACK_ALLOC() ((void)0)
#define UTLBLOCKMEMORY_TRACK_FREE() ((void)0)
#endif
//-----------------------------------------------------------------------------
// The CUtlBlockMemory class:
// A growable memory class that allocates non-sequential blocks, but is indexed sequentially
//-----------------------------------------------------------------------------
template< class T, class I >
class CUtlBlockMemory
{
public:
// constructor, destructor
CUtlBlockMemory( int nGrowSize = 0, int nInitSize = 0 );
~CUtlBlockMemory();
// Set the size by which the memory grows - round up to the next power of 2
void Init( int nGrowSize = 0, int nInitSize = 0 );
// here to match CUtlMemory, but only used by ResetDbgInfo, so it can just return NULL
T* Base() { return NULL; }
const T* Base() const { return NULL; }
class Iterator_t
{
public:
Iterator_t( I i ) : index( i ) {}
I index;
bool operator==( const Iterator_t it ) const { return index == it.index; }
bool operator!=( const Iterator_t it ) const { return index != it.index; }
};
Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); }
Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); }
I GetIndex( const Iterator_t &it ) const { return it.index; }
bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; }
bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); }
Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); }
// element access
T& operator[]( I i );
const T& operator[]( I i ) const;
T& Element( I i );
const T& Element( I i ) const;
// Can we use this index?
bool IsIdxValid( I i ) const;
static I InvalidIndex() { return ( I )-1; }
void Swap( CUtlBlockMemory< T, I > &mem );
// Size
int NumAllocated() const;
int Count() const { return NumAllocated(); }
// Grows memory by max(num,growsize) rounded up to the next power of 2, and returns the allocation index/ptr
void Grow( int num = 1 );
// Makes sure we've got at least this much memory
void EnsureCapacity( int num );
// Memory deallocation
void Purge();
// Purge all but the given number of elements
void Purge( int numElements );
protected:
int Index( int major, int minor ) const { return ( major << m_nIndexShift ) | minor; }
int MajorIndex( int i ) const { return i >> m_nIndexShift; }
int MinorIndex( int i ) const { return i & m_nIndexMask; }
void ChangeSize( int nBlocks );
int NumElementsInBlock() const { return m_nIndexMask + 1; }
T** m_pMemory;
int m_nBlocks;
int m_nIndexMask : 27;
int m_nIndexShift : 5;
};
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
template< class T, class I >
CUtlBlockMemory<T,I>::CUtlBlockMemory( int nGrowSize, int nInitAllocationCount )
: m_pMemory( 0 ), m_nBlocks( 0 ), m_nIndexMask( 0 ), m_nIndexShift( 0 )
{
Init( nGrowSize, nInitAllocationCount );
}
template< class T, class I >
CUtlBlockMemory<T,I>::~CUtlBlockMemory()
{
Purge();
}
//-----------------------------------------------------------------------------
// Fast swap
//-----------------------------------------------------------------------------
template< class T, class I >
void CUtlBlockMemory<T,I>::Swap( CUtlBlockMemory< T, I > &mem )
{
V_swap( m_pMemory, mem.m_pMemory );
V_swap( m_nBlocks, mem.m_nBlocks );
V_swap( m_nIndexMask, mem.m_nIndexMask );
V_swap( m_nIndexShift, mem.m_nIndexShift );
}
//-----------------------------------------------------------------------------
// Set the size by which the memory grows - round up to the next power of 2
//-----------------------------------------------------------------------------
template< class T, class I >
void CUtlBlockMemory<T,I>::Init( int nGrowSize /* = 0 */, int nInitSize /* = 0 */ )
{
Purge();
if ( nGrowSize == 0)
{
// default grow size is smallest size s.t. c++ allocation overhead is ~6% of block size
nGrowSize = ( 127 + sizeof( T ) ) / sizeof( T );
}
nGrowSize = SmallestPowerOfTwoGreaterOrEqual( nGrowSize );
m_nIndexMask = nGrowSize - 1;
m_nIndexShift = 0;
while ( nGrowSize > 1 )
{
nGrowSize >>= 1;
++m_nIndexShift;
}
Assert( m_nIndexMask + 1 == ( 1 << m_nIndexShift ) );
Grow( nInitSize );
}
//-----------------------------------------------------------------------------
// element access
//-----------------------------------------------------------------------------
template< class T, class I >
inline T& CUtlBlockMemory<T,I>::operator[]( I i )
{
Assert( IsIdxValid(i) );
T *pBlock = m_pMemory[ MajorIndex( i ) ];
return pBlock[ MinorIndex( i ) ];
}
template< class T, class I >
inline const T& CUtlBlockMemory<T,I>::operator[]( I i ) const
{
Assert( IsIdxValid(i) );
const T *pBlock = m_pMemory[ MajorIndex( i ) ];
return pBlock[ MinorIndex( i ) ];
}
template< class T, class I >
inline T& CUtlBlockMemory<T,I>::Element( I i )
{
Assert( IsIdxValid(i) );
T *pBlock = m_pMemory[ MajorIndex( i ) ];
return pBlock[ MinorIndex( i ) ];
}
template< class T, class I >
inline const T& CUtlBlockMemory<T,I>::Element( I i ) const
{
Assert( IsIdxValid(i) );
const T *pBlock = m_pMemory[ MajorIndex( i ) ];
return pBlock[ MinorIndex( i ) ];
}
//-----------------------------------------------------------------------------
// Size
//-----------------------------------------------------------------------------
template< class T, class I >
inline int CUtlBlockMemory<T,I>::NumAllocated() const
{
return m_nBlocks * NumElementsInBlock();
}
//-----------------------------------------------------------------------------
// Is element index valid?
//-----------------------------------------------------------------------------
template< class T, class I >
inline bool CUtlBlockMemory<T,I>::IsIdxValid( I i ) const
{
return ( i >= 0 ) && ( MajorIndex( i ) < m_nBlocks );
}
template< class T, class I >
void CUtlBlockMemory<T,I>::Grow( int num )
{
if ( num <= 0 )
return;
int nBlockSize = NumElementsInBlock();
int nBlocks = ( num + nBlockSize - 1 ) / nBlockSize;
ChangeSize( m_nBlocks + nBlocks );
}
template< class T, class I >
void CUtlBlockMemory<T,I>::ChangeSize( int nBlocks )
{
UTLBLOCKMEMORY_TRACK_FREE(); // this must stay before the recalculation of m_nBlocks, since it implicitly uses the old value
int nBlocksOld = m_nBlocks;
m_nBlocks = nBlocks;
UTLBLOCKMEMORY_TRACK_ALLOC(); // this must stay after the recalculation of m_nBlocks, since it implicitly uses the new value
// free old blocks if shrinking
for ( int i = m_nBlocks; i < nBlocksOld; ++i )
{
UTLBLOCKMEMORY_TRACK_FREE();
free( (void*)m_pMemory[ i ] );
}
if ( m_pMemory )
{
MEM_ALLOC_CREDIT_CLASS();
m_pMemory = (T**)realloc( m_pMemory, m_nBlocks * sizeof(T*) );
Assert( m_pMemory );
}
else
{
MEM_ALLOC_CREDIT_CLASS();
m_pMemory = (T**)malloc( m_nBlocks * sizeof(T*) );
Assert( m_pMemory );
}
if ( !m_pMemory )
{
Error( "CUtlBlockMemory overflow!\n" );
}
// allocate new blocks if growing
int nBlockSize = NumElementsInBlock();
for ( int i = nBlocksOld; i < m_nBlocks; ++i )
{
MEM_ALLOC_CREDIT_CLASS();
m_pMemory[ i ] = (T*)malloc( nBlockSize * sizeof( T ) );
Assert( m_pMemory[ i ] );
}
}
//-----------------------------------------------------------------------------
// Makes sure we've got at least this much memory
//-----------------------------------------------------------------------------
template< class T, class I >
inline void CUtlBlockMemory<T,I>::EnsureCapacity( int num )
{
Grow( num - NumAllocated() );
}
//-----------------------------------------------------------------------------
// Memory deallocation
//-----------------------------------------------------------------------------
template< class T, class I >
void CUtlBlockMemory<T,I>::Purge()
{
if ( !m_pMemory )
return;
for ( int i = 0; i < m_nBlocks; ++i )
{
UTLBLOCKMEMORY_TRACK_FREE();
free( (void*)m_pMemory[ i ] );
}
m_nBlocks = 0;
UTLBLOCKMEMORY_TRACK_FREE();
free( (void*)m_pMemory );
m_pMemory = 0;
}
template< class T, class I >
void CUtlBlockMemory<T,I>::Purge( int numElements )
{
Assert( numElements >= 0 );
int nAllocated = NumAllocated();
if ( numElements > nAllocated )
{
// Ensure this isn't a grow request in disguise.
Assert( numElements <= nAllocated );
return;
}
if ( numElements <= 0 )
{
Purge();
return;
}
int nBlockSize = NumElementsInBlock();
int nBlocksOld = m_nBlocks;
int nBlocks = ( numElements + nBlockSize - 1 ) / nBlockSize;
// If the number of blocks is the same as the allocated number of blocks, we are done.
if ( nBlocks == m_nBlocks )
return;
ChangeSize( nBlocks );
}
#include "tier0/memdbgoff.h"
#endif // UTLBLOCKMEMORY_H

1448
public/tier1/utlbuffer.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,246 @@
//====== Copyright (c) Valve Corporation, All rights reserved. =======//
#ifndef TIER1_UTL_BUFFER_STRIDER_HDR
#define TIER1_UTL_BUFFER_STRIDER_HDR
#include "tier1/strtools.h"
//#include "tier0/memdbg_for_headers.h"
template< class T, class A >
class CUtlVector;
class CBufferStrider
{
public:
CBufferStrider( void *pBuffer );
template <typename T> T *Stride( int nCount = 1 );
template <typename T> T StrideUnaligned( );
template <typename T> void StrideUnaligned( T* pOut, int nCount = 1 );
char* StrideString( );
char* StrideString( const void *pEnd );
template <typename T> T Peek( ){ return *(T*)Get(); }
uint8 *Get(){ return m_pBuffer; }
void Set( void *p ){ m_pBuffer = ( uint8 *)p; }
void Align( uint nAlignment ){ m_pBuffer = ( uint8* )( ( uintp( m_pBuffer ) + nAlignment - 1 ) & ~uintp( nAlignment - 1 ) ); }
protected:
uint8 *m_pBuffer;
};
template <typename T>
inline T *CBufferStrider::Stride( int nCount )
{
uint nAlignMask = VALIGNOF( T ) - 1; NOTE_UNUSED( nAlignMask );
AssertDbg( !( uintp( m_pBuffer ) & nAlignMask ) );
T* p = ( T* ) m_pBuffer;
m_pBuffer += sizeof( T ) * nCount;
return p;
}
template <typename T>
inline T CBufferStrider::StrideUnaligned( )
{
T out;
memcpy( &out, m_pBuffer, sizeof( T ) );
m_pBuffer += sizeof( T );
return out;
}
template <typename T>
inline void CBufferStrider::StrideUnaligned( T* pOut, int nCount )
{
memcpy( pOut, m_pBuffer, sizeof( T ) * nCount );
m_pBuffer += sizeof( T ) * nCount;
}
inline char* CBufferStrider::StrideString( const void *pEnd )
{
uint8 *pNextItem = m_pBuffer;
do
{
if ( pNextItem >= ( uint8* ) pEnd )
{
return NULL; // we steppend past end of buffer
}
}
while ( *( pNextItem++ ) );
// found end of string
char *pString = ( char* ) m_pBuffer;
m_pBuffer = pNextItem;
return pString;
}
inline char* CBufferStrider::StrideString( )
{
uint8 *pNextItem = m_pBuffer;
while ( *( pNextItem++ ) ) // this will crash in case of malformed (no terminating NULL) buffer
{
continue;
}
// found end of string
char *pString = ( char* ) m_pBuffer;
m_pBuffer = pNextItem;
return pString;
}
inline
CBufferStrider::CBufferStrider( void *pBuffer )
: m_pBuffer( ( uint8* ) pBuffer )
{
}
#define MULTIBUFFER_ASSERTS
class CMultiBufferCounter
{
public:
CMultiBufferCounter( )
:m_nByteCount( 0 )
#ifdef MULTIBUFFER_ASSERTS
, m_nMaxAlignment( 0 )
, m_nRunAlignment( 0xFFFFFFFF )
#endif
{}
template <typename T>
T* operator()( T *& pDummy, uint nCount )
{
#ifdef MULTIBUFFER_ASSERTS
const uint nAlignMask = VALIGNOF( T ) - 1;
Assert( m_nRunAlignment >= nAlignMask );
m_nRunAlignment &= nAlignMask;
m_nMaxAlignment |= nAlignMask;
#endif
m_nByteCount += sizeof( T ) * nCount;
return NULL; // we didn't allocate anything yet!
}
template< typename T, typename A >
T* operator()( T*& pDummy, const CUtlVector< T, A > &arr )
{
( *this )( pDummy, arr.Count( ) );
return NULL; // we didn't allocate anything yet
}
char *String( const char *& pDummy, const char *pSourceString )
{
if ( pSourceString )
{
( *this )( pDummy, uint( V_strlen( pSourceString ) + 1 ) );
}
return NULL; // we didn't allocate anything yet
}
uint GetByteCount( )const { return m_nByteCount; }
protected:
uint m_nByteCount;
#ifdef MULTIBUFFER_ASSERTS
uint m_nMaxAlignment;
uint m_nRunAlignment;
#endif
};
class CMultiBufferStrider: public CBufferStrider
{
public:
CMultiBufferStrider( void *pBuffer ): CBufferStrider( pBuffer ){}
template <typename T>
T* operator() ( T*& refPtr, uint nCount )
{
refPtr = nCount ? Stride< T >( nCount ) : NULL;
return refPtr;
}
template < typename T, typename A >
T* operator()( T *&refPtr, const CUtlVector< T, A > &arr )
{
if ( arr.IsEmpty( ) )
{
refPtr = NULL;
}
else
{
refPtr = Stride< T >( arr.Count( ) );
V_memcpy( refPtr, arr.Base( ), sizeof( T ) * arr.Count( ) );
}
return refPtr;
}
char *String( const char *& refPtr, const char *pSourceString )
{
if ( pSourceString )
{
uint nBufLen = V_strlen( pSourceString ) + 1;
char *pOut = const_cast< char* >( ( *this )( refPtr, nBufLen ) );
V_memcpy( pOut, pSourceString, nBufLen );
AssertDbg( refPtr == pOut );
return pOut;
}
else
{
return NULL; // we didn't allocate anything
}
}
};
//////////////////////////////////////////////////////////////////////////
// Derive from this buffer and override function Enum( T& ) that should
// enumerate all the pointers and sizes of buffers to be allocated
//
template <typename Derived>
class CMultiBufferHelper
{
public:
CMultiBufferHelper( )
{
m_pMultiBuffer = NULL;
m_nMultiBufferSize = 0;
}
~CMultiBufferHelper( )
{
if ( m_pMultiBuffer )
{
MemAlloc_FreeAligned( m_pMultiBuffer );
m_pMultiBuffer = NULL;
m_nMultiBufferSize = 0;
}
}
uint8 *GetBuffer( ) { return m_pMultiBuffer; }
uint GetBufferSize( ) { return m_nMultiBufferSize; }
uint8 *TakeBuffer( )
{
// forget the buffer
uint8 *pBuffer = m_pMultiBuffer;
m_pMultiBuffer = NULL;
m_nMultiBufferSize = 0;
return pBuffer;
}
protected:
template <typename Ctx >
void ReallocateMultiBuffer( Ctx &context )
{
if ( m_pMultiBuffer )
{
MemAlloc_FreeAligned( m_pMultiBuffer );
}
CMultiBufferCounter byteCounter;
static_cast< Derived* >( this )->OnAllocateMultiBuffer( byteCounter, context );
m_nMultiBufferSize = byteCounter.GetByteCount( );
m_pMultiBuffer = ( uint8* )MemAlloc_AllocAligned( m_nMultiBufferSize, 16 );
CMultiBufferStrider bufferStrider( m_pMultiBuffer );
static_cast< Derived* >( this )->OnAllocateMultiBuffer( bufferStrider, context );
Assert( m_pMultiBuffer + m_nMultiBufferSize == bufferStrider.Get( ) );
}
protected:
uint8 *m_pMultiBuffer;
uint m_nMultiBufferSize;
};
#endif

View File

@@ -0,0 +1,197 @@
//====== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. =======//
//
// Purpose:
//
// $NoKeywords: $
//
// Utilities for serialization/unserialization buffer
//=============================================================================//
#ifndef UTLBUFFERUTIL_H
#define UTLBUFFERUTIL_H
#ifdef _WIN32
#pragma once
#endif
#include "tier1/utlvector.h"
#include "tier1/utlbuffer.h"
//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
class Vector2D;
class Vector;
class Vector4D;
class QAngle;
class Quaternion;
class VMatrix;
class Color;
class CUtlBinaryBlock;
class CUtlString;
class CUtlCharConversion;
class CUtlSymbolLarge;
//-----------------------------------------------------------------------------
// For string serialization, set the delimiter rules
//-----------------------------------------------------------------------------
void SetSerializationDelimiter( CUtlCharConversion *pConv );
void SetSerializationArrayDelimiter( const char *pDelimiter );
//-----------------------------------------------------------------------------
// Standard serialization methods for basic types
//-----------------------------------------------------------------------------
bool Serialize( CUtlBuffer &buf, const bool &src );
bool Unserialize( CUtlBuffer &buf, bool &dest );
bool Serialize( CUtlBuffer &buf, const int &src );
bool Unserialize( CUtlBuffer &buf, int &dest );
bool Serialize( CUtlBuffer &buf, const float &src );
bool Unserialize( CUtlBuffer &buf, float &dest );
bool Serialize( CUtlBuffer &buf, const Vector2D &src );
bool Unserialize( CUtlBuffer &buf, Vector2D &dest );
bool Serialize( CUtlBuffer &buf, const Vector &src );
bool Unserialize( CUtlBuffer &buf, Vector &dest );
bool Serialize( CUtlBuffer &buf, const Vector4D &src );
bool Unserialize( CUtlBuffer &buf, Vector4D &dest );
bool Serialize( CUtlBuffer &buf, const QAngle &src );
bool Unserialize( CUtlBuffer &buf, QAngle &dest );
bool Serialize( CUtlBuffer &buf, const Quaternion &src );
bool Unserialize( CUtlBuffer &buf, Quaternion &dest );
bool Serialize( CUtlBuffer &buf, const VMatrix &src );
bool Unserialize( CUtlBuffer &buf, VMatrix &dest );
bool Serialize( CUtlBuffer &buf, const Color &src );
bool Unserialize( CUtlBuffer &buf, Color &dest );
bool Serialize( CUtlBuffer &buf, const CUtlBinaryBlock &src );
bool Unserialize( CUtlBuffer &buf, CUtlBinaryBlock &dest );
bool Serialize( CUtlBuffer &buf, const CUtlString &src );
bool Unserialize( CUtlBuffer &buf, CUtlString &dest );
bool Serialize( CUtlBuffer &buf, const CUtlSymbolLarge &src );
// There is explicitly no unserialize of CUtlSymbolLarge,
// it requires adding the a string to a specific symbol table.
//-----------------------------------------------------------------------------
// You can use this to check if a type serializes on multiple lines
//-----------------------------------------------------------------------------
template< class T >
inline bool SerializesOnMultipleLines()
{
return false;
}
template< >
inline bool SerializesOnMultipleLines<VMatrix>()
{
return true;
}
template< >
inline bool SerializesOnMultipleLines<CUtlBinaryBlock>()
{
return true;
}
//-----------------------------------------------------------------------------
// Vector serialization
//-----------------------------------------------------------------------------
template< class T >
bool Serialize( CUtlBuffer &buf, const CUtlVector<T> &src )
{
extern const char *s_pUtlBufferUtilArrayDelim;
int nCount = src.Count();
if ( !buf.IsText() )
{
buf.PutInt( nCount );
for ( int i = 0; i < nCount; ++i )
{
::Serialize( buf, src[i] );
}
return buf.IsValid();
}
if ( !SerializesOnMultipleLines<T>() )
{
buf.PutChar('\n');
for ( int i = 0; i < nCount; ++i )
{
::Serialize( buf, src[i] );
if ( s_pUtlBufferUtilArrayDelim && (i != nCount-1) )
{
buf.PutString( s_pUtlBufferUtilArrayDelim );
}
buf.PutChar('\n');
}
}
else
{
for ( int i = 0; i < nCount; ++i )
{
::Serialize( buf, src[i] );
if ( s_pUtlBufferUtilArrayDelim && (i != nCount-1) )
{
buf.PutString( s_pUtlBufferUtilArrayDelim );
}
buf.PutChar(' ');
}
}
return buf.IsValid();
}
template< class T >
bool Unserialize( CUtlBuffer &buf, CUtlVector<T> &dest )
{
dest.RemoveAll();
MEM_ALLOC_CREDIT_FUNCTION();
if ( !buf.IsText() )
{
int nCount = buf.GetInt();
if ( nCount )
{
dest.EnsureCapacity( nCount );
for ( int i = 0; i < nCount; ++i )
{
VerifyEquals( dest.AddToTail(), i );
if ( !::Unserialize( buf, dest[i] ) )
return false;
}
}
return buf.IsValid();
}
while ( true )
{
buf.EatWhiteSpace();
if ( !buf.IsValid() )
break;
int i = dest.AddToTail( );
if ( ! ::Unserialize( buf, dest[i] ) )
return false;
}
return true;
}
#endif // UTLBUFFERUTIL_H

385
public/tier1/utlcommon.h Normal file
View File

@@ -0,0 +1,385 @@
//========= Copyright <20> 2011, Valve Corporation, All rights reserved. ============//
//
// Purpose: common helpers for reuse among various Utl containers
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef UTLCOMMON_H
#define UTLCOMMON_H
#pragma once
#include "strtools.h"
//-----------------------------------------------------------------------------
// Henry Goffin (henryg) was here. Questions? Bugs? Go slap him around a bit.
//-----------------------------------------------------------------------------
// empty_t is the canonical "no-value" type which is fully defined but empty.
struct empty_t {};
// undefined_t is the canonical "undefined" type, used mostly for typedefs;
// parameters of type undefined_t will not compile, which is actually useful
// behavior when it comes to template programming. Google "SFINAE" for info.
struct undefined_t;
// CTypeSelect<sel,A,B>::type is a typedef of A if sel is nonzero, else B
template <int sel, typename A, typename B>
struct CTypeSelect { typedef A type; };
template <typename A, typename B>
struct CTypeSelect<0, A, B> { typedef B type; };
// CTypeEquals<A, B>::value is nonzero if A and B are the same type
template <typename A, typename B, bool bIgnoreConstVolatile = false, bool bIgnoreReference = false>
struct CTypeEquals { enum { value = 0 }; };
template <typename Same>
struct CTypeEquals<Same, Same, false, false> { enum { value = 1 }; };
template <typename A, typename B>
struct CTypeEquals<A, B, true, true> : CTypeEquals< const volatile A&, const volatile B& > {};
template <typename A, typename B>
struct CTypeEquals<A, B, true, false> : CTypeEquals< const volatile A, const volatile B > {};
template <typename A, typename B>
struct CTypeEquals<A, B, false, true> : CTypeEquals< A&, B& > {};
// CUtlKeyValuePair is intended for use with key-lookup containers.
// Because it is specialized for "empty_t" values, one container can
// function as either a set of keys OR a key-value dictionary while
// avoiding storage waste or padding for the empty_t value objects.
template <typename K, typename V>
class CUtlKeyValuePair
{
public:
typedef V ValueReturn_t;
K m_key;
V m_value;
CUtlKeyValuePair() {}
template < typename KInit >
explicit CUtlKeyValuePair( const KInit &k ) : m_key( k ) {}
template < typename KInit, typename VInit >
CUtlKeyValuePair( const KInit &k, const VInit &v ) : m_key( k ), m_value( v ) {}
V &GetValue() { return m_value; }
const V &GetValue() const { return m_value; }
};
template <typename K>
class CUtlKeyValuePair<K, empty_t>
{
public:
typedef const K ValueReturn_t;
K m_key;
CUtlKeyValuePair() {}
template < typename KInit >
explicit CUtlKeyValuePair( const KInit &k ) : m_key( k ) {}
template < typename KInit >
CUtlKeyValuePair( const KInit &k, empty_t ) : m_key( k ) {}
CUtlKeyValuePair( const K &k, const empty_t& ) : m_key( k ) {}
const K &GetValue() const { return m_key; }
};
// Default functors. You can specialize these if your type does
// not implement operator== or operator< in an efficient way for
// some odd reason.
template <typename T> struct DefaultLessFunctor;
template <typename T> struct DefaultEqualFunctor;
// Hashing functor used by hash tables. You can either specialize
// for types which are widely used, or plug a custom functor directly
// into the hash table. If you do roll your own, please read up on
// bit-mixing and the avalanche property; be sure that your values
// are reasonably well-distributed across the entire 32-bit range.
// http://en.wikipedia.org/wiki/Avalanche_effect
// http://home.comcast.net/~bretm/hash/5.html
//
template <typename T> struct DefaultHashFunctor;
// Argument type information. Struct currently contains one or two typedefs:
// typename Arg_t = primary argument type. Usually const T&, sometimes T.
// typename Alt_t = optional alternate type. Usually *undefined*.
//
// Any specializations should be implemented via simple inheritance
// from ArgumentTypeInfoImpl< BestArgType, [optional] AlternateArgType >
//
template <typename T> struct ArgumentTypeInfo;
// Some fundamental building-block functors...
struct StringLessFunctor
{
StringLessFunctor( int i ) {};
StringLessFunctor( void ) {};
inline bool operator!() const { return false; }
bool operator()( const char *a, const char *b ) const
{
return V_strcmp( a, b ) < 0;
}
};
struct StringEqualFunctor { bool operator()( const char *a, const char *b ) const { return V_strcmp( a, b ) == 0; } };
struct CaselessStringLessFunctor { bool operator()( const char *a, const char *b ) const { return V_strcasecmp( a, b ) < 0; } };
struct CaselessStringEqualFunctor { bool operator()( const char *a, const char *b ) const { return V_strcasecmp( a, b ) == 0; } };
struct IdentityHashFunctor { unsigned int operator() ( uint32 s ) const { return s; } };
struct Mix32HashFunctor { unsigned int operator()( uint32 s ) const; };
struct Mix64HashFunctor { unsigned int operator()( uint64 s ) const; };
struct StringHashFunctor { unsigned int operator()( const char* s ) const; };
struct CaselessStringHashFunctor { unsigned int operator()( const char* s ) const; };
struct PointerLessFunctor { bool operator()( const void *a, const void *b ) const { return a < b; } };
struct PointerEqualFunctor { bool operator()( const void *a, const void *b ) const { return a == b; } };
#if defined( PLATFORM_64BITS )
struct PointerHashFunctor { unsigned int operator()( const void* s ) const { return Mix64HashFunctor()( ( uintp ) s ); } };
#else
struct PointerHashFunctor { unsigned int operator()( const void* s ) const { return Mix32HashFunctor()( ( uintp ) s ); } };
#endif
// Generic implementation of Less and Equal functors
template < typename T >
struct DefaultLessFunctor
{
bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a < b; }
bool operator()( typename ArgumentTypeInfo< T >::Alt_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a < b; }
bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Alt_t b ) const { return a < b; }
};
template < typename T >
struct DefaultEqualFunctor
{
bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a == b; }
bool operator()( typename ArgumentTypeInfo< T >::Alt_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a == b; }
bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Alt_t b ) const { return a == b; }
};
// Hashes for basic types
template <> struct DefaultHashFunctor<char> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<signed char> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<unsigned char> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<signed short> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<unsigned short> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<signed int> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<unsigned int> : Mix32HashFunctor { };
#if !defined(PLATFORM_64BITS) || defined(_WIN32)
template <> struct DefaultHashFunctor<signed long> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<unsigned long> : Mix32HashFunctor { };
#elif defined(POSIX)
template <> struct DefaultHashFunctor<signed long> : Mix64HashFunctor { };
template <> struct DefaultHashFunctor<unsigned long> : Mix64HashFunctor { };
#endif
template <> struct DefaultHashFunctor<signed long long> : Mix64HashFunctor { };
template <> struct DefaultHashFunctor<unsigned long long> : Mix64HashFunctor { };
template <> struct DefaultHashFunctor<void*> : PointerHashFunctor { };
template <> struct DefaultHashFunctor<const void*> : PointerHashFunctor { };
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
template <> struct DefaultHashFunctor<wchar_t> : Mix32HashFunctor { };
#endif
// String specializations. If you want to operate on raw values, use
// PointerLessFunctor and friends from the "building-block" section above
template <> struct DefaultLessFunctor<char*> : StringLessFunctor { };
template <> struct DefaultLessFunctor<const char*> : StringLessFunctor { };
template <> struct DefaultEqualFunctor<char*> : StringEqualFunctor { };
template <> struct DefaultEqualFunctor<const char*> : StringEqualFunctor { };
template <> struct DefaultHashFunctor<char*> : StringHashFunctor { };
template <> struct DefaultHashFunctor<const char*> : StringHashFunctor { };
// CUtlString/CUtlConstString are specialized here and not in utlstring.h
// because I consider string datatypes to be fundamental, and don't feel
// comfortable making that header file dependent on this one. (henryg)
class CUtlString;
template < typename T > class CUtlConstStringBase;
template <> struct DefaultLessFunctor<CUtlString> : StringLessFunctor { };
template <> struct DefaultHashFunctor<CUtlString> : StringHashFunctor { };
template <> struct DefaultEqualFunctor<CUtlString> : StringEqualFunctor {};
template < typename T > struct DefaultLessFunctor< CUtlConstStringBase<T> > : StringLessFunctor { };
template < typename T > struct DefaultHashFunctor< CUtlConstStringBase<T> > : StringHashFunctor { };
// Helpers to deduce if a type defines a public AltArgumentType_t typedef:
template < typename T >
struct HasClassAltArgumentType
{
template < typename X > static long Test( typename X::AltArgumentType_t* );
template < typename X > static char Test( ... );
enum { value = ( sizeof( Test< T >( NULL ) ) != sizeof( char ) ) };
};
template < typename T, bool = HasClassAltArgumentType< T >::value >
struct GetClassAltArgumentType { typedef typename T::AltArgumentType_t Result_t; };
template < typename T >
struct GetClassAltArgumentType< T, false > { typedef undefined_t Result_t; };
// Unwrap references; reference types don't have member typedefs.
template < typename T >
struct GetClassAltArgumentType< T&, false > : GetClassAltArgumentType< T > { };
// ArgumentTypeInfoImpl is the base for all ArgumentTypeInfo specializations.
template < typename ArgT, typename AltT = typename GetClassAltArgumentType<ArgT>::Result_t >
struct ArgumentTypeInfoImpl
{
enum { has_alt = 1 };
typedef ArgT Arg_t;
typedef AltT Alt_t;
};
// Handle cases where AltArgumentType_t is typedef'd to undefined_t
template < typename ArgT >
struct ArgumentTypeInfoImpl< ArgT, undefined_t >
{
enum { has_alt = 0 };
typedef ArgT Arg_t;
typedef undefined_t Alt_t;
};
// Handle cases where AltArgumentType_t is typedef'd to the primary type
template < typename ArgT >
struct ArgumentTypeInfoImpl< ArgT, ArgT >
{
enum { has_alt = 0 };
typedef ArgT Arg_t;
typedef undefined_t Alt_t;
};
// By default, everything is passed via const ref and doesn't define an alternate type.
template <typename T> struct ArgumentTypeInfo : ArgumentTypeInfoImpl< const T& > { };
// Small native types are most efficiently passed by value.
template <> struct ArgumentTypeInfo< bool > : ArgumentTypeInfoImpl< bool > { };
template <> struct ArgumentTypeInfo< char > : ArgumentTypeInfoImpl< char > { };
template <> struct ArgumentTypeInfo< signed char > : ArgumentTypeInfoImpl< signed char > { };
template <> struct ArgumentTypeInfo< unsigned char > : ArgumentTypeInfoImpl< unsigned char > { };
template <> struct ArgumentTypeInfo< signed short > : ArgumentTypeInfoImpl< signed short > { };
template <> struct ArgumentTypeInfo< unsigned short > : ArgumentTypeInfoImpl< unsigned short > { };
template <> struct ArgumentTypeInfo< signed int > : ArgumentTypeInfoImpl< signed int > { };
template <> struct ArgumentTypeInfo< unsigned int > : ArgumentTypeInfoImpl< unsigned int > { };
template <> struct ArgumentTypeInfo< signed long > : ArgumentTypeInfoImpl< signed long > { };
template <> struct ArgumentTypeInfo< unsigned long > : ArgumentTypeInfoImpl< unsigned long > { };
template <> struct ArgumentTypeInfo< signed long long > : ArgumentTypeInfoImpl< signed long long > { };
template <> struct ArgumentTypeInfo< unsigned long long > : ArgumentTypeInfoImpl< unsigned long long > { };
template <> struct ArgumentTypeInfo< float > : ArgumentTypeInfoImpl< float > { };
template <> struct ArgumentTypeInfo< double > : ArgumentTypeInfoImpl< double > { };
template <> struct ArgumentTypeInfo< long double > : ArgumentTypeInfoImpl< long double > { };
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
template <> struct ArgumentTypeInfo< wchar_t > : ArgumentTypeInfoImpl< wchar_t > { };
#endif
// Pointers are also most efficiently passed by value.
template < typename T > struct ArgumentTypeInfo< T* > : ArgumentTypeInfoImpl< T* > { };
// Specializations to unwrap const-decorated types and references
template <typename T> struct ArgumentTypeInfo<const T> : ArgumentTypeInfo<T> { };
template <typename T> struct ArgumentTypeInfo<volatile T> : ArgumentTypeInfo<T> { };
template <typename T> struct ArgumentTypeInfo<const volatile T> : ArgumentTypeInfo<T> { };
template <typename T> struct ArgumentTypeInfo<T&> : ArgumentTypeInfo<T> { };
template <typename T> struct DefaultLessFunctor<const T> : DefaultLessFunctor<T> { };
template <typename T> struct DefaultLessFunctor<volatile T> : DefaultLessFunctor<T> { };
template <typename T> struct DefaultLessFunctor<const volatile T> : DefaultLessFunctor<T> { };
template <typename T> struct DefaultLessFunctor<T&> : DefaultLessFunctor<T> { };
template <typename T> struct DefaultEqualFunctor<const T> : DefaultEqualFunctor<T> { };
template <typename T> struct DefaultEqualFunctor<volatile T> : DefaultEqualFunctor<T> { };
template <typename T> struct DefaultEqualFunctor<const volatile T> : DefaultEqualFunctor<T> { };
template <typename T> struct DefaultEqualFunctor<T&> : DefaultEqualFunctor<T> { };
template <typename T> struct DefaultHashFunctor<const T> : DefaultHashFunctor<T> { };
template <typename T> struct DefaultHashFunctor<volatile T> : DefaultHashFunctor<T> { };
template <typename T> struct DefaultHashFunctor<const volatile T> : DefaultHashFunctor<T> { };
template <typename T> struct DefaultHashFunctor<T&> : DefaultHashFunctor<T> { };
// Hash all pointer types as raw pointers by default
template <typename T> struct DefaultHashFunctor< T * > : PointerHashFunctor { };
// Here follow the useful implementations.
// Bob Jenkins's 32-bit mix function.
inline unsigned int Mix32HashFunctor::operator()( uint32 n ) const
{
// Perform a mixture of the bits in n, where each bit
// of the input value has an equal chance to affect each
// bit of the output. This turns tightly clustered input
// values into a smooth distribution.
//
// This takes 16-20 cycles on modern x86 architectures;
// that's roughly the same cost as a mispredicted branch.
// It's also reasonably efficient on PPC-based consoles.
//
// If you're still thinking, "too many instructions!",
// do keep in mind that reading one byte of uncached RAM
// is about 30x slower than executing this code. It pays
// to have a good hash function which minimizes collisions
// (and therefore long lookup chains).
n = ( n + 0x7ed55d16 ) + ( n << 12 );
n = ( n ^ 0xc761c23c ) ^ ( n >> 19 );
n = ( n + 0x165667b1 ) + ( n << 5 );
n = ( n + 0xd3a2646c ) ^ ( n << 9 );
n = ( n + 0xfd7046c5 ) + ( n << 3 );
n = ( n ^ 0xb55a4f09 ) ^ ( n >> 16 );
return n;
}
inline unsigned int Mix64HashFunctor::operator()( uint64 s ) const
{
// Thomas Wang hash, http://www.concentric.net/~ttwang/tech/inthash.htm
s = ( ~s ) + ( s << 21 ); // s = (s << 21) - s - 1;
s = s ^ ( s >> 24 );
s = (s + ( s << 3 ) ) + ( s << 8 ); // s * 265
s = s ^ ( s >> 14 );
s = ( s + ( s << 2 ) ) + ( s << 4 ); // s * 21
s = s ^ ( s >> 28 );
s = s + ( s << 31 );
return (unsigned int)s;
}
// Based on the widely-used FNV-1A string hash with a final
// mixing step to improve dispersion for very small and very
// large hash table sizes.
inline unsigned int StringHashFunctor::operator()( const char* s ) const
{
uint32 h = 2166136261u;
for ( ; *s; ++s )
{
uint32 c = (unsigned char) *s;
h = (h ^ c) * 16777619;
}
return (h ^ (h << 17)) + (h >> 21);
}
// Equivalent to StringHashFunctor on lower-case strings.
inline unsigned int CaselessStringHashFunctor::operator()( const char* s ) const
{
uint32 h = 2166136261u;
for ( ; *s; ++s )
{
uint32 c = (unsigned char) *s;
// Brutally fast branchless ASCII tolower():
// if ((c >= 'A') && (c <= 'Z')) c += ('a' - 'A');
c += (((('A'-1) - c) & (c - ('Z'+1))) >> 26) & 32;
h = (h ^ c) * 16777619;
}
return (h ^ (h << 17)) + (h >> 21);
}
#endif // UTLCOMMON_H

View File

@@ -0,0 +1,97 @@
//========== Copyright (c) Valve Corporation, All rights reserved. ==========//
//
// Purpose: A header describing use of the delegate system. It's hiding
// the highly complex implementation details of the delegate system
//
// $NoKeywords: $
//
//===========================================================================//
#ifndef UTLDELEGATE_H
#define UTLDELEGATE_H
#ifdef _WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// The delegate system: A method of invoking methods, whether they are
// member methods of classes, static methods of classes, or free functions,
// dealing with all the nastiness in differences between how the calls have
// to happen yet works in a highly optimal fashion. For details, see
//
// http://www.codeproject.com/cpp/FastDelegate.asp
//
// The delegate design pattern is described here
//
// http://en.wikipedia.org/wiki/Delegation_(programming)
//-----------------------------------------------------------------------------
#ifdef UTLDELEGATE_USAGE_DEMONSTRATION
//-----------------------------------------------------------------------------
// Here, we show how to use this system (the ifdef UTLDELEGATE_USAGE_DEMONSTRATION is used to get syntax coloring).
//-----------------------------------------------------------------------------
// First, define the functions you wish to call.
int Test1( char *pString, float x );
class CTestClass
{
public:
void Test2();
static float Test3( int x );
};
void Test()
{
CTestClass testClass;
// CUtlDelegate is a class that can be used to invoke methods of classes
// or static functions in a highly efficient manner.
// There are a couple ways to hook up a delegate. One is in a constructor
// Note that the template parameter of CUtlFastDelegate looks like the
// function type: first, you have the return type, then ( parameter list )
CUtlDelegate< int ( char *, float ) > delegate1( &Test1 );
// Another way is to use the UtlMakeDelegate method, allowing you to
// define the delegate later. Note that UtlMakeDelegate does *not* do a heap allocation
CUtlDelegate< void () > delegate2;
delegate2 = UtlMakeDelegate( &testClass, &CTestClass::Test2 );
// A third method is to use the Bind() method of CUtlFastDelegate
// Note that you do not pass in the class pointer for static functions
CUtlDelegate< float ( int ) > delegate3;
delegate3.Bind( &CTestClass::Test3 );
// Use the () operator to invoke the function calls.
int x = delegate1( "hello", 1.0f );
delegate2();
float y = delegate3( 5 );
// Use the Clear() method to unbind a delegate.
delegate1.Clear();
// You can use operator! or IsEmpty() to see if a delegate is bound
if ( !delegate1.IsEmpty() )
{
delegate1( "hello2" );
}
// Delegates maintain an internal non-templatized representation of the
// functions they are bound to called CUtlAbstractDelegate. These are
// useful when keeping a list of untyped delegates or when passing
// delegates across interface boundaries.
const CUtlAbstractDelegate &abstractDelegate3 = delegate3.GetAbstractDelegate();
CUtlDelegate< float ( int ) > delegate4;
delegate4.SetAbstractDelegate( abstractDelegate3 );
delegate4( 10 );
}
#endif // UTLDELEGATE_USAGE_DEMONSTRATION
// Looking in this file may cause blindness.
#include "tier1/utldelegateimpl.h"
#endif // UTLDELEGATE_H

File diff suppressed because it is too large Load Diff

365
public/tier1/utldict.h Normal file
View File

@@ -0,0 +1,365 @@
//====== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. =======//
//
// Purpose: A dictionary mapping from symbol to structure
//
// $Header: $
// $NoKeywords: $
//=============================================================================//
#ifndef UTLDICT_H
#define UTLDICT_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
#include "tier1/utlmap.h"
// Include this because tons of code was implicitly getting utlsymbol or utlvector via utldict.h
#include "tier1/utlsymbol.h"
#include "tier0/memdbgon.h"
enum EDictCompareType
{
k_eDictCompareTypeCaseSensitive=0,
k_eDictCompareTypeCaseInsensitive=1,
k_eDictCompareTypeFilenames // Slashes and backslashes count as the same character..
};
//-----------------------------------------------------------------------------
// A dictionary mapping from symbol to structure
//-----------------------------------------------------------------------------
// This is a useful macro to iterate from start to end in order in a map
#define FOR_EACH_DICT( dictName, iteratorName ) \
for( int iteratorName=dictName.First(); iteratorName != dictName.InvalidIndex(); iteratorName = dictName.Next( iteratorName ) )
// faster iteration, but in an unspecified order
#define FOR_EACH_DICT_FAST( dictName, iteratorName ) \
for ( int iteratorName = 0; iteratorName < dictName.MaxElement(); ++iteratorName ) if ( !dictName.IsValidIndex( iteratorName ) ) continue; else
//-----------------------------------------------------------------------------
// A dictionary mapping from symbol to structure
//-----------------------------------------------------------------------------
template <class T, class I = int >
class CUtlDict
{
public:
typedef const char* KeyType_t;
typedef T ElemType_t;
// constructor, destructor
// Left at growSize = 0, the memory will first allocate 1 element and double in size
// at each increment.
CUtlDict( int compareType = k_eDictCompareTypeCaseInsensitive, int growSize = 0, int initSize = 0 );
~CUtlDict( );
void EnsureCapacity( int );
// gets particular elements
T& Element( I i );
const T& Element( I i ) const;
T& operator[]( I i );
const T& operator[]( I i ) const;
// gets element names
//char *GetElementName( I i );
char const *GetElementName( I i ) const;
void SetElementName( I i, char const *pName );
// Number of elements
unsigned int Count() const;
// Number of allocated slots
I MaxElement() const;
// Checks if a node is valid and in the tree
bool IsValidIndex( I i ) const;
// Invalid index
static I InvalidIndex();
// Insert method (inserts in order)
I Insert( const char *pName, const T &element );
I Insert( const char *pName );
// Find method
I Find( const char *pName ) const;
bool HasElement( const char *pName ) const;
// Remove methods
void RemoveAt( I i );
void Remove( const char *pName );
void RemoveAll( );
// Purge memory
void Purge();
void PurgeAndDeleteElements(); // Call delete on each element.
// Iteration methods
I First() const;
I Next( I i ) const;
// Nested typedefs, for code that might need
// to fish out the index type from a given dict
typedef I IndexType_t;
protected:
typedef CUtlMap<const char *, T, I> DictElementMap_t;
DictElementMap_t m_Elements;
};
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
template <class T, class I>
CUtlDict<T, I>::CUtlDict( int compareType, int growSize, int initSize ) : m_Elements( growSize, initSize )
{
if ( compareType == k_eDictCompareTypeFilenames )
{
m_Elements.SetLessFunc( CaselessStringLessThanIgnoreSlashes );
}
else if ( compareType == k_eDictCompareTypeCaseInsensitive )
{
m_Elements.SetLessFunc( CaselessStringLessThan );
}
else
{
m_Elements.SetLessFunc( StringLessThan );
}
}
template <class T, class I>
CUtlDict<T, I>::~CUtlDict()
{
Purge();
}
template <class T, class I>
inline void CUtlDict<T, I>::EnsureCapacity( int num )
{
return m_Elements.EnsureCapacity( num );
}
//-----------------------------------------------------------------------------
// gets particular elements
//-----------------------------------------------------------------------------
template <class T, class I>
inline T& CUtlDict<T, I>::Element( I i )
{
return m_Elements[i];
}
template <class T, class I>
inline const T& CUtlDict<T, I>::Element( I i ) const
{
return m_Elements[i];
}
//-----------------------------------------------------------------------------
// gets element names
//-----------------------------------------------------------------------------
/*template <class T, class I>
inline char *CUtlDict<T, I>::GetElementName( I i )
{
return const_cast< char* >( m_Elements.Key( i ) );
}*/
template <class T, class I>
inline char const *CUtlDict<T, I>::GetElementName( I i ) const
{
return m_Elements.Key( i );
}
template <class T, class I>
inline T& CUtlDict<T, I>::operator[]( I i )
{
return Element(i);
}
template <class T, class I>
inline const T & CUtlDict<T, I>::operator[]( I i ) const
{
return Element(i);
}
template <class T, class I>
inline void CUtlDict<T, I>::SetElementName( I i, char const *pName )
{
MEM_ALLOC_CREDIT_CLASS();
// TODO: This makes a copy of the old element
// TODO: This relies on the rb tree putting the most recently
// removed element at the head of the insert list
free( const_cast< char* >( m_Elements.Key( i ) ) );
m_Elements.Reinsert( strdup( pName ), i );
}
//-----------------------------------------------------------------------------
// Num elements
//-----------------------------------------------------------------------------
template <class T, class I>
inline unsigned int CUtlDict<T, I>::Count() const
{
return m_Elements.Count();
}
//-----------------------------------------------------------------------------
// Number of allocated slots
//-----------------------------------------------------------------------------
template <class T, class I>
inline I CUtlDict<T, I>::MaxElement() const
{
return m_Elements.MaxElement();
}
//-----------------------------------------------------------------------------
// Checks if a node is valid and in the tree
//-----------------------------------------------------------------------------
template <class T, class I>
inline bool CUtlDict<T, I>::IsValidIndex( I i ) const
{
return m_Elements.IsValidIndex(i);
}
//-----------------------------------------------------------------------------
// Invalid index
//-----------------------------------------------------------------------------
template <class T, class I>
inline I CUtlDict<T, I>::InvalidIndex()
{
return DictElementMap_t::InvalidIndex();
}
//-----------------------------------------------------------------------------
// Delete a node from the tree
//-----------------------------------------------------------------------------
template <class T, class I>
void CUtlDict<T, I>::RemoveAt(I elem)
{
free( const_cast< char* >( m_Elements.Key( elem ) ) );
m_Elements.RemoveAt(elem);
}
//-----------------------------------------------------------------------------
// remove a node in the tree
//-----------------------------------------------------------------------------
template <class T, class I> void CUtlDict<T, I>::Remove( const char *search )
{
I node = Find( search );
if (node != InvalidIndex())
{
RemoveAt(node);
}
}
//-----------------------------------------------------------------------------
// Removes all nodes from the tree
//-----------------------------------------------------------------------------
template <class T, class I>
void CUtlDict<T, I>::RemoveAll()
{
typename DictElementMap_t::IndexType_t index = m_Elements.FirstInorder();
while ( index != m_Elements.InvalidIndex() )
{
const char* p = m_Elements.Key( index );
free( const_cast< char* >( p ) );
index = m_Elements.NextInorder( index );
}
m_Elements.RemoveAll();
}
template <class T, class I>
void CUtlDict<T, I>::Purge()
{
RemoveAll();
}
template <class T, class I>
void CUtlDict<T, I>::PurgeAndDeleteElements()
{
// Delete all the elements.
I index = m_Elements.FirstInorder();
while ( index != m_Elements.InvalidIndex() )
{
const char* p = m_Elements.Key( index );
free( const_cast< char* >( p ) );
delete m_Elements[index];
index = m_Elements.NextInorder( index );
}
m_Elements.RemoveAll();
}
//-----------------------------------------------------------------------------
// inserts a node into the tree
//-----------------------------------------------------------------------------
template <class T, class I>
I CUtlDict<T, I>::Insert( const char *pName, const T &element )
{
MEM_ALLOC_CREDIT_CLASS();
return m_Elements.Insert( strdup( pName ), element );
}
template <class T, class I>
I CUtlDict<T, I>::Insert( const char *pName )
{
MEM_ALLOC_CREDIT_CLASS();
return m_Elements.Insert( strdup( pName ) );
}
//-----------------------------------------------------------------------------
// finds a node in the tree
//-----------------------------------------------------------------------------
template <class T, class I>
I CUtlDict<T, I>::Find( const char *pName ) const
{
MEM_ALLOC_CREDIT_CLASS();
if ( pName )
return m_Elements.Find( pName );
else
return InvalidIndex();
}
//-----------------------------------------------------------------------------
// returns true if we already have this node
//-----------------------------------------------------------------------------
template <class T, class I>
bool CUtlDict<T, I>::HasElement( const char *pName ) const
{
if ( pName )
return m_Elements.IsValidIndex( m_Elements.Find( pName ) );
else
return false;
}
//-----------------------------------------------------------------------------
// Iteration methods
//-----------------------------------------------------------------------------
template <class T, class I>
I CUtlDict<T, I>::First() const
{
return m_Elements.FirstInorder();
}
template <class T, class I>
I CUtlDict<T, I>::Next( I i ) const
{
return m_Elements.NextInorder(i);
}
#include "tier0/memdbgoff.h"
#endif // UTLDICT_H

161
public/tier1/utlencode.h Normal file
View File

@@ -0,0 +1,161 @@
//===== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
//
// Encoder suitable for encoding binary data as key values
//
// Every 3 characters = 4 encoded characters
// Syntax:
// - a ... { A ... [ 0 ... 9
// 0 1 ... 27 28 .. 54 55 .. 64
//
// SRC0 ... SRCN ...
// FL X0 . XN ...
// FL = 6 bits
//
// if Xk == 64 then SRCk is pad
// else
// SRCk = Xk + 64 * ( FL >> ( 2 * k ) % 4 )
//
#ifndef UTLENCODE_H
#define UTLENCODE_H
#pragma once
namespace KvEncoder
{
inline char DecodeChar( char ch )
{
if ( ch == '-' )
return 0;
if ( ch >= 'a' && ch <= '{' )
return 1 + ch - 'a';
if ( ch >= 'A' && ch <= '[' )
return 28 + ch - 'A';
if ( ch >= '0' && ch <= '9' )
return 55 + ch - '0';
return -1;
}
inline char EncodeChar( char ch )
{
if ( ch == 0 )
return '-';
if ( ch >= 1 && ch <= 27 )
return 'a' + ch - 1;
if ( ch >= 28 && ch <= 54 )
return 'A' + ch - 28;
if ( ch >= 55 && ch <= 64 )
return '0' + ch - 55;
return -1;
}
inline unsigned long EncodeByte( unsigned char x )
{
unsigned int iSegment = x / 64;
unsigned int iOffset = x % 64;
return (
( unsigned long ) ( ( iOffset ) & 0xFFFF ) |
( unsigned long ) ( ( ( iSegment ) & 0xFFFF ) << 16 )
);
}
inline unsigned char DecodeByte( int iSegment, int iOffset )
{
return iSegment * 64 + iOffset;
}
inline int GuessEncodedLength( int nLength )
{
return 4 * ( ( nLength + 2 ) / 3 );
}
inline int GuessDecodedLength( int nLength )
{
return 3 * ( ( nLength + 3 ) / 4 );
}
inline BOOL Encode( CUtlBuffer &src, CUtlBuffer &dst )
{
int numBytes = dst.Size();
int nReqLen = GuessEncodedLength( src.TellPut() );
if ( numBytes < nReqLen )
return FALSE;
char *pBase = (char *) dst.Base();
char *pSrc = (char *) src.Base();
int srcBytes = src.TellPut();
while ( srcBytes > 0 )
{
char *pSegs = pBase;
char *pOffs = pBase + 1;
int flags = 0;
for ( int k = 0; k < 3; ++ k )
{
if ( srcBytes -- > 0 )
{
unsigned long enc = EncodeByte( *pSrc ++ );
*( pOffs ++ ) = EncodeChar( enc & 0xFFFF );
flags |= ( enc >> 16 ) << ( 2 * k );
}
else
{
*( pOffs ++ ) = EncodeChar( 64 );
}
}
*pSegs = EncodeChar( flags );
pBase = pOffs;
}
dst.SeekPut( CUtlBuffer::SEEK_HEAD, nReqLen );
return TRUE;
}
inline BOOL Decode( CUtlBuffer &src, CUtlBuffer &dst )
{
int numBytesLimit = dst.Size();
char *pBase = (char *) src.Base();
char *pData = (char *) dst.Base();
char *pBaseEnd = pBase + src.TellPut();
while ( pBase < pBaseEnd )
{
int flags = DecodeChar( *( pBase ++ ) );
if ( -1 == flags )
return FALSE;
for ( int k = 0; k < 3 && pBase < pBaseEnd; ++ k )
{
int off = DecodeChar( *( pBase ++ ) );
if ( off == -1 )
return FALSE;
if ( off == 64 )
continue;
int seg = flags >> ( 2 * k );
seg %= 4;
if ( numBytesLimit --> 0 )
*( pData ++ ) = DecodeByte( seg, off );
else
return FALSE;
}
}
int numBytes = dst.Size() - numBytesLimit;
dst.SeekPut( CUtlBuffer::SEEK_HEAD, numBytes );
return TRUE;
}
}; // namespace KvEncoder
#endif // UTLENCODE_H

241
public/tier1/utlenvelope.h Normal file
View File

@@ -0,0 +1,241 @@
//========== Copyright <20> 2005, Valve Corporation, All rights reserved. ========
//
// Purpose: A class to wrap data for transport over a boundary like a thread
// or window.
//
//=============================================================================
#include "tier1/utlstring.h"
#include "tier0/basetypes.h"
#ifndef UTLENVELOPE_H
#define UTLENVELOPE_H
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
class CUtlDataEnvelope
{
public:
CUtlDataEnvelope( const void *pData, int nBytes );
CUtlDataEnvelope( const CUtlDataEnvelope &from );
~CUtlDataEnvelope();
CUtlDataEnvelope &operator=( const CUtlDataEnvelope &from );
operator void *();
operator void *() const;
private:
void Assign( const void *pData, int nBytes );
void Assign( const CUtlDataEnvelope &from );
void Purge();
// TODO: switch to a reference counted array?
union
{
byte *m_pData;
byte m_data[4];
};
int m_nBytes;
};
//-----------------------------------------------------------------------------
template <typename T>
class CUtlEnvelope : protected CUtlDataEnvelope
{
public:
CUtlEnvelope( const T *pData, int nElems = 1 );
CUtlEnvelope( const CUtlEnvelope<T> &from );
CUtlEnvelope<T> &operator=( const CUtlEnvelope<T> &from );
operator T *();
operator T *() const;
operator void *();
operator void *() const;
};
//-----------------------------------------------------------------------------
template <>
class CUtlEnvelope<const char *>
{
public:
CUtlEnvelope( const char *pData )
{
m_string = pData;
}
CUtlEnvelope( const CUtlEnvelope<const char *> &from )
{
m_string = from.m_string;
}
CUtlEnvelope<const char *> &operator=( const CUtlEnvelope<const char *> &from )
{
m_string = from.m_string;
return *this;
}
operator char *()
{
return (char *) m_string.Get();
}
operator char *() const
{
return (char *) m_string.Get();
}
operator void *()
{
return (void *) m_string.Get();
}
operator void *() const
{
return (void *) m_string.Get();
}
private:
CUtlString m_string;
};
//-----------------------------------------------------------------------------
#include "tier0/memdbgon.h"
inline void CUtlDataEnvelope::Assign( const void *pData, int nBytes )
{
if ( pData )
{
m_nBytes = nBytes;
if ( m_nBytes > 4 )
{
m_pData = new byte[nBytes];
memcpy( m_pData, pData, nBytes );
}
else
{
memcpy( m_data, pData, nBytes );
}
}
else
{
m_pData = NULL;
m_nBytes = 0;
}
}
inline void CUtlDataEnvelope::Assign( const CUtlDataEnvelope &from )
{
Assign( from.operator void *(), from.m_nBytes );
}
inline void CUtlDataEnvelope::Purge()
{
if (m_nBytes > 4)
delete [] m_pData;
m_nBytes = 0;
}
inline CUtlDataEnvelope::CUtlDataEnvelope( const void *pData, int nBytes )
{
Assign( pData, nBytes );
}
inline CUtlDataEnvelope::CUtlDataEnvelope( const CUtlDataEnvelope &from )
{
Assign( from );
}
inline CUtlDataEnvelope::~CUtlDataEnvelope()
{
Purge();
}
inline CUtlDataEnvelope &CUtlDataEnvelope::operator=( const CUtlDataEnvelope &from )
{
Purge();
Assign( from );
return *this;
}
inline CUtlDataEnvelope::operator void *()
{
if ( !m_nBytes )
{
return NULL;
}
return ( m_nBytes > 4) ? m_pData : m_data;
}
inline CUtlDataEnvelope::operator void *() const
{
if ( !m_nBytes )
{
return NULL;
}
return ( m_nBytes > 4) ? (void *)m_pData : (void *)m_data;
}
//-----------------------------------------------------------------------------
template <typename T>
inline CUtlEnvelope<T>::CUtlEnvelope( const T *pData, int nElems )
: CUtlDataEnvelope( pData, sizeof(T) * nElems )
{
}
template <typename T>
inline CUtlEnvelope<T>::CUtlEnvelope( const CUtlEnvelope<T> &from )
: CUtlDataEnvelope( from )
{
}
template <typename T>
inline CUtlEnvelope<T> &CUtlEnvelope<T>::operator=( const CUtlEnvelope<T> &from )
{
CUtlDataEnvelope::operator=( from );
return *this;
}
template <typename T>
inline CUtlEnvelope<T>::operator T *()
{
return (T *)CUtlDataEnvelope::operator void *();
}
template <typename T>
inline CUtlEnvelope<T>::operator T *() const
{
return (T *)( (const_cast<CUtlEnvelope<T> *>(this))->operator T *() );
}
template <typename T>
inline CUtlEnvelope<T>::operator void *()
{
return CUtlDataEnvelope::operator void *();
}
template <typename T>
inline CUtlEnvelope<T>::operator void *() const
{
return ( (const_cast<CUtlEnvelope<T> *>(this))->operator void *() );
}
//-----------------------------------------------------------------------------
#include "tier0/memdbgoff.h"
#endif // UTLENVELOPE_H

View File

@@ -0,0 +1,354 @@
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//
// A growable memory class.
//===========================================================================//
#ifndef UTLFIXEDMEMORY_H
#define UTLFIXEDMEMORY_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
#include "tier0/platform.h"
#include "tier0/memalloc.h"
#include "tier0/memdbgon.h"
#pragma warning (disable:4100)
#pragma warning (disable:4514)
//-----------------------------------------------------------------------------
#ifdef UTLFIXEDMEMORY_TRACK
#define UTLFIXEDMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
#define UTLFIXEDMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
#else
#define UTLFIXEDMEMORY_TRACK_ALLOC() ((void)0)
#define UTLFIXEDMEMORY_TRACK_FREE() ((void)0)
#endif
//-----------------------------------------------------------------------------
// The CUtlFixedMemory class:
// A growable memory class that allocates non-sequential blocks, but is indexed sequentially
//-----------------------------------------------------------------------------
template< class T >
class CUtlFixedMemory
{
public:
// constructor, destructor
CUtlFixedMemory( int nGrowSize = 0, int nInitSize = 0 );
~CUtlFixedMemory();
// Set the size by which the memory grows
void Init( int nGrowSize = 0, int nInitSize = 0 );
// here to match CUtlMemory, but only used by ResetDbgInfo, so it can just return NULL
T* Base() { return NULL; }
const T* Base() const { return NULL; }
protected:
struct BlockHeader_t;
public:
class Iterator_t
{
public:
Iterator_t( BlockHeader_t *p, int i ) : m_pBlockHeader( p ), m_nIndex( i ) {}
BlockHeader_t *m_pBlockHeader;
intp m_nIndex;
bool operator==( const Iterator_t it ) const { return m_pBlockHeader == it.m_pBlockHeader && m_nIndex == it.m_nIndex; }
bool operator!=( const Iterator_t it ) const { return m_pBlockHeader != it.m_pBlockHeader || m_nIndex != it.m_nIndex; }
};
Iterator_t First() const { return m_pBlocks ? Iterator_t( m_pBlocks, 0 ) : InvalidIterator(); }
Iterator_t Next( const Iterator_t &it ) const
{
Assert( IsValidIterator( it ) );
if ( !IsValidIterator( it ) )
return InvalidIterator();
BlockHeader_t * RESTRICT pHeader = it.m_pBlockHeader;
if ( it.m_nIndex + 1 < pHeader->m_nBlockSize )
return Iterator_t( pHeader, it.m_nIndex + 1 );
return pHeader->m_pNext ? Iterator_t( pHeader->m_pNext, 0 ) : InvalidIterator();
}
intp GetIndex( const Iterator_t &it ) const
{
Assert( IsValidIterator( it ) );
if ( !IsValidIterator( it ) )
return InvalidIndex();
return ( intp )( HeaderToBlock( it.m_pBlockHeader ) + it.m_nIndex );
}
bool IsIdxAfter( intp i, const Iterator_t &it ) const
{
Assert( IsValidIterator( it ) );
if ( !IsValidIterator( it ) )
return false;
if ( IsInBlock( i, it.m_pBlockHeader ) )
return i > GetIndex( it );
for ( BlockHeader_t * RESTRICT pbh = it.m_pBlockHeader->m_pNext; pbh; pbh = pbh->m_pNext )
{
if ( IsInBlock( i, pbh ) )
return true;
}
return false;
}
bool IsValidIterator( const Iterator_t &it ) const { return it.m_pBlockHeader && it.m_nIndex >= 0 && it.m_nIndex < it.m_pBlockHeader->m_nBlockSize; }
Iterator_t InvalidIterator() const { return Iterator_t( NULL, INVALID_INDEX ); }
// element access
T& operator[]( intp i );
const T& operator[]( intp i ) const;
T& Element( intp i );
const T& Element( intp i ) const;
// Can we use this index?
bool IsIdxValid( intp i ) const;
// Specify the invalid ('null') index that we'll only return on failure
static const intp INVALID_INDEX = 0; // For use with COMPILE_TIME_ASSERT
static intp InvalidIndex() { return INVALID_INDEX; }
// Size
int NumAllocated() const;
int Count() const { return NumAllocated(); }
// Grows memory by max(num,growsize), and returns the allocation index/ptr
void Grow( int num = 1 );
// Makes sure we've got at least this much memory
void EnsureCapacity( int num );
// Memory deallocation
void Purge();
protected:
// Fast swap - WARNING: Swap invalidates all ptr-based indices!!!
void Swap( CUtlFixedMemory< T > &mem );
bool IsInBlock( intp i, BlockHeader_t *pBlockHeader ) const
{
T *p = ( T* )i;
const T *p0 = HeaderToBlock( pBlockHeader );
return p >= p0 && p < p0 + pBlockHeader->m_nBlockSize;
}
struct BlockHeader_t
{
BlockHeader_t *m_pNext;
intp m_nBlockSize;
};
const T *HeaderToBlock( const BlockHeader_t *pHeader ) const { return ( T* )( pHeader + 1 ); }
const BlockHeader_t *BlockToHeader( const T *pBlock ) const { return ( BlockHeader_t* )( pBlock ) - 1; }
BlockHeader_t* m_pBlocks;
int m_nAllocationCount;
int m_nGrowSize;
};
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
template< class T >
CUtlFixedMemory<T>::CUtlFixedMemory( int nGrowSize, int nInitAllocationCount )
: m_pBlocks( 0 ), m_nAllocationCount( 0 ), m_nGrowSize( 0 )
{
Init( nGrowSize, nInitAllocationCount );
}
template< class T >
CUtlFixedMemory<T>::~CUtlFixedMemory()
{
Purge();
}
//-----------------------------------------------------------------------------
// Fast swap - WARNING: Swap invalidates all ptr-based indices!!!
//-----------------------------------------------------------------------------
template< class T >
void CUtlFixedMemory<T>::Swap( CUtlFixedMemory< T > &mem )
{
V_swap( m_pBlocks, mem.m_pBlocks );
V_swap( m_nAllocationCount, mem.m_nAllocationCount );
V_swap( m_nGrowSize, mem.m_nGrowSize );
}
//-----------------------------------------------------------------------------
// Set the size by which the memory grows - round up to the next power of 2
//-----------------------------------------------------------------------------
template< class T >
void CUtlFixedMemory<T>::Init( int nGrowSize /* = 0 */, int nInitSize /* = 0 */ )
{
Purge();
m_nGrowSize = nGrowSize;
Grow( nInitSize );
}
//-----------------------------------------------------------------------------
// element access
//-----------------------------------------------------------------------------
template< class T >
inline T& CUtlFixedMemory<T>::operator[]( intp i )
{
Assert( IsIdxValid(i) );
return *( T* )i;
}
template< class T >
inline const T& CUtlFixedMemory<T>::operator[]( intp i ) const
{
Assert( IsIdxValid(i) );
return *( T* )i;
}
template< class T >
inline T& CUtlFixedMemory<T>::Element( intp i )
{
Assert( IsIdxValid(i) );
return *( T* )i;
}
template< class T >
inline const T& CUtlFixedMemory<T>::Element( intp i ) const
{
Assert( IsIdxValid(i) );
return *( T* )i;
}
//-----------------------------------------------------------------------------
// Size
//-----------------------------------------------------------------------------
template< class T >
inline int CUtlFixedMemory<T>::NumAllocated() const
{
return m_nAllocationCount;
}
//-----------------------------------------------------------------------------
// Is element index valid?
//-----------------------------------------------------------------------------
template< class T >
inline bool CUtlFixedMemory<T>::IsIdxValid( intp i ) const
{
#ifdef _DEBUG
for ( BlockHeader_t *pbh = m_pBlocks; pbh; pbh = pbh->m_pNext )
{
if ( IsInBlock( i, pbh ) )
return true;
}
return false;
#else
return i != InvalidIndex();
#endif
}
template< class T >
void CUtlFixedMemory<T>::Grow( int num )
{
if ( num <= 0 )
return;
int nBlockSize = m_nGrowSize;
if ( nBlockSize == 0 )
{
if ( m_nAllocationCount )
{
nBlockSize = m_nAllocationCount;
}
else
{
// Compute an allocation which is at least as big as a cache line...
nBlockSize = ( 31 + sizeof( T ) ) / sizeof( T );
Assert( nBlockSize );
}
}
if ( nBlockSize < num )
{
int n = ( num + nBlockSize -1 ) / nBlockSize;
Assert( n * nBlockSize >= num );
Assert( ( n - 1 ) * nBlockSize < num );
nBlockSize *= n;
}
m_nAllocationCount += nBlockSize;
MEM_ALLOC_CREDIT_CLASS();
BlockHeader_t * RESTRICT pBlockHeader = ( BlockHeader_t* )malloc( sizeof( BlockHeader_t ) + nBlockSize * sizeof( T ) );
if ( !pBlockHeader )
{
Error( "CUtlFixedMemory overflow!\n" );
}
pBlockHeader->m_pNext = NULL;
pBlockHeader->m_nBlockSize = nBlockSize;
if ( !m_pBlocks )
{
m_pBlocks = pBlockHeader;
}
else
{
#if 1 // IsIdxAfter assumes that newly allocated blocks are at the end
BlockHeader_t * RESTRICT pbh = m_pBlocks;
while ( pbh->m_pNext )
{
pbh = pbh->m_pNext;
}
pbh->m_pNext = pBlockHeader;
#else
pBlockHeader = m_pBlocks;
pBlockHeader->m_pNext = m_pBlocks;
#endif
}
}
//-----------------------------------------------------------------------------
// Makes sure we've got at least this much memory
//-----------------------------------------------------------------------------
template< class T >
inline void CUtlFixedMemory<T>::EnsureCapacity( int num )
{
Grow( num - NumAllocated() );
}
//-----------------------------------------------------------------------------
// Memory deallocation
//-----------------------------------------------------------------------------
template< class T >
void CUtlFixedMemory<T>::Purge()
{
if ( !m_pBlocks )
return;
for ( BlockHeader_t *pbh = m_pBlocks; pbh; )
{
BlockHeader_t *pFree = pbh;
pbh = pbh->m_pNext;
free( pFree );
}
m_pBlocks = NULL;
m_nAllocationCount = 0;
}
#include "tier0/memdbgoff.h"
#endif // UTLFIXEDMEMORY_H

124
public/tier1/utlflags.h Normal file
View File

@@ -0,0 +1,124 @@
//====== Copyright <20> 1996-2004, Valve Corporation, All rights reserved. =======
//
// Purpose: Simple class to make it easier to deal with flags
//
//=============================================================================
#ifndef UTLFLAGS_H
#define UTLFLAGS_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
//-----------------------------------------------------------------------------
// Simple class to make it easier to deal with flags
//-----------------------------------------------------------------------------
template< class T >
class CUtlFlags
{
public:
CUtlFlags( int nInitialFlags = 0 );
// Flag setting
void SetFlag( int nFlagMask );
void SetFlag( int nFlagMask, bool bEnable );
// Flag clearing
void ClearFlag( int nFlagMask );
void ClearAllFlags();
bool IsFlagSet( int nFlagMask ) const;
// Is any flag set?
bool IsAnyFlagSet() const;
private:
T m_nFlags;
};
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
template< class T >
CUtlFlags<T>::CUtlFlags( int nInitialFlags )
{
// Makes sure we didn't truncate
Assert( nInitialFlags == (T)nInitialFlags );
m_nFlags = (T)nInitialFlags;
}
//-----------------------------------------------------------------------------
// Set flags
//-----------------------------------------------------------------------------
template< class T >
void CUtlFlags<T>::SetFlag( int nFlagMask )
{
// Makes sure we didn't truncate
Assert( nFlagMask == (T)nFlagMask );
m_nFlags |= (T)nFlagMask;
}
template< class T >
void CUtlFlags<T>::SetFlag( int nFlagMask, bool bEnable )
{
// Makes sure we didn't truncate
Assert( nFlagMask == (T)nFlagMask );
if ( bEnable )
{
m_nFlags |= (T)nFlagMask;
}
else
{
m_nFlags &= ~((T)nFlagMask);
}
}
//-----------------------------------------------------------------------------
// Clear flags
//-----------------------------------------------------------------------------
template< class T >
void CUtlFlags<T>::ClearFlag( int nFlagMask )
{
// Makes sure we didn't truncate
Assert( nFlagMask == (T)nFlagMask );
m_nFlags &= ~((T)nFlagMask);
}
template< class T >
void CUtlFlags<T>::ClearAllFlags()
{
m_nFlags = 0;
}
//-----------------------------------------------------------------------------
// Is a flag set?
//-----------------------------------------------------------------------------
template< class T >
bool CUtlFlags<T>::IsFlagSet( int nFlagMask ) const
{
// Makes sure we didn't truncate
Assert( nFlagMask == (T)nFlagMask );
return ( m_nFlags & nFlagMask ) != 0;
}
//-----------------------------------------------------------------------------
// Is any flag set?
//-----------------------------------------------------------------------------
template< class T >
bool CUtlFlags<T>::IsAnyFlagSet() const
{
return m_nFlags != 0;
}
#endif // UTLFLAGS_H

View 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

1299
public/tier1/utlhash.h Normal file

File diff suppressed because it is too large Load Diff

342
public/tier1/utlhashdict.h Normal file
View File

@@ -0,0 +1,342 @@
//========== Copyright <20> 2005, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#ifndef UTLHASHDICT_H
#define UTLHASHDICT_H
#if defined( _WIN32 )
#pragma once
#endif
#include "tier1/utlhash.h"
#include "tier1/generichash.h"
#include "mathlib/mathlib.h"
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
template <typename T, bool bCaseInsensitive = true, bool bDupeStrings = true>
class CUtlHashDict
{
public:
// constructor, destructor
CUtlHashDict( int bucketCount = 16, int growCount = 0, int initCount = 0 );
~CUtlHashDict( );
// gets particular elements
T& Element( unsigned i );
const T& Element( unsigned i ) const;
T& operator[]( unsigned i );
const T& operator[]( unsigned i ) const;
// gets element names
char const *GetElementName( unsigned i ) const;
// Number of elements
int Count() const;
// Checks if a node is valid and in the tree
bool IsValidIndex( unsigned i ) const;
// Invalid index
static unsigned InvalidHandle();
// Insert method (inserts in order)
unsigned Insert( const char *pName, const T &element );
unsigned Insert( const char *pName );
// Find method
unsigned Find( const char *pName ) const;
// Remove methods
void RemoveAt( unsigned i );
void Remove( const char *pName );
void RemoveAll( );
// Purge memory
void Purge();
void PurgeAndDeleteElements(); // Call delete on each element.
// Iteration methods
unsigned First() const;
unsigned Next( unsigned i ) const;
protected:
struct Entry_t
{
const char *pszSymbol;
T value;
};
template <bool bCaseIgnore>
class CCompare
{
public:
CCompare( int ignored ) {}
bool operator()( const Entry_t &entry1, const Entry_t &entry2 ) const
{
return !( ( bCaseIgnore ) ? stricmp( entry1.pszSymbol, entry2.pszSymbol ) : strcmp( entry1.pszSymbol, entry2.pszSymbol ) );
}
};
template <bool bCaseIgnore>
class CHash
{
public:
CHash( int ignored ) {}
unsigned operator()( const Entry_t &entry ) const
{
return !( ( bCaseIgnore ) ? HashStringCaseless( entry.pszSymbol ) : HashString( entry.pszSymbol ) );
}
};
typedef CUtlHash<Entry_t, CCompare<bCaseInsensitive>, CHash<bCaseInsensitive> > CHashTable;
CHashTable m_Elements;
int m_nCount;
};
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::CUtlHashDict( int bucketCount = 16, int growCount = 0, int initCount = 0 ) :
m_Elements( SmallestPowerOfTwoGreaterOrEqual(bucketCount), growCount, initCount )
{
Assert( SmallestPowerOfTwoGreaterOrEqual(bucketCount) <= 0xffff );
}
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::~CUtlHashDict()
{
Purge();
}
//-----------------------------------------------------------------------------
// gets particular elements
//-----------------------------------------------------------------------------
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
inline T& CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Element( unsigned i )
{
return m_Elements[i].value;
}
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
inline const T& CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Element( unsigned i ) const
{
return m_Elements[i].value;
}
//-----------------------------------------------------------------------------
// gets element names
//-----------------------------------------------------------------------------
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
inline char const *CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::GetElementName( unsigned i ) const
{
return m_Elements[i].pszSymbol;
}
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
inline T& CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::operator[]( unsigned i )
{
return m_Elements[i].value;
}
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
inline const T & CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::operator[]( unsigned i ) const
{
return m_Elements[i].value;
}
//-----------------------------------------------------------------------------
// Num elements
//-----------------------------------------------------------------------------
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
inline int CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Count() const
{
Assert( m_nCount == m_Elements.Count() );
return m_nCount;
}
//-----------------------------------------------------------------------------
// Checks if a node is valid and in the tree
//-----------------------------------------------------------------------------
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
inline bool CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::IsValidIndex( unsigned i ) const
{
return m_Elements.IsValidHandle(i);
}
//-----------------------------------------------------------------------------
// Invalid index
//-----------------------------------------------------------------------------
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
inline unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::InvalidHandle()
{
return CHashTable::InvalidHandle();
}
//-----------------------------------------------------------------------------
// Delete a node from the tree
//-----------------------------------------------------------------------------
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::RemoveAt(unsigned elem)
{
if ( bDupeStrings )
{
free( (void *)m_Elements[elem].pszSymbol );
}
m_Elements.Remove(elem);
m_nCount--;
}
//-----------------------------------------------------------------------------
// remove a node in the tree
//-----------------------------------------------------------------------------
template <typename T, bool bCaseInsensitive, bool bDupeStrings> void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Remove( const char *search )
{
unsigned node = Find( search );
if (node != InvalidHandle())
{
RemoveAt(node);
}
}
//-----------------------------------------------------------------------------
// Removes all nodes from the tree
//-----------------------------------------------------------------------------
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::RemoveAll()
{
if ( bDupeStrings )
{
UtlHashHandle_t index = m_Elements.GetFirstHandle();
while ( index != m_Elements.InvalidHandle() )
{
free( (void *)m_Elements[index].pszSymbol );
index = m_Elements.GetNextHandle( index );
}
}
m_Elements.RemoveAll();
m_nCount = 0;
}
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Purge()
{
if ( bDupeStrings )
{
UtlHashHandle_t index = m_Elements.GetFirstHandle();
while ( index != m_Elements.InvalidHandle() )
{
free( (void *)m_Elements[index].pszSymbol );
index = m_Elements.GetNextHandle( index );
}
}
m_Elements.Purge();
m_nCount = 0;
}
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::PurgeAndDeleteElements()
{
// Delete all the elements.
unsigned index = m_Elements.GetFirstHandle();
while ( index != m_Elements.InvalidHandle() )
{
if ( bDupeStrings )
{
free( (void *)m_Elements[index].pszSymbol );
}
delete m_Elements[index].value;
index = m_Elements.GetNextHandle( index );
}
m_Elements.RemoveAll();
m_nCount = 0;
}
//-----------------------------------------------------------------------------
// inserts a node into the tree
//-----------------------------------------------------------------------------
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Insert( const char *pName, const T &element )
{
MEM_ALLOC_CREDIT_CLASS();
m_nCount++;
Entry_t entry =
{
(bDupeStrings) ? strdup( pName ) : pName,
element
};
bool bInserted;
unsigned result = m_Elements.Insert( entry, &bInserted );
if ( bDupeStrings && !bInserted )
{
free( (void *)entry.pszSymbol );
}
return result;
}
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Insert( const char *pName )
{
MEM_ALLOC_CREDIT_CLASS();
m_nCount++;
Entry_t entry =
{
(bDupeStrings) ? strdup( pName ) : pName
};
bool bInserted;
unsigned result = m_Elements.Insert( entry, &bInserted );
if ( bDupeStrings && !bInserted )
{
free( (void *)entry.pszSymbol );
}
return result;
}
//-----------------------------------------------------------------------------
// finds a node in the tree
//-----------------------------------------------------------------------------
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Find( const char *pName ) const
{
MEM_ALLOC_CREDIT_CLASS();
if ( pName )
return m_Elements.Find( *((Entry_t *)&pName) );
else
return InvalidHandle();
}
//-----------------------------------------------------------------------------
// Iteration methods
//-----------------------------------------------------------------------------
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::First() const
{
return m_Elements.GetFirstHandle();
}
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Next( unsigned i ) const
{
return m_Elements.GetNextHandle(i);
}
#endif // UTLHASHDICT_H

997
public/tier1/utlhashtable.h Normal file
View File

@@ -0,0 +1,997 @@
//========= Copyright <20> 2011, Valve Corporation, All rights reserved. ============//
//
// Purpose: a fast growable hashtable with stored hashes, L2-friendly behavior.
// Useful as a string dictionary or a low-overhead set/map for small POD types.
//
// Usage notes:
// - handles are NOT STABLE across element removal! use RemoveAndAdvance()
// if you are removing elements while iterating through the hashtable.
// Use CUtlStableHashtable if you need stable handles (less efficient).
// - handles are also NOT STABLE across element insertion. The handle
// resulting from the insertion of an element may not retreive the
// same (or any!) element after further insertions. Again, use
// CUtlStableHashtable if you need stable handles
// - Insert() first searches for an existing match and returns it if found
// - a value type of "empty_t" can be used to eliminate value storage and
// switch Element() to return const Key references instead of values
// - an extra user flag bit is accessible via Get/SetUserFlag()
// - hash function pointer / functor is exposed via GetHashRef()
// - comparison function pointer / functor is exposed via GetEqualRef()
// - if your value type cannot be copy-constructed, use key-only Insert()
// to default-initialize the value and then manipulate it afterwards.
// - The reason that UtlHashtable permutes itself and invalidates
// iterators is to make it faster in the case where you are not
// tracking iterators. If you use it as a set or a map ("is this
// value a member?") as opposed to a long-term container, then you
// probably don't need stable iterators. Hashtable tries to place
// newly inserted data in the primary hash slot, making an
// assumption that if you inserted it recently, you're more likely
// to access it than if you inserted something a long time
// ago. It's effectively trying to minimize cache misses for hot
// data if you add and remove a lot.
// If you don't care too much about cache misses, UtlStableHashtable
// is what you're looking for
//
// Implementation notes:
// - overall hash table load is kept between .25 and .75
// - items which would map to the same ideal slot are chained together
// - chained items are stored sequentially in adjacent free spaces
// - "root" entries are prioritized over chained entries; if a
// slot is not occupied by an item in its root position, the table
// is guaranteed to contain no keys which would hash to that slot.
// - new items go at the head of the chain (ie, in their root slot)
// and evict / "bump" any chained entries which occupy that slot
// - chain-following skips over unused holes and continues examining
// table entries until a chain entry with FLAG_LAST is encountered
//
// CUtlHashtable< uint32 > setOfIntegers;
// CUtlHashtable< const char* > setOfStringPointers;
// CUtlHashtable< int, CUtlVector<blah_t> > mapFromIntsToArrays;
//
// $NoKeywords: $
//
// A closed-form (open addressing) hashtable with linear sequential probing.
//=============================================================================//
#ifndef UTLHASHTABLE_H
#define UTLHASHTABLE_H
#pragma once
#include "utlcommon.h"
#include "utlmemory.h"
#include "mathlib/mathlib.h"
#include "utllinkedlist.h"
//-----------------------------------------------------------------------------
// Henry Goffin (henryg) was here. Questions? Bugs? Go slap him around a bit.
//-----------------------------------------------------------------------------
typedef unsigned int UtlHashHandle_t;
#define FOR_EACH_HASHTABLE( table, iter ) \
for ( UtlHashHandle_t iter = (table).FirstHandle(); iter != (table).InvalidHandle(); iter = (table).NextHandle( iter ) )
// CUtlHashtableEntry selects between 16 and 32 bit storage backing
// for flags_and_hash depending on the size of the stored types.
template < typename KeyT, typename ValueT = empty_t >
class CUtlHashtableEntry
{
public:
typedef CUtlKeyValuePair< KeyT, ValueT > KVPair;
enum { INT16_STORAGE = ( sizeof( KVPair ) <= 2 ) };
typedef typename CTypeSelect< INT16_STORAGE, int16, int32 >::type storage_t;
enum
{
FLAG_FREE = INT16_STORAGE ? 0x8000 : 0x80000000, // must be high bit for IsValid and IdealIndex to work
FLAG_LAST = INT16_STORAGE ? 0x4000 : 0x40000000,
MASK_HASH = INT16_STORAGE ? 0x3FFF : 0x3FFFFFFF
};
storage_t flags_and_hash;
storage_t data[ ( sizeof(KVPair) + sizeof(storage_t) - 1 ) / sizeof(storage_t) ];
bool IsValid() const { return flags_and_hash >= 0; }
void MarkInvalid() { int32 flag = FLAG_FREE; flags_and_hash = (storage_t)flag; }
const KVPair *Raw() const { return reinterpret_cast< const KVPair * >( &data[0] ); }
const KVPair *operator->() const { Assert( IsValid() ); return reinterpret_cast< const KVPair * >( &data[0] ); }
KVPair *Raw() { return reinterpret_cast< KVPair * >( &data[0] ); }
KVPair *operator->() { Assert( IsValid() ); return reinterpret_cast< KVPair * >( &data[0] ); }
// Returns the ideal index of the data in this slot, or all bits set if invalid
uint32 FORCEINLINE IdealIndex( uint32 slotmask ) const { return IdealIndex( flags_and_hash, slotmask ) | ( (int32)flags_and_hash >> 31 ); }
// Use template tricks to fully define only one function that takes either 16 or 32 bits
// and performs different logic without using "if ( INT16_STORAGE )", because GCC and MSVC
// sometimes have trouble removing the constant branch, which is dumb... but whatever.
// 16-bit hashes are simply too narrow for large hashtables; more mask bits than hash bits!
// So we duplicate the hash bits. (Note: h *= MASK_HASH+2 is the same as h += h<<HASH_BITS)
typedef typename CTypeSelect< INT16_STORAGE, int16, undefined_t >::type uint32_if16BitStorage;
typedef typename CTypeSelect< INT16_STORAGE, undefined_t, int32 >::type uint32_if32BitStorage;
static FORCEINLINE uint32 IdealIndex( uint32_if16BitStorage h, uint32 m ) { h &= MASK_HASH; h *= MASK_HASH + 2; return h & m; }
static FORCEINLINE uint32 IdealIndex( uint32_if32BitStorage h, uint32 m ) { return h & m; }
// More efficient than memcpy for the small types that are stored in a hashtable
void MoveDataFrom( CUtlHashtableEntry &src )
{
storage_t * RESTRICT srcData = &src.data[0];
for ( int i = 0; i < ARRAYSIZE( data ); ++i ) { data[i] = srcData[i]; }
}
};
template <typename KeyT, typename ValueT = empty_t, typename KeyHashT = DefaultHashFunctor<KeyT>, typename KeyIsEqualT = DefaultEqualFunctor<KeyT>, typename AlternateKeyT = typename ArgumentTypeInfo<KeyT>::Alt_t >
class CUtlHashtable
{
public:
typedef UtlHashHandle_t handle_t;
protected:
typedef CUtlKeyValuePair<KeyT, ValueT> KVPair;
typedef typename ArgumentTypeInfo<KeyT>::Arg_t KeyArg_t;
typedef typename ArgumentTypeInfo<ValueT>::Arg_t ValueArg_t;
typedef typename ArgumentTypeInfo<AlternateKeyT>::Arg_t KeyAlt_t;
typedef CUtlHashtableEntry< KeyT, ValueT > entry_t;
enum { FLAG_FREE = entry_t::FLAG_FREE };
enum { FLAG_LAST = entry_t::FLAG_LAST };
enum { MASK_HASH = entry_t::MASK_HASH };
CUtlMemory< entry_t > m_table;
int m_nUsed;
int m_nMinSize;
bool m_bSizeLocked;
KeyIsEqualT m_eq;
KeyHashT m_hash;
// Allocate an empty table and then re-insert all existing entries.
void DoRealloc( int size );
// Move an existing entry to a free slot, leaving a hole behind
void BumpEntry( unsigned int idx );
// Insert an unconstructed KVPair at the primary slot
int DoInsertUnconstructed( unsigned int h, bool allowGrow );
// Implementation for Insert functions, constructs a KVPair
// with either a default-construted or copy-constructed value
template <typename KeyParamT> handle_t DoInsert( KeyParamT k, unsigned int h, bool* pDidInsert );
template <typename KeyParamT> handle_t DoInsert( KeyParamT k, typename ArgumentTypeInfo<ValueT>::Arg_t v, unsigned int h, bool* pDidInsert );
template <typename KeyParamT> handle_t DoInsertNoCheck( KeyParamT k, typename ArgumentTypeInfo<ValueT>::Arg_t v, unsigned int h );
// Key lookup. Can also return previous-in-chain if result is chained.
template <typename KeyParamT> handle_t DoLookup( KeyParamT x, unsigned int h, handle_t *pPreviousInChain ) const;
// Remove single element by key + hash. Returns the index of the new hole
// that was created. Returns InvalidHandle() if element was not found.
template <typename KeyParamT> int DoRemove( KeyParamT x, unsigned int h );
// Friend CUtlStableHashtable so that it can call our Do* functions directly
template < typename K, typename V, typename S, typename H, typename E, typename A > friend class CUtlStableHashtable;
public:
explicit CUtlHashtable( int minimumSize = 32 )
: m_nUsed(0), m_nMinSize(MAX(8, minimumSize)), m_bSizeLocked(false), m_eq(), m_hash() { }
CUtlHashtable( int minimumSize, const KeyHashT &hash, KeyIsEqualT const &eq = KeyIsEqualT() )
: m_nUsed(0), m_nMinSize(MAX(8, minimumSize)), m_bSizeLocked(false), m_eq(eq), m_hash(hash) { }
CUtlHashtable( entry_t* pMemory, unsigned int nCount, const KeyHashT &hash = KeyHashT(), KeyIsEqualT const &eq = KeyIsEqualT() )
: m_nUsed(0), m_nMinSize(8), m_bSizeLocked(false), m_eq(eq), m_hash(hash) { SetExternalBuffer( pMemory, nCount ); }
~CUtlHashtable() { RemoveAll(); }
CUtlHashtable &operator=( CUtlHashtable const &src );
// Set external memory
void SetExternalBuffer( byte* pRawBuffer, unsigned int nBytes, bool bAssumeOwnership = false, bool bGrowable = false );
void SetExternalBuffer( entry_t* pBuffer, unsigned int nSize, bool bAssumeOwnership = false, bool bGrowable = false );
// Functor/function-pointer access
KeyHashT& GetHashRef() { return m_hash; }
KeyIsEqualT& GetEqualRef() { return m_eq; }
KeyHashT const &GetHashRef() const { return m_hash; }
KeyIsEqualT const &GetEqualRef() const { return m_eq; }
// Handle validation
bool IsValidHandle( handle_t idx ) const { return (unsigned)idx < (unsigned)m_table.Count() && m_table[idx].IsValid(); }
static handle_t InvalidHandle() { return (handle_t) -1; }
// Iteration functions
handle_t FirstHandle() const { return NextHandle( (handle_t) -1 ); }
handle_t NextHandle( handle_t start ) const;
// Returns the number of unique keys in the table
int Count() const { return m_nUsed; }
// Key lookup, returns InvalidHandle() if not found
handle_t Find( KeyArg_t k ) const { return DoLookup<KeyArg_t>( k, m_hash(k), NULL ); }
handle_t Find( KeyArg_t k, unsigned int hash) const { Assert( hash == m_hash(k) ); return DoLookup<KeyArg_t>( k, hash, NULL ); }
// Alternate-type key lookup, returns InvalidHandle() if not found
handle_t Find( KeyAlt_t k ) const { return DoLookup<KeyAlt_t>( k, m_hash(k), NULL ); }
handle_t Find( KeyAlt_t k, unsigned int hash) const { Assert( hash == m_hash(k) ); return DoLookup<KeyAlt_t>( k, hash, NULL ); }
// True if the key is in the table
bool HasElement( KeyArg_t k ) const { return InvalidHandle() != Find( k ); }
bool HasElement( KeyAlt_t k ) const { return InvalidHandle() != Find( k ); }
// Key insertion or lookup, always returns a valid handle
// Using a different prototype for InsertIfNotFound since it could be confused with Insert if the ValueArg_t is a bool*
handle_t Insert( KeyArg_t k ) { return DoInsert<KeyArg_t>( k, m_hash(k), nullptr ); }
handle_t InsertIfNotFound( KeyArg_t k, bool* pDidInsert ) { return DoInsert<KeyArg_t>( k, m_hash( k ), pDidInsert ); }
handle_t Insert( KeyArg_t k, ValueArg_t v, bool *pDidInsert = nullptr ) { return DoInsert<KeyArg_t>( k, v, m_hash(k), pDidInsert ); }
handle_t Insert( KeyArg_t k, ValueArg_t v, unsigned int hash, bool *pDidInsert = nullptr ) { Assert( hash == m_hash(k) ); return DoInsert<KeyArg_t>( k, v, hash, pDidInsert ); }
// Alternate-type key insertion or lookup, always returns a valid handle
// Using a different prototype for InsertIfNotFound since it could be confused with Insert if the ValueArg_t is a bool*
handle_t Insert( KeyAlt_t k ) { return DoInsert<KeyAlt_t>( k, m_hash(k), nullptr ); }
handle_t InsertIfNotFound( KeyAlt_t k, bool* pDidInsert ) { return DoInsert<KeyAlt_t>( k, m_hash( k ), pDidInsert ); }
handle_t Insert( KeyAlt_t k, ValueArg_t v, bool *pDidInsert = NULL ) { return DoInsert<KeyAlt_t>( k, v, m_hash(k), pDidInsert ); }
handle_t Insert( KeyAlt_t k, ValueArg_t v, unsigned int hash, bool *pDidInsert = NULL ) { Assert( hash == m_hash(k) ); return DoInsert<KeyAlt_t>( k, v, hash, pDidInsert ); }
// Key removal, returns false if not found
bool Remove( KeyArg_t k ) { return DoRemove<KeyArg_t>( k, m_hash(k) ) >= 0; }
bool Remove( KeyArg_t k, unsigned int hash ) { Assert( hash == m_hash(k) ); return DoRemove<KeyArg_t>( k, hash ) >= 0; }
// Alternate-type key removal, returns false if not found
bool Remove( KeyAlt_t k ) { return DoRemove<KeyAlt_t>( k, m_hash(k) ) >= 0; }
bool Remove( KeyAlt_t k, unsigned int hash ) { Assert( hash == m_hash(k) ); return DoRemove<KeyAlt_t>( k, hash ) >= 0; }
// Remove while iterating, returns the next handle for forward iteration
// Note: aside from this, ALL handles are invalid if an element is removed
handle_t RemoveAndAdvance( handle_t idx );
// Remove by handle, convenient when you look up a handle and do something with it before removing the element
void RemoveByHandle( handle_t idx );
// Nuke contents
void RemoveAll();
// Nuke and release memory.
void Purge() { RemoveAll(); m_table.Purge(); }
// Reserve table capacity up front to avoid reallocation during insertions
void Reserve( int expected ) { if ( expected > m_nUsed ) DoRealloc( expected * 4 / 3 ); }
// Shrink to best-fit size, re-insert keys for optimal lookup
void Compact( bool bMinimal ) { DoRealloc( bMinimal ? m_nUsed : ( m_nUsed * 4 / 3 ) ); }
// Access functions. Note: if ValueT is empty_t, all functions return const keys.
typedef typename KVPair::ValueReturn_t Element_t;
KeyT const &Key( handle_t idx ) const { return m_table[idx]->m_key; }
Element_t const &Element( handle_t idx ) const { return m_table[idx]->GetValue(); }
Element_t &Element(handle_t idx) { return m_table[idx]->GetValue(); }
Element_t const &operator[]( handle_t idx ) const { return m_table[idx]->GetValue(); }
Element_t &operator[]( handle_t idx ) { return m_table[idx]->GetValue(); }
void ReplaceKey( handle_t idx, KeyArg_t k ) { Assert( m_eq( m_table[idx]->m_key, k ) && m_hash( k ) == m_hash( m_table[idx]->m_key ) ); m_table[idx]->m_key = k; }
void ReplaceKey( handle_t idx, KeyAlt_t k ) { Assert( m_eq( m_table[idx]->m_key, k ) && m_hash( k ) == m_hash( m_table[idx]->m_key ) ); m_table[idx]->m_key = k; }
Element_t const &Get( KeyArg_t k, Element_t const &defaultValue ) const { handle_t h = Find( k ); if ( h != InvalidHandle() ) return Element( h ); return defaultValue; }
Element_t const &Get( KeyAlt_t k, Element_t const &defaultValue ) const { handle_t h = Find( k ); if ( h != InvalidHandle() ) return Element( h ); return defaultValue; }
Element_t const *GetPtr( KeyArg_t k ) const { handle_t h = Find(k); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
Element_t const *GetPtr( KeyAlt_t k ) const { handle_t h = Find(k); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
Element_t *GetPtr( KeyArg_t k ) { handle_t h = Find( k ); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
Element_t *GetPtr( KeyAlt_t k ) { handle_t h = Find( k ); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
// Swap memory and contents with another identical hashtable
// (NOTE: if using function pointers or functors with state,
// it is up to the caller to ensure that they are compatible!)
void Swap( CUtlHashtable &other ) { m_table.Swap(other.m_table); ::V_swap(m_nUsed, other.m_nUsed); }
// GetMemoryUsage returns all memory held by this class
// and its held classes. It does not include sizeof(*this).
size_t GetMemoryUsage() const
{
return m_table.AllocSize();
}
size_t GetReserveCount( )const
{
return m_table.Count();
}
#if _DEBUG
// Validate the integrity of the hashtable
void DbgCheckIntegrity() const;
#endif
private:
CUtlHashtable(const CUtlHashtable& copyConstructorIsNotImplemented);
};
// Set external memory (raw byte buffer, best-fit)
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
void CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::SetExternalBuffer( byte* pRawBuffer, unsigned int nBytes, bool bAssumeOwnership, bool bGrowable )
{
AssertDbg( ((uintptr_t)pRawBuffer % VALIGNOF(int)) == 0 );
uint32 bestSize = LargestPowerOfTwoLessThanOrEqual( nBytes / sizeof(entry_t) );
Assert( bestSize != 0 && bestSize*sizeof(entry_t) <= nBytes );
return SetExternalBuffer( (entry_t*) pRawBuffer, bestSize, bAssumeOwnership, bGrowable );
}
// Set external memory (typechecked, must be power of two)
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
void CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::SetExternalBuffer( entry_t* pBuffer, unsigned int nSize, bool bAssumeOwnership, bool bGrowable )
{
Assert( IsPowerOfTwo(nSize) );
Assert( m_nUsed == 0 );
for ( uint i = 0; i < nSize; ++i )
pBuffer[i].MarkInvalid();
if ( bAssumeOwnership )
m_table.AssumeMemory( pBuffer, nSize );
else
m_table.SetExternalBuffer( pBuffer, nSize );
m_bSizeLocked = !bGrowable;
}
// Allocate an empty table and then re-insert all existing entries.
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
void CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DoRealloc( int size )
{
Assert( !m_bSizeLocked );
size = SmallestPowerOfTwoGreaterOrEqual( MAX( m_nMinSize, size ) );
Assert( size > 0 && (uint)size <= entry_t::IdealIndex( ~0, 0x1FFFFFFF ) ); // reasonable power of 2
Assert( size > m_nUsed );
CUtlMemory<entry_t> oldTable;
oldTable.Swap( m_table );
entry_t * RESTRICT const pOldBase = oldTable.Base();
m_table.EnsureCapacity( size );
entry_t * const pNewBase = m_table.Base();
for ( int i = 0; i < size; ++i )
pNewBase[i].MarkInvalid();
int nLeftToMove = m_nUsed;
m_nUsed = 0;
for ( int i = oldTable.Count() - 1; i >= 0; --i )
{
if ( pOldBase[i].IsValid() )
{
int newIdx = DoInsertUnconstructed( pOldBase[i].flags_and_hash, false );
pNewBase[newIdx].MoveDataFrom( pOldBase[i] );
if ( --nLeftToMove == 0 )
break;
}
}
Assert( nLeftToMove == 0 );
}
// Move an existing entry to a free slot, leaving a hole behind
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
void CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::BumpEntry( unsigned int idx )
{
Assert( m_table[idx].IsValid() );
Assert( m_nUsed < m_table.Count() );
entry_t* table = m_table.Base();
unsigned int slotmask = m_table.Count()-1;
unsigned int new_flags_and_hash = table[idx].flags_and_hash & (FLAG_LAST | MASK_HASH);
unsigned int chainid = entry_t::IdealIndex( new_flags_and_hash, slotmask );
// Look for empty slots scanning forward, stripping FLAG_LAST as we go.
// Note: this potentially strips FLAG_LAST from table[idx] if we pass it
int newIdx = chainid; // start at ideal slot
for ( ; ; newIdx = (newIdx + 1) & slotmask )
{
if ( table[newIdx].IdealIndex( slotmask ) == chainid )
{
if ( table[newIdx].flags_and_hash & FLAG_LAST )
{
table[newIdx].flags_and_hash &= ~FLAG_LAST;
new_flags_and_hash |= FLAG_LAST;
}
continue;
}
if ( table[newIdx].IsValid() )
{
continue;
}
break;
}
// Did we pick something closer to the ideal slot, leaving behind a
// FLAG_LAST bit on the current slot because we didn't scan past it?
if ( table[idx].flags_and_hash & FLAG_LAST )
{
#ifdef _DEBUG
Assert( new_flags_and_hash & FLAG_LAST );
// Verify logic: we must have moved to an earlier slot, right?
uint offset = ((uint)idx - chainid + slotmask + 1) & slotmask;
uint newOffset = ((uint)newIdx - chainid + slotmask + 1) & slotmask;
Assert( newOffset < offset );
#endif
// Scan backwards from old to new location, depositing FLAG_LAST on
// the first match we find. (+slotmask) is the same as (-1) without
// having to make anyone think about two's complement shenanigans.
int scan = (idx + slotmask) & slotmask;
while ( scan != newIdx )
{
if ( table[scan].IdealIndex( slotmask ) == chainid )
{
table[scan].flags_and_hash |= FLAG_LAST;
new_flags_and_hash &= ~FLAG_LAST;
break;
}
scan = (scan + slotmask) & slotmask;
}
}
// Move entry to the free slot we found, leaving a hole at idx
table[newIdx].flags_and_hash = new_flags_and_hash;
table[newIdx].MoveDataFrom( table[idx] );
table[idx].MarkInvalid();
}
// Insert a value at the root position for that value's hash chain.
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
int CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DoInsertUnconstructed( unsigned int h, bool allowGrow )
{
if ( allowGrow && !m_bSizeLocked )
{
// Keep the load factor between .25 and .75
int newSize = m_nUsed + 1;
if ( ( newSize*4 < m_table.Count() && m_table.Count() > m_nMinSize*2 ) || newSize*4 > m_table.Count()*3 )
{
DoRealloc( newSize * 4 / 3 );
}
}
Assert( m_nUsed < m_table.Count() );
++m_nUsed;
entry_t* table = m_table.Base();
unsigned int slotmask = m_table.Count()-1;
unsigned int new_flags_and_hash = FLAG_LAST | (h & MASK_HASH);
unsigned int idx = entry_t::IdealIndex( h, slotmask );
if ( table[idx].IdealIndex( slotmask ) == idx )
{
// There is already an entry in this chain.
new_flags_and_hash &= ~FLAG_LAST;
BumpEntry(idx);
}
else if ( table[idx].IsValid() )
{
// Somebody else is living in our ideal index but does not belong
// to our entry chain; move it out of the way, start a new chain.
BumpEntry(idx);
}
table[idx].flags_and_hash = new_flags_and_hash;
return idx;
}
// Key lookup. Can also return previous-in-chain if result is a chained slot.
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
template <typename KeyParamT>
UtlHashHandle_t CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DoLookup( KeyParamT x, unsigned int h, handle_t *pPreviousInChain ) const
{
if ( m_nUsed == 0 )
{
// Empty table.
return (handle_t) -1;
}
const entry_t* table = m_table.Base();
unsigned int slotmask = m_table.Count()-1;
Assert( m_table.Count() > 0 && (slotmask & m_table.Count()) == 0 );
unsigned int chainid = entry_t::IdealIndex( h, slotmask );
unsigned int idx = chainid;
if ( table[idx].IdealIndex( slotmask ) != chainid )
{
// Nothing in root position? No match.
return (handle_t) -1;
}
// Linear scan until found or end of chain
handle_t lastIdx = (handle_t) -1;
while (1)
{
// Only examine this slot if it is valid and belongs to our hash chain
if ( table[idx].IdealIndex( slotmask ) == chainid )
{
// Test the full-width hash to avoid unnecessary calls to m_eq()
if ( ((table[idx].flags_and_hash ^ h) & MASK_HASH) == 0 && m_eq( table[idx]->m_key, x ) )
{
// Found match!
if (pPreviousInChain)
*pPreviousInChain = lastIdx;
return (handle_t) idx;
}
if ( table[idx].flags_and_hash & FLAG_LAST )
{
// End of chain. No match.
return (handle_t) -1;
}
lastIdx = (handle_t) idx;
}
idx = (idx + 1) & slotmask;
}
}
// Key insertion, or return index of existing key if found
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
template <typename KeyParamT>
UtlHashHandle_t CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DoInsert( KeyParamT k, unsigned int h, bool* pDidInsert )
{
handle_t idx = DoLookup<KeyParamT>( k, h, NULL );
bool bShouldInsert = ( idx == (handle_t)-1 );
if ( pDidInsert )
{
*pDidInsert = bShouldInsert;
}
if ( bShouldInsert )
{
idx = (handle_t) DoInsertUnconstructed( h, true );
Construct( m_table[ idx ].Raw(), k );
}
return idx;
}
// Key insertion, or return index of existing key if found
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
template <typename KeyParamT>
UtlHashHandle_t CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DoInsert( KeyParamT k, typename ArgumentTypeInfo<ValueT>::Arg_t v, unsigned int h, bool *pDidInsert )
{
handle_t idx = DoLookup<KeyParamT>( k, h, NULL );
if ( idx == (handle_t) -1 )
{
idx = (handle_t) DoInsertUnconstructed( h, true );
Construct( m_table[ idx ].Raw(), k, v );
if ( pDidInsert ) *pDidInsert = true;
}
else
{
if ( pDidInsert ) *pDidInsert = false;
}
return idx;
}
// Key insertion
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
template <typename KeyParamT>
UtlHashHandle_t CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DoInsertNoCheck( KeyParamT k, typename ArgumentTypeInfo<ValueT>::Arg_t v, unsigned int h )
{
Assert( DoLookup<KeyParamT>( k, h, NULL ) == (handle_t) -1 );
handle_t idx = (handle_t) DoInsertUnconstructed( h, true );
Construct( m_table[ idx ].Raw(), k, v );
return idx;
}
// Remove single element by key + hash. Returns the location of the new empty hole.
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
template <typename KeyParamT>
int CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DoRemove( KeyParamT x, unsigned int h )
{
unsigned int slotmask = m_table.Count()-1;
handle_t previous = (handle_t) -1;
int idx = (int) DoLookup<KeyParamT>( x, h, &previous );
if (idx == -1)
{
return -1;
}
enum { FAKEFLAG_ROOT = 1 };
int nLastAndRootFlags = m_table[idx].flags_and_hash & FLAG_LAST;
nLastAndRootFlags |= ( (uint)idx == m_table[idx].IdealIndex( slotmask ) );
// Remove from table
m_table[idx].MarkInvalid();
Destruct( m_table[idx].Raw() );
--m_nUsed;
if ( nLastAndRootFlags == FLAG_LAST ) // last only, not root
{
// This was the end of the chain - mark previous as last.
// (This isn't the root, so there must be a previous.)
Assert( previous != (handle_t) -1 );
m_table[previous].flags_and_hash |= FLAG_LAST;
}
if ( nLastAndRootFlags == FAKEFLAG_ROOT ) // root only, not last
{
// If we are removing the root and there is more to the chain,
// scan to find the next chain entry and move it to the root.
unsigned int chainid = entry_t::IdealIndex( h, slotmask );
unsigned int nextIdx = idx;
while (1)
{
nextIdx = (nextIdx + 1) & slotmask;
if ( m_table[nextIdx].IdealIndex( slotmask ) == chainid )
{
break;
}
}
Assert( !(m_table[nextIdx].flags_and_hash & FLAG_FREE) );
// Leave a hole where the next entry in the chain was.
m_table[idx].flags_and_hash = m_table[nextIdx].flags_and_hash;
m_table[idx].MoveDataFrom( m_table[nextIdx] );
m_table[nextIdx].MarkInvalid();
return nextIdx;
}
// The hole is still where the element used to be.
return idx;
}
// Assignment operator. It's up to the user to make sure that the hash and equality functors match.
template <typename K, typename V, typename H, typename E, typename A>
CUtlHashtable<K,V,H,E,A> &CUtlHashtable<K,V,H,E,A>::operator=( CUtlHashtable<K,V,H,E,A> const &src )
{
if ( &src != this )
{
Assert( !m_bSizeLocked || m_table.Count() >= src.m_nUsed );
if ( !m_bSizeLocked )
{
Purge();
Reserve(src.m_nUsed);
}
else
{
RemoveAll();
}
const entry_t * srcTable = src.m_table.Base();
for ( int i = src.m_table.Count() - 1; i >= 0; --i )
{
if ( srcTable[i].IsValid() )
{
// If this assert trips, double-check that both hashtables
// have the same hash function pointers or hash functor state!
Assert( m_hash(srcTable[i]->m_key) == src.m_hash(srcTable[i]->m_key) );
int newIdx = DoInsertUnconstructed( srcTable[i].flags_and_hash , false );
Construct( m_table[newIdx].Raw(), *srcTable[i].Raw() ); // copy construct KVPair
}
}
}
return *this;
}
// Remove and return the next valid iterator for a forward iteration.
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
UtlHashHandle_t CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::RemoveAndAdvance( UtlHashHandle_t idx )
{
Assert( IsValidHandle( idx ) );
// TODO optimize, implement DoRemoveAt that does not need to re-evaluate equality in DoLookup
int hole = DoRemove< KeyArg_t >( m_table[idx]->m_key, m_table[idx].flags_and_hash & MASK_HASH );
// DoRemove returns the index of the element that it moved to fill the hole, if any.
if ( hole <= (int) idx )
{
// Didn't fill, or filled from a previously seen element.
return NextHandle( idx );
}
else
{
// Do not advance; slot has a new un-iterated value.
Assert( IsValidHandle(idx) );
return idx;
}
}
// Remove and return the next valid iterator for a forward iteration.
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
void CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::RemoveByHandle( UtlHashHandle_t idx )
{
AssertDbg( IsValidHandle( idx ) );
// Copied from RemoveAndAdvance(): TODO optimize, implement DoRemoveAt that does not need to re-evaluate equality in DoLookup
DoRemove< KeyArg_t >( m_table[idx]->m_key, m_table[idx].flags_and_hash & MASK_HASH );
}
// Burn it with fire.
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
void CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::RemoveAll()
{
int used = m_nUsed;
if ( used != 0 )
{
entry_t* table = m_table.Base();
for ( int i = m_table.Count() - 1; i >= 0; --i )
{
if ( table[i].IsValid() )
{
table[i].MarkInvalid();
Destruct( table[i].Raw() );
if ( --used == 0 )
break;
}
}
m_nUsed = 0;
}
}
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
UtlHashHandle_t CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::NextHandle( handle_t start ) const
{
const entry_t *table = m_table.Base();
for ( int i = (int)start + 1; i < m_table.Count(); ++i )
{
if ( table[i].IsValid() )
return (handle_t) i;
}
return (handle_t) -1;
}
#if _DEBUG
template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
void CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DbgCheckIntegrity() const
{
// Stress test the hash table as a test of both container functionality
// and also the validity of the user's Hash and Equal function objects.
// NOTE: will fail if function objects require any sort of state!
CUtlHashtable clone;
unsigned int bytes = sizeof(entry_t)*max(16,m_table.Count());
byte* tempbuf = (byte*) malloc(bytes);
clone.SetExternalBuffer( tempbuf, bytes, false, false );
clone = *this;
int count = 0, roots = 0, ends = 0;
int slotmask = m_table.Count() - 1;
for (int i = 0; i < m_table.Count(); ++i)
{
if (!(m_table[i].flags_and_hash & FLAG_FREE)) ++count;
if (m_table[i].IdealIndex(slotmask) == (uint)i) ++roots;
if (m_table[i].flags_and_hash & FLAG_LAST) ++ends;
if (m_table[i].IsValid())
{
Assert( Find(m_table[i]->m_key) == (handle_t)i );
Verify( clone.Remove(m_table[i]->m_key) );
}
else
{
Assert( m_table[i].flags_and_hash == FLAG_FREE );
}
}
Assert( count == Count() && count >= roots && roots == ends );
Assert( clone.Count() == 0 );
clone.Purge();
free(tempbuf);
}
#endif
//-----------------------------------------------------------------------
// CUtlStableHashtable
//-----------------------------------------------------------------------
// Stable hashtables are less memory and cache efficient, but can be
// iterated quickly and their element handles are completely stable.
// Implemented as a hashtable which only stores indices, and a separate
// CUtlLinkedList data table which contains key-value pairs; this may
// change to a more efficient structure in the future if space becomes
// critical. I have some ideas about that but not the time to implement
// at the moment. -henryg
// Note: RemoveAndAdvance is slower than in CUtlHashtable because the
// key needs to be re-hashed under the current implementation.
template <typename KeyT, typename ValueT = empty_t, typename KeyHashT = DefaultHashFunctor<KeyT>, typename KeyIsEqualT = DefaultEqualFunctor<KeyT>, typename IndexStorageT = uint16, typename AlternateKeyT = typename ArgumentTypeInfo<KeyT>::Alt_t >
class CUtlStableHashtable
{
public:
typedef typename ArgumentTypeInfo<KeyT>::Arg_t KeyArg_t;
typedef typename ArgumentTypeInfo<ValueT>::Arg_t ValueArg_t;
typedef typename ArgumentTypeInfo<AlternateKeyT>::Arg_t KeyAlt_t;
typedef typename CTypeSelect< sizeof( IndexStorageT ) == 2, uint16, uint32 >::type IndexStorage_t;
protected:
COMPILE_TIME_ASSERT( sizeof( IndexStorage_t ) == sizeof( IndexStorageT ) );
typedef CUtlKeyValuePair< KeyT, ValueT > KVPair;
struct HashProxy;
struct EqualProxy;
struct IndirectIndex;
typedef CUtlHashtable< IndirectIndex, empty_t, HashProxy, EqualProxy, AlternateKeyT > Hashtable_t;
typedef CUtlLinkedList< KVPair, IndexStorage_t > LinkedList_t;
template <typename KeyArgumentT> bool DoRemove( KeyArgumentT k );
template <typename KeyArgumentT> UtlHashHandle_t DoFind( KeyArgumentT k ) const;
template <typename KeyArgumentT> UtlHashHandle_t DoInsert( KeyArgumentT k );
template <typename KeyArgumentT, typename ValueArgumentT> UtlHashHandle_t DoInsert( KeyArgumentT k, ValueArgumentT v );
public:
KeyHashT &GetHashRef() { return m_table.GetHashRef().m_hash; }
KeyIsEqualT &GetEqualRef() { return m_table.GetEqualRef().m_eq; }
KeyHashT const &GetHashRef() const { return m_table.GetHashRef().m_hash; }
KeyIsEqualT const &GetEqualRef() const { return m_table.GetEqualRef().m_eq; }
UtlHashHandle_t Insert( KeyArg_t k ) { return DoInsert<KeyArg_t>( k ); }
UtlHashHandle_t Insert( KeyAlt_t k ) { return DoInsert<KeyAlt_t>( k ); }
UtlHashHandle_t Insert( KeyArg_t k, ValueArg_t v ) { return DoInsert<KeyArg_t, ValueArg_t>( k, v ); }
UtlHashHandle_t Insert( KeyAlt_t k, ValueArg_t v ) { return DoInsert<KeyAlt_t, ValueArg_t>( k, v ); }
UtlHashHandle_t Find( KeyArg_t k ) const { return DoFind<KeyArg_t>( k ); }
UtlHashHandle_t Find( KeyAlt_t k ) const { return DoFind<KeyAlt_t>( k ); }
bool Remove( KeyArg_t k ) { return DoRemove<KeyArg_t>( k ); }
bool Remove( KeyAlt_t k ) { return DoRemove<KeyAlt_t>( k ); }
void RemoveAll() { m_table.RemoveAll(); m_data.RemoveAll(); }
void Purge() { m_table.Purge(); m_data.Purge(); }
int Count() const { return m_table.Count(); }
typedef typename KVPair::ValueReturn_t Element_t;
KeyT const &Key( UtlHashHandle_t idx ) const { return m_data[idx].m_key; }
Element_t const &Element( UtlHashHandle_t idx ) const { return m_data[idx].GetValue(); }
Element_t &Element( UtlHashHandle_t idx ) { return m_data[idx].GetValue(); }
Element_t const &operator[]( UtlHashHandle_t idx ) const { return m_data[idx].GetValue(); }
Element_t &operator[]( UtlHashHandle_t idx ) { return m_data[idx].GetValue(); }
void ReplaceKey( UtlHashHandle_t idx, KeyArg_t k ) { Assert( GetEqualRef()( m_data[idx].m_key, k ) && GetHashRef()( k ) == GetHashRef()( m_data[idx].m_key ) ); m_data[idx].m_key = k; }
void ReplaceKey( UtlHashHandle_t idx, KeyAlt_t k ) { Assert( GetEqualRef()( m_data[idx].m_key, k ) && GetHashRef()( k ) == GetHashRef()( m_data[idx].m_key ) ); m_data[idx].m_key = k; }
Element_t const &Get( KeyArg_t k, Element_t const &defaultValue ) const { UtlHashHandle_t h = Find( k ); if ( h != InvalidHandle() ) return Element( h ); return defaultValue; }
Element_t const &Get( KeyAlt_t k, Element_t const &defaultValue ) const { UtlHashHandle_t h = Find( k ); if ( h != InvalidHandle() ) return Element( h ); return defaultValue; }
Element_t const *GetPtr( KeyArg_t k ) const { UtlHashHandle_t h = Find(k); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
Element_t const *GetPtr( KeyAlt_t k ) const { UtlHashHandle_t h = Find(k); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
Element_t *GetPtr( KeyArg_t k ) { UtlHashHandle_t h = Find( k ); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
Element_t *GetPtr( KeyAlt_t k ) { UtlHashHandle_t h = Find( k ); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
UtlHashHandle_t FirstHandle() const { return ExtendInvalidHandle( m_data.Head() ); }
UtlHashHandle_t NextHandle( UtlHashHandle_t h ) const { return ExtendInvalidHandle( m_data.Next( h ) ); }
bool IsValidHandle( UtlHashHandle_t h ) const { return m_data.IsValidIndex( h ); }
UtlHashHandle_t InvalidHandle() const { return (UtlHashHandle_t)-1; }
UtlHashHandle_t RemoveAndAdvance( UtlHashHandle_t h )
{
Assert( m_data.IsValidIndex( h ) );
m_table.Remove( IndirectIndex( h ) );
IndexStorage_t next = m_data.Next( h );
m_data.Remove( h );
return ExtendInvalidHandle(next);
}
void Compact( bool bMinimal ) { m_table.Compact( bMinimal ); /*m_data.Compact();*/ }
void Swap( CUtlStableHashtable &other )
{
m_table.Swap(other.m_table);
// XXX swapping CUtlLinkedList by block memory swap, ugh
char buf[ sizeof(m_data) ];
memcpy( buf, &m_data, sizeof(m_data) );
memcpy( &m_data, &other.m_data, sizeof(m_data) );
memcpy( &other.m_data, buf, sizeof(m_data) );
}
protected:
// Perform extension of 0xFFFF to 0xFFFFFFFF if necessary. Note: ( a < CONSTANT ) ? 0 : -1 is usually branchless
static UtlHashHandle_t ExtendInvalidHandle( uint32 x ) { return x; }
static UtlHashHandle_t ExtendInvalidHandle( uint16 x ) { uint32 a = x; return a | ( ( a < 0xFFFFu ) ? 0 : -1 ); }
struct IndirectIndex
{
explicit IndirectIndex(IndexStorage_t i) : m_index(i) { }
IndexStorage_t m_index;
};
struct HashProxy
{
KeyHashT m_hash;
unsigned int operator()( IndirectIndex idx ) const
{
const ptrdiff_t tableoffset = (uintptr_t)(&((Hashtable_t*)1024)->GetHashRef()) - 1024;
const ptrdiff_t owneroffset = offsetof(CUtlStableHashtable, m_table) + tableoffset;
CUtlStableHashtable* pOwner = (CUtlStableHashtable*)((uintptr_t)this - owneroffset);
return m_hash( pOwner->m_data[ idx.m_index ].m_key );
}
unsigned int operator()( KeyArg_t k ) const { return m_hash( k ); }
unsigned int operator()( KeyAlt_t k ) const { return m_hash( k ); }
};
struct EqualProxy
{
KeyIsEqualT m_eq;
unsigned int operator()( IndirectIndex lhs, IndirectIndex rhs ) const
{
return lhs.m_index == rhs.m_index;
}
unsigned int operator()( IndirectIndex lhs, KeyArg_t rhs ) const
{
const ptrdiff_t tableoffset = (uintptr_t)(&((Hashtable_t*)1024)->GetEqualRef()) - 1024;
const ptrdiff_t owneroffset = offsetof(CUtlStableHashtable, m_table) + tableoffset;
CUtlStableHashtable* pOwner = (CUtlStableHashtable*)((uintptr_t)this - owneroffset);
return m_eq( pOwner->m_data[ lhs.m_index ].m_key, rhs );
}
unsigned int operator()( IndirectIndex lhs, KeyAlt_t rhs ) const
{
const ptrdiff_t tableoffset = (uintptr_t)(&((Hashtable_t*)1024)->GetEqualRef()) - 1024;
const ptrdiff_t owneroffset = offsetof(CUtlStableHashtable, m_table) + tableoffset;
CUtlStableHashtable* pOwner = (CUtlStableHashtable*)((uintptr_t)this - owneroffset);
return m_eq( pOwner->m_data[ lhs.m_index ].m_key, rhs );
}
};
class CCustomLinkedList : public LinkedList_t
{
public:
int AddToTailUnconstructed()
{
IndexStorage_t newNode = this->AllocInternal();
if ( newNode != this->InvalidIndex() )
this->LinkToTail( newNode );
return newNode;
}
};
Hashtable_t m_table;
CCustomLinkedList m_data;
};
template <typename K, typename V, typename H, typename E, typename S, typename A>
template <typename KeyArgumentT>
inline bool CUtlStableHashtable<K,V,H,E,S,A>::DoRemove( KeyArgumentT k )
{
unsigned int hash = m_table.GetHashRef()( k );
UtlHashHandle_t h = m_table.template DoLookup<KeyArgumentT>( k, hash, NULL );
if ( h == m_table.InvalidHandle() )
return false;
int idx = m_table[ h ].m_index;
m_table.template DoRemove<IndirectIndex>( IndirectIndex( idx ), hash );
m_data.Remove( idx );
return true;
}
template <typename K, typename V, typename H, typename E, typename S, typename A>
template <typename KeyArgumentT>
inline UtlHashHandle_t CUtlStableHashtable<K,V,H,E,S,A>::DoFind( KeyArgumentT k ) const
{
unsigned int hash = m_table.GetHashRef()( k );
UtlHashHandle_t h = m_table.template DoLookup<KeyArgumentT>( k, hash, NULL );
if ( h != m_table.InvalidHandle() )
return m_table[ h ].m_index;
return (UtlHashHandle_t) -1;
}
template <typename K, typename V, typename H, typename E, typename S, typename A>
template <typename KeyArgumentT>
inline UtlHashHandle_t CUtlStableHashtable<K,V,H,E,S,A>::DoInsert( KeyArgumentT k )
{
unsigned int hash = m_table.GetHashRef()( k );
UtlHashHandle_t h = m_table.template DoLookup<KeyArgumentT>( k, hash, NULL );
if ( h != m_table.InvalidHandle() )
return m_table[ h ].m_index;
int idx = m_data.AddToTailUnconstructed();
Construct( &m_data[idx], k );
m_table.template DoInsertNoCheck<IndirectIndex>( IndirectIndex( idx ), empty_t(), hash );
return idx;
}
template <typename K, typename V, typename H, typename E, typename S, typename A>
template <typename KeyArgumentT, typename ValueArgumentT>
inline UtlHashHandle_t CUtlStableHashtable<K,V,H,E,S,A>::DoInsert( KeyArgumentT k, ValueArgumentT v )
{
unsigned int hash = m_table.GetHashRef()( k );
UtlHashHandle_t h = m_table.template DoLookup<KeyArgumentT>( k, hash, NULL );
if ( h != m_table.InvalidHandle() )
return m_table[ h ].m_index;
int idx = m_data.AddToTailUnconstructed();
Construct( &m_data[idx], k, v );
m_table.template DoInsertNoCheck<IndirectIndex>( IndirectIndex( idx ), empty_t(), hash );
return idx;
}
#endif // UTLHASHTABLE_H

View File

@@ -0,0 +1,273 @@
//====== Copyright <20> 1996-2009, Valve Corporation, All rights reserved. =======//
#ifndef INCREMENTAL_VECTOR_H
#define INCREMENTAL_VECTOR_H
// this class facilitates an array of pointers that get added and removed frequently;
// it's intrusive: the class that is pointed to must contain and maintain an index
#include "tier1/utlvector.h"
template < class CLASS >
struct DefaultIncrementalVectorAccessor_t
{
static int GetIndex( const CLASS * p ) { return p->m_nIncrementalVectorIndex; }
static void SetIndex( CLASS * p, int nIndex ) { p->m_nIncrementalVectorIndex = nIndex; }
};
template <class T, class Accessor = DefaultIncrementalVectorAccessor_t< T > , class Allocator = CUtlMemory< T* > >
class CUtlIncrementalVector
{
public:
T** Base(){ return m_data.Base(); }
T*const* Base()const{ return m_data.Base(); }
typedef T* ElemType_t;
typedef T** iterator;
typedef T*const* const_iterator;
enum { IsUtlVector = true }; // Used to match this at compiletime
iterator begin() { return Base(); }
const_iterator begin() const { return Base(); }
iterator end() { return Base() + Count(); }
const_iterator end() const { return Base() + Count(); }
void SetCountAndCreateOrDelete( int nNewCount )
{
int nOldCount = Count();
for( int i = nNewCount; i < nOldCount; ++i )
{
delete m_data[i];
}
m_data.SetCount( nNewCount );
for( int i = nOldCount; i < nNewCount; ++i )
{
m_data[i] = new T;
Accessor::SetIndex( m_data[i], i );
}
Validate();
}
int Count() const
{
return m_data.Count();
}
T* operator[]( int i )
{
Assert( !m_data[i] || Accessor::GetIndex( m_data[i] ) == i );
return m_data[i];
}
const T* operator[]( int i )const
{
Assert( !m_data[i] || Accessor::GetIndex( m_data[i] ) == i );
return m_data[i];
}
void SetElementToNull( int i )
{
m_data[ i ] = NULL;
}
T* AddToTail( T* p )
{
Validate();
Accessor::SetIndex( p, m_data.Count() );
m_data.AddToTail( p );
Validate();
return p;
}
void MoveToHead( T *pMid )
{
Validate();
int nMidIndex = Accessor::GetIndex( pMid );
Accessor::SetIndex( pMid, 0 );
T *pHead = m_data[0];
Accessor::SetIndex( pHead, nMidIndex );
m_data[0] = pMid;
m_data[nMidIndex] = pHead;
Validate();
}
void SwapItems( int i1, int i2 )
{
Validate();
T *p1 = m_data[i1];
T *p2 = m_data[i2];
Accessor::SetIndex( p1, i2 );
Accessor::SetIndex( p2, i1 );
m_data[i1] = p2;
m_data[i2] = p1;
Validate();
}
void InsertNewMultipleBefore( int nIndex, int nCount )
{
if( nCount )
{
for( int i = nIndex; i < m_data.Count(); ++i )
{
T *pElement = m_data[i];
Accessor::SetIndex( pElement, Accessor::GetIndex( pElement ) + nCount );
}
m_data.InsertMultipleBefore( nIndex, nCount );
for( int i = 0; i < nCount; ++i )
{
T *p = new T;
Accessor::SetIndex( p, nIndex + i );
m_data[ nIndex + i ] = p;
}
}
}
void RemoveAndDeleteMultiple( int nIndex, int nCount )
{
if( nCount )
{
for( int i = nIndex, nEnd = MIN( nIndex + nCount, m_data.Count() ); i < nEnd; ++i )
{
delete m_data[i];
}
m_data.RemoveMultiple( nIndex, nCount );
for ( int i = nIndex; i < m_data.Count(); ++i )
{
Accessor::SetIndex( m_data[ i ], i );
}
}
}
void RemoveMultiple( int nIndex, int nCount )
{
if ( nCount )
{
m_data.RemoveMultiple( nIndex, nCount );
for ( int i = nIndex; i < Count(); ++i )
{
Accessor::SetIndex( m_data[ i ], i );
}
}
}
void RemoveMultipleFromHead( int num )
{
if ( num )
{
m_data.RemoveMultipleFromHead( num );
for ( int i = 0; i < Count(); ++i )
{
Accessor::SetIndex( m_data[ i ], i );
}
}
}
void RemoveAndDelete( int nIndex ) ///< preserves order, shifts elements
{
if( nIndex < Count() )
{
delete m_data[nIndex];
for( int i = nIndex + 1; i < Count(); ++i )
{
Accessor::SetIndex( m_data[ i ], i - 1 );
m_data[ i - 1 ] = m_data[ i ];
}
m_data.RemoveMultipleFromTail( 1 );
}
}
void FastRemove( int elem ) // doesn't preserve order
{
Validate();
//T* pDeletable = m_data[elem];
T* pLast = m_data.Tail(); // Optimization Warning: pLast and pDelete pointers are aliased
m_data[elem] = pLast;
m_data.RemoveMultipleFromTail( 1 );
Accessor::SetIndex( pLast, elem );
// Accessor::SetIndex( pDeletable, -1 ); // this is not really necessary, except for debugging; there's also a danger that client deleted the object before calling FastRemove
Validate();
}
T* FindAndFastRemove( T* p ) // removes first occurrence of src, doesn't preserve order
{
int nIndex = Accessor::GetIndex( p );
Assert( m_data[nIndex] == p );
FastRemove( nIndex );
return p;
}
int Find( const T* p )const
{
int nIndex = Accessor::GetIndex( p );
if ( uint( nIndex ) < uint( Count() ) && m_data[ nIndex ] == p )
return nIndex;
else
return -1;
}
bool Has( const T *p )const
{
int nIndex = Accessor::GetIndex( p );
return uint( nIndex ) < uint( Count() ) && m_data[ nIndex ] == p;
}
void FastRemoveAndDelete( T* p )
{
int nIndex = Accessor::GetIndex( p );
FastRemove( nIndex );
delete p;
}
void PurgeAndDeleteElements()
{
Validate();
m_data.PurgeAndDeleteElements();
}
inline void Validate()
{
#if defined( DBGFLAG_ASSERT ) && defined( _DEBUG )
for( int i =0 ;i < Count(); ++i )
{
Assert( !m_data[i] || Accessor::GetIndex( m_data[i] ) == i );
}
#endif
}
void Purge()
{
m_data.Purge();
}
bool IsEmpty()const
{
return m_data.IsEmpty();
}
T *Tail()
{
return m_data.Tail();
}
void EnsureCapacity( int nCap )
{
m_data.EnsureCapacity( nCap );
}
void Sort( int (__cdecl *pfnCompare)(const ElemType_t *, const ElemType_t *) )
{
m_data.Sort( pfnCompare );
for( int i = 0; i < m_data.Count(); ++i )
{
Accessor::SetIndex( m_data[i], i );
}
}
protected:
CUtlVector< T*, Allocator > m_data;
};
#define DECLARE_INCREMENTAL_VECTOR_TYPE(CLASS, MEMBER) \
struct CLASS##_##NAME##_IncrementalVectorAccessor_t \
{ \
static int GetIndex( const CLASS * p ) { return p->MEMBER; } \
static void SetIndex( const CLASS * p, int nIndex ) { p->MEMBER = nIndex; } \
}; \
typedef CUtlIncrementalVector < CLASS, CLASS##_##NAME##_IncrementalVectorAccessor_t >
#endif

View File

@@ -0,0 +1,299 @@
//================ Copyright (c) 1996-2009 Valve Corporation. All Rights Reserved. =================
//
//
//
//==================================================================================================
#ifndef UTLINTERVALTREE_H
#define UTLINTERVALTREE_H
#ifdef _WIN32
#pragma once
#endif
#include <stdlib.h> // qsort
#include "tier0/platform.h"
#include "tier1/utlstack.h"
//
// An interval tree is a tree of "segments" or "intervals" of type T which can be searched for overlaps with another interval.
//
// Usage:
/*
// Convenience typedef, the application data is the DataType == const void * part of it
typedef CUtlIntervalTree< const void *, float > TreeType;
// Build list of intervals to insert
CUtlVector< TreeType::Value_t > intervals;
TreeType::Value_t iv;
for ( int i = 0 ; i < numtoinsert; ++i )
{
iv.m_Data = (const void *) [i'th user value ];
iv.SetLowVal( leftEdge );
iv.SetHighVal( rightEdge );
intervals.AddToTail( iv );
}
// Then build up the tree
TreeType tree;
tree.BuildTree( intervals.Base(), intervals.Count() );
// Now search the tree
TreeType::Interval_t test;
test.SetLowVal( nLowTest );
test.SetHighVal( nHighTest );
// Results vector:
CUtlVector< TreeType::Value_t > vec;
// Search for overlapping spans, return interval data (sorted by low value if passed in true as third argument)
tree.FindOverlaps( test, vec, true );
// Print results (sorted if third argument is set to true)
for ( int i = 0; i < vec.Count(); ++i )
{
Msg( " [%d] overlap [%f, %f] [val %d]\n",
i, vec[ i ].GetLowVal(), vec[ i ].GetHighVal(), (int)vec[ i ].m_Data );
}
*/
//
template< class DataType, class T = float >
class CUtlIntervalTree
{
public:
template< class S >
class Interval
{
public:
Interval() : m_Low(0), m_High(0)
{
}
Interval( const S &lowVal, const S &highVal ) :
m_Low( lowVal ), m_High( highVal )
{
}
inline void SetLowVal( const S &v )
{
m_Low = v;
}
inline const S &GetLowVal(void) const
{
return m_Low;
}
inline void SetHighVal( const S &v )
{
m_High = v;
}
inline const S &GetHighVal(void) const
{
return m_High;
}
inline bool IsOverlapping( const Interval< S > &other, bool bStricOverlapsOnly ) const
{
if ( bStricOverlapsOnly )
{
return ( GetLowVal() < other.GetHighVal() && GetHighVal() > other.GetLowVal() );
}
return ( GetLowVal() <= other.GetHighVal() && GetHighVal() >= other.GetLowVal() );
}
private:
S m_Low;
S m_High;
};
typedef Interval< T > Interval_t;
struct Value_t : public Interval_t
{
DataType m_Data;
};
CUtlIntervalTree() : m_pRoot( NULL ) {}
~CUtlIntervalTree(void);
void BuildTree( Value_t *pIntervals, unsigned int nCount );
void FindOverlaps( const Interval_t &rCheck, CUtlVector< Value_t > &vecOverlappingIntervals, bool bSortResultsByLowVal, bool bStricOverlapsOnly = false ) const;
private:
struct TreeNode
{
TreeNode( const Value_t &interval ) :
m_Interval(interval),
m_pLeft( NULL ),
m_pRight( NULL )
{
}
Value_t m_Interval;
TreeNode *m_pLeft;
TreeNode *m_pRight;
T m_MinVal;
T m_MaxVal;
};
TreeNode *m_pRoot;
private:
void DeleteTree_R( TreeNode *pNode );
TreeNode *Insert_R( const Value_t *pIntervals, unsigned int nCount );
};
template< class DataType, class T >
inline int CompareIntervals( const void *p1, const void *p2 )
{
const CUtlIntervalTree<DataType,T>::Interval_t *pInterval1 = ( const CUtlIntervalTree<DataType,T>::Interval_t *)p1;
const CUtlIntervalTree<DataType,T>::Interval_t *pInterval2 = ( const CUtlIntervalTree<DataType,T>::Interval_t *)p2;
T lowVal1 = pInterval1->GetLowVal();
T lowVal2 = pInterval2->GetLowVal();
if ( lowVal1 > lowVal2 )
return 1;
else if ( lowVal1 < lowVal2 )
return -1;
return 0;
}
template< class DataType, class T >
inline void CUtlIntervalTree< DataType, T >::BuildTree( Value_t *pIntervals, unsigned int nCount )
{
if ( m_pRoot )
{
DeleteTree_R( m_pRoot );
m_pRoot = NULL;
}
if ( nCount > 0 )
{
qsort( pIntervals, nCount, sizeof( Value_t ), CompareIntervals< DataType, T > );
// Recursively build tree
m_pRoot = Insert_R( pIntervals, nCount );
}
}
template< class DataType, class T >
inline CUtlIntervalTree<DataType, T>::~CUtlIntervalTree(void)
{
if ( m_pRoot )
{
DeleteTree_R( m_pRoot );
}
}
template< class DataType, class T >
inline typename CUtlIntervalTree<DataType, T>::TreeNode *CUtlIntervalTree<DataType, T>::Insert_R( const Value_t *pIntervals, unsigned int nCount )
{
unsigned int rootIdx = nCount / 2;
TreeNode *pRoot = new TreeNode( pIntervals[ rootIdx ] );
switch( nCount )
{
case 1:
{
// m_pLeft, m_pRight are NULL by default
pRoot->m_MinVal = pRoot->m_Interval.GetLowVal();
pRoot->m_MaxVal = pRoot->m_Interval.GetHighVal();
}
break;
case 2:
{
pRoot->m_pLeft = Insert_R( pIntervals, 1 );
// m_pRight == NULL by default
pRoot->m_MinVal = pRoot->m_pLeft->m_MinVal;
pRoot->m_MaxVal = MAX( pRoot->m_pLeft->m_MaxVal, pRoot->m_Interval.GetHighVal() );
}
break;
default: // nCount > 2
{
pRoot->m_pLeft = Insert_R( pIntervals, rootIdx );
pRoot->m_pRight = Insert_R( &pIntervals[ rootIdx + 1 ], nCount - rootIdx - 1 );
pRoot->m_MinVal = pRoot->m_pLeft->m_MinVal;
// Max is greatest of this or two children...
pRoot->m_MaxVal = MAX( MAX( pRoot->m_pLeft->m_MaxVal, pRoot->m_pRight->m_MaxVal ), pRoot->m_Interval.GetHighVal() );
}
break;
}
return pRoot;
}
template< class DataType, class T >
inline void CUtlIntervalTree<DataType, T>::DeleteTree_R( TreeNode *pNode )
{
if ( pNode->m_pLeft )
{
DeleteTree_R( pNode->m_pLeft );
}
if ( pNode->m_pRight )
{
DeleteTree_R( pNode->m_pRight );
}
delete pNode;
}
template< class DataType, class T >
inline void CUtlIntervalTree<DataType, T>::FindOverlaps( const Interval_t &rCheck, CUtlVector< Value_t > &vecOverlappingIntervals, bool bSortResultsByLowVal, bool bStricOverlapsOnly /*= false*/ ) const
{
const TreeNode *pNode = m_pRoot;
if ( !pNode )
return;
// Work queue stack
CUtlStack< const TreeNode * > stack;
stack.Push( NULL );
while ( pNode != NULL )
{
if ( rCheck.IsOverlapping( pNode->m_Interval, bStricOverlapsOnly ) )
{
vecOverlappingIntervals.AddToTail( pNode->m_Interval );
}
bool bCheckLeft = ( pNode->m_pLeft &&
pNode->m_pLeft->m_MaxVal >= rCheck.GetLowVal() );
bool bCheckRight = ( pNode->m_pRight &&
pNode->m_pRight->m_MinVal <= rCheck.GetHighVal() );
if ( bCheckRight )
{
if ( bCheckLeft )
{
// queue it up for later
stack.Push( pNode->m_pLeft );
}
pNode = pNode->m_pRight;
}
else if ( bCheckLeft )
{
pNode = pNode->m_pLeft;
}
else
{
stack.Pop( pNode );
}
}
if ( bSortResultsByLowVal &&
vecOverlappingIntervals.Count() > 1 )
{
qsort( vecOverlappingIntervals.Base(), vecOverlappingIntervals.Count(), sizeof( Value_t ), CompareIntervals< DataType, T > );
}
}
#endif // UTLINTERVALTREE_H

File diff suppressed because it is too large Load Diff

1294
public/tier1/utllinkedlist.h Normal file

File diff suppressed because it is too large Load Diff

295
public/tier1/utlmap.h Normal file
View File

@@ -0,0 +1,295 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Header: $
// $NoKeywords: $
//=============================================================================//
#ifndef UTLMAP_H
#define UTLMAP_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
#include "utlrbtree.h"
//-----------------------------------------------------------------------------
//
// Purpose: An associative container. Pretty much identical to std::map.
//
//-----------------------------------------------------------------------------
// This is a useful macro to iterate from start to end in order in a map
#define FOR_EACH_MAP( mapName, iteratorName ) \
for ( int iteratorName = (mapName).FirstInorder(); (mapName).IsUtlMap && iteratorName != (mapName).InvalidIndex(); iteratorName = (mapName).NextInorder( iteratorName ) )
// faster iteration, but in an unspecified order
#define FOR_EACH_MAP_FAST( mapName, iteratorName ) \
for ( int iteratorName = 0; (mapName).IsUtlMap && iteratorName < (mapName).MaxElement(); ++iteratorName ) if ( !(mapName).IsValidIndex( iteratorName ) ) continue; else
struct base_utlmap_t
{
public:
// This enum exists so that FOR_EACH_MAP and FOR_EACH_MAP_FAST cannot accidentally
// be used on a type that is not a CUtlMap. If the code compiles then all is well.
// The check for IsUtlMap being true should be free.
// Using an enum rather than a static const bool ensures that this trick works even
// with optimizations disabled on gcc.
enum { IsUtlMap = true };
};
template <typename K, typename T, typename I = unsigned short, typename LessFunc_t = bool (*)( const K &, const K & )>
class CUtlMap : public base_utlmap_t
{
public:
typedef K KeyType_t;
typedef T ElemType_t;
typedef I IndexType_t;
// constructor, destructor
// Left at growSize = 0, the memory will first allocate 1 element and double in size
// at each increment.
// LessFunc_t is required, but may be set after the constructor using SetLessFunc() below
CUtlMap( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 )
: m_Tree( growSize, initSize, CKeyLess( lessfunc ) )
{
}
CUtlMap( LessFunc_t lessfunc )
: m_Tree( CKeyLess( lessfunc ) )
{
}
void EnsureCapacity( int num ) { m_Tree.EnsureCapacity( num ); }
// gets particular elements
ElemType_t & Element( IndexType_t i ) { return m_Tree.Element( i ).elem; }
const ElemType_t & Element( IndexType_t i ) const { return m_Tree.Element( i ).elem; }
ElemType_t & operator[]( IndexType_t i ) { return m_Tree.Element( i ).elem; }
const ElemType_t & operator[]( IndexType_t i ) const { return m_Tree.Element( i ).elem; }
KeyType_t & Key( IndexType_t i ) { return m_Tree.Element( i ).key; }
const KeyType_t & Key( IndexType_t i ) const { return m_Tree.Element( i ).key; }
// Num elements
unsigned int Count() const { return m_Tree.Count(); }
// Max "size" of the vector
IndexType_t MaxElement() const { return m_Tree.MaxElement(); }
// Checks if a node is valid and in the map
bool IsValidIndex( IndexType_t i ) const { return m_Tree.IsValidIndex( i ); }
// Checks if the map as a whole is valid
bool IsValid() const { return m_Tree.IsValid(); }
// Invalid index
static IndexType_t InvalidIndex() { return CTree::InvalidIndex(); }
// Sets the less func
void SetLessFunc( LessFunc_t func )
{
m_Tree.SetLessFunc( CKeyLess( func ) );
}
// Insert method (inserts in order)
IndexType_t Insert( const KeyType_t &key, const ElemType_t &insert )
{
Node_t node;
node.key = key;
node.elem = insert;
return m_Tree.Insert( node );
}
IndexType_t Insert( const KeyType_t &key )
{
Node_t node;
node.key = key;
return m_Tree.Insert( node );
}
// API to macth src2 for Panormama
// Note in src2 straight Insert() calls will assert on duplicates
// Chosing not to take that change until discussed further
IndexType_t InsertWithDupes( const KeyType_t &key, const ElemType_t &insert )
{
Node_t node;
node.key = key;
node.elem = insert;
return m_Tree.Insert( node );
}
IndexType_t InsertWithDupes( const KeyType_t &key )
{
Node_t node;
node.key = key;
return m_Tree.Insert( node );
}
bool HasElement( const KeyType_t &key ) const
{
Node_t dummyNode;
dummyNode.key = key;
return m_Tree.HasElement( dummyNode );
}
// Find method
IndexType_t Find( const KeyType_t &key ) const
{
Node_t dummyNode;
dummyNode.key = key;
return m_Tree.Find( dummyNode );
}
// FindFirst method
// This finds the first inorder occurrence of key
IndexType_t FindFirst( const KeyType_t &key ) const
{
Node_t dummyNode;
dummyNode.key = key;
return m_Tree.FindFirst( dummyNode );
}
const ElemType_t &FindElement( const KeyType_t &key, const ElemType_t &defaultValue ) const
{
IndexType_t i = Find( key );
if ( i == InvalidIndex() )
return defaultValue;
return Element( i );
}
// First element >= key
IndexType_t FindClosest( const KeyType_t &key, CompareOperands_t eFindCriteria ) const
{
Node_t dummyNode;
dummyNode.key = key;
return m_Tree.FindClosest( dummyNode, eFindCriteria );
}
// Remove methods
void RemoveAt( IndexType_t i ) { m_Tree.RemoveAt( i ); }
bool Remove( const KeyType_t &key )
{
Node_t dummyNode;
dummyNode.key = key;
return m_Tree.Remove( dummyNode );
}
void RemoveAll( ) { m_Tree.RemoveAll(); }
void Purge( ) { m_Tree.Purge(); }
// Purges the list and calls delete on each element in it.
void PurgeAndDeleteElements();
// Iteration
IndexType_t FirstInorder() const { return m_Tree.FirstInorder(); }
IndexType_t NextInorder( IndexType_t i ) const { return m_Tree.NextInorder( i ); }
IndexType_t PrevInorder( IndexType_t i ) const { return m_Tree.PrevInorder( i ); }
IndexType_t LastInorder() const { return m_Tree.LastInorder(); }
// API Matching src2 for Panorama
IndexType_t NextInorderSameKey( IndexType_t i ) const
{
IndexType_t iNext = NextInorder( i );
if ( !IsValidIndex( iNext ) )
return InvalidIndex();
if ( Key( iNext ) != Key( i ) )
return InvalidIndex();
return iNext;
}
// If you change the search key, this can be used to reinsert the
// element into the map.
void Reinsert( const KeyType_t &key, IndexType_t i )
{
m_Tree[i].key = key;
m_Tree.Reinsert(i);
}
IndexType_t InsertOrReplace( const KeyType_t &key, const ElemType_t &insert )
{
IndexType_t i = Find( key );
if ( i != InvalidIndex() )
{
Element( i ) = insert;
return i;
}
return Insert( key, insert );
}
void Swap( CUtlMap< K, T, I > &that )
{
m_Tree.Swap( that.m_Tree );
}
struct Node_t
{
Node_t()
{
}
Node_t( const Node_t &from )
: key( from.key ),
elem( from.elem )
{
}
KeyType_t key;
ElemType_t elem;
};
class CKeyLess
{
public:
CKeyLess( const LessFunc_t& lessFunc ) : m_LessFunc(lessFunc) {}
bool operator!() const
{
return !m_LessFunc;
}
bool operator()( const Node_t &left, const Node_t &right ) const
{
return m_LessFunc( left.key, right.key );
}
LessFunc_t m_LessFunc;
};
typedef CUtlRBTree<Node_t, I, CKeyLess> CTree;
CTree *AccessTree() { return &m_Tree; }
protected:
CTree m_Tree;
};
//-----------------------------------------------------------------------------
// Purges the list and calls delete on each element in it.
template< typename K, typename T, typename I, typename LessFunc_t >
inline void CUtlMap<K, T, I, LessFunc_t>::PurgeAndDeleteElements()
{
for ( I i = 0; i < MaxElement(); ++i )
{
if ( !IsValidIndex( i ) )
continue;
delete Element( i );
}
Purge();
}
#endif // UTLMAP_H

1136
public/tier1/utlmemory.h Normal file

File diff suppressed because it is too large Load Diff

773
public/tier1/utlmultilist.h Normal file
View File

@@ -0,0 +1,773 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Multiple linked list container class
//
// $Revision: $
// $NoKeywords: $
//=============================================================================//
#ifndef UTLMULTILIST_H
#define UTLMULTILIST_H
#ifdef _WIN32
#pragma once
#endif
#include "utllinkedlist.h"
// memdbgon must be the last include file in a .h file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// class CUtlMultiList:
// description:
// A lovely index-based linked list! T is the class type, I is the index
// type, which usually should be an unsigned short or smaller.
// This list can contain multiple lists
//-----------------------------------------------------------------------------
template <class T, class I>
class CUtlMultiList
{
protected:
// What the linked list element looks like
struct ListElem_t
{
T m_Element;
I m_Previous;
I m_Next;
};
struct List_t
{
I m_Head;
I m_Tail;
I m_Count;
};
typedef CUtlMemory<ListElem_t> M; // Keep naming similar to CUtlLinkedList
public:
typedef I ListHandle_t;
// constructor, destructor
CUtlMultiList( int growSize = 0, int initSize = 0 );
CUtlMultiList( void *pMemory, int memsize );
~CUtlMultiList( );
// gets particular elements
T& Element( I i );
T const& Element( I i ) const;
T& operator[]( I i );
T const& operator[]( I i ) const;
// Make sure we have a particular amount of memory
void EnsureCapacity( int num );
// Memory deallocation
void Purge();
// List Creation/deletion
ListHandle_t CreateList();
void DestroyList( ListHandle_t list );
bool IsValidList( ListHandle_t list ) const;
// Insertion methods (call default constructor)....
I InsertBefore( ListHandle_t list, I before );
I InsertAfter( ListHandle_t list, I after );
I AddToHead( ListHandle_t list );
I AddToTail( ListHandle_t list );
// Insertion methods (call copy constructor)....
I InsertBefore( ListHandle_t list, I before, T const& src );
I InsertAfter( ListHandle_t list, I after, T const& src );
I AddToHead( ListHandle_t list, T const& src );
I AddToTail( ListHandle_t list, T const& src );
// Removal methods
void Remove( ListHandle_t list, I elem );
// Removes all items in a single list
void RemoveAll( ListHandle_t list );
// Removes all items in all lists
void RemoveAll();
// Allocation/deallocation methods
// NOTE: To free, it must *not* be in a list!
I Alloc( );
void Free( I elem );
// list modification
void LinkBefore( ListHandle_t list, I before, I elem );
void LinkAfter( ListHandle_t list, I after, I elem );
void Unlink( ListHandle_t list, I elem );
void LinkToHead( ListHandle_t list, I elem );
void LinkToTail( ListHandle_t list, I elem );
// invalid index
static I InvalidIndex() { return (I)~0; }
static bool IndexInRange( int index );
static size_t ElementSize() { return sizeof(ListElem_t); }
// list statistics
int Count( ListHandle_t list ) const;
int TotalCount( ) const;
I MaxElementIndex() const;
// Traversing the list
I Head( ListHandle_t list ) const;
I Tail( ListHandle_t list ) const;
I Previous( I element ) const;
I Next( I element ) const;
// Are nodes in a list or valid?
bool IsValidIndex( I i ) const;
bool IsInList( I i ) const;
protected:
// constructs the class
void ConstructList( );
// Gets at the list element....
ListElem_t& InternalElement( I i ) { return m_Memory[i]; }
ListElem_t const& InternalElement( I i ) const { return m_Memory[i]; }
// A test for debug mode only...
bool IsElementInList( ListHandle_t list, I elem ) const;
// copy constructors not allowed
CUtlMultiList( CUtlMultiList<T, I> const& list ) { Assert(0); }
M m_Memory;
CUtlLinkedList<List_t, I> m_List;
I* m_pElementList;
I m_FirstFree;
I m_TotalElements;
int m_MaxElementIndex; // The number allocated (use int so we can catch overflow)
void ResetDbgInfo()
{
m_pElements = m_Memory.Base();
#ifdef _DEBUG
// Allocate space for the element list (which list is each element in)
if (m_Memory.NumAllocated() > 0)
{
if (!m_pElementList)
{
m_pElementList = (I*)malloc( m_Memory.NumAllocated() * sizeof(I) );
}
else
{
m_pElementList = (I*)realloc( m_pElementList, m_Memory.NumAllocated() * sizeof(I) );
}
}
#endif
}
// For debugging purposes;
// it's in release builds so this can be used in libraries correctly
ListElem_t *m_pElements;
};
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
template <class T, class I>
CUtlMultiList<T,I>::CUtlMultiList( int growSize, int initSize ) :
m_Memory(growSize, initSize), m_pElementList(0)
{
ConstructList();
}
template <class T, class I>
CUtlMultiList<T,I>::CUtlMultiList( void* pMemory, int memsize ) :
m_Memory((ListElem_t *)pMemory, memsize/sizeof(ListElem_t)), m_pElementList(0)
{
ConstructList();
}
template <class T, class I>
CUtlMultiList<T,I>::~CUtlMultiList( )
{
RemoveAll();
if (m_pElementList)
free(m_pElementList);
}
template <class T, class I>
void CUtlMultiList<T,I>::ConstructList( )
{
m_FirstFree = InvalidIndex();
m_TotalElements = 0;
m_MaxElementIndex = 0;
ResetDbgInfo();
}
//-----------------------------------------------------------------------------
// gets particular elements
//-----------------------------------------------------------------------------
template <class T, class I>
inline T& CUtlMultiList<T,I>::Element( I i )
{
return m_Memory[i].m_Element;
}
template <class T, class I>
inline T const& CUtlMultiList<T,I>::Element( I i ) const
{
return m_Memory[i].m_Element;
}
template <class T, class I>
inline T& CUtlMultiList<T,I>::operator[]( I i )
{
return m_Memory[i].m_Element;
}
template <class T, class I>
inline T const& CUtlMultiList<T,I>::operator[]( I i ) const
{
return m_Memory[i].m_Element;
}
//-----------------------------------------------------------------------------
// list creation/destruction
//-----------------------------------------------------------------------------
template <class T, class I>
typename CUtlMultiList<T,I>::ListHandle_t CUtlMultiList<T,I>::CreateList()
{
ListHandle_t l = m_List.AddToTail();
m_List[l].m_Head = m_List[l].m_Tail = InvalidIndex();
m_List[l].m_Count = 0;
return l;
}
template <class T, class I>
void CUtlMultiList<T,I>::DestroyList( ListHandle_t list )
{
Assert( IsValidList(list) );
RemoveAll( list );
m_List.Remove(list);
}
template <class T, class I>
bool CUtlMultiList<T,I>::IsValidList( ListHandle_t list ) const
{
return m_List.IsValidIndex(list);
}
//-----------------------------------------------------------------------------
// list statistics
//-----------------------------------------------------------------------------
template <class T, class I>
inline int CUtlMultiList<T,I>::TotalCount() const
{
return m_TotalElements;
}
template <class T, class I>
inline int CUtlMultiList<T,I>::Count( ListHandle_t list ) const
{
Assert( IsValidList(list) );
return m_List[list].m_Count;
}
template <class T, class I>
inline I CUtlMultiList<T,I>::MaxElementIndex() const
{
return m_MaxElementIndex;
}
//-----------------------------------------------------------------------------
// Traversing the list
//-----------------------------------------------------------------------------
template <class T, class I>
inline I CUtlMultiList<T,I>::Head(ListHandle_t list) const
{
Assert( IsValidList(list) );
return m_List[list].m_Head;
}
template <class T, class I>
inline I CUtlMultiList<T,I>::Tail(ListHandle_t list) const
{
Assert( IsValidList(list) );
return m_List[list].m_Tail;
}
template <class T, class I>
inline I CUtlMultiList<T,I>::Previous( I i ) const
{
Assert( IsValidIndex(i) );
return InternalElement(i).m_Previous;
}
template <class T, class I>
inline I CUtlMultiList<T,I>::Next( I i ) const
{
Assert( IsValidIndex(i) );
return InternalElement(i).m_Next;
}
//-----------------------------------------------------------------------------
// Are nodes in the list or valid?
//-----------------------------------------------------------------------------
template <class T, class I>
inline bool CUtlMultiList<T,I>::IndexInRange( int index ) // Static method
{
// Since I is not necessarily the type returned by M (int), we need to check that M returns
// indices which are representable by I. A common case is 'I === unsigned short', in which case
// case CUtlMemory will have 'InvalidIndex == (int)-1' (which casts to 65535 in I), and will
// happily return elements at index 65535 and above.
// Do a couple of static checks here: the invalid index should be (I)~0 given how we use m_MaxElementIndex,
// and 'I' should be unsigned (to avoid signed arithmetic errors for plausibly exhaustible ranges).
// These COMPILE_TIME_ASSERT checks need to be in individual scopes to avoid build breaks
// on MacOS and Linux due to a gcc bug.
{ COMPILE_TIME_ASSERT( (I)M::INVALID_INDEX == (I)~0 ); }
{ COMPILE_TIME_ASSERT( ( sizeof(I) > 2 ) || ( ( (I)-1 ) > 0 ) ); }
return ( ( (I)index == index ) && ( (I)index != InvalidIndex() ) );
}
template <class T, class I>
inline bool CUtlMultiList<T,I>::IsValidIndex( I i ) const
{
// GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0).
// We get the warning even if we cast inside the expression. It only goes away if we assign to another variable.
long x = i;
return (i < m_MaxElementIndex) && (x >= 0) &&
((m_Memory[i].m_Previous != i) || (m_Memory[i].m_Next == i));
}
template <class T, class I>
inline bool CUtlMultiList<T,I>::IsInList( I i ) const
{
// GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0).
// We get the warning even if we cast inside the expression. It only goes away if we assign to another variable.
long x = i;
return (i < m_MaxElementIndex) && (x >= 0) && (Previous(i) != i);
}
//-----------------------------------------------------------------------------
// Makes sure we have enough memory allocated to store a requested # of elements
//-----------------------------------------------------------------------------
template< class T, class I >
void CUtlMultiList<T, I>::EnsureCapacity( int num )
{
m_Memory.EnsureCapacity(num);
ResetDbgInfo();
}
//-----------------------------------------------------------------------------
// Deallocate memory
//-----------------------------------------------------------------------------
template <class T, class I>
void CUtlMultiList<T,I>::Purge()
{
RemoveAll();
m_List.Purge();
m_Memory.Purge( );
m_List.Purge();
m_FirstFree = InvalidIndex();
m_TotalElements = 0;
m_MaxElementIndex = 0;
ResetDbgInfo();
}
//-----------------------------------------------------------------------------
// Node allocation/deallocation
//-----------------------------------------------------------------------------
template <class T, class I>
I CUtlMultiList<T,I>::Alloc( )
{
I elem;
if (m_FirstFree == InvalidIndex())
{
// We can overflow before the utlmemory overflows, since we have have I != int
if ( !IndexInRange( m_MaxElementIndex ) )
{
// We rarely if ever handle alloc failure. Continuing leads to corruption.
Error( "CUtlMultiList overflow! (exhausted index range)\n" );
return InvalidIndex();
}
// Nothing in the free list; add.
// Since nothing is in the free list, m_TotalElements == total # of elements
// the list knows about.
if (m_MaxElementIndex == m_Memory.NumAllocated())
{
m_Memory.Grow();
ResetDbgInfo();
if ( m_MaxElementIndex >= m_Memory.NumAllocated() )
{
// We rarely if ever handle alloc failure. Continuing leads to corruption.
Error( "CUtlMultiList overflow! (exhausted memory allocator)\n" );
return InvalidIndex();
}
}
elem = (I)m_MaxElementIndex;
++m_MaxElementIndex;
}
else
{
elem = m_FirstFree;
m_FirstFree = InternalElement(m_FirstFree).m_Next;
}
// Mark the element as not being in a list
InternalElement(elem).m_Next = InternalElement(elem).m_Previous = elem;
++m_TotalElements;
Construct( &Element(elem) );
return elem;
}
template <class T, class I>
void CUtlMultiList<T,I>::Free( I elem )
{
Assert( IsValidIndex(elem) && !IsInList(elem) );
Destruct( &Element(elem) );
InternalElement(elem).m_Next = m_FirstFree;
m_FirstFree = elem;
--m_TotalElements;
}
//-----------------------------------------------------------------------------
// A test for debug mode only...
//-----------------------------------------------------------------------------
template <class T, class I>
inline bool CUtlMultiList<T,I>::IsElementInList( ListHandle_t list, I elem ) const
{
if (!m_pElementList)
return true;
return m_pElementList[elem] == list;
}
//-----------------------------------------------------------------------------
// list modification
//-----------------------------------------------------------------------------
template <class T, class I>
void CUtlMultiList<T,I>::LinkBefore( ListHandle_t list, I before, I elem )
{
Assert( IsValidIndex(elem) && IsValidList(list) );
// Unlink it if it's in the list at the moment
Unlink(list, elem);
ListElem_t& newElem = InternalElement(elem);
// The element *after* our newly linked one is the one we linked before.
newElem.m_Next = before;
if (before == InvalidIndex())
{
// In this case, we're linking to the end of the list, so reset the tail
newElem.m_Previous = m_List[list].m_Tail;
m_List[list].m_Tail = elem;
}
else
{
// Here, we're not linking to the end. Set the prev pointer to point to
// the element we're linking.
Assert( IsInList(before) );
ListElem_t& beforeElem = InternalElement(before);
newElem.m_Previous = beforeElem.m_Previous;
beforeElem.m_Previous = elem;
}
// Reset the head if we linked to the head of the list
if (newElem.m_Previous == InvalidIndex())
m_List[list].m_Head = elem;
else
InternalElement(newElem.m_Previous).m_Next = elem;
// one more element baby
++m_List[list].m_Count;
// Store the element into the list
if (m_pElementList)
m_pElementList[elem] = list;
}
template <class T, class I>
void CUtlMultiList<T,I>::LinkAfter( ListHandle_t list, I after, I elem )
{
Assert( IsValidIndex(elem) );
// Unlink it if it's in the list at the moment
Unlink(list, elem);
ListElem_t& newElem = InternalElement(elem);
// The element *before* our newly linked one is the one we linked after
newElem.m_Previous = after;
if (after == InvalidIndex())
{
// In this case, we're linking to the head of the list, reset the head
newElem.m_Next = m_List[list].m_Head;
m_List[list].m_Head = elem;
}
else
{
// Here, we're not linking to the end. Set the next pointer to point to
// the element we're linking.
Assert( IsInList(after) );
ListElem_t& afterElem = InternalElement(after);
newElem.m_Next = afterElem.m_Next;
afterElem.m_Next = elem;
}
// Reset the tail if we linked to the tail of the list
if (newElem.m_Next == InvalidIndex())
m_List[list].m_Tail = elem;
else
InternalElement(newElem.m_Next).m_Previous = elem;
// one more element baby
++m_List[list].m_Count;
// Store the element into the list
if (m_pElementList)
m_pElementList[elem] = list;
}
template <class T, class I>
void CUtlMultiList<T,I>::Unlink( ListHandle_t list, I elem )
{
Assert( IsValidIndex(elem) && IsValidList(list) );
if (IsInList(elem))
{
// Make sure the element is in the right list
Assert( IsElementInList( list, elem ) );
ListElem_t& oldElem = InternalElement(elem);
// If we're the first guy, reset the head
// otherwise, make our previous node's next pointer = our next
if (oldElem.m_Previous != InvalidIndex())
InternalElement(oldElem.m_Previous).m_Next = oldElem.m_Next;
else
m_List[list].m_Head = oldElem.m_Next;
// If we're the last guy, reset the tail
// otherwise, make our next node's prev pointer = our prev
if (oldElem.m_Next != InvalidIndex())
InternalElement(oldElem.m_Next).m_Previous = oldElem.m_Previous;
else
m_List[list].m_Tail = oldElem.m_Previous;
// This marks this node as not in the list,
// but not in the free list either
oldElem.m_Previous = oldElem.m_Next = elem;
// One less puppy
--m_List[list].m_Count;
// Store the element into the list
if (m_pElementList)
m_pElementList[elem] = m_List.InvalidIndex();
}
}
template <class T, class I>
inline void CUtlMultiList<T,I>::LinkToHead( ListHandle_t list, I elem )
{
LinkAfter( list, InvalidIndex(), elem );
}
template <class T, class I>
inline void CUtlMultiList<T,I>::LinkToTail( ListHandle_t list, I elem )
{
LinkBefore( list, InvalidIndex(), elem );
}
//-----------------------------------------------------------------------------
// Insertion methods; allocates and links (uses default constructor)
//-----------------------------------------------------------------------------
template <class T, class I>
I CUtlMultiList<T,I>::InsertBefore( ListHandle_t list, I before )
{
// Make a new node
I newNode = Alloc();
if ( newNode == InvalidIndex() )
return newNode;
// Link it in
LinkBefore( list, before, newNode );
// Construct the data
Construct( &Element(newNode) );
return newNode;
}
template <class T, class I>
I CUtlMultiList<T,I>::InsertAfter( ListHandle_t list, I after )
{
// Make a new node
I newNode = Alloc();
if ( newNode == InvalidIndex() )
return newNode;
// Link it in
LinkAfter( list, after, newNode );
// Construct the data
Construct( &Element(newNode) );
return newNode;
}
template <class T, class I>
inline I CUtlMultiList<T,I>::AddToHead( ListHandle_t list )
{
return InsertAfter( list, InvalidIndex() );
}
template <class T, class I>
inline I CUtlMultiList<T,I>::AddToTail( ListHandle_t list )
{
return InsertBefore( list, InvalidIndex() );
}
//-----------------------------------------------------------------------------
// Insertion methods; allocates and links (uses copy constructor)
//-----------------------------------------------------------------------------
template <class T, class I>
I CUtlMultiList<T,I>::InsertBefore( ListHandle_t list, I before, T const& src )
{
// Make a new node
I newNode = Alloc();
if ( newNode == InvalidIndex() )
return newNode;
// Link it in
LinkBefore( list, before, newNode );
// Construct the data
CopyConstruct( &Element(newNode), src );
return newNode;
}
template <class T, class I>
I CUtlMultiList<T,I>::InsertAfter( ListHandle_t list, I after, T const& src )
{
// Make a new node
I newNode = Alloc();
if ( newNode == InvalidIndex() )
return newNode;
// Link it in
LinkAfter( list, after, newNode );
// Construct the data
CopyConstruct( &Element(newNode), src );
return newNode;
}
template <class T, class I>
inline I CUtlMultiList<T,I>::AddToHead( ListHandle_t list, T const& src )
{
return InsertAfter( list, InvalidIndex(), src );
}
template <class T, class I>
inline I CUtlMultiList<T,I>::AddToTail( ListHandle_t list, T const& src )
{
return InsertBefore( list, InvalidIndex(), src );
}
//-----------------------------------------------------------------------------
// Removal methods
//-----------------------------------------------------------------------------
template <class T, class I>
void CUtlMultiList<T,I>::Remove( ListHandle_t list, I elem )
{
if (IsInList(elem))
Unlink(list, elem);
Free( elem );
}
// Removes all items in a single list
template <class T, class I>
void CUtlMultiList<T,I>::RemoveAll( ListHandle_t list )
{
Assert( IsValidList(list) );
I i = Head(list);
I next;
while( i != InvalidIndex() )
{
next = Next(i);
Remove(list, i);
i = next;
}
}
template <class T, class I>
void CUtlMultiList<T,I>::RemoveAll()
{
if (m_MaxElementIndex == 0)
return;
// Put everything into the free list
I prev = InvalidIndex();
for (int i = (int)m_MaxElementIndex; --i >= 0; )
{
// Invoke the destructor
if (IsValidIndex((I)i))
Destruct( &Element((I)i) );
// next points to the next free list item
InternalElement((I)i).m_Next = prev;
// Indicates it's in the free list
InternalElement((I)i).m_Previous = (I)i;
prev = (I)i;
}
// First free points to the first element
m_FirstFree = 0;
// Clear everything else out
for (I list = m_List.Head(); list != m_List.InvalidIndex(); list = m_List.Next(list) )
{
m_List[list].m_Head = InvalidIndex();
m_List[list].m_Tail = InvalidIndex();
m_List[list].m_Count = 0;
}
m_TotalElements = 0;
}
#include "tier0/memdbgoff.h"
#endif // UTLMULTILIST_H

625
public/tier1/utlntree.h Normal file
View File

@@ -0,0 +1,625 @@
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: N-way tree container class
//
// $Revision: $
// $NoKeywords: $
//=============================================================================//
#ifndef UTLNTREE_H
#define UTLNTREE_H
#ifdef _WIN32
#pragma once
#endif
#include "basetypes.h"
#include "utlmemory.h"
#include "tier0/dbg.h"
#define INVALID_NTREE_IDX ((I)~0)
//-----------------------------------------------------------------------------
// class CUtlNTree:
// description:
// A lovely index-based linked list! T is the class type, I is the index
// type, which usually should be an unsigned short or smaller.
//-----------------------------------------------------------------------------
template <class T, class I = unsigned short>
class CUtlNTree
{
public:
typedef T ElemType_t;
typedef I IndexType_t;
// constructor, destructor
CUtlNTree( int growSize = 0, int initSize = 0 );
CUtlNTree( void *pMemory, int memsize );
~CUtlNTree( );
// gets particular elements
T& Element( I i );
const T& Element( I i ) const;
T& operator[]( I i );
const T& operator[]( I i ) const;
// Make sure we have a particular amount of memory
void EnsureCapacity( int num );
// Clears the tree, doesn't deallocate memory
void RemoveAll();
// Memory deallocation
void Purge();
// Allocation/deallocation methods
I Alloc( );
void Free( I elem );
void FreeSubTree( I elem );
// list modification
void SetRoot( I root );
void LinkChildBefore( I parent, I before, I elem );
void LinkChildAfter( I parent, I after, I elem );
void Unlink( I elem );
// Alloc + link combined
I InsertChildBefore( I parent, I before );
I InsertChildAfter( I parent, I after );
I InsertChildBefore( I parent, I before, const T &elem );
I InsertChildAfter( I parent, I after, const T &elem );
// Unlink + free combined
void Remove( I elem );
void RemoveSubTree( I elem );
// invalid index
inline static I InvalidIndex() { return INVALID_NTREE_IDX; }
inline static size_t ElementSize() { return sizeof(Node_t); }
// list statistics
int Count() const;
I MaxElementIndex() const;
// Traversing the list
I Root() const;
I FirstChild( I i ) const;
I PrevSibling( I i ) const;
I NextSibling( I i ) const;
I Parent( I i ) const;
// Are nodes in the list or valid?
bool IsValidIndex( I i ) const;
bool IsInTree( I i ) const;
protected:
// What the linked list element looks like
struct Node_t
{
T m_Element;
I m_Parent;
I m_FirstChild;
I m_PrevSibling;
I m_NextSibling;
private:
// No copy constructor for these...
Node_t( const Node_t& );
};
// constructs the class
void ConstructList();
// Allocates the element, doesn't call the constructor
I AllocInternal();
// Gets at the node element....
Node_t& InternalNode( I i ) { return m_Memory[i]; }
const Node_t& InternalNode( I i ) const { return m_Memory[i]; }
void ResetDbgInfo()
{
m_pElements = m_Memory.Base();
}
// copy constructors not allowed
CUtlNTree( CUtlNTree<T, I> const& tree ) { Assert(0); }
CUtlMemory<Node_t> m_Memory;
I m_Root;
I m_FirstFree;
I m_ElementCount; // The number actually in the tree
I m_MaxElementIndex; // The max index we've ever assigned
// For debugging purposes;
// it's in release builds so this can be used in libraries correctly
Node_t *m_pElements;
};
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
template <class T, class I>
CUtlNTree<T,I>::CUtlNTree( int growSize, int initSize ) :
m_Memory(growSize, initSize)
{
ConstructList();
ResetDbgInfo();
}
template <class T, class I>
CUtlNTree<T,I>::CUtlNTree( void* pMemory, int memsize ) :
m_Memory(pMemory, memsize/sizeof(T))
{
ConstructList();
ResetDbgInfo();
}
template <class T, class I>
CUtlNTree<T,I>::~CUtlNTree( )
{
RemoveAll();
}
template <class T, class I>
void CUtlNTree<T,I>::ConstructList()
{
m_Root = InvalidIndex();
m_FirstFree = InvalidIndex();
m_ElementCount = m_MaxElementIndex = 0;
}
//-----------------------------------------------------------------------------
// gets particular elements
//-----------------------------------------------------------------------------
template <class T, class I>
inline T& CUtlNTree<T,I>::Element( I i )
{
return m_Memory[i].m_Element;
}
template <class T, class I>
inline const T& CUtlNTree<T,I>::Element( I i ) const
{
return m_Memory[i].m_Element;
}
template <class T, class I>
inline T& CUtlNTree<T,I>::operator[]( I i )
{
return m_Memory[i].m_Element;
}
template <class T, class I>
inline const T& CUtlNTree<T,I>::operator[]( I i ) const
{
return m_Memory[i].m_Element;
}
//-----------------------------------------------------------------------------
// list statistics
//-----------------------------------------------------------------------------
template <class T, class I>
inline int CUtlNTree<T,I>::Count() const
{
return m_ElementCount;
}
template <class T, class I>
inline I CUtlNTree<T,I>::MaxElementIndex() const
{
return m_MaxElementIndex;
}
//-----------------------------------------------------------------------------
// Traversing the list
//-----------------------------------------------------------------------------
template <class T, class I>
inline I CUtlNTree<T,I>::Root() const
{
return m_Root;
}
template <class T, class I>
inline I CUtlNTree<T,I>::FirstChild( I i ) const
{
Assert( IsInTree(i) );
return InternalNode(i).m_FirstChild;
}
template <class T, class I>
inline I CUtlNTree<T,I>::PrevSibling( I i ) const
{
Assert( IsInTree(i) );
return InternalNode(i).m_PrevSibling;
}
template <class T, class I>
inline I CUtlNTree<T,I>::NextSibling( I i ) const
{
Assert( IsInTree(i) );
return InternalNode(i).m_NextSibling;
}
template <class T, class I>
inline I CUtlNTree<T,I>::Parent( I i ) const
{
Assert( IsInTree(i) );
return InternalNode(i).m_Parent;
}
//-----------------------------------------------------------------------------
// Are nodes in the list or valid?
//-----------------------------------------------------------------------------
template <class T, class I>
inline bool CUtlNTree<T,I>::IsValidIndex( I i ) const
{
return (i < m_MaxElementIndex) && (i >= 0);
}
template <class T, class I>
inline bool CUtlNTree<T,I>::IsInTree( I i ) const
{
bool bIndexPositive = ( 0 > (I)(-1) ) ? (i >= 0) : true;
return (i < m_MaxElementIndex) && bIndexPositive && (InternalNode(i).m_PrevSibling != i);
}
//-----------------------------------------------------------------------------
// Makes sure we have enough memory allocated to store a requested # of elements
//-----------------------------------------------------------------------------
template< class T, class I >
void CUtlNTree<T, I>::EnsureCapacity( int num )
{
MEM_ALLOC_CREDIT_CLASS();
m_Memory.EnsureCapacity(num);
ResetDbgInfo();
}
//-----------------------------------------------------------------------------
// Deallocate memory
//-----------------------------------------------------------------------------
template <class T, class I>
void CUtlNTree<T,I>::Purge()
{
RemoveAll();
m_Memory.Purge( );
m_FirstFree = InvalidIndex();
m_MaxElementIndex = 0;
ResetDbgInfo();
}
//-----------------------------------------------------------------------------
// Node allocation/deallocation
//-----------------------------------------------------------------------------
template <class T, class I>
I CUtlNTree<T,I>::AllocInternal( )
{
I elem;
if ( m_FirstFree == INVALID_NTREE_IDX )
{
// Nothing in the free list; add.
// Since nothing is in the free list, m_MaxElementIndex == total # of elements
// the list knows about.
if ((int)m_MaxElementIndex == m_Memory.NumAllocated())
{
MEM_ALLOC_CREDIT_CLASS();
m_Memory.Grow();
}
Assert( m_MaxElementIndex != INVALID_NTREE_IDX );
elem = (I)m_MaxElementIndex;
++m_MaxElementIndex;
if ( elem == InvalidIndex() )
{
Error("CUtlNTree overflow!\n");
}
}
else
{
elem = m_FirstFree;
m_FirstFree = InternalNode( m_FirstFree ).m_NextSibling;
}
Node_t &node = InternalNode( elem );
node.m_NextSibling = node.m_PrevSibling = node.m_Parent = node.m_FirstChild = INVALID_NTREE_IDX;
ResetDbgInfo();
// one more element baby
++m_ElementCount;
return elem;
}
template <class T, class I>
I CUtlNTree<T,I>::Alloc( )
{
I elem = AllocInternal();
Construct( &Element(elem) );
return elem;
}
template <class T, class I>
void CUtlNTree<T,I>::Free( I elem )
{
Assert( IsInTree( elem ) );
Unlink( elem );
// If there's children, this will result in leaks. Use FreeSubTree instead.
Assert( FirstChild( elem ) == INVALID_NTREE_IDX );
Node_t &node = InternalNode( elem );
Destruct( &node.m_Element );
node.m_NextSibling = m_FirstFree;
node.m_PrevSibling = elem; // Marks it as being in the free list
node.m_Parent = node.m_FirstChild = INVALID_NTREE_IDX;
m_FirstFree = elem;
// one less element baby
--m_ElementCount;
}
template <class T, class I>
void CUtlNTree<T,I>::FreeSubTree( I elem )
{
Assert( IsValidIndex( elem ) );
I child = FirstChild( elem );
while ( child != INVALID_NTREE_IDX )
{
I next = NextSibling( child );
FreeSubTree( child );
child = next;
}
Free( elem );
}
//-----------------------------------------------------------------------------
// Clears the tree
//-----------------------------------------------------------------------------
template <class T, class I>
void CUtlNTree<T,I>::RemoveAll()
{
if ( m_MaxElementIndex == 0 )
return;
// Put everything into the free list (even unlinked things )
I prev = InvalidIndex();
for (int i = (int)m_MaxElementIndex; --i >= 0; prev = (I)i )
{
Node_t &node = InternalNode( i );
if ( IsInTree( i ) )
{
Destruct( &node.m_Element );
}
node.m_NextSibling = prev;
node.m_PrevSibling = (I)i; // Marks it as being in the free list
node.m_Parent = node.m_FirstChild = INVALID_NTREE_IDX;
}
// First free points to the first element
m_FirstFree = 0;
// Clear everything else out
m_Root = INVALID_NTREE_IDX;
m_ElementCount = 0;
}
//-----------------------------------------------------------------------------
// list modification
//-----------------------------------------------------------------------------
template <class T, class I>
void CUtlNTree<T,I>::SetRoot( I root )
{
// Resetting the root while it's got stuff in it is bad...
Assert( m_Root == InvalidIndex() );
m_Root = root;
}
//-----------------------------------------------------------------------------
// Links a node after a particular node
//-----------------------------------------------------------------------------
template <class T, class I>
void CUtlNTree<T,I>::LinkChildAfter( I parent, I after, I elem )
{
Assert( IsInTree(elem) );
// Unlink it if it's in the list at the moment
Unlink(elem);
Node_t& newElem = InternalNode(elem);
newElem.m_Parent = parent;
newElem.m_PrevSibling = after;
if ( after != INVALID_NTREE_IDX )
{
Node_t& prevSiblingNode = InternalNode( after );
newElem.m_NextSibling = prevSiblingNode.m_NextSibling;
prevSiblingNode.m_NextSibling = elem;
}
else
{
if ( parent != INVALID_NTREE_IDX )
{
Node_t& parentNode = InternalNode( parent );
newElem.m_NextSibling = parentNode.m_FirstChild;
parentNode.m_FirstChild = elem;
}
else
{
newElem.m_NextSibling = m_Root;
if ( m_Root != INVALID_NTREE_IDX )
{
Node_t& rootNode = InternalNode( m_Root );
rootNode.m_PrevSibling = elem;
}
m_Root = elem;
}
}
if ( newElem.m_NextSibling != INVALID_NTREE_IDX )
{
Node_t& nextSiblingNode = InternalNode( newElem.m_NextSibling );
nextSiblingNode.m_PrevSibling = elem;
}
}
//-----------------------------------------------------------------------------
// Links a node before a particular node
//-----------------------------------------------------------------------------
template <class T, class I>
void CUtlNTree<T,I>::LinkChildBefore( I parent, I before, I elem )
{
Assert( IsValidIndex(elem) );
if ( before != INVALID_NTREE_IDX )
{
LinkChildAfter( parent, InternalNode( before ).m_PrevSibling, elem );
return;
}
// NOTE: I made the choice to do an O(n) operation here
// instead of store more data per node (LastChild).
// This might not be the right choice. Revisit if we get perf problems.
I after;
if ( parent != INVALID_NTREE_IDX )
{
after = InternalNode( parent ).m_FirstChild;
}
else
{
after = m_Root;
}
if ( after == INVALID_NTREE_IDX )
{
LinkChildAfter( parent, after, elem );
return;
}
I next = InternalNode( after ).m_NextSibling;
while ( next != InvalidIndex() )
{
after = next;
next = InternalNode( next ).m_NextSibling;
}
LinkChildAfter( parent, after, elem );
}
//-----------------------------------------------------------------------------
// Unlinks a node from the tree
//-----------------------------------------------------------------------------
template <class T, class I>
void CUtlNTree<T,I>::Unlink( I elem )
{
Assert( IsInTree(elem) );
Node_t *pOldNode = &InternalNode( elem );
// If we're the first guy, reset the head
// otherwise, make our previous node's next pointer = our next
if ( pOldNode->m_PrevSibling != INVALID_NTREE_IDX )
{
InternalNode( pOldNode->m_PrevSibling ).m_NextSibling = pOldNode->m_NextSibling;
}
else
{
if ( pOldNode->m_Parent != INVALID_NTREE_IDX )
{
InternalNode( pOldNode->m_Parent ).m_FirstChild = pOldNode->m_NextSibling;
}
else if ( m_Root == elem )
{
m_Root = pOldNode->m_NextSibling;
}
}
// If we're the last guy, reset the tail
// otherwise, make our next node's prev pointer = our prev
if ( pOldNode->m_NextSibling != INVALID_NTREE_IDX )
{
InternalNode( pOldNode->m_NextSibling ).m_PrevSibling = pOldNode->m_PrevSibling;
}
// Unlink everything except children
pOldNode->m_Parent = pOldNode->m_PrevSibling = pOldNode->m_NextSibling = INVALID_NTREE_IDX;
}
//-----------------------------------------------------------------------------
// Alloc + link combined
//-----------------------------------------------------------------------------
template <class T, class I>
I CUtlNTree<T,I>::InsertChildBefore( I parent, I before )
{
I elem = AllocInternal();
Construct( &Element( elem ) );
LinkChildBefore( parent, before, elem );
return elem;
}
template <class T, class I>
I CUtlNTree<T,I>::InsertChildAfter( I parent, I after )
{
I elem = AllocInternal();
Construct( &Element( elem ) );
LinkChildAfter( parent, after, elem );
return elem;
}
template <class T, class I>
I CUtlNTree<T,I>::InsertChildBefore( I parent, I before, const T &data )
{
I elem = AllocInternal();
CopyConstruct( &Element( elem ), data );
LinkChildBefore( parent, before, elem );
return elem;
}
template <class T, class I>
I CUtlNTree<T,I>::InsertChildAfter( I parent, I after, const T &data )
{
I elem = AllocInternal();
CopyConstruct( &Element( elem ), data );
LinkChildAfter( parent, after, elem );
return elem;
}
//-----------------------------------------------------------------------------
// Unlink + free combined
//-----------------------------------------------------------------------------
template <class T, class I>
void CUtlNTree<T,I>::Remove( I elem )
{
Unlink( elem );
Free( elem );
}
template <class T, class I>
void CUtlNTree<T,I>::RemoveSubTree( I elem )
{
UnlinkSubTree( elem );
Free( elem );
}
#endif // UTLNTREE_H

View File

@@ -0,0 +1,258 @@
//===== Copyright <20> 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 T> 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<T>& 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 T> class CUtlReferenceList : public CUtlIntrusiveDList< CUtlReference<T> >
{
public:
~CUtlReferenceList( void )
{
CUtlReference<T> *i = CUtlIntrusiveDList<CUtlReference<T> >::m_pHead;
while( i )
{
CUtlReference<T> *n = i->m_pNext;
i->m_pNext = NULL;
i->m_pPrev = NULL;
i->m_pObject = NULL;
i = n;
}
CUtlIntrusiveDList<CUtlReference<T> >::m_pHead = NULL;
}
};
//-----------------------------------------------------------------------------
// Put this macro in classes that are referenced by CUtlReference
//-----------------------------------------------------------------------------
#define DECLARE_REFERENCED_CLASS( _className ) \
private: \
CUtlReferenceList< _className > m_References; \
template<class T> friend class CUtlReference;
template < class T >
class CUtlReferenceVector : public CUtlBlockVector< CUtlReference< T > >
{
public:
void RemoveAll()
{
for ( int i = 0; i < this->Count(); i++ )
{
this->Element( i ).KillRef();
}
CUtlBlockVector< CUtlReference< T > >::RemoveAll();
}
void FastRemove( int elem )
{
Assert( this->IsValidIndex(elem) );
if ( this->m_Size > 0 )
{
if ( elem != this->m_Size -1 )
{
this->Element( elem ).Set( this->Element( this->m_Size - 1 ).GetObject() );
}
Destruct( &Element( this->m_Size - 1 ) );
--this->m_Size;
}
}
bool FindAndFastRemove( const CUtlReference< T >& src )
{
int elem = Find( src );
if ( elem != -1 )
{
FastRemove( elem );
return true;
}
return false;
}
private:
//
// Disallow methods of CUtlBlockVector that can cause element addresses to change, thus
// breaking assumptions of CUtlReference
//
void Remove( int elem );
bool FindAndRemove( const T& src );
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

52
public/tier1/utlpair.h Normal file
View File

@@ -0,0 +1,52 @@
//========= Copyright, Valve Corporation, All rights reserved. ================//
//
// std::pair style container; exists to work easily in our CUtlMap/CUtlHashMap classes
//
//=============================================================================//
#ifndef UTLPAIR_H
#define UTLPAIR_H
#ifdef _WIN32
#pragma once
#endif
// std::pair style container; exists to work easily in our CUtlMap/CUtlHashMap classes
template<typename T1, typename T2>
class CUtlPair
{
public:
CUtlPair() {}
CUtlPair( T1 t1, T2 t2 ) : first( t1 ), second( t2 ) {}
bool operator<( const CUtlPair<T1,T2> &rhs ) const {
if ( first != rhs.first )
return first < rhs.first;
return second < rhs.second;
}
bool operator==( const CUtlPair<T1,T2> &rhs ) const {
return first == rhs.first && second == rhs.second;
}
T1 first;
T2 second;
};
// utility to make a CUtlPair without having to specify template parameters
template<typename T1, typename T2>
inline CUtlPair<T1,T2> MakeUtlPair( T1 t1, T2 t2 )
{
return CUtlPair<T1,T2>(t1, t2);
}
//// HashItem() overload that works automatically with our hash containers
//template<typename T1, typename T2>
//inline uint32 HashItem( const CUtlPair<T1,T2> &item )
//{
// return HashItem( (uint64)HashItem( item.first ) + ((uint64)HashItem( item.second ) << 32) );
//}
#endif // UTLPAIR_H

View File

@@ -0,0 +1,249 @@
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#ifndef UTLPRIORITYQUEUE_H
#define UTLPRIORITYQUEUE_H
#ifdef _WIN32
#pragma once
#endif
#include "tier1/utlvector.h"
template < typename T >
class CDefUtlPriorityQueueLessFunc
{
public:
bool operator()( const T &lhs, const T &rhs, bool (*lessFuncPtr)( T const&, T const& ) )
{
return lessFuncPtr( lhs, rhs );
}
};
template < typename T >
class CDefUtlPriorityQueueSetIndexFunc
{
public:
inline static void SetIndex( T &heapElement, int nNewIndex ) { }
};
// T is the type stored in the queue, it must include the priority
// The head of the list contains the element with GREATEST priority
// configure the LessFunc_t to get the desired queue order
template< class T, class LessFunc = CDefUtlPriorityQueueLessFunc< T >, class A = CUtlMemory<T>, class SetIndexFunc = CDefUtlPriorityQueueSetIndexFunc< T > >
class CUtlPriorityQueue
{
public:
// Less func typedef
// Returns true if the first parameter is "less priority" than the second
// Items that are "less priority" sort toward the tail of the queue
typedef bool (*LessFunc_t)( T const&, T const& );
typedef T ElemType_t;
// constructor: lessfunc is required, but may be set after the constructor with
// SetLessFunc
CUtlPriorityQueue( int growSize = 0, int initSize = 0, LessFunc_t lessfunc = 0 );
CUtlPriorityQueue( T *pMemory, int numElements, LessFunc_t lessfunc = 0 );
// gets particular elements
inline T const& ElementAtHead() const { return m_heap.Element(0); }
inline bool IsValidIndex(int index) { return m_heap.IsValidIndex(index); }
// O(lgn) to rebalance the heap
void RemoveAtHead();
void RemoveAt( int index );
// Update the position of the specified element in the tree for it current value O(lgn)
void RevaluateElement( const int index );
// O(lgn) to rebalance heap
void Insert( T const &element );
// Sets the less func
void SetLessFunc( LessFunc_t func );
// Returns the count of elements in the queue
inline int Count() const { return m_heap.Count(); }
// doesn't deallocate memory
void RemoveAll() { m_heap.RemoveAll(); }
// Memory deallocation
void Purge() { m_heap.Purge(); }
inline const T & Element( int index ) const { return m_heap.Element(index); }
inline T & Element( int index ) { return m_heap.Element(index); }
bool IsHeapified();
protected:
CUtlVector<T, A> m_heap;
void Swap( int index1, int index2 );
int PercolateDown( int nIndex );
int PercolateUp( int nIndex );
// Used for sorting.
LessFunc_t m_LessFunc;
};
template< class T, class LessFunc, class A, class SetIndexFunc >
inline CUtlPriorityQueue<T, LessFunc, A, SetIndexFunc >::CUtlPriorityQueue( int growSize, int initSize, LessFunc_t lessfunc ) :
m_heap(growSize, initSize), m_LessFunc(lessfunc)
{
}
template< class T, class LessFunc, class A, class SetIndexFunc >
inline CUtlPriorityQueue<T, LessFunc, A, SetIndexFunc >::CUtlPriorityQueue( T *pMemory, int allocationCount, LessFunc_t lessfunc ) :
m_heap(pMemory, allocationCount), m_LessFunc(lessfunc)
{
}
template< class T, class LessFunc, class A, class SetIndexFunc >
inline void CUtlPriorityQueue<T, LessFunc, A, SetIndexFunc >::RemoveAtHead()
{
m_heap.FastRemove( 0 );
if ( Count() > 0 )
{
SetIndexFunc::SetIndex( m_heap[ 0 ], 0 );
}
PercolateDown( 0 );
}
template< class T, class LessFunc, class A, class SetIndexFunc >
inline void CUtlPriorityQueue<T, LessFunc, A, SetIndexFunc >::RemoveAt( int index )
{
Assert(m_heap.IsValidIndex(index));
m_heap.FastRemove( index );
if ( index < Count() )
{
SetIndexFunc::SetIndex( m_heap[ index ], index );
}
RevaluateElement( index );
}
template< class T, class LessFunc, class A, class SetIndexFunc >
inline void CUtlPriorityQueue<T, LessFunc, A, SetIndexFunc >::RevaluateElement( const int nStartingIndex )
{
int index = PercolateDown( nStartingIndex );
// If index is still the same as the starting index, then the specified element was larger than
// its children, so it could be larger than its parent, so treat this like an insertion and swap
// the node with its parent until it is no longer larger than its parent.
if ( index == nStartingIndex )
{
PercolateUp( index );
}
}
template< class T, class LessFunc, class A, class SetIndexFunc >
inline bool CUtlPriorityQueue<T, LessFunc, A, SetIndexFunc >::IsHeapified()
{
LessFunc lessFunc;
for ( int child = Count(); child-- > 1; ) // no need to check the element [0] , it's the parent of all and has no parent itself
{
int parent = ( ( child + 1 ) / 2 ) - 1;
if ( lessFunc( m_heap[ parent ], m_heap[ child ], m_LessFunc ) )
{
return false; // this priority queue is not properly heapified, needs reordering
}
}
return true; // the priority queue is heapified correctly, needs no reordering
}
template< class T, class LessFunc, class A, class SetIndexFunc >
inline int CUtlPriorityQueue<T, LessFunc, A, SetIndexFunc >::PercolateDown( int index )
{
int count = Count();
LessFunc lessFunc;
int half = count/2;
int larger = index;
while ( index < half )
{
int child = ((index+1) * 2) - 1; // if we wasted an element, this math would be more compact (1 based array)
if ( child < count )
{
// Item has been filtered down to its proper place, terminate.
if ( lessFunc( m_heap[index], m_heap[child], m_LessFunc ) )
{
// mark the potential swap and check the other child
larger = child;
}
}
// go to sibling
child++;
if ( child < count )
{
// If this child is larger, swap it instead
if ( lessFunc( m_heap[larger], m_heap[child], m_LessFunc ) )
larger = child;
}
if ( larger == index )
break;
// swap with the larger child
Swap( index, larger );
index = larger;
}
return index;
}
template< class T, class LessFunc, class A, class SetIndexFunc >
inline int CUtlPriorityQueue<T, LessFunc, A, SetIndexFunc >::PercolateUp( int index )
{
if ( index >= Count() )
return index;
LessFunc lessFunc;
while ( index != 0 )
{
int parent = ((index+1) / 2) - 1;
if ( lessFunc( m_heap[index], m_heap[parent], m_LessFunc ) )
break;
// swap with parent and repeat
Swap( parent, index );
index = parent;
}
return index;
}
template< class T, class LessFunc, class A, class SetIndexFunc >
inline void CUtlPriorityQueue<T, LessFunc, A, SetIndexFunc >::Insert( T const &element )
{
int index = m_heap.AddToTail();
m_heap[index] = element;
SetIndexFunc::SetIndex( m_heap[ index ], index );
PercolateUp( index );
}
template< class T, class LessFunc, class A, class SetIndexFunc >
inline void CUtlPriorityQueue<T, LessFunc, A, SetIndexFunc >::Swap( int index1, int index2 )
{
T tmp = m_heap[index1];
m_heap[index1] = m_heap[index2];
m_heap[index2] = tmp;
SetIndexFunc::SetIndex( m_heap[ index1 ], index1 );
SetIndexFunc::SetIndex( m_heap[ index2 ], index2 );
}
template< class T, class LessFunc, class A, class SetIndexFunc >
inline void CUtlPriorityQueue<T, LessFunc, A, SetIndexFunc >::SetLessFunc( LessFunc_t lessfunc )
{
m_LessFunc = lessfunc;
}
#endif // UTLPRIORITYQUEUE_H

176
public/tier1/utlqueue.h Normal file
View File

@@ -0,0 +1,176 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef UTLQUEUE_H
#define UTLQUEUE_H
#ifdef _WIN32
#pragma once
#endif
#include "utlvector.h"
// T is the type stored in the queue
template< class T, class M = CUtlMemory< T > >
class CUtlQueue
{
public:
// constructor: lessfunc is required, but may be set after the constructor with
// SetLessFunc
CUtlQueue( int growSize = 0, int initSize = 0 );
CUtlQueue( T *pMemory, int numElements );
// element access
T& operator[]( int i );
T const& operator[]( int i ) const;
T& Element( int i );
T const& Element( int i ) const;
// return the item from the front of the queue and delete it
T const& RemoveAtHead();
// return the item from the end of the queue and delete it
T const& RemoveAtTail();
// return item at the front of the queue
T const& Head();
// return item at the end of the queue
T const& Tail();
// put a new item on the queue to the tail.
void Insert( T const &element );
// checks if an element of this value already exists on the queue, returns true if it does
bool Check( T const element );
// Returns the count of elements in the queue
int Count() const { return m_heap.Count(); }
// Is element index valid?
bool IsIdxValid( int i ) const;
// doesn't deallocate memory
void RemoveAll() { m_heap.RemoveAll(); }
// Memory deallocation
void Purge() { m_heap.Purge(); }
protected:
CUtlVector<T, M> m_heap;
T m_current;
};
//-----------------------------------------------------------------------------
// The CUtlQueueFixed class:
// A queue class with a fixed allocation scheme
//-----------------------------------------------------------------------------
template< class T, size_t MAX_SIZE >
class CUtlQueueFixed : public CUtlQueue< T, CUtlMemoryFixed<T, MAX_SIZE > >
{
typedef CUtlQueue< T, CUtlMemoryFixed<T, MAX_SIZE > > BaseClass;
public:
// constructor, destructor
CUtlQueueFixed( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {}
CUtlQueueFixed( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {}
};
template< class T, class M >
inline CUtlQueue<T, M>::CUtlQueue( int growSize, int initSize ) :
m_heap(growSize, initSize)
{
}
template< class T, class M >
inline CUtlQueue<T, M>::CUtlQueue( T *pMemory, int numElements ) :
m_heap(pMemory, numElements)
{
}
//-----------------------------------------------------------------------------
// element access
//-----------------------------------------------------------------------------
template< class T, class M >
inline T& CUtlQueue<T,M>::operator[]( int i )
{
return m_heap[i];
}
template< class T, class M >
inline T const& CUtlQueue<T,M>::operator[]( int i ) const
{
return m_heap[i];
}
template< class T, class M >
inline T& CUtlQueue<T,M>::Element( int i )
{
return m_heap[i];
}
template< class T, class M >
inline T const& CUtlQueue<T,M>::Element( int i ) const
{
return m_heap[i];
}
//-----------------------------------------------------------------------------
// Is element index valid?
//-----------------------------------------------------------------------------
template< class T, class M >
inline bool CUtlQueue<T,M>::IsIdxValid( int i ) const
{
return (i >= 0) && (i < m_heap.Count());
}
template <class T, class M>
inline T const& CUtlQueue<T, M>::RemoveAtHead()
{
m_current = m_heap[0];
m_heap.Remove((int)0);
return m_current;
}
template <class T, class M>
inline T const& CUtlQueue<T, M>::RemoveAtTail()
{
m_current = m_heap[ m_heap.Count() - 1 ];
m_heap.Remove((int)(m_heap.Count() - 1));
return m_current;
}
template <class T, class M>
inline T const& CUtlQueue<T, M>::Head()
{
m_current = m_heap[0];
return m_current;
}
template <class T, class M>
inline T const& CUtlQueue<T, M>::Tail()
{
m_current = m_heap[ m_heap.Count() - 1 ];
return m_current;
}
template <class T, class M>
void CUtlQueue<T, M>::Insert( T const &element )
{
int index = m_heap.AddToTail();
m_heap[index] = element;
}
template <class T, class M>
bool CUtlQueue<T, M>::Check( T const element )
{
int index = m_heap.Find(element);
return ( index != -1 );
}
#endif // UTLQUEUE_H

1700
public/tier1/utlrbtree.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,906 @@
//====== Copyright <20> 1996-2007, Valve Corporation, All rights reserved. =======//
//
// Purpose:
//
// $NoKeywords: $
//
// A Fixed-allocation class for maintaining a 1d or 2d or 3d array of data in a structure-of-arrays
// (SOA) sse-friendly manner.
// =============================================================================//
#ifndef UTLSOACONTAINER_H
#define UTLSOACONTAINER_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/platform.h"
#include "tier0/dbg.h"
#include "tier0/threadtools.h"
#include "tier1/utlmemory.h"
#include "tier1/utlblockmemory.h"
#include "mathlib/ssemath.h"
// strided pointers. gives you a class that acts like a pointer, but the ++ and += operators do the
// right thing
template<class T> class CStridedPtr
{
protected:
T *m_pData;
size_t m_nStride;
public:
FORCEINLINE CStridedPtr<T>( void *pData, size_t nByteStride )
{
m_pData = reinterpret_cast<T *>( pData );
m_nStride = nByteStride / sizeof( T );
}
FORCEINLINE CStridedPtr<T>( void ) {}
T *operator->(void) const
{
return m_pData;
}
T & operator*(void) const
{
return *m_pData;
}
FORCEINLINE operator T *(void)
{
return m_pData;
}
FORCEINLINE CStridedPtr<T> & operator++(void)
{
m_pData += m_nStride;
return *this;
}
FORCEINLINE void operator+=( size_t nNumElements )
{
m_pData += nNumElements * m_nStride;
}
FORCEINLINE size_t Stride( void ) const
{
return m_nStride;
}
};
template<class T> class CStridedConstPtr
{
protected:
const T *m_pData;
size_t m_nStride;
public:
FORCEINLINE CStridedConstPtr<T>( void const *pData, size_t nByteStride )
{
m_pData = reinterpret_cast<T const *>( pData );
m_nStride = nByteStride / sizeof( T );
}
FORCEINLINE CStridedConstPtr<T>( void ) {}
const T *operator->(void) const
{
return m_pData;
}
const T & operator*(void) const
{
return *m_pData;
}
FORCEINLINE operator const T *(void) const
{
return m_pData;
}
FORCEINLINE CStridedConstPtr<T> &operator++(void)
{
m_pData += m_nStride;
return *this;
}
FORCEINLINE void operator+=( size_t nNumElements )
{
m_pData += nNumElements*m_nStride;
}
FORCEINLINE size_t Stride( void ) const
{
return m_nStride;
}
};
// allowed field data types. if you change these values, you need to change the tables in the .cpp file
enum EAttributeDataType
{
ATTRDATATYPE_NONE = -1, // pad and varargs ender
ATTRDATATYPE_FLOAT = 0, // a float attribute
ATTRDATATYPE_4V, // vector data type, stored as class FourVectors
ATTRDATATYPE_INT, // integer. not especially sse-able on all architectures.
ATTRDATATYPE_POINTER, // a pointer.
ATTRDATATYPE_COUNT,
};
#define MAX_SOA_FIELDS 32
class KMeansQuantizedValue;
class IKMeansErrorMetric;
typedef fltx4 (*UNARYSIMDFUNCTION)( fltx4 const & );
typedef fltx4 (*BINARYSIMDFUNCTION)( fltx4 const &, fltx4 const & );
class CSOAAttributeReference;
/// mode of threading for a container. Normalyy automatically set based upon dimensions, but
/// controllable via SetThreadMode.
enum SOAThreadMode_t
{
SOATHREADMODE_NONE = 0,
SOATHREADMODE_BYROWS = 1,
SOATHREADMODE_BYSLICES = 2,
SOATHREADMODE_BYROWS_AND_SLICES = 3,
SOATHREADMODE_AUTO = -1, // compute based upon dimensions
};
class CSOAContainer
{
friend class CSOAAttributeReference;
public:
// Constructor, destructor
CSOAContainer( void ); // an empty one with no attributes
CSOAContainer( int nCols, int nRows, int nSlices, ... );
~CSOAContainer( void );
// !!!!! UPDATE SERIALIZATION CODE WHENEVER THE STRUCTURE OF CSOAContainer CHANGES !!!!!
// To avoid dependency on datamodel, serialization is implemented in utlsoacontainer_serialization.cpp, in dmxloader.lib
//bool Serialize( CDmxElement *pRootElement );
//bool Unserialize( const CDmxElement *pRootElement );
// Set the data type for an attribute. If you set the data type, but tell it not to allocate,
// the data type will be set but writes will assert, and reads will give you back zeros. if
// AllocateData hasn't been called yet, this will set up for AllocateData to reserve space for
// this attribute. If you have already called AllocateData, but wish to add an attribute, you
// can also use this, which will result in separate memory being allocated for this attribute.
void SetAttributeType( int nAttrIdx, EAttributeDataType nDataType, bool bAllocateMemory = true );
EAttributeDataType GetAttributeType( int nAttrIdx ) const;
// Set the attribute type for a field, if that field is not already present (potentially
// allocating memory). You can use this, for instance, to make sure an already loaded image has
// an alpha channel.
void EnsureDataType( int nAttrIdx, EAttributeDataType nDataType );
// set back to un-initted state, freeing memory
void Purge( void );
// Allocate, purge data
void AllocateData( int nNCols, int nNRows, int nSlices = 1 ); // actually allocate the memory and set the pointers up
void PurgeData( void );
// Did the container allocate memory for this attribute?
bool HasAllocatedMemory( int nAttrIdx ) const;
// easy constructor for 2d using varargs. call like
// #define ATTR_RED 0
// #define ATTR_GREEN 1
// #define ATTR_BLUE 2
// CSOAContainer myimage( 256, 256, ATTR_RED, ATTRDATATYPE_FLOAT, ATTR_GREEN, ATTRDATATYPE_FLOAT,
// ATTR_BLUE, ATTRDATATYPE_FLOAT, -1 );
int NumCols( void ) const;
int NumRows( void ) const;
int NumSlices( void ) const;
void AssertDataType( int nAttrIdx, EAttributeDataType nDataType ) const;
// # of groups of 4 elements per row
int NumQuadsPerRow( void ) const;
int Count( void ) const; // for 1d data
int NumElements( void ) const;
// how much to step to go from the end of one row to the start of the next one. Basically, how
// many bytes to add at the end of a row when iterating over the whole 2d array with ++
size_t RowToRowStep( int nAttrIdx ) const;
template<class T> T *RowPtr( int nAttributeIdx, int nRowNumber, int nSliceNumber = 0 ) const;
void const *ConstRowPtr( int nAttributeIdx, int nRowNumber, int nSliceNumber = 0 ) const;
template<class T> T *ElementPointer( int nAttributeIdx, int nX = 0, int nY = 0, int nZ = 0 ) const;
FourVectors *ElementPointer4V( int nAttributeIdx, int nX = 0, int nY = 0, int nZ = 0 ) const;
size_t ItemByteStride( int nAttributeIdx ) const;
FORCEINLINE float &FloatValue( int nAttrIdx, int nX, int nY, int nZ ) const
{
AssertDataType( nAttrIdx, ATTRDATATYPE_FLOAT );
return RowPtr<float>( nAttrIdx, nY, nZ )[nX];
}
// return a reference to an attribute, which can have operations performed on it. For instance,
// this is valid code to zero out the red component of a whole image:
// myImage[FBM_ATTR_RED] = 0.;
CSOAAttributeReference operator[]( int nAttrIdx );
// this is just an alias for readbaility w/ ptrs. instead of (*p)[FBM_ATTR_RED], you can do p->Attr( FBM_ATTR_RED );
FORCEINLINE CSOAAttributeReference Attr( int nAttrIdx );
// copy the attribute data from another soacontainer. must be compatible geometry.
void CopyAttrFrom( CSOAContainer const &other, int nDestAttributeIdx, int nSrcAttributeIndex = -1 );
// copy the attribute data from another attribute. must be compatible data format
void CopyAttrToAttr( int nSrcAttributeIndex, int nDestAttributeIndex);
// copy a subvolume of attribute data from one container to another.
void CopyRegionFrom( CSOAContainer const &src, int nSrcAttr, int nDestAttr,
int nSrcMinX, int nSrcMaxX, int nSrcMinY, int nSrcMaxY, int nSrcMinZ, int nSrcMaxZ,
int nDestX, int nDestY, int nDestZ );
// copy all fields from a region of src to this.
void CopyRegionFrom( CSOAContainer const &src,
int nSrcMinX, int nSrcMaxX, int nSrcMinY, int nSrcMaxY, int nSrcMinZ, int nSrcMaxZ,
int nDestX, int nDestY, int nDestZ );
// move all the data from one csoacontainer to another, leaving the source empty. this is just
// a pointer copy.
FORCEINLINE void MoveDataFrom( CSOAContainer other );
// arithmetic and data filling functions. All SIMD and hopefully fast
/// set all elements of a float attribute to random #s
void RandomizeAttribute( int nAttr, float flMin, float flMax ) const;
/// this.attr = vec
void FillAttr( int nAttr, Vector const &vecValue );
/// this.attr = float
void FillAttr( int nAttr, float flValue );
/// this.nDestAttr *= src.nSrcAttr
void MulAttr( CSOAContainer const &src, int nSrcAttr, int nDestAttr );
/// Returns the result of repeatedly combining attr values with the initial value using the specified function.
/// For instance, SumAttributeValue is just ReduceAttr<AddSIMD>( attr, FOUR_ZEROS );
template<BINARYSIMDFUNCTION fn> float ReduceAttr( int nSrcAttr, fltx4 const &fl4InitialValue ) const;
template<BINARYSIMDFUNCTION fn> void ApplyBinaryFunctionToAttr( int nDestAttr, fltx4 const &flFnArg1 );
/// this.attr = fn1( fn2( attr, arg2 ), arg1 )
template<BINARYSIMDFUNCTION fn1, BINARYSIMDFUNCTION fn2> void ApplyTwoComposedBinaryFunctionsToAttr( int nDestAttr, fltx4 const &flFnArg1, fltx4 const &flFnArg2 );
/// this.nDestAttr *= flValue
void MulAttr( int nDestAttr, float flScale )
{
ApplyBinaryFunctionToAttr<MulSIMD>( nDestAttr, ReplicateX4( flScale ) );
}
void AddToAttr( int nDestAttr, float flAddend )
{
ApplyBinaryFunctionToAttr<AddSIMD>( nDestAttr, ReplicateX4( flAddend ) );
}
// this.attr = max( this.attr, flminvalue )
void MaxAttr( int nDestAttr, float flMinValue )
{
ApplyBinaryFunctionToAttr<MaxSIMD>( nDestAttr, ReplicateX4( flMinValue ) );
}
/// this.attr = min( this.attr, flminvalue )
void MinAttr( int nDestAttr, float flMaxValue )
{
ApplyBinaryFunctionToAttr<MinSIMD>( nDestAttr, ReplicateX4( flMaxValue ) );
}
void ClampAttr( int nDestAttr, float flMinValue, float flMaxValue )
{
ApplyTwoComposedBinaryFunctionsToAttr<MinSIMD, MaxSIMD>( nDestAttr, ReplicateX4( flMaxValue ), ReplicateX4( flMinValue ) );
}
/// this.attr = normalize( this.attr )
void NormalizeAttr( int nAttr );
/// fill 2d a rectangle with values interpolated from 4 corner values.
void FillAttrWithInterpolatedValues( int nAttr, float flValue00, float flValue10, float flValue01, float flValue11 ) const;
void FillAttrWithInterpolatedValues( int nAttr, Vector flValue00, Vector flValue10,
Vector const &flValue01, Vector const &flValue11 ) const;
/// grab 3 scalar attributes from one csoaa and fill in a fourvector attr in.
void PackScalarAttributesToVectorAttribute( CSOAContainer *pInput,
int nVecAttributeOut,
int nScalarAttributeX,
int nScalarAttributeY,
int nScalarAttributeZ );
/// grab the 3 components of a vector attribute and store in 3 scalar attributes.
void UnPackVectorAttributeToScalarAttributes( CSOAContainer *pInput,
int nVecAttributeIn,
int nScalarAttributeX,
int nScalarAttributeY,
int nScalarAttributeZ );
/// this.attrout = src.attrin * vec (component by component )
void MultiplyVectorAttribute( CSOAContainer *pInput, int nAttributeIn, Vector const &vecScalar, int nAttributeOut );
/// Given an soa container of a different dimension, resize one attribute from it to fit this
/// table's geometry. point sampling only
void ResampleAttribute( CSOAContainer &pInput, int nAttr );
/// sum of all floats in an attribute
float SumAttributeValue( int nAttr ) const;
/// sum(attr) / ( w * h * d )
float AverageFloatAttributeValue( int nAttr ) const;
/// maximum float value in a float attr
float MaxAttributeValue( int nAttr ) const;
/// minimum float value in a float attr
float MinAttributeValue( int nAttr ) const;
/// scalartargetattribute += w*exp( vecdir dot ndirection)
void AddGaussianSRBF( float flWeight, Vector vecDir, int nDirectionAttribute, int nScalarTargetAttribute );
/// vec3targetattribute += w*exp( vecdir dot ndirection)
void AddGaussianSRBF( Vector vecWeight, Vector vecDir, int nDirectionAttribute,
int nVectorTargetAttribute );
/// find the largest value of a vector attribute
void FindLargestMagnitudeVector( int nAttr, int *nx, int *ny, int *nz );
void KMeansQuantization( int const *pFieldIndices, int nNumFields,
KMeansQuantizedValue *pOutValues,
int nNumResultsDesired, IKMeansErrorMetric *pErrorCalculator,
int nFieldToStoreIndexInto, int nNumIterations,
int nChannelToReceiveErrorSignal = -1 );
// Calculate the signed distance, in voxels, between all voxels and a surface boundary defined
// by nSrcField being >0. Voxels with nSrcField <0 will end up with negative distances. Voxels
// with nSrcField == 0 will get 0, and nSrcField >0 will yield positive distances. Note the
// min/max x/y/z fields don't reflect the range to be written, but rather represent the bounds
// of updated voxels that you want your distance field modified to take into account. This
// volume will be bloated based upon the nMaxDistance parameter and simd padding. A
// brute-force algorithm is used, but it is threaded and simd'd. Large "nMaxDistance" values
// applied to large images can take a long time, as the execution time per output pixel is
// proportional to maxdistance^2. The rect argument, if passed, will be modified to be the
// entire rectangle modified by the operation.
void GenerateDistanceField( int nSrcField, int nDestField,
int nMaxDistance,
Rect3D_t *pRect = NULL );
void SetThreadMode( SOAThreadMode_t eThreadMode );
protected:
int m_nColumns; // # of rows and columns created with
int m_nRows;
int m_nSlices;
int m_nPaddedColumns; // # of columns rounded up for sse
int m_nNumQuadsPerRow; // # of groups of 4 elements per row
uint8 *m_pDataMemory; // the actual data memory
uint8 *m_pAttributePtrs[MAX_SOA_FIELDS];
EAttributeDataType m_nDataType[MAX_SOA_FIELDS];
size_t m_nStrideInBytes[MAX_SOA_FIELDS]; // stride from one field datum to another
size_t m_nRowStrideInBytes[MAX_SOA_FIELDS]; // stride from one row datum to another per field
size_t m_nSliceStrideInBytes[MAX_SOA_FIELDS]; // stride from one slice datum to another per field
uint32 m_nFieldPresentMask;
uint8 *m_pConstantDataMemory;
uint8 *m_pSeparateDataMemory[MAX_SOA_FIELDS]; // for fields allocated separately from the main allocation
SOAThreadMode_t m_eThreadMode; // set thread mode
FORCEINLINE void Init( void )
{
memset( m_nDataType, 0xff, sizeof( m_nDataType ) );
memset( m_pSeparateDataMemory, 0, sizeof( m_pSeparateDataMemory ) );
#ifdef _DEBUG
memset( m_pAttributePtrs, 0xFF, sizeof( m_pAttributePtrs ) );
memset( m_nStrideInBytes, 0xFF, sizeof( m_nStrideInBytes ) );
memset( m_nRowStrideInBytes, 0xFF, sizeof( m_nRowStrideInBytes ) );
memset( m_nSliceStrideInBytes, 0xFF, sizeof( m_nSliceStrideInBytes ) );
#endif
m_pConstantDataMemory = NULL;
m_pDataMemory = 0;
m_nNumQuadsPerRow = 0;
m_nColumns = m_nPaddedColumns = m_nRows = m_nSlices = 0;
m_nFieldPresentMask = 0;
m_eThreadMode = SOATHREADMODE_NONE;
}
void UpdateDistanceRow( int nSearchRadius, int nMinX, int nMaxX, int nY, int nZ,
int nSrcField, int nDestField );
// parallel helper functions. These do the work, and all take a row/column range as their first arguments.
void CopyAttrFromPartial( int nStartRow, int nNumRows, int nStartSlice, int nEndSlice, CSOAContainer const *pOther, int nDestAttributeIndex, int nSrcAttributeIndex );
void FillAttrPartial( int nStartRow, int nNumRows, int nStartSlice, int nEndSlice, int nAttr, fltx4 fl4Value );
// Allocation utility funcs (NOTE: all allocs are multiples of 16, and are aligned allocs)
size_t DataMemorySize( void ) const; // total bytes of data memory to allocate at m_pDataMemory (if all attributes were allocated in a single block)
size_t ConstantMemorySize( void ) const; // total bytes of constant memory to allocate at m_pConstantDataMemory (if all constant attributes were allocated in a single block)
size_t AttributeMemorySize( int nAttrIndex ) const; // total bytes of data memory allocated to a single attribute (constant or otherwise)
void AllocateDataMemory( void );
void AllocateConstantMemory( void );
};
// define binary op class to allow this construct without temps:
// dest( FBM_ATTR_RED ) = src( FBM_ATTR_BLUE ) + src( FBM_ATTR_GREEN )
template<BINARYSIMDFUNCTION fn> class CSOAAttributeReferenceBinaryOp;
class CSOAAttributeReference
{
friend class CSOAContainer;
class CSOAContainer *m_pContainer;
int m_nAttributeID;
public:
FORCEINLINE void operator *=( float flScale ) const
{
m_pContainer->MulAttr( m_nAttributeID, flScale );
}
FORCEINLINE void operator +=( float flAddend ) const
{
m_pContainer->AddToAttr( m_nAttributeID, flAddend );
}
FORCEINLINE void operator -=( float flAddend ) const
{
m_pContainer->AddToAttr( m_nAttributeID, -flAddend );
}
FORCEINLINE void operator =( float flValue ) const
{
m_pContainer->FillAttr( m_nAttributeID, flValue );
}
FORCEINLINE void operator =( CSOAAttributeReference const &other ) const
{
m_pContainer->CopyAttrFrom( *other.m_pContainer, m_nAttributeID, other.m_nAttributeID );
}
template<BINARYSIMDFUNCTION fn> FORCEINLINE void operator =( CSOAAttributeReferenceBinaryOp<fn> const &op );
FORCEINLINE void CopyTo( CSOAAttributeReference &other ) const; // since operator= is over-ridden
};
// define binary op class to allow this construct without temps:
// dest( FBM_ATTR_RED ) = src( FBM_ATTR_BLUE ) + src( FBM_ATTR_GREEN )
template<BINARYSIMDFUNCTION fn> class CSOAAttributeReferenceBinaryOp
{
public:
CSOAAttributeReference m_opA;
CSOAAttributeReference m_opB;
CSOAAttributeReferenceBinaryOp( CSOAAttributeReference const &a, CSOAAttributeReference const & b )
{
a.CopyTo( m_opA );
b.CopyTo( m_opB );
}
};
#define DEFINE_OP( opname, fnname ) \
FORCEINLINE CSOAAttributeReferenceBinaryOp<fnname> operator opname( CSOAAttributeReference const &left, CSOAAttributeReference const &right ) \
{ \
return CSOAAttributeReferenceBinaryOp<fnname>( left, right ); \
}
// these operator overloads let you do
// dst[ATT1] = src1[ATT] + src2[ATT] with no temporaries generated
DEFINE_OP( +, AddSIMD );
DEFINE_OP( *, MulSIMD );
DEFINE_OP( -, SubSIMD );
DEFINE_OP( /, DivSIMD );
template<BINARYSIMDFUNCTION fn> FORCEINLINE void CSOAAttributeReference::operator =( CSOAAttributeReferenceBinaryOp<fn> const &op )
{
m_pContainer->AssertDataType( m_nAttributeID, ATTRDATATYPE_FLOAT );
fltx4 *pOut = m_pContainer->RowPtr<fltx4>( m_nAttributeID, 0 );
// GCC on PS3 gets confused by this code, so we literally have to break it into multiple statements
CSOAContainer *pContainerA = op.m_opA.m_pContainer;
CSOAContainer *pContainerB = op.m_opB.m_pContainer;
fltx4 *pInA = pContainerA->RowPtr< fltx4 >( op.m_opA.m_nAttributeID, 0 );
fltx4 *pInB = pContainerB->RowPtr< fltx4 >( op.m_opB.m_nAttributeID, 0 );
size_t nRowToRowStride = m_pContainer->RowToRowStep( m_nAttributeID ) / sizeof( fltx4 );
int nRowCtr = m_pContainer->NumRows() * m_pContainer->NumSlices();
do
{
int nColCtr = m_pContainer->NumQuadsPerRow();
do
{
*(pOut++) = fn( *( pInA++ ), *( pInB++ ) );
} while ( --nColCtr );
pOut += nRowToRowStride;
pInA += nRowToRowStride;
pInB += nRowToRowStride;
} while ( --nRowCtr );
}
FORCEINLINE void CSOAAttributeReference::CopyTo( CSOAAttributeReference &other ) const
{
other.m_pContainer = m_pContainer;
other.m_nAttributeID = m_nAttributeID;
}
FORCEINLINE CSOAAttributeReference CSOAContainer::operator[]( int nAttrIdx )
{
CSOAAttributeReference ret;
ret.m_pContainer = this;
ret.m_nAttributeID = nAttrIdx;
return ret;
}
FORCEINLINE CSOAAttributeReference CSOAContainer::Attr( int nAttrIdx )
{
return (*this)[nAttrIdx];
}
template<BINARYSIMDFUNCTION fn1, BINARYSIMDFUNCTION fn2> void CSOAContainer::ApplyTwoComposedBinaryFunctionsToAttr( int nDestAttr, fltx4 const &fl4FnArg1, fltx4 const &fl4FnArg2 )
{
if ( m_nDataType[nDestAttr] == ATTRDATATYPE_4V )
{
FourVectors *pOut = RowPtr<FourVectors>( nDestAttr, 0 );
size_t nRowToRowStride = RowToRowStep( nDestAttr ) / sizeof( FourVectors );
int nRowCtr = NumRows() * NumSlices();
do
{
int nColCtr = NumQuadsPerRow();
do
{
pOut->x = fn1( fn2( pOut->x, fl4FnArg2 ), fl4FnArg1 );
pOut->y = fn1( fn2( pOut->y, fl4FnArg2 ), fl4FnArg1 );
pOut->z = fn1( fn2( pOut->z, fl4FnArg2 ), fl4FnArg1 );
} while ( --nColCtr );
pOut += nRowToRowStride;
} while ( --nRowCtr );
}
else
{
AssertDataType( nDestAttr, ATTRDATATYPE_FLOAT );
fltx4 *pOut = RowPtr<fltx4>( nDestAttr, 0 );
size_t nRowToRowStride = RowToRowStep( nDestAttr ) / sizeof( fltx4 );
int nRowCtr = NumRows() * NumSlices();
do
{
int nColCtr = NumQuadsPerRow();
do
{
*pOut = fn1( fn2( *pOut, fl4FnArg2 ), fl4FnArg1 );
pOut++;
} while ( --nColCtr );
pOut += nRowToRowStride;
} while ( --nRowCtr );
}
}
template<BINARYSIMDFUNCTION fn> void CSOAContainer::ApplyBinaryFunctionToAttr( int nDestAttr, fltx4 const &fl4FnArg1 )
{
if ( m_nDataType[nDestAttr] == ATTRDATATYPE_4V )
{
FourVectors *pOut = RowPtr<FourVectors>( nDestAttr, 0 );
size_t nRowToRowStride = RowToRowStep( nDestAttr ) / sizeof( FourVectors );
int nRowCtr = NumRows() * NumSlices();
do
{
int nColCtr = NumQuadsPerRow();
do
{
pOut->x = fn( pOut->x, fl4FnArg1 );
pOut->y = fn( pOut->y, fl4FnArg1 );
pOut->z = fn( pOut->z, fl4FnArg1 );
} while ( --nColCtr );
pOut += nRowToRowStride;
} while ( --nRowCtr );
}
else
{
AssertDataType( nDestAttr, ATTRDATATYPE_FLOAT );
fltx4 *pOut = RowPtr<fltx4>( nDestAttr, 0 );
size_t nRowToRowStride = RowToRowStep( nDestAttr ) / sizeof( fltx4 );
int nRowCtr = NumRows() * NumSlices();
do
{
int nColCtr = NumQuadsPerRow();
do
{
*pOut = fn( *pOut, fl4FnArg1 );
pOut++;
} while ( --nColCtr );
pOut += nRowToRowStride;
} while ( --nRowCtr );
}
}
template<BINARYSIMDFUNCTION fn> float CSOAContainer::ReduceAttr( int nSrcAttr, fltx4 const &fl4InitialValue ) const
{
AssertDataType( nSrcAttr, ATTRDATATYPE_FLOAT );
fltx4 fl4Result = fl4InitialValue;
fltx4 const *pIn = RowPtr<fltx4>( nSrcAttr, 0 );
size_t nRowToRowStride = RowToRowStep( nSrcAttr ) / sizeof( fltx4 );
int nRowCtr = NumRows() * NumSlices();
bi32x4 fl4LastColumnMask = (bi32x4)LoadAlignedSIMD( g_SIMD_SkipTailMask[NumCols() & 3 ] );
do
{
for( int i = 0; i < NumQuadsPerRow() - 1; i++ )
{
fl4Result = fn( fl4Result, *( pIn++ ) );
}
// handle the last column in case its not a multiple of 4 wide
fl4Result = MaskedAssign( fl4LastColumnMask, fn( fl4Result, *( pIn++ ) ), fl4Result );
pIn += nRowToRowStride;
} while ( --nRowCtr );
// now, combine the subfields
fl4Result = fn(
fn( fl4Result, SplatYSIMD( fl4Result ) ),
fn( SplatZSIMD( fl4Result ), SplatWSIMD( fl4Result ) ) );
return SubFloat( fl4Result, 0 );
}
#define QUANTIZER_NJOBS 1 // # of simultaneous subjobs to execute for kmeans quantizer
// kmeans quantization classes
// the array of quantized values returned by quantization
class KMeansQuantizedValue
{
public:
FourVectors m_vecValuePosition; // replicated
fltx4 m_fl4Values[MAX_SOA_FIELDS]; // replicated
float m_flValueAccumulators[QUANTIZER_NJOBS][MAX_SOA_FIELDS];
float m_flWeightAccumulators[QUANTIZER_NJOBS];
FORCEINLINE float operator()( int n )
{
return SubFloat( m_fl4Values[n], 0 );
}
};
class KMeansSampleDescriptor
{
public:
fltx4 *m_pInputValues[MAX_SOA_FIELDS];
FORCEINLINE fltx4 const & operator()( int nField ) const
{
return *m_pInputValues[nField];
}
};
class IKMeansErrorMetric
{
public:
virtual void CalculateError( KMeansSampleDescriptor const &sampleAddresses,
FourVectors const &v4SamplePositions,
KMeansQuantizedValue const &valueToCompareAgainst,
fltx4 *pfl4ErrOut ) =0;
// for things like normalization, etc
virtual void PostAdjustQuantizedValue( KMeansQuantizedValue &valueToAdjust )
{
}
// for global fixup after each adjustment step
virtual void PostStep( int const *pFieldIndices, int nNumFields,
KMeansQuantizedValue *pValues, int nNumQuantizedValues,
int nIndexField, CSOAContainer &data )
{
}
};
FORCEINLINE CSOAContainer::CSOAContainer( void )
{
Init();
}
//-----------------------------------------------------------------------------
// Did the container allocate memory for this attribute?
//-----------------------------------------------------------------------------
FORCEINLINE bool CSOAContainer::HasAllocatedMemory( int nAttrIdx ) const
{
return ( m_nFieldPresentMask & ( 1 << nAttrIdx ) ) != 0;
}
FORCEINLINE EAttributeDataType CSOAContainer::GetAttributeType( int nAttrIdx ) const
{
Assert( ( nAttrIdx >= 0 ) && ( nAttrIdx < MAX_SOA_FIELDS ) );
return m_nDataType[nAttrIdx];
}
FORCEINLINE void CSOAContainer::EnsureDataType( int nAttrIdx, EAttributeDataType nDataType )
{
if ( !HasAllocatedMemory( nAttrIdx ) )
{
SetAttributeType( nAttrIdx, nDataType );
}
}
FORCEINLINE int CSOAContainer::NumRows( void ) const
{
return m_nRows;
}
FORCEINLINE int CSOAContainer::NumCols( void ) const
{
return m_nColumns;
}
FORCEINLINE int CSOAContainer::NumSlices( void ) const
{
return m_nSlices;
}
FORCEINLINE void CSOAContainer::AssertDataType( int nAttrIdx, EAttributeDataType nDataType ) const
{
Assert( nAttrIdx >= 0 );
Assert( nAttrIdx < MAX_SOA_FIELDS );
Assert( m_nDataType[ nAttrIdx ] == nDataType );
}
// # of groups of 4 elements per row
FORCEINLINE int CSOAContainer::NumQuadsPerRow( void ) const
{
return m_nNumQuadsPerRow;
}
FORCEINLINE int CSOAContainer::Count( void ) const // for 1d data
{
return NumCols();
}
FORCEINLINE int CSOAContainer::NumElements( void ) const
{
return NumCols() * NumRows() * NumSlices();
}
// how much to step to go from the end of one row to the start of the next one. Basically, how
// many bytes to add at the end of a row when iterating over the whole 2d array with ++
FORCEINLINE size_t CSOAContainer::RowToRowStep( int nAttrIdx ) const
{
return 0;
}
template<class T> FORCEINLINE T *CSOAContainer::RowPtr( int nAttributeIdx, int nRowNumber, int nSliceNumber ) const
{
Assert( nRowNumber < m_nRows );
Assert( nAttributeIdx < MAX_SOA_FIELDS );
Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE );
Assert( ( m_nFieldPresentMask & ( 1 << nAttributeIdx ) ) || ( ( nRowNumber == 0 ) && ( nSliceNumber == 0 ) ) );
return reinterpret_cast<T *>(
m_pAttributePtrs[nAttributeIdx] +
+ nRowNumber * m_nRowStrideInBytes[nAttributeIdx]
+ nSliceNumber * m_nSliceStrideInBytes[nAttributeIdx] );
}
FORCEINLINE void const *CSOAContainer::ConstRowPtr( int nAttributeIdx, int nRowNumber, int nSliceNumber ) const
{
Assert( nRowNumber < m_nRows );
Assert( nAttributeIdx < MAX_SOA_FIELDS );
Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE );
return m_pAttributePtrs[nAttributeIdx]
+ nRowNumber * m_nRowStrideInBytes[nAttributeIdx]
+ nSliceNumber * m_nSliceStrideInBytes[nAttributeIdx];
}
template<class T> FORCEINLINE T *CSOAContainer::ElementPointer( int nAttributeIdx, int nX, int nY, int nZ ) const
{
Assert( nAttributeIdx < MAX_SOA_FIELDS );
Assert( nX < m_nColumns );
Assert( nY < m_nRows );
Assert( nZ < m_nSlices );
Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE );
Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_4V );
return reinterpret_cast<T *>( m_pAttributePtrs[nAttributeIdx]
+ nX * m_nStrideInBytes[nAttributeIdx]
+ nY * m_nRowStrideInBytes[nAttributeIdx]
+ nZ * m_nSliceStrideInBytes[nAttributeIdx]
);
}
FORCEINLINE FourVectors *CSOAContainer::ElementPointer4V( int nAttributeIdx, int nX, int nY, int nZ ) const
{
Assert( nAttributeIdx < MAX_SOA_FIELDS );
Assert( nX < m_nColumns );
Assert( nY < m_nRows );
Assert( nZ < m_nSlices );
Assert( m_nDataType[nAttributeIdx] == ATTRDATATYPE_4V );
int nXIdx = nX / 4;
uint8 *pRet = m_pAttributePtrs[nAttributeIdx]
+ nXIdx * 4 * m_nStrideInBytes[nAttributeIdx]
+ nY * m_nRowStrideInBytes[nAttributeIdx]
+ nZ * m_nSliceStrideInBytes[nAttributeIdx];
pRet += 4 * ( nX & 3 );
return reinterpret_cast<FourVectors *>( pRet );
}
FORCEINLINE size_t CSOAContainer::ItemByteStride( int nAttributeIdx ) const
{
Assert( nAttributeIdx < MAX_SOA_FIELDS );
Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE );
return m_nStrideInBytes[ nAttributeIdx ];
}
// move all the data from one csoacontainer to another, leaving the source empty.
// this is just a pointer copy.
FORCEINLINE void CSOAContainer::MoveDataFrom( CSOAContainer other )
{
(*this) = other;
other.Init();
}
class CFltX4AttributeIterator : public CStridedConstPtr<fltx4>
{
FORCEINLINE CFltX4AttributeIterator( CSOAContainer const *pContainer, int nAttribute, int nRowNumber = 0 )
: CStridedConstPtr<fltx4>( pContainer->ConstRowPtr( nAttribute, nRowNumber),
pContainer->ItemByteStride( nAttribute ) )
{
}
};
class CFltX4AttributeWriteIterator : public CStridedPtr<fltx4>
{
FORCEINLINE CFltX4AttributeWriteIterator( CSOAContainer const *pContainer, int nAttribute, int nRowNumber = 0 )
: CStridedPtr<fltx4>( pContainer->RowPtr<uint8>( nAttribute, nRowNumber),
pContainer->ItemByteStride( nAttribute ) )
{
}
};
FORCEINLINE FourVectors CompressSIMD( FourVectors const &a, FourVectors const &b )
{
FourVectors ret;
ret.x = CompressSIMD( a.x, b.x );
ret.y = CompressSIMD( a.y, b.y );
ret.z = CompressSIMD( a.z, b.z );
return ret;
}
FORCEINLINE FourVectors Compress4SIMD( FourVectors const &a, FourVectors const &b,
FourVectors const &c, FourVectors const &d )
{
FourVectors ret;
ret.x = Compress4SIMD( a.x, b.x, c.x, d.x );
ret.y = Compress4SIMD( a.y, b.y, c.y, d.y );
ret.z = Compress4SIMD( a.z, b.z, c.z, d.z );
return ret;
}
#endif

View File

@@ -0,0 +1,447 @@
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
//
// $Header: $
// $NoKeywords: $
//
// A growable array class that keeps all elements in order using binary search
//===========================================================================//
#ifndef UTLSORTVECTOR_H
#define UTLSORTVECTOR_H
#ifdef _WIN32
#pragma once
#endif
#include "utlvector.h"
//-----------------------------------------------------------------------------
// class CUtlSortVector:
// description:
// This in an sorted order-preserving vector. Items may be inserted or removed
// at any point in the vector. When an item is inserted, all elements are
// moved down by one element using memmove. When an item is removed, all
// elements are shifted back down. Items are searched for in the vector
// using a binary search technique. Clients must pass in a Less() function
// into the constructor of the vector to determine the sort order.
//-----------------------------------------------------------------------------
#ifndef _WIN32
// gcc has no qsort_s, so i need to use a static var to hold the sort context. this makes cutlsortvector _not_ thread sfae under linux
extern void *g_pUtlSortVectorQSortContext;
#endif
template <class T>
class CUtlSortVectorDefaultLess
{
public:
bool Less( const T& lhs, const T& rhs, void * )
{
return lhs < rhs;
}
};
template <class T, class LessFunc = CUtlSortVectorDefaultLess<T>, class BaseVector = CUtlVector<T> >
class CUtlSortVector : public BaseVector
{
typedef BaseVector BaseClass;
public:
/// constructor
CUtlSortVector( int nGrowSize = 0, int initSize = 0 );
CUtlSortVector( T* pMemory, int numElements );
/// inserts (copy constructs) an element in sorted order into the list
int Insert( const T& src );
/// inserts (copy constructs) an element in sorted order into the list if it isn't already in the list
int InsertIfNotFound( const T& src );
/// Finds an element within the list using a binary search. These are templatized based upon the key
/// in which case the less function must handle the Less function for key, T and T, key
template< typename TKey >
int Find( const TKey& search ) const;
template< typename TKey >
int FindLessOrEqual( const TKey& search ) const;
template< typename TKey >
int FindLess( const TKey& search ) const;
template <typename K>
int FindAs( const K& key ) const;
/// Removes a particular element
void Remove( const T& search );
void Remove( int i );
/// Allows methods to set a context to be used with the less function..
void SetLessContext( void *pCtx );
/// A version of insertion that will produce an un-ordered list.
/// Note that you can only use this index until sorting is redone with RedoSort!!!
int InsertNoSort( const T& src );
void RedoSort( bool bForceSort = false );
/// Use this to insert at a specific insertion point; using FindLessOrEqual
/// is required for use this this. This will test that what you've inserted
/// produces a correctly ordered list.
int InsertAfter( int nElemIndex, const T &src );
/// finds a particular element using a linear search. Useful when used
/// in between calls to InsertNoSort and RedoSort
template< typename TKey >
int FindUnsorted( const TKey &src ) const;
protected:
// No copy constructor
CUtlSortVector( const CUtlSortVector<T, LessFunc> & );
// never call these; illegal for this class
int AddToHead();
int AddToTail();
int InsertBefore( int elem );
int InsertAfter( int elem );
int AddToHead( const T& src );
int AddToTail( const T& src );
int InsertBefore( int elem, const T& src );
int AddMultipleToHead( int num );
int AddMultipleToTail( int num, const T *pToCopy=NULL );
int InsertMultipleBefore( int elem, int num, const T *pToCopy=NULL );
int InsertMultipleAfter( int elem, int num );
int AddVectorToTail( CUtlVector<T> const &src );
struct QSortContext_t
{
void *m_pLessContext;
LessFunc *m_pLessFunc;
};
#ifdef _WIN32
static int CompareHelper( void *context, const T *lhs, const T *rhs )
{
QSortContext_t *ctx = reinterpret_cast< QSortContext_t * >( context );
if ( ctx->m_pLessFunc->Less( *lhs, *rhs, ctx->m_pLessContext ) )
return -1;
if ( ctx->m_pLessFunc->Less( *rhs, *lhs, ctx->m_pLessContext ) )
return 1;
return 0;
}
#else
static int CompareHelper( const T *lhs, const T *rhs )
{
QSortContext_t *ctx = reinterpret_cast< QSortContext_t * >( g_pUtlSortVectorQSortContext );
if ( ctx->m_pLessFunc->Less( *lhs, *rhs, ctx->m_pLessContext ) )
return -1;
if ( ctx->m_pLessFunc->Less( *rhs, *lhs, ctx->m_pLessContext ) )
return 1;
return 0;
}
#endif
void *m_pLessContext;
bool m_bNeedsSort;
private:
template< typename TKey >
int FindLessOrEqual( const TKey& search, bool *pFound ) const;
void QuickSort( LessFunc& less, int X, int I );
};
//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
template <class T, class LessFunc, class BaseVector>
CUtlSortVector<T, LessFunc, BaseVector>::CUtlSortVector( int nGrowSize, int initSize ) :
m_pLessContext(NULL), BaseVector( nGrowSize, initSize ), m_bNeedsSort( false )
{
}
template <class T, class LessFunc, class BaseVector>
CUtlSortVector<T, LessFunc, BaseVector>::CUtlSortVector( T* pMemory, int numElements ) :
m_pLessContext(NULL), BaseVector( pMemory, numElements ), m_bNeedsSort( false )
{
}
//-----------------------------------------------------------------------------
// Allows methods to set a context to be used with the less function..
//-----------------------------------------------------------------------------
template <class T, class LessFunc, class BaseVector>
void CUtlSortVector<T, LessFunc, BaseVector>::SetLessContext( void *pCtx )
{
m_pLessContext = pCtx;
}
//-----------------------------------------------------------------------------
// grows the vector
//-----------------------------------------------------------------------------
template <class T, class LessFunc, class BaseVector>
int CUtlSortVector<T, LessFunc, BaseVector>::Insert( const T& src )
{
AssertFatal( !m_bNeedsSort );
int pos = FindLessOrEqual( src ) + 1;
this->GrowVector();
this->ShiftElementsRight(pos);
CopyConstruct<T>( &this->Element(pos), src );
return pos;
}
template <class T, class LessFunc, class BaseVector>
int CUtlSortVector<T, LessFunc, BaseVector>::InsertNoSort( const T& src )
{
m_bNeedsSort = true;
int lastElement = BaseVector::m_Size;
// Just stick the new element at the end of the vector, but don't do a sort
this->GrowVector();
this->ShiftElementsRight(lastElement);
CopyConstruct( &this->Element(lastElement), src );
return lastElement;
}
/// inserts (copy constructs) an element in sorted order into the list if it isn't already in the list
template <class T, class LessFunc, class BaseVector>
int CUtlSortVector<T, LessFunc, BaseVector>::InsertIfNotFound( const T& src )
{
AssertFatal( !m_bNeedsSort );
bool bFound;
int pos = FindLessOrEqual( src, &bFound );
if ( bFound )
return pos;
++pos;
BaseVector::InsertBefore( pos, src );
return pos;
}
template <class T, class LessFunc, class BaseVector>
int CUtlSortVector<T, LessFunc, BaseVector>::InsertAfter( int nIndex, const T &src )
{
int nInsertedIndex = BaseClass::InsertAfter( nIndex, src );
#ifdef DEBUG
LessFunc less;
if ( nInsertedIndex > 0 )
{
Assert( less.Less( this->Element(nInsertedIndex-1), src, m_pLessContext ) );
}
if ( nInsertedIndex < BaseClass::Count()-1 )
{
Assert( less.Less( src, this->Element(nInsertedIndex+1), m_pLessContext ) );
}
#endif
return nInsertedIndex;
}
template <class T, class LessFunc, class BaseVector>
void CUtlSortVector<T, LessFunc, BaseVector>::QuickSort( LessFunc& less, int nLower, int nUpper )
{
#ifdef _WIN32
typedef int (__cdecl *QSortCompareFunc_t)(void *context, const void *, const void *);
if ( this->Count() > 1 )
{
QSortContext_t ctx;
ctx.m_pLessContext = m_pLessContext;
ctx.m_pLessFunc = &less;
qsort_s( Base(), Count(), sizeof(T), (QSortCompareFunc_t)&CUtlSortVector<T, LessFunc>::CompareHelper, &ctx );
}
#else
typedef int (__cdecl *QSortCompareFunc_t)( const void *, const void *);
if ( this->Count() > 1 )
{
QSortContext_t ctx;
ctx.m_pLessContext = m_pLessContext;
ctx.m_pLessFunc = &less;
g_pUtlSortVectorQSortContext = &ctx;
qsort( this->Base(), this->Count(), sizeof(T), (QSortCompareFunc_t)&CUtlSortVector<T, LessFunc>::CompareHelper );
}
#endif
}
template <class T, class LessFunc, class BaseVector>
void CUtlSortVector<T, LessFunc, BaseVector>::RedoSort( bool bForceSort /*= false */ )
{
if ( !m_bNeedsSort && !bForceSort )
return;
m_bNeedsSort = false;
LessFunc less;
QuickSort( less, 0, this->Count() - 1 );
}
//-----------------------------------------------------------------------------
// finds a particular element
//-----------------------------------------------------------------------------
template <class T, class LessFunc, class BaseVector>
template < typename TKey >
int CUtlSortVector<T, LessFunc, BaseVector>::Find( const TKey& src ) const
{
AssertFatal( !m_bNeedsSort );
LessFunc less;
int start = 0, end = this->Count() - 1;
while (start <= end)
{
int mid = (start + end) >> 1;
if ( less.Less( this->Element(mid), src, m_pLessContext ) )
{
start = mid + 1;
}
else if ( less.Less( src, this->Element(mid), m_pLessContext ) )
{
end = mid - 1;
}
else
{
return mid;
}
}
return -1;
}
//-----------------------------------------------------------------------------
// finds a particular element using a linear search. Useful when used
// in between calls to InsertNoSort and RedoSort
//-----------------------------------------------------------------------------
template< class T, class LessFunc, class BaseVector >
template < typename TKey >
int CUtlSortVector<T, LessFunc, BaseVector>::FindUnsorted( const TKey &src ) const
{
LessFunc less;
int nCount = this->Count();
for ( int i = 0; i < nCount; ++i )
{
if ( less.Less( this->Element( i ), src, m_pLessContext ) )
continue;
if ( less.Less( src, this->Element( i ), m_pLessContext ) )
continue;
return i;
}
return -1;
}
//-----------------------------------------------------------------------------
// finds a particular element
//-----------------------------------------------------------------------------
template <class T, class LessFunc, class BaseVector>
template <typename K>
int CUtlSortVector<T, LessFunc, BaseVector>::FindAs( const K& key ) const
{
AssertFatal( !m_bNeedsSort );
LessFunc less;
int start = 0, end = this->Count() - 1;
while (start <= end)
{
int mid = (start + end) >> 1;
int nResult = less.Compare( this->Element(mid), key, m_pLessContext );
if ( nResult < 0 )
{
start = mid + 1;
}
else if ( nResult > 0 )
{
end = mid - 1;
}
else
{
return mid;
}
}
return -1;
}
//-----------------------------------------------------------------------------
// finds a particular element
//-----------------------------------------------------------------------------
template <class T, class LessFunc, class BaseVector>
template < typename TKey >
int CUtlSortVector<T, LessFunc, BaseVector>::FindLessOrEqual( const TKey& src, bool *pFound ) const
{
AssertFatal( !m_bNeedsSort );
LessFunc less;
int start = 0, end = this->Count() - 1;
while (start <= end)
{
int mid = (start + end) >> 1;
if ( less.Less( this->Element(mid), src, m_pLessContext ) )
{
start = mid + 1;
}
else if ( less.Less( src, this->Element(mid), m_pLessContext ) )
{
end = mid - 1;
}
else
{
*pFound = true;
return mid;
}
}
*pFound = false;
return end;
}
template <class T, class LessFunc, class BaseVector>
template < typename TKey >
int CUtlSortVector<T, LessFunc, BaseVector>::FindLessOrEqual( const TKey& src ) const
{
bool bFound;
return FindLessOrEqual( src, &bFound );
}
template <class T, class LessFunc, class BaseVector>
template < typename TKey >
int CUtlSortVector<T, LessFunc, BaseVector>::FindLess( const TKey& src ) const
{
AssertFatal( !m_bNeedsSort );
LessFunc less;
int start = 0, end = this->Count() - 1;
while (start <= end)
{
int mid = (start + end) >> 1;
if ( less.Less( this->Element(mid), src, m_pLessContext ) )
{
start = mid + 1;
}
else
{
end = mid - 1;
}
}
return end;
}
//-----------------------------------------------------------------------------
// Removes a particular element
//-----------------------------------------------------------------------------
template <class T, class LessFunc, class BaseVector>
void CUtlSortVector<T, LessFunc, BaseVector>::Remove( const T& search )
{
AssertFatal( !m_bNeedsSort );
int pos = Find(search);
if (pos != -1)
{
BaseVector::Remove(pos);
}
}
template <class T, class LessFunc, class BaseVector>
void CUtlSortVector<T, LessFunc, BaseVector>::Remove( int i )
{
BaseVector::Remove( i );
}
#endif // UTLSORTVECTOR_H

1076
public/tier1/utlspheretree.h Normal file

File diff suppressed because it is too large Load Diff

331
public/tier1/utlstack.h Normal file
View File

@@ -0,0 +1,331 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
// A stack based on a growable array
//=============================================================================//
#ifndef UTLSTACK_H
#define UTLSTACK_H
#include <assert.h>
#include <string.h>
#include "utlmemory.h"
//-----------------------------------------------------------------------------
// The CUtlStack class:
// A growable stack class which doubles in size by default.
// It will always keep all elements consecutive in memory, and may move the
// elements around in memory (via a realloc) when elements are pushed or
// popped. Clients should therefore refer to the elements of the stack
// by index (they should *never* maintain pointers to elements in the stack).
//-----------------------------------------------------------------------------
template< class T, class M = CUtlMemory< T > >
class CUtlStack
{
public:
// constructor, destructor
CUtlStack( int growSize = 0, int initSize = 0 );
~CUtlStack();
void CopyFrom( const CUtlStack<T, M> &from );
// element access
T& operator[]( int i );
T const& operator[]( int i ) const;
T& Element( int i );
T const& Element( int i ) const;
// Gets the base address (can change when adding elements!)
T* Base();
T const* Base() const;
// Looks at the stack top
T& Top();
T const& Top() const;
// Size
int Count() const;
// Is element index valid?
bool IsIdxValid( int i ) const;
// Adds an element, uses default constructor
int Push();
// Adds an element, uses copy constructor
int Push( T const& src );
// Pops the stack
void Pop();
void Pop( T& oldTop );
void PopMultiple( int num );
// Makes sure we have enough memory allocated to store a requested # of elements
void EnsureCapacity( int num );
// Clears the stack, no deallocation
void Clear();
// Memory deallocation
void Purge();
private:
// Grows the stack allocation
void GrowStack();
// For easier access to the elements through the debugger
void ResetDbgInfo();
M m_Memory;
int m_Size;
// For easier access to the elements through the debugger
T* m_pElements;
};
//-----------------------------------------------------------------------------
// For easier access to the elements through the debugger
//-----------------------------------------------------------------------------
template< class T, class M >
inline void CUtlStack<T,M>::ResetDbgInfo()
{
m_pElements = m_Memory.Base();
}
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
template< class T, class M >
CUtlStack<T,M>::CUtlStack( int growSize, int initSize ) :
m_Memory(growSize, initSize), m_Size(0)
{
ResetDbgInfo();
}
template< class T, class M >
CUtlStack<T,M>::~CUtlStack()
{
Purge();
}
//-----------------------------------------------------------------------------
// copy into
//-----------------------------------------------------------------------------
template< class T, class M >
void CUtlStack<T,M>::CopyFrom( const CUtlStack<T, M> &from )
{
Purge();
EnsureCapacity( from.Count() );
for ( int i = 0; i < from.Count(); i++ )
{
Push( from[i] );
}
}
//-----------------------------------------------------------------------------
// element access
//-----------------------------------------------------------------------------
template< class T, class M >
inline T& CUtlStack<T,M>::operator[]( int i )
{
assert( IsIdxValid(i) );
return m_Memory[i];
}
template< class T, class M >
inline T const& CUtlStack<T,M>::operator[]( int i ) const
{
assert( IsIdxValid(i) );
return m_Memory[i];
}
template< class T, class M >
inline T& CUtlStack<T,M>::Element( int i )
{
assert( IsIdxValid(i) );
return m_Memory[i];
}
template< class T, class M >
inline T const& CUtlStack<T,M>::Element( int i ) const
{
assert( IsIdxValid(i) );
return m_Memory[i];
}
//-----------------------------------------------------------------------------
// Gets the base address (can change when adding elements!)
//-----------------------------------------------------------------------------
template< class T, class M >
inline T* CUtlStack<T,M>::Base()
{
return m_Memory.Base();
}
template< class T, class M >
inline T const* CUtlStack<T,M>::Base() const
{
return m_Memory.Base();
}
//-----------------------------------------------------------------------------
// Returns the top of the stack
//-----------------------------------------------------------------------------
template< class T, class M >
inline T& CUtlStack<T,M>::Top()
{
assert( m_Size > 0 );
return Element(m_Size-1);
}
template< class T, class M >
inline T const& CUtlStack<T,M>::Top() const
{
assert( m_Size > 0 );
return Element(m_Size-1);
}
//-----------------------------------------------------------------------------
// Size
//-----------------------------------------------------------------------------
template< class T, class M >
inline int CUtlStack<T,M>::Count() const
{
return m_Size;
}
//-----------------------------------------------------------------------------
// Is element index valid?
//-----------------------------------------------------------------------------
template< class T, class M >
inline bool CUtlStack<T,M>::IsIdxValid( int i ) const
{
return (i >= 0) && (i < m_Size);
}
//-----------------------------------------------------------------------------
// Grows the stack
//-----------------------------------------------------------------------------
template< class T, class M >
void CUtlStack<T,M>::GrowStack()
{
if (m_Size >= m_Memory.NumAllocated())
m_Memory.Grow();
++m_Size;
ResetDbgInfo();
}
//-----------------------------------------------------------------------------
// Makes sure we have enough memory allocated to store a requested # of elements
//-----------------------------------------------------------------------------
template< class T, class M >
void CUtlStack<T,M>::EnsureCapacity( int num )
{
m_Memory.EnsureCapacity(num);
ResetDbgInfo();
}
//-----------------------------------------------------------------------------
// Adds an element, uses default constructor
//-----------------------------------------------------------------------------
template< class T, class M >
int CUtlStack<T,M>::Push()
{
GrowStack();
Construct( &Element(m_Size-1) );
return m_Size - 1;
}
//-----------------------------------------------------------------------------
// Adds an element, uses copy constructor
//-----------------------------------------------------------------------------
template< class T, class M >
int CUtlStack<T,M>::Push( T const& src )
{
GrowStack();
CopyConstruct( &Element(m_Size-1), src );
return m_Size - 1;
}
//-----------------------------------------------------------------------------
// Pops the stack
//-----------------------------------------------------------------------------
template< class T, class M >
void CUtlStack<T,M>::Pop()
{
assert( m_Size > 0 );
Destruct( &Element(m_Size-1) );
--m_Size;
}
template< class T, class M >
void CUtlStack<T,M>::Pop( T& oldTop )
{
assert( m_Size > 0 );
oldTop = Top();
Pop();
}
template< class T, class M >
void CUtlStack<T,M>::PopMultiple( int num )
{
assert( m_Size >= num );
for ( int i = 0; i < num; ++i )
Destruct( &Element( m_Size - i - 1 ) );
m_Size -= num;
}
//-----------------------------------------------------------------------------
// Element removal
//-----------------------------------------------------------------------------
template< class T, class M >
void CUtlStack<T,M>::Clear()
{
for (int i = m_Size; --i >= 0; )
Destruct(&Element(i));
m_Size = 0;
}
//-----------------------------------------------------------------------------
// Memory deallocation
//-----------------------------------------------------------------------------
template< class T, class M >
void CUtlStack<T,M>::Purge()
{
Clear();
m_Memory.Purge( );
ResetDbgInfo();
}
#endif // UTLSTACK_H

1488
public/tier1/utlstring.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,74 @@
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
#ifndef UTLSTRINGTOKEN_H
#define UTLSTRINGTOKEN_H
#ifdef _WIN32
#pragma once
#endif
#include <limits.h>
#include "tier0/threadtools.h"
#include "tier1/mempool.h"
#include "tier1/generichash.h"
#define DEBUG_STRINGTOKENS 0
#define STRINGTOKEN_MURMURHASH_SEED 0x31415926
class CUtlStringToken
{
public:
uint32 m_nHashCode;
#if DEBUG_STRINGTOKENS
char const *m_pDebugName;
#endif
FORCEINLINE bool operator==( CUtlStringToken const &other ) const
{
return ( other.m_nHashCode == m_nHashCode );
}
FORCEINLINE bool operator!=( CUtlStringToken const &other ) const
{
return ( other.m_nHashCode != m_nHashCode );
}
FORCEINLINE bool operator<( CUtlStringToken const &other ) const
{
return ( m_nHashCode < other.m_nHashCode );
}
/// access to the hash code for people who need to store thse as 32-bits, regardless of the
/// setting of DEBUG_STRINGTOKENS (for instance, for atomic operations).
FORCEINLINE uint32 GetHashCode( void ) const { return m_nHashCode; }
FORCEINLINE void SetHashCode( uint32 nCode ) { m_nHashCode = nCode; }
#ifndef _DEBUG // the auto-generated things are too big when not inlined and optimized away
#include "tier1/utlstringtoken_generated_contructors.h"
#else
CUtlStringToken( char const *pString ) // generate one from a dynamic string
{
m_nHashCode = MurmurHash2LowerCase( pString, STRINGTOKEN_MURMURHASH_SEED );
}
#endif
CUtlStringToken() { m_nHashCode = 0; }
};
FORCEINLINE CUtlStringToken MakeStringToken( char const *pString )
{
CUtlStringToken ret;
ret.m_nHashCode = MurmurHash2LowerCase( pString, STRINGTOKEN_MURMURHASH_SEED );
return ret;
}
#endif // UTLSTRINGTOKEN_H

View File

@@ -0,0 +1,959 @@
//===== Copyright <20> 1996-2009, Valve Corporation, All rights reserved. ======//
//
// Purpose: inlines for compile-time hashing of constant strings
//
// : $
//
//===========================================================================//
// DO NOT EDIT THIS FILE - IT IS GENERATED BY RUNNING GENERATE_CONSTRUCTORS.PL
#define TOLOWERU( c ) ( ( uint32 ) ( ( ( c >= 'A' ) && ( c <= 'Z' ) )? c + 32 : c ) )
FORCEINLINE CUtlStringToken( const char ( &str )[1] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 0;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[2] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 1;
h ^= TOLOWERU( str[ 0 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[3] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 2;
h ^= TOLOWERU( str[ 0 + 1 ] ) << 8;
h ^= TOLOWERU( str[ 0 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[4] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 3;
h ^= TOLOWERU( str[ 0 + 2 ] ) << 16;
h ^= TOLOWERU( str[ 0 + 1 ] ) << 8;
h ^= TOLOWERU( str[ 0 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[5] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 4;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[6] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 5;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 4 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[7] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 6;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 4 + 1 ] ) << 8;
h ^= TOLOWERU( str[ 4 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[8] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 7;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 4 + 2 ] ) << 16;
h ^= TOLOWERU( str[ 4 + 1 ] ) << 8;
h ^= TOLOWERU( str[ 4 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[9] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 8;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[10] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 9;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 8 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[11] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 10;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 8 + 1 ] ) << 8;
h ^= TOLOWERU( str[ 8 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[12] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 11;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 8 + 2 ] ) << 16;
h ^= TOLOWERU( str[ 8 + 1 ] ) << 8;
h ^= TOLOWERU( str[ 8 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[13] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 12;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[14] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 13;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 12 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[15] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 14;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 12 + 1 ] ) << 8;
h ^= TOLOWERU( str[ 12 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[16] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 15;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 12 + 2 ] ) << 16;
h ^= TOLOWERU( str[ 12 + 1 ] ) << 8;
h ^= TOLOWERU( str[ 12 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[17] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 16;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 12 ] ) + ( TOLOWERU( str[ 12 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 12 + 2 ] ) << 16 ) +( TOLOWERU( str[ 12 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[18] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 17;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 12 ] ) + ( TOLOWERU( str[ 12 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 12 + 2 ] ) << 16 ) +( TOLOWERU( str[ 12 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 16 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[19] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 18;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 12 ] ) + ( TOLOWERU( str[ 12 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 12 + 2 ] ) << 16 ) +( TOLOWERU( str[ 12 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 16 + 1 ] ) << 8;
h ^= TOLOWERU( str[ 16 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[20] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 19;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 12 ] ) + ( TOLOWERU( str[ 12 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 12 + 2 ] ) << 16 ) +( TOLOWERU( str[ 12 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 16 + 2 ] ) << 16;
h ^= TOLOWERU( str[ 16 + 1 ] ) << 8;
h ^= TOLOWERU( str[ 16 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[21] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 20;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 12 ] ) + ( TOLOWERU( str[ 12 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 12 + 2 ] ) << 16 ) +( TOLOWERU( str[ 12 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 16 ] ) + ( TOLOWERU( str[ 16 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 16 + 2 ] ) << 16 ) +( TOLOWERU( str[ 16 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[22] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 21;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 12 ] ) + ( TOLOWERU( str[ 12 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 12 + 2 ] ) << 16 ) +( TOLOWERU( str[ 12 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 16 ] ) + ( TOLOWERU( str[ 16 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 16 + 2 ] ) << 16 ) +( TOLOWERU( str[ 16 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 20 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[23] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 22;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 12 ] ) + ( TOLOWERU( str[ 12 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 12 + 2 ] ) << 16 ) +( TOLOWERU( str[ 12 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 16 ] ) + ( TOLOWERU( str[ 16 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 16 + 2 ] ) << 16 ) +( TOLOWERU( str[ 16 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 20 + 1 ] ) << 8;
h ^= TOLOWERU( str[ 20 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[24] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 23;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 12 ] ) + ( TOLOWERU( str[ 12 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 12 + 2 ] ) << 16 ) +( TOLOWERU( str[ 12 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 16 ] ) + ( TOLOWERU( str[ 16 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 16 + 2 ] ) << 16 ) +( TOLOWERU( str[ 16 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 20 + 2 ] ) << 16;
h ^= TOLOWERU( str[ 20 + 1 ] ) << 8;
h ^= TOLOWERU( str[ 20 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[25] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 24;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 12 ] ) + ( TOLOWERU( str[ 12 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 12 + 2 ] ) << 16 ) +( TOLOWERU( str[ 12 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 16 ] ) + ( TOLOWERU( str[ 16 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 16 + 2 ] ) << 16 ) +( TOLOWERU( str[ 16 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 20 ] ) + ( TOLOWERU( str[ 20 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 20 + 2 ] ) << 16 ) +( TOLOWERU( str[ 20 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[26] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 25;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 12 ] ) + ( TOLOWERU( str[ 12 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 12 + 2 ] ) << 16 ) +( TOLOWERU( str[ 12 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 16 ] ) + ( TOLOWERU( str[ 16 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 16 + 2 ] ) << 16 ) +( TOLOWERU( str[ 16 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 20 ] ) + ( TOLOWERU( str[ 20 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 20 + 2 ] ) << 16 ) +( TOLOWERU( str[ 20 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 24 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[27] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 26;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 12 ] ) + ( TOLOWERU( str[ 12 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 12 + 2 ] ) << 16 ) +( TOLOWERU( str[ 12 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 16 ] ) + ( TOLOWERU( str[ 16 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 16 + 2 ] ) << 16 ) +( TOLOWERU( str[ 16 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 20 ] ) + ( TOLOWERU( str[ 20 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 20 + 2 ] ) << 16 ) +( TOLOWERU( str[ 20 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 24 + 1 ] ) << 8;
h ^= TOLOWERU( str[ 24 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[28] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 27;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 12 ] ) + ( TOLOWERU( str[ 12 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 12 + 2 ] ) << 16 ) +( TOLOWERU( str[ 12 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 16 ] ) + ( TOLOWERU( str[ 16 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 16 + 2 ] ) << 16 ) +( TOLOWERU( str[ 16 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 20 ] ) + ( TOLOWERU( str[ 20 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 20 + 2 ] ) << 16 ) +( TOLOWERU( str[ 20 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= TOLOWERU( str[ 24 + 2 ] ) << 16;
h ^= TOLOWERU( str[ 24 + 1 ] ) << 8;
h ^= TOLOWERU( str[ 24 + 0 ] );
h *= m;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}
FORCEINLINE CUtlStringToken( const char ( &str )[29] )
{
const uint32 m = 0x5bd1e995;
uint32 h = STRINGTOKEN_MURMURHASH_SEED ^ 28;
uint32 k;
const int r = 24;
k = TOLOWERU( str[ 0 ] ) + ( TOLOWERU( str[ 0 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 0 + 2 ] ) << 16 ) +( TOLOWERU( str[ 0 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 4 ] ) + ( TOLOWERU( str[ 4 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 4 + 2 ] ) << 16 ) +( TOLOWERU( str[ 4 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 8 ] ) + ( TOLOWERU( str[ 8 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 8 + 2 ] ) << 16 ) +( TOLOWERU( str[ 8 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 12 ] ) + ( TOLOWERU( str[ 12 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 12 + 2 ] ) << 16 ) +( TOLOWERU( str[ 12 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 16 ] ) + ( TOLOWERU( str[ 16 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 16 + 2 ] ) << 16 ) +( TOLOWERU( str[ 16 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 20 ] ) + ( TOLOWERU( str[ 20 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 20 + 2 ] ) << 16 ) +( TOLOWERU( str[ 20 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = TOLOWERU( str[ 24 ] ) + ( TOLOWERU( str[ 24 + 1 ] ) << 8 ) + ( TOLOWERU( str[ 24 + 2 ] ) << 16 ) +( TOLOWERU( str[ 24 + 3 ] ) << 24 );
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
m_nHashCode = h;
}

380
public/tier1/utlsymbol.h Normal file
View File

@@ -0,0 +1,380 @@
//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose: Defines a symbol table
//
// $Header: $
// $NoKeywords: $
//===========================================================================//
#ifndef UTLSYMBOL_H
#define UTLSYMBOL_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/platform.h"
#include "tier0/threadtools.h"
#include "tier1/utlrbtree.h"
#include "tier1/utlvector.h"
#include "tier1/utlbuffer.h"
#include "tier1/utllinkedlist.h"
#include "tier1/stringpool.h"
//-----------------------------------------------------------------------------
// forward declarations
//-----------------------------------------------------------------------------
class CUtlSymbolTable;
class CUtlSymbolTableMT;
//-----------------------------------------------------------------------------
// This is a symbol, which is a easier way of dealing with strings.
//-----------------------------------------------------------------------------
typedef unsigned short UtlSymId_t;
#define UTL_INVAL_SYMBOL ((UtlSymId_t)~0)
class CUtlSymbol
{
public:
// constructor, destructor
CUtlSymbol() : m_Id(UTL_INVAL_SYMBOL) {}
CUtlSymbol( UtlSymId_t id ) : m_Id(id) {}
CUtlSymbol( const char* pStr );
CUtlSymbol( CUtlSymbol const& sym ) : m_Id(sym.m_Id) {}
// operator=
CUtlSymbol& operator=( CUtlSymbol const& src ) { m_Id = src.m_Id; return *this; }
// operator==
bool operator==( CUtlSymbol const& src ) const { return m_Id == src.m_Id; }
bool operator==( const char* pStr ) const;
// Is valid?
bool IsValid() const { return m_Id != UTL_INVAL_SYMBOL; }
// Gets at the symbol
operator UtlSymId_t () const { return m_Id; }
// Gets the string associated with the symbol
const char* String( ) const;
// Modules can choose to disable the static symbol table so to prevent accidental use of them.
static void DisableStaticSymbolTable();
// Methods with explicit locking mechanism. Only use for optimization reasons.
static void LockTableForRead();
static void UnlockTableForRead();
const char * StringNoLock() const;
protected:
UtlSymId_t m_Id;
// Initializes the symbol table
static void Initialize();
// returns the current symbol table
static CUtlSymbolTableMT* CurrTable();
// The standard global symbol table
static CUtlSymbolTableMT* s_pSymbolTable;
static bool s_bAllowStaticSymbolTable;
friend class CCleanupUtlSymbolTable;
};
//-----------------------------------------------------------------------------
// CUtlSymbolTable:
// description:
// This class defines a symbol table, which allows us to perform mappings
// of strings to symbols and back. The symbol class itself contains
// a static version of this class for creating global strings, but this
// class can also be instanced to create local symbol tables.
//
// This class stores the strings in a series of string pools. The first
// two bytes of each string are decorated with a hash to speed up
// comparisons.
//-----------------------------------------------------------------------------
class CUtlSymbolTable
{
public:
// constructor, destructor
CUtlSymbolTable( int growSize = 0, int initSize = 16, bool caseInsensitive = false );
~CUtlSymbolTable();
// Finds and/or creates a symbol based on the string
CUtlSymbol AddString( const char* pString );
// Finds the symbol for pString
CUtlSymbol Find( const char* pString ) const;
// Look up the string associated with a particular symbol
const char* String( CUtlSymbol id ) const;
inline bool HasElement(const char* pStr) const
{
return Find(pStr) != UTL_INVAL_SYMBOL;
}
// Remove all symbols in the table.
void RemoveAll();
int GetNumStrings( void ) const
{
return m_Lookup.Count();
}
// We store one of these at the beginning of every string to speed
// up comparisons.
typedef unsigned short hashDecoration_t;
protected:
class CStringPoolIndex
{
public:
inline CStringPoolIndex()
{
}
inline CStringPoolIndex( unsigned short iPool, unsigned short iOffset )
: m_iPool(iPool), m_iOffset(iOffset)
{}
inline bool operator==( const CStringPoolIndex &other ) const
{
return m_iPool == other.m_iPool && m_iOffset == other.m_iOffset;
}
unsigned short m_iPool; // Index into m_StringPools.
unsigned short m_iOffset; // Index into the string pool.
};
class CLess
{
public:
CLess( int ignored = 0 ) {} // permits default initialization to NULL in CUtlRBTree
bool operator!() const { return false; }
bool operator()( const CStringPoolIndex &left, const CStringPoolIndex &right ) const;
};
// Stores the symbol lookup
class CTree : public CUtlRBTree<CStringPoolIndex, unsigned short, CLess>
{
public:
CTree( int growSize, int initSize ) : CUtlRBTree<CStringPoolIndex, unsigned short, CLess>( growSize, initSize ) {}
friend class CUtlSymbolTable::CLess; // Needed to allow CLess to calculate pointer to symbol table
};
struct StringPool_t
{
int m_TotalLen; // How large is
int m_SpaceUsed;
char m_Data[1];
};
CTree m_Lookup;
bool m_bInsensitive;
mutable unsigned short m_nUserSearchStringHash;
mutable const char* m_pUserSearchString;
// stores the string data
CUtlVector<StringPool_t*> m_StringPools;
private:
int FindPoolWithSpace( int len ) const;
const char* StringFromIndex( const CStringPoolIndex &index ) const;
const char* DecoratedStringFromIndex( const CStringPoolIndex &index ) const;
friend class CLess;
friend class CSymbolHash;
};
class CUtlSymbolTableMT : public CUtlSymbolTable
{
public:
CUtlSymbolTableMT( int growSize = 0, int initSize = 32, bool caseInsensitive = false )
: CUtlSymbolTable( growSize, initSize, caseInsensitive )
{
}
CUtlSymbol AddString( const char* pString )
{
m_lock.LockForWrite();
CUtlSymbol result = CUtlSymbolTable::AddString( pString );
m_lock.UnlockWrite();
return result;
}
CUtlSymbol Find( const char* pString ) const
{
m_lock.LockForWrite();
CUtlSymbol result = CUtlSymbolTable::Find( pString );
m_lock.UnlockWrite();
return result;
}
const char* String( CUtlSymbol id ) const
{
m_lock.LockForRead();
const char *pszResult = CUtlSymbolTable::String( id );
m_lock.UnlockRead();
return pszResult;
}
const char * StringNoLock( CUtlSymbol id ) const
{
return CUtlSymbolTable::String( id );
}
void LockForRead()
{
m_lock.LockForRead();
}
void UnlockForRead()
{
m_lock.UnlockRead();
}
private:
#ifdef WIN32
mutable CThreadSpinRWLock m_lock;
#else
mutable CThreadRWLock m_lock;
#endif
};
//-----------------------------------------------------------------------------
// CUtlFilenameSymbolTable:
// description:
// This class defines a symbol table of individual filenames, stored more
// efficiently than a standard symbol table. Internally filenames are broken
// up into file and path entries, and a file handle class allows convenient
// access to these.
//-----------------------------------------------------------------------------
// The handle is a CUtlSymbol for the dirname and the same for the filename, the accessor
// copies them into a static char buffer for return.
typedef void* FileNameHandle_t;
// Symbol table for more efficiently storing filenames by breaking paths and filenames apart.
// Refactored from BaseFileSystem.h
class CUtlFilenameSymbolTable
{
// Internal representation of a FileHandle_t
// If we get more than 64K filenames, we'll have to revisit...
// Right now CUtlSymbol is a short, so this packs into an int/void * pointer size...
struct FileNameHandleInternal_t
{
FileNameHandleInternal_t()
{
COMPILE_TIME_ASSERT( sizeof( *this ) == sizeof( FileNameHandle_t ) );
COMPILE_TIME_ASSERT( sizeof( value ) == 4 );
value = 0;
#ifdef PLATFORM_64BITS
pad = 0;
#endif
}
// We pack the path and file values into a single 32 bit value. We were running
// out of space with the two 16 bit values (more than 64k files) so instead of increasing
// the total size we split the underlying pool into two (paths and files) and
// use a smaller path string pool and a larger file string pool.
unsigned int value;
#ifdef PLATFORM_64BITS
// some padding to make sure we are the same size as FileNameHandle_t on 64 bit.
unsigned int pad;
#endif
static const unsigned int cNumBitsInPath = 12;
static const unsigned int cNumBitsInFile = 32 - cNumBitsInPath;
static const unsigned int cMaxPathValue = 1 << cNumBitsInPath;
static const unsigned int cMaxFileValue = 1 << cNumBitsInFile;
static const unsigned int cPathBitMask = cMaxPathValue - 1;
static const unsigned int cFileBitMask = cMaxFileValue - 1;
// Part before the final '/' character
unsigned int GetPath() const { return ((value >> cNumBitsInFile) & cPathBitMask); }
void SetPath( unsigned int path ) { Assert( path < cMaxPathValue ); value = ((value & cFileBitMask) | ((path & cPathBitMask) << cNumBitsInFile)); }
// Part after the final '/', including extension
unsigned int GetFile() const { return (value & cFileBitMask); }
void SetFile( unsigned int file ) { Assert( file < cMaxFileValue ); value = ((value & (cPathBitMask << cNumBitsInFile)) | (file & cFileBitMask)); }
};
public:
FileNameHandle_t FindOrAddFileName( const char *pFileName );
FileNameHandle_t FindFileName( const char *pFileName );
int PathIndex( const FileNameHandle_t &handle ) { return (( const FileNameHandleInternal_t * )&handle)->GetPath(); }
bool String( const FileNameHandle_t& handle, char *buf, int buflen );
void RemoveAll();
void SpewStrings();
bool SaveToBuffer( CUtlBuffer &buffer );
bool RestoreFromBuffer( CUtlBuffer &buffer );
private:
CCountedStringPoolBase<unsigned short> m_PathStringPool;
CCountedStringPoolBase<unsigned int> m_FileStringPool;
mutable CThreadSpinRWLock m_lock;
};
// This creates a simple class that includes the underlying CUtlSymbol
// as a private member and then instances a private symbol table to
// manage those symbols. Avoids the possibility of the code polluting the
// 'global'/default symbol table, while letting the code look like
// it's just using = and .String() to look at CUtlSymbol type objects
//
// NOTE: You can't pass these objects between .dlls in an interface (also true of CUtlSymbol of course)
//
#define DECLARE_PRIVATE_SYMBOLTYPE( typename ) \
class typename \
{ \
public: \
typename(); \
typename( const char* pStr ); \
typename& operator=( typename const& src ); \
bool operator==( typename const& src ) const; \
const char* String( ) const; \
private: \
CUtlSymbol m_SymbolId; \
};
// Put this in the .cpp file that uses the above typename
#define IMPLEMENT_PRIVATE_SYMBOLTYPE( typename ) \
static CUtlSymbolTable g_##typename##SymbolTable; \
typename::typename() \
{ \
m_SymbolId = UTL_INVAL_SYMBOL; \
} \
typename::typename( const char* pStr ) \
{ \
m_SymbolId = g_##typename##SymbolTable.AddString( pStr ); \
} \
typename& typename::operator=( typename const& src ) \
{ \
m_SymbolId = src.m_SymbolId; \
return *this; \
} \
bool typename::operator==( typename const& src ) const \
{ \
return ( m_SymbolId == src.m_SymbolId ); \
} \
const char* typename::String( ) const \
{ \
return g_##typename##SymbolTable.String( m_SymbolId ); \
}
#endif // UTLSYMBOL_H

View File

@@ -0,0 +1,506 @@
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose: Defines a large symbol table (intp sized handles, can store more than 64k strings)
//
// $Header: $
// $NoKeywords: $
//===========================================================================//
#ifndef UTLSYMBOLLARGE_H
#define UTLSYMBOLLARGE_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/threadtools.h"
#include "tier1/utltshash.h"
#include "tier1/stringpool.h"
#include "tier0/vprof.h"
#include "tier1/utltshash.h"
//-----------------------------------------------------------------------------
// CUtlSymbolTableLarge:
// description:
// This class defines a symbol table, which allows us to perform mappings
// of strings to symbols and back.
//
// This class stores the strings in a series of string pools. The returned CUtlSymbolLarge is just a pointer
// to the string data, the hash precedes it in memory and is used to speed up searching, etc.
//-----------------------------------------------------------------------------
typedef intp UtlSymLargeId_t;
#define UTL_INVAL_SYMBOL_LARGE ((UtlSymLargeId_t)~0)
class CUtlSymbolLarge
{
public:
// constructor, destructor
CUtlSymbolLarge()
{
u.m_Id = UTL_INVAL_SYMBOL_LARGE;
}
CUtlSymbolLarge( UtlSymLargeId_t id )
{
u.m_Id = id;
}
CUtlSymbolLarge( CUtlSymbolLarge const& sym )
{
u.m_Id = sym.u.m_Id;
}
// operator=
CUtlSymbolLarge& operator=( CUtlSymbolLarge const& src )
{
u.m_Id = src.u.m_Id;
return *this;
}
// operator==
bool operator==( CUtlSymbolLarge const& src ) const
{
return u.m_Id == src.u.m_Id;
}
// operator==
bool operator==( UtlSymLargeId_t const& src ) const
{
return u.m_Id == src;
}
// operator==
bool operator!=( CUtlSymbolLarge const& src ) const
{
return u.m_Id != src.u.m_Id;
}
// operator==
bool operator!=( UtlSymLargeId_t const& src ) const
{
return u.m_Id != src;
}
// Gets at the symbol
operator UtlSymLargeId_t const() const
{
return u.m_Id;
}
// Gets the string associated with the symbol
inline const char* String( ) const
{
if ( u.m_Id == UTL_INVAL_SYMBOL_LARGE )
return "";
return u.m_pAsString;
}
inline bool IsValid() const
{
return u.m_Id != UTL_INVAL_SYMBOL_LARGE ? true : false;
}
private:
// Disallowed
CUtlSymbolLarge( const char* pStr ); // they need to go through the table to assign the ptr
bool operator==( const char* pStr ) const; // disallow since we don't know if the table this is from was case sensitive or not... maybe we don't care
union
{
UtlSymLargeId_t m_Id;
char const *m_pAsString;
} u;
};
#define MIN_STRING_POOL_SIZE 2048
inline uint32 CUtlSymbolLarge_Hash( bool CASEINSENSITIVE, const char *pString, int len )
{
return ( CASEINSENSITIVE ? HashStringCaseless( pString ) : HashString( pString ) );
}
typedef uint32 LargeSymbolTableHashDecoration_t;
// The structure consists of the hash immediately followed by the string data
struct CUtlSymbolTableLargeBaseTreeEntry_t
{
LargeSymbolTableHashDecoration_t m_Hash;
// Variable length string data
char m_String[1];
bool IsEmpty() const
{
return ( ( m_Hash == 0 ) && ( 0 == m_String[0] ) );
}
char const *String() const
{
return (const char *)&m_String[ 0 ];
}
CUtlSymbolLarge ToSymbol() const
{
return reinterpret_cast< UtlSymLargeId_t >( String() );
}
LargeSymbolTableHashDecoration_t HashValue() const
{
return m_Hash;
}
};
template< class TreeType, bool CASEINSENSITIVE >
class CTreeEntryLess
{
public:
CTreeEntryLess( int ignored = 0 ) {} // permits default initialization to NULL in CUtlRBTree
bool operator!() const { return false; }
bool operator()( CUtlSymbolTableLargeBaseTreeEntry_t * const &left, CUtlSymbolTableLargeBaseTreeEntry_t * const &right ) const
{
// compare the hashes
if ( left->m_Hash == right->m_Hash )
{
// if the hashes match compare the strings
if ( !CASEINSENSITIVE )
return strcmp( left->String(), right->String() ) < 0;
else
return V_stricmp( left->String(), right->String() ) < 0;
}
else
{
return left->m_Hash < right->m_Hash;
}
}
};
// For non-threaded versions, simply index into CUtlRBTree
template< bool CASEINSENSITIVE >
class CNonThreadsafeTree : public CUtlRBTree<CUtlSymbolTableLargeBaseTreeEntry_t *, intp, CTreeEntryLess< CNonThreadsafeTree< CASEINSENSITIVE >, CASEINSENSITIVE > >
{
public:
typedef CUtlRBTree<CUtlSymbolTableLargeBaseTreeEntry_t *, intp, CTreeEntryLess< CNonThreadsafeTree, CASEINSENSITIVE > > CNonThreadsafeTreeType;
CNonThreadsafeTree() :
CNonThreadsafeTreeType( 0, 16 )
{
}
inline void Commit()
{
// Nothing, only matters for thread-safe tables
}
inline intp Insert( CUtlSymbolTableLargeBaseTreeEntry_t *entry )
{
return CNonThreadsafeTreeType::Insert( entry );
}
inline intp Find( CUtlSymbolTableLargeBaseTreeEntry_t *entry ) const
{
return CNonThreadsafeTreeType::Find( entry );
}
inline intp InvalidIndex() const
{
return CNonThreadsafeTreeType::InvalidIndex();
}
inline int GetElements( int nFirstElement, int nCount, CUtlSymbolLarge *pElements ) const
{
CUtlVector< CUtlSymbolTableLargeBaseTreeEntry_t * > list;
list.EnsureCount( nCount );
for ( int i = 0; i < nCount; ++i )
{
pElements[ i ] = CNonThreadsafeTreeType::Element( i )->ToSymbol();
}
return nCount;
}
};
// Since CUtlSymbolTableLargeBaseTreeEntry_t already has the hash
// contained inside of it, don't need to recompute a hash here
template < int BUCKET_COUNT, class KEYTYPE, bool CASEINSENSITIVE >
class CCThreadsafeTreeHashMethod
{
public:
static int Hash( const KEYTYPE &key, int nBucketMask )
{
uint32 nHash = key->HashValue();
return ( nHash & nBucketMask );
}
static bool Compare( CUtlSymbolTableLargeBaseTreeEntry_t * const &lhs, CUtlSymbolTableLargeBaseTreeEntry_t * const &rhs )
{
if ( lhs->m_Hash != rhs->m_Hash )
return false;
if ( !CASEINSENSITIVE )
{
return ( !Q_strcmp( lhs->String(), rhs->String() ) ? true : false );
}
return ( !Q_stricmp( lhs->String(), rhs->String() ) ? true : false );
}
};
/*
NOTE: So the only crappy thing about using a CUtlTSHash here is that the KEYTYPE is a CUtlSymbolTableLargeBaseTreeEntry_t ptr which has both the
hash and the string since with strings there is a good chance of hash collision after you have a fair number of strings so we have to implement
a Compare method (above) which falls back to strcmp/stricmp if the hashes are equal. This means that all of the data is in the KEYTYPE of the hash and the
payload doesn't matter. So I made the payload also be a pointer to a CUtlSymbolTableLargeBaseTreeEntry_t since that makes using the API more convenient
TODO: If we have a CUtlTSHash that was all about the existence of the KEYTYPE and didn't require a payload (or template on 'void') then we could eliminate
50% of the pointer overhead used for this data structure.
*/
// Thread safe version is based on the
template < bool CASEINSENSITIVE >
class CThreadsafeTree : public CUtlTSHash< CUtlSymbolTableLargeBaseTreeEntry_t *, 2048, CUtlSymbolTableLargeBaseTreeEntry_t *, CCThreadsafeTreeHashMethod< 2048, CUtlSymbolTableLargeBaseTreeEntry_t *, CASEINSENSITIVE > >
{
public:
typedef CUtlTSHash< CUtlSymbolTableLargeBaseTreeEntry_t *, 2048, CUtlSymbolTableLargeBaseTreeEntry_t *, CCThreadsafeTreeHashMethod< 2048, CUtlSymbolTableLargeBaseTreeEntry_t *, CASEINSENSITIVE > > CThreadsafeTreeType;
CThreadsafeTree() :
CThreadsafeTreeType( 32 )
{
}
inline void Commit()
{
CThreadsafeTreeType::Commit();
}
inline UtlTSHashHandle_t Insert( CUtlSymbolTableLargeBaseTreeEntry_t *entry )
{
return CThreadsafeTreeType::Insert( entry, entry );
}
inline UtlTSHashHandle_t Find( CUtlSymbolTableLargeBaseTreeEntry_t *entry )
{
return CThreadsafeTreeType::Find( entry );
}
inline UtlTSHashHandle_t InvalidIndex() const
{
return CThreadsafeTreeType::InvalidHandle();
}
inline int GetElements( UtlTSHashHandle_t nFirstElement, int nCount, CUtlSymbolLarge *pElements ) const
{
CUtlVector< UtlTSHashHandle_t > list;
list.EnsureCount( nCount );
int c = CThreadsafeTreeType::GetElements( nFirstElement, nCount, list.Base() );
for ( int i = 0; i < c; ++i )
{
pElements[ i ] = CThreadsafeTreeType::Element( list[ i ] )->ToSymbol();
}
return c;
}
};
// Base Class for threaded and non-threaded types
template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE = MIN_STRING_POOL_SIZE >
class CUtlSymbolTableLargeBase
{
public:
// constructor, destructor
CUtlSymbolTableLargeBase();
~CUtlSymbolTableLargeBase();
// Finds and/or creates a symbol based on the string
CUtlSymbolLarge AddString( const char* pString );
// Finds the symbol for pString
CUtlSymbolLarge Find( const char* pString ) const;
// Remove all symbols in the table.
void RemoveAll();
int GetNumStrings( void ) const
{
return m_Lookup.Count();
}
void Commit()
{
m_Lookup.Commit();
}
// Returns elements in the table
int GetElements( int nFirstElement, int nCount, CUtlSymbolLarge *pElements ) const
{
return m_Lookup.GetElements( nFirstElement, nCount, pElements );
}
const char *GetElementString(int nElement) const
{
return m_Lookup.Element(nElement)->String();
}
uint64 GetMemoryUsage() const
{
uint64 unBytesUsed = 0u;
for ( int i=0; i < m_StringPools.Count(); i++ )
{
StringPool_t *pPool = m_StringPools[i];
unBytesUsed += (uint64)pPool->m_TotalLen;
}
return unBytesUsed;
}
protected:
struct StringPool_t
{
int m_TotalLen; // How large is
int m_SpaceUsed;
char m_Data[1];
};
TreeType m_Lookup;
// stores the string data
CUtlVector< StringPool_t * > m_StringPools;
private:
int FindPoolWithSpace( int len ) const;
};
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE >
inline CUtlSymbolTableLargeBase<TreeType, CASEINSENSITIVE, POOL_SIZE >::CUtlSymbolTableLargeBase() :
m_StringPools( 8 )
{
}
template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE >
inline CUtlSymbolTableLargeBase<TreeType, CASEINSENSITIVE, POOL_SIZE>::~CUtlSymbolTableLargeBase()
{
// Release the stringpool string data
RemoveAll();
}
template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE >
inline CUtlSymbolLarge CUtlSymbolTableLargeBase<TreeType, CASEINSENSITIVE, POOL_SIZE>::Find( const char* pString ) const
{
VPROF( "CUtlSymbolLarge::Find" );
if (!pString)
return CUtlSymbolLarge();
// Passing this special invalid symbol makes the comparison function
// use the string passed in the context
int len = Q_strlen( pString ) + 1;
CUtlSymbolTableLargeBaseTreeEntry_t *search = (CUtlSymbolTableLargeBaseTreeEntry_t *)_alloca( len + sizeof( LargeSymbolTableHashDecoration_t ) );
search->m_Hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, len );
Q_memcpy( (char *)&search->m_String[ 0 ], pString, len );
intp idx = const_cast< TreeType & >(m_Lookup).Find( search );
if ( idx == m_Lookup.InvalidIndex() )
return UTL_INVAL_SYMBOL_LARGE;
const CUtlSymbolTableLargeBaseTreeEntry_t *entry = m_Lookup[ idx ];
return entry->ToSymbol();
}
template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE >
inline int CUtlSymbolTableLargeBase<TreeType, CASEINSENSITIVE, POOL_SIZE>::FindPoolWithSpace( int len ) const
{
for ( int i=0; i < m_StringPools.Count(); i++ )
{
StringPool_t *pPool = m_StringPools[i];
if ( (pPool->m_TotalLen - pPool->m_SpaceUsed) >= len )
{
return i;
}
}
return -1;
}
//-----------------------------------------------------------------------------
// Finds and/or creates a symbol based on the string
//-----------------------------------------------------------------------------
template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE >
inline CUtlSymbolLarge CUtlSymbolTableLargeBase<TreeType, CASEINSENSITIVE, POOL_SIZE>::AddString( const char* pString )
{
VPROF("CUtlSymbolLarge::AddString");
if (!pString)
return UTL_INVAL_SYMBOL_LARGE;
CUtlSymbolLarge id = Find( pString );
if ( id != UTL_INVAL_SYMBOL_LARGE )
return id;
int lenString = Q_strlen(pString) + 1; // length of just the string
int lenDecorated = lenString + sizeof(LargeSymbolTableHashDecoration_t); // and with its hash decoration
// make sure that all strings are aligned on 2-byte boundaries so the hashes will read correctly
// This assert seems to be invalid because LargeSymbolTableHashDecoration_t is always
// a uint32, by design.
//COMPILE_TIME_ASSERT(sizeof(LargeSymbolTableHashDecoration_t) == sizeof(intp));
lenDecorated = ALIGN_VALUE(lenDecorated, sizeof( LargeSymbolTableHashDecoration_t ) );
// Find a pool with space for this string, or allocate a new one.
int iPool = FindPoolWithSpace( lenDecorated );
if ( iPool == -1 )
{
// Add a new pool.
int newPoolSize = MAX( lenDecorated + sizeof( StringPool_t ), POOL_SIZE );
StringPool_t *pPool = (StringPool_t*)malloc( newPoolSize );
pPool->m_TotalLen = newPoolSize - sizeof( StringPool_t );
pPool->m_SpaceUsed = 0;
iPool = m_StringPools.AddToTail( pPool );
}
// Compute a hash
LargeSymbolTableHashDecoration_t hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, lenString );
// Copy the string in.
StringPool_t *pPool = m_StringPools[iPool];
// Assert( pPool->m_SpaceUsed < 0xFFFF ); // Pool could be bigger than 2k
// This should never happen, because if we had a string > 64k, it
// would have been given its entire own pool.
CUtlSymbolTableLargeBaseTreeEntry_t *entry = ( CUtlSymbolTableLargeBaseTreeEntry_t * )&pPool->m_Data[ pPool->m_SpaceUsed ];
pPool->m_SpaceUsed += lenDecorated;
entry->m_Hash = hash;
char *pText = (char *)&entry->m_String [ 0 ];
Q_memcpy( pText, pString, lenString );
// insert the string into the database
MEM_ALLOC_CREDIT();
return m_Lookup.Element( m_Lookup.Insert( entry ) )->ToSymbol();
}
//-----------------------------------------------------------------------------
// Remove all symbols in the table.
//-----------------------------------------------------------------------------
#ifdef ANALYZE_SUPPRESS // So that swig builds
ANALYZE_SUPPRESS( 6001 ); // warning C6001: Using uninitialized memory '*m_StringPools.public: ...
#endif
template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE >
inline void CUtlSymbolTableLargeBase<TreeType, CASEINSENSITIVE, POOL_SIZE>::RemoveAll()
{
m_Lookup.Purge();
for ( int i=0; i < m_StringPools.Count(); i++ )
free( m_StringPools[i] );
m_StringPools.RemoveAll();
}
#ifdef ANALYZE_UNSUPPRESS // So that swig builds
ANALYZE_UNSUPPRESS(); // warning C6001: Using uninitialized memory '*m_StringPools.public: ...
#endif
// Case-sensitive
typedef CUtlSymbolTableLargeBase< CNonThreadsafeTree< false >, false > CUtlSymbolTableLarge;
// Case-insensitive
typedef CUtlSymbolTableLargeBase< CNonThreadsafeTree< true >, true > CUtlSymbolTableLarge_CI;
// Multi-threaded case-sensitive
typedef CUtlSymbolTableLargeBase< CThreadsafeTree< false >, false > CUtlSymbolTableLargeMT;
// Multi-threaded case-insensitive
typedef CUtlSymbolTableLargeBase< CThreadsafeTree< true >, true > CUtlSymbolTableLargeMT_CI;
#endif // UTLSYMBOLLARGE_H

182
public/tier1/utltscache.h Normal file
View File

@@ -0,0 +1,182 @@
//===== Copyright © 1996-2006, Valve Corporation, All rights reserved. ======//
//
// Purpose: thread safe cache template class
//
//===========================================================================//
// a thread-safe cache. Cache queries and updates may be performed on multiple threads at once in a
// lock-free fashion. You must call the "FrameUpdate" function while no one is querying against
// this cache.
#include "tier1/utlintrusivelist.h"
// in order to use this class, KEYTYPE must implement bool IsAcceptable( KEYTYPE const & ), and
// RECORDTYPE must implement CreateCacheData( KEYTYPE const & )
template< class RECORDTYPE, class KEYTYPE, class EXTRACREATEDATA, int nNumCacheLines, int nAssociativity = 4 > class CUtlTSCache
{
public:
class CCacheEntry : public CAlignedNewDelete<16>
{
public:
CCacheEntry *m_pNext;
CCacheEntry *m_pNextPending;
KEYTYPE m_Key;
RECORDTYPE m_Data;
};
~CUtlTSCache( void )
{
PerFrameUpdate(); // move pending to free
for( CCacheEntry *pNode = m_pFreeList; pNode; )
{
CCacheEntry *pNext = pNode->m_pNext;
if ( ! ( ( ( pNode >= m_pInitiallyAllocatedNodes ) &&
( pNode < m_pInitiallyAllocatedNodes + InitialAllocationSize() ) ) ) )
{
delete pNode;
}
pNode = pNext;
}
delete[] m_pInitiallyAllocatedNodes;
}
CUtlTSCache( void )
{
MEM_ALLOC_CREDIT_CLASS();
memset( m_pCache, 0, sizeof( m_pCache ) );
m_pInitiallyAllocatedNodes = new CCacheEntry[ InitialAllocationSize() ];
m_pFreeList = NULL;
for( int i = 0; i < InitialAllocationSize(); i++ )
{
IntrusiveList::AddToHead( m_pFreeList, m_pInitiallyAllocatedNodes + i );
}
m_pPendingFreeList = NULL;
}
void PerFrameUpdate( void )
{
for( CCacheEntry *pNode = m_pPendingFreeList; pNode; pNode = pNode->m_pNextPending )
{
IntrusiveList::AddToHead( m_pFreeList, pNode );
}
m_pPendingFreeList = NULL;
}
// Invalidate() is NOT thread-safe. If you need a thread-safe invalidate, you're going to need
// to do something like store a generation count in the key.
void Invalidate( void )
{
for( int i = 0; i < ARRAYSIZE( m_pCache ); i++ )
{
CCacheEntry *pNode = m_pCache[i];
if ( pNode )
{
IntrusiveList::AddToHead( m_pFreeList, pNode );
}
m_pCache[i] = NULL;
}
}
// lookup a value, maybe add one
RECORDTYPE *Lookup( KEYTYPE const &key, EXTRACREATEDATA const &extraCreateData )
{
// first perform our hash function
uint nHash = HashItem( key ) % nNumCacheLines;
CCacheEntry **pCacheLine = m_pCache + nHash * nAssociativity;
// now, see if we have an acceptable node
CCacheEntry *pOldValue[nAssociativity];
int nOffset = ( nAssociativity ) ? -1 : 0;
for( int i = 0; i < nAssociativity; i++ )
{
pOldValue[i] = pCacheLine[i];
if ( pOldValue[i] )
{
if ( key.IsAcceptable( pOldValue[i]->m_Key ) )
{
return &( pOldValue[i]->m_Data );
}
}
else
{
nOffset = i; // replace empty lines first
}
}
// no acceptable entry. We must generate and replace one. We will use a pseudo-random replacement scheme
if ( ( nAssociativity > 1 ) && ( nOffset == -1 ) )
{
nOffset = ( m_nLineCounter++ ) % nAssociativity;
}
// get a node
CCacheEntry *pNode = GetNode();
pNode->m_Key = key;
pNode->m_Data.CreateCacheData( key, extraCreateData );
// we will look for a place to insert this. It is possible that we will find no good place and will just ditch it.
for( int i = 0; i < nAssociativity; i++ )
{
// try to install it.
if ( ThreadInterlockedAssignPointerIf( ( void * volatile * ) ( pCacheLine + nOffset ), pNode, pOldValue[nOffset] ) )
{
// put the old one on the pending free list
if ( pOldValue[nOffset] )
{
IntrusiveList::AddToHeadByFieldTS( m_pPendingFreeList, pOldValue[nOffset], &CCacheEntry::m_pNextPending );
}
return &( pNode->m_Data ); // success!
}
nOffset++;
if ( nOffset == nAssociativity )
{
nOffset = 0; // wrap around
}
}
// we failed to install this node into the cache. we'll not bother
IntrusiveList::AddToHeadByFieldTS( m_pPendingFreeList, pNode, &CCacheEntry::m_pNextPending );
return &( pNode->m_Data );
}
protected:
int InitialAllocationSize( void )
{
return nNumCacheLines * nAssociativity;
}
CCacheEntry *GetNode( void )
{
CCacheEntry *pNode = IntrusiveList::RemoveHeadTS( m_pFreeList );
if ( ! pNode )
{
pNode = new CCacheEntry;
}
return pNode;
}
CInterlockedUInt m_nLineCounter; // for cycling through cache lines
CCacheEntry *m_pCache[nNumCacheLines * nAssociativity];
CCacheEntry *m_pFreeList; // nodes available for the cache
CCacheEntry *m_pPendingFreeList; // nodes to be moved to the free list at end of frame
CCacheEntry *m_pInitiallyAllocatedNodes;
};

625
public/tier1/utltshash.h Normal file
View File

@@ -0,0 +1,625 @@
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//
// Thread-safe hash class
//===========================================================================//
#ifndef UTLTSHASH_H
#define UTLTSHASH_H
#ifdef _WIN32
#pragma once
#endif
#include <limits.h>
#include "tier0/threadtools.h"
#include "tier1/mempool.h"
#include "generichash.h"
//=============================================================================
//
// Threadsafe Hash
//
// Number of buckets must be a power of 2.
// Key must be intp sized (32-bits on x32, 64-bits on x64)
// Designed for a usage pattern where the data is semi-static, and there
// is a well-defined point where we are guaranteed no queries are occurring.
//
// Insertions are added into a thread-safe list, and when Commit() is called,
// the insertions are moved into a lock-free list
//
// Elements are never individually removed; clears must occur at a time
// where we and guaranteed no queries are occurring
//
typedef intp UtlTSHashHandle_t;
template < class T >
abstract_class ITSHashConstructor
{
public:
virtual void Construct( T* pElement ) = 0;
};
template < class T >
class CDefaultTSHashConstructor : public ITSHashConstructor< T >
{
public:
virtual void Construct( T* pElement )
{
::Construct( pElement );
}
};
template < int BUCKET_COUNT, class KEYTYPE = intp >
class CUtlTSHashGenericHash
{
public:
static int Hash( const KEYTYPE &key, int nBucketMask )
{
int nHash = HashIntConventional( (intp)key );
if ( BUCKET_COUNT <= USHRT_MAX )
{
nHash ^= ( nHash >> 16 );
}
if ( BUCKET_COUNT <= UCHAR_MAX )
{
nHash ^= ( nHash >> 8 );
}
return ( nHash & nBucketMask );
}
static bool Compare( const KEYTYPE &lhs, const KEYTYPE &rhs )
{
return lhs == rhs;
}
};
template < int BUCKET_COUNT, class KEYTYPE >
class CUtlTSHashUseKeyHashMethod
{
public:
static int Hash( const KEYTYPE &key, int nBucketMask )
{
uint32 nHash = key.HashValue();
return ( nHash & nBucketMask );
}
static bool Compare( const KEYTYPE &lhs, const KEYTYPE &rhs )
{
return lhs == rhs;
}
};
template< class T, int BUCKET_COUNT, class KEYTYPE = intp, class HashFuncs = CUtlTSHashGenericHash< BUCKET_COUNT, KEYTYPE >, int nAlignment = 0 >
class CUtlTSHash
{
public:
// Constructor/Deconstructor.
CUtlTSHash( int nAllocationCount );
~CUtlTSHash();
// Invalid handle.
static UtlTSHashHandle_t InvalidHandle( void ) { return ( UtlTSHashHandle_t )0; }
// Retrieval. Super fast, is thread-safe
UtlTSHashHandle_t Find( KEYTYPE uiKey );
// Insertion ( find or add ).
UtlTSHashHandle_t Insert( KEYTYPE uiKey, const T &data, bool *pDidInsert = NULL );
UtlTSHashHandle_t Insert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor, bool *pDidInsert = NULL );
// This insertion method assumes the element is not in the hash table, skips
UtlTSHashHandle_t FastInsert( KEYTYPE uiKey, const T &data );
UtlTSHashHandle_t FastInsert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor );
// Commit recent insertions, making finding them faster.
// Only call when you're certain no threads are accessing the hash table
void Commit( );
// Removal. Only call when you're certain no threads are accessing the hash table
void FindAndRemove( KEYTYPE uiKey );
void Remove( UtlTSHashHandle_t hHash ) { FindAndRemove( GetID( hHash ) ); }
void RemoveAll( void );
void Purge( void );
// Returns the number of elements in the hash table
int Count() const;
// Returns elements in the table
int GetElements( int nFirstElement, int nCount, UtlTSHashHandle_t *pHandles ) const;
// Element access
T &Element( UtlTSHashHandle_t hHash );
T const &Element( UtlTSHashHandle_t hHash ) const;
T &operator[]( UtlTSHashHandle_t hHash );
T const &operator[]( UtlTSHashHandle_t hHash ) const;
KEYTYPE GetID( UtlTSHashHandle_t hHash ) const;
// Convert element * to hashHandle
UtlTSHashHandle_t ElementPtrToHandle( T* pElement ) const;
private:
// Templatized for memory tracking purposes
template < typename Data_t >
struct HashFixedDataInternal_t
{
KEYTYPE m_uiKey;
HashFixedDataInternal_t< Data_t >* m_pNext;
Data_t m_Data;
};
typedef HashFixedDataInternal_t<T> HashFixedData_t;
enum
{
BUCKET_MASK = BUCKET_COUNT - 1
};
struct HashBucket_t
{
HashFixedData_t *m_pFirst;
HashFixedData_t *m_pFirstUncommitted;
CThreadSpinRWLock m_AddLock;
};
UtlTSHashHandle_t Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement );
UtlTSHashHandle_t InsertUncommitted( KEYTYPE uiKey, HashBucket_t &bucket );
CMemoryPoolMT m_EntryMemory;
HashBucket_t m_aBuckets[BUCKET_COUNT];
bool m_bNeedsCommit;
#ifdef _DEBUG
CInterlockedInt m_ContentionCheck;
#endif
};
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::CUtlTSHash( int nAllocationCount ) :
m_EntryMemory( sizeof( HashFixedData_t ), nAllocationCount, CUtlMemoryPool::GROW_SLOW, MEM_ALLOC_CLASSNAME( HashFixedData_t ), nAlignment )
{
#ifdef _DEBUG
m_ContentionCheck = 0;
#endif
m_bNeedsCommit = false;
for ( int i = 0; i < BUCKET_COUNT; i++ )
{
HashBucket_t &bucket = m_aBuckets[ i ];
bucket.m_pFirst = NULL;
bucket.m_pFirstUncommitted = NULL;
}
}
//-----------------------------------------------------------------------------
// Purpose: Deconstructor
//-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::~CUtlTSHash()
{
#ifdef _DEBUG
if ( m_ContentionCheck != 0 )
{
DebuggerBreak();
}
#endif
Purge();
}
//-----------------------------------------------------------------------------
// Purpose: Destroy dynamically allocated hash data.
//-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Purge( void )
{
RemoveAll();
}
//-----------------------------------------------------------------------------
// Returns the number of elements in the hash table
//-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Count() const
{
return m_EntryMemory.Count();
}
//-----------------------------------------------------------------------------
// Returns elements in the table
//-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::GetElements( int nFirstElement, int nCount, UtlTSHashHandle_t *pHandles ) const
{
int nIndex = 0;
for ( int i = 0; i < BUCKET_COUNT; i++ )
{
const HashBucket_t &bucket = m_aBuckets[ i ];
bucket.m_AddLock.LockForRead( );
for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pElement = pElement->m_pNext )
{
if ( --nFirstElement >= 0 )
continue;
pHandles[ nIndex++ ] = (UtlTSHashHandle_t)pElement;
if ( nIndex >= nCount )
{
bucket.m_AddLock.UnlockRead( );
return nIndex;
}
}
bucket.m_AddLock.UnlockRead( );
}
return nIndex;
}
//-----------------------------------------------------------------------------
// Purpose: Insert data into the hash table given its key (KEYTYPE),
// without a check to see if the element already exists within the tree.
//-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::InsertUncommitted( KEYTYPE uiKey, HashBucket_t &bucket )
{
m_bNeedsCommit = true;
HashFixedData_t *pNewElement = static_cast< HashFixedData_t * >( m_EntryMemory.Alloc() );
pNewElement->m_pNext = bucket.m_pFirstUncommitted;
bucket.m_pFirstUncommitted = pNewElement;
pNewElement->m_uiKey = uiKey;
return (UtlTSHashHandle_t)pNewElement;
}
//-----------------------------------------------------------------------------
// Purpose: Insert data into the hash table given its key, with
// a check to see if the element already exists within the tree.
//-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Insert( KEYTYPE uiKey, const T &data, bool *pDidInsert )
{
#ifdef _DEBUG
if ( m_ContentionCheck != 0 )
{
DebuggerBreak();
}
#endif
if ( pDidInsert )
{
*pDidInsert = false;
}
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
HashBucket_t &bucket = m_aBuckets[ iBucket ];
// First try lock-free
UtlTSHashHandle_t h = Find( uiKey );
if ( h != InvalidHandle() )
return h;
// Now, try again, but only look in uncommitted elements
bucket.m_AddLock.LockForWrite( );
h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst );
if ( h == InvalidHandle() )
{
h = InsertUncommitted( uiKey, bucket );
CopyConstruct( &Element(h), data );
if ( pDidInsert )
{
*pDidInsert = true;
}
}
bucket.m_AddLock.UnlockWrite( );
return h;
}
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Insert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor, bool *pDidInsert )
{
#ifdef _DEBUG
if ( m_ContentionCheck != 0 )
{
DebuggerBreak();
}
#endif
if ( pDidInsert )
{
*pDidInsert = false;
}
// First try lock-free
UtlTSHashHandle_t h = Find( uiKey );
if ( h != InvalidHandle() )
return h;
// Now, try again, but only look in uncommitted elements
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
HashBucket_t &bucket = m_aBuckets[ iBucket ];
bucket.m_AddLock.LockForWrite( );
h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst );
if ( h == InvalidHandle() )
{
// Useful if non-trivial work needs to happen to make data; don't want to
// do it and then have to undo it if it turns out we don't need to add it
h = InsertUncommitted( uiKey, bucket );
pConstructor->Construct( &Element(h) );
if ( pDidInsert )
{
*pDidInsert = true;
}
}
bucket.m_AddLock.UnlockWrite( );
return h;
}
//-----------------------------------------------------------------------------
// Purpose: Insert data into the hash table given its key
// without a check to see if the element already exists within the tree.
//-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FastInsert( KEYTYPE uiKey, const T &data )
{
#ifdef _DEBUG
if ( m_ContentionCheck != 0 )
{
DebuggerBreak();
}
#endif
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
HashBucket_t &bucket = m_aBuckets[ iBucket ];
bucket.m_AddLock.LockForWrite( );
UtlTSHashHandle_t h = InsertUncommitted( uiKey, bucket );
CopyConstruct( &Element(h), data );
bucket.m_AddLock.UnlockWrite( );
return h;
}
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FastInsert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor )
{
#ifdef _DEBUG
if ( m_ContentionCheck != 0 )
{
DebuggerBreak();
}
#endif
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
HashBucket_t &bucket = m_aBuckets[ iBucket ];
bucket.m_AddLock.LockForWrite( );
UtlTSHashHandle_t h = InsertUncommitted( uiKey, bucket );
pConstructor->Construct( &Element(h) );
bucket.m_AddLock.UnlockWrite( );
return h;
}
//-----------------------------------------------------------------------------
// Purpose: Commits all uncommitted insertions
//-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Commit( )
{
// FIXME: Is this legal? Want this to be lock-free
if ( !m_bNeedsCommit )
return;
// This must occur when no queries are occurring
#ifdef _DEBUG
m_ContentionCheck++;
#endif
for ( int i = 0; i < BUCKET_COUNT; i++ )
{
HashBucket_t &bucket = m_aBuckets[ i ];
bucket.m_AddLock.LockForRead( );
bucket.m_pFirst = bucket.m_pFirstUncommitted;
bucket.m_AddLock.UnlockRead( );
}
m_bNeedsCommit = false;
#ifdef _DEBUG
m_ContentionCheck--;
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Remove a single element from the hash
//-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FindAndRemove( KEYTYPE uiKey )
{
if ( m_EntryMemory.Count() == 0 )
return;
// This must occur when no queries are occurring
#ifdef _DEBUG
m_ContentionCheck++;
#endif
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
HashBucket_t &bucket = m_aBuckets[ iBucket ];
bucket.m_AddLock.LockForWrite( );
HashFixedData_t *pPrev = NULL;
for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pPrev = pElement, pElement = pElement->m_pNext )
{
if ( !HashFuncs::Compare( pElement->m_uiKey, uiKey ) )
continue;
if ( pPrev )
{
pPrev->m_pNext = pElement->m_pNext;
}
else
{
bucket.m_pFirstUncommitted = pElement->m_pNext;
}
if ( bucket.m_pFirst == pElement )
{
bucket.m_pFirst = bucket.m_pFirst->m_pNext;
}
Destruct( &pElement->m_Data );
#ifdef _DEBUG
memset( pElement, 0xDD, sizeof(HashFixedData_t) );
#endif
m_EntryMemory.Free( pElement );
break;
}
bucket.m_AddLock.UnlockWrite( );
#ifdef _DEBUG
m_ContentionCheck--;
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Remove all elements from the hash
//-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::RemoveAll( void )
{
m_bNeedsCommit = false;
if ( m_EntryMemory.Count() == 0 )
return;
// This must occur when no queries are occurring
#ifdef _DEBUG
m_ContentionCheck++;
#endif
for ( int i = 0; i < BUCKET_COUNT; i++ )
{
HashBucket_t &bucket = m_aBuckets[ i ];
bucket.m_AddLock.LockForWrite( );
for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pElement = pElement->m_pNext )
{
Destruct( &pElement->m_Data );
}
bucket.m_pFirst = NULL;
bucket.m_pFirstUncommitted = NULL;
bucket.m_AddLock.UnlockWrite( );
}
m_EntryMemory.Clear();
#ifdef _DEBUG
m_ContentionCheck--;
#endif
}
//-----------------------------------------------------------------------------
// Finds an element, but only in the committed elements
//-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement )
{
#ifdef _DEBUG
if ( m_ContentionCheck != 0 )
{
DebuggerBreak();
}
#endif
for ( HashFixedData_t *pElement = pFirstElement; pElement != pLastElement; pElement = pElement->m_pNext )
{
if ( HashFuncs::Compare( pElement->m_uiKey, uiKey ) )
return (UtlTSHashHandle_t)pElement;
}
return InvalidHandle();
}
//-----------------------------------------------------------------------------
// Finds an element, but only in the committed elements
//-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Find( KEYTYPE uiKey )
{
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
const HashBucket_t &bucket = m_aBuckets[iBucket];
UtlTSHashHandle_t h = Find( uiKey, bucket.m_pFirst, NULL );
if ( h != InvalidHandle() )
return h;
// Didn't find it in the fast ( committed ) list. Let's try the slow ( uncommitted ) one
bucket.m_AddLock.LockForRead( );
h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst );
bucket.m_AddLock.UnlockRead( );
return h;
}
//-----------------------------------------------------------------------------
// Purpose: Return data given a hash handle.
//-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline T &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Element( UtlTSHashHandle_t hHash )
{
return ((HashFixedData_t *)hHash)->m_Data;
}
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline T const &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Element( UtlTSHashHandle_t hHash ) const
{
return ((HashFixedData_t *)hHash)->m_Data;
}
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline T &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::operator[]( UtlTSHashHandle_t hHash )
{
return ((HashFixedData_t *)hHash)->m_Data;
}
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline T const &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::operator[]( UtlTSHashHandle_t hHash ) const
{
return ((HashFixedData_t *)hHash)->m_Data;
}
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline KEYTYPE CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::GetID( UtlTSHashHandle_t hHash ) const
{
return ((HashFixedData_t *)hHash)->m_uiKey;
}
// Convert element * to hashHandle
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::ElementPtrToHandle( T* pElement ) const
{
Assert( pElement );
HashFixedData_t *pFixedData = (HashFixedData_t*)( (uint8*)pElement - offsetof( HashFixedData_t, m_Data ) );
Assert( m_EntryMemory.IsAllocationWithinPool( pFixedData ) );
return (UtlTSHashHandle_t)pFixedData;
}
#endif // UTLTSHASH_H

1485
public/tier1/utlvector.h Normal file

File diff suppressed because it is too large Load Diff