amd64: fix multithread, fix vgui, fix physmodels

This commit is contained in:
nillerusr
2022-06-05 01:44:42 +03:00
parent 01413fdd71
commit 9ee21ecf90
63 changed files with 5679 additions and 2468 deletions
+431 -11
View File
@@ -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
View File
@@ -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() );
+33 -37
View File
@@ -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
View File
@@ -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
View File
@@ -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