mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Tier1: fully implement CUtlSymbol(*)
The class has been modified to match the implementation of the engine, the only modifications done were changing size types, so they compile to the correct size based on the platform (in case of the GameSDK project, this will be 64 bits).
This commit is contained in:
parent
615598c1b9
commit
582ec3791e
@ -248,7 +248,7 @@ inline T CCountedStringPoolBase<T>::ReferenceStringHandle( const char* pIntrinsi
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int newElement = m_Elements.AddToTail();
|
||||
T newElement = (T)m_Elements.AddToTail();
|
||||
VerifyNotOverflowed( newElement );
|
||||
nCurrentBucket = newElement;
|
||||
}
|
||||
@ -260,7 +260,7 @@ inline T CCountedStringPoolBase<T>::ReferenceStringHandle( const char* pIntrinsi
|
||||
m_HashTable[ nHashBucketIndex ] = nCurrentBucket;
|
||||
|
||||
m_Elements[nCurrentBucket].pString = new char[Q_strlen( pIntrinsic ) + 1];
|
||||
Q_strcpy( m_Elements[nCurrentBucket].pString, pIntrinsic );
|
||||
strcpy( m_Elements[nCurrentBucket].pString, pIntrinsic );
|
||||
|
||||
return nCurrentBucket;
|
||||
}
|
||||
@ -342,9 +342,10 @@ inline void CCountedStringPoolBase<T>::SpewStrings()
|
||||
int i;
|
||||
for ( i = 0; i < m_Elements.Count(); i++ )
|
||||
{
|
||||
char* string = m_Elements[i].pString;
|
||||
char* pString = m_Elements[i].pString;
|
||||
NOTE_UNUSED(pString);
|
||||
|
||||
DevMsg("String %d: ref:%hhu %s\n", i, m_Elements[i].nReferenceCount, string == NULL? "EMPTY - ok for slot zero only!" : string);
|
||||
DevMsg("String %d: ref:%hhu %s\n", i, m_Elements[i].nReferenceCount, pString == NULL? "EMPTY - ok for slot zero only!" : pString);
|
||||
}
|
||||
|
||||
DevMsg("\n%d total counted strings.", m_Elements.Count());
|
||||
|
@ -158,11 +158,12 @@ void V_ComposeFileName(const char* path, const char* filename, char* dest, size_
|
||||
// Remove any extension from in and return resulting string in out
|
||||
void V_StripExtension(const char* in, char* out, size_t outLen);
|
||||
|
||||
// Copy out the file extension into dest
|
||||
void V_ExtractFileExtension(const char* path, char* dest, size_t destSize);
|
||||
|
||||
// Returns a pointer to the file extension or NULL if one doesn't exist
|
||||
const char* V_GetFileExtension(const char* path, const bool keepDot = false);
|
||||
|
||||
// Copy out the file extension into dest
|
||||
void V_ExtractFileExtension(const char* path, char* dest, size_t destSize);
|
||||
bool V_ExtractFilePath(const char* path, char* dest, size_t destSize);
|
||||
|
||||
// Extracts the base name of a file (no path, no extension, assumes '/' or '\' as path separator)
|
||||
void V_FileBase(const char* in, OUT_Z_CAP(maxlen) char* out, size_t maxlen);
|
||||
|
@ -104,7 +104,7 @@ class CUtlSymbolTable
|
||||
{
|
||||
public:
|
||||
// constructor, destructor
|
||||
CUtlSymbolTable( int growSize = 0, int initSize = 16, bool caseInsensitive = false );
|
||||
CUtlSymbolTable( ssize_t growSize = 0, ssize_t initSize = 16, bool caseInsensitive = false );
|
||||
~CUtlSymbolTable();
|
||||
|
||||
// Finds and/or creates a symbol based on the string
|
||||
@ -159,21 +159,21 @@ protected:
|
||||
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;
|
||||
int 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 ) {}
|
||||
CTree( ssize_t growSize, ssize_t 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;
|
||||
size_t m_TotalLen; // How large is
|
||||
size_t m_SpaceUsed;
|
||||
char m_Data[1];
|
||||
};
|
||||
|
||||
@ -187,7 +187,7 @@ protected:
|
||||
CUtlVector<StringPool_t*> m_StringPools;
|
||||
|
||||
private:
|
||||
int FindPoolWithSpace( int len ) const;
|
||||
int FindPoolWithSpace( size_t len ) const;
|
||||
const char* StringFromIndex( const CStringPoolIndex &index ) const;
|
||||
const char* DecoratedStringFromIndex( const CStringPoolIndex &index ) const;
|
||||
|
||||
@ -196,62 +196,60 @@ private:
|
||||
|
||||
};
|
||||
|
||||
// TODO[ AMOS ]: implement CThreadSpinRWLock
|
||||
class CUtlSymbolTableMT : public CUtlSymbolTable
|
||||
{
|
||||
public:
|
||||
CUtlSymbolTableMT( ssize_t growSize = 0, ssize_t initSize = 32, bool caseInsensitive = false )
|
||||
: CUtlSymbolTable( growSize, initSize, caseInsensitive )
|
||||
{
|
||||
}
|
||||
|
||||
//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
|
||||
//};
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -270,71 +268,68 @@ 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;
|
||||
|
||||
// TODO[ AMOS ]: implement CThreadSpinRWLock
|
||||
#ifdef PLATFORM_64BITS
|
||||
pad = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
//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;
|
||||
//};
|
||||
// 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
|
||||
|
@ -1240,21 +1240,6 @@ void V_StripExtension(const char* in, char* out, size_t outSize)
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *path -
|
||||
// *dest -
|
||||
// destSize -
|
||||
// Output : void V_ExtractFileExtension
|
||||
//-----------------------------------------------------------------------------
|
||||
void V_ExtractFileExtension(const char* path, char* dest, size_t destSize)
|
||||
{
|
||||
*dest = 0;
|
||||
const char* extension = V_GetFileExtension(path);
|
||||
if (NULL != extension)
|
||||
V_strncpy(dest, extension, destSize);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns a pointer to the file extension within a file name string
|
||||
// Input: in - file name
|
||||
@ -1288,6 +1273,52 @@ const char* V_GetFileExtension(const char* path, const bool keepDot)
|
||||
return out ? out : path;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *path -
|
||||
// *dest -
|
||||
// destSize -
|
||||
// Output : void V_ExtractFileExtension
|
||||
//-----------------------------------------------------------------------------
|
||||
void V_ExtractFileExtension(const char* path, char* dest, size_t destSize)
|
||||
{
|
||||
*dest = 0;
|
||||
const char* extension = V_GetFileExtension(path);
|
||||
if (NULL != extension)
|
||||
V_strncpy(dest, extension, destSize);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *path -
|
||||
// *dest -
|
||||
// destSize -
|
||||
// Output : void V_ExtractFilePath
|
||||
//-----------------------------------------------------------------------------
|
||||
bool V_ExtractFilePath(const char* path, char* dest, size_t destSize)
|
||||
{
|
||||
Assert(destSize >= 1);
|
||||
if (destSize < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Last char
|
||||
const size_t len = V_strlen(path);
|
||||
const char* src = path + (len ? len - 1 : 0);
|
||||
|
||||
// back up until a \ or the start
|
||||
while (src != path && !PATHSEPARATOR(*(src - 1)))
|
||||
{
|
||||
src--;
|
||||
}
|
||||
|
||||
const ssize_t copysize = Min(size_t(src - path), destSize - 1);
|
||||
memcpy(dest, path, copysize);
|
||||
dest[copysize] = 0;
|
||||
|
||||
return copysize != 0 ? true : false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Extracts the base name of a file (no path, no extension, assumes '/' or '\' as path separator)
|
||||
|
528
r5dev/tier1/utlsymbol.cpp
Normal file
528
r5dev/tier1/utlsymbol.cpp
Normal file
@ -0,0 +1,528 @@
|
||||
//====== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. =======//
|
||||
//
|
||||
// Purpose: Defines a symbol table
|
||||
//
|
||||
// $Header: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#pragma warning (disable:4514)
|
||||
|
||||
#include "tier1/utlsymbol.h"
|
||||
#include "tier0/threadtools.h"
|
||||
//#include "stringpool.h"
|
||||
//#include "generichash.h"
|
||||
//#include "tier0/vprof.h"
|
||||
#include <stddef.h>
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define INVALID_STRING_INDEX CStringPoolIndex( 0xFFFF, 0xFFFF )
|
||||
|
||||
#define MIN_STRING_POOL_SIZE 2048
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// globals
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CUtlSymbolTableMT* CUtlSymbol::s_pSymbolTable = 0;
|
||||
bool CUtlSymbol::s_bAllowStaticSymbolTable = true;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// symbol methods
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CUtlSymbol::Initialize()
|
||||
{
|
||||
// If this assert fails, then the module that this call is in has chosen to disallow
|
||||
// use of the static symbol table. Usually, it's to prevent confusion because it's easy
|
||||
// to accidentally use the global symbol table when you really want to use a specific one.
|
||||
Assert( s_bAllowStaticSymbolTable );
|
||||
|
||||
// necessary to allow us to create global symbols
|
||||
static bool symbolsInitialized = false;
|
||||
if (!symbolsInitialized)
|
||||
{
|
||||
s_pSymbolTable = new CUtlSymbolTableMT;
|
||||
symbolsInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CUtlSymbol::LockTableForRead()
|
||||
{
|
||||
Initialize();
|
||||
s_pSymbolTable->LockForRead();
|
||||
}
|
||||
|
||||
void CUtlSymbol::UnlockTableForRead()
|
||||
{
|
||||
s_pSymbolTable->UnlockForRead();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Singleton to delete table on exit from module
|
||||
//-----------------------------------------------------------------------------
|
||||
class CCleanupUtlSymbolTable
|
||||
{
|
||||
public:
|
||||
~CCleanupUtlSymbolTable()
|
||||
{
|
||||
delete CUtlSymbol::s_pSymbolTable;
|
||||
CUtlSymbol::s_pSymbolTable = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
static CCleanupUtlSymbolTable g_CleanupSymbolTable;
|
||||
|
||||
CUtlSymbolTableMT* CUtlSymbol::CurrTable()
|
||||
{
|
||||
Initialize();
|
||||
return s_pSymbolTable;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// string->symbol->string
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CUtlSymbol::CUtlSymbol( const char* pStr )
|
||||
{
|
||||
m_Id = CurrTable()->AddString( pStr );
|
||||
}
|
||||
|
||||
const char* CUtlSymbol::String( ) const
|
||||
{
|
||||
return CurrTable()->String(m_Id);
|
||||
}
|
||||
|
||||
const char* CUtlSymbol::StringNoLock( ) const
|
||||
{
|
||||
return CurrTable()->StringNoLock(m_Id);
|
||||
}
|
||||
|
||||
void CUtlSymbol::DisableStaticSymbolTable()
|
||||
{
|
||||
s_bAllowStaticSymbolTable = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// checks if the symbol matches a string
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool CUtlSymbol::operator==( const char* pStr ) const
|
||||
{
|
||||
if (m_Id == UTL_INVAL_SYMBOL)
|
||||
return false;
|
||||
return strcmp( String(), pStr ) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// symbol table stuff
|
||||
//-----------------------------------------------------------------------------
|
||||
inline const char* CUtlSymbolTable::DecoratedStringFromIndex( const CStringPoolIndex &index ) const
|
||||
{
|
||||
Assert( index.m_iPool < m_StringPools.Count() );
|
||||
Assert( index.m_iOffset < m_StringPools[index.m_iPool]->m_TotalLen );
|
||||
|
||||
// step over the hash decorating the beginning of the string
|
||||
return (&m_StringPools[index.m_iPool]->m_Data[index.m_iOffset]);
|
||||
}
|
||||
|
||||
inline const char* CUtlSymbolTable::StringFromIndex( const CStringPoolIndex &index ) const
|
||||
{
|
||||
// step over the hash decorating the beginning of the string
|
||||
return DecoratedStringFromIndex(index)+sizeof(hashDecoration_t);
|
||||
}
|
||||
|
||||
// The first two bytes of each string in the pool are actually the hash for that string.
|
||||
// Thus we compare hashes rather than entire strings for a significant perf benefit.
|
||||
// However since there is a high rate of hash collision we must still compare strings
|
||||
// if the hashes match.
|
||||
int CUtlSymbolTable::CLess::operator()( const CStringPoolIndex &i1, const CStringPoolIndex &i2 ) const
|
||||
{
|
||||
// Need to do pointer math because CUtlSymbolTable is used in CUtlVectors, and hence
|
||||
// can be arbitrarily moved in memory on a realloc. Yes, this is portable. In reality,
|
||||
// right now at least, because m_LessFunc is the first member of CUtlRBTree, and m_Lookup
|
||||
// is the first member of CUtlSymbolTabke, this == pTable
|
||||
CUtlSymbolTable *pTable = (CUtlSymbolTable *)( (byte *)this - offsetof(CUtlSymbolTable::CTree, m_LessFunc) ) - offsetof(CUtlSymbolTable, m_Lookup );
|
||||
|
||||
#if 1 // using the hashes
|
||||
const char *str1, *str2;
|
||||
hashDecoration_t hash1, hash2;
|
||||
|
||||
if (i1 == INVALID_STRING_INDEX)
|
||||
{
|
||||
str1 = pTable->m_pUserSearchString;
|
||||
hash1 = pTable->m_nUserSearchStringHash;
|
||||
}
|
||||
else
|
||||
{
|
||||
str1 = pTable->DecoratedStringFromIndex( i1 );
|
||||
hashDecoration_t storedHash = *reinterpret_cast<const hashDecoration_t *>(str1);
|
||||
str1 += sizeof(hashDecoration_t);
|
||||
AssertMsg( storedHash == ( !pTable->m_bInsensitive ? HashString(str1) : HashStringCaseless(str1) ),
|
||||
"The stored hash (%d) for symbol %s is not correct.", storedHash, str1 );
|
||||
hash1 = storedHash;
|
||||
}
|
||||
|
||||
if (i2 == INVALID_STRING_INDEX)
|
||||
{
|
||||
str2 = pTable->m_pUserSearchString;
|
||||
hash2 = pTable->m_nUserSearchStringHash;
|
||||
}
|
||||
else
|
||||
{
|
||||
str2 = pTable->DecoratedStringFromIndex( i2 );
|
||||
hashDecoration_t storedHash = *reinterpret_cast<const hashDecoration_t *>(str2);
|
||||
str2 += sizeof(hashDecoration_t);
|
||||
AssertMsg( storedHash == ( !pTable->m_bInsensitive ? HashString(str2) : HashStringCaseless(str2) ),
|
||||
"The stored hash (%d) for symbol '%s' is not correct.", storedHash, str2 );
|
||||
hash2 = storedHash;
|
||||
}
|
||||
|
||||
// compare the hashes
|
||||
if ( hash1 == hash2 )
|
||||
{
|
||||
if ( !str1 && str2 )
|
||||
return 1;
|
||||
if ( !str2 && str1 )
|
||||
return -1;
|
||||
if ( !str1 && !str2 )
|
||||
return 0;
|
||||
|
||||
// if the hashes match compare the strings
|
||||
if ( !pTable->m_bInsensitive )
|
||||
return strcmp( str1, str2 ) < 0;
|
||||
else
|
||||
return V_stricmp( str1, str2 ) < 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return hash1 < hash2;
|
||||
}
|
||||
|
||||
#else // not using the hashes, just comparing strings
|
||||
const char* str1 = (i1 == INVALID_STRING_INDEX) ? pTable->m_pUserSearchString :
|
||||
pTable->StringFromIndex( i1 );
|
||||
const char* str2 = (i2 == INVALID_STRING_INDEX) ? pTable->m_pUserSearchString :
|
||||
pTable->StringFromIndex( i2 );
|
||||
|
||||
if ( !str1 && str2 )
|
||||
return 1;
|
||||
if ( !str2 && str1 )
|
||||
return -1;
|
||||
if ( !str1 && !str2 )
|
||||
return 0;
|
||||
if ( !pTable->m_bInsensitive )
|
||||
return strcmp( str1, str2 ) < 0;
|
||||
else
|
||||
return strcmpi( str1, str2 ) < 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// constructor, destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CUtlSymbolTable::CUtlSymbolTable( ssize_t growSize, ssize_t initSize, bool caseInsensitive ) :
|
||||
m_Lookup( growSize, initSize ), m_bInsensitive( caseInsensitive ), m_StringPools( 8 ),
|
||||
m_nUserSearchStringHash( 0 ), m_pUserSearchString( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
CUtlSymbolTable::~CUtlSymbolTable()
|
||||
{
|
||||
// Release the stringpool string data
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
CUtlSymbol CUtlSymbolTable::Find( const char* pString ) const
|
||||
{
|
||||
//VPROF( "CUtlSymbol::Find" );
|
||||
if (!pString)
|
||||
return CUtlSymbol();
|
||||
|
||||
// Store a special context used to help with insertion
|
||||
m_pUserSearchString = pString;
|
||||
m_nUserSearchStringHash = m_bInsensitive
|
||||
? ( unsigned short )HashStringCaseless( pString )
|
||||
: ( unsigned short )HashString( pString );
|
||||
|
||||
// Passing this special invalid symbol makes the comparison function
|
||||
// use the string passed in the context
|
||||
UtlSymId_t idx = m_Lookup.Find( INVALID_STRING_INDEX );
|
||||
|
||||
#ifdef _DEBUG
|
||||
m_pUserSearchString = NULL;
|
||||
m_nUserSearchStringHash = 0;
|
||||
#endif
|
||||
|
||||
return CUtlSymbol( idx );
|
||||
}
|
||||
|
||||
|
||||
int CUtlSymbolTable::FindPoolWithSpace( size_t 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
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CUtlSymbol CUtlSymbolTable::AddString( const char* pString )
|
||||
{
|
||||
//VPROF("CUtlSymbol::AddString");
|
||||
if (!pString)
|
||||
return CUtlSymbol( UTL_INVAL_SYMBOL );
|
||||
|
||||
CUtlSymbol id = Find( pString );
|
||||
|
||||
if (id.IsValid())
|
||||
return id;
|
||||
|
||||
size_t lenString = strlen(pString) + 1; // length of just the string
|
||||
size_t lenDecorated = lenString + sizeof(hashDecoration_t); // and with its hash decoration
|
||||
// make sure that all strings are aligned on 2-byte boundaries so the hashes will read correctly
|
||||
COMPILE_TIME_ASSERT(sizeof(hashDecoration_t) == 2);
|
||||
lenDecorated = (lenDecorated + 1) & (~0x01); // round up to nearest multiple of 2
|
||||
|
||||
// Find a pool with space for this string, or allocate a new one.
|
||||
int iPool = FindPoolWithSpace( lenDecorated );
|
||||
if ( iPool == -1 )
|
||||
{
|
||||
// Add a new pool.
|
||||
size_t newPoolSize = MAX( lenDecorated + sizeof( StringPool_t ), MIN_STRING_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
|
||||
hashDecoration_t hash = m_bInsensitive
|
||||
? ( unsigned short )HashStringCaseless( pString )
|
||||
: ( unsigned short )HashString( pString );
|
||||
|
||||
// Copy the string in.
|
||||
StringPool_t *pPool = m_StringPools[iPool];
|
||||
Assert( pPool->m_SpaceUsed < 0xFFFF ); // This should never happen, because if we had a string > 64k, it
|
||||
// would have been given its entire own pool.
|
||||
|
||||
unsigned short iStringOffset = ( unsigned short )pPool->m_SpaceUsed;
|
||||
const char *startingAddr = &pPool->m_Data[pPool->m_SpaceUsed];
|
||||
|
||||
// store the hash at the head of the string
|
||||
*((hashDecoration_t *)(startingAddr)) = hash;
|
||||
// and then the string's data
|
||||
memcpy( (void *)(startingAddr + sizeof(hashDecoration_t)), pString, lenString );
|
||||
pPool->m_SpaceUsed += lenDecorated;
|
||||
|
||||
// insert the string into the vector.
|
||||
CStringPoolIndex index;
|
||||
index.m_iPool = ( unsigned short )iPool;
|
||||
index.m_iOffset = ( unsigned short )iStringOffset;
|
||||
|
||||
MEM_ALLOC_CREDIT();
|
||||
UtlSymId_t idx = m_Lookup.Insert( index );
|
||||
return CUtlSymbol( idx );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Look up the string associated with a particular symbol
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const char* CUtlSymbolTable::String( CUtlSymbol id ) const
|
||||
{
|
||||
if (!id.IsValid())
|
||||
return "";
|
||||
|
||||
Assert( m_Lookup.IsValidIndex((UtlSymId_t)id) );
|
||||
return StringFromIndex( m_Lookup[id] );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Remove all symbols in the table.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CUtlSymbolTable::RemoveAll()
|
||||
{
|
||||
m_Lookup.Purge();
|
||||
|
||||
for ( int i=0; i < m_StringPools.Count(); i++ )
|
||||
free( m_StringPools[i] );
|
||||
|
||||
m_StringPools.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pFileName -
|
||||
// Output : FileNameHandle_t
|
||||
//-----------------------------------------------------------------------------
|
||||
FileNameHandle_t CUtlFilenameSymbolTable::FindOrAddFileName( const char *pFileName )
|
||||
{
|
||||
if ( !pFileName )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// find first
|
||||
FileNameHandle_t hFileName = FindFileName( pFileName );
|
||||
if ( hFileName )
|
||||
{
|
||||
return hFileName;
|
||||
}
|
||||
|
||||
// Fix slashes+dotslashes and make lower case first..
|
||||
char fn[ MAX_PATH ];
|
||||
Q_strncpy( fn, pFileName, sizeof( fn ) );
|
||||
V_RemoveDotSlashes( fn );
|
||||
#ifdef _WIN32
|
||||
strlwr( fn );
|
||||
#endif
|
||||
|
||||
// Split the filename into constituent parts
|
||||
char basepath[ MAX_PATH ];
|
||||
V_ExtractFilePath( fn, basepath, sizeof( basepath ) );
|
||||
char filename[ MAX_PATH ];
|
||||
Q_strncpy( filename, fn + Q_strlen( basepath ), sizeof( filename ) );
|
||||
|
||||
// not found, lock and look again
|
||||
FileNameHandleInternal_t handle;
|
||||
m_lock.LockForWrite();
|
||||
handle.SetPath( m_PathStringPool.FindStringHandle( basepath ) );
|
||||
handle.SetFile( m_FileStringPool.FindStringHandle( filename ) );
|
||||
if ( handle.GetPath() && handle.GetFile() )
|
||||
{
|
||||
// found
|
||||
m_lock.UnlockWrite();
|
||||
return *( FileNameHandle_t * )( &handle );
|
||||
}
|
||||
|
||||
// safely add it
|
||||
handle.SetPath( m_PathStringPool.ReferenceStringHandle( basepath ) );
|
||||
handle.SetFile( m_FileStringPool.ReferenceStringHandle( filename ) );
|
||||
m_lock.UnlockWrite();
|
||||
|
||||
return *( FileNameHandle_t * )( &handle );
|
||||
}
|
||||
|
||||
FileNameHandle_t CUtlFilenameSymbolTable::FindFileName( const char *pFileName )
|
||||
{
|
||||
if ( !pFileName )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Fix slashes+dotslashes and make lower case first..
|
||||
char fn[ MAX_PATH ];
|
||||
Q_strncpy( fn, pFileName, sizeof( fn ) );
|
||||
V_RemoveDotSlashes( fn );
|
||||
#ifdef _WIN32
|
||||
strlwr( fn );
|
||||
#endif
|
||||
|
||||
// Split the filename into constituent parts
|
||||
char basepath[ MAX_PATH ];
|
||||
V_ExtractFilePath( fn, basepath, sizeof( basepath ) );
|
||||
char filename[ MAX_PATH ];
|
||||
Q_strncpy( filename, fn + Q_strlen( basepath ), sizeof( filename ) );
|
||||
|
||||
FileNameHandleInternal_t handle;
|
||||
|
||||
m_lock.LockForRead();
|
||||
handle.SetPath( m_PathStringPool.FindStringHandle( basepath ) );
|
||||
handle.SetFile( m_FileStringPool.FindStringHandle( filename ) );
|
||||
m_lock.UnlockRead();
|
||||
|
||||
|
||||
if ( ( handle.GetPath() == 0 ) || ( handle.GetFile() == 0 ) )
|
||||
return NULL;
|
||||
|
||||
return *( FileNameHandle_t * )( &handle );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : handle -
|
||||
// Output : const char
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CUtlFilenameSymbolTable::String( const FileNameHandle_t& handle, char *buf, int buflen )
|
||||
{
|
||||
buf[ 0 ] = 0;
|
||||
|
||||
FileNameHandleInternal_t *internalFileHandle = ( FileNameHandleInternal_t * )&handle;
|
||||
if ( !internalFileHandle )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lock.LockForRead();
|
||||
const char *path = m_PathStringPool.HandleToString( (unsigned short)internalFileHandle->GetPath() );
|
||||
const char *fn = m_FileStringPool.HandleToString( (unsigned short)internalFileHandle->GetFile() );
|
||||
m_lock.UnlockRead();
|
||||
|
||||
if ( !path || !fn )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Q_strncpy( buf, path, buflen );
|
||||
Q_strncat( buf, fn, buflen );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CUtlFilenameSymbolTable::RemoveAll()
|
||||
{
|
||||
m_PathStringPool.FreeAll();
|
||||
m_FileStringPool.FreeAll();
|
||||
}
|
||||
|
||||
void CUtlFilenameSymbolTable::SpewStrings()
|
||||
{
|
||||
m_lock.LockForRead();
|
||||
m_PathStringPool.SpewStrings();
|
||||
m_FileStringPool.SpewStrings();
|
||||
m_lock.UnlockRead();
|
||||
}
|
||||
|
||||
bool CUtlFilenameSymbolTable::SaveToBuffer( CUtlBuffer &buffer )
|
||||
{
|
||||
m_lock.LockForRead();
|
||||
bool bResult = m_PathStringPool.SaveToBuffer( buffer );
|
||||
bResult = bResult && m_FileStringPool.SaveToBuffer( buffer );
|
||||
m_lock.UnlockRead();
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
bool CUtlFilenameSymbolTable::RestoreFromBuffer( CUtlBuffer &buffer )
|
||||
{
|
||||
m_lock.LockForWrite();
|
||||
bool bResult = m_PathStringPool.RestoreFromBuffer( buffer );
|
||||
bResult = bResult && m_FileStringPool.RestoreFromBuffer( buffer );
|
||||
m_lock.UnlockWrite();
|
||||
|
||||
return bResult;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user