mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Add Valve Source SDK utl classes
These have pending modifications/implementations.
This commit is contained in:
parent
00deea0ccb
commit
edeb8ea586
@ -343,6 +343,19 @@ template <typename T> const char* MemAllocClassName(T* p)
|
||||
#define abstract_class class NO_VTABLE
|
||||
#endif
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
#define OVERRIDE override
|
||||
// warning C4481: nonstandard extension used: override specifier 'override'
|
||||
#pragma warning(disable : 4481)
|
||||
#elif defined( __clang__ )
|
||||
#define OVERRIDE override
|
||||
// warning: 'override' keyword is a C++11 extension [-Wc++11-extensions]
|
||||
// Disabling this warning is less intrusive than enabling C++11 extensions
|
||||
#pragma GCC diagnostic ignored "-Wc++11-extensions"
|
||||
#else
|
||||
#define OVERRIDE
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Generally useful platform-independent macros (move to another file?)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
127
r5dev/tier1/stringpool.cpp
Normal file
127
r5dev/tier1/stringpool.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "core/stdafx.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "tier1/stringpool.h"
|
||||
#include "tier1/generichash.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
//#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Comparison function for string sorted associative data structures
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool StrLessInsensitive( const char * const &pszLeft, const char * const &pszRight )
|
||||
{
|
||||
return ( Q_stricmp( pszLeft, pszRight) < 0 );
|
||||
}
|
||||
|
||||
bool StrLessSensitive( const char * const &pszLeft, const char * const &pszRight )
|
||||
{
|
||||
return ( Q_strcmp( pszLeft, pszRight) < 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CStringPool::CStringPool( StringPoolCase_t caseSensitivity )
|
||||
: m_Strings( 32, 256, caseSensitivity == StringPoolCaseInsensitive ? StrLessInsensitive : StrLessSensitive )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CStringPool::~CStringPool()
|
||||
{
|
||||
FreeAll();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
unsigned int CStringPool::Count() const
|
||||
{
|
||||
return m_Strings.Count();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
const char * CStringPool::Find( const char *pszValue )
|
||||
{
|
||||
unsigned short i = m_Strings.Find(pszValue);
|
||||
if ( m_Strings.IsValidIndex(i) )
|
||||
return m_Strings[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * CStringPool::Allocate( const char *pszValue )
|
||||
{
|
||||
char *pszNew;
|
||||
|
||||
unsigned short i = m_Strings.Find(pszValue);
|
||||
bool bNew = (i == m_Strings.InvalidIndex());
|
||||
|
||||
if ( !bNew )
|
||||
return m_Strings[i];
|
||||
|
||||
pszNew = strdup( pszValue );
|
||||
m_Strings.Insert( pszNew );
|
||||
|
||||
return pszNew;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CStringPool::FreeAll()
|
||||
{
|
||||
unsigned short i = m_Strings.FirstInorder();
|
||||
while ( i != m_Strings.InvalidIndex() )
|
||||
{
|
||||
free( (void *)m_Strings[i] );
|
||||
i = m_Strings.NextInorder(i);
|
||||
}
|
||||
m_Strings.RemoveAll();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
#ifdef _DEBUG
|
||||
CON_COMMAND( test_stringpool, "Tests the class CStringPool" )
|
||||
{
|
||||
CStringPool pool;
|
||||
|
||||
Assert(pool.Count() == 0);
|
||||
|
||||
pool.Allocate("test");
|
||||
Assert(pool.Count() == 1);
|
||||
|
||||
pool.Allocate("test");
|
||||
Assert(pool.Count() == 1);
|
||||
|
||||
pool.Allocate("test2");
|
||||
Assert(pool.Count() == 2);
|
||||
|
||||
Assert( pool.Find("test2") != NULL );
|
||||
Assert( pool.Find("TEST") != NULL );
|
||||
Assert( pool.Find("Test2") != NULL );
|
||||
Assert( pool.Find("test") != NULL );
|
||||
|
||||
pool.FreeAll();
|
||||
Assert(pool.Count() == 0);
|
||||
|
||||
Msg("Pass.");
|
||||
}
|
||||
#endif
|
||||
*/
|
511
r5dev/tier1/stringpool.h
Normal file
511
r5dev/tier1/stringpool.h
Normal 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
|
295
r5dev/tier1/utlmap.h
Normal file
295
r5dev/tier1/utlmap.h
Normal 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 match src2 for Panorama
|
||||
// Note in src2 straight Insert() calls will assert on duplicates
|
||||
// Choosing 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
|
380
r5dev/tier1/utlsymbol.h
Normal file
380
r5dev/tier1/utlsymbol.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user