mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-01-09 18:48:51 +08:00
c0def21c93
Changed/Added classes: CThreadMutex, CUtlMemoryBlockAllocator, CRawAllocator, CUtlHashtable, CUtlVector, CUtlMemory, CUtlMemory_RawAllocator, CUtlSymbolLarge, CUtlSymbolTableLargeBase
388 lines
11 KiB
C++
388 lines
11 KiB
C++
//===== Copyright © 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/generichash.h"
|
|
#include "tier1/utlvector.h"
|
|
#include "tier1/utlhashtable.h"
|
|
#include "tier1/memblockallocator.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 unsigned int UtlSymLargeId_t;
|
|
|
|
#define UTL_INVAL_SYMBOL_LARGE ((UtlSymLargeId_t)~0)
|
|
|
|
class CUtlSymbolLarge
|
|
{
|
|
public:
|
|
// constructor, destructor
|
|
CUtlSymbolLarge()
|
|
{
|
|
m_pString = NULL;
|
|
}
|
|
|
|
CUtlSymbolLarge( const char* pStr )
|
|
{
|
|
m_pString = pStr;
|
|
}
|
|
|
|
CUtlSymbolLarge( CUtlSymbolLarge const& sym )
|
|
{
|
|
m_pString = sym.m_pString;
|
|
}
|
|
|
|
// operator=
|
|
CUtlSymbolLarge& operator=( CUtlSymbolLarge const& src )
|
|
{
|
|
m_pString = src.m_pString;
|
|
return *this;
|
|
}
|
|
|
|
// operator==
|
|
bool operator==( CUtlSymbolLarge const& src ) const
|
|
{
|
|
return m_pString == src.m_pString;
|
|
}
|
|
|
|
// operator!=
|
|
bool operator!=( CUtlSymbolLarge const& src ) const
|
|
{
|
|
return m_pString != src.m_pString;
|
|
}
|
|
|
|
inline const char* String() const
|
|
{
|
|
return m_pString;
|
|
}
|
|
|
|
inline bool IsValid() const
|
|
{
|
|
return m_pString != NULL;
|
|
}
|
|
|
|
private:
|
|
// Disallowed
|
|
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
|
|
|
|
const char* m_pString;
|
|
};
|
|
|
|
inline uint32 CUtlSymbolLarge_Hash( bool CASEINSENSITIVE, const char *pString, int len )
|
|
{
|
|
return ( CASEINSENSITIVE ? MurmurHash2LowerCase( pString, len, 0x31415926 ) : MurmurHash2( pString, len, 0x31415926 ) );
|
|
}
|
|
|
|
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 CUtlSymbolLarge( String() );
|
|
}
|
|
|
|
LargeSymbolTableHashDecoration_t HashValue() const
|
|
{
|
|
return m_Hash;
|
|
}
|
|
};
|
|
|
|
// Base Class for threaded and non-threaded types
|
|
template < class MutexType, bool CASEINSENSITIVE >
|
|
class CUtlSymbolTableLargeBase
|
|
{
|
|
public:
|
|
// constructor, destructor
|
|
CUtlSymbolTableLargeBase( int nGrowSize = 0, int nInitSize = 16, RawAllocatorType_t eAllocatorType = RawAllocator_Standard )
|
|
: m_HashTable( 0, eAllocatorType ),
|
|
m_MemBlocks( nGrowSize, nInitSize, eAllocatorType ),
|
|
m_Mutex( "CUtlSymbolTableLargeBase" ),
|
|
m_MemBlockAllocator( ( nInitSize > 0 ) ? 8 : 0, 2048, eAllocatorType ),
|
|
m_nElementLimit( INT_MAX - 1 ),
|
|
m_bThrowError( true ) { }
|
|
|
|
~CUtlSymbolTableLargeBase() { }
|
|
|
|
// Finds and/or creates a symbol based on the string
|
|
CUtlSymbolLarge AddString( const char* pString );
|
|
CUtlSymbolLarge AddString( const char* pString, int nLength );
|
|
|
|
// Finds the symbol for pString
|
|
CUtlSymbolLarge Find( const char* pString ) const;
|
|
CUtlSymbolLarge Find( const char* pString, int nLength ) const;
|
|
|
|
// Remove all symbols in the table.
|
|
void RemoveAll();
|
|
void Purge();
|
|
|
|
private:
|
|
CUtlSymbolLarge AddString( unsigned int hash, const char* pString, int nLength );
|
|
CUtlSymbolLarge Find( unsigned int hash, const char* pString, int nLength ) const;
|
|
|
|
const char* String( UtlSymLargeId_t id ) const;
|
|
unsigned int HashValue( UtlSymLargeId_t id ) const;
|
|
|
|
struct UtlSymTableLargeAltKey
|
|
{
|
|
CUtlSymbolTableLargeBase* m_pTable;
|
|
const char* m_pString;
|
|
int m_nLength;
|
|
};
|
|
|
|
struct UtlSymTableLargeHashFunctor
|
|
{
|
|
ptrdiff_t m_tableOffset;
|
|
|
|
UtlSymTableLargeHashFunctor()
|
|
{
|
|
m_tableOffset = 1024 - (uintptr_t)(&((Hashtable_t*)1024)->GetHashRef());
|
|
}
|
|
|
|
unsigned int operator()( UtlSymTableLargeAltKey k ) const
|
|
{
|
|
return CUtlSymbolLarge_Hash( CASEINSENSITIVE, k.m_pString, k.m_nLength );
|
|
}
|
|
|
|
unsigned int operator()( UtlSymLargeId_t k ) const
|
|
{
|
|
CUtlSymbolTableLargeBase* pTable = (CUtlSymbolTableLargeBase*)((uintptr_t)this + m_tableOffset);
|
|
|
|
pTable->HashValue( k );
|
|
}
|
|
};
|
|
|
|
struct UtlSymTableLargeEqualFunctor
|
|
{
|
|
ptrdiff_t m_tableOffset;
|
|
|
|
UtlSymTableLargeEqualFunctor()
|
|
{
|
|
m_tableOffset = 1024 - (uintptr_t)(&((Hashtable_t*)1024)->GetEqualRef());
|
|
}
|
|
|
|
bool operator()( UtlSymLargeId_t a, UtlSymLargeId_t b ) const
|
|
{
|
|
CUtlSymbolTableLargeBase* pTable = (CUtlSymbolTableLargeBase*)((uintptr_t)this + m_tableOffset);
|
|
|
|
if ( !CASEINSENSITIVE )
|
|
return strcmp( pTable->String( a ), pTable->String( b ) ) == 0;
|
|
else
|
|
return V_stricmp_fast( pTable->String( a ), pTable->String( b ) ) == 0;
|
|
}
|
|
|
|
bool operator()( UtlSymTableLargeAltKey a, UtlSymLargeId_t b ) const
|
|
{
|
|
const char* pString = a.m_pTable->String( b );
|
|
|
|
if ( a.m_nLength != strlen( pString ) )
|
|
return false;
|
|
|
|
if ( !CASEINSENSITIVE )
|
|
return strncmp( a.m_pString, pString, a.m_nLength ) == 0;
|
|
else
|
|
return _V_strnicmp_fast( a.m_pString, pString, a.m_nLength ) == 0;
|
|
}
|
|
|
|
bool operator()( UtlSymLargeId_t a, UtlSymTableLargeAltKey b ) const
|
|
{
|
|
return operator()( b, a );
|
|
}
|
|
};
|
|
|
|
typedef CUtlHashtable<UtlSymLargeId_t, empty_t, UtlSymTableLargeHashFunctor, UtlSymTableLargeEqualFunctor, UtlSymTableLargeAltKey, CUtlMemory_RawAllocator<CUtlHashtableEntry<UtlSymLargeId_t, empty_t>>> Hashtable_t;
|
|
typedef CUtlVector< MemBlockHandle_t, CUtlMemory_RawAllocator<MemBlockHandle_t> > MemBlocksVec_t;
|
|
|
|
Hashtable_t m_HashTable;
|
|
MemBlocksVec_t m_MemBlocks;
|
|
MutexType m_Mutex;
|
|
CUtlMemoryBlockAllocator m_MemBlockAllocator;
|
|
int m_nElementLimit;
|
|
bool m_bThrowError;
|
|
};
|
|
|
|
template < class MutexType, bool CASEINSENSITIVE >
|
|
inline CUtlSymbolLarge CUtlSymbolTableLargeBase< MutexType, CASEINSENSITIVE >::Find( unsigned int hash, const char* pString, int nLength ) const
|
|
{
|
|
UtlSymTableLargeAltKey key;
|
|
|
|
key.m_pTable = ( CUtlSymbolTableLargeBase* )this;
|
|
key.m_pString = pString;
|
|
key.m_nLength = nLength;
|
|
|
|
UtlHashHandle_t h = m_HashTable.Find( key, hash );
|
|
|
|
if ( h == m_HashTable.InvalidHandle() )
|
|
return CUtlSymbolLarge();
|
|
|
|
return CUtlSymbolLarge( String( m_HashTable[ h ] ) );
|
|
}
|
|
|
|
template < class MutexType, bool CASEINSENSITIVE >
|
|
inline CUtlSymbolLarge CUtlSymbolTableLargeBase< MutexType, CASEINSENSITIVE >::AddString( unsigned int hash, const char* pString, int nLength )
|
|
{
|
|
if ( m_MemBlocks.Count() >= m_nElementLimit )
|
|
{
|
|
if ( m_bThrowError )
|
|
{
|
|
Plat_FatalErrorFunc( "FATAL ERROR: CUtlSymbolTableLarge element limit of %u exceeded\n", m_nElementLimit );
|
|
DebuggerBreak();
|
|
}
|
|
|
|
Warning( "ERROR: CUtlSymbolTableLarge element limit of %u exceeded\n", m_nElementLimit );
|
|
}
|
|
|
|
MemBlockHandle_t block = m_MemBlockAllocator.Alloc( nLength + sizeof( LargeSymbolTableHashDecoration_t ) + 1 );
|
|
|
|
CUtlSymbolTableLargeBaseTreeEntry_t *entry = (CUtlSymbolTableLargeBaseTreeEntry_t *)m_MemBlockAllocator.GetBlock( block );
|
|
|
|
entry->m_Hash = hash;
|
|
char *pText = (char *)&entry->m_String[ 0 ];
|
|
memcpy( pText, pString, nLength );
|
|
pText[ nLength ] = '\0';
|
|
|
|
UtlSymLargeId_t id = m_MemBlocks.AddToTail( block + sizeof( LargeSymbolTableHashDecoration_t ) );
|
|
|
|
empty_t empty;
|
|
m_HashTable.Insert( id, empty, hash );
|
|
|
|
return entry->ToSymbol();
|
|
}
|
|
|
|
template < class MutexType, bool CASEINSENSITIVE >
|
|
inline const char* CUtlSymbolTableLargeBase< MutexType, CASEINSENSITIVE >::String( UtlSymLargeId_t id ) const
|
|
{
|
|
return ( const char* )m_MemBlockAllocator.GetBlock( m_MemBlocks[ id ] );
|
|
}
|
|
|
|
template < class MutexType, bool CASEINSENSITIVE >
|
|
inline unsigned int CUtlSymbolTableLargeBase< MutexType, CASEINSENSITIVE >::HashValue( UtlSymLargeId_t id ) const
|
|
{
|
|
CUtlSymbolTableLargeBaseTreeEntry_t *entry = (CUtlSymbolTableLargeBaseTreeEntry_t *)m_MemBlockAllocator.GetBlock( m_MemBlocks[ id ] - sizeof( LargeSymbolTableHashDecoration_t ) );
|
|
|
|
return entry->HashValue();
|
|
}
|
|
|
|
template < class MutexType, bool CASEINSENSITIVE >
|
|
inline CUtlSymbolLarge CUtlSymbolTableLargeBase< MutexType, CASEINSENSITIVE >::Find( const char* pString, int nLength ) const
|
|
{
|
|
CUtlSymbolLarge sym;
|
|
|
|
if ( pString && nLength > 0 && *pString )
|
|
{
|
|
unsigned int hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, nLength );
|
|
|
|
m_Mutex.Lock( __FILE__, __LINE__ );
|
|
|
|
sym = Find( hash, pString, nLength );
|
|
|
|
m_Mutex.Unlock( __FILE__, __LINE__ );
|
|
}
|
|
|
|
return sym;
|
|
}
|
|
|
|
template < class MutexType, bool CASEINSENSITIVE >
|
|
inline CUtlSymbolLarge CUtlSymbolTableLargeBase< MutexType, CASEINSENSITIVE >::Find( const char* pString ) const
|
|
{
|
|
return Find( pString, pString ? strlen( pString ) : 0 );
|
|
}
|
|
|
|
template < class MutexType, bool CASEINSENSITIVE >
|
|
inline CUtlSymbolLarge CUtlSymbolTableLargeBase< MutexType, CASEINSENSITIVE >::AddString( const char* pString, int nLength )
|
|
{
|
|
CUtlSymbolLarge sym;
|
|
|
|
if ( pString && nLength > 0 && *pString )
|
|
{
|
|
unsigned int hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, nLength );
|
|
|
|
m_Mutex.Lock( __FILE__, __LINE__ );
|
|
|
|
sym = Find( hash, pString, nLength );
|
|
|
|
if ( !sym.IsValid() )
|
|
sym = AddString( hash, pString, nLength );
|
|
|
|
m_Mutex.Unlock( __FILE__, __LINE__ );
|
|
}
|
|
|
|
return sym;
|
|
}
|
|
|
|
template < class MutexType, bool CASEINSENSITIVE >
|
|
inline CUtlSymbolLarge CUtlSymbolTableLargeBase< MutexType, CASEINSENSITIVE >::AddString( const char* pString )
|
|
{
|
|
return AddString( pString, pString ? strlen( pString ) : 0 );
|
|
}
|
|
|
|
template < class MutexType, bool CASEINSENSITIVE >
|
|
inline void CUtlSymbolTableLargeBase< MutexType, CASEINSENSITIVE >::RemoveAll()
|
|
{
|
|
m_Mutex.Lock( __FILE__, __LINE__ );
|
|
|
|
m_MemBlocks.RemoveAll();
|
|
m_HashTable.RemoveAll();
|
|
m_MemBlockAllocator.RemoveAll();
|
|
|
|
m_Mutex.Unlock( __FILE__, __LINE__ );
|
|
}
|
|
|
|
template < class MutexType, bool CASEINSENSITIVE >
|
|
inline void CUtlSymbolTableLargeBase< MutexType, CASEINSENSITIVE >::Purge()
|
|
{
|
|
m_Mutex.Lock( __FILE__, __LINE__ );
|
|
|
|
m_MemBlocks.Purge();
|
|
m_HashTable.Purge();
|
|
m_MemBlockAllocator.Purge();
|
|
|
|
m_Mutex.Unlock( __FILE__, __LINE__ );
|
|
}
|
|
|
|
// Case-sensitive
|
|
typedef CUtlSymbolTableLargeBase< CThreadEmptyMutex, false > CUtlSymbolTableLarge;
|
|
// Case-insensitive
|
|
typedef CUtlSymbolTableLargeBase< CThreadEmptyMutex, true > CUtlSymbolTableLarge_CI;
|
|
// Multi-threaded case-sensitive
|
|
typedef CUtlSymbolTableLargeBase< CThreadMutex, false > CUtlSymbolTableLargeMT;
|
|
// Multi-threaded case-insensitive
|
|
typedef CUtlSymbolTableLargeBase< CThreadMutex, true > CUtlSymbolTableLargeMT_CI;
|
|
|
|
#endif // UTLSYMBOLLARGE_H
|