mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-07 17:29:36 +00:00
amd64: fix multithread, fix vgui, fix physmodels
This commit is contained in:
+431
-11
@@ -1,4 +1,4 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
@@ -14,21 +14,33 @@
|
||||
|
||||
#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();
|
||||
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
|
||||
@@ -48,14 +60,15 @@ protected:
|
||||
//
|
||||
// At some point this should replace CStringPool
|
||||
//-----------------------------------------------------------------------------
|
||||
class CCountedStringPool
|
||||
template<class T>
|
||||
class CCountedStringPoolBase
|
||||
{
|
||||
public: // HACK, hash_item_t structure should not be public.
|
||||
|
||||
struct hash_item_t
|
||||
{
|
||||
char* pString;
|
||||
unsigned short nNextElement;
|
||||
T nNextElement;
|
||||
unsigned char nReferenceCount;
|
||||
unsigned char pad;
|
||||
};
|
||||
@@ -67,13 +80,14 @@ public: // HACK, hash_item_t structure should not be public.
|
||||
HASH_TABLE_SIZE = 1024
|
||||
};
|
||||
|
||||
CUtlVector<unsigned short> m_HashTable; // Points to each element
|
||||
CUtlVector<T> m_HashTable; // Points to each element
|
||||
CUtlVector<hash_item_t> m_Elements;
|
||||
unsigned short m_FreeListStart;
|
||||
T m_FreeListStart;
|
||||
StringPoolCase_t m_caseSensitivity;
|
||||
|
||||
public:
|
||||
CCountedStringPool();
|
||||
virtual ~CCountedStringPool();
|
||||
CCountedStringPoolBase( StringPoolCase_t caseSensitivity = StringPoolCaseInsensitive );
|
||||
virtual ~CCountedStringPoolBase();
|
||||
|
||||
void FreeAll();
|
||||
|
||||
@@ -82,10 +96,416 @@ public:
|
||||
void DereferenceString( const char* pIntrinsic );
|
||||
|
||||
// These are only reliable if there are less than 64k strings in your string pool
|
||||
unsigned short FindStringHandle( const char* pIntrinsic );
|
||||
unsigned short ReferenceStringHandle( const char* pIntrinsic );
|
||||
char *HandleToString( unsigned short handle );
|
||||
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
|
||||
|
||||
+458
-112
@@ -1,4 +1,4 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//====== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. =======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
@@ -14,6 +14,8 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "unitlib/unitlib.h" // just here for tests - remove before checking in!!!
|
||||
|
||||
#include "tier1/utlmemory.h"
|
||||
#include "tier1/byteswap.h"
|
||||
#include <stdarg.h>
|
||||
@@ -102,11 +104,48 @@ CUtlCharConversion *GetNoEscCharConversion();
|
||||
SetOverflowFuncs( static_cast <UtlBufferOverflowFunc_t>( _get ), static_cast <UtlBufferOverflowFunc_t>( _put ) )
|
||||
|
||||
|
||||
|
||||
typedef unsigned short ushort;
|
||||
|
||||
template < class A >
|
||||
static const char *GetFmtStr( int nRadix = 10, bool bPrint = true ) { Assert( 0 ); return ""; }
|
||||
#if defined( LINUX ) || defined( __clang__ ) || ( defined( _MSC_VER ) && _MSC_VER >= 1900 )
|
||||
template <> const char *GetFmtStr< short > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%hd"; }
|
||||
template <> const char *GetFmtStr< ushort > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%hu"; }
|
||||
template <> const char *GetFmtStr< int > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%d"; }
|
||||
template <> const char *GetFmtStr< uint > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 || nRadix == 16 ); return nRadix == 16 ? "%x" : "%u"; }
|
||||
template <> const char *GetFmtStr< int64 > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%lld"; }
|
||||
template <> const char *GetFmtStr< float > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%f"; }
|
||||
template <> const char *GetFmtStr< double > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return bPrint ? "%.15lf" : "%lf"; } // force Printf to print DBL_DIG=15 digits of precision for doubles - defaults to FLT_DIG=6
|
||||
#else
|
||||
template <> static const char *GetFmtStr< short > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%hd"; }
|
||||
template <> static const char *GetFmtStr< ushort > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%hu"; }
|
||||
template <> static const char *GetFmtStr< int > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%d"; }
|
||||
template <> static const char *GetFmtStr< uint > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 || nRadix == 16 ); return nRadix == 16 ? "%x" : "%u"; }
|
||||
template <> static const char *GetFmtStr< int64 > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%lld"; }
|
||||
template <> static const char *GetFmtStr< float > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%f"; }
|
||||
template <> static const char *GetFmtStr< double > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return bPrint ? "%.15lf" : "%lf"; } // force Printf to print DBL_DIG=15 digits of precision for doubles - defaults to FLT_DIG=6
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// Command parsing..
|
||||
//-----------------------------------------------------------------------------
|
||||
class CUtlBuffer
|
||||
{
|
||||
// Brian has on his todo list to revisit this as there are issues in some cases with CUtlVector using operator = instead of copy construtor in InsertMultiple, etc.
|
||||
// The unsafe case is something like this:
|
||||
// CUtlVector< CUtlBuffer > vecFoo;
|
||||
//
|
||||
// CUtlBuffer buf;
|
||||
// buf.Put( xxx );
|
||||
// vecFoo.Insert( buf );
|
||||
//
|
||||
// This will cause memory corruption when vecFoo is cleared
|
||||
//
|
||||
//private:
|
||||
// // Disallow copying
|
||||
// CUtlBuffer( const CUtlBuffer & );// { Assert( 0 ); }
|
||||
// CUtlBuffer &operator=( const CUtlBuffer & );// { Assert( 0 ); return *this; }
|
||||
|
||||
public:
|
||||
enum SeekType_t
|
||||
{
|
||||
@@ -132,7 +171,19 @@ public:
|
||||
CUtlBuffer( int growSize = 0, int initSize = 0, int nFlags = 0 );
|
||||
CUtlBuffer( const void* pBuffer, int size, int nFlags = 0 );
|
||||
// This one isn't actually defined so that we catch contructors that are trying to pass a bool in as the third param.
|
||||
CUtlBuffer( const void *pBuffer, int size, bool crap );
|
||||
CUtlBuffer( const void *pBuffer, int size, bool crap ) = delete;
|
||||
|
||||
// UtlBuffer objects should not be copyable; we do a slow copy if you use this but it asserts.
|
||||
// (REI: I'd like to delete these but we have some python bindings that currently rely on being able to copy these objects)
|
||||
CUtlBuffer( const CUtlBuffer& ); // = delete;
|
||||
CUtlBuffer& operator= ( const CUtlBuffer& ); // = delete;
|
||||
|
||||
#if VALVE_CPP11
|
||||
// UtlBuffer is non-copyable (same as CUtlMemory), but it is moveable. We would like to declare these with '= default'
|
||||
// but unfortunately VS2013 isn't fully C++11 compliant, so we have to manually declare these in the boilerplate way.
|
||||
CUtlBuffer( CUtlBuffer&& moveFrom ); // = default;
|
||||
CUtlBuffer& operator= ( CUtlBuffer&& moveFrom ); // = default;
|
||||
#endif
|
||||
|
||||
unsigned char GetFlags() const;
|
||||
|
||||
@@ -143,11 +194,15 @@ public:
|
||||
// Makes sure we've got at least this much memory
|
||||
void EnsureCapacity( int num );
|
||||
|
||||
// Access for direct read into buffer
|
||||
void * AccessForDirectRead( int nBytes );
|
||||
|
||||
// Attaches the buffer to external memory....
|
||||
void SetExternalBuffer( void* pMemory, int nSize, int nInitialPut, int nFlags = 0 );
|
||||
bool IsExternallyAllocated() const;
|
||||
// Takes ownership of the passed memory, including freeing it when this buffer is destroyed.
|
||||
void AssumeMemory( void *pMemory, int nSize, int nInitialPut, int nFlags = 0 );
|
||||
void *Detach();
|
||||
void* DetachMemory();
|
||||
|
||||
// copies data from another buffer
|
||||
void CopyBuffer( const CUtlBuffer &buffer );
|
||||
@@ -156,9 +211,10 @@ public:
|
||||
void Swap( CUtlBuffer &buf );
|
||||
void Swap( CUtlMemory<uint8> &mem );
|
||||
|
||||
|
||||
FORCEINLINE void ActivateByteSwappingIfBigEndian( void )
|
||||
{
|
||||
if ( IsX360() )
|
||||
if ( ( IsX360() || IsPS3() ) )
|
||||
ActivateByteSwapping( true );
|
||||
}
|
||||
|
||||
@@ -174,6 +230,9 @@ public:
|
||||
// Clears out the buffer; frees memory
|
||||
void Purge();
|
||||
|
||||
// Dump the buffer to stdout
|
||||
void Spew( );
|
||||
|
||||
// Read stuff out.
|
||||
// Binary mode: it'll just read the bits directly in, and characters will be
|
||||
// read for strings until a null character is reached.
|
||||
@@ -185,28 +244,25 @@ public:
|
||||
unsigned short GetUnsignedShort( );
|
||||
int GetInt( );
|
||||
int64 GetInt64( );
|
||||
int GetIntHex( );
|
||||
unsigned int GetIntHex( );
|
||||
unsigned int GetUnsignedInt( );
|
||||
uint64 GetUnsignedInt64( );
|
||||
float GetFloat( );
|
||||
double GetDouble( );
|
||||
void * GetPtr();
|
||||
template <size_t maxLenInChars> void GetString( char( &pString )[maxLenInChars] )
|
||||
{
|
||||
GetStringInternal( pString, maxLenInChars );
|
||||
}
|
||||
|
||||
void GetString( char *pString, size_t maxLenInChars )
|
||||
{
|
||||
GetStringInternal( pString, maxLenInChars );
|
||||
}
|
||||
void * GetPtr();
|
||||
void GetString( char* pString, int nMaxChars );
|
||||
bool Get( void* pMem, int size );
|
||||
void GetLine( char* pLine, int nMaxChars );
|
||||
|
||||
void GetStringManualCharCount( char *pString, size_t maxLenInChars )
|
||||
{
|
||||
GetStringInternal( pString, maxLenInChars );
|
||||
GetString( pString, maxLenInChars );
|
||||
}
|
||||
|
||||
void Get( void* pMem, int size );
|
||||
void GetLine( char* pLine, int nMaxChars = 0 );
|
||||
template <size_t maxLenInChars> void GetString( char( &pString )[maxLenInChars] )
|
||||
{
|
||||
GetString( pString, maxLenInChars );
|
||||
}
|
||||
|
||||
// Used for getting objects that have a byteswap datadesc defined
|
||||
template <typename T> void GetObjects( T *dest, int count = 1 );
|
||||
@@ -238,7 +294,7 @@ public:
|
||||
|
||||
// Just like scanf, but doesn't work in binary mode
|
||||
int Scanf( SCANF_FORMAT_STRING const char* pFmt, ... );
|
||||
int VaScanf( const char* pFmt, va_list list );
|
||||
int VaScanf( const char* pFmt, va_list list );
|
||||
|
||||
// Eats white space, advances Get index
|
||||
void EatWhiteSpace();
|
||||
@@ -270,16 +326,16 @@ public:
|
||||
// PutString will not write a terminating character
|
||||
void PutChar( char c );
|
||||
void PutUnsignedChar( unsigned char uc );
|
||||
void PutUint64( uint64 ub );
|
||||
void PutInt16( int16 s16 );
|
||||
void PutShort( short s );
|
||||
void PutUnsignedShort( unsigned short us );
|
||||
void PutInt( int i );
|
||||
void PutInt64( int64 i );
|
||||
void PutUnsignedInt( unsigned int u );
|
||||
void PutUnsignedInt64( uint64 u );
|
||||
void PutUint64( uint64 u );
|
||||
void PutFloat( float f );
|
||||
void PutDouble( double d );
|
||||
void PutPtr( void * ); // Writes the pointer, not the pointed to
|
||||
void PutPtr( void * ); // Writes the pointer, not the pointed to
|
||||
void PutString( const char* pString );
|
||||
void Put( const void* pMem, int size );
|
||||
|
||||
@@ -318,8 +374,8 @@ public:
|
||||
// Buffer base
|
||||
const void* Base() const;
|
||||
void* Base();
|
||||
// Returns the base as a const char*, only valid in text mode.
|
||||
const char *String() const;
|
||||
|
||||
const void* String() const;
|
||||
|
||||
// memory allocation size, does *not* reflect size written or read,
|
||||
// use TellPut or TellGet for that
|
||||
@@ -352,6 +408,12 @@ public:
|
||||
// Temporarily disables pretty print
|
||||
void EnableTabs( bool bEnable );
|
||||
|
||||
#if !defined( _GAMECONSOLE )
|
||||
// Swap my internal memory with another buffer,
|
||||
// and copy all of its other members
|
||||
void SwapCopy( CUtlBuffer &other ) ;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// error flags
|
||||
enum
|
||||
@@ -371,7 +433,10 @@ protected:
|
||||
bool CheckPut( int size );
|
||||
bool CheckGet( int size );
|
||||
|
||||
// NOTE: Pass in nPut here even though it is just a copy of m_Put. This is almost always called immediately
|
||||
// after modifying m_Put and this lets it stay in a register
|
||||
void AddNullTermination( );
|
||||
void AddNullTermination( int nPut );
|
||||
|
||||
// Methods to help with pretty-printing
|
||||
bool WasLastCharacterCR();
|
||||
@@ -400,16 +465,18 @@ protected:
|
||||
// Call this to peek arbitrarily long into memory. It doesn't fail unless
|
||||
// it can't read *anything* new
|
||||
bool CheckArbitraryPeekGet( int nOffset, int &nIncrement );
|
||||
void GetStringInternal( char *pString, size_t maxLenInChars );
|
||||
|
||||
template <typename T> void GetType( T& dest, const char *pszFmt );
|
||||
template <typename T> void GetType( T& dest );
|
||||
template <typename T> void GetTypeBin( T& dest );
|
||||
template <typename T> bool GetTypeText( T &value, int nRadix = 10 );
|
||||
template <typename T> void GetObject( T *src );
|
||||
|
||||
template <typename T> void PutType( T src, const char *pszFmt );
|
||||
template <typename T> void PutType( T src );
|
||||
template <typename T> void PutTypeBin( T src );
|
||||
template <typename T> void PutObject( T *src );
|
||||
|
||||
// be sure to also update the copy constructor
|
||||
// and SwapCopy() when adding members.
|
||||
CUtlMemory<unsigned char> m_Memory;
|
||||
int m_Get;
|
||||
int m_Put;
|
||||
@@ -417,7 +484,7 @@ protected:
|
||||
unsigned char m_Error;
|
||||
unsigned char m_Flags;
|
||||
unsigned char m_Reserved;
|
||||
#if defined( _X360 )
|
||||
#if defined( _GAMECONSOLE )
|
||||
unsigned char pad;
|
||||
#endif
|
||||
|
||||
@@ -605,7 +672,7 @@ inline void CUtlBuffer::GetObject( T *dest )
|
||||
{
|
||||
if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) )
|
||||
{
|
||||
Q_memcpy( dest, PeekGet(), sizeof( T ) );
|
||||
*dest = *(T *)PeekGet();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -615,7 +682,7 @@ inline void CUtlBuffer::GetObject( T *dest )
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_memset( dest, 0, sizeof(T) );
|
||||
Q_memset( &dest, 0, sizeof(T) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,18 +704,18 @@ inline void CUtlBuffer::GetTypeBin( T &dest )
|
||||
{
|
||||
if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) )
|
||||
{
|
||||
Q_memcpy(&dest, PeekGet(), sizeof(T) );
|
||||
dest = *(T *)PeekGet();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Byteswap.SwapBufferToTargetEndian<T>( &dest, (T*)PeekGet() );
|
||||
}
|
||||
m_Get += sizeof(T);
|
||||
}
|
||||
m_Get += sizeof(T);
|
||||
}
|
||||
else
|
||||
{
|
||||
dest = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -656,8 +723,8 @@ inline void CUtlBuffer::GetTypeBin< float >( float &dest )
|
||||
{
|
||||
if ( CheckGet( sizeof( float ) ) )
|
||||
{
|
||||
uintptr_t pData = (uintptr_t)PeekGet();
|
||||
if ( IsX360() && ( pData & 0x03 ) )
|
||||
uintp pData = (uintp)PeekGet();
|
||||
if ( ( IsX360() || IsPS3() ) && ( pData & 0x03 ) )
|
||||
{
|
||||
// handle unaligned read
|
||||
((unsigned char*)&dest)[0] = ((unsigned char*)pData)[0];
|
||||
@@ -668,22 +735,148 @@ inline void CUtlBuffer::GetTypeBin< float >( float &dest )
|
||||
else
|
||||
{
|
||||
// aligned read
|
||||
Q_memcpy( &dest, (void*)pData, sizeof(float) );
|
||||
dest = *(float *)pData;
|
||||
}
|
||||
if ( m_Byteswap.IsSwappingBytes() )
|
||||
{
|
||||
m_Byteswap.SwapBufferToTargetEndian< float >( &dest, &dest );
|
||||
}
|
||||
m_Get += sizeof( float );
|
||||
}
|
||||
m_Get += sizeof( float );
|
||||
}
|
||||
else
|
||||
{
|
||||
dest = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void CUtlBuffer::GetTypeBin< double >( double &dest )
|
||||
{
|
||||
if ( CheckGet( sizeof( double ) ) )
|
||||
{
|
||||
uintp pData = (uintp)PeekGet();
|
||||
if ( ( IsX360() || IsPS3() ) && ( pData & 0x07 ) )
|
||||
{
|
||||
// handle unaligned read
|
||||
((unsigned char*)&dest)[0] = ((unsigned char*)pData)[0];
|
||||
((unsigned char*)&dest)[1] = ((unsigned char*)pData)[1];
|
||||
((unsigned char*)&dest)[2] = ((unsigned char*)pData)[2];
|
||||
((unsigned char*)&dest)[3] = ((unsigned char*)pData)[3];
|
||||
((unsigned char*)&dest)[4] = ((unsigned char*)pData)[4];
|
||||
((unsigned char*)&dest)[5] = ((unsigned char*)pData)[5];
|
||||
((unsigned char*)&dest)[6] = ((unsigned char*)pData)[6];
|
||||
((unsigned char*)&dest)[7] = ((unsigned char*)pData)[7];
|
||||
}
|
||||
else
|
||||
{
|
||||
// aligned read
|
||||
dest = *(double *)pData;
|
||||
}
|
||||
if ( m_Byteswap.IsSwappingBytes() )
|
||||
{
|
||||
m_Byteswap.SwapBufferToTargetEndian< double >( &dest, &dest );
|
||||
}
|
||||
m_Get += sizeof( double );
|
||||
}
|
||||
else
|
||||
{
|
||||
dest = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T StringToNumber( char *pString, char **ppEnd, int nRadix )
|
||||
{
|
||||
Assert( 0 );
|
||||
*ppEnd = pString;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int8 StringToNumber( char *pString, char **ppEnd, int nRadix )
|
||||
{
|
||||
return ( int8 )strtol( pString, ppEnd, nRadix );
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint8 StringToNumber( char *pString, char **ppEnd, int nRadix )
|
||||
{
|
||||
return ( uint8 )strtoul( pString, ppEnd, nRadix );
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int16 StringToNumber( char *pString, char **ppEnd, int nRadix )
|
||||
{
|
||||
return ( int16 )strtol( pString, ppEnd, nRadix );
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint16 StringToNumber( char *pString, char **ppEnd, int nRadix )
|
||||
{
|
||||
return ( uint16 )strtoul( pString, ppEnd, nRadix );
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int32 StringToNumber( char *pString, char **ppEnd, int nRadix )
|
||||
{
|
||||
return ( int32 )strtol( pString, ppEnd, nRadix );
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint32 StringToNumber( char *pString, char **ppEnd, int nRadix )
|
||||
{
|
||||
return ( uint32 )strtoul( pString, ppEnd, nRadix );
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int64 StringToNumber( char *pString, char **ppEnd, int nRadix )
|
||||
{
|
||||
#if defined(_PS3) || defined(POSIX)
|
||||
return ( int64 )strtoll( pString, ppEnd, nRadix );
|
||||
#else // !_PS3
|
||||
return ( int64 )_strtoi64( pString, ppEnd, nRadix );
|
||||
#endif // _PS3
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float StringToNumber( char *pString, char **ppEnd, int nRadix )
|
||||
{
|
||||
NOTE_UNUSED( nRadix );
|
||||
return ( float )strtod( pString, ppEnd );
|
||||
}
|
||||
|
||||
template <>
|
||||
inline double StringToNumber( char *pString, char **ppEnd, int nRadix )
|
||||
{
|
||||
NOTE_UNUSED( nRadix );
|
||||
return ( double )strtod( pString, ppEnd );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool CUtlBuffer::GetTypeText( T &value, int nRadix /*= 10*/ )
|
||||
{
|
||||
// NOTE: This is not bullet-proof; it assumes numbers are < 128 characters
|
||||
int nLength = 128;
|
||||
if ( !CheckArbitraryPeekGet( 0, nLength ) )
|
||||
{
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
char *pStart = (char*)PeekGet();
|
||||
char* pEnd = pStart;
|
||||
value = StringToNumber< T >( pStart, &pEnd, nRadix );
|
||||
|
||||
int nBytesRead = (int)( pEnd - pStart );
|
||||
if ( nBytesRead == 0 )
|
||||
return false;
|
||||
|
||||
m_Get += nBytesRead;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void CUtlBuffer::GetType( T &dest, const char *pszFmt )
|
||||
inline void CUtlBuffer::GetType( T &dest )
|
||||
{
|
||||
if (!IsText())
|
||||
{
|
||||
@@ -691,93 +884,115 @@ inline void CUtlBuffer::GetType( T &dest, const char *pszFmt )
|
||||
}
|
||||
else
|
||||
{
|
||||
dest = 0;
|
||||
Scanf( pszFmt, &dest );
|
||||
GetTypeText( dest );
|
||||
}
|
||||
}
|
||||
|
||||
inline char CUtlBuffer::GetChar( )
|
||||
{
|
||||
// LEGACY WARNING: this behaves differently than GetUnsignedChar()
|
||||
char c;
|
||||
GetType( c, "%c" );
|
||||
GetTypeBin( c ); // always reads as binary
|
||||
return c;
|
||||
}
|
||||
|
||||
inline unsigned char CUtlBuffer::GetUnsignedChar( )
|
||||
{
|
||||
// LEGACY WARNING: this behaves differently than GetChar()
|
||||
unsigned char c;
|
||||
GetType( c, "%u" );
|
||||
if (!IsText())
|
||||
{
|
||||
GetTypeBin( c );
|
||||
}
|
||||
else
|
||||
{
|
||||
c = ( unsigned char )GetUnsignedShort();
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
inline short CUtlBuffer::GetShort( )
|
||||
{
|
||||
short s;
|
||||
GetType( s, "%d" );
|
||||
GetType( s );
|
||||
return s;
|
||||
}
|
||||
|
||||
inline unsigned short CUtlBuffer::GetUnsignedShort( )
|
||||
{
|
||||
unsigned short s;
|
||||
GetType( s, "%u" );
|
||||
GetType( s );
|
||||
return s;
|
||||
}
|
||||
|
||||
inline int CUtlBuffer::GetInt( )
|
||||
{
|
||||
int i;
|
||||
GetType( i, "%d" );
|
||||
GetType( i );
|
||||
return i;
|
||||
}
|
||||
|
||||
inline int64 CUtlBuffer::GetInt64( )
|
||||
{
|
||||
int64 i;
|
||||
GetType( i, "%lld" );
|
||||
GetType( i );
|
||||
return i;
|
||||
}
|
||||
|
||||
inline int CUtlBuffer::GetIntHex( )
|
||||
inline unsigned int CUtlBuffer::GetIntHex( )
|
||||
{
|
||||
int i;
|
||||
GetType( i, "%x" );
|
||||
uint i;
|
||||
if (!IsText())
|
||||
{
|
||||
GetTypeBin( i );
|
||||
}
|
||||
else
|
||||
{
|
||||
GetTypeText( i, 16 );
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
inline unsigned int CUtlBuffer::GetUnsignedInt( )
|
||||
{
|
||||
unsigned int u;
|
||||
GetType( u, "%u" );
|
||||
return u;
|
||||
unsigned int i;
|
||||
GetType( i );
|
||||
return i;
|
||||
}
|
||||
|
||||
inline uint64 CUtlBuffer::GetUnsignedInt64()
|
||||
{
|
||||
uint64 i;
|
||||
GetType( i );
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
inline float CUtlBuffer::GetFloat( )
|
||||
{
|
||||
float f;
|
||||
GetType( f, "%f" );
|
||||
GetType( f );
|
||||
return f;
|
||||
}
|
||||
|
||||
inline void *CUtlBuffer::GetPtr( )
|
||||
{
|
||||
void *p;
|
||||
// LEGACY WARNING: in text mode, PutPtr writes 32 bit pointers in hex, while GetPtr reads 32 or 64 bit pointers in decimal
|
||||
#ifndef PLATFORM_64BITS
|
||||
p = ( void* )GetUnsignedInt();
|
||||
#else
|
||||
p = ( void* )GetInt64();
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
inline double CUtlBuffer::GetDouble( )
|
||||
{
|
||||
double d;
|
||||
GetType( d, "%f" );
|
||||
GetType( d );
|
||||
return d;
|
||||
}
|
||||
|
||||
inline void *CUtlBuffer::GetPtr( )
|
||||
{
|
||||
void *p;
|
||||
// LEGACY WARNING: in text mode, PutPtr writes 32 bit pointers in hex, while GetPtr reads 32 or 64 bit pointers in decimal
|
||||
#if !defined(X64BITS) && !defined(PLATFORM_64BITS)
|
||||
p = ( void* )GetUnsignedInt();
|
||||
#else
|
||||
p = ( void* )GetInt64();
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Where am I writing?
|
||||
@@ -835,14 +1050,14 @@ inline void CUtlBuffer::PutObject( T *src )
|
||||
{
|
||||
if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) )
|
||||
{
|
||||
Q_memcpy( PeekPut(), src, sizeof( T ) );
|
||||
*(T *)PeekPut() = *src;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Byteswap.SwapFieldsToTargetEndian<T>( (T*)PeekPut(), src );
|
||||
}
|
||||
m_Put += sizeof(T);
|
||||
AddNullTermination();
|
||||
AddNullTermination( m_Put );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -864,19 +1079,93 @@ inline void CUtlBuffer::PutTypeBin( T src )
|
||||
{
|
||||
if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) )
|
||||
{
|
||||
Q_memcpy( PeekPut(), &src, sizeof( T ) );
|
||||
*(T *)PeekPut() = src;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Byteswap.SwapBufferToTargetEndian<T>( (T*)PeekPut(), &src );
|
||||
}
|
||||
m_Put += sizeof(T);
|
||||
AddNullTermination();
|
||||
AddNullTermination( m_Put );
|
||||
}
|
||||
}
|
||||
|
||||
#if defined( _GAMECONSOLE )
|
||||
template <>
|
||||
inline void CUtlBuffer::PutTypeBin< float >( float src )
|
||||
{
|
||||
if ( CheckPut( sizeof( src ) ) )
|
||||
{
|
||||
if ( m_Byteswap.IsSwappingBytes() )
|
||||
{
|
||||
m_Byteswap.SwapBufferToTargetEndian<float>( &src, &src );
|
||||
}
|
||||
|
||||
//
|
||||
// Write the data
|
||||
//
|
||||
unsigned pData = (unsigned)PeekPut();
|
||||
if ( pData & 0x03 )
|
||||
{
|
||||
// handle unaligned write
|
||||
byte* dst = (byte*)pData;
|
||||
byte* srcPtr = (byte*)&src;
|
||||
dst[0] = srcPtr[0];
|
||||
dst[1] = srcPtr[1];
|
||||
dst[2] = srcPtr[2];
|
||||
dst[3] = srcPtr[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
*(float *)pData = src;
|
||||
}
|
||||
|
||||
m_Put += sizeof(float);
|
||||
AddNullTermination( m_Put );
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void CUtlBuffer::PutTypeBin< double >( double src )
|
||||
{
|
||||
if ( CheckPut( sizeof( src ) ) )
|
||||
{
|
||||
if ( m_Byteswap.IsSwappingBytes() )
|
||||
{
|
||||
m_Byteswap.SwapBufferToTargetEndian<double>( &src, &src );
|
||||
}
|
||||
|
||||
//
|
||||
// Write the data
|
||||
//
|
||||
unsigned pData = (unsigned)PeekPut();
|
||||
if ( pData & 0x07 )
|
||||
{
|
||||
// handle unaligned write
|
||||
byte* dst = (byte*)pData;
|
||||
byte* srcPtr = (byte*)&src;
|
||||
dst[0] = srcPtr[0];
|
||||
dst[1] = srcPtr[1];
|
||||
dst[2] = srcPtr[2];
|
||||
dst[3] = srcPtr[3];
|
||||
dst[4] = srcPtr[4];
|
||||
dst[5] = srcPtr[5];
|
||||
dst[6] = srcPtr[6];
|
||||
dst[7] = srcPtr[7];
|
||||
}
|
||||
else
|
||||
{
|
||||
*(double *)pData = src;
|
||||
}
|
||||
|
||||
m_Put += sizeof(double);
|
||||
AddNullTermination( m_Put );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
inline void CUtlBuffer::PutType( T src, const char *pszFmt )
|
||||
inline void CUtlBuffer::PutType( T src )
|
||||
{
|
||||
if (!IsText())
|
||||
{
|
||||
@@ -884,7 +1173,7 @@ inline void CUtlBuffer::PutType( T src, const char *pszFmt )
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf( pszFmt, src );
|
||||
Printf( GetFmtStr< T >(), src );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -952,68 +1241,74 @@ inline void CUtlBuffer::PutChar( char c )
|
||||
|
||||
inline void CUtlBuffer::PutUnsignedChar( unsigned char c )
|
||||
{
|
||||
PutType( c, "%u" );
|
||||
}
|
||||
|
||||
inline void CUtlBuffer::PutUint64( uint64 ub )
|
||||
{
|
||||
PutType( ub, "%llu" );
|
||||
}
|
||||
|
||||
inline void CUtlBuffer::PutInt16( int16 s16 )
|
||||
{
|
||||
PutType( s16, "%d" );
|
||||
if (!IsText())
|
||||
{
|
||||
PutTypeBin( c );
|
||||
}
|
||||
else
|
||||
{
|
||||
PutUnsignedShort( c );
|
||||
}
|
||||
}
|
||||
|
||||
inline void CUtlBuffer::PutShort( short s )
|
||||
{
|
||||
PutType( s, "%d" );
|
||||
PutType( s );
|
||||
}
|
||||
|
||||
inline void CUtlBuffer::PutUnsignedShort( unsigned short s )
|
||||
{
|
||||
PutType( s, "%u" );
|
||||
PutType( s );
|
||||
}
|
||||
|
||||
inline void CUtlBuffer::PutInt( int i )
|
||||
{
|
||||
PutType( i, "%d" );
|
||||
PutType( i );
|
||||
}
|
||||
|
||||
inline void CUtlBuffer::PutInt64( int64 i )
|
||||
{
|
||||
PutType( i, "%llu" );
|
||||
PutType( i );
|
||||
}
|
||||
|
||||
inline void CUtlBuffer::PutUnsignedInt( unsigned int u )
|
||||
{
|
||||
PutType( u, "%u" );
|
||||
PutType( u );
|
||||
}
|
||||
|
||||
inline void CUtlBuffer::PutUnsignedInt64( uint64 i )
|
||||
{
|
||||
PutType( i );
|
||||
}
|
||||
|
||||
inline void CUtlBuffer::PutUint64( uint64 i )
|
||||
{
|
||||
PutType( i );
|
||||
}
|
||||
|
||||
inline void CUtlBuffer::PutFloat( float f )
|
||||
{
|
||||
PutType( f, "%f" );
|
||||
PutType( f );
|
||||
}
|
||||
|
||||
inline void CUtlBuffer::PutDouble( double d )
|
||||
{
|
||||
PutType( d, "%f" );
|
||||
PutType( d );
|
||||
}
|
||||
|
||||
inline void CUtlBuffer::PutPtr( void *p )
|
||||
{
|
||||
// LEGACY WARNING: in text mode, PutPtr writes 32 bit pointers in hex, while GetPtr reads 32 or 64 bit pointers in decimal
|
||||
if (!IsText())
|
||||
{
|
||||
PutTypeBin( p );
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf( "0x%p", p );
|
||||
}
|
||||
// LEGACY WARNING: in text mode, PutPtr writes 32 bit pointers in hex, while GetPtr reads 32 or 64 bit pointers in decimal
|
||||
if (!IsText())
|
||||
{
|
||||
PutTypeBin( p );
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf( "0x%p", p );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Am I a text buffer?
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -1062,26 +1357,25 @@ inline bool CUtlBuffer::IsReadOnly() const
|
||||
//-----------------------------------------------------------------------------
|
||||
// Buffer base and size
|
||||
//-----------------------------------------------------------------------------
|
||||
inline const void* CUtlBuffer::Base() const
|
||||
{
|
||||
return m_Memory.Base();
|
||||
inline const void* CUtlBuffer::Base() const
|
||||
{
|
||||
return m_Memory.Base();
|
||||
}
|
||||
|
||||
inline void* CUtlBuffer::Base()
|
||||
{
|
||||
return m_Memory.Base();
|
||||
return m_Memory.Base();
|
||||
}
|
||||
|
||||
// Returns the base as a const char*, only valid in text mode.
|
||||
inline const char *CUtlBuffer::String() const
|
||||
inline const void* CUtlBuffer::String() const
|
||||
{
|
||||
Assert( IsText() );
|
||||
return reinterpret_cast<const char*>( m_Memory.Base() );
|
||||
}
|
||||
|
||||
inline int CUtlBuffer::Size() const
|
||||
{
|
||||
return m_Memory.NumAllocated();
|
||||
inline int CUtlBuffer::Size() const
|
||||
{
|
||||
return m_Memory.NumAllocated();
|
||||
}
|
||||
|
||||
|
||||
@@ -1095,7 +1389,7 @@ inline void CUtlBuffer::Clear()
|
||||
m_Error = 0;
|
||||
m_nOffset = 0;
|
||||
m_nMaxPut = -1;
|
||||
AddNullTermination();
|
||||
AddNullTermination( m_Put );
|
||||
}
|
||||
|
||||
inline void CUtlBuffer::Purge()
|
||||
@@ -1108,6 +1402,58 @@ inline void CUtlBuffer::Purge()
|
||||
m_Memory.Purge();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void *CUtlBuffer::AccessForDirectRead( int nBytes )
|
||||
{
|
||||
Assert( m_Get == 0 && m_Put == 0 && m_nMaxPut == 0 );
|
||||
EnsureCapacity( nBytes );
|
||||
m_nMaxPut = nBytes;
|
||||
return Base();
|
||||
}
|
||||
|
||||
inline void *CUtlBuffer::Detach()
|
||||
{
|
||||
void *p = m_Memory.Detach();
|
||||
Clear();
|
||||
return p;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline void CUtlBuffer::Spew( )
|
||||
{
|
||||
SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
|
||||
|
||||
char pTmpLine[1024];
|
||||
while( IsValid() && GetBytesRemaining() )
|
||||
{
|
||||
V_memset( pTmpLine, 0, sizeof(pTmpLine) );
|
||||
Get( pTmpLine, MIN( ( size_t )GetBytesRemaining(), sizeof(pTmpLine)-1 ) );
|
||||
Msg( _T( "%s" ), pTmpLine );
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(_GAMECONSOLE)
|
||||
inline void CUtlBuffer::SwapCopy( CUtlBuffer &other )
|
||||
{
|
||||
m_Get = other.m_Get;
|
||||
m_Put = other.m_Put;
|
||||
m_Error = other.m_Error;
|
||||
m_Flags = other.m_Flags;
|
||||
m_Reserved = other.m_Reserved;
|
||||
m_nTab = other.m_nTab;
|
||||
m_nMaxPut = other.m_nMaxPut;
|
||||
m_nOffset = other.m_nOffset;
|
||||
m_GetOverflowFunc = other.m_GetOverflowFunc;
|
||||
m_PutOverflowFunc = other.m_PutOverflowFunc;
|
||||
m_Byteswap = other.m_Byteswap;
|
||||
|
||||
m_Memory.Swap( other.m_Memory );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void CUtlBuffer::CopyBuffer( const CUtlBuffer &buffer )
|
||||
{
|
||||
CopyBuffer( buffer.Base(), buffer.TellPut() );
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Linked list container class
|
||||
//
|
||||
@@ -26,6 +26,9 @@
|
||||
#define FOR_EACH_LL( listName, iteratorName ) \
|
||||
for( auto iteratorName=(listName).Head(); (listName).IsUtlLinkedList && iteratorName != (listName).InvalidIndex(); iteratorName = (listName).Next( iteratorName ) )
|
||||
|
||||
#define FOR_EACH_LL_BACK( listName, iteratorName ) \
|
||||
for( auto iteratorName=(listName).Tail(); (listName).IsUtlLinkedList && iteratorName != (listName).InvalidIndex(); iteratorName = (listName).Previous( iteratorName ) )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class CUtlLinkedList:
|
||||
// description:
|
||||
@@ -65,12 +68,15 @@ public:
|
||||
typedef S IndexType_t; // should really be called IndexStorageType_t, but that would be a huge change
|
||||
typedef I IndexLocalType_t;
|
||||
typedef M MemoryAllocator_t;
|
||||
static const bool IsUtlLinkedList = true; // Used to match this at compiletime
|
||||
enum { IsUtlLinkedList = true }; // Used to match this at compiletime
|
||||
|
||||
// constructor, destructor
|
||||
CUtlLinkedList( int growSize = 0, int initSize = 0 );
|
||||
~CUtlLinkedList();
|
||||
|
||||
CUtlLinkedList( const CUtlLinkedList& ) = delete;
|
||||
CUtlLinkedList& operator=( const CUtlLinkedList& ) = delete;
|
||||
|
||||
// gets particular elements
|
||||
T& Element( I i );
|
||||
T const& Element( I i ) const;
|
||||
@@ -115,6 +121,9 @@ public:
|
||||
I Alloc( bool multilist = false );
|
||||
void Free( I elem );
|
||||
|
||||
// Identify the owner of this linked list's memory:
|
||||
void SetAllocOwner( const char *pszAllocOwner );
|
||||
|
||||
// list modification
|
||||
void LinkBefore( I before, I elem );
|
||||
void LinkAfter( I after, I elem );
|
||||
@@ -348,16 +357,13 @@ protected:
|
||||
typedef UtlLinkedListElem_t<T, S> ListElem_t;
|
||||
|
||||
// constructs the class
|
||||
I AllocInternal( bool multilist = false );
|
||||
I AllocInternal( bool multilist = false ) RESTRICT;
|
||||
void ConstructList();
|
||||
|
||||
// Gets at the list element....
|
||||
ListElem_t& InternalElement( I i ) { return m_Memory[i]; }
|
||||
ListElem_t const& InternalElement( I i ) const { return m_Memory[i]; }
|
||||
|
||||
// copy constructors not allowed
|
||||
CUtlLinkedList( CUtlLinkedList<T, S, ML, I, M> const& list ) { Assert(0); }
|
||||
|
||||
M m_Memory;
|
||||
I m_Head;
|
||||
I m_Tail;
|
||||
@@ -379,17 +385,10 @@ protected:
|
||||
{
|
||||
m_pElements = m_Memory.Base();
|
||||
}
|
||||
|
||||
private:
|
||||
// Faster version of Next that can only be used from tested code internal
|
||||
// to this class, such as Find(). It avoids the cost of checking the index
|
||||
// validity, which is a big win on debug builds.
|
||||
I PrivateNext( I i ) const;
|
||||
};
|
||||
|
||||
|
||||
// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice
|
||||
// MoeMod : CUtlFixedMemory uses intp as index type
|
||||
template < class T >
|
||||
class CUtlFixedLinkedList : public CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > >
|
||||
{
|
||||
@@ -397,25 +396,24 @@ public:
|
||||
CUtlFixedLinkedList( int growSize = 0, int initSize = 0 )
|
||||
: CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > >( growSize, initSize ) {}
|
||||
|
||||
typedef CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > > BaseClass;
|
||||
bool IsValidIndex( intp i ) const
|
||||
{
|
||||
if ( !BaseClass::Memory().IsIdxValid( i ) )
|
||||
if ( !this->Memory().IsIdxValid( i ) )
|
||||
return false;
|
||||
|
||||
#ifdef _DEBUG // it's safe to skip this here, since the only way to get indices after m_LastAlloc is to use MaxElementIndex
|
||||
if ( BaseClass::Memory().IsIdxAfter( i, this->m_LastAlloc ) )
|
||||
if ( this->Memory().IsIdxAfter( i, this->m_LastAlloc ) )
|
||||
{
|
||||
Assert( 0 );
|
||||
return false; // don't read values that have been allocated, but not constructed
|
||||
}
|
||||
#endif
|
||||
|
||||
return ( BaseClass::Memory()[ i ].m_Previous != i ) || ( BaseClass::Memory()[ i ].m_Next == i );
|
||||
return ( this->Memory()[ i ].m_Previous != i ) || ( this->Memory()[ i ].m_Next == i );
|
||||
}
|
||||
|
||||
private:
|
||||
intp MaxElementIndex() const { Assert( 0 ); return BaseClass::InvalidIndex(); } // fixedmemory containers don't support iteration from 0..maxelements-1
|
||||
int MaxElementIndex() const { Assert( 0 ); return this->InvalidIndex(); } // fixedmemory containers don't support iteration from 0..maxelements-1
|
||||
void ResetDbgInfo() {}
|
||||
};
|
||||
|
||||
@@ -439,8 +437,10 @@ template <class T, class S, bool ML, class I, class M>
|
||||
CUtlLinkedList<T,S,ML,I,M>::CUtlLinkedList( int growSize, int initSize ) :
|
||||
m_Memory( growSize, initSize ), m_LastAlloc( m_Memory.InvalidIterator() )
|
||||
{
|
||||
#if !defined( PLATFORM_WINDOWS_PC64 ) && !defined( PLATFORM_64BITS )
|
||||
// Prevent signed non-int datatypes
|
||||
COMPILE_TIME_ASSERT( sizeof(S) == sizeof(M::InvalidIndex()) || ( ( (S)-1 ) > 0 ) );
|
||||
COMPILE_TIME_ASSERT( sizeof(S) == 4 || ( ( (S)-1 ) > 0 ) );
|
||||
#endif
|
||||
ConstructList();
|
||||
ResetDbgInfo();
|
||||
}
|
||||
@@ -540,21 +540,13 @@ inline I CUtlLinkedList<T,S,ML,I,M>::Next( I i ) const
|
||||
return InternalElement(i).m_Next;
|
||||
}
|
||||
|
||||
template <class T, class S, bool ML, class I, class M>
|
||||
inline I CUtlLinkedList<T,S,ML,I,M>::PrivateNext( I i ) const
|
||||
{
|
||||
return InternalElement(i).m_Next;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Are nodes in the list or valid?
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning( disable: 4310 ) // Allows "(I)(S)M::INVALID_INDEX" below
|
||||
#endif
|
||||
template <class T, class S, bool ML, class I, class M>
|
||||
inline bool CUtlLinkedList<T,S,ML,I,M>::IndexInRange( I index ) // Static method
|
||||
{
|
||||
@@ -565,17 +557,17 @@ inline bool CUtlLinkedList<T,S,ML,I,M>::IndexInRange( I index ) // Static method
|
||||
|
||||
// Do some static checks here:
|
||||
// 'I' needs to be able to store 'S'
|
||||
COMPILE_TIME_ASSERT( sizeof(I) >= sizeof(S) );
|
||||
// These COMPILE_TIME_ASSERT checks need to be in individual scopes to avoid build breaks
|
||||
// on MacOS and Linux due to a gcc bug.
|
||||
{ COMPILE_TIME_ASSERT( sizeof(I) >= sizeof(S) ); }
|
||||
// 'S' should be unsigned (to avoid signed arithmetic errors for plausibly exhaustible ranges)
|
||||
COMPILE_TIME_ASSERT( ( sizeof(S) > 2 ) || ( ( (S)-1 ) > 0 ) );
|
||||
{ COMPILE_TIME_ASSERT( ( sizeof(S) > 2 ) || ( ( (S)-1 ) > 0 ) ); }
|
||||
// M::INVALID_INDEX should be storable in S to avoid ambiguities (e.g. with 65536)
|
||||
COMPILE_TIME_ASSERT( ( M::INVALID_INDEX == -1 ) || ( M::INVALID_INDEX == (S)M::INVALID_INDEX ) );
|
||||
{ COMPILE_TIME_ASSERT( ( M::INVALID_INDEX == -1 ) || ( M::INVALID_INDEX == (S)M::INVALID_INDEX ) ); }
|
||||
|
||||
return ( ( (S)index == index ) && ( (S)index != InvalidIndex() ) );
|
||||
}
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <class T, class S, bool ML, class I, class M>
|
||||
inline bool CUtlLinkedList<T,S,ML,I,M>::IsValidIndex( I i ) const
|
||||
@@ -626,6 +618,12 @@ void CUtlLinkedList<T,S,ML,I,M>::SetGrowSize( int growSize )
|
||||
ResetDbgInfo();
|
||||
}
|
||||
|
||||
template< class T, class S, bool ML, class I, class M >
|
||||
void CUtlLinkedList<T,S,ML,I,M>::SetAllocOwner( const char *pszAllocOwner )
|
||||
{
|
||||
m_Memory.SetAllocOwner( pszAllocOwner );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Deallocate memory
|
||||
@@ -665,7 +663,7 @@ void CUtlLinkedList<T,S,ML,I,M>::PurgeAndDeleteElements()
|
||||
// Node allocation/deallocation
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class S, bool ML, class I, class M>
|
||||
I CUtlLinkedList<T,S,ML,I,M>::AllocInternal( bool multilist )
|
||||
I CUtlLinkedList<T,S,ML,I,M>::AllocInternal( bool multilist ) RESTRICT
|
||||
{
|
||||
Assert( !multilist || ML );
|
||||
#ifdef MULTILIST_PEDANTIC_ASSERTS
|
||||
@@ -798,7 +796,7 @@ inline I CUtlLinkedList<T,S,ML,I,M>::AddToHead( )
|
||||
template <class T, class S, bool ML, class I, class M>
|
||||
inline I CUtlLinkedList<T,S,ML,I,M>::AddToTail( )
|
||||
{
|
||||
return InsertBefore( InvalidIndex() );
|
||||
return InsertBefore( InvalidIndex() );
|
||||
}
|
||||
|
||||
|
||||
@@ -860,9 +858,7 @@ inline I CUtlLinkedList<T,S,ML,I,M>::AddToTail( T const& src )
|
||||
template<class T, class S, bool ML, class I, class M>
|
||||
I CUtlLinkedList<T,S,ML,I,M>::Find( const T &src ) const
|
||||
{
|
||||
// Cache the invalidIndex to avoid two levels of function calls on each iteration.
|
||||
I invalidIndex = InvalidIndex();
|
||||
for ( I i=Head(); i != invalidIndex; i = PrivateNext( i ) )
|
||||
for ( I i=Head(); i != InvalidIndex(); i = Next( i ) )
|
||||
{
|
||||
if ( Element( i ) == src )
|
||||
return i;
|
||||
|
||||
+97
-39
@@ -1,4 +1,4 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
@@ -17,22 +17,21 @@
|
||||
#include "tier0/dbg.h"
|
||||
#include <string.h>
|
||||
#include "tier0/platform.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
|
||||
#include "tier0/memalloc.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning (disable:4100)
|
||||
#pragma warning (disable:4514)
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifdef UTLMEMORY_TRACK
|
||||
#define UTLMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlMemory", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 )
|
||||
#define UTLMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlMemory", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 )
|
||||
#define UTLMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "||Sum of all UtlMemory||", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 )
|
||||
#define UTLMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "||Sum of all UtlMemory||", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 )
|
||||
#else
|
||||
#define UTLMEMORY_TRACK_ALLOC() ((void)0)
|
||||
#define UTLMEMORY_TRACK_FREE() ((void)0)
|
||||
@@ -46,6 +45,8 @@
|
||||
template< class T, class I = int >
|
||||
class CUtlMemory
|
||||
{
|
||||
template< class A, class B> friend class CUtlVector;
|
||||
template< class A, size_t B> friend class CUtlVectorFixedGrowableCompat;
|
||||
public:
|
||||
// constructor, destructor
|
||||
CUtlMemory( int nGrowSize = 0, int nInitSize = 0 );
|
||||
@@ -53,6 +54,12 @@ public:
|
||||
CUtlMemory( const T* pMemory, int numElements );
|
||||
~CUtlMemory();
|
||||
|
||||
CUtlMemory( const CUtlMemory& ) = delete;
|
||||
CUtlMemory& operator=( const CUtlMemory& ) = delete;
|
||||
|
||||
CUtlMemory( CUtlMemory&& moveFrom );
|
||||
CUtlMemory& operator=( CUtlMemory&& moveFrom );
|
||||
|
||||
// Set the size by which the memory grows
|
||||
void Init( int nGrowSize = 0, int nInitSize = 0 );
|
||||
|
||||
@@ -92,8 +99,9 @@ public:
|
||||
// Attaches the buffer to external memory....
|
||||
void SetExternalBuffer( T* pMemory, int numElements );
|
||||
void SetExternalBuffer( const T* pMemory, int numElements );
|
||||
// Takes ownership of the passed memory, including freeing it when this buffer is destroyed.
|
||||
void AssumeMemory( T *pMemory, int nSize );
|
||||
T* Detach();
|
||||
void *DetachMemory();
|
||||
|
||||
// Fast swap
|
||||
void Swap( CUtlMemory< T, I > &mem );
|
||||
@@ -212,8 +220,7 @@ public:
|
||||
CUtlMemoryFixed( T* pMemory, int numElements ) { Assert( 0 ); }
|
||||
|
||||
// Can we use this index?
|
||||
// Use unsigned math to improve performance
|
||||
bool IsIdxValid( int i ) const { return (size_t)i < SIZE; }
|
||||
bool IsIdxValid( int i ) const { return (i >= 0) && (i < SIZE); }
|
||||
|
||||
// Specify the invalid ('null') index that we'll only return on failure
|
||||
static const int INVALID_INDEX = -1; // For use with COMPILE_TIME_ASSERT
|
||||
@@ -224,11 +231,10 @@ public:
|
||||
const T* Base() const { if ( nAlignment == 0 ) return (T*)(&m_Memory[0]); else return (T*)AlignValue( &m_Memory[0], nAlignment ); }
|
||||
|
||||
// element access
|
||||
// Use unsigned math and inlined checks to improve performance.
|
||||
T& operator[]( int i ) { Assert( (size_t)i < SIZE ); return Base()[i]; }
|
||||
const T& operator[]( int i ) const { Assert( (size_t)i < SIZE ); return Base()[i]; }
|
||||
T& Element( int i ) { Assert( (size_t)i < SIZE ); return Base()[i]; }
|
||||
const T& Element( int i ) const { Assert( (size_t)i < SIZE ); return Base()[i]; }
|
||||
T& operator[]( int i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
|
||||
const T& operator[]( int i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
|
||||
T& Element( int i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
|
||||
const T& Element( int i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
|
||||
|
||||
// Attaches the buffer to external memory....
|
||||
void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); }
|
||||
@@ -274,12 +280,7 @@ private:
|
||||
char m_Memory[ SIZE*sizeof(T) + nAlignment ];
|
||||
};
|
||||
|
||||
#if defined(POSIX)
|
||||
// From Chris Green: Memory is a little fuzzy but I believe this class did
|
||||
// something fishy with respect to msize and alignment that was OK under our
|
||||
// allocator, the glibc allocator, etc but not the valgrind one (which has no
|
||||
// padding because it detects all forms of head/tail overwrite, including
|
||||
// writing 1 byte past a 1 byte allocation).
|
||||
#ifdef _LINUX
|
||||
#define REMEMBER_ALLOC_SIZE_FOR_VALGRIND 1
|
||||
#endif
|
||||
|
||||
@@ -445,6 +446,44 @@ template< class T, class I >
|
||||
CUtlMemory<T,I>::~CUtlMemory()
|
||||
{
|
||||
Purge();
|
||||
|
||||
#ifdef _DEBUG
|
||||
m_pMemory = reinterpret_cast< T* >( 0xFEFEBAAD );
|
||||
m_nAllocationCount = 0x7BADF00D;
|
||||
#endif
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
CUtlMemory<T,I>::CUtlMemory( CUtlMemory&& moveFrom )
|
||||
: m_pMemory(moveFrom.m_pMemory)
|
||||
, m_nAllocationCount(moveFrom.m_nAllocationCount)
|
||||
, m_nGrowSize(moveFrom.m_nGrowSize)
|
||||
{
|
||||
moveFrom.m_pMemory = nullptr;
|
||||
moveFrom.m_nAllocationCount = 0;
|
||||
moveFrom.m_nGrowSize = 0;
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
CUtlMemory<T,I>& CUtlMemory<T,I>::operator=( CUtlMemory&& moveFrom )
|
||||
{
|
||||
// Copy member variables to locals before purge to handle self-assignment
|
||||
T* pMemory = moveFrom.m_pMemory;
|
||||
int nAllocationCount = moveFrom.m_nAllocationCount;
|
||||
int nGrowSize = moveFrom.m_nGrowSize;
|
||||
|
||||
moveFrom.m_pMemory = nullptr;
|
||||
moveFrom.m_nAllocationCount = 0;
|
||||
moveFrom.m_nGrowSize = 0;
|
||||
|
||||
// If this is a self-assignment, Purge() is a no-op here
|
||||
Purge();
|
||||
|
||||
m_pMemory = pMemory;
|
||||
m_nAllocationCount = nAllocationCount;
|
||||
m_nGrowSize = nGrowSize;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
@@ -493,7 +532,7 @@ void CUtlMemory<T,I>::ConvertToGrowableMemory( int nGrowSize )
|
||||
|
||||
int nNumBytes = m_nAllocationCount * sizeof(T);
|
||||
T *pMemory = (T*)malloc( nNumBytes );
|
||||
memcpy( (void*)pMemory, (void*)m_pMemory, nNumBytes );
|
||||
memcpy( pMemory, m_pMemory, nNumBytes );
|
||||
m_pMemory = pMemory;
|
||||
}
|
||||
else
|
||||
@@ -543,6 +582,24 @@ void CUtlMemory<T,I>::AssumeMemory( T* pMemory, int numElements )
|
||||
m_nAllocationCount = numElements;
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
void *CUtlMemory<T,I>::DetachMemory()
|
||||
{
|
||||
if ( IsExternallyAllocated() )
|
||||
return NULL;
|
||||
|
||||
void *pMemory = m_pMemory;
|
||||
m_pMemory = 0;
|
||||
m_nAllocationCount = 0;
|
||||
return pMemory;
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
inline T* CUtlMemory<T,I>::Detach()
|
||||
{
|
||||
return (T*)DetachMemory();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// element access
|
||||
@@ -550,35 +607,31 @@ void CUtlMemory<T,I>::AssumeMemory( T* pMemory, int numElements )
|
||||
template< class T, class I >
|
||||
inline T& CUtlMemory<T,I>::operator[]( I i )
|
||||
{
|
||||
// Avoid function calls in the asserts to improve debug build performance
|
||||
Assert( m_nGrowSize != EXTERNAL_CONST_BUFFER_MARKER ); //Assert( !IsReadOnly() );
|
||||
Assert( (uint32)i < (uint32)m_nAllocationCount );
|
||||
return m_pMemory[(uint32)i];
|
||||
Assert( !IsReadOnly() );
|
||||
Assert( IsIdxValid(i) );
|
||||
return m_pMemory[i];
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
inline const T& CUtlMemory<T,I>::operator[]( I i ) const
|
||||
{
|
||||
// Avoid function calls in the asserts to improve debug build performance
|
||||
Assert( (uint32)i < (uint32)m_nAllocationCount );
|
||||
return m_pMemory[(uint32)i];
|
||||
Assert( IsIdxValid(i) );
|
||||
return m_pMemory[i];
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
inline T& CUtlMemory<T,I>::Element( I i )
|
||||
{
|
||||
// Avoid function calls in the asserts to improve debug build performance
|
||||
Assert( m_nGrowSize != EXTERNAL_CONST_BUFFER_MARKER ); //Assert( !IsReadOnly() );
|
||||
Assert( (uint32)i < (uint32)m_nAllocationCount );
|
||||
return m_pMemory[(uint32)i];
|
||||
Assert( !IsReadOnly() );
|
||||
Assert( IsIdxValid(i) );
|
||||
return m_pMemory[i];
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
inline const T& CUtlMemory<T,I>::Element( I i ) const
|
||||
{
|
||||
// Avoid function calls in the asserts to improve debug build performance
|
||||
Assert( (uint32)i < (uint32)m_nAllocationCount );
|
||||
return m_pMemory[(uint32)i];
|
||||
Assert( IsIdxValid(i) );
|
||||
return m_pMemory[i];
|
||||
}
|
||||
|
||||
|
||||
@@ -651,10 +704,10 @@ inline int CUtlMemory<T,I>::Count() const
|
||||
template< class T, class I >
|
||||
inline bool CUtlMemory<T,I>::IsIdxValid( I i ) const
|
||||
{
|
||||
// If we always cast 'i' and 'm_nAllocationCount' to unsigned then we can
|
||||
// do our range checking with a single comparison instead of two. This gives
|
||||
// a modest speedup in debug builds.
|
||||
return (uint32)i < (uint32)m_nAllocationCount;
|
||||
// GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0).
|
||||
// We get the warning even if we cast inside the expression. It only goes away if we assign to another variable.
|
||||
long x = i;
|
||||
return ( x >= 0 ) && ( x < m_nAllocationCount );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -672,6 +725,11 @@ inline int UtlMemory_CalcNewAllocationCount( int nAllocationCount, int nGrowSize
|
||||
{
|
||||
// Compute an allocation which is at least as big as a cache line...
|
||||
nAllocationCount = (31 + nBytesItem) / nBytesItem;
|
||||
// If the requested amount is larger then compute an allocation which
|
||||
// is exactly the right size. Otherwise we can end up with wasted memory
|
||||
// when CUtlVector::EnsureCount(n) is called.
|
||||
if ( nAllocationCount < nNewSize )
|
||||
nAllocationCount = nNewSize;
|
||||
}
|
||||
|
||||
while (nAllocationCount < nNewSize)
|
||||
|
||||
+137
-25
@@ -1,4 +1,4 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose: Defines a symbol table
|
||||
//
|
||||
@@ -13,9 +13,13 @@
|
||||
#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"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -24,6 +28,7 @@
|
||||
class CUtlSymbolTable;
|
||||
class CUtlSymbolTableMT;
|
||||
|
||||
#define FILENAMEHANDLE_INVALID 0
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// This is a symbol, which is a easier way of dealing with strings.
|
||||
@@ -52,14 +57,19 @@ public:
|
||||
bool IsValid() const { return m_Id != UTL_INVAL_SYMBOL; }
|
||||
|
||||
// Gets at the symbol
|
||||
operator UtlSymId_t const() const { return m_Id; }
|
||||
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;
|
||||
|
||||
@@ -85,13 +95,17 @@ protected:
|
||||
// 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 = 32, bool caseInsensitive = false );
|
||||
CUtlSymbolTable( int growSize = 0, int initSize = 16, bool caseInsensitive = false );
|
||||
~CUtlSymbolTable();
|
||||
|
||||
// Finds and/or creates a symbol based on the string
|
||||
@@ -102,6 +116,11 @@ public:
|
||||
|
||||
// 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();
|
||||
@@ -111,6 +130,10 @@ public:
|
||||
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
|
||||
{
|
||||
@@ -120,10 +143,8 @@ protected:
|
||||
}
|
||||
|
||||
inline CStringPoolIndex( unsigned short iPool, unsigned short iOffset )
|
||||
{
|
||||
m_iPool = iPool;
|
||||
m_iOffset = iOffset;
|
||||
}
|
||||
: m_iPool(iPool), m_iOffset(iOffset)
|
||||
{}
|
||||
|
||||
inline bool operator==( const CStringPoolIndex &other ) const
|
||||
{
|
||||
@@ -158,7 +179,9 @@ protected:
|
||||
};
|
||||
|
||||
CTree m_Lookup;
|
||||
|
||||
bool m_bInsensitive;
|
||||
mutable unsigned short m_nUserSearchStringHash;
|
||||
mutable const char* m_pUserSearchString;
|
||||
|
||||
// stores the string data
|
||||
@@ -167,11 +190,14 @@ protected:
|
||||
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 : private CUtlSymbolTable
|
||||
class CUtlSymbolTableMT : public CUtlSymbolTable
|
||||
{
|
||||
public:
|
||||
CUtlSymbolTableMT( int growSize = 0, int initSize = 32, bool caseInsensitive = false )
|
||||
@@ -189,9 +215,9 @@ public:
|
||||
|
||||
CUtlSymbol Find( const char* pString ) const
|
||||
{
|
||||
m_lock.LockForRead();
|
||||
m_lock.LockForWrite();
|
||||
CUtlSymbol result = CUtlSymbolTable::Find( pString );
|
||||
m_lock.UnlockRead();
|
||||
m_lock.UnlockWrite();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -202,9 +228,24 @@ public:
|
||||
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:
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
#ifdef WIN32
|
||||
mutable CThreadSpinRWLock m_lock;
|
||||
#else
|
||||
mutable CThreadRWLock m_lock;
|
||||
@@ -225,7 +266,6 @@ private:
|
||||
// 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;
|
||||
#define FILENAMEHANDLE_INVALID 0
|
||||
|
||||
// Symbol table for more efficiently storing filenames by breaking paths and filenames apart.
|
||||
// Refactored from BaseFileSystem.h
|
||||
@@ -238,32 +278,104 @@ class CUtlFilenameSymbolTable
|
||||
{
|
||||
FileNameHandleInternal_t()
|
||||
{
|
||||
path = 0;
|
||||
file = 0;
|
||||
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 short path;
|
||||
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 short file;
|
||||
unsigned int GetFile() const { return (value & cFileBitMask); }
|
||||
void SetFile( unsigned int file ) { Assert( file < cMaxFileValue ); value = ((value & (cPathBitMask << cNumBitsInFile)) | (file & cFileBitMask)); }
|
||||
};
|
||||
|
||||
class HashTable;
|
||||
|
||||
public:
|
||||
CUtlFilenameSymbolTable();
|
||||
~CUtlFilenameSymbolTable();
|
||||
FileNameHandle_t FindOrAddFileName( const char *pFileName );
|
||||
FileNameHandle_t FindFileName( const char *pFileName );
|
||||
int PathIndex(const FileNameHandle_t &handle) { return (( const FileNameHandleInternal_t * )&handle)->path; }
|
||||
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:
|
||||
//CCountedStringPool m_StringPool;
|
||||
HashTable* m_Strings;
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user