summaryrefslogtreecommitdiff
path: root/public/tier1
diff options
context:
space:
mode:
Diffstat (limited to 'public/tier1')
-rw-r--r--public/tier1/CommandBuffer.h167
-rw-r--r--public/tier1/KeyValues.h486
-rw-r--r--public/tier1/UtlSortVector.h414
-rw-r--r--public/tier1/UtlStringMap.h99
-rw-r--r--public/tier1/bitbuf.h809
-rw-r--r--public/tier1/byteswap.h249
-rw-r--r--public/tier1/callqueue.h203
-rw-r--r--public/tier1/characterset.h43
-rw-r--r--public/tier1/checksum_crc.h31
-rw-r--r--public/tier1/checksum_md5.h62
-rw-r--r--public/tier1/checksum_sha1.h174
-rw-r--r--public/tier1/convar.h725
-rw-r--r--public/tier1/convar_serverbounded.h53
-rw-r--r--public/tier1/datamanager.h277
-rw-r--r--public/tier1/delegates.h99
-rw-r--r--public/tier1/diff.h29
-rw-r--r--public/tier1/fileio.h101
-rw-r--r--public/tier1/fmtstr.h366
-rw-r--r--public/tier1/functors.h637
-rw-r--r--public/tier1/generichash.h116
-rw-r--r--public/tier1/iconvar.h116
-rw-r--r--public/tier1/ilocalize.h504
-rw-r--r--public/tier1/instancelog.h84
-rw-r--r--public/tier1/interface.h230
-rw-r--r--public/tier1/keyvaluesjson.h70
-rw-r--r--public/tier1/kvpacker.h49
-rw-r--r--public/tier1/lzmaDecoder.h102
-rw-r--r--public/tier1/lzss.h69
-rw-r--r--public/tier1/mempool.h559
-rw-r--r--public/tier1/memstack.h207
-rw-r--r--public/tier1/netadr.h136
-rw-r--r--public/tier1/passwordhash.h94
-rw-r--r--public/tier1/processor_detect.h12
-rw-r--r--public/tier1/rangecheckedvar.h118
-rw-r--r--public/tier1/refcount.h419
-rw-r--r--public/tier1/reliabletimer.h183
-rw-r--r--public/tier1/smartptr.h279
-rw-r--r--public/tier1/snappy-sinksource.h137
-rw-r--r--public/tier1/snappy-stubs-public.h98
-rw-r--r--public/tier1/snappy.h191
-rw-r--r--public/tier1/sparsematrix.h123
-rw-r--r--public/tier1/stringpool.h91
-rw-r--r--public/tier1/strtools.h1285
-rw-r--r--public/tier1/thash.h698
-rw-r--r--public/tier1/tier1.h106
-rw-r--r--public/tier1/tokenreader.h99
-rw-r--r--public/tier1/uniqueid.h56
-rw-r--r--public/tier1/utlallocation.h134
-rw-r--r--public/tier1/utlarray.h332
-rw-r--r--public/tier1/utlbidirectionalset.h394
-rw-r--r--public/tier1/utlbinaryblock.h107
-rw-r--r--public/tier1/utlblockmemory.h350
-rw-r--r--public/tier1/utlbuffer.h1094
-rw-r--r--public/tier1/utlbufferutil.h192
-rw-r--r--public/tier1/utlcommon.h371
-rw-r--r--public/tier1/utldelegate.h97
-rw-r--r--public/tier1/utldelegateimpl.h2656
-rw-r--r--public/tier1/utldict.h358
-rw-r--r--public/tier1/utlenvelope.h241
-rw-r--r--public/tier1/utlfixedmemory.h354
-rw-r--r--public/tier1/utlflags.h124
-rw-r--r--public/tier1/utlhandletable.h586
-rw-r--r--public/tier1/utlhash.h936
-rw-r--r--public/tier1/utlhashdict.h342
-rw-r--r--public/tier1/utlhashtable.h988
-rw-r--r--public/tier1/utlintrusivelist.h888
-rw-r--r--public/tier1/utllinkedlist.h1293
-rw-r--r--public/tier1/utlmap.h252
-rw-r--r--public/tier1/utlmemory.h1077
-rw-r--r--public/tier1/utlmovingaverage.h103
-rw-r--r--public/tier1/utlmultilist.h771
-rw-r--r--public/tier1/utlntree.h624
-rw-r--r--public/tier1/utlobjectreference.h165
-rw-r--r--public/tier1/utlpair.h52
-rw-r--r--public/tier1/utlpriorityqueue.h198
-rw-r--r--public/tier1/utlqueue.h551
-rw-r--r--public/tier1/utlrbtree.h1593
-rw-r--r--public/tier1/utlsoacontainer.h334
-rw-r--r--public/tier1/utlstack.h331
-rw-r--r--public/tier1/utlstring.h469
-rw-r--r--public/tier1/utlsymbol.h269
-rw-r--r--public/tier1/utlsymbollarge.h499
-rw-r--r--public/tier1/utltshash.h625
-rw-r--r--public/tier1/utlvector.h1513
84 files changed, 32518 insertions, 0 deletions
diff --git a/public/tier1/CommandBuffer.h b/public/tier1/CommandBuffer.h
new file mode 100644
index 0000000..d9bfd7d
--- /dev/null
+++ b/public/tier1/CommandBuffer.h
@@ -0,0 +1,167 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//===========================================================================//
+
+
+#ifndef COMMANDBUFFER_H
+#define COMMANDBUFFER_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier1/utllinkedlist.h"
+#include "tier1/convar.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CUtlBuffer;
+
+
+//-----------------------------------------------------------------------------
+// Invalid command handle
+//-----------------------------------------------------------------------------
+typedef int CommandHandle_t;
+enum
+{
+ COMMAND_BUFFER_INVALID_COMMAND_HANDLE = 0
+};
+
+
+//-----------------------------------------------------------------------------
+// A command buffer class- a queue of argc/argv based commands associated
+// with a particular time
+//-----------------------------------------------------------------------------
+class CCommandBuffer
+{
+public:
+ // Constructor, destructor
+ CCommandBuffer( );
+ ~CCommandBuffer();
+
+ // Inserts text into the command buffer
+ bool AddText( const char *pText, int nTickDelay = 0 );
+
+ // Used to iterate over all commands appropriate for the current time
+ void BeginProcessingCommands( int nDeltaTicks );
+ bool DequeueNextCommand( );
+ int DequeueNextCommand( const char **& ppArgv );
+ int ArgC() const;
+ const char **ArgV() const;
+ const char *ArgS() const; // All args that occur after the 0th arg, in string form
+ const char *GetCommandString() const; // The entire command in string form, including the 0th arg
+ const CCommand& GetCommand() const;
+ void EndProcessingCommands();
+
+ // Are we in the middle of processing commands?
+ bool IsProcessingCommands();
+
+ // Delays all queued commands to execute at a later time
+ void DelayAllQueuedCommands( int nTickDelay );
+
+ // Indicates how long to delay when encoutering a 'wait' command
+ void SetWaitDelayTime( int nTickDelay );
+
+ // Returns a handle to the next command to process
+ // (useful when inserting commands into the buffer during processing
+ // of commands to force immediate execution of those commands,
+ // most relevantly, to implement a feature where you stream a file
+ // worth of commands into the buffer, where the file size is too large
+ // to entirely contain in the buffer).
+ CommandHandle_t GetNextCommandHandle();
+
+ // Specifies a max limit of the args buffer. For unittesting. Size == 0 means use default
+ void LimitArgumentBufferSize( int nSize );
+
+ void SetWaitEnabled( bool bEnable ) { m_bWaitEnabled = bEnable; }
+ bool IsWaitEnabled( void ) { return m_bWaitEnabled; }
+
+ int GetArgumentBufferSize() { return m_nArgSBufferSize; }
+ int GetMaxArgumentBufferSize() { return m_nMaxArgSBufferLength; }
+
+private:
+ enum
+ {
+ ARGS_BUFFER_LENGTH = 8192,
+ };
+
+ struct Command_t
+ {
+ int m_nTick;
+ int m_nFirstArgS;
+ int m_nBufferSize;
+ };
+
+ // Insert a command into the command queue at the appropriate time
+ void InsertCommandAtAppropriateTime( int hCommand );
+
+ // Insert a command into the command queue
+ // Only happens if it's inserted while processing other commands
+ void InsertImmediateCommand( int hCommand );
+
+ // Insert a command into the command queue
+ bool InsertCommand( const char *pArgS, int nCommandSize, int nTick );
+
+ // Returns the length of the next command, as well as the offset to the next command
+ void GetNextCommandLength( const char *pText, int nMaxLen, int *pCommandLength, int *pNextCommandOffset );
+
+ // Compacts the command buffer
+ void Compact();
+
+ // Parses argv0 out of the buffer
+ bool ParseArgV0( CUtlBuffer &buf, char *pArgv0, int nMaxLen, const char **pArgs );
+
+ char m_pArgSBuffer[ ARGS_BUFFER_LENGTH ];
+ int m_nLastUsedArgSSize;
+ int m_nArgSBufferSize;
+ CUtlFixedLinkedList< Command_t > m_Commands;
+ int m_nCurrentTick;
+ int m_nLastTickToProcess;
+ int m_nWaitDelayTicks;
+ int m_hNextCommand;
+ int m_nMaxArgSBufferLength;
+ bool m_bIsProcessingCommands;
+ bool m_bWaitEnabled;
+
+ // NOTE: This is here to avoid the pointers returned by DequeueNextCommand
+ // to become invalid by calling AddText. Is there a way we can avoid the memcpy?
+ CCommand m_CurrentCommand;
+};
+
+
+//-----------------------------------------------------------------------------
+// Returns the next command
+//-----------------------------------------------------------------------------
+inline int CCommandBuffer::ArgC() const
+{
+ return m_CurrentCommand.ArgC();
+}
+
+inline const char **CCommandBuffer::ArgV() const
+{
+ return m_CurrentCommand.ArgV();
+}
+
+inline const char *CCommandBuffer::ArgS() const
+{
+ return m_CurrentCommand.ArgS();
+}
+
+inline const char *CCommandBuffer::GetCommandString() const
+{
+ return m_CurrentCommand.GetCommandString();
+}
+
+inline const CCommand& CCommandBuffer::GetCommand() const
+{
+ return m_CurrentCommand;
+}
+
+#endif // COMMANDBUFFER_H
diff --git a/public/tier1/KeyValues.h b/public/tier1/KeyValues.h
new file mode 100644
index 0000000..3f0544a
--- /dev/null
+++ b/public/tier1/KeyValues.h
@@ -0,0 +1,486 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef KEYVALUES_H
+#define KEYVALUES_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+// #include <vgui/VGUI.h>
+
+#ifndef NULL
+#ifdef __cplusplus
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+#endif
+
+#include "utlvector.h"
+#include "Color.h"
+
+#define FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \
+ for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() )
+
+#define FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \
+ for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() )
+
+#define FOR_EACH_VALUE( kvRoot, kvValue ) \
+ for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() )
+
+class IBaseFileSystem;
+class CUtlBuffer;
+class Color;
+typedef void * FileHandle_t;
+class CKeyValuesGrowableStringTable;
+
+//-----------------------------------------------------------------------------
+// Purpose: Simple recursive data access class
+// Used in vgui for message parameters and resource files
+// Destructor deletes all child KeyValues nodes
+// Data is stored in key (string names) - (string/int/float)value pairs called nodes.
+//
+// About KeyValues Text File Format:
+
+// It has 3 control characters '{', '}' and '"'. Names and values may be quoted or
+// not. The quote '"' character must not be used within name or values, only for
+// quoting whole tokens. You may use escape sequences wile parsing and add within a
+// quoted token a \" to add quotes within your name or token. When using Escape
+// Sequence the parser must now that by setting KeyValues::UsesEscapeSequences( true ),
+// which it's off by default. Non-quoted tokens ends with a whitespace, '{', '}' and '"'.
+// So you may use '{' and '}' within quoted tokens, but not for non-quoted tokens.
+// An open bracket '{' after a key name indicates a list of subkeys which is finished
+// with a closing bracket '}'. Subkeys use the same definitions recursively.
+// Whitespaces are space, return, newline and tabulator. Allowed Escape sequences
+// are \n, \t, \\, \n and \". The number character '#' is used for macro purposes
+// (eg #include), don't use it as first character in key names.
+//-----------------------------------------------------------------------------
+class KeyValues
+{
+public:
+ // By default, the KeyValues class uses a string table for the key names that is
+ // limited to 4MB. The game will exit in error if this space is exhausted. In
+ // general this is preferable for game code for performance and memory fragmentation
+ // reasons.
+ //
+ // If this is not acceptable, you can use this call to switch to a table that can grow
+ // arbitrarily. This call must be made before any KeyValues objects are allocated or it
+ // will result in undefined behavior. If you use the growable string table, you cannot
+ // share KeyValues pointers directly with any other module. You can serialize them across
+ // module boundaries. These limitations are acceptable in the Steam backend code
+ // this option was written for, but may not be in other situations. Make sure to
+ // understand the implications before using this.
+ static void SetUseGrowableStringTable( bool bUseGrowableTable );
+
+ KeyValues( const char *setName );
+
+ //
+ // AutoDelete class to automatically free the keyvalues.
+ // Simply construct it with the keyvalues you allocated and it will free them when falls out of scope.
+ // When you decide that keyvalues shouldn't be deleted call Assign(NULL) on it.
+ // If you constructed AutoDelete(NULL) you can later assign the keyvalues to be deleted with Assign(pKeyValues).
+ // You can also pass temporary KeyValues object as an argument to a function by wrapping it into KeyValues::AutoDelete
+ // instance: call_my_function( KeyValues::AutoDelete( new KeyValues( "test" ) ) )
+ //
+ class AutoDelete
+ {
+ public:
+ explicit inline AutoDelete( KeyValues *pKeyValues ) : m_pKeyValues( pKeyValues ) {}
+ explicit inline AutoDelete( const char *pchKVName ) : m_pKeyValues( new KeyValues( pchKVName ) ) {}
+ inline ~AutoDelete( void ) { if( m_pKeyValues ) m_pKeyValues->deleteThis(); }
+ inline void Assign( KeyValues *pKeyValues ) { m_pKeyValues = pKeyValues; }
+ KeyValues *operator->() { return m_pKeyValues; }
+ operator KeyValues *() { return m_pKeyValues; }
+ private:
+ AutoDelete( AutoDelete const &x ); // forbid
+ AutoDelete & operator= ( AutoDelete const &x ); // forbid
+ KeyValues *m_pKeyValues;
+ };
+
+ // Quick setup constructors
+ KeyValues( const char *setName, const char *firstKey, const char *firstValue );
+ KeyValues( const char *setName, const char *firstKey, const wchar_t *firstValue );
+ KeyValues( const char *setName, const char *firstKey, int firstValue );
+ KeyValues( const char *setName, const char *firstKey, const char *firstValue, const char *secondKey, const char *secondValue );
+ KeyValues( const char *setName, const char *firstKey, int firstValue, const char *secondKey, int secondValue );
+
+ // Section name
+ const char *GetName() const;
+ void SetName( const char *setName);
+
+ // gets the name as a unique int
+ int GetNameSymbol() const { return m_iKeyName; }
+
+ // File access. Set UsesEscapeSequences true, if resource file/buffer uses Escape Sequences (eg \n, \t)
+ void UsesEscapeSequences(bool state); // default false
+ void UsesConditionals(bool state); // default true
+ bool LoadFromFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, bool refreshCache = false );
+ bool SaveToFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, bool sortKeys = false, bool bAllowEmptyString = false, bool bCacheResult = false );
+
+ // Read from a buffer... Note that the buffer must be null terminated
+ bool LoadFromBuffer( char const *resourceName, const char *pBuffer, IBaseFileSystem* pFileSystem = NULL, const char *pPathID = NULL );
+
+ // Read from a utlbuffer...
+ bool LoadFromBuffer( char const *resourceName, CUtlBuffer &buf, IBaseFileSystem* pFileSystem = NULL, const char *pPathID = NULL );
+
+ // Find a keyValue, create it if it is not found.
+ // Set bCreate to true to create the key if it doesn't already exist (which ensures a valid pointer will be returned)
+ KeyValues *FindKey(const char *keyName, bool bCreate = false);
+ KeyValues *FindKey(int keySymbol) const;
+ KeyValues *CreateNewKey(); // creates a new key, with an autogenerated name. name is guaranteed to be an integer, of value 1 higher than the highest other integer key name
+ void AddSubKey( KeyValues *pSubkey ); // Adds a subkey. Make sure the subkey isn't a child of some other keyvalues
+ void RemoveSubKey(KeyValues *subKey); // removes a subkey from the list, DOES NOT DELETE IT
+
+ // Key iteration.
+ //
+ // NOTE: GetFirstSubKey/GetNextKey will iterate keys AND values. Use the functions
+ // below if you want to iterate over just the keys or just the values.
+ //
+ KeyValues *GetFirstSubKey() { return m_pSub; } // returns the first subkey in the list
+ KeyValues *GetNextKey() { return m_pPeer; } // returns the next subkey
+ const KeyValues *GetNextKey() const { return m_pPeer; } // returns the next subkey
+
+ void SetNextKey( KeyValues * pDat);
+ KeyValues *FindLastSubKey(); // returns the LAST subkey in the list. This requires a linked list iteration to find the key. Returns NULL if we don't have any children
+
+ //
+ // These functions can be used to treat it like a true key/values tree instead of
+ // confusing values with keys.
+ //
+ // So if you wanted to iterate all subkeys, then all values, it would look like this:
+ // for ( KeyValues *pKey = pRoot->GetFirstTrueSubKey(); pKey; pKey = pKey->GetNextTrueSubKey() )
+ // {
+ // Msg( "Key name: %s\n", pKey->GetName() );
+ // }
+ // for ( KeyValues *pValue = pRoot->GetFirstValue(); pKey; pKey = pKey->GetNextValue() )
+ // {
+ // Msg( "Int value: %d\n", pValue->GetInt() ); // Assuming pValue->GetDataType() == TYPE_INT...
+ // }
+ KeyValues* GetFirstTrueSubKey();
+ KeyValues* GetNextTrueSubKey();
+
+ KeyValues* GetFirstValue(); // When you get a value back, you can use GetX and pass in NULL to get the value.
+ KeyValues* GetNextValue();
+
+
+ // Data access
+ int GetInt( const char *keyName = NULL, int defaultValue = 0 );
+ uint64 GetUint64( const char *keyName = NULL, uint64 defaultValue = 0 );
+ float GetFloat( const char *keyName = NULL, float defaultValue = 0.0f );
+ const char *GetString( const char *keyName = NULL, const char *defaultValue = "" );
+ const wchar_t *GetWString( const char *keyName = NULL, const wchar_t *defaultValue = L"" );
+ void *GetPtr( const char *keyName = NULL, void *defaultValue = (void*)0 );
+ bool GetBool( const char *keyName = NULL, bool defaultValue = false, bool* optGotDefault = NULL );
+ Color GetColor( const char *keyName = NULL /* default value is all black */);
+ bool IsEmpty(const char *keyName = NULL);
+
+ // Data access
+ int GetInt( int keySymbol, int defaultValue = 0 );
+ float GetFloat( int keySymbol, float defaultValue = 0.0f );
+ const char *GetString( int keySymbol, const char *defaultValue = "" );
+ const wchar_t *GetWString( int keySymbol, const wchar_t *defaultValue = L"" );
+ void *GetPtr( int keySymbol, void *defaultValue = (void*)0 );
+ Color GetColor( int keySymbol /* default value is all black */);
+ bool IsEmpty( int keySymbol );
+
+ // Key writing
+ void SetWString( const char *keyName, const wchar_t *value );
+ void SetString( const char *keyName, const char *value );
+ void SetInt( const char *keyName, int value );
+ void SetUint64( const char *keyName, uint64 value );
+ void SetFloat( const char *keyName, float value );
+ void SetPtr( const char *keyName, void *value );
+ void SetColor( const char *keyName, Color value);
+ void SetBool( const char *keyName, bool value ) { SetInt( keyName, value ? 1 : 0 ); }
+
+ // Memory allocation (optimized)
+ void *operator new( size_t iAllocSize );
+ void *operator new( size_t iAllocSize, int nBlockUse, const char *pFileName, int nLine );
+ void operator delete( void *pMem );
+ void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine );
+
+ KeyValues& operator=( const KeyValues& src );
+
+ // Adds a chain... if we don't find stuff in this keyvalue, we'll look
+ // in the one we're chained to.
+ void ChainKeyValue( KeyValues* pChain );
+
+ void RecursiveSaveToFile( CUtlBuffer& buf, int indentLevel, bool sortKeys = false, bool bAllowEmptyString = false );
+
+ bool WriteAsBinary( CUtlBuffer &buffer );
+ bool ReadAsBinary( CUtlBuffer &buffer, int nStackDepth = 0 );
+
+ // Allocate & create a new copy of the keys
+ KeyValues *MakeCopy( void ) const;
+
+ // Allocate & create a new copy of the keys, including the next keys. This is useful for top level files
+ // that don't use the usual convention of a root key with lots of children (like soundscape files).
+ KeyValues *MakeCopy( bool copySiblings ) const;
+
+ // Make a new copy of all subkeys, add them all to the passed-in keyvalues
+ void CopySubkeys( KeyValues *pParent ) const;
+
+ // Clear out all subkeys, and the current value
+ void Clear( void );
+
+ // Data type
+ enum types_t
+ {
+ TYPE_NONE = 0,
+ TYPE_STRING,
+ TYPE_INT,
+ TYPE_FLOAT,
+ TYPE_PTR,
+ TYPE_WSTRING,
+ TYPE_COLOR,
+ TYPE_UINT64,
+ TYPE_NUMTYPES,
+ };
+ types_t GetDataType(const char *keyName = NULL);
+
+ // Virtual deletion function - ensures that KeyValues object is deleted from correct heap
+ void deleteThis();
+
+ void SetStringValue( char const *strValue );
+
+ // unpack a key values list into a structure
+ void UnpackIntoStructure( struct KeyValuesUnpackStructure const *pUnpackTable, void *pDest, size_t DestSizeInBytes );
+
+ // Process conditional keys for widescreen support.
+ bool ProcessResolutionKeys( const char *pResString );
+
+ // Dump keyvalues recursively into a dump context
+ bool Dump( class IKeyValuesDumpContext *pDump, int nIndentLevel = 0, bool bSorted = false );
+
+ // Merge in another KeyValues, keeping "our" settings
+ void RecursiveMergeKeyValues( KeyValues *baseKV );
+
+ void AddSubkeyUsingKnownLastChild( KeyValues *pSubKey, KeyValues *pLastChild );
+
+private:
+ KeyValues( KeyValues& ); // prevent copy constructor being used
+
+ // prevent delete being called except through deleteThis()
+ ~KeyValues();
+
+ KeyValues* CreateKey( const char *keyName );
+
+ /// Create a child key, given that we know which child is currently the last child.
+ /// This avoids the O(N^2) behaviour when adding children in sequence to KV,
+ /// when CreateKey() wil have to re-locate the end of the list each time. This happens,
+ /// for example, every time we load any KV file whatsoever.
+ KeyValues* CreateKeyUsingKnownLastChild( const char *keyName, KeyValues *pLastChild );
+
+ void CopyKeyValuesFromRecursive( const KeyValues& src );
+ void CopyKeyValue( const KeyValues& src, size_t tmpBufferSizeB, char* tmpBuffer );
+
+ void RemoveEverything();
+// void RecursiveSaveToFile( IBaseFileSystem *filesystem, CUtlBuffer &buffer, int indentLevel );
+// void WriteConvertedString( CUtlBuffer &buffer, const char *pszString );
+
+ // NOTE: If both filesystem and pBuf are non-null, it'll save to both of them.
+ // If filesystem is null, it'll ignore f.
+ void RecursiveSaveToFile( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel, bool sortKeys, bool bAllowEmptyString );
+ void SaveKeyToFile( KeyValues *dat, IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel, bool sortKeys, bool bAllowEmptyString );
+ void WriteConvertedString( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const char *pszString );
+
+ void RecursiveLoadFromBuffer( char const *resourceName, CUtlBuffer &buf );
+
+ // For handling #include "filename"
+ void AppendIncludedKeys( CUtlVector< KeyValues * >& includedKeys );
+ void ParseIncludedKeys( char const *resourceName, const char *filetoinclude,
+ IBaseFileSystem* pFileSystem, const char *pPathID, CUtlVector< KeyValues * >& includedKeys );
+
+ // For handling #base "filename"
+ void MergeBaseKeys( CUtlVector< KeyValues * >& baseKeys );
+
+ // NOTE: If both filesystem and pBuf are non-null, it'll save to both of them.
+ // If filesystem is null, it'll ignore f.
+ void InternalWrite( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const void *pData, int len );
+
+ void Init();
+ const char * ReadToken( CUtlBuffer &buf, bool &wasQuoted, bool &wasConditional );
+ void WriteIndents( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel );
+
+ void FreeAllocatedValue();
+ void AllocateValueBlock(int size);
+
+ int m_iKeyName; // keyname is a symbol defined in KeyValuesSystem
+
+ // These are needed out of the union because the API returns string pointers
+ char *m_sValue;
+ wchar_t *m_wsValue;
+
+ // we don't delete these
+ union
+ {
+ int m_iValue;
+ float m_flValue;
+ void *m_pValue;
+ unsigned char m_Color[4];
+ };
+
+ char m_iDataType;
+ char m_bHasEscapeSequences; // true, if while parsing this KeyValue, Escape Sequences are used (default false)
+ char m_bEvaluateConditionals; // true, if while parsing this KeyValue, conditionals blocks are evaluated (default true)
+ char unused[1];
+
+ KeyValues *m_pPeer; // pointer to next key in list
+ KeyValues *m_pSub; // pointer to Start of a new sub key list
+ KeyValues *m_pChain;// Search here if it's not in our list
+
+private:
+ // Statics to implement the optional growable string table
+ // Function pointers that will determine which mode we are in
+ static int (*s_pfGetSymbolForString)( const char *name, bool bCreate );
+ static const char *(*s_pfGetStringForSymbol)( int symbol );
+ static CKeyValuesGrowableStringTable *s_pGrowableStringTable;
+
+public:
+ // Functions that invoke the default behavior
+ static int GetSymbolForStringClassic( const char *name, bool bCreate = true );
+ static const char *GetStringForSymbolClassic( int symbol );
+
+ // Functions that use the growable string table
+ static int GetSymbolForStringGrowable( const char *name, bool bCreate = true );
+ static const char *GetStringForSymbolGrowable( int symbol );
+
+ // Functions to get external access to whichever of the above functions we're going to call.
+ static int CallGetSymbolForString( const char *name, bool bCreate = true ) { return s_pfGetSymbolForString( name, bCreate ); }
+ static const char *CallGetStringForSymbol( int symbol ) { return s_pfGetStringForSymbol( symbol ); }
+};
+
+typedef KeyValues::AutoDelete KeyValuesAD;
+
+enum KeyValuesUnpackDestinationTypes_t
+{
+ UNPACK_TYPE_FLOAT, // dest is a float
+ UNPACK_TYPE_VECTOR, // dest is a Vector
+ UNPACK_TYPE_VECTOR_COLOR, // dest is a vector, src is a color
+ UNPACK_TYPE_STRING, // dest is a char *. unpacker will allocate.
+ UNPACK_TYPE_INT, // dest is an int
+ UNPACK_TYPE_FOUR_FLOATS, // dest is an array of 4 floats. source is a string like "1 2 3 4"
+ UNPACK_TYPE_TWO_FLOATS, // dest is an array of 2 floats. source is a string like "1 2"
+};
+
+#define UNPACK_FIXED( kname, kdefault, dtype, ofs ) { kname, kdefault, dtype, ofs, 0 }
+#define UNPACK_VARIABLE( kname, kdefault, dtype, ofs, sz ) { kname, kdefault, dtype, ofs, sz }
+#define UNPACK_END_MARKER { NULL, NULL, UNPACK_TYPE_FLOAT, 0 }
+
+struct KeyValuesUnpackStructure
+{
+ char const *m_pKeyName; // null to terminate tbl
+ char const *m_pKeyDefault; // null ok
+ KeyValuesUnpackDestinationTypes_t m_eDataType; // UNPACK_TYPE_INT, ..
+ size_t m_nFieldOffset; // use offsetof to set
+ size_t m_nFieldSize; // for strings or other variable length
+};
+
+//-----------------------------------------------------------------------------
+// inline methods
+//-----------------------------------------------------------------------------
+inline int KeyValues::GetInt( int keySymbol, int defaultValue )
+{
+ KeyValues *dat = FindKey( keySymbol );
+ return dat ? dat->GetInt( (const char *)NULL, defaultValue ) : defaultValue;
+}
+
+inline float KeyValues::GetFloat( int keySymbol, float defaultValue )
+{
+ KeyValues *dat = FindKey( keySymbol );
+ return dat ? dat->GetFloat( (const char *)NULL, defaultValue ) : defaultValue;
+}
+
+inline const char *KeyValues::GetString( int keySymbol, const char *defaultValue )
+{
+ KeyValues *dat = FindKey( keySymbol );
+ return dat ? dat->GetString( (const char *)NULL, defaultValue ) : defaultValue;
+}
+
+inline const wchar_t *KeyValues::GetWString( int keySymbol, const wchar_t *defaultValue )
+{
+ KeyValues *dat = FindKey( keySymbol );
+ return dat ? dat->GetWString( (const char *)NULL, defaultValue ) : defaultValue;
+}
+
+inline void *KeyValues::GetPtr( int keySymbol, void *defaultValue )
+{
+ KeyValues *dat = FindKey( keySymbol );
+ return dat ? dat->GetPtr( (const char *)NULL, defaultValue ) : defaultValue;
+}
+
+inline Color KeyValues::GetColor( int keySymbol )
+{
+ Color defaultValue( 0, 0, 0, 0 );
+ KeyValues *dat = FindKey( keySymbol );
+ return dat ? dat->GetColor( ) : defaultValue;
+}
+
+inline bool KeyValues::IsEmpty( int keySymbol )
+{
+ KeyValues *dat = FindKey( keySymbol );
+ return dat ? dat->IsEmpty( ) : true;
+}
+
+bool EvaluateConditional( const char *str );
+
+class CUtlSortVectorKeyValuesByName
+{
+public:
+ bool Less( const KeyValues* lhs, const KeyValues* rhs, void * )
+ {
+ return Q_stricmp( lhs->GetName(), rhs->GetName() ) < 0;
+ }
+};
+
+//
+// KeyValuesDumpContext and generic implementations
+//
+
+class IKeyValuesDumpContext
+{
+public:
+ virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel ) = 0;
+ virtual bool KvWriteValue( KeyValues *pValue, int nIndentLevel ) = 0;
+ virtual bool KvEndKey( KeyValues *pKey, int nIndentLevel ) = 0;
+};
+
+class IKeyValuesDumpContextAsText : public IKeyValuesDumpContext
+{
+public:
+ virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel );
+ virtual bool KvWriteValue( KeyValues *pValue, int nIndentLevel );
+ virtual bool KvEndKey( KeyValues *pKey, int nIndentLevel );
+
+public:
+ virtual bool KvWriteIndent( int nIndentLevel );
+ virtual bool KvWriteText( char const *szText ) = 0;
+};
+
+class CKeyValuesDumpContextAsDevMsg : public IKeyValuesDumpContextAsText
+{
+public:
+ // Overrides developer level to dump in DevMsg, zero to dump as Msg
+ CKeyValuesDumpContextAsDevMsg( int nDeveloperLevel = 1 ) : m_nDeveloperLevel( nDeveloperLevel ) {}
+
+public:
+ virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel );
+ virtual bool KvWriteText( char const *szText );
+
+protected:
+ int m_nDeveloperLevel;
+};
+
+inline bool KeyValuesDumpAsDevMsg( KeyValues *pKeyValues, int nIndentLevel = 0, int nDeveloperLevel = 1 )
+{
+ CKeyValuesDumpContextAsDevMsg ctx( nDeveloperLevel );
+ return pKeyValues->Dump( &ctx, nIndentLevel );
+}
+
+#endif // KEYVALUES_H
diff --git a/public/tier1/UtlSortVector.h b/public/tier1/UtlSortVector.h
new file mode 100644
index 0000000..9890c60
--- /dev/null
+++ b/public/tier1/UtlSortVector.h
@@ -0,0 +1,414 @@
+//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
+//
+// $Header: $
+// $NoKeywords: $
+//
+// A growable array class that keeps all elements in order using binary search
+//===========================================================================//
+
+#ifndef UTLSORTVECTOR_H
+#define UTLSORTVECTOR_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "utlvector.h"
+
+
+//-----------------------------------------------------------------------------
+// class CUtlSortVector:
+// description:
+// This in an sorted order-preserving vector. Items may be inserted or removed
+// at any point in the vector. When an item is inserted, all elements are
+// moved down by one element using memmove. When an item is removed, all
+// elements are shifted back down. Items are searched for in the vector
+// using a binary search technique. Clients must pass in a Less() function
+// into the constructor of the vector to determine the sort order.
+//-----------------------------------------------------------------------------
+
+#ifndef _WIN32
+// gcc has no qsort_s, so i need to use a static var to hold the sort context. this makes cutlsortvector _not_ thread sfae under linux
+extern void *g_pUtlSortVectorQSortContext;
+#endif
+
+template <class T>
+class CUtlSortVectorDefaultLess
+{
+public:
+ bool Less( const T& lhs, const T& rhs, void * )
+ {
+ return lhs < rhs;
+ }
+};
+
+template <class T, class LessFunc = CUtlSortVectorDefaultLess<T>, class BaseVector = CUtlVector<T> >
+class CUtlSortVector : public BaseVector
+{
+ typedef BaseVector BaseClass;
+public:
+ /// constructor
+ CUtlSortVector( int nGrowSize = 0, int initSize = 0 );
+ CUtlSortVector( T* pMemory, int numElements );
+
+ /// inserts (copy constructs) an element in sorted order into the list
+ int Insert( const T& src );
+
+ /// inserts (copy constructs) an element in sorted order into the list if it isn't already in the list
+ int InsertIfNotFound( const T& src );
+
+ /// Finds an element within the list using a binary search. These are templatized based upon the key
+ /// in which case the less function must handle the Less function for key, T and T, key
+ template< typename TKey >
+ int Find( const TKey& search ) const;
+ template< typename TKey >
+ int FindLessOrEqual( const TKey& search ) const;
+ template< typename TKey >
+ int FindLess( const TKey& search ) const;
+
+ /// Removes a particular element
+ void Remove( const T& search );
+ void Remove( int i );
+
+ /// Allows methods to set a context to be used with the less function..
+ void SetLessContext( void *pCtx );
+
+ /// A version of insertion that will produce an un-ordered list.
+ /// Note that you can only use this index until sorting is redone with RedoSort!!!
+ int InsertNoSort( const T& src );
+ void RedoSort( bool bForceSort = false );
+
+ /// Use this to insert at a specific insertion point; using FindLessOrEqual
+ /// is required for use this this. This will test that what you've inserted
+ /// produces a correctly ordered list.
+ int InsertAfter( int nElemIndex, const T &src );
+
+ /// finds a particular element using a linear search. Useful when used
+ /// in between calls to InsertNoSort and RedoSort
+ template< typename TKey >
+ int FindUnsorted( const TKey &src ) const;
+
+protected:
+ // No copy constructor
+ CUtlSortVector( const CUtlSortVector<T, LessFunc> & );
+
+ // never call these; illegal for this class
+ int AddToHead();
+ int AddToTail();
+ int InsertBefore( int elem );
+ int InsertAfter( int elem );
+ int InsertBefore( int elem, const T& src );
+ int AddToHead( const T& src );
+ int AddToTail( const T& src );
+ int AddMultipleToHead( int num );
+ int AddMultipleToTail( int num, const T *pToCopy=NULL );
+ int InsertMultipleBefore( int elem, int num, const T *pToCopy=NULL );
+ int InsertMultipleAfter( int elem, int num );
+ int AddVectorToTail( CUtlVector<T> const &src );
+
+ struct QSortContext_t
+ {
+ void *m_pLessContext;
+ LessFunc *m_pLessFunc;
+ };
+
+#ifdef _WIN32
+ static int CompareHelper( void *context, const T *lhs, const T *rhs )
+ {
+ QSortContext_t *ctx = reinterpret_cast< QSortContext_t * >( context );
+ if ( ctx->m_pLessFunc->Less( *lhs, *rhs, ctx->m_pLessContext ) )
+ return -1;
+ if ( ctx->m_pLessFunc->Less( *rhs, *lhs, ctx->m_pLessContext ) )
+ return 1;
+ return 0;
+ }
+#else
+ static int CompareHelper( const T *lhs, const T *rhs )
+ {
+ QSortContext_t *ctx = reinterpret_cast< QSortContext_t * >( g_pUtlSortVectorQSortContext );
+ if ( ctx->m_pLessFunc->Less( *lhs, *rhs, ctx->m_pLessContext ) )
+ return -1;
+ if ( ctx->m_pLessFunc->Less( *rhs, *lhs, ctx->m_pLessContext ) )
+ return 1;
+ return 0;
+ }
+#endif
+
+ void *m_pLessContext;
+ bool m_bNeedsSort;
+
+private:
+ template< typename TKey >
+ int FindLessOrEqual( const TKey& search, bool *pFound ) const;
+
+ void QuickSort( LessFunc& less, int X, int I );
+};
+
+
+//-----------------------------------------------------------------------------
+// constructor
+//-----------------------------------------------------------------------------
+template <class T, class LessFunc, class BaseVector>
+CUtlSortVector<T, LessFunc, BaseVector>::CUtlSortVector( int nGrowSize, int initSize ) :
+ m_pLessContext(NULL), BaseVector( nGrowSize, initSize ), m_bNeedsSort( false )
+{
+}
+
+template <class T, class LessFunc, class BaseVector>
+CUtlSortVector<T, LessFunc, BaseVector>::CUtlSortVector( T* pMemory, int numElements ) :
+ m_pLessContext(NULL), BaseVector( pMemory, numElements ), m_bNeedsSort( false )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Allows methods to set a context to be used with the less function..
+//-----------------------------------------------------------------------------
+template <class T, class LessFunc, class BaseVector>
+void CUtlSortVector<T, LessFunc, BaseVector>::SetLessContext( void *pCtx )
+{
+ m_pLessContext = pCtx;
+}
+
+//-----------------------------------------------------------------------------
+// grows the vector
+//-----------------------------------------------------------------------------
+template <class T, class LessFunc, class BaseVector>
+int CUtlSortVector<T, LessFunc, BaseVector>::Insert( const T& src )
+{
+ AssertFatal( !m_bNeedsSort );
+
+ int pos = FindLessOrEqual( src ) + 1;
+ this->GrowVector();
+ this->ShiftElementsRight(pos);
+ CopyConstruct<T>( &this->Element(pos), src );
+ return pos;
+}
+
+template <class T, class LessFunc, class BaseVector>
+int CUtlSortVector<T, LessFunc, BaseVector>::InsertNoSort( const T& src )
+{
+ m_bNeedsSort = true;
+ int lastElement = BaseVector::m_Size;
+ // Just stick the new element at the end of the vector, but don't do a sort
+ this->GrowVector();
+ this->ShiftElementsRight(lastElement);
+ CopyConstruct( &this->Element(lastElement), src );
+ return lastElement;
+}
+
+/// inserts (copy constructs) an element in sorted order into the list if it isn't already in the list
+template <class T, class LessFunc, class BaseVector>
+int CUtlSortVector<T, LessFunc, BaseVector>::InsertIfNotFound( const T& src )
+{
+ AssertFatal( !m_bNeedsSort );
+ bool bFound;
+ int pos = FindLessOrEqual( src, &bFound );
+ if ( bFound )
+ return pos;
+
+ ++pos;
+ this->GrowVector();
+ this->ShiftElementsRight(pos);
+ CopyConstruct<T>( &this->Element(pos), src );
+ return pos;
+}
+
+template <class T, class LessFunc, class BaseVector>
+int CUtlSortVector<T, LessFunc, BaseVector>::InsertAfter( int nIndex, const T &src )
+{
+ int nInsertedIndex = this->BaseClass::InsertAfter( nIndex, src );
+
+#ifdef DEBUG
+ LessFunc less;
+ if ( nInsertedIndex > 0 )
+ {
+ Assert( less.Less( this->Element(nInsertedIndex-1), src, m_pLessContext ) );
+ }
+ if ( nInsertedIndex < BaseClass::Count()-1 )
+ {
+ Assert( less.Less( src, this->Element(nInsertedIndex+1), m_pLessContext ) );
+ }
+#endif
+ return nInsertedIndex;
+}
+
+
+template <class T, class LessFunc, class BaseVector>
+void CUtlSortVector<T, LessFunc, BaseVector>::QuickSort( LessFunc& less, int nLower, int nUpper )
+{
+#ifdef _WIN32
+ typedef int (__cdecl *QSortCompareFunc_t)(void *context, const void *, const void *);
+ if ( this->Count() > 1 )
+ {
+ QSortContext_t ctx;
+ ctx.m_pLessContext = m_pLessContext;
+ ctx.m_pLessFunc = &less;
+
+ qsort_s( Base(), Count(), sizeof(T), (QSortCompareFunc_t)&CUtlSortVector<T, LessFunc>::CompareHelper, &ctx );
+ }
+#else
+ typedef int (__cdecl *QSortCompareFunc_t)( const void *, const void *);
+ if ( this->Count() > 1 )
+ {
+ QSortContext_t ctx;
+ ctx.m_pLessContext = m_pLessContext;
+ ctx.m_pLessFunc = &less;
+ g_pUtlSortVectorQSortContext = &ctx;
+
+ qsort( this->Base(), this->Count(), sizeof(T), (QSortCompareFunc_t)&CUtlSortVector<T, LessFunc>::CompareHelper );
+ }
+#endif
+}
+
+template <class T, class LessFunc, class BaseVector>
+void CUtlSortVector<T, LessFunc, BaseVector>::RedoSort( bool bForceSort /*= false */ )
+{
+ if ( !m_bNeedsSort && !bForceSort )
+ return;
+
+ m_bNeedsSort = false;
+ LessFunc less;
+ QuickSort( less, 0, this->Count() - 1 );
+}
+
+//-----------------------------------------------------------------------------
+// finds a particular element
+//-----------------------------------------------------------------------------
+template <class T, class LessFunc, class BaseVector>
+template < typename TKey >
+int CUtlSortVector<T, LessFunc, BaseVector>::Find( const TKey& src ) const
+{
+ AssertFatal( !m_bNeedsSort );
+
+ LessFunc less;
+
+ int start = 0, end = this->Count() - 1;
+ while (start <= end)
+ {
+ int mid = (start + end) >> 1;
+ if ( less.Less( this->Element(mid), src, m_pLessContext ) )
+ {
+ start = mid + 1;
+ }
+ else if ( less.Less( src, this->Element(mid), m_pLessContext ) )
+ {
+ end = mid - 1;
+ }
+ else
+ {
+ return mid;
+ }
+ }
+ return -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// finds a particular element using a linear search. Useful when used
+// in between calls to InsertNoSort and RedoSort
+//-----------------------------------------------------------------------------
+template< class T, class LessFunc, class BaseVector >
+template < typename TKey >
+int CUtlSortVector<T, LessFunc, BaseVector>::FindUnsorted( const TKey &src ) const
+{
+ LessFunc less;
+ int nCount = this->Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ if ( less.Less( this->Element(i), src, m_pLessContext ) )
+ continue;
+ if ( less.Less( src, this->Element(i), m_pLessContext ) )
+ continue;
+ return i;
+ }
+ return -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// finds a particular element
+//-----------------------------------------------------------------------------
+template <class T, class LessFunc, class BaseVector>
+template < typename TKey >
+int CUtlSortVector<T, LessFunc, BaseVector>::FindLessOrEqual( const TKey& src, bool *pFound ) const
+{
+ AssertFatal( !m_bNeedsSort );
+
+ LessFunc less;
+ int start = 0, end = this->Count() - 1;
+ while (start <= end)
+ {
+ int mid = (start + end) >> 1;
+ if ( less.Less( this->Element(mid), src, m_pLessContext ) )
+ {
+ start = mid + 1;
+ }
+ else if ( less.Less( src, this->Element(mid), m_pLessContext ) )
+ {
+ end = mid - 1;
+ }
+ else
+ {
+ *pFound = true;
+ return mid;
+ }
+ }
+
+ *pFound = false;
+ return end;
+}
+
+template <class T, class LessFunc, class BaseVector>
+template < typename TKey >
+int CUtlSortVector<T, LessFunc, BaseVector>::FindLessOrEqual( const TKey& src ) const
+{
+ bool bFound;
+ return FindLessOrEqual( src, &bFound );
+}
+
+template <class T, class LessFunc, class BaseVector>
+template < typename TKey >
+int CUtlSortVector<T, LessFunc, BaseVector>::FindLess( const TKey& src ) const
+{
+ AssertFatal( !m_bNeedsSort );
+
+ LessFunc less;
+ int start = 0, end = this->Count() - 1;
+ while (start <= end)
+ {
+ int mid = (start + end) >> 1;
+ if ( less.Less( this->Element(mid), src, m_pLessContext ) )
+ {
+ start = mid + 1;
+ }
+ else
+ {
+ end = mid - 1;
+ }
+ }
+ return end;
+}
+
+
+//-----------------------------------------------------------------------------
+// Removes a particular element
+//-----------------------------------------------------------------------------
+template <class T, class LessFunc, class BaseVector>
+void CUtlSortVector<T, LessFunc, BaseVector>::Remove( const T& search )
+{
+ AssertFatal( !m_bNeedsSort );
+
+ int pos = Find(search);
+ if (pos != -1)
+ {
+ BaseVector::Remove(pos);
+ }
+}
+
+template <class T, class LessFunc, class BaseVector>
+void CUtlSortVector<T, LessFunc, BaseVector>::Remove( int i )
+{
+ BaseVector::Remove( i );
+}
+
+#endif // UTLSORTVECTOR_H
diff --git a/public/tier1/UtlStringMap.h b/public/tier1/UtlStringMap.h
new file mode 100644
index 0000000..59d5c23
--- /dev/null
+++ b/public/tier1/UtlStringMap.h
@@ -0,0 +1,99 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef UTLSTRINGMAP_H
+#define UTLSTRINGMAP_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "utlsymbol.h"
+
+template <class T>
+class CUtlStringMap
+{
+public:
+ CUtlStringMap( bool caseInsensitive = true ) : m_SymbolTable( 0, 32, caseInsensitive )
+ {
+ }
+
+ // Get data by the string itself:
+ T& operator[]( const char *pString )
+ {
+ CUtlSymbol symbol = m_SymbolTable.AddString( pString );
+ int index = ( int )( UtlSymId_t )symbol;
+ if( m_Vector.Count() <= index )
+ {
+ m_Vector.EnsureCount( index + 1 );
+ }
+ return m_Vector[index];
+ }
+
+ // Get data by the string's symbol table ID - only used to retrieve a pre-existing symbol, not create a new one!
+ T& operator[]( UtlSymId_t n )
+ {
+ Assert( n >=0 && n <= m_Vector.Count() );
+ return m_Vector[n];
+ }
+
+ const T& operator[]( UtlSymId_t n ) const
+ {
+ Assert( n >=0 && n <= m_Vector.Count() );
+ return m_Vector[n];
+ }
+
+ bool Defined( const char *pString ) const
+ {
+ return m_SymbolTable.Find( pString ) != UTL_INVAL_SYMBOL;
+ }
+
+ UtlSymId_t Find( const char *pString ) const
+ {
+ return m_SymbolTable.Find( pString );
+ }
+
+ static UtlSymId_t InvalidIndex()
+ {
+ return UTL_INVAL_SYMBOL;
+ }
+
+ int GetNumStrings( void ) const
+ {
+ return m_SymbolTable.GetNumStrings();
+ }
+
+ const char *String( int n ) const
+ {
+ return m_SymbolTable.String( n );
+ }
+
+ // Clear all of the data from the map
+ void Clear()
+ {
+ m_Vector.RemoveAll();
+ m_SymbolTable.RemoveAll();
+ }
+
+ void Purge()
+ {
+ m_Vector.Purge();
+ m_SymbolTable.RemoveAll();
+ }
+
+ void PurgeAndDeleteElements()
+ {
+ m_Vector.PurgeAndDeleteElements();
+ m_SymbolTable.RemoveAll();
+ }
+
+
+
+private:
+ CUtlVector<T> m_Vector;
+ CUtlSymbolTable m_SymbolTable;
+};
+
+#endif // UTLSTRINGMAP_H
diff --git a/public/tier1/bitbuf.h b/public/tier1/bitbuf.h
new file mode 100644
index 0000000..b92e010
--- /dev/null
+++ b/public/tier1/bitbuf.h
@@ -0,0 +1,809 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+// NOTE: bf_read is guaranteed to return zeros if it overflows.
+
+#ifndef BITBUF_H
+#define BITBUF_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "mathlib/mathlib.h"
+#include "mathlib/vector.h"
+#include "basetypes.h"
+#include "tier0/dbg.h"
+
+
+#if _DEBUG
+#define BITBUF_INLINE inline
+#else
+#define BITBUF_INLINE FORCEINLINE
+#endif
+
+//-----------------------------------------------------------------------------
+// Forward declarations.
+//-----------------------------------------------------------------------------
+
+class Vector;
+class QAngle;
+
+//-----------------------------------------------------------------------------
+// You can define a handler function that will be called in case of
+// out-of-range values and overruns here.
+//
+// NOTE: the handler is only called in debug mode.
+//
+// Call SetBitBufErrorHandler to install a handler.
+//-----------------------------------------------------------------------------
+
+typedef enum
+{
+ BITBUFERROR_VALUE_OUT_OF_RANGE=0, // Tried to write a value with too few bits.
+ BITBUFERROR_BUFFER_OVERRUN, // Was about to overrun a buffer.
+
+ BITBUFERROR_NUM_ERRORS
+} BitBufErrorType;
+
+
+typedef void (*BitBufErrorHandler)( BitBufErrorType errorType, const char *pDebugName );
+
+
+#if defined( _DEBUG )
+ extern void InternalBitBufErrorHandler( BitBufErrorType errorType, const char *pDebugName );
+ #define CallErrorHandler( errorType, pDebugName ) InternalBitBufErrorHandler( errorType, pDebugName );
+#else
+ #define CallErrorHandler( errorType, pDebugName )
+#endif
+
+
+// Use this to install the error handler. Call with NULL to uninstall your error handler.
+void SetBitBufErrorHandler( BitBufErrorHandler fn );
+
+
+//-----------------------------------------------------------------------------
+// Helpers.
+//-----------------------------------------------------------------------------
+
+inline int BitByte( int bits )
+{
+ // return PAD_NUMBER( bits, 8 ) >> 3;
+ return (bits + 7) >> 3;
+}
+
+//-----------------------------------------------------------------------------
+// namespaced helpers
+//-----------------------------------------------------------------------------
+namespace bitbuf
+{
+ // ZigZag Transform: Encodes signed integers so that they can be
+ // effectively used with varint encoding.
+ //
+ // varint operates on unsigned integers, encoding smaller numbers into
+ // fewer bytes. If you try to use it on a signed integer, it will treat
+ // this number as a very large unsigned integer, which means that even
+ // small signed numbers like -1 will take the maximum number of bytes
+ // (10) to encode. ZigZagEncode() maps signed integers to unsigned
+ // in such a way that those with a small absolute value will have smaller
+ // encoded values, making them appropriate for encoding using varint.
+ //
+ // int32 -> uint32
+ // -------------------------
+ // 0 -> 0
+ // -1 -> 1
+ // 1 -> 2
+ // -2 -> 3
+ // ... -> ...
+ // 2147483647 -> 4294967294
+ // -2147483648 -> 4294967295
+ //
+ // >> encode >>
+ // << decode <<
+
+ inline uint32 ZigZagEncode32(int32 n)
+ {
+ // Note: the right-shift must be arithmetic
+ return(n << 1) ^ (n >> 31);
+ }
+
+ inline int32 ZigZagDecode32(uint32 n)
+ {
+ return(n >> 1) ^ -static_cast<int32>(n & 1);
+ }
+
+ inline uint64 ZigZagEncode64(int64 n)
+ {
+ // Note: the right-shift must be arithmetic
+ return(n << 1) ^ (n >> 63);
+ }
+
+ inline int64 ZigZagDecode64(uint64 n)
+ {
+ return(n >> 1) ^ -static_cast<int64>(n & 1);
+ }
+
+ const int kMaxVarintBytes = 10;
+ const int kMaxVarint32Bytes = 5;
+}
+
+//-----------------------------------------------------------------------------
+// Used for serialization
+//-----------------------------------------------------------------------------
+
+class bf_write
+{
+public:
+ bf_write();
+
+ // nMaxBits can be used as the number of bits in the buffer.
+ // It must be <= nBytes*8. If you leave it at -1, then it's set to nBytes * 8.
+ bf_write( void *pData, int nBytes, int nMaxBits = -1 );
+ bf_write( const char *pDebugName, void *pData, int nBytes, int nMaxBits = -1 );
+
+ // Start writing to the specified buffer.
+ // nMaxBits can be used as the number of bits in the buffer.
+ // It must be <= nBytes*8. If you leave it at -1, then it's set to nBytes * 8.
+ void StartWriting( void *pData, int nBytes, int iStartBit = 0, int nMaxBits = -1 );
+
+ // Restart buffer writing.
+ void Reset();
+
+ // Get the base pointer.
+ unsigned char* GetBasePointer() { return (unsigned char*) m_pData; }
+
+ // Enable or disable assertion on overflow. 99% of the time, it's a bug that we need to catch,
+ // but there may be the occasional buffer that is allowed to overflow gracefully.
+ void SetAssertOnOverflow( bool bAssert );
+
+ // This can be set to assign a name that gets output if the buffer overflows.
+ const char* GetDebugName();
+ void SetDebugName( const char *pDebugName );
+
+
+// Seek to a specific position.
+public:
+
+ void SeekToBit( int bitPos );
+
+
+// Bit functions.
+public:
+
+ void WriteOneBit(int nValue);
+ void WriteOneBitNoCheck(int nValue);
+ void WriteOneBitAt( int iBit, int nValue );
+
+ // Write signed or unsigned. Range is only checked in debug.
+ void WriteUBitLong( unsigned int data, int numbits, bool bCheckRange=true );
+ void WriteSBitLong( int data, int numbits );
+
+ // Tell it whether or not the data is unsigned. If it's signed,
+ // cast to unsigned before passing in (it will cast back inside).
+ void WriteBitLong(unsigned int data, int numbits, bool bSigned);
+
+ // Write a list of bits in.
+ bool WriteBits(const void *pIn, int nBits);
+
+ // writes an unsigned integer with variable bit length
+ void WriteUBitVar( unsigned int data );
+
+ // writes a varint encoded integer
+ void WriteVarInt32( uint32 data );
+ void WriteVarInt64( uint64 data );
+ void WriteSignedVarInt32( int32 data );
+ void WriteSignedVarInt64( int64 data );
+ int ByteSizeVarInt32( uint32 data );
+ int ByteSizeVarInt64( uint64 data );
+ int ByteSizeSignedVarInt32( int32 data );
+ int ByteSizeSignedVarInt64( int64 data );
+
+ // Copy the bits straight out of pIn. This seeks pIn forward by nBits.
+ // Returns an error if this buffer or the read buffer overflows.
+ bool WriteBitsFromBuffer( class bf_read *pIn, int nBits );
+
+ void WriteBitAngle( float fAngle, int numbits );
+ void WriteBitCoord (const float f);
+ void WriteBitCoordMP( const float f, bool bIntegral, bool bLowPrecision );
+ void WriteBitFloat(float val);
+ void WriteBitVec3Coord( const Vector& fa );
+ void WriteBitNormal( float f );
+ void WriteBitVec3Normal( const Vector& fa );
+ void WriteBitAngles( const QAngle& fa );
+
+
+// Byte functions.
+public:
+
+ void WriteChar(int val);
+ void WriteByte(int val);
+ void WriteShort(int val);
+ void WriteWord(int val);
+ void WriteLong(long val);
+ void WriteLongLong(int64 val);
+ void WriteFloat(float val);
+ bool WriteBytes( const void *pBuf, int nBytes );
+
+ // Returns false if it overflows the buffer.
+ bool WriteString(const char *pStr);
+
+
+// Status.
+public:
+
+ // How many bytes are filled in?
+ int GetNumBytesWritten() const;
+ int GetNumBitsWritten() const;
+ int GetMaxNumBits();
+ int GetNumBitsLeft();
+ int GetNumBytesLeft();
+ unsigned char* GetData();
+ const unsigned char* GetData() const;
+
+ // Has the buffer overflowed?
+ bool CheckForOverflow(int nBits);
+ inline bool IsOverflowed() const {return m_bOverflow;}
+
+ void SetOverflowFlag();
+
+
+public:
+ // The current buffer.
+ unsigned long* RESTRICT m_pData;
+ int m_nDataBytes;
+ int m_nDataBits;
+
+ // Where we are in the buffer.
+ int m_iCurBit;
+
+private:
+
+ // Errors?
+ bool m_bOverflow;
+
+ bool m_bAssertOnOverflow;
+ const char *m_pDebugName;
+};
+
+
+//-----------------------------------------------------------------------------
+// Inlined methods
+//-----------------------------------------------------------------------------
+
+// How many bytes are filled in?
+inline int bf_write::GetNumBytesWritten() const
+{
+ return BitByte(m_iCurBit);
+}
+
+inline int bf_write::GetNumBitsWritten() const
+{
+ return m_iCurBit;
+}
+
+inline int bf_write::GetMaxNumBits()
+{
+ return m_nDataBits;
+}
+
+inline int bf_write::GetNumBitsLeft()
+{
+ return m_nDataBits - m_iCurBit;
+}
+
+inline int bf_write::GetNumBytesLeft()
+{
+ return GetNumBitsLeft() >> 3;
+}
+
+inline unsigned char* bf_write::GetData()
+{
+ return (unsigned char*) m_pData;
+}
+
+inline const unsigned char* bf_write::GetData() const
+{
+ return (unsigned char*) m_pData;
+}
+
+BITBUF_INLINE bool bf_write::CheckForOverflow(int nBits)
+{
+ if ( m_iCurBit + nBits > m_nDataBits )
+ {
+ SetOverflowFlag();
+ CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() );
+ }
+
+ return m_bOverflow;
+}
+
+BITBUF_INLINE void bf_write::SetOverflowFlag()
+{
+#ifdef DBGFLAG_ASSERT
+ if ( m_bAssertOnOverflow )
+ {
+ Assert( false );
+ }
+#endif
+ m_bOverflow = true;
+}
+
+BITBUF_INLINE void bf_write::WriteOneBitNoCheck(int nValue)
+{
+#if __i386__
+ if(nValue)
+ m_pData[m_iCurBit >> 5] |= 1u << (m_iCurBit & 31);
+ else
+ m_pData[m_iCurBit >> 5] &= ~(1u << (m_iCurBit & 31));
+#else
+ extern unsigned long g_LittleBits[32];
+ if(nValue)
+ m_pData[m_iCurBit >> 5] |= g_LittleBits[m_iCurBit & 31];
+ else
+ m_pData[m_iCurBit >> 5] &= ~g_LittleBits[m_iCurBit & 31];
+#endif
+
+ ++m_iCurBit;
+}
+
+inline void bf_write::WriteOneBit(int nValue)
+{
+ if( m_iCurBit >= m_nDataBits )
+ {
+ SetOverflowFlag();
+ CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() );
+ return;
+ }
+ WriteOneBitNoCheck( nValue );
+}
+
+
+inline void bf_write::WriteOneBitAt( int iBit, int nValue )
+{
+ if( iBit >= m_nDataBits )
+ {
+ SetOverflowFlag();
+ CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() );
+ return;
+ }
+
+#if __i386__
+ if(nValue)
+ m_pData[iBit >> 5] |= 1u << (iBit & 31);
+ else
+ m_pData[iBit >> 5] &= ~(1u << (iBit & 31));
+#else
+ extern unsigned long g_LittleBits[32];
+ if(nValue)
+ m_pData[iBit >> 5] |= g_LittleBits[iBit & 31];
+ else
+ m_pData[iBit >> 5] &= ~g_LittleBits[iBit & 31];
+#endif
+}
+
+BITBUF_INLINE void bf_write::WriteUBitLong( unsigned int curData, int numbits, bool bCheckRange ) RESTRICT
+{
+#ifdef _DEBUG
+ // Make sure it doesn't overflow.
+ if ( bCheckRange && numbits < 32 )
+ {
+ if ( curData >= (unsigned long)(1 << numbits) )
+ {
+ CallErrorHandler( BITBUFERROR_VALUE_OUT_OF_RANGE, GetDebugName() );
+ }
+ }
+ Assert( numbits >= 0 && numbits <= 32 );
+#endif
+
+ if ( GetNumBitsLeft() < numbits )
+ {
+ m_iCurBit = m_nDataBits;
+ SetOverflowFlag();
+ CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() );
+ return;
+ }
+
+ int iCurBitMasked = m_iCurBit & 31;
+ int iDWord = m_iCurBit >> 5;
+ m_iCurBit += numbits;
+
+ // Mask in a dword.
+ Assert( (iDWord*4 + sizeof(long)) <= (unsigned int)m_nDataBytes );
+ unsigned long * RESTRICT pOut = &m_pData[iDWord];
+
+ // Rotate data into dword alignment
+ curData = (curData << iCurBitMasked) | (curData >> (32 - iCurBitMasked));
+
+ // Calculate bitmasks for first and second word
+ unsigned int temp = 1 << (numbits-1);
+ unsigned int mask1 = (temp*2-1) << iCurBitMasked;
+ unsigned int mask2 = (temp-1) >> (31 - iCurBitMasked);
+
+ // Only look beyond current word if necessary (avoid access violation)
+ int i = mask2 & 1;
+ unsigned long dword1 = LoadLittleDWord( pOut, 0 );
+ unsigned long dword2 = LoadLittleDWord( pOut, i );
+
+ // Drop bits into place
+ dword1 ^= ( mask1 & ( curData ^ dword1 ) );
+ dword2 ^= ( mask2 & ( curData ^ dword2 ) );
+
+ // Note reversed order of writes so that dword1 wins if mask2 == 0 && i == 0
+ StoreLittleDWord( pOut, i, dword2 );
+ StoreLittleDWord( pOut, 0, dword1 );
+}
+
+// writes an unsigned integer with variable bit length
+BITBUF_INLINE void bf_write::WriteUBitVar( unsigned int data )
+{
+ /* Reference:
+ if ( data < 0x10u )
+ WriteUBitLong( 0, 2 ), WriteUBitLong( data, 4 );
+ else if ( data < 0x100u )
+ WriteUBitLong( 1, 2 ), WriteUBitLong( data, 8 );
+ else if ( data < 0x1000u )
+ WriteUBitLong( 2, 2 ), WriteUBitLong( data, 12 );
+ else
+ WriteUBitLong( 3, 2 ), WriteUBitLong( data, 32 );
+ */
+ // a < b ? -1 : 0 translates into a CMP, SBB instruction pair
+ // with no flow control. should also be branchless on consoles.
+ int n = (data < 0x10u ? -1 : 0) + (data < 0x100u ? -1 : 0) + (data < 0x1000u ? -1 : 0);
+ WriteUBitLong( data*4 + n + 3, 6 + n*4 + 12 );
+ if ( data >= 0x1000u )
+ {
+ WriteUBitLong( data >> 16, 16 );
+ }
+}
+
+// write raw IEEE float bits in little endian form
+BITBUF_INLINE void bf_write::WriteBitFloat(float val)
+{
+ long intVal;
+
+ Assert(sizeof(long) == sizeof(float));
+ Assert(sizeof(float) == 4);
+
+ intVal = *((long*)&val);
+ WriteUBitLong( intVal, 32 );
+}
+
+//-----------------------------------------------------------------------------
+// This is useful if you just want a buffer to write into on the stack.
+//-----------------------------------------------------------------------------
+
+template<int SIZE>
+class old_bf_write_static : public bf_write
+{
+public:
+ inline old_bf_write_static() : bf_write(m_StaticData, SIZE) {}
+
+ char m_StaticData[SIZE];
+};
+
+
+
+//-----------------------------------------------------------------------------
+// Used for unserialization
+//-----------------------------------------------------------------------------
+
+class bf_read
+{
+public:
+ bf_read();
+
+ // nMaxBits can be used as the number of bits in the buffer.
+ // It must be <= nBytes*8. If you leave it at -1, then it's set to nBytes * 8.
+ bf_read( const void *pData, int nBytes, int nBits = -1 );
+ bf_read( const char *pDebugName, const void *pData, int nBytes, int nBits = -1 );
+
+ // Start reading from the specified buffer.
+ // pData's start address must be dword-aligned.
+ // nMaxBits can be used as the number of bits in the buffer.
+ // It must be <= nBytes*8. If you leave it at -1, then it's set to nBytes * 8.
+ void StartReading( const void *pData, int nBytes, int iStartBit = 0, int nBits = -1 );
+
+ // Restart buffer reading.
+ void Reset();
+
+ // Enable or disable assertion on overflow. 99% of the time, it's a bug that we need to catch,
+ // but there may be the occasional buffer that is allowed to overflow gracefully.
+ void SetAssertOnOverflow( bool bAssert );
+
+ // This can be set to assign a name that gets output if the buffer overflows.
+ const char* GetDebugName() const { return m_pDebugName; }
+ void SetDebugName( const char *pName );
+
+ void ExciseBits( int startbit, int bitstoremove );
+
+
+// Bit functions.
+public:
+
+ // Returns 0 or 1.
+ int ReadOneBit();
+
+
+protected:
+
+ unsigned int CheckReadUBitLong(int numbits); // For debugging.
+ int ReadOneBitNoCheck(); // Faster version, doesn't check bounds and is inlined.
+ bool CheckForOverflow(int nBits);
+
+
+public:
+
+ // Get the base pointer.
+ const unsigned char* GetBasePointer() { return m_pData; }
+
+ BITBUF_INLINE int TotalBytesAvailable( void ) const
+ {
+ return m_nDataBytes;
+ }
+
+ // Read a list of bits in.
+ void ReadBits(void *pOut, int nBits);
+ // Read a list of bits in, but don't overrun the destination buffer.
+ // Returns the number of bits read into the buffer. The remaining
+ // bits are skipped over.
+ int ReadBitsClamped_ptr(void *pOut, size_t outSizeBytes, size_t nBits);
+ // Helper 'safe' template function that infers the size of the destination
+ // array. This version of the function should be preferred.
+ // Usage: char databuffer[100];
+ // ReadBitsClamped( dataBuffer, msg->m_nLength );
+ template <typename T, size_t N>
+ int ReadBitsClamped( T (&pOut)[N], size_t nBits )
+ {
+ return ReadBitsClamped_ptr( pOut, N * sizeof(T), nBits );
+ }
+
+ float ReadBitAngle( int numbits );
+
+ unsigned int ReadUBitLong( int numbits ) RESTRICT;
+ unsigned int ReadUBitLongNoInline( int numbits ) RESTRICT;
+ unsigned int PeekUBitLong( int numbits );
+ int ReadSBitLong( int numbits );
+
+ // reads an unsigned integer with variable bit length
+ unsigned int ReadUBitVar();
+ unsigned int ReadUBitVarInternal( int encodingType );
+
+ // reads a varint encoded integer
+ uint32 ReadVarInt32();
+ uint64 ReadVarInt64();
+ int32 ReadSignedVarInt32();
+ int64 ReadSignedVarInt64();
+
+ // You can read signed or unsigned data with this, just cast to
+ // a signed int if necessary.
+ unsigned int ReadBitLong(int numbits, bool bSigned);
+
+ float ReadBitCoord();
+ float ReadBitCoordMP( bool bIntegral, bool bLowPrecision );
+ float ReadBitFloat();
+ float ReadBitNormal();
+ void ReadBitVec3Coord( Vector& fa );
+ void ReadBitVec3Normal( Vector& fa );
+ void ReadBitAngles( QAngle& fa );
+
+ // Faster for comparisons but do not fully decode float values
+ unsigned int ReadBitCoordBits();
+ unsigned int ReadBitCoordMPBits( bool bIntegral, bool bLowPrecision );
+
+// Byte functions (these still read data in bit-by-bit).
+public:
+
+ BITBUF_INLINE int ReadChar() { return (char)ReadUBitLong(8); }
+ BITBUF_INLINE int ReadByte() { return ReadUBitLong(8); }
+ BITBUF_INLINE int ReadShort() { return (short)ReadUBitLong(16); }
+ BITBUF_INLINE int ReadWord() { return ReadUBitLong(16); }
+ BITBUF_INLINE long ReadLong() { return ReadUBitLong(32); }
+ int64 ReadLongLong();
+ float ReadFloat();
+ bool ReadBytes(void *pOut, int nBytes);
+
+ // Returns false if bufLen isn't large enough to hold the
+ // string in the buffer.
+ //
+ // Always reads to the end of the string (so you can read the
+ // next piece of data waiting).
+ //
+ // If bLine is true, it stops when it reaches a '\n' or a null-terminator.
+ //
+ // pStr is always null-terminated (unless bufLen is 0).
+ //
+ // pOutNumChars is set to the number of characters left in pStr when the routine is
+ // complete (this will never exceed bufLen-1).
+ //
+ bool ReadString( char *pStr, int bufLen, bool bLine=false, int *pOutNumChars=NULL );
+
+ // Reads a string and allocates memory for it. If the string in the buffer
+ // is > 2048 bytes, then pOverflow is set to true (if it's not NULL).
+ char* ReadAndAllocateString( bool *pOverflow = 0 );
+
+ // Returns nonzero if any bits differ
+ int CompareBits( bf_read * RESTRICT other, int bits ) RESTRICT;
+ int CompareBitsAt( int offset, bf_read * RESTRICT other, int otherOffset, int bits ) RESTRICT;
+
+// Status.
+public:
+ int GetNumBytesLeft();
+ int GetNumBytesRead();
+ int GetNumBitsLeft();
+ int GetNumBitsRead() const;
+
+ // Has the buffer overflowed?
+ inline bool IsOverflowed() const {return m_bOverflow;}
+
+ inline bool Seek(int iBit); // Seek to a specific bit.
+ inline bool SeekRelative(int iBitDelta); // Seek to an offset from the current position.
+
+ // Called when the buffer is overflowed.
+ void SetOverflowFlag();
+
+
+public:
+
+ // The current buffer.
+ const unsigned char* RESTRICT m_pData;
+ int m_nDataBytes;
+ int m_nDataBits;
+
+ // Where we are in the buffer.
+ int m_iCurBit;
+
+
+private:
+ // Errors?
+ bool m_bOverflow;
+
+ // For debugging..
+ bool m_bAssertOnOverflow;
+
+ const char *m_pDebugName;
+};
+
+//-----------------------------------------------------------------------------
+// Inlines.
+//-----------------------------------------------------------------------------
+
+inline int bf_read::GetNumBytesRead()
+{
+ return BitByte(m_iCurBit);
+}
+
+inline int bf_read::GetNumBitsLeft()
+{
+ return m_nDataBits - m_iCurBit;
+}
+
+inline int bf_read::GetNumBytesLeft()
+{
+ return GetNumBitsLeft() >> 3;
+}
+
+inline int bf_read::GetNumBitsRead() const
+{
+ return m_iCurBit;
+}
+
+inline bool bf_read::Seek(int iBit)
+{
+ if(iBit < 0 || iBit > m_nDataBits)
+ {
+ SetOverflowFlag();
+ m_iCurBit = m_nDataBits;
+ return false;
+ }
+ else
+ {
+ m_iCurBit = iBit;
+ return true;
+ }
+}
+
+// Seek to an offset from the current position.
+inline bool bf_read::SeekRelative(int iBitDelta)
+{
+ return Seek(m_iCurBit+iBitDelta);
+}
+
+inline bool bf_read::CheckForOverflow(int nBits)
+{
+ if( m_iCurBit + nBits > m_nDataBits )
+ {
+ SetOverflowFlag();
+ CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() );
+ }
+
+ return m_bOverflow;
+}
+
+inline int bf_read::ReadOneBitNoCheck()
+{
+#if VALVE_LITTLE_ENDIAN
+ unsigned int value = ((unsigned long * RESTRICT)m_pData)[m_iCurBit >> 5] >> (m_iCurBit & 31);
+#else
+ unsigned char value = m_pData[m_iCurBit >> 3] >> (m_iCurBit & 7);
+#endif
+ ++m_iCurBit;
+ return value & 1;
+}
+
+inline int bf_read::ReadOneBit()
+{
+ if( GetNumBitsLeft() <= 0 )
+ {
+ SetOverflowFlag();
+ CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() );
+ return 0;
+ }
+ return ReadOneBitNoCheck();
+}
+
+inline float bf_read::ReadBitFloat()
+{
+ union { uint32 u; float f; } c = { ReadUBitLong(32) };
+ return c.f;
+}
+
+BITBUF_INLINE unsigned int bf_read::ReadUBitVar()
+{
+ // six bits: low 2 bits for encoding + first 4 bits of value
+ unsigned int sixbits = ReadUBitLong(6);
+ unsigned int encoding = sixbits & 3;
+ if ( encoding )
+ {
+ // this function will seek back four bits and read the full value
+ return ReadUBitVarInternal( encoding );
+ }
+ return sixbits >> 2;
+}
+
+BITBUF_INLINE unsigned int bf_read::ReadUBitLong( int numbits ) RESTRICT
+{
+ Assert( numbits > 0 && numbits <= 32 );
+
+ if ( GetNumBitsLeft() < numbits )
+ {
+ m_iCurBit = m_nDataBits;
+ SetOverflowFlag();
+ CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() );
+ return 0;
+ }
+
+ unsigned int iStartBit = m_iCurBit & 31u;
+ int iLastBit = m_iCurBit + numbits - 1;
+ unsigned int iWordOffset1 = m_iCurBit >> 5;
+ unsigned int iWordOffset2 = iLastBit >> 5;
+ m_iCurBit += numbits;
+
+#if __i386__
+ unsigned int bitmask = (2 << (numbits-1)) - 1;
+#else
+ extern unsigned long g_ExtraMasks[33];
+ unsigned int bitmask = g_ExtraMasks[numbits];
+#endif
+
+ unsigned int dw1 = LoadLittleDWord( (unsigned long* RESTRICT)m_pData, iWordOffset1 ) >> iStartBit;
+ unsigned int dw2 = LoadLittleDWord( (unsigned long* RESTRICT)m_pData, iWordOffset2 ) << (32 - iStartBit);
+
+ return (dw1 | dw2) & bitmask;
+}
+
+BITBUF_INLINE int bf_read::CompareBits( bf_read * RESTRICT other, int numbits ) RESTRICT
+{
+ return (ReadUBitLong(numbits) != other->ReadUBitLong(numbits));
+}
+
+
+#endif
+
+
+
diff --git a/public/tier1/byteswap.h b/public/tier1/byteswap.h
new file mode 100644
index 0000000..1c298f6
--- /dev/null
+++ b/public/tier1/byteswap.h
@@ -0,0 +1,249 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Low level byte swapping routines.
+//
+// $NoKeywords: $
+//=============================================================================
+#ifndef BYTESWAP_H
+#define BYTESWAP_H
+#if defined(_WIN32)
+#pragma once
+#endif
+
+#include "datamap.h" // Needed for typedescription_t. Note datamap.h is tier1 as well.
+
+class CByteswap
+{
+public:
+ CByteswap()
+ {
+ // Default behavior sets the target endian to match the machine native endian (no swap).
+ SetTargetBigEndian( IsMachineBigEndian() );
+ }
+
+ //-----------------------------------------------------------------------------
+ // Write a single field.
+ //-----------------------------------------------------------------------------
+ void SwapFieldToTargetEndian( void* pOutputBuffer, void *pData, typedescription_t *pField );
+
+ //-----------------------------------------------------------------------------
+ // Write a block of fields. Works a bit like the saverestore code.
+ //-----------------------------------------------------------------------------
+ void SwapFieldsToTargetEndian( void *pOutputBuffer, void *pBaseData, datamap_t *pDataMap );
+
+ // Swaps fields for the templated type to the output buffer.
+ template<typename T> inline void SwapFieldsToTargetEndian( T* pOutputBuffer, void *pBaseData, unsigned int objectCount = 1 )
+ {
+ for ( unsigned int i = 0; i < objectCount; ++i, ++pOutputBuffer )
+ {
+ SwapFieldsToTargetEndian( (void*)pOutputBuffer, pBaseData, &T::m_DataMap );
+ pBaseData = (byte*)pBaseData + sizeof(T);
+ }
+ }
+
+ // Swaps fields for the templated type in place.
+ template<typename T> inline void SwapFieldsToTargetEndian( T* pOutputBuffer, unsigned int objectCount = 1 )
+ {
+ SwapFieldsToTargetEndian<T>( pOutputBuffer, (void*)pOutputBuffer, objectCount );
+ }
+
+ //-----------------------------------------------------------------------------
+ // True if the current machine is detected as big endian.
+ // (Endienness is effectively detected at compile time when optimizations are
+ // enabled)
+ //-----------------------------------------------------------------------------
+ static bool IsMachineBigEndian()
+ {
+ short nIsBigEndian = 1;
+
+ // if we are big endian, the first byte will be a 0, if little endian, it will be a one.
+ return (bool)(0 == *(char *)&nIsBigEndian );
+ }
+
+ //-----------------------------------------------------------------------------
+ // Sets the target byte ordering we are swapping to or from.
+ //
+ // Braindead Endian Reference:
+ // x86 is LITTLE Endian
+ // PowerPC is BIG Endian
+ //-----------------------------------------------------------------------------
+ inline void SetTargetBigEndian( bool bigEndian )
+ {
+ m_bBigEndian = bigEndian;
+ m_bSwapBytes = IsMachineBigEndian() != bigEndian;
+ }
+
+ // Changes target endian
+ inline void FlipTargetEndian( void )
+ {
+ m_bSwapBytes = !m_bSwapBytes;
+ m_bBigEndian = !m_bBigEndian;
+ }
+
+ // Forces byte swapping state, regardless of endianess
+ inline void ActivateByteSwapping( bool bActivate )
+ {
+ SetTargetBigEndian( IsMachineBigEndian() != bActivate );
+ }
+
+ //-----------------------------------------------------------------------------
+ // Returns true if the target machine is the same as this one in endianness.
+ //
+ // Used to determine when a byteswap needs to take place.
+ //-----------------------------------------------------------------------------
+ inline bool IsSwappingBytes( void ) // Are bytes being swapped?
+ {
+ return m_bSwapBytes;
+ }
+
+ inline bool IsTargetBigEndian( void ) // What is the current target endian?
+ {
+ return m_bBigEndian;
+ }
+
+ //-----------------------------------------------------------------------------
+ // IsByteSwapped()
+ //
+ // When supplied with a chunk of input data and a constant or magic number
+ // (in native format) determines the endienness of the current machine in
+ // relation to the given input data.
+ //
+ // Returns:
+ // 1 if input is the same as nativeConstant.
+ // 0 if input is byteswapped relative to nativeConstant.
+ // -1 if input is not the same as nativeConstant and not byteswapped either.
+ //
+ // ( This is useful for detecting byteswapping in magic numbers in structure
+ // headers for example. )
+ //-----------------------------------------------------------------------------
+ template<typename T> inline int SourceIsNativeEndian( T input, T nativeConstant )
+ {
+ // If it's the same, it isn't byteswapped:
+ if( input == nativeConstant )
+ return 1;
+
+ int output;
+ LowLevelByteSwap<T>( &output, &input );
+ if( output == nativeConstant )
+ return 0;
+
+ assert( 0 ); // if we get here, input is neither a swapped nor unswapped version of nativeConstant.
+ return -1;
+ }
+
+ //-----------------------------------------------------------------------------
+ // Swaps an input buffer full of type T into the given output buffer.
+ //
+ // Swaps [count] items from the inputBuffer to the outputBuffer.
+ // If inputBuffer is omitted or NULL, then it is assumed to be the same as
+ // outputBuffer - effectively swapping the contents of the buffer in place.
+ //-----------------------------------------------------------------------------
+ template<typename T> inline void SwapBuffer( T* outputBuffer, T* inputBuffer = NULL, int count = 1 )
+ {
+ assert( count >= 0 );
+ assert( outputBuffer );
+
+ // Fail gracefully in release:
+ if( count <=0 || !outputBuffer )
+ return;
+
+ // Optimization for the case when we are swapping in place.
+ if( inputBuffer == NULL )
+ {
+ inputBuffer = outputBuffer;
+ }
+
+ // Swap everything in the buffer:
+ for( int i = 0; i < count; i++ )
+ {
+ LowLevelByteSwap<T>( &outputBuffer[i], &inputBuffer[i] );
+ }
+ }
+
+ //-----------------------------------------------------------------------------
+ // Swaps an input buffer full of type T into the given output buffer.
+ //
+ // Swaps [count] items from the inputBuffer to the outputBuffer.
+ // If inputBuffer is omitted or NULL, then it is assumed to be the same as
+ // outputBuffer - effectively swapping the contents of the buffer in place.
+ //-----------------------------------------------------------------------------
+ template<typename T> inline void SwapBufferToTargetEndian( T* outputBuffer, T* inputBuffer = NULL, int count = 1 )
+ {
+ assert( count >= 0 );
+ assert( outputBuffer );
+
+ // Fail gracefully in release:
+ if( count <=0 || !outputBuffer )
+ return;
+
+ // Optimization for the case when we are swapping in place.
+ if( inputBuffer == NULL )
+ {
+ inputBuffer = outputBuffer;
+ }
+
+ // Are we already the correct endienness? ( or are we swapping 1 byte items? )
+ if( !m_bSwapBytes || ( sizeof(T) == 1 ) )
+ {
+ // If we were just going to swap in place then return.
+ if( !inputBuffer )
+ return;
+
+ // Otherwise copy the inputBuffer to the outputBuffer:
+ memcpy( outputBuffer, inputBuffer, count * sizeof( T ) );
+ return;
+
+ }
+
+ // Swap everything in the buffer:
+ for( int i = 0; i < count; i++ )
+ {
+ LowLevelByteSwap<T>( &outputBuffer[i], &inputBuffer[i] );
+ }
+ }
+
+private:
+ //-----------------------------------------------------------------------------
+ // The lowest level byte swapping workhorse of doom. output always contains the
+ // swapped version of input. ( Doesn't compare machine to target endianness )
+ //-----------------------------------------------------------------------------
+ template<typename T> static void LowLevelByteSwap( T *output, T *input )
+ {
+ T temp = *output;
+#if defined( _X360 )
+ // Intrinsics need the source type to be fixed-point
+ DWORD* word = (DWORD*)input;
+ switch( sizeof(T) )
+ {
+ case 8:
+ {
+ __storewordbytereverse( *word, 0, &temp );
+ __storewordbytereverse( *(word+1), 4, &temp );
+ }
+ break;
+
+ case 4:
+ __storewordbytereverse( *word, 0, &temp );
+ break;
+
+ case 2:
+ __storeshortbytereverse( *input, 0, &temp );
+ break;
+
+ default:
+ Assert( "Invalid size in CByteswap::LowLevelByteSwap" && 0 );
+ }
+#else
+ for( size_t i = 0; i < sizeof(T); i++ )
+ {
+ ((unsigned char* )&temp)[i] = ((unsigned char*)input)[sizeof(T)-(i+1)];
+ }
+#endif
+ Q_memcpy( output, &temp, sizeof(T) );
+ }
+
+ unsigned int m_bSwapBytes : 1;
+ unsigned int m_bBigEndian : 1;
+};
+
+#endif /* !BYTESWAP_H */
diff --git a/public/tier1/callqueue.h b/public/tier1/callqueue.h
new file mode 100644
index 0000000..5e0e994
--- /dev/null
+++ b/public/tier1/callqueue.h
@@ -0,0 +1,203 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef CALLQUEUE_H
+#define CALLQUEUE_H
+
+#include "tier0/tslist.h"
+#include "functors.h"
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+
+//-----------------------------------------------------
+// Avert thy eyes! Imagine rather:
+//
+// void QueueCall( <function>, [args1, [arg2,]...]
+// void QueueCall( <object>, <function>, [args1, [arg2,]...]
+// void QueueRefCall( <object>, <<function>, [args1, [arg2,]...]
+//-----------------------------------------------------
+
+#define DEFINE_CALLQUEUE_NONMEMBER_QUEUE_CALL(N) \
+ template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ void QueueCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ QueueFunctorInternal( CreateFunctor( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
+ }
+
+//-------------------------------------
+
+#define DEFINE_CALLQUEUE_MEMBER_QUEUE_CALL(N) \
+ template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ void QueueCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ QueueFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
+ }
+
+//-------------------------------------
+
+#define DEFINE_CALLQUEUE_CONST_MEMBER_QUEUE_CALL(N) \
+ template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ void QueueCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ QueueFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
+ }
+
+//-------------------------------------
+
+#define DEFINE_CALLQUEUE_REF_COUNTING_MEMBER_QUEUE_CALL(N) \
+ template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ void QueueRefCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ QueueFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
+ }
+
+//-------------------------------------
+
+#define DEFINE_CALLQUEUE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL(N) \
+ template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ void QueueRefCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ QueueFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
+ \
+ }
+
+#define FUNC_GENERATE_QUEUE_METHODS() \
+ FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_NONMEMBER_QUEUE_CALL ); \
+ FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_MEMBER_QUEUE_CALL ); \
+ FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_CONST_MEMBER_QUEUE_CALL );\
+ FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_REF_COUNTING_MEMBER_QUEUE_CALL ); \
+ FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL )
+
+//-----------------------------------------------------
+
+template <typename QUEUE_TYPE = CTSQueue<CFunctor *> >
+class CCallQueueT
+{
+public:
+ CCallQueueT()
+ : m_bNoQueue( false )
+ {
+#ifdef _DEBUG
+ m_nCurSerialNumber = 0;
+ m_nBreakSerialNumber = (unsigned)-1;
+#endif
+ }
+
+ void DisableQueue( bool bDisable )
+ {
+ if ( m_bNoQueue == bDisable )
+ {
+ return;
+ }
+ if ( !m_bNoQueue )
+ CallQueued();
+
+ m_bNoQueue = bDisable;
+ }
+
+ bool IsDisabled() const
+ {
+ return m_bNoQueue;
+ }
+
+ int Count()
+ {
+ return m_queue.Count();
+ }
+
+ void CallQueued()
+ {
+ if ( !m_queue.Count() )
+ {
+ return;
+ }
+
+ m_queue.PushItem( NULL );
+
+ CFunctor *pFunctor;
+
+ while ( m_queue.PopItem( &pFunctor ) && pFunctor != NULL )
+ {
+#ifdef _DEBUG
+ if ( pFunctor->m_nUserID == m_nBreakSerialNumber)
+ {
+ m_nBreakSerialNumber = (unsigned)-1;
+ }
+#endif
+ (*pFunctor)();
+ pFunctor->Release();
+ }
+
+ }
+
+ void QueueFunctor( CFunctor *pFunctor )
+ {
+ Assert( pFunctor );
+ QueueFunctorInternal( RetAddRef( pFunctor ) );
+ }
+
+ void Flush()
+ {
+ m_queue.PushItem( NULL );
+
+ CFunctor *pFunctor;
+
+ while ( m_queue.PopItem( &pFunctor ) && pFunctor != NULL )
+ {
+ pFunctor->Release();
+ }
+ }
+
+ FUNC_GENERATE_QUEUE_METHODS();
+
+private:
+ void QueueFunctorInternal( CFunctor *pFunctor )
+ {
+ if ( !m_bNoQueue )
+ {
+#ifdef _DEBUG
+ pFunctor->m_nUserID = m_nCurSerialNumber++;
+#endif
+ m_queue.PushItem( pFunctor );
+ }
+ else
+ {
+ (*pFunctor)();
+ pFunctor->Release();
+ }
+ }
+
+ QUEUE_TYPE m_queue;
+ bool m_bNoQueue;
+ unsigned m_nCurSerialNumber;
+ unsigned m_nBreakSerialNumber;
+};
+
+class CCallQueue : public CCallQueueT<>
+{
+};
+
+//-----------------------------------------------------
+// Optional interface that can be bound to concrete CCallQueue
+//-----------------------------------------------------
+
+class ICallQueue
+{
+public:
+ void QueueFunctor( CFunctor *pFunctor )
+ {
+ QueueFunctorInternal( RetAddRef( pFunctor ) );
+ }
+
+ FUNC_GENERATE_QUEUE_METHODS();
+
+private:
+ virtual void QueueFunctorInternal( CFunctor *pFunctor ) = 0;
+};
+
+#endif // CALLQUEUE_H
diff --git a/public/tier1/characterset.h b/public/tier1/characterset.h
new file mode 100644
index 0000000..0c639e1
--- /dev/null
+++ b/public/tier1/characterset.h
@@ -0,0 +1,43 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Shared code for parsing / searching for characters in a string
+// using lookup tables
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef CHARACTERSET_H
+#define CHARACTERSET_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+struct characterset_t
+{
+ char set[256];
+};
+
+
+// This is essentially a strpbrk() using a precalculated lookup table
+//-----------------------------------------------------------------------------
+// Purpose: builds a simple lookup table of a group of important characters
+// Input : *pSetBuffer - pointer to the buffer for the group
+// *pSetString - list of characters to flag
+//-----------------------------------------------------------------------------
+extern void CharacterSetBuild( characterset_t *pSetBuffer, const char *pSetString );
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pSetBuffer - pre-build group buffer
+// character - character to lookup
+// Output : int - 1 if the character was in the set
+//-----------------------------------------------------------------------------
+#define IN_CHARACTERSET( SetBuffer, character ) ((SetBuffer).set[ (unsigned char) (character) ])
+
+
+#endif // CHARACTERSET_H
diff --git a/public/tier1/checksum_crc.h b/public/tier1/checksum_crc.h
new file mode 100644
index 0000000..dbbc50a
--- /dev/null
+++ b/public/tier1/checksum_crc.h
@@ -0,0 +1,31 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Generic CRC functions
+//
+// $NoKeywords: $
+//=============================================================================//
+#ifndef CHECKSUM_CRC_H
+#define CHECKSUM_CRC_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+typedef unsigned int CRC32_t;
+
+void CRC32_Init( CRC32_t *pulCRC );
+void CRC32_ProcessBuffer( CRC32_t *pulCRC, const void *p, int len );
+void CRC32_Final( CRC32_t *pulCRC );
+CRC32_t CRC32_GetTableEntry( unsigned int slot );
+
+inline CRC32_t CRC32_ProcessSingleBuffer( const void *p, int len )
+{
+ CRC32_t crc;
+
+ CRC32_Init( &crc );
+ CRC32_ProcessBuffer( &crc, p, len );
+ CRC32_Final( &crc );
+
+ return crc;
+}
+
+#endif // CHECKSUM_CRC_H
diff --git a/public/tier1/checksum_md5.h b/public/tier1/checksum_md5.h
new file mode 100644
index 0000000..e7cf7ec
--- /dev/null
+++ b/public/tier1/checksum_md5.h
@@ -0,0 +1,62 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Generic MD5 hashing algo
+//
+//=============================================================================//
+
+#ifndef CHECKSUM_MD5_H
+#define CHECKSUM_MD5_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+// 16 bytes == 128 bit digest
+#define MD5_DIGEST_LENGTH 16
+#define MD5_BIT_LENGTH ( MD5_DIGEST_LENGTH * sizeof(unsigned char) )
+struct MD5Value_t
+{
+ unsigned char bits[MD5_DIGEST_LENGTH];
+
+ void Zero();
+ bool IsZero() const;
+
+ bool operator==( const MD5Value_t &src ) const;
+ bool operator!=( const MD5Value_t &src ) const;
+
+};
+
+// MD5 Hash
+typedef struct
+{
+ unsigned int buf[4];
+ unsigned int bits[2];
+ unsigned char in[64];
+} MD5Context_t;
+
+void MD5Init( MD5Context_t *context );
+void MD5Update( MD5Context_t *context, unsigned char const *buf, unsigned int len );
+void MD5Final( unsigned char digest[ MD5_DIGEST_LENGTH ], MD5Context_t *context );
+
+char *MD5_Print(unsigned char *digest, int hashlen );
+
+/// Convenience wrapper to calculate the MD5 for a buffer, all in one step, without
+/// bothering with the context object.
+void MD5_ProcessSingleBuffer( const void *p, int len, MD5Value_t &md5Result );
+
+unsigned int MD5_PseudoRandom(unsigned int nSeed);
+
+/// Returns true if the values match.
+bool MD5_Compare( const MD5Value_t &data, const MD5Value_t &compare );
+
+inline bool MD5Value_t::operator==( const MD5Value_t &src ) const
+{
+ return MD5_Compare( *this, src );
+}
+
+inline bool MD5Value_t::operator!=( const MD5Value_t &src ) const
+{
+ return !MD5_Compare( *this, src );
+}
+
+#endif // CHECKSUM_MD5_H
diff --git a/public/tier1/checksum_sha1.h b/public/tier1/checksum_sha1.h
new file mode 100644
index 0000000..7c87aa5
--- /dev/null
+++ b/public/tier1/checksum_sha1.h
@@ -0,0 +1,174 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implementation of SHA-1
+//
+//=============================================================================
+
+#ifndef CHECKSUM_SHA1_H
+#define CHECKSUM_SHA1_H
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+
+/*
+ 100% free public domain implementation of the SHA-1
+ algorithm by Dominik Reichl <[email protected]>
+
+
+ === Test Vectors (from FIPS PUB 180-1) ===
+
+ SHA1("abc") =
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+
+ SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+
+ SHA1(A million repetitions of "a") =
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#if !defined(_MINIMUM_BUILD_)
+#include <stdio.h> // Needed for file access
+#if defined( _PS3 )
+#include <sys/memory.h>
+#else
+#include <memory.h>
+#endif
+#include <string.h> // Needed for strcat and strcpy
+#endif
+
+// If you're compiling big endian, just comment out the following line
+#define SHA1_LITTLE_ENDIAN
+
+typedef union
+{
+ unsigned char c[64];
+ unsigned long l[16];
+} SHA1_WORKSPACE_BLOCK;
+
+// SHA1 hash
+const unsigned int k_cubHash = 20;
+const unsigned int k_cchHash = 41; // k_cubHash * 2, plus 1 for terminator
+#pragma pack( push, 1 )
+typedef unsigned char SHADigest_t[ k_cubHash ];
+#pragma pack( pop )
+
+#if !defined(_MINIMUM_BUILD_)
+class CSHA1
+#else
+class Minimum_CSHA1
+#endif
+{
+public:
+ // Two different formats for ReportHash(...)
+ enum
+ {
+ REPORT_HEX = 0,
+ REPORT_DIGIT = 1
+ };
+
+ // Constructor and Destructor
+#if !defined(_MINIMUM_BUILD_)
+ CSHA1();
+ virtual ~CSHA1() ;
+#else
+ Minimum_CSHA1() ;
+ ~Minimum_CSHA1() ; // no virtual destructor's in the minimal builds !
+#endif
+
+ unsigned long m_state[5];
+ unsigned long m_count[2];
+ unsigned char m_buffer[64];
+ unsigned char m_digest[k_cubHash];
+
+ void Reset();
+
+ // Update the hash value
+ void Update(unsigned char *data, unsigned int len);
+#if !defined(_MINIMUM_BUILD_)
+ bool HashFile(char *szFileName);
+#endif
+
+ // Finalize hash and report
+ void Final();
+#if !defined(_MINIMUM_BUILD_)
+ void ReportHash(char *szReport, unsigned char uReportType = REPORT_HEX);
+#endif
+ void GetHash(unsigned char *uDest);
+
+private:
+ // Private SHA-1 transformation
+ void Transform(unsigned long state[5], unsigned char buffer[64]);
+
+ // Member variables
+ unsigned char m_workspace[64];
+ SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above
+};
+
+#define GenerateHash( hash, pubData, cubData ) { CSHA1 sha1; sha1.Update( (byte *)pubData, cubData ); sha1.Final(); sha1.GetHash( hash ); }
+
+#if !defined(_MINIMUM_BUILD_)
+// hash comparison function, for use with CUtlMap/CUtlRBTree
+bool HashLessFunc( SHADigest_t const &lhs, SHADigest_t const &rhs );
+
+// utility class for manipulating SHA1 hashes in their compact form
+struct CSHA
+{
+public:
+ SHADigest_t m_shaDigest;
+
+ CSHA()
+ {
+ memset( m_shaDigest, 0, k_cubHash );
+ }
+
+ explicit CSHA( const SHADigest_t rhs )
+ {
+ memcpy( m_shaDigest, rhs, k_cubHash );
+ }
+
+ SHADigest_t &SHADigest()
+ {
+ return m_shaDigest;
+ }
+
+ bool operator<( const CSHA &rhs ) const
+ {
+ return memcmp( m_shaDigest, rhs.m_shaDigest, k_cubHash ) < 0;
+ }
+
+ bool operator==( const CSHA &rhs ) const
+ {
+ return memcmp( m_shaDigest, rhs.m_shaDigest, k_cubHash ) == 0;
+ }
+
+ bool operator!=( const CSHA &rhs ) const
+ {
+ return !(*this == rhs);
+ }
+
+ bool operator==( const SHADigest_t &rhs ) const
+ {
+ return memcmp( m_shaDigest, rhs, k_cubHash ) == 0;
+ }
+
+ bool operator!=( const SHADigest_t &rhs ) const
+ {
+ return !(*this == rhs);
+ }
+
+ CSHA &operator=( const SHADigest_t rhs )
+ {
+ memcpy( m_shaDigest, rhs, k_cubHash );
+ return *this;
+ }
+
+ void AssignTo( SHADigest_t rhs ) const
+ {
+ memcpy( rhs, m_shaDigest, k_cubHash );
+ }
+};
+#endif // _MINIMUM_BUILD_
+
+#endif // CHECKSUM_SHA1_H
diff --git a/public/tier1/convar.h b/public/tier1/convar.h
new file mode 100644
index 0000000..5043b6b
--- /dev/null
+++ b/public/tier1/convar.h
@@ -0,0 +1,725 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef CONVAR_H
+#define CONVAR_H
+
+#if _WIN32
+#pragma once
+#endif
+
+#include "tier0/dbg.h"
+#include "tier1/iconvar.h"
+#include "tier1/utlvector.h"
+#include "tier1/utlstring.h"
+#include "icvar.h"
+
+#ifdef _WIN32
+#define FORCEINLINE_CVAR FORCEINLINE
+#elif POSIX
+#define FORCEINLINE_CVAR inline
+#else
+#error "implement me"
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class ConVar;
+class CCommand;
+class ConCommand;
+class ConCommandBase;
+struct characterset_t;
+
+
+
+//-----------------------------------------------------------------------------
+// Any executable that wants to use ConVars need to implement one of
+// these to hook up access to console variables.
+//-----------------------------------------------------------------------------
+class IConCommandBaseAccessor
+{
+public:
+ // Flags is a combination of FCVAR flags in cvar.h.
+ // hOut is filled in with a handle to the variable.
+ virtual bool RegisterConCommandBase( ConCommandBase *pVar ) = 0;
+};
+
+
+//-----------------------------------------------------------------------------
+// Helper method for console development
+//-----------------------------------------------------------------------------
+#if defined( _X360 ) && !defined( _RETAIL )
+void ConVar_PublishToVXConsole();
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Called when a ConCommand needs to execute
+//-----------------------------------------------------------------------------
+typedef void ( *FnCommandCallbackVoid_t )( void );
+typedef void ( *FnCommandCallback_t )( const CCommand &command );
+
+#define COMMAND_COMPLETION_MAXITEMS 64
+#define COMMAND_COMPLETION_ITEM_LENGTH 64
+
+//-----------------------------------------------------------------------------
+// Returns 0 to COMMAND_COMPLETION_MAXITEMS worth of completion strings
+//-----------------------------------------------------------------------------
+typedef int ( *FnCommandCompletionCallback )( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
+
+
+//-----------------------------------------------------------------------------
+// Interface version
+//-----------------------------------------------------------------------------
+class ICommandCallback
+{
+public:
+ virtual void CommandCallback( const CCommand &command ) = 0;
+};
+
+class ICommandCompletionCallback
+{
+public:
+ virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands ) = 0;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: The base console invoked command/cvar interface
+//-----------------------------------------------------------------------------
+class ConCommandBase
+{
+ friend class CCvar;
+ friend class ConVar;
+ friend class ConCommand;
+ friend void ConVar_Register( int nCVarFlag, IConCommandBaseAccessor *pAccessor );
+ friend void ConVar_PublishToVXConsole();
+
+ // FIXME: Remove when ConVar changes are done
+ friend class CDefaultCvar;
+
+public:
+ ConCommandBase( void );
+ ConCommandBase( const char *pName, const char *pHelpString = 0,
+ int flags = 0 );
+
+ virtual ~ConCommandBase( void );
+
+ virtual bool IsCommand( void ) const;
+
+ // Check flag
+ virtual bool IsFlagSet( int flag ) const;
+ // Set flag
+ virtual void AddFlags( int flags );
+
+ // Return name of cvar
+ virtual const char *GetName( void ) const;
+
+ // Return help text for cvar
+ virtual const char *GetHelpText( void ) const;
+
+ // Deal with next pointer
+ const ConCommandBase *GetNext( void ) const;
+ ConCommandBase *GetNext( void );
+
+ virtual bool IsRegistered( void ) const;
+
+ // Returns the DLL identifier
+ virtual CVarDLLIdentifier_t GetDLLIdentifier() const;
+
+protected:
+ virtual void CreateBase( const char *pName, const char *pHelpString = 0,
+ int flags = 0 );
+
+ // Used internally by OneTimeInit to initialize/shutdown
+ virtual void Init();
+ void Shutdown();
+
+ // Internal copy routine ( uses new operator from correct module )
+ char *CopyString( const char *from );
+
+private:
+ // Next ConVar in chain
+ // Prior to register, it points to the next convar in the DLL.
+ // Once registered, though, m_pNext is reset to point to the next
+ // convar in the global list
+ ConCommandBase *m_pNext;
+
+ // Has the cvar been added to the global list?
+ bool m_bRegistered;
+
+ // Static data
+ const char *m_pszName;
+ const char *m_pszHelpString;
+
+ // ConVar flags
+ int m_nFlags;
+
+protected:
+ // ConVars add themselves to this list for the executable.
+ // Then ConVar_Register runs through all the console variables
+ // and registers them into a global list stored in vstdlib.dll
+ static ConCommandBase *s_pConCommandBases;
+
+ // ConVars in this executable use this 'global' to access values.
+ static IConCommandBaseAccessor *s_pAccessor;
+};
+
+
+//-----------------------------------------------------------------------------
+// Command tokenizer
+//-----------------------------------------------------------------------------
+class CCommand
+{
+public:
+ CCommand();
+ CCommand( int nArgC, const char **ppArgV );
+ bool Tokenize( const char *pCommand, characterset_t *pBreakSet = NULL );
+ void Reset();
+
+ int ArgC() const;
+ const char **ArgV() const;
+ const char *ArgS() const; // All args that occur after the 0th arg, in string form
+ const char *GetCommandString() const; // The entire command in string form, including the 0th arg
+ const char *operator[]( int nIndex ) const; // Gets at arguments
+ const char *Arg( int nIndex ) const; // Gets at arguments
+
+ // Helper functions to parse arguments to commands.
+ const char* FindArg( const char *pName ) const;
+ int FindArgInt( const char *pName, int nDefaultVal ) const;
+
+ static int MaxCommandLength();
+ static characterset_t* DefaultBreakSet();
+
+private:
+ enum
+ {
+ COMMAND_MAX_ARGC = 64,
+ COMMAND_MAX_LENGTH = 512,
+ };
+
+ int m_nArgc;
+ int m_nArgv0Size;
+ char m_pArgSBuffer[ COMMAND_MAX_LENGTH ];
+ char m_pArgvBuffer[ COMMAND_MAX_LENGTH ];
+ const char* m_ppArgv[ COMMAND_MAX_ARGC ];
+};
+
+inline int CCommand::MaxCommandLength()
+{
+ return COMMAND_MAX_LENGTH - 1;
+}
+
+inline int CCommand::ArgC() const
+{
+ return m_nArgc;
+}
+
+inline const char **CCommand::ArgV() const
+{
+ return m_nArgc ? (const char**)m_ppArgv : NULL;
+}
+
+inline const char *CCommand::ArgS() const
+{
+ return m_nArgv0Size ? &m_pArgSBuffer[m_nArgv0Size] : "";
+}
+
+inline const char *CCommand::GetCommandString() const
+{
+ return m_nArgc ? m_pArgSBuffer : "";
+}
+
+inline const char *CCommand::Arg( int nIndex ) const
+{
+ // FIXME: Many command handlers appear to not be particularly careful
+ // about checking for valid argc range. For now, we're going to
+ // do the extra check and return an empty string if it's out of range
+ if ( nIndex < 0 || nIndex >= m_nArgc )
+ return "";
+ return m_ppArgv[nIndex];
+}
+
+inline const char *CCommand::operator[]( int nIndex ) const
+{
+ return Arg( nIndex );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: The console invoked command
+//-----------------------------------------------------------------------------
+class ConCommand : public ConCommandBase
+{
+friend class CCvar;
+
+public:
+ typedef ConCommandBase BaseClass;
+
+ ConCommand( const char *pName, FnCommandCallbackVoid_t callback,
+ const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
+ ConCommand( const char *pName, FnCommandCallback_t callback,
+ const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
+ ConCommand( const char *pName, ICommandCallback *pCallback,
+ const char *pHelpString = 0, int flags = 0, ICommandCompletionCallback *pCommandCompletionCallback = 0 );
+
+ virtual ~ConCommand( void );
+
+ virtual bool IsCommand( void ) const;
+
+ virtual int AutoCompleteSuggest( const char *partial, CUtlVector< CUtlString > &commands );
+
+ virtual bool CanAutoComplete( void );
+
+ // Invoke the function
+ virtual void Dispatch( const CCommand &command );
+
+private:
+ // NOTE: To maintain backward compat, we have to be very careful:
+ // All public virtual methods must appear in the same order always
+ // since engine code will be calling into this code, which *does not match*
+ // in the mod code; it's using slightly different, but compatible versions
+ // of this class. Also: Be very careful about adding new fields to this class.
+ // Those fields will not exist in the version of this class that is instanced
+ // in mod code.
+
+ // Call this function when executing the command
+ union
+ {
+ FnCommandCallbackVoid_t m_fnCommandCallbackV1;
+ FnCommandCallback_t m_fnCommandCallback;
+ ICommandCallback *m_pCommandCallback;
+ };
+
+ union
+ {
+ FnCommandCompletionCallback m_fnCompletionCallback;
+ ICommandCompletionCallback *m_pCommandCompletionCallback;
+ };
+
+ bool m_bHasCompletionCallback : 1;
+ bool m_bUsingNewCommandCallback : 1;
+ bool m_bUsingCommandCallbackInterface : 1;
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: A console variable
+//-----------------------------------------------------------------------------
+class ConVar : public ConCommandBase, public IConVar
+{
+friend class CCvar;
+friend class ConVarRef;
+
+public:
+ typedef ConCommandBase BaseClass;
+
+ ConVar( const char *pName, const char *pDefaultValue, int flags = 0);
+
+ ConVar( const char *pName, const char *pDefaultValue, int flags,
+ const char *pHelpString );
+ ConVar( const char *pName, const char *pDefaultValue, int flags,
+ const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax );
+ ConVar( const char *pName, const char *pDefaultValue, int flags,
+ const char *pHelpString, FnChangeCallback_t callback );
+ ConVar( const char *pName, const char *pDefaultValue, int flags,
+ const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax,
+ FnChangeCallback_t callback );
+ ConVar( const char *pName, const char *pDefaultValue, int flags,
+ const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax,
+ bool bCompMin, float fCompMin, bool bCompMax, float fCompMax,
+ FnChangeCallback_t callback );
+
+
+
+ virtual ~ConVar( void );
+
+ virtual bool IsFlagSet( int flag ) const;
+ virtual const char* GetHelpText( void ) const;
+ virtual bool IsRegistered( void ) const;
+ virtual const char *GetName( void ) const;
+ virtual void AddFlags( int flags );
+ virtual bool IsCommand( void ) const;
+
+ // Install a change callback (there shouldn't already be one....)
+ void InstallChangeCallback( FnChangeCallback_t callback );
+
+ // Retrieve value
+ FORCEINLINE_CVAR float GetFloat( void ) const;
+ FORCEINLINE_CVAR int GetInt( void ) const;
+ FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); }
+ FORCEINLINE_CVAR char const *GetString( void ) const;
+
+ // Any function that allocates/frees memory needs to be virtual or else you'll have crashes
+ // from alloc/free across dll/exe boundaries.
+
+ // These just call into the IConCommandBaseAccessor to check flags and set the var (which ends up calling InternalSetValue).
+ virtual void SetValue( const char *value );
+ virtual void SetValue( float value );
+ virtual void SetValue( int value );
+
+ // Reset to default value
+ void Revert( void );
+
+ // True if it has a min/max setting
+ bool GetMin( float& minVal ) const;
+ bool GetMax( float& maxVal ) const;
+ const char *GetDefault( void ) const;
+ void SetDefault( const char *pszDefault );
+
+ // True if it has a min/max competitive setting
+ bool GetCompMin( float& minVal ) const;
+ bool GetCompMax( float& maxVal ) const;
+
+ FORCEINLINE_CVAR bool IsCompetitiveRestricted() const;
+ bool SetCompetitiveMode( bool bCompetitive );
+
+private:
+ // Called by CCvar when the value of a var is changing.
+ virtual void InternalSetValue(const char *value);
+ // For CVARs marked FCVAR_NEVER_AS_STRING
+ virtual void InternalSetFloatValue( float fNewValue, bool bForce = false );
+ virtual void InternalSetIntValue( int nValue );
+
+ virtual bool ClampValue( float& value );
+ virtual void ChangeStringValue( const char *tempVal, float flOldValue );
+
+ void Create( const char *pName, const char *pDefaultValue, int flags = 0,
+ const char *pHelpString = 0, bool bMin = false, float fMin = 0.0,
+ bool bMax = false, float fMax = 0.0,
+ bool bCompMin = false, float fCompMin = 0.0,
+ bool bCompMax = false, float fCompMax = 0.0,
+ FnChangeCallback_t callback = 0 );
+
+
+ // Used internally by OneTimeInit to initialize.
+ virtual void Init();
+ int GetFlags() { return m_pParent->m_nFlags; }
+private:
+
+ // This either points to "this" or it points to the original declaration of a ConVar.
+ // This allows ConVars to exist in separate modules, and they all use the first one to be declared.
+ // m_pParent->m_pParent must equal m_pParent (ie: m_pParent must be the root, or original, ConVar).
+ ConVar *m_pParent;
+
+ // Static data
+ const char *m_pszDefaultValue;
+
+ // Value
+ // Dynamically allocated
+ char *m_pszString;
+ int m_StringLength;
+
+ // Values
+ float m_fValue;
+ int m_nValue;
+
+ // Min/Max values
+ bool m_bHasMin;
+ float m_fMinVal;
+ bool m_bHasMax;
+ float m_fMaxVal;
+
+ // Min/Max values for competitive.
+ bool m_bHasCompMin;
+ float m_fCompMinVal;
+ bool m_bHasCompMax;
+ float m_fCompMaxVal;
+
+ bool m_bCompetitiveRestrictions;
+
+
+ // Call this function when ConVar changes
+ FnChangeCallback_t m_fnChangeCallback;
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Return ConVar value as a float
+// Output : float
+//-----------------------------------------------------------------------------
+FORCEINLINE_CVAR float ConVar::GetFloat( void ) const
+{
+ return m_pParent->m_fValue;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return ConVar value as an int
+// Output : int
+//-----------------------------------------------------------------------------
+FORCEINLINE_CVAR int ConVar::GetInt( void ) const
+{
+ return m_pParent->m_nValue;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc.
+// Output : const char *
+//-----------------------------------------------------------------------------
+FORCEINLINE_CVAR const char *ConVar::GetString( void ) const
+{
+ if ( m_nFlags & FCVAR_NEVER_AS_STRING )
+ return "FCVAR_NEVER_AS_STRING";
+
+ return ( m_pParent->m_pszString ) ? m_pParent->m_pszString : "";
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return whether this convar is restricted for competitive play.
+// Output : bool
+//-----------------------------------------------------------------------------
+FORCEINLINE_CVAR bool ConVar::IsCompetitiveRestricted() const
+{
+ const int nFlags = m_pParent->m_nFlags;
+
+ const bool bHasCompSettings = m_pParent->m_bHasCompMin || m_pParent->m_bHasCompMax;
+ const bool bClientCanAdjust = ( nFlags & ( FCVAR_ARCHIVE | FCVAR_ALLOWED_IN_COMPETITIVE ) ) != 0;
+ const bool bInternalUseOnly = ( nFlags & ( FCVAR_HIDDEN | FCVAR_DEVELOPMENTONLY | FCVAR_INTERNAL_USE | FCVAR_GAMEDLL | FCVAR_REPLICATED | FCVAR_CHEAT ) ) != 0;
+
+ return bHasCompSettings || !( bClientCanAdjust || bInternalUseOnly );
+}
+
+
+//-----------------------------------------------------------------------------
+// Used to read/write convars that already exist (replaces the FindVar method)
+//-----------------------------------------------------------------------------
+class ConVarRef
+{
+public:
+ ConVarRef( const char *pName );
+ ConVarRef( const char *pName, bool bIgnoreMissing );
+ ConVarRef( IConVar *pConVar );
+
+ void Init( const char *pName, bool bIgnoreMissing );
+ bool IsValid() const;
+ bool IsFlagSet( int nFlags ) const;
+ IConVar *GetLinkedConVar();
+
+ // Get/Set value
+ float GetFloat( void ) const;
+ int GetInt( void ) const;
+ bool GetBool() const { return !!GetInt(); }
+ const char *GetString( void ) const;
+ // True if it has a min/max setting
+ bool GetMin( float& minVal ) const;
+ bool GetMax( float& maxVal ) const;
+
+ void SetValue( const char *pValue );
+ void SetValue( float flValue );
+ void SetValue( int nValue );
+ void SetValue( bool bValue );
+
+ const char *GetName() const;
+
+ const char *GetDefault() const;
+
+private:
+ // High-speed method to read convar data
+ IConVar *m_pConVar;
+ ConVar *m_pConVarState;
+};
+
+
+//-----------------------------------------------------------------------------
+// Did we find an existing convar of that name?
+//-----------------------------------------------------------------------------
+FORCEINLINE_CVAR bool ConVarRef::IsFlagSet( int nFlags ) const
+{
+ return ( m_pConVar->IsFlagSet( nFlags ) != 0 );
+}
+
+FORCEINLINE_CVAR IConVar *ConVarRef::GetLinkedConVar()
+{
+ return m_pConVar;
+}
+
+FORCEINLINE_CVAR const char *ConVarRef::GetName() const
+{
+ return m_pConVar->GetName();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Return ConVar value as a float
+//-----------------------------------------------------------------------------
+FORCEINLINE_CVAR float ConVarRef::GetFloat( void ) const
+{
+ return m_pConVarState->m_fValue;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return ConVar value as an int
+//-----------------------------------------------------------------------------
+FORCEINLINE_CVAR int ConVarRef::GetInt( void ) const
+{
+ return m_pConVarState->m_nValue;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc.
+//-----------------------------------------------------------------------------
+FORCEINLINE_CVAR const char *ConVarRef::GetString( void ) const
+{
+ Assert( !IsFlagSet( FCVAR_NEVER_AS_STRING ) );
+ return m_pConVarState->m_pszString;
+}
+
+FORCEINLINE_CVAR bool ConVarRef::GetMin( float& minVal ) const
+{
+ return m_pConVarState->GetMin( minVal );
+}
+
+FORCEINLINE_CVAR bool ConVarRef::GetMax( float& maxVal ) const
+{
+ return m_pConVarState->GetMax( maxVal );
+}
+
+FORCEINLINE_CVAR void ConVarRef::SetValue( const char *pValue )
+{
+ m_pConVar->SetValue( pValue );
+}
+
+FORCEINLINE_CVAR void ConVarRef::SetValue( float flValue )
+{
+ m_pConVar->SetValue( flValue );
+}
+
+FORCEINLINE_CVAR void ConVarRef::SetValue( int nValue )
+{
+ m_pConVar->SetValue( nValue );
+}
+
+FORCEINLINE_CVAR void ConVarRef::SetValue( bool bValue )
+{
+ m_pConVar->SetValue( bValue ? 1 : 0 );
+}
+
+FORCEINLINE_CVAR const char *ConVarRef::GetDefault() const
+{
+ return m_pConVarState->m_pszDefaultValue;
+}
+
+
+//-----------------------------------------------------------------------------
+// Called by the framework to register ConCommands with the ICVar
+//-----------------------------------------------------------------------------
+void ConVar_Register( int nCVarFlag = 0, IConCommandBaseAccessor *pAccessor = NULL );
+void ConVar_Unregister( );
+
+
+//-----------------------------------------------------------------------------
+// Utility methods
+//-----------------------------------------------------------------------------
+void ConVar_PrintFlags( const ConCommandBase *var );
+void ConVar_PrintDescription( const ConCommandBase *pVar );
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Utility class to quickly allow ConCommands to call member methods
+//-----------------------------------------------------------------------------
+#pragma warning (disable : 4355 )
+
+template< class T >
+class CConCommandMemberAccessor : public ConCommand, public ICommandCallback, public ICommandCompletionCallback
+{
+ typedef ConCommand BaseClass;
+ typedef void ( T::*FnMemberCommandCallback_t )( const CCommand &command );
+ typedef int ( T::*FnMemberCommandCompletionCallback_t )( const char *pPartial, CUtlVector< CUtlString > &commands );
+
+public:
+ CConCommandMemberAccessor( T* pOwner, const char *pName, FnMemberCommandCallback_t callback, const char *pHelpString = 0,
+ int flags = 0, FnMemberCommandCompletionCallback_t completionFunc = 0 ) :
+ BaseClass( pName, this, pHelpString, flags, ( completionFunc != 0 ) ? this : NULL )
+ {
+ m_pOwner = pOwner;
+ m_Func = callback;
+ m_CompletionFunc = completionFunc;
+ }
+
+ ~CConCommandMemberAccessor()
+ {
+ Shutdown();
+ }
+
+ void SetOwner( T* pOwner )
+ {
+ m_pOwner = pOwner;
+ }
+
+ virtual void CommandCallback( const CCommand &command )
+ {
+ Assert( m_pOwner && m_Func );
+ (m_pOwner->*m_Func)( command );
+ }
+
+ virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands )
+ {
+ Assert( m_pOwner && m_CompletionFunc );
+ return (m_pOwner->*m_CompletionFunc)( pPartial, commands );
+ }
+
+private:
+ T* m_pOwner;
+ FnMemberCommandCallback_t m_Func;
+ FnMemberCommandCompletionCallback_t m_CompletionFunc;
+};
+
+#pragma warning ( default : 4355 )
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Utility macros to quicky generate a simple console command
+//-----------------------------------------------------------------------------
+#define CON_COMMAND( name, description ) \
+ static void name( const CCommand &args ); \
+ static ConCommand name##_command( #name, name, description ); \
+ static void name( const CCommand &args )
+
+#define CON_COMMAND_F( name, description, flags ) \
+ static void name( const CCommand &args ); \
+ static ConCommand name##_command( #name, name, description, flags ); \
+ static void name( const CCommand &args )
+
+#define CON_COMMAND_F_COMPLETION( name, description, flags, completion ) \
+ static void name( const CCommand &args ); \
+ static ConCommand name##_command( #name, name, description, flags, completion ); \
+ static void name( const CCommand &args )
+
+#define CON_COMMAND_EXTERN( name, _funcname, description ) \
+ void _funcname( const CCommand &args ); \
+ static ConCommand name##_command( #name, _funcname, description ); \
+ void _funcname( const CCommand &args )
+
+#define CON_COMMAND_EXTERN_F( name, _funcname, description, flags ) \
+ void _funcname( const CCommand &args ); \
+ static ConCommand name##_command( #name, _funcname, description, flags ); \
+ void _funcname( const CCommand &args )
+
+#define CON_COMMAND_MEMBER_F( _thisclass, name, _funcname, description, flags ) \
+ void _funcname( const CCommand &args ); \
+ friend class CCommandMemberInitializer_##_funcname; \
+ class CCommandMemberInitializer_##_funcname \
+ { \
+ public: \
+ CCommandMemberInitializer_##_funcname() : m_ConCommandAccessor( NULL, name, &_thisclass::_funcname, description, flags ) \
+ { \
+ m_ConCommandAccessor.SetOwner( GET_OUTER( _thisclass, m_##_funcname##_register ) ); \
+ } \
+ private: \
+ CConCommandMemberAccessor< _thisclass > m_ConCommandAccessor; \
+ }; \
+ \
+ CCommandMemberInitializer_##_funcname m_##_funcname##_register; \
+
+
+#endif // CONVAR_H
diff --git a/public/tier1/convar_serverbounded.h b/public/tier1/convar_serverbounded.h
new file mode 100644
index 0000000..3bdd1ab
--- /dev/null
+++ b/public/tier1/convar_serverbounded.h
@@ -0,0 +1,53 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Helper class for cvars that have restrictions on their value.
+//
+//=============================================================================//
+
+#ifndef CONVAR_SERVERBOUNDED_H
+#define CONVAR_SERVERBOUNDED_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+// This class is used to virtualize a ConVar's value, so the client can restrict its
+// value while connected to a server. When using this across modules, it's important
+// to dynamic_cast it to a ConVar_ServerBounded or you won't get the restricted value.
+//
+// NOTE: FCVAR_USERINFO vars are not virtualized before they are sent to the server
+// (we have no way to detect if the virtualized value would change), so
+// if you want to use a bounded cvar's value on the server, you must rebound it
+// the same way the client does.
+class ConVar_ServerBounded : public ConVar
+{
+public:
+ ConVar_ServerBounded( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString )
+ : ConVar( pName, pDefaultValue, flags, pHelpString )
+ {
+ }
+
+ ConVar_ServerBounded( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, FnChangeCallback_t callback )
+ : ConVar( pName, pDefaultValue, flags, pHelpString, callback )
+ {
+ }
+
+ ConVar_ServerBounded( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax )
+ : ConVar( pName, pDefaultValue, flags, pHelpString, bMin, fMin, bMax, fMax ) {}
+
+ // You must implement GetFloat.
+ virtual float GetFloat() const = 0;
+
+ // You can optionally implement these.
+ virtual int GetInt() const { return (int)GetFloat(); }
+ virtual bool GetBool() const { return ( GetInt() != 0 ); }
+
+ // Use this to get the underlying cvar's value.
+ float GetBaseFloatValue() const
+ {
+ return ConVar::GetFloat();
+ }
+};
+
+
+#endif // CONVAR_SERVERBOUNDED_H
diff --git a/public/tier1/datamanager.h b/public/tier1/datamanager.h
new file mode 100644
index 0000000..8803054
--- /dev/null
+++ b/public/tier1/datamanager.h
@@ -0,0 +1,277 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef RESOURCEMANAGER_H
+#define RESOURCEMANAGER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/threadtools.h"
+#include "utlmultilist.h"
+#include "utlvector.h"
+
+FORWARD_DECLARE_HANDLE( memhandle_t );
+
+#define INVALID_MEMHANDLE ((memhandle_t)0xffffffff)
+
+class CDataManagerBase
+{
+public:
+
+ // public API
+ // -----------------------------------------------------------------------------
+ // memhandle_t CreateResource( params ) // implemented by derived class
+ void DestroyResource( memhandle_t handle );
+
+ // type-safe implementation in derived class
+ //void *LockResource( memhandle_t handle );
+ int UnlockResource( memhandle_t handle );
+ void TouchResource( memhandle_t handle );
+ void MarkAsStale( memhandle_t handle ); // move to head of LRU
+
+ int LockCount( memhandle_t handle );
+ int BreakLock( memhandle_t handle );
+ int BreakAllLocks();
+
+ // HACKHACK: For convenience - offers no lock protection
+ // type-safe implementation in derived class
+ //void *GetResource_NoLock( memhandle_t handle );
+
+ unsigned int TargetSize();
+ unsigned int AvailableSize();
+ unsigned int UsedSize();
+
+ void NotifySizeChanged( memhandle_t handle, unsigned int oldSize, unsigned int newSize );
+
+ void SetTargetSize( unsigned int targetSize );
+
+ // NOTE: flush is equivalent to Destroy
+ unsigned int FlushAllUnlocked();
+ unsigned int FlushToTargetSize();
+ unsigned int FlushAll();
+ unsigned int Purge( unsigned int nBytesToPurge );
+ unsigned int EnsureCapacity( unsigned int size );
+
+ // Thread lock
+ virtual void Lock() {}
+ virtual bool TryLock() { return true; }
+ virtual void Unlock() {}
+
+ // Iteration
+
+ // -----------------------------------------------------------------------------
+
+ // Debugging only!!!!
+ void GetLRUHandleList( CUtlVector< memhandle_t >& list );
+ void GetLockHandleList( CUtlVector< memhandle_t >& list );
+
+
+protected:
+ // derived class must call these to implement public API
+ unsigned short CreateHandle( bool bCreateLocked );
+ memhandle_t StoreResourceInHandle( unsigned short memoryIndex, void *pStore, unsigned int realSize );
+ void *GetResource_NoLock( memhandle_t handle );
+ void *GetResource_NoLockNoLRUTouch( memhandle_t handle );
+ void *LockResource( memhandle_t handle );
+
+ // NOTE: you must call this from the destructor of the derived class! (will assert otherwise)
+ void FreeAllLists() { FlushAll(); m_listsAreFreed = true; }
+
+ CDataManagerBase( unsigned int maxSize );
+ virtual ~CDataManagerBase();
+
+
+ inline unsigned int MemTotal_Inline() const { return m_targetMemorySize; }
+ inline unsigned int MemAvailable_Inline() const { return m_targetMemorySize - m_memUsed; }
+ inline unsigned int MemUsed_Inline() const { return m_memUsed; }
+
+// Implemented by derived class:
+ virtual void DestroyResourceStorage( void * ) = 0;
+ virtual unsigned int GetRealSize( void * ) = 0;
+
+ memhandle_t ToHandle( unsigned short index );
+ unsigned short FromHandle( memhandle_t handle );
+
+ void TouchByIndex( unsigned short memoryIndex );
+ void * GetForFreeByIndex( unsigned short memoryIndex );
+
+ // One of these is stored per active allocation
+ struct resource_lru_element_t
+ {
+ resource_lru_element_t()
+ {
+ lockCount = 0;
+ serial = 1;
+ pStore = 0;
+ }
+
+ unsigned short lockCount;
+ unsigned short serial;
+ void *pStore;
+ };
+
+ unsigned int m_targetMemorySize;
+ unsigned int m_memUsed;
+
+ CUtlMultiList< resource_lru_element_t, unsigned short > m_memoryLists;
+
+ unsigned short m_lruList;
+ unsigned short m_lockList;
+ unsigned short m_freeList;
+ unsigned short m_listsAreFreed : 1;
+ unsigned short m_unused : 15;
+
+};
+
+template< class STORAGE_TYPE, class CREATE_PARAMS, class LOCK_TYPE = STORAGE_TYPE *, class MUTEX_TYPE = CThreadNullMutex>
+class CDataManager : public CDataManagerBase
+{
+ typedef CDataManagerBase BaseClass;
+public:
+
+ CDataManager<STORAGE_TYPE, CREATE_PARAMS, LOCK_TYPE, MUTEX_TYPE>( unsigned int size = (unsigned)-1 ) : BaseClass(size) {}
+
+
+ ~CDataManager<STORAGE_TYPE, CREATE_PARAMS, LOCK_TYPE, MUTEX_TYPE>()
+ {
+ // NOTE: This must be called in all implementations of CDataManager
+ FreeAllLists();
+ }
+
+ // Use GetData() to translate pointer to LOCK_TYPE
+ LOCK_TYPE LockResource( memhandle_t hMem )
+ {
+ void *pLock = BaseClass::LockResource( hMem );
+ if ( pLock )
+ {
+ return StoragePointer(pLock)->GetData();
+ }
+
+ return NULL;
+ }
+
+ // Use GetData() to translate pointer to LOCK_TYPE
+ LOCK_TYPE GetResource_NoLock( memhandle_t hMem )
+ {
+ void *pLock = const_cast<void *>(BaseClass::GetResource_NoLock( hMem ));
+ if ( pLock )
+ {
+ return StoragePointer(pLock)->GetData();
+ }
+ return NULL;
+ }
+
+ // Use GetData() to translate pointer to LOCK_TYPE
+ // Doesn't touch the memory LRU
+ LOCK_TYPE GetResource_NoLockNoLRUTouch( memhandle_t hMem )
+ {
+ void *pLock = const_cast<void *>(BaseClass::GetResource_NoLockNoLRUTouch( hMem ));
+ if ( pLock )
+ {
+ return StoragePointer(pLock)->GetData();
+ }
+ return NULL;
+ }
+
+ // Wrapper to match implementation of allocation with typed storage & alloc params.
+ memhandle_t CreateResource( const CREATE_PARAMS &createParams, bool bCreateLocked = false )
+ {
+ BaseClass::EnsureCapacity(STORAGE_TYPE::EstimatedSize(createParams));
+ unsigned short memoryIndex = BaseClass::CreateHandle( bCreateLocked );
+ STORAGE_TYPE *pStore = STORAGE_TYPE::CreateResource( createParams );
+ return BaseClass::StoreResourceInHandle( memoryIndex, pStore, pStore->Size() );
+ }
+
+ // Iteration. Must lock first
+ memhandle_t GetFirstUnlocked()
+ {
+ unsigned node = m_memoryLists.Head(m_lruList);
+ if ( node == m_memoryLists.InvalidIndex() )
+ {
+ return INVALID_MEMHANDLE;
+ }
+ return ToHandle( node );
+ }
+
+ memhandle_t GetFirstLocked()
+ {
+ unsigned node = m_memoryLists.Head(m_lockList);
+ if ( node == m_memoryLists.InvalidIndex() )
+ {
+ return INVALID_MEMHANDLE;
+ }
+ return ToHandle( node );
+ }
+
+ memhandle_t GetNext( memhandle_t hPrev )
+ {
+ if ( hPrev == INVALID_MEMHANDLE )
+ {
+ return INVALID_MEMHANDLE;
+ }
+
+ unsigned short iNext = m_memoryLists.Next( FromHandle( hPrev ) );
+ if ( iNext == m_memoryLists.InvalidIndex() )
+ {
+ return INVALID_MEMHANDLE;
+ }
+
+ return ToHandle( iNext );
+ }
+
+ MUTEX_TYPE &AccessMutex() { return m_mutex; }
+ virtual void Lock() { m_mutex.Lock(); }
+ virtual bool TryLock() { return m_mutex.TryLock(); }
+ virtual void Unlock() { m_mutex.Unlock(); }
+
+private:
+ STORAGE_TYPE *StoragePointer( void *pMem )
+ {
+ return static_cast<STORAGE_TYPE *>(pMem);
+ }
+
+ virtual void DestroyResourceStorage( void *pStore )
+ {
+ StoragePointer(pStore)->DestroyResource();
+ }
+
+ virtual unsigned int GetRealSize( void *pStore )
+ {
+ return StoragePointer(pStore)->Size();
+ }
+
+ MUTEX_TYPE m_mutex;
+};
+
+//-----------------------------------------------------------------------------
+
+inline unsigned short CDataManagerBase::FromHandle( memhandle_t handle )
+{
+ unsigned int fullWord = (unsigned int)handle;
+ unsigned short serial = fullWord>>16;
+ unsigned short index = fullWord & 0xFFFF;
+ index--;
+ if ( m_memoryLists.IsValidIndex(index) && m_memoryLists[index].serial == serial )
+ return index;
+ return m_memoryLists.InvalidIndex();
+}
+
+inline int CDataManagerBase::LockCount( memhandle_t handle )
+{
+ Lock();
+ int result = 0;
+ unsigned short memoryIndex = FromHandle(handle);
+ if ( memoryIndex != m_memoryLists.InvalidIndex() )
+ {
+ result = m_memoryLists[memoryIndex].lockCount;
+ }
+ Unlock();
+ return result;
+}
+
+
+#endif // RESOURCEMANAGER_H
diff --git a/public/tier1/delegates.h b/public/tier1/delegates.h
new file mode 100644
index 0000000..35a50cf
--- /dev/null
+++ b/public/tier1/delegates.h
@@ -0,0 +1,99 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Simple macros to generate delegation code
+//
+//=============================================================================
+
+#ifndef DELEGATES_H
+#define DELEGATES_H
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+
+#define DELEGATE_TO_OBJECT_0( RetType, FuncName, pDelegated ) RetType FuncName() { return (pDelegated)->FuncName(); }
+#define DELEGATE_TO_OBJECT_0V( FuncName, pDelegated ) void FuncName() { (pDelegated)->FuncName(); }
+#define DELEGATE_TO_OBJECT_1( RetType, FuncName, ArgType1, pDelegated ) RetType FuncName( ArgType1 a1 ) { return (pDelegated)->FuncName( a1 ); }
+#define DELEGATE_TO_OBJECT_1V( FuncName, ArgType1, pDelegated ) void FuncName( ArgType1 a1 ) { (pDelegated)->FuncName( a1 ); }
+#define DELEGATE_TO_OBJECT_2( RetType, FuncName, ArgType1, ArgType2, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2 ) { return (pDelegated)->FuncName( a1, a2 ); }
+#define DELEGATE_TO_OBJECT_2V( FuncName, ArgType1, ArgType2, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2 ) { (pDelegated)->FuncName( a1, a2 ); }
+#define DELEGATE_TO_OBJECT_3( RetType, FuncName, ArgType1, ArgType2, ArgType3, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) { return (pDelegated)->FuncName( a1, a2, a3 ); }
+#define DELEGATE_TO_OBJECT_3V( FuncName, ArgType1, ArgType2, ArgType3, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) { (pDelegated)->FuncName( a1, a2, a3 ); }
+#define DELEGATE_TO_OBJECT_4( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) { return (pDelegated)->FuncName( a1, a2, a3, a4 ); }
+#define DELEGATE_TO_OBJECT_4V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) { (pDelegated)->FuncName( a1, a2, a3, a4 ); }
+#define DELEGATE_TO_OBJECT_5( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5 ); }
+#define DELEGATE_TO_OBJECT_5V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5 ); }
+#define DELEGATE_TO_OBJECT_6( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6 ); }
+#define DELEGATE_TO_OBJECT_6V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6 ); }
+#define DELEGATE_TO_OBJECT_7( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
+#define DELEGATE_TO_OBJECT_7V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
+#define DELEGATE_TO_OBJECT_8( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
+#define DELEGATE_TO_OBJECT_8V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
+#define DELEGATE_TO_OBJECT_9( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
+#define DELEGATE_TO_OBJECT_9V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
+#define DELEGATE_TO_OBJECT_11V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, ArgType10, ArgType11, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9, ArgType10 a10, ArgType11 a11 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 ); }
+
+#define DELEGATE_TO_OBJECT_0C( RetType, FuncName, pDelegated ) RetType FuncName() const { return (pDelegated)->FuncName(); }
+#define DELEGATE_TO_OBJECT_0VC( FuncName, pDelegated ) void FuncName() const { (pDelegated)->FuncName(); }
+#define DELEGATE_TO_OBJECT_1C( RetType, FuncName, ArgType1, pDelegated ) RetType FuncName( ArgType1 a1 ) const { return (pDelegated)->FuncName( a1 ); }
+#define DELEGATE_TO_OBJECT_1VC( FuncName, ArgType1, pDelegated ) void FuncName( ArgType1 a1 ) const { (pDelegated)->FuncName( a1 ); }
+#define DELEGATE_TO_OBJECT_2C( RetType, FuncName, ArgType1, ArgType2, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2 ) const { return (pDelegated)->FuncName( a1, a2 ); }
+#define DELEGATE_TO_OBJECT_2VC( FuncName, ArgType1, ArgType2, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2 ) const { (pDelegated)->FuncName( a1, a2 ); }
+#define DELEGATE_TO_OBJECT_3C( RetType, FuncName, ArgType1, ArgType2, ArgType3, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) const { return (pDelegated)->FuncName( a1, a2, a3 ); }
+#define DELEGATE_TO_OBJECT_3VC( FuncName, ArgType1, ArgType2, ArgType3, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) const { (pDelegated)->FuncName( a1, a2, a3 ); }
+#define DELEGATE_TO_OBJECT_4C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4 ); }
+#define DELEGATE_TO_OBJECT_4VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) const { (pDelegated)->FuncName( a1, a2, a3, a4 ); }
+#define DELEGATE_TO_OBJECT_5C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5 ); }
+#define DELEGATE_TO_OBJECT_5VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5 ); }
+#define DELEGATE_TO_OBJECT_6C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6 ); }
+#define DELEGATE_TO_OBJECT_6VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6 ); }
+#define DELEGATE_TO_OBJECT_7C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
+#define DELEGATE_TO_OBJECT_7VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
+#define DELEGATE_TO_OBJECT_8C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
+#define DELEGATE_TO_OBJECT_8VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
+#define DELEGATE_TO_OBJECT_9C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
+#define DELEGATE_TO_OBJECT_9VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
+
+#define DELEGATE_TO_BASE_0( RetType, FuncName, BaseClass ) RetType FuncName() { return BaseClass::FuncName(); }
+#define DELEGATE_TO_BASE_0V( FuncName, BaseClass ) void FuncName() { BaseClass::FuncName(); }
+#define DELEGATE_TO_BASE_1( RetType, FuncName, ArgType1, BaseClass ) RetType FuncName( ArgType1 a1 ) { return BaseClass::FuncName( a1 ); }
+#define DELEGATE_TO_BASE_1V( FuncName, ArgType1, BaseClass ) void FuncName( ArgType1 a1 ) { BaseClass::FuncName( a1 ); }
+#define DELEGATE_TO_BASE_2( RetType, FuncName, ArgType1, ArgType2, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2 ) { return BaseClass::FuncName( a1, a2 ); }
+#define DELEGATE_TO_BASE_2V( FuncName, ArgType1, ArgType2, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2 ) { BaseClass::FuncName( a1, a2 ); }
+#define DELEGATE_TO_BASE_3( RetType, FuncName, ArgType1, ArgType2, ArgType3, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) { return BaseClass::FuncName( a1, a2, a3 ); }
+#define DELEGATE_TO_BASE_3V( FuncName, ArgType1, ArgType2, ArgType3, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) { BaseClass::FuncName( a1, a2, a3 ); }
+#define DELEGATE_TO_BASE_4( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) { return BaseClass::FuncName( a1, a2, a3, a4 ); }
+#define DELEGATE_TO_BASE_4V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) { BaseClass::FuncName( a1, a2, a3, a4 ); }
+#define DELEGATE_TO_BASE_5( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5 ); }
+#define DELEGATE_TO_BASE_5V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) { BaseClass::FuncName( a1, a2, a3, a4, a5 ); }
+#define DELEGATE_TO_BASE_6( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6 ); }
+#define DELEGATE_TO_BASE_6V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) { BaseClass::FuncName( a1, a2, a3, a4, a5, a6 ); }
+#define DELEGATE_TO_BASE_7( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
+#define DELEGATE_TO_BASE_7V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
+#define DELEGATE_TO_BASE_8( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
+#define DELEGATE_TO_BASE_8V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
+#define DELEGATE_TO_BASE_9( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
+#define DELEGATE_TO_BASE_9V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
+
+#define DELEGATE_TO_BASE_0C( RetType, FuncName, BaseClass ) RetType FuncName() const { return BaseClass::FuncName(); }
+#define DELEGATE_TO_BASE_0VC( FuncName, BaseClass ) void FuncName() const { BaseClass::FuncName(); }
+#define DELEGATE_TO_BASE_1C( RetType, FuncName, ArgType1, BaseClass ) RetType FuncName( ArgType1 a1 ) const { return BaseClass::FuncName( a1 ); }
+#define DELEGATE_TO_BASE_1VC( FuncName, ArgType1, BaseClass ) void FuncName( ArgType1 a1 ) const { BaseClass::FuncName( a1 ); }
+#define DELEGATE_TO_BASE_2C( RetType, FuncName, ArgType1, ArgType2, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2 ) const { return BaseClass::FuncName( a1, a2 ); }
+#define DELEGATE_TO_BASE_2VC( FuncName, ArgType1, ArgType2, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2 ) const { BaseClass::FuncName( a1, a2 ); }
+#define DELEGATE_TO_BASE_3C( RetType, FuncName, ArgType1, ArgType2, ArgType3, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) const { return BaseClass::FuncName( a1, a2, a3 ); }
+#define DELEGATE_TO_BASE_3VC( FuncName, ArgType1, ArgType2, ArgType3, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) const { BaseClass::FuncName( a1, a2, a3 ); }
+#define DELEGATE_TO_BASE_4C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) const { return BaseClass::FuncName( a1, a2, a3, a4 ); }
+#define DELEGATE_TO_BASE_4VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) const { BaseClass::FuncName( a1, a2, a3, a4 ); }
+#define DELEGATE_TO_BASE_5C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5 ); }
+#define DELEGATE_TO_BASE_5VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5 ); }
+#define DELEGATE_TO_BASE_6C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6 ); }
+#define DELEGATE_TO_BASE_6VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5, a6 ); }
+#define DELEGATE_TO_BASE_7C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
+#define DELEGATE_TO_BASE_7VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7 ); }
+#define DELEGATE_TO_BASE_8C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
+#define DELEGATE_TO_BASE_8VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); }
+#define DELEGATE_TO_BASE_9C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
+#define DELEGATE_TO_BASE_9VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); }
+
+#endif // DELEGATES_H
diff --git a/public/tier1/diff.h b/public/tier1/diff.h
new file mode 100644
index 0000000..fc2fb75
--- /dev/null
+++ b/public/tier1/diff.h
@@ -0,0 +1,29 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+// Serialization/unserialization buffer
+//=============================================================================//
+
+#ifndef DIFF_H
+#define DIFF_H
+#pragma once
+
+int FindDiffs(uint8 const *NewBlock, uint8 const *OldBlock,
+ int NewSize, int OldSize, int &DiffListSize,uint8 *Output,uint32 OutSize);
+
+int FindDiffsForLargeFiles(uint8 const *NewBlock, uint8 const *OldBlock,
+ int NewSize, int OldSize, int &DiffListSize,uint8 *Output,
+ uint32 OutSize,
+ int hashsize=65536);
+
+void ApplyDiffs(uint8 const *OldBlock, uint8 const *DiffList,
+ int OldSize, int DiffListSize, int &ResultListSize,uint8 *Output,uint32 OutSize);
+
+int FindDiffsLowMemory(uint8 const *NewBlock, uint8 const *OldBlock,
+ int NewSize, int OldSize, int &DiffListSize,uint8 *Output,uint32 OutSize);
+
+#endif
+
diff --git a/public/tier1/fileio.h b/public/tier1/fileio.h
new file mode 100644
index 0000000..d85ca18
--- /dev/null
+++ b/public/tier1/fileio.h
@@ -0,0 +1,101 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A collection of utility classes to simplify file I/O, and
+// as much as possible contain portability problems. Here avoiding
+// including windows.h.
+//
+//=============================================================================
+
+#ifndef FILEIO_H
+#define FILEIO_H
+
+#if defined (_WIN32)
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
+#if !defined( _PS3 )
+#include <signal.h>
+#endif // _PS3
+#endif
+
+#include "tier0/platform.h"
+#include "tier1/utlstring.h"
+#include "tier1/utllinkedlist.h"
+
+const int64 k_nMillion = 1000000;
+const int64 k_nThousand = 1000;
+const int64 k_nKiloByte = 1024;
+const int64 k_nMegabyte = k_nKiloByte * k_nKiloByte;
+const int64 k_nGigabyte = k_nMegabyte * k_nKiloByte;
+
+class CPathString
+{
+public:
+
+ // Constructors: Automatically fixes slashes and removes double slashes when the object is
+ // constructed, and then knows how to append magic \\?\ on Windows for unicode paths
+ CPathString( const char *pchUTF8Path );
+ ~CPathString();
+
+ // Gets the path in UTF8
+ const char *GetUTF8Path();
+
+ // Gets wchar_t based path, with \\?\ pre-pended (allowing long paths on Win32, should only be used with unicode aware filesystem calls)
+ const wchar_t *GetWCharPathPrePended();
+
+private:
+
+ void PopulateWCharPath();
+
+ char *m_pchUTF8Path;
+ wchar_t *m_pwchWideCharPathPrepended;
+
+};
+
+#if !defined(_PS3)
+//-----------------------------------------------------------------------------
+// Purpose: Encapsulates watching a directory for file changes
+//-----------------------------------------------------------------------------
+class CDirWatcher
+{
+public:
+ CDirWatcher();
+ ~CDirWatcher();
+
+ // only one directory can be watched at a time
+ void SetDirToWatch( const char *pchDir );
+
+ // retrieve any changes
+ bool GetChangedFile( CUtlString *psFile );
+
+#ifdef DBGFLAG_VALIDATE
+ void Validate( CValidator &validator, const char *pchName );
+#endif
+
+private:
+ CUtlLinkedList<CUtlString> m_listChangedFiles;
+ void *m_hFile;
+ void *m_pOverlapped;
+ void *m_pFileInfo;
+#ifdef OSX
+public:
+ struct timespec m_modTime;
+ void AddFileToChangeList( const char *pchFile );
+ CUtlString m_BaseDir;
+private:
+ void *m_WatcherStream;
+#endif
+ friend class CDirWatcherFriend;
+
+#ifdef LINUX
+ void AddFileToChangeList( const char *pchFile );
+#endif
+#ifdef WIN32
+ // used by callback functions to push a file onto the list
+ void AddFileToChangeList( const char *pchFile );
+ void PostDirWatch();
+#endif
+};
+#endif // _PS3
+
+#endif // FILEIO_H
diff --git a/public/tier1/fmtstr.h b/public/tier1/fmtstr.h
new file mode 100644
index 0000000..66ea88f
--- /dev/null
+++ b/public/tier1/fmtstr.h
@@ -0,0 +1,366 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A simple class for performing safe and in-expression sprintf-style
+// string formatting
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef FMTSTR_H
+#define FMTSTR_H
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "tier0/platform.h"
+#include "tier0/dbg.h"
+#include "tier1/strtools.h"
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+#if defined(POSIX)
+#pragma GCC visibility push(hidden)
+#endif
+
+//=============================================================================
+
+// using macro to be compatable with GCC
+#define FmtStrVSNPrintf( szBuf, nBufSize, bQuietTruncation, ppszFormat, nPrevLen, lastArg ) \
+ do \
+ { \
+ int result; \
+ va_list arg_ptr; \
+ bool bTruncated = false; \
+ static int scAsserted = 0; \
+ \
+ va_start(arg_ptr, lastArg); \
+ result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \
+ va_end(arg_ptr); \
+ \
+ (szBuf)[(nBufSize)-1] = 0; \
+ if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \
+ { \
+ Warning( "FmtStrVSNPrintf truncated to %d without QUIET_TRUNCATION specified!\n", ( int )( nBufSize ) ); \
+ AssertMsg( 0, "FmtStrVSNPrintf truncated without QUIET_TRUNCATION specified!\n" ); \
+ scAsserted++; \
+ } \
+ m_nLength = nPrevLen + result; \
+ } \
+ while (0)
+
+// using macro to be compatable with GCC
+#define FmtStrVSNPrintfNoLengthFixup( szBuf, nBufSize, bQuietTruncation, ppszFormat, nPrevLen, lastArg ) \
+ do \
+ { \
+ int result; \
+ va_list arg_ptr; \
+ bool bTruncated = false; \
+ static int scAsserted = 0; \
+ \
+ va_start(arg_ptr, lastArg); \
+ result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \
+ va_end(arg_ptr); \
+ \
+ (szBuf)[(nBufSize)-1] = 0; \
+ if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \
+ { \
+ Warning( "FmtStrVSNPrintf truncated to %d without QUIET_TRUNCATION specified!\n", ( int )( nBufSize ) ); \
+ AssertMsg( 0, "FmtStrVSNPrintf truncated without QUIET_TRUNCATION specified!\n" ); \
+ scAsserted++; \
+ } \
+ } \
+ while (0)
+
+//-----------------------------------------------------------------------------
+//
+// Purpose: String formatter with specified size
+//
+
+template <int SIZE_BUF, bool QUIET_TRUNCATION = false >
+class CFmtStrN
+{
+public:
+ CFmtStrN()
+ {
+ InitQuietTruncation();
+ m_szBuf[0] = 0;
+ m_nLength = 0;
+ }
+
+ // Standard C formatting
+ CFmtStrN(PRINTF_FORMAT_STRING const char *pszFormat, ...) FMTFUNCTION( 2, 3 )
+ {
+ InitQuietTruncation();
+ FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
+ }
+
+ // Use this for pass-through formatting
+ CFmtStrN(const char ** ppszFormat, ...)
+ {
+ InitQuietTruncation();
+ FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat, 0, ppszFormat );
+ }
+
+ // Explicit reformat
+ const char *sprintf(PRINTF_FORMAT_STRING const char *pszFormat, ...) FMTFUNCTION( 2, 3 )
+ {
+ InitQuietTruncation();
+ FmtStrVSNPrintf(m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
+ return m_szBuf;
+ }
+
+ // Use this for va_list formatting
+ const char *sprintf_argv(const char *pszFormat, va_list arg_ptr)
+ {
+ int result;
+ bool bTruncated = false;
+ static int s_nWarned = 0;
+
+ InitQuietTruncation();
+ result = V_vsnprintfRet( m_szBuf, SIZE_BUF - 1, pszFormat, arg_ptr, &bTruncated );
+ m_szBuf[SIZE_BUF - 1] = 0;
+ if ( bTruncated && !m_bQuietTruncation && ( s_nWarned < 5 ) )
+ {
+ Warning( "CFmtStr truncated to %d without QUIET_TRUNCATION specified!\n", SIZE_BUF );
+ AssertMsg( 0, "CFmtStr truncated without QUIET_TRUNCATION specified!\n" );
+ s_nWarned++;
+ }
+ m_nLength = V_strlen( m_szBuf );
+ return m_szBuf;
+ }
+
+ // Use this for pass-through formatting
+ void VSprintf(const char **ppszFormat, ...)
+ {
+ InitQuietTruncation();
+ FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat, 0, ppszFormat );
+ }
+
+ // Compatible API with CUtlString for converting to const char*
+ const char *Get( ) const { return m_szBuf; }
+ const char *String( ) const { return m_szBuf; }
+ // Use for access
+ operator const char *() const { return m_szBuf; }
+ char *Access() { return m_szBuf; }
+
+ // Access template argument
+ static inline int GetMaxLength() { return SIZE_BUF-1; }
+
+ CFmtStrN<SIZE_BUF,QUIET_TRUNCATION> & operator=( const char *pchValue )
+ {
+ V_strncpy( m_szBuf, pchValue, SIZE_BUF );
+ m_nLength = V_strlen( m_szBuf );
+ return *this;
+ }
+
+ CFmtStrN<SIZE_BUF,QUIET_TRUNCATION> & operator+=( const char *pchValue )
+ {
+ Append( pchValue );
+ return *this;
+ }
+
+ int Length() const { return m_nLength; }
+
+ void SetLength( int nLength )
+ {
+ m_nLength = Min( nLength, SIZE_BUF - 1 );
+ m_szBuf[m_nLength] = '\0';
+ }
+
+ void Clear()
+ {
+ m_szBuf[0] = 0;
+ m_nLength = 0;
+ }
+
+ void AppendFormat( PRINTF_FORMAT_STRING const char *pchFormat, ... ) FMTFUNCTION( 2, 3 )
+ {
+ char *pchEnd = m_szBuf + m_nLength;
+ FmtStrVSNPrintf( pchEnd, SIZE_BUF - m_nLength, m_bQuietTruncation, &pchFormat, m_nLength, pchFormat );
+ }
+
+ void AppendFormatV( const char *pchFormat, va_list args );
+
+ void Append( const char *pchValue )
+ {
+ // This function is close to the metal to cut down on the CPU cost
+ // of the previous incantation of Append which was implemented as
+ // AppendFormat( "%s", pchValue ). This implementation, though not
+ // as easy to read, instead does a strcpy from the existing end
+ // point of the CFmtStrN. This brings something like a 10-20x speedup
+ // in my rudimentary tests. It isn't using V_strncpy because that
+ // function doesn't return the number of characters copied, which
+ // we need to adjust m_nLength. Doing the V_strncpy with a V_strlen
+ // afterwards took twice as long as this implementations in tests,
+ // so V_strncpy's implementation was used to write this method.
+ char *pDest = m_szBuf + m_nLength;
+ const int maxLen = SIZE_BUF - m_nLength;
+ char *pLast = pDest + maxLen - 1;
+ while ( (pDest < pLast) && (*pchValue != 0) )
+ {
+ *pDest = *pchValue;
+ ++pDest; ++pchValue;
+ }
+ *pDest = 0;
+ m_nLength = pDest - m_szBuf;
+ }
+
+ //optimized version of append for just adding a single character
+ void Append( char ch )
+ {
+ if( m_nLength < SIZE_BUF - 1 )
+ {
+ m_szBuf[ m_nLength ] = ch;
+ m_nLength++;
+ m_szBuf[ m_nLength ] = '\0';
+ }
+ }
+
+ void AppendIndent( uint32 unCount, char chIndent = '\t' );
+
+ void SetQuietTruncation( bool bQuiet ) { m_bQuietTruncation = bQuiet; }
+
+protected:
+ virtual void InitQuietTruncation()
+ {
+ m_bQuietTruncation = QUIET_TRUNCATION;
+ }
+
+ bool m_bQuietTruncation;
+
+private:
+ char m_szBuf[SIZE_BUF];
+ int m_nLength;
+};
+
+
+// Version which will not assert if strings are truncated
+
+template < int SIZE_BUF >
+class CFmtStrQuietTruncationN : public CFmtStrN<SIZE_BUF, true >
+{
+};
+
+
+template< int SIZE_BUF, bool QUIET_TRUNCATION >
+void CFmtStrN< SIZE_BUF, QUIET_TRUNCATION >::AppendIndent( uint32 unCount, char chIndent )
+{
+ Assert( Length() + unCount < SIZE_BUF );
+ if( Length() + unCount >= SIZE_BUF )
+ unCount = SIZE_BUF - (1+Length());
+ for ( uint32 x = 0; x < unCount; x++ )
+ {
+ m_szBuf[ m_nLength++ ] = chIndent;
+ }
+ m_szBuf[ m_nLength ] = '\0';
+}
+
+template< int SIZE_BUF, bool QUIET_TRUNCATION >
+void CFmtStrN< SIZE_BUF, QUIET_TRUNCATION >::AppendFormatV( const char *pchFormat, va_list args )
+{
+ int cubPrinted = V_vsnprintf( m_szBuf+Length(), SIZE_BUF - Length(), pchFormat, args );
+ m_nLength += cubPrinted;
+}
+
+
+#if defined(POSIX)
+#pragma GCC visibility pop
+#endif
+
+//-----------------------------------------------------------------------------
+//
+// Purpose: Default-sized string formatter
+//
+
+#define FMTSTR_STD_LEN 256
+
+typedef CFmtStrN<FMTSTR_STD_LEN> CFmtStr;
+typedef CFmtStrQuietTruncationN<FMTSTR_STD_LEN> CFmtStrQuietTruncation;
+typedef CFmtStrN<1024> CFmtStr1024;
+typedef CFmtStrN<8192> CFmtStrMax;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Fast-path number-to-string helper (with optional quoting)
+// Derived off of the Steam CNumStr but with a few tweaks, such as
+// trimming off the in-our-cases-unnecessary strlen calls (by not
+// storing the length in the class).
+//-----------------------------------------------------------------------------
+
+class CNumStr
+{
+public:
+ CNumStr() { m_szBuf[0] = 0; }
+
+ explicit CNumStr( bool b ) { SetBool( b ); }
+
+ explicit CNumStr( int8 n8 ) { SetInt8( n8 ); }
+ explicit CNumStr( uint8 un8 ) { SetUint8( un8 ); }
+ explicit CNumStr( int16 n16 ) { SetInt16( n16 ); }
+ explicit CNumStr( uint16 un16 ) { SetUint16( un16 ); }
+ explicit CNumStr( int32 n32 ) { SetInt32( n32 ); }
+ explicit CNumStr( uint32 un32 ) { SetUint32( un32 ); }
+ explicit CNumStr( int64 n64 ) { SetInt64( n64 ); }
+ explicit CNumStr( uint64 un64 ) { SetUint64( un64 ); }
+
+#if defined(COMPILER_GCC) && defined(PLATFORM_64BITS)
+ explicit CNumStr( lint64 n64 ) { SetInt64( (int64)n64 ); }
+ explicit CNumStr( ulint64 un64 ) { SetUint64( (uint64)un64 ); }
+#endif
+
+ explicit CNumStr( double f ) { SetDouble( f ); }
+ explicit CNumStr( float f ) { SetFloat( f ); }
+
+ inline void SetBool( bool b ) { Q_memcpy( m_szBuf, b ? "1" : "0", 2 ); }
+
+#ifdef _WIN32
+ inline void SetInt8( int8 n8 ) { _itoa( (int32)n8, m_szBuf, 10 ); }
+ inline void SetUint8( uint8 un8 ) { _itoa( (int32)un8, m_szBuf, 10 ); }
+ inline void SetInt16( int16 n16 ) { _itoa( (int32)n16, m_szBuf, 10 ); }
+ inline void SetUint16( uint16 un16 ) { _itoa( (int32)un16, m_szBuf, 10 ); }
+ inline void SetInt32( int32 n32 ) { _itoa( n32, m_szBuf, 10 ); }
+ inline void SetUint32( uint32 un32 ) { _i64toa( (int64)un32, m_szBuf, 10 ); }
+ inline void SetInt64( int64 n64 ) { _i64toa( n64, m_szBuf, 10 ); }
+ inline void SetUint64( uint64 un64 ) { _ui64toa( un64, m_szBuf, 10 ); }
+#else
+ inline void SetInt8( int8 n8 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)n8 ); }
+ inline void SetUint8( uint8 un8 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)un8 ); }
+ inline void SetInt16( int16 n16 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)n16 ); }
+ inline void SetUint16( uint16 un16 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)un16 ); }
+ inline void SetInt32( int32 n32 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", n32 ); }
+ inline void SetUint32( uint32 un32 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%u", un32 ); }
+ inline void SetInt64( int64 n64 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%lld", n64 ); }
+ inline void SetUint64( uint64 un64 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%llu", un64 ); }
+#endif
+
+ inline void SetDouble( double f ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%.18g", f ); }
+ inline void SetFloat( float f ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%.18g", f ); }
+
+ inline void SetHexUint64( uint64 un64 ) { Q_binarytohex( (byte *)&un64, sizeof( un64 ), m_szBuf, sizeof( m_szBuf ) ); }
+
+ operator const char *() const { return m_szBuf; }
+ const char* String() const { return m_szBuf; }
+
+ void AddQuotes()
+ {
+ Assert( m_szBuf[0] != '"' );
+ const int nLength = Q_strlen( m_szBuf );
+ Q_memmove( m_szBuf + 1, m_szBuf, nLength );
+ m_szBuf[0] = '"';
+ m_szBuf[nLength + 1] = '"';
+ m_szBuf[nLength + 2] = 0;
+ }
+
+protected:
+ char m_szBuf[28]; // long enough to hold 18 digits of precision, a decimal, a - sign, e+### suffix, and quotes
+
+};
+
+
+//=============================================================================
+
+bool BGetLocalFormattedDateAndTime( time_t timeVal, char *pchDate, int cubDate, char *pchTime, int cubTime );
+bool BGetLocalFormattedDate( time_t timeVal, char *pchDate, int cubDate );
+bool BGetLocalFormattedTime( time_t timeVal, char *pchTime, int cubTime );
+
+#endif // FMTSTR_H
diff --git a/public/tier1/functors.h b/public/tier1/functors.h
new file mode 100644
index 0000000..afc45d3
--- /dev/null
+++ b/public/tier1/functors.h
@@ -0,0 +1,637 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implements a generic infrastucture for functors combining
+// a number of techniques to provide transparent parameter type
+// deduction and packaging. Supports both member and non-member functions.
+//
+// See also: http://en.wikipedia.org/wiki/Function_object
+//
+// Note that getting into the guts of this file is not for the
+// feint of heart. The core concept here is that the compiler can
+// figure out all the parameter types.
+//
+// E.g.:
+//
+// struct CMyClass
+// {
+// void foo( int i) {}
+// };
+//
+// int bar(int i) { return i; }
+//
+// CMyClass myInstance;
+//
+// CFunctor *pFunctor = CreateFunctor( &myInstance, CMyClass::foo, 8675 );
+// CFunctor *pFunctor2 = CreateFunctor( &bar, 309 );
+//
+// void CallEm()
+// {
+// (*pFunctor)();
+// (*pFunctor2)();
+// }
+//
+//=============================================================================
+
+#ifndef FUNCTORS_H
+#define FUNCTORS_H
+
+#include "tier0/platform.h"
+#include "tier1/refcount.h"
+#include "tier1/utlenvelope.h"
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+
+//-----------------------------------------------------------------------------
+//
+// Macros used as basis for template generation. Just ignore the man behind the
+// curtain
+//
+//-----------------------------------------------------------------------------
+
+#define FUNC_TEMPLATE_ARG_PARAMS_0
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_0
+#define FUNC_ARG_MEMBERS_0
+#define FUNC_ARG_FORMAL_PARAMS_0
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_0
+#define FUNC_CALL_ARGS_INIT_0
+#define FUNC_CALL_MEMBER_ARGS_0
+#define FUNC_CALL_ARGS_0
+#define FUNC_FUNCTOR_CALL_ARGS_0
+#define FUNC_TEMPLATE_FUNC_PARAMS_0
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_0
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_0
+
+#define FUNC_TEMPLATE_ARG_PARAMS_1 , typename ARG_TYPE_1
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_1 , ARG_TYPE_1
+#define FUNC_ARG_MEMBERS_1 ARG_TYPE_1 m_arg1
+#define FUNC_ARG_FORMAL_PARAMS_1 , const ARG_TYPE_1 &arg1
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_1 const ARG_TYPE_1 &arg1
+#define FUNC_CALL_ARGS_INIT_1 , m_arg1( arg1 )
+#define FUNC_CALL_MEMBER_ARGS_1 m_arg1
+#define FUNC_CALL_ARGS_1 arg1
+#define FUNC_FUNCTOR_CALL_ARGS_1 , arg1
+#define FUNC_TEMPLATE_FUNC_PARAMS_1 , typename FUNC_ARG_TYPE_1
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_1 FUNC_ARG_TYPE_1
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_1 , FUNC_ARG_TYPE_1
+
+#define FUNC_TEMPLATE_ARG_PARAMS_2 , typename ARG_TYPE_1, typename ARG_TYPE_2
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_2 , ARG_TYPE_1, ARG_TYPE_2
+#define FUNC_ARG_MEMBERS_2 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2
+#define FUNC_ARG_FORMAL_PARAMS_2 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_2 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2
+#define FUNC_CALL_ARGS_INIT_2 , m_arg1( arg1 ), m_arg2( arg2 )
+#define FUNC_CALL_MEMBER_ARGS_2 m_arg1, m_arg2
+#define FUNC_CALL_ARGS_2 arg1, arg2
+#define FUNC_FUNCTOR_CALL_ARGS_2 , arg1, arg2
+#define FUNC_TEMPLATE_FUNC_PARAMS_2 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_2 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_2 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2
+
+#define FUNC_TEMPLATE_ARG_PARAMS_3 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_3 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3
+#define FUNC_ARG_MEMBERS_3 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3
+#define FUNC_ARG_FORMAL_PARAMS_3 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_3 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3
+#define FUNC_CALL_ARGS_INIT_3 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 )
+#define FUNC_CALL_MEMBER_ARGS_3 m_arg1, m_arg2, m_arg3
+#define FUNC_CALL_ARGS_3 arg1, arg2, arg3
+#define FUNC_FUNCTOR_CALL_ARGS_3 , arg1, arg2, arg3
+#define FUNC_TEMPLATE_FUNC_PARAMS_3 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_3 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_3 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3
+
+#define FUNC_TEMPLATE_ARG_PARAMS_4 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_4 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4
+#define FUNC_ARG_MEMBERS_4 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4
+#define FUNC_ARG_FORMAL_PARAMS_4 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_4 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4
+#define FUNC_CALL_ARGS_INIT_4 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 )
+#define FUNC_CALL_MEMBER_ARGS_4 m_arg1, m_arg2, m_arg3, m_arg4
+#define FUNC_CALL_ARGS_4 arg1, arg2, arg3, arg4
+#define FUNC_FUNCTOR_CALL_ARGS_4 , arg1, arg2, arg3, arg4
+#define FUNC_TEMPLATE_FUNC_PARAMS_4 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_4 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_4 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4
+
+#define FUNC_TEMPLATE_ARG_PARAMS_5 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_5 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5
+#define FUNC_ARG_MEMBERS_5 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5
+#define FUNC_ARG_FORMAL_PARAMS_5 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_5 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5
+#define FUNC_CALL_ARGS_INIT_5 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 )
+#define FUNC_CALL_MEMBER_ARGS_5 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5
+#define FUNC_CALL_ARGS_5 arg1, arg2, arg3, arg4, arg5
+#define FUNC_FUNCTOR_CALL_ARGS_5 , arg1, arg2, arg3, arg4, arg5
+#define FUNC_TEMPLATE_FUNC_PARAMS_5 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_5 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_5 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5
+
+#define FUNC_TEMPLATE_ARG_PARAMS_6 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_6 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6
+#define FUNC_ARG_MEMBERS_6 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6
+#define FUNC_ARG_FORMAL_PARAMS_6 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_6 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6
+#define FUNC_CALL_ARGS_INIT_6 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 )
+#define FUNC_CALL_MEMBER_ARGS_6 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6
+#define FUNC_CALL_ARGS_6 arg1, arg2, arg3, arg4, arg5, arg6
+#define FUNC_FUNCTOR_CALL_ARGS_6 , arg1, arg2, arg3, arg4, arg5, arg6
+#define FUNC_TEMPLATE_FUNC_PARAMS_6 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_6 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_6 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6
+
+#define FUNC_TEMPLATE_ARG_PARAMS_7 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_7 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7
+#define FUNC_ARG_MEMBERS_7 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7;
+#define FUNC_ARG_FORMAL_PARAMS_7 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_7 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7
+#define FUNC_CALL_ARGS_INIT_7 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 )
+#define FUNC_CALL_MEMBER_ARGS_7 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7
+#define FUNC_CALL_ARGS_7 arg1, arg2, arg3, arg4, arg5, arg6, arg7
+#define FUNC_FUNCTOR_CALL_ARGS_7 , arg1, arg2, arg3, arg4, arg5, arg6, arg7
+#define FUNC_TEMPLATE_FUNC_PARAMS_7 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_7 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_7 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7
+
+#define FUNC_TEMPLATE_ARG_PARAMS_8 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_8 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8
+#define FUNC_ARG_MEMBERS_8 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8;
+#define FUNC_ARG_FORMAL_PARAMS_8 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_8 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8
+#define FUNC_CALL_ARGS_INIT_8 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 )
+#define FUNC_CALL_MEMBER_ARGS_8 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8
+#define FUNC_CALL_ARGS_8 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8
+#define FUNC_FUNCTOR_CALL_ARGS_8 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8
+#define FUNC_TEMPLATE_FUNC_PARAMS_8 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_8 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_8 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8
+
+#define FUNC_TEMPLATE_ARG_PARAMS_9 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_9 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9
+#define FUNC_ARG_MEMBERS_9 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9;
+#define FUNC_ARG_FORMAL_PARAMS_9 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_9 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9
+#define FUNC_CALL_ARGS_INIT_9 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 )
+#define FUNC_CALL_MEMBER_ARGS_9 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9
+#define FUNC_CALL_ARGS_9 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
+#define FUNC_FUNCTOR_CALL_ARGS_9 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
+#define FUNC_TEMPLATE_FUNC_PARAMS_9 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_9 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_9 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9
+
+#define FUNC_TEMPLATE_ARG_PARAMS_10 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_10 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10
+#define FUNC_ARG_MEMBERS_10 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10;
+#define FUNC_ARG_FORMAL_PARAMS_10 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_10 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10
+#define FUNC_CALL_ARGS_INIT_10 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 )
+#define FUNC_CALL_MEMBER_ARGS_10 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10
+#define FUNC_CALL_ARGS_10 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10
+#define FUNC_FUNCTOR_CALL_ARGS_10 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10
+#define FUNC_TEMPLATE_FUNC_PARAMS_10 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_10 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_10 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10
+
+#define FUNC_TEMPLATE_ARG_PARAMS_11 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_11 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11
+#define FUNC_ARG_MEMBERS_11 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11
+#define FUNC_ARG_FORMAL_PARAMS_11 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_11 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11
+#define FUNC_CALL_ARGS_INIT_11 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 )
+#define FUNC_CALL_MEMBER_ARGS_11 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11
+#define FUNC_CALL_ARGS_11 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11
+#define FUNC_FUNCTOR_CALL_ARGS_11 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11
+#define FUNC_TEMPLATE_FUNC_PARAMS_11 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_11 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_11 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11
+
+#define FUNC_TEMPLATE_ARG_PARAMS_12 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_12 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12
+#define FUNC_ARG_MEMBERS_12 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12
+#define FUNC_ARG_FORMAL_PARAMS_12 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_12 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12
+#define FUNC_CALL_ARGS_INIT_12 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 )
+#define FUNC_CALL_MEMBER_ARGS_12 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12
+#define FUNC_CALL_ARGS_12 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12
+#define FUNC_FUNCTOR_CALL_ARGS_12 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12
+#define FUNC_TEMPLATE_FUNC_PARAMS_12 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_12 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_12 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12
+
+#define FUNC_TEMPLATE_ARG_PARAMS_13 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_13 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13
+#define FUNC_ARG_MEMBERS_13 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12; ARG_TYPE_13 m_arg13
+#define FUNC_ARG_FORMAL_PARAMS_13 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_13 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13
+#define FUNC_CALL_ARGS_INIT_13 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 )
+#define FUNC_CALL_MEMBER_ARGS_13 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13
+#define FUNC_CALL_ARGS_13 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13
+#define FUNC_FUNCTOR_CALL_ARGS_13 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13
+#define FUNC_TEMPLATE_FUNC_PARAMS_13 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12, typename FUNC_ARG_TYPE_13
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_13 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12, FUNC_ARG_TYPE_13
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_13 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12, FUNC_ARG_TYPE_13
+
+#define FUNC_TEMPLATE_ARG_PARAMS_14 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13, typename ARG_TYPE_14
+#define FUNC_BASE_TEMPLATE_ARG_PARAMS_14 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13, ARG_TYPE_14
+#define FUNC_ARG_MEMBERS_14 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12; ARG_TYPE_13 m_arg13; ARG_TYPE_14 m_arg14
+#define FUNC_ARG_FORMAL_PARAMS_14 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13, const ARG_TYPE_14 &arg14
+#define FUNC_PROXY_ARG_FORMAL_PARAMS_14 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13, const ARG_TYPE_14 &arg14
+#define FUNC_CALL_ARGS_INIT_14 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 ), m_arg14( arg14 )
+#define FUNC_CALL_MEMBER_ARGS_14 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14
+#define FUNC_CALL_ARGS_14 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14
+#define FUNC_FUNCTOR_CALL_ARGS_14 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14
+#define FUNC_TEMPLATE_FUNC_PARAMS_14 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12, typename FUNC_ARG_TYPE_13, typename FUNC_ARG_TYPE_14
+#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_14 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12, FUNC_ARG_TYPE_13, FUNC_ARG_TYPE_14
+#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_14 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12, FUNC_ARG_TYPE_13, FUNC_ARG_TYPE_14
+
+#define FUNC_GENERATE_ALL( INNERMACRONAME ) \
+ INNERMACRONAME(0); \
+ INNERMACRONAME(1); \
+ INNERMACRONAME(2); \
+ INNERMACRONAME(3); \
+ INNERMACRONAME(4); \
+ INNERMACRONAME(5); \
+ INNERMACRONAME(6); \
+ INNERMACRONAME(7); \
+ INNERMACRONAME(8); \
+ INNERMACRONAME(9); \
+ INNERMACRONAME(10);\
+ INNERMACRONAME(11);\
+ INNERMACRONAME(12);\
+ INNERMACRONAME(13);\
+ INNERMACRONAME(14)
+
+//-----------------------------------------------------------------------------
+//
+// Purpose: Base class of all function objects
+//
+//-----------------------------------------------------------------------------
+
+abstract_class CFunctor : public IRefCounted
+{
+public:
+ CFunctor()
+ {
+#ifdef DEBUG
+ m_nUserID = 0;
+#endif
+ }
+ // Add a virtual destructor to silence the clang warning.
+ // This is harmless but not important since the only derived class
+ // doesn't have a destructor.
+ virtual ~CFunctor() {}
+
+ virtual void operator()() = 0;
+
+ unsigned m_nUserID; // For debugging
+};
+
+
+//-----------------------------------------------------------------------------
+// When calling through a functor, care needs to be taken to not pass objects that might go away.
+// Since this code determines the type to store in the functor based on the actual arguments,
+// this is achieved by changing the point of call.
+//
+// See also CUtlEnvelope
+//-----------------------------------------------------------------------------
+
+// convert a reference to a passable value
+template <typename T>
+inline T RefToVal(const T &item)
+{
+ return item;
+}
+
+//-----------------------------------------------------------------------------
+// This class can be used to pass into a functor a proxy object for a pointer
+// to be resolved later. For example, you can execute a "call" on a resource
+// whose actual value is not known until a later time
+//-----------------------------------------------------------------------------
+
+template <typename T>
+class CLateBoundPtr
+{
+public:
+ CLateBoundPtr( T **ppObject )
+ : m_ppObject( ppObject )
+ {
+ }
+
+ T *operator->() { return *m_ppObject; }
+ T &operator *() { return **m_ppObject; }
+ operator T *() const { return (T*)(*m_ppObject); }
+ operator void *() { return *m_ppObject; }
+
+private:
+ T **m_ppObject;
+};
+
+//-----------------------------------------------------------------------------
+//
+// Purpose: Classes to define memory management policies when operating
+// on pointers to members
+//
+//-----------------------------------------------------------------------------
+
+class CFuncMemPolicyNone
+{
+public:
+ static void OnAcquire(void *pObject) {}
+ static void OnRelease(void *pObject) {}
+};
+
+template <class OBJECT_TYPE_PTR = IRefCounted *>
+class CFuncMemPolicyRefCount
+{
+public:
+ static void OnAcquire(OBJECT_TYPE_PTR pObject) { pObject->AddRef(); }
+ static void OnRelease(OBJECT_TYPE_PTR pObject) { pObject->Release(); }
+};
+
+//-----------------------------------------------------------------------------
+//
+// Purpose: Function proxy is a generic facility for holding a function
+// pointer. Can be used on own, though primarily for use
+// by this file
+//
+//-----------------------------------------------------------------------------
+
+template <class OBJECT_TYPE_PTR, typename FUNCTION_TYPE, class MEM_POLICY = CFuncMemPolicyNone >
+class CMemberFuncProxyBase
+{
+protected:
+ CMemberFuncProxyBase( OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied )
+ : m_pObject( pObject ),
+ m_pfnProxied( pfnProxied )
+ {
+ MEM_POLICY::OnAcquire(m_pObject);
+ }
+
+ ~CMemberFuncProxyBase()
+ {
+ MEM_POLICY::OnRelease(m_pObject);
+ }
+
+ void Set( OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied )
+ {
+ m_pfnProxied = pfnProxied;
+ m_pObject = pObject;
+ }
+
+ void OnCall()
+ {
+ Assert( (void *)m_pObject != NULL );
+ }
+
+ FUNCTION_TYPE m_pfnProxied;
+ OBJECT_TYPE_PTR m_pObject;
+};
+
+
+#define DEFINE_MEMBER_FUNC_PROXY( N ) \
+ template <class OBJECT_TYPE_PTR, typename FUNCTION_TYPE FUNC_TEMPLATE_ARG_PARAMS_##N, class MEM_POLICY = CFuncMemPolicyNone> \
+ class CMemberFuncProxy##N : public CMemberFuncProxyBase<OBJECT_TYPE_PTR, FUNCTION_TYPE, MEM_POLICY> \
+ { \
+ public: \
+ CMemberFuncProxy##N( OBJECT_TYPE_PTR pObject = NULL, FUNCTION_TYPE pfnProxied = NULL ) \
+ : CMemberFuncProxyBase<OBJECT_TYPE_PTR, FUNCTION_TYPE, MEM_POLICY >( pObject, pfnProxied ) \
+ { \
+ } \
+ \
+ void operator()( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ this->OnCall(); \
+ ((*this->m_pObject).*this->m_pfnProxied)( FUNC_CALL_ARGS_##N ); \
+ } \
+ }
+
+FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNC_PROXY );
+
+
+//-----------------------------------------------------------------------------
+//
+// The actual functor implementation
+//
+//-----------------------------------------------------------------------------
+
+#include "tier0/memdbgon.h"
+
+typedef CRefCounted1<CFunctor, CRefCountServiceMT> CFunctorBase;
+
+#define DEFINE_FUNCTOR_TEMPLATE(N) \
+ template <typename FUNC_TYPE FUNC_TEMPLATE_ARG_PARAMS_##N, class FUNCTOR_BASE = CFunctorBase> \
+ class CFunctor##N : public CFunctorBase \
+ { \
+ public: \
+ CFunctor##N( FUNC_TYPE pfnProxied FUNC_ARG_FORMAL_PARAMS_##N ) : m_pfnProxied( pfnProxied ) FUNC_CALL_ARGS_INIT_##N {} \
+ void operator()() { m_pfnProxied(FUNC_CALL_MEMBER_ARGS_##N); } \
+ \
+ private: \
+ FUNC_TYPE m_pfnProxied; \
+ FUNC_ARG_MEMBERS_##N; \
+ }
+
+FUNC_GENERATE_ALL( DEFINE_FUNCTOR_TEMPLATE );
+
+#define DEFINE_MEMBER_FUNCTOR( N ) \
+ template <class OBJECT_TYPE_PTR, typename FUNCTION_TYPE FUNC_TEMPLATE_ARG_PARAMS_##N, class FUNCTOR_BASE = CFunctorBase, class MEM_POLICY = CFuncMemPolicyNone> \
+ class CMemberFunctor##N : public FUNCTOR_BASE \
+ { \
+ public: \
+ CMemberFunctor##N( OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied FUNC_ARG_FORMAL_PARAMS_##N ) : m_Proxy( pObject, pfnProxied ) FUNC_CALL_ARGS_INIT_##N {} \
+ void operator()() { m_Proxy(FUNC_CALL_MEMBER_ARGS_##N); } \
+ \
+ private: \
+ CMemberFuncProxy##N<OBJECT_TYPE_PTR, FUNCTION_TYPE FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, MEM_POLICY> m_Proxy; \
+ FUNC_ARG_MEMBERS_##N; \
+ };
+
+
+FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR );
+
+//-----------------------------------------------------------------------------
+//
+// The real magic, letting the compiler figure out all the right template parameters
+//
+//-----------------------------------------------------------------------------
+
+#define DEFINE_NONMEMBER_FUNCTOR_FACTORY(N) \
+ template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ inline CFunctor *CreateFunctor(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ typedef FUNCTION_RETTYPE (*Func_t)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N); \
+ return new CFunctor##N<Func_t FUNC_BASE_TEMPLATE_ARG_PARAMS_##N>( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \
+ }
+
+FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_FACTORY );
+
+//-------------------------------------
+
+#define DEFINE_MEMBER_FUNCTOR_FACTORY(N) \
+template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+{ \
+ return new CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N>(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
+}
+
+FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_FACTORY );
+
+//-------------------------------------
+
+#define DEFINE_CONST_MEMBER_FUNCTOR_FACTORY(N) \
+ template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ return new CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N>(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
+ }
+
+FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_FACTORY );
+
+//-------------------------------------
+
+#define DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY(N) \
+ template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ inline CFunctor *CreateRefCountingFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ return new CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
+ }
+
+FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY );
+
+//-------------------------------------
+
+#define DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY(N) \
+ template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ inline CFunctor *CreateRefCountingFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ return new CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
+ }
+
+FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY );
+
+//-----------------------------------------------------------------------------
+//
+// Templates to assist early-out direct call code
+//
+//-----------------------------------------------------------------------------
+
+#define DEFINE_NONMEMBER_FUNCTOR_DIRECT(N) \
+ template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ inline void FunctorDirectCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+{ \
+ (*pfnProxied)( FUNC_CALL_ARGS_##N ); \
+}
+
+FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_DIRECT );
+
+
+//-------------------------------------
+
+#define DEFINE_MEMBER_FUNCTOR_DIRECT(N) \
+ template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ inline void FunctorDirectCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+{ \
+ ((*pObject).*pfnProxied)(FUNC_CALL_ARGS_##N); \
+}
+
+FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_DIRECT );
+
+//-------------------------------------
+
+#define DEFINE_CONST_MEMBER_FUNCTOR_DIRECT(N) \
+ template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ inline void FunctorDirectCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
+{ \
+ ((*pObject).*pfnProxied)(FUNC_CALL_ARGS_##N); \
+}
+
+FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_DIRECT );
+
+#include "tier0/memdbgoff.h"
+
+//-----------------------------------------------------------------------------
+// Factory class useable as templated traits
+//-----------------------------------------------------------------------------
+
+class CDefaultFunctorFactory
+{
+public:
+ FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_FACTORY );
+ FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_FACTORY );
+ FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_FACTORY );
+ FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY );
+ FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY );
+};
+
+template <class CAllocator, class CCustomFunctorBase = CFunctorBase>
+class CCustomizedFunctorFactory
+{
+public:
+ void SetAllocator( CAllocator *pAllocator )
+ {
+ m_pAllocator = pAllocator;
+ }
+
+ #define DEFINE_NONMEMBER_FUNCTOR_FACTORY_CUSTOM(N) \
+ template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ inline CFunctor *CreateFunctor( FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ typedef FUNCTION_RETTYPE (*Func_t)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N); \
+ return new (m_pAllocator->Alloc( sizeof(CFunctor##N<Func_t FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>) )) CFunctor##N<Func_t FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \
+ }
+
+ FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_FACTORY_CUSTOM );
+
+ //-------------------------------------
+
+ #define DEFINE_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \
+ template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>) )) CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
+ }
+
+ FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_FACTORY_CUSTOM );
+
+ //-------------------------------------
+
+ #define DEFINE_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \
+ template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ inline CFunctor *CreateFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>) )) CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
+ }
+
+ FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM );
+
+ //-------------------------------------
+
+ #define DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \
+ template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ inline CFunctor *CreateRefCountingFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >) )) CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
+ }
+
+ FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY_CUSTOM );
+
+ //-------------------------------------
+
+ #define DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \
+ template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ inline CFunctor *CreateRefCountingFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >) )) CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \
+ }
+
+ FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM );
+
+private:
+ CAllocator *m_pAllocator;
+
+};
+
+//-----------------------------------------------------------------------------
+
+#endif // FUNCTORS_H
diff --git a/public/tier1/generichash.h b/public/tier1/generichash.h
new file mode 100644
index 0000000..59b8b61
--- /dev/null
+++ b/public/tier1/generichash.h
@@ -0,0 +1,116 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Variant Pearson Hash general purpose hashing algorithm described
+// by Cargill in C++ Report 1994. Generates a 16-bit result.
+//
+//=============================================================================
+
+#ifndef GENERICHASH_H
+#define GENERICHASH_H
+
+#if defined(_WIN32)
+#pragma once
+#endif
+
+//-----------------------------------------------------------------------------
+
+unsigned FASTCALL HashString( const char *pszKey );
+unsigned FASTCALL HashStringCaseless( const char *pszKey );
+unsigned FASTCALL HashStringCaselessConventional( const char *pszKey );
+unsigned FASTCALL Hash4( const void *pKey );
+unsigned FASTCALL Hash8( const void *pKey );
+unsigned FASTCALL Hash12( const void *pKey );
+unsigned FASTCALL Hash16( const void *pKey );
+unsigned FASTCALL HashBlock( const void *pKey, unsigned size );
+
+unsigned FASTCALL HashInt( const int key );
+
+// hash a uint32 into a uint32
+FORCEINLINE uint32 HashIntAlternate( uint32 n)
+{
+ n = ( n + 0x7ed55d16 ) + ( n << 12 );
+ n = ( n ^ 0xc761c23c ) ^ ( n >> 19 );
+ n = ( n + 0x165667b1 ) + ( n << 5 );
+ n = ( n + 0xd3a2646c ) ^ ( n << 9 );
+ n = ( n + 0xfd7046c5 ) + ( n << 3 );
+ n = ( n ^ 0xb55a4f09 ) ^ ( n >> 16 );
+ return n;
+}
+
+inline unsigned HashIntConventional( const int n ) // faster but less effective
+{
+ // first byte
+ unsigned hash = 0xAAAAAAAA + (n & 0xFF);
+ // second byte
+ hash = ( hash << 5 ) + hash + ( (n >> 8) & 0xFF );
+ // third byte
+ hash = ( hash << 5 ) + hash + ( (n >> 16) & 0xFF );
+ // fourth byte
+ hash = ( hash << 5 ) + hash + ( (n >> 24) & 0xFF );
+
+ return hash;
+
+ /* this is the old version, which would cause a load-hit-store on every
+ line on a PowerPC, and therefore took hundreds of clocks to execute!
+
+ byte *p = (byte *)&n;
+ unsigned hash = 0xAAAAAAAA + *p++;
+ hash = ( ( hash << 5 ) + hash ) + *p++;
+ hash = ( ( hash << 5 ) + hash ) + *p++;
+ return ( ( hash << 5 ) + hash ) + *p;
+ */
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T>
+inline unsigned HashItem( const T &item )
+{
+ // TODO: Confirm comiler optimizes out unused paths
+ if ( sizeof(item) == 4 )
+ return Hash4( &item );
+ else if ( sizeof(item) == 8 )
+ return Hash8( &item );
+ else if ( sizeof(item) == 12 )
+ return Hash12( &item );
+ else if ( sizeof(item) == 16 )
+ return Hash16( &item );
+ else
+ return HashBlock( &item, sizeof(item) );
+}
+
+template <> inline unsigned HashItem<int>(const int &key )
+{
+ return HashInt( key );
+}
+
+template <> inline unsigned HashItem<unsigned>(const unsigned &key )
+{
+ return HashInt( (int)key );
+}
+
+template<> inline unsigned HashItem<const char *>(const char * const &pszKey )
+{
+ return HashString( pszKey );
+}
+
+template<> inline unsigned HashItem<char *>(char * const &pszKey )
+{
+ return HashString( pszKey );
+}
+
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Murmur hash
+//-----------------------------------------------------------------------------
+uint32 MurmurHash2( const void * key, int len, uint32 seed );
+
+// return murmurhash2 of a downcased string
+uint32 MurmurHash2LowerCase( char const *pString, uint32 nSeed );
+
+uint64 MurmurHash64( const void * key, int len, uint32 seed );
+
+
+#endif /* !GENERICHASH_H */
diff --git a/public/tier1/iconvar.h b/public/tier1/iconvar.h
new file mode 100644
index 0000000..cdbbda8
--- /dev/null
+++ b/public/tier1/iconvar.h
@@ -0,0 +1,116 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef ICONVAR_H
+#define ICONVAR_H
+
+#if _WIN32
+#pragma once
+#endif
+
+#include "tier0/dbg.h"
+#include "tier0/platform.h"
+#include "tier1/strtools.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class IConVar;
+class CCommand;
+
+
+//-----------------------------------------------------------------------------
+// ConVar flags
+//-----------------------------------------------------------------------------
+// The default, no flags at all
+#define FCVAR_NONE 0
+
+// Command to ConVars and ConCommands
+// ConVar Systems
+#define FCVAR_UNREGISTERED (1<<0) // If this is set, don't add to linked list, etc.
+#define FCVAR_DEVELOPMENTONLY (1<<1) // Hidden in released products. Flag is removed automatically if ALLOW_DEVELOPMENT_CVARS is defined.
+#define FCVAR_GAMEDLL (1<<2) // defined by the game DLL
+#define FCVAR_CLIENTDLL (1<<3) // defined by the client DLL
+#define FCVAR_HIDDEN (1<<4) // Hidden. Doesn't appear in find or autocomplete. Like DEVELOPMENTONLY, but can't be compiled out.
+
+// ConVar only
+#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value
+#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server.
+#define FCVAR_ARCHIVE (1<<7) // set to cause it to be saved to vars.rc
+#define FCVAR_NOTIFY (1<<8) // notifies players when changed
+#define FCVAR_USERINFO (1<<9) // changes the client's info string
+#define FCVAR_CHEAT (1<<14) // Only useable in singleplayer / debug / multiplayer & sv_cheats
+
+#define FCVAR_PRINTABLEONLY (1<<10) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ).
+#define FCVAR_UNLOGGED (1<<11) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log
+#define FCVAR_NEVER_AS_STRING (1<<12) // never try to print that cvar
+
+// It's a ConVar that's shared between the client and the server.
+// At signon, the values of all such ConVars are sent from the server to the client (skipped for local
+// client, of course )
+// If a change is requested it must come from the console (i.e., no remote client changes)
+// If a value is changed while a server is active, it's replicated to all connected clients
+#define FCVAR_REPLICATED (1<<13) // server setting enforced on clients, TODO rename to FCAR_SERVER at some time
+#define FCVAR_DEMO (1<<16) // record this cvar when starting a demo file
+#define FCVAR_DONTRECORD (1<<17) // don't record these command in demofiles
+#define FCVAR_RELOAD_MATERIALS (1<<20) // If this cvar changes, it forces a material reload
+#define FCVAR_RELOAD_TEXTURES (1<<21) // If this cvar changes, if forces a texture reload
+
+#define FCVAR_NOT_CONNECTED (1<<22) // cvar cannot be changed by a client that is connected to a server
+#define FCVAR_MATERIAL_SYSTEM_THREAD (1<<23) // Indicates this cvar is read from the material system thread
+#define FCVAR_ARCHIVE_XBOX (1<<24) // cvar written to config.cfg on the Xbox
+
+#define FCVAR_ACCESSIBLE_FROM_THREADS (1<<25) // used as a debugging tool necessary to check material system thread convars
+
+#define FCVAR_SERVER_CAN_EXECUTE (1<<28)// the server is allowed to execute this command on clients via ClientCommand/NET_StringCmd/CBaseClientState::ProcessStringCmd.
+#define FCVAR_SERVER_CANNOT_QUERY (1<<29)// If this is set, then the server is not allowed to query this cvar's value (via IServerPluginHelpers::StartQueryCvarValue).
+#define FCVAR_CLIENTCMD_CAN_EXECUTE (1<<30) // IVEngineClient::ClientCmd is allowed to execute this command.
+ // Note: IVEngineClient::ClientCmd_Unrestricted can run any client command.
+#define FCVAR_EXEC_DESPITE_DEFAULT (1<<31) // -default causes a lot of commands to be ignored (but still be recorded as though they had run).
+ // This causes them to be executed anyways.
+
+#define FCVAR_INTERNAL_USE (1<<15) // This var isn't archived, but is exposed to players--and its use is allowed in competitive play.
+#define FCVAR_ALLOWED_IN_COMPETITIVE (1<<18) // This convar can be changed in competitive (strict) settings mode even though it is not archived. Meant for one-offs like cl_showfps that are not user facing settings but are benign
+// #define FCVAR_AVAILABLE (1<<19)
+// #define FCVAR_AVAILABLE (1<<26)
+// #define FCVAR_AVAILABLE (1<<27)
+
+#define FCVAR_MATERIAL_THREAD_MASK ( FCVAR_RELOAD_MATERIALS | FCVAR_RELOAD_TEXTURES | FCVAR_MATERIAL_SYSTEM_THREAD )
+
+//-----------------------------------------------------------------------------
+// Called when a ConVar changes value
+// NOTE: For FCVAR_NEVER_AS_STRING ConVars, pOldValue == NULL
+//-----------------------------------------------------------------------------
+typedef void ( *FnChangeCallback_t )( IConVar *var, const char *pOldValue, float flOldValue );
+
+
+//-----------------------------------------------------------------------------
+// Abstract interface for ConVars
+//-----------------------------------------------------------------------------
+abstract_class IConVar
+{
+public:
+ // Value set
+ virtual void SetValue( const char *pValue ) = 0;
+ virtual void SetValue( float flValue ) = 0;
+ virtual void SetValue( int nValue ) = 0;
+
+ // Return name of command
+ virtual const char *GetName( void ) const = 0;
+
+ // Accessors.. not as efficient as using GetState()/GetInfo()
+ // if you call these methods multiple times on the same IConVar
+ virtual bool IsFlagSet( int nFlag ) const = 0;
+};
+
+
+#endif // ICONVAR_H
diff --git a/public/tier1/ilocalize.h b/public/tier1/ilocalize.h
new file mode 100644
index 0000000..35d8d3a
--- /dev/null
+++ b/public/tier1/ilocalize.h
@@ -0,0 +1,504 @@
+
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef TIER1_ILOCALIZE_H
+#define TIER1_ILOCALIZE_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "appframework/IAppSystem.h"
+#include <tier1/KeyValues.h>
+
+// unicode character type
+// for more unicode manipulation functions #include <wchar.h>
+#if !defined(_WCHAR_T_DEFINED) && !defined(GNUC)
+typedef unsigned short wchar_t;
+#define _WCHAR_T_DEFINED
+#endif
+
+
+// direct references to localized strings
+typedef unsigned long StringIndex_t;
+const unsigned long INVALID_LOCALIZE_STRING_INDEX = (StringIndex_t) -1;
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles localization of text
+// looks up string names and returns the localized unicode text
+//-----------------------------------------------------------------------------
+abstract_class ILocalize
+{
+public:
+ // adds the contents of a file to the localization table
+ virtual bool AddFile( const char *fileName, const char *pPathID = NULL, bool bIncludeFallbackSearchPaths = false ) = 0;
+
+ // Remove all strings from the table
+ virtual void RemoveAll() = 0;
+
+ // Finds the localized text for tokenName
+ virtual wchar_t *Find(char const *tokenName) = 0;
+
+ // finds the index of a token by token name, INVALID_STRING_INDEX if not found
+ virtual StringIndex_t FindIndex(const char *tokenName) = 0;
+
+ // gets the values by the string index
+ virtual const char *GetNameByIndex(StringIndex_t index) = 0;
+ virtual wchar_t *GetValueByIndex(StringIndex_t index) = 0;
+
+ ///////////////////////////////////////////////////////////////////
+ // the following functions should only be used by localization editors
+
+ // iteration functions
+ virtual StringIndex_t GetFirstStringIndex() = 0;
+ // returns the next index, or INVALID_STRING_INDEX if no more strings available
+ virtual StringIndex_t GetNextStringIndex(StringIndex_t index) = 0;
+
+ // adds a single name/unicode string pair to the table
+ virtual void AddString( const char *tokenName, wchar_t *unicodeString, const char *fileName ) = 0;
+
+ // changes the value of a string
+ virtual void SetValueByIndex(StringIndex_t index, wchar_t *newValue) = 0;
+
+ // saves the entire contents of the token tree to the file
+ virtual bool SaveToFile( const char *fileName ) = 0;
+
+ // iterates the filenames
+ virtual int GetLocalizationFileCount() = 0;
+ virtual const char *GetLocalizationFileName(int index) = 0;
+
+ // returns the name of the file the specified localized string is stored in
+ virtual const char *GetFileNameByIndex(StringIndex_t index) = 0;
+
+ // for development only, reloads localization files
+ virtual void ReloadLocalizationFiles( ) = 0;
+
+ virtual const char *FindAsUTF8( const char *pchTokenName ) = 0;
+
+ // need to replace the existing ConstructString with this
+ virtual void ConstructString(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const char *tokenName, KeyValues *localizationVariables) = 0;
+ virtual void ConstructString(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, StringIndex_t unlocalizedTextSymbol, KeyValues *localizationVariables) = 0;
+
+ ///////////////////////////////////////////////////////////////////
+ // static interface
+
+ // converts an english string to unicode
+ // returns the number of wchar_t in resulting string, including null terminator
+ static int ConvertANSIToUnicode(const char *ansi, OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t *unicode, int unicodeBufferSizeInBytes);
+
+ // converts an unicode string to an english string
+ // unrepresentable characters are converted to system default
+ // returns the number of characters in resulting string, including null terminator
+ static int ConvertUnicodeToANSI(const wchar_t *unicode, OUT_Z_BYTECAP(ansiBufferSize) char *ansi, int ansiBufferSize);
+
+ // builds a localized formatted string
+ // uses the format strings first: %s1, %s2, ... unicode strings (wchar_t *)
+ template < typename T >
+ static void ConstructString(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) T *unicodeOuput, int unicodeBufferSizeInBytes, const T *formatString, int numFormatParameters, ...)
+ {
+ va_list argList;
+ va_start( argList, numFormatParameters );
+
+ ConstructStringVArgsInternal( unicodeOuput, unicodeBufferSizeInBytes, formatString, numFormatParameters, argList );
+
+ va_end( argList );
+ }
+
+ template < typename T >
+ static void ConstructStringVArgs(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) T *unicodeOuput, int unicodeBufferSizeInBytes, const T *formatString, int numFormatParameters, va_list argList)
+ {
+ ConstructStringVArgsInternal( unicodeOuput, unicodeBufferSizeInBytes, formatString, numFormatParameters, argList );
+ }
+
+ template < typename T >
+ static void ConstructString(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) T *unicodeOutput, int unicodeBufferSizeInBytes, const T *formatString, KeyValues *localizationVariables)
+ {
+ ConstructStringKeyValuesInternal( unicodeOutput, unicodeBufferSizeInBytes, formatString, localizationVariables );
+ }
+
+
+ // Safe version of Construct String that has the compiler infer the buffer size
+ template <size_t maxLenInChars, typename T >
+ static void ConstructString_safe( OUT_Z_ARRAY T (&pDest)[maxLenInChars], const T *formatString, int numFormatParameters, ... )
+ {
+ va_list argList;
+ va_start( argList, numFormatParameters );
+
+ ConstructStringVArgsInternal( pDest, maxLenInChars * sizeof( *pDest ), formatString, numFormatParameters, argList );
+
+ va_end( argList );
+ }
+
+ template <size_t maxLenInChars, typename T >
+ static void ConstructString_safe( OUT_Z_ARRAY T (&pDest)[maxLenInChars], const T *formatString, KeyValues *localizationVariables )
+ {
+ ConstructStringKeyValuesInternal( pDest, maxLenInChars * sizeof( *pDest ), formatString, localizationVariables );
+ }
+
+ // Non-static version to be safe version of the virtual functions that utilize KVP
+ template <size_t maxLenInChars, typename T >
+ void ConstructString_safe( OUT_Z_ARRAY T( &pDest )[maxLenInChars], const char *formatString, KeyValues *localizationVariables )
+ {
+ ConstructString( pDest, maxLenInChars * sizeof( *pDest ), formatString, localizationVariables );
+ }
+
+private:
+ // internal "interface"
+ static void ConstructStringVArgsInternal(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) char *unicodeOutput, int unicodeBufferSizeInBytes, const char *formatString, int numFormatParameters, va_list argList);
+ static void ConstructStringVArgsInternal(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const wchar_t *formatString, int numFormatParameters, va_list argList);
+
+ static void ConstructStringKeyValuesInternal(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) char *unicodeOutput, int unicodeBufferSizeInBytes, const char *formatString, KeyValues *localizationVariables);
+ static void ConstructStringKeyValuesInternal(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const wchar_t *formatString, KeyValues *localizationVariables);
+};
+
+#ifdef GC
+
+ typedef char locchar_t;
+
+ #define loc_snprintf Q_snprintf
+ #define loc_sprintf_safe V_sprintf_safe
+ #define loc_sncat Q_strncat
+ #define loc_scat_safe V_strcat_safe
+ #define loc_sncpy Q_strncpy
+ #define loc_scpy_safe V_strcpy_safe
+ #define loc_strlen Q_strlen
+ #define LOCCHAR( x ) x
+
+#else
+
+ typedef wchar_t locchar_t;
+
+ #define loc_snprintf V_snwprintf
+ #define loc_sprintf_safe V_swprintf_safe
+ #define loc_sncat V_wcsncat
+ #define loc_scat_safe V_wcscat_safe
+ #define loc_sncpy Q_wcsncpy
+ #define loc_scpy_safe V_wcscpy_safe
+ #define loc_strlen Q_wcslen
+ #define LOCCHAR(x) L ## x
+
+#endif
+
+// --------------------------------------------------------------------------
+// Purpose:
+// --------------------------------------------------------------------------
+
+template < typename T >
+class TypedKeyValuesStringHelper
+{
+public:
+ static const T *Read( KeyValues *pKeyValues, const char *pKeyName, const T *pDefaultValue );
+ static void Write( KeyValues *pKeyValues, const char *pKeyName, const T *pValue );
+};
+
+// --------------------------------------------------------------------------
+
+template < >
+class TypedKeyValuesStringHelper<char>
+{
+public:
+ static const char *Read( KeyValues *pKeyValues, const char *pKeyName, const char *pDefaultValue ) { return pKeyValues->GetString( pKeyName, pDefaultValue ); }
+ static void Write( KeyValues *pKeyValues, const char *pKeyName, const char *pValue ) { pKeyValues->SetString( pKeyName, pValue ); }
+};
+
+// --------------------------------------------------------------------------
+
+template < >
+class TypedKeyValuesStringHelper<wchar_t>
+{
+public:
+ static const wchar_t *Read( KeyValues *pKeyValues, const char *pKeyName, const wchar_t *pDefaultValue ) { return pKeyValues->GetWString( pKeyName, pDefaultValue ); }
+ static void Write( KeyValues *pKeyValues, const char *pKeyName, const wchar_t *pValue ) { pKeyValues->SetWString( pKeyName, pValue ); }
+};
+
+// --------------------------------------------------------------------------
+// Purpose: CLocalizedStringArg<> is a class that will take a variable of any
+// arbitary type and convert it to a string of whatever character type
+// we're using for localization (locchar_t).
+//
+// Independently it isn't very useful, though it can be used to sort-of-
+// intelligently fill out the correct format string. It's designed to be
+// used for the arguments of CConstructLocalizedString, which can be of
+// arbitrary number and type.
+//
+// If you pass in a (non-specialized) pointer, the code will assume that
+// you meant that pointer to be used as a localized string. This will
+// still fail to compile if some non-string type is passed in, but will
+// handle weird combinations of const/volatile/whatever automatically.
+// --------------------------------------------------------------------------
+
+// The base implementation doesn't do anything except fail to compile if you
+// use it. Getting an "incomplete type" error here means that you tried to construct
+// a localized string with a type that doesn't have a specialization.
+template < typename T >
+class CLocalizedStringArg;
+
+// --------------------------------------------------------------------------
+
+template < typename T >
+class CLocalizedStringArgStringImpl
+{
+public:
+ enum { kIsValid = true };
+
+ CLocalizedStringArgStringImpl( const locchar_t *pStr ) : m_pStr( pStr ) { }
+
+ const locchar_t *GetLocArg() const { Assert( m_pStr ); return m_pStr; }
+
+private:
+ const locchar_t *m_pStr;
+};
+
+// --------------------------------------------------------------------------
+
+template < typename T >
+class CLocalizedStringArg<T *> : public CLocalizedStringArgStringImpl<T>
+{
+public:
+ CLocalizedStringArg( const locchar_t *pStr ) : CLocalizedStringArgStringImpl<T>( pStr ) { }
+};
+
+// --------------------------------------------------------------------------
+
+template < typename T >
+class CLocalizedStringArgPrintfImpl
+{
+public:
+ enum { kIsValid = true };
+
+ CLocalizedStringArgPrintfImpl( T value, const locchar_t *loc_Format ) { loc_snprintf( m_cBuffer, kBufferSize, loc_Format, value ); }
+
+ const locchar_t *GetLocArg() const { return m_cBuffer; }
+
+private:
+ enum { kBufferSize = 128, };
+ locchar_t m_cBuffer[ kBufferSize ];
+};
+
+// --------------------------------------------------------------------------
+
+template < >
+class CLocalizedStringArg<uint16> : public CLocalizedStringArgPrintfImpl<uint16>
+{
+public:
+ CLocalizedStringArg( uint16 unValue ) : CLocalizedStringArgPrintfImpl<uint16>( unValue, LOCCHAR("%u") ) { }
+};
+
+// --------------------------------------------------------------------------
+
+template < >
+class CLocalizedStringArg<uint32> : public CLocalizedStringArgPrintfImpl<uint32>
+{
+public:
+ CLocalizedStringArg( uint32 unValue ) : CLocalizedStringArgPrintfImpl<uint32>( unValue, LOCCHAR("%u") ) { }
+};
+
+// --------------------------------------------------------------------------
+
+template < >
+class CLocalizedStringArg<uint64> : public CLocalizedStringArgPrintfImpl<uint64>
+{
+public:
+ CLocalizedStringArg( uint64 unValue ) : CLocalizedStringArgPrintfImpl<uint64>( unValue, LOCCHAR("%llu") ) { }
+};
+
+// --------------------------------------------------------------------------
+
+template < >
+class CLocalizedStringArg<float> : public CLocalizedStringArgPrintfImpl<float>
+{
+public:
+ // Display one decimal point if we've got a value less than one, and no point
+ // if we're greater than one or are effectively zero.
+ CLocalizedStringArg( float fValue )
+ : CLocalizedStringArgPrintfImpl<float>( fValue,
+ fabsf( fValue ) <= FLT_EPSILON || fabsf( fValue ) >= 1.0f ? LOCCHAR("%.0f") : LOCCHAR("%.1f") )
+ {
+ //
+ }
+};
+
+// --------------------------------------------------------------------------
+// Purpose:
+// --------------------------------------------------------------------------
+class CConstructLocalizedString
+{
+public:
+ template < typename T >
+ CConstructLocalizedString( const locchar_t *loc_Format, T arg0 )
+ {
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<T>::kIsValid );
+
+ m_loc_Buffer[0] = '\0';
+
+ if ( loc_Format )
+ {
+ ::ILocalize::ConstructString( m_loc_Buffer, sizeof( m_loc_Buffer ), loc_Format, 1, CLocalizedStringArg<T>( arg0 ).GetLocArg() );
+ }
+ }
+
+ template < typename T, typename U >
+ CConstructLocalizedString( const locchar_t *loc_Format, T arg0, U arg1 )
+ {
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<T>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<U>::kIsValid );
+
+ m_loc_Buffer[0] = '\0';
+
+ if ( loc_Format )
+ {
+ ::ILocalize::ConstructString( m_loc_Buffer, sizeof( m_loc_Buffer ), loc_Format, 2, CLocalizedStringArg<T>( arg0 ).GetLocArg(), CLocalizedStringArg<U>( arg1 ).GetLocArg() );
+ }
+ }
+
+ template < typename T, typename U, typename V >
+ CConstructLocalizedString( const locchar_t *loc_Format, T arg0, U arg1, V arg2 )
+ {
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<T>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<U>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<V>::kIsValid );
+
+ m_loc_Buffer[0] = '\0';
+
+ if ( loc_Format )
+ {
+ ::ILocalize::ConstructString( m_loc_Buffer,
+ sizeof( m_loc_Buffer ),
+ loc_Format,
+ 3,
+ CLocalizedStringArg<T>( arg0 ).GetLocArg(),
+ CLocalizedStringArg<U>( arg1 ).GetLocArg(),
+ CLocalizedStringArg<V>( arg2 ).GetLocArg() );
+ }
+ }
+
+ template < typename T, typename U, typename V, typename W >
+ CConstructLocalizedString( const locchar_t *loc_Format, T arg0, U arg1, V arg2, W arg3 )
+ {
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<T>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<U>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<V>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<W>::kIsValid );
+
+ m_loc_Buffer[0] = '\0';
+
+ if ( loc_Format )
+ {
+ ::ILocalize::ConstructString( m_loc_Buffer,
+ sizeof( m_loc_Buffer ),
+ loc_Format,
+ 4,
+ CLocalizedStringArg<T>( arg0 ).GetLocArg(),
+ CLocalizedStringArg<U>( arg1 ).GetLocArg(),
+ CLocalizedStringArg<V>( arg2 ).GetLocArg(),
+ CLocalizedStringArg<W>( arg3 ).GetLocArg() );
+ }
+ }
+
+ template < typename T, typename U, typename V, typename W, typename X >
+ CConstructLocalizedString( const locchar_t *loc_Format, T arg0, U arg1, V arg2, W arg3, X arg4 )
+ {
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<T>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<U>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<V>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<W>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<X>::kIsValid );
+
+ m_loc_Buffer[0] = '\0';
+
+ if ( loc_Format )
+ {
+ ::ILocalize::ConstructString( m_loc_Buffer,
+ sizeof( m_loc_Buffer ),
+ loc_Format,
+ 5,
+ CLocalizedStringArg<T>( arg0 ).GetLocArg(),
+ CLocalizedStringArg<U>( arg1 ).GetLocArg(),
+ CLocalizedStringArg<V>( arg2 ).GetLocArg(),
+ CLocalizedStringArg<W>( arg3 ).GetLocArg(),
+ CLocalizedStringArg<X>( arg4 ).GetLocArg() );
+ }
+ }
+
+ template < typename T, typename U, typename V, typename W, typename X, typename Y >
+ CConstructLocalizedString( const locchar_t *loc_Format, T arg0, U arg1, V arg2, W arg3, X arg4, Y arg5 )
+ {
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<T>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<U>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<V>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<W>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<X>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<Y>::kIsValid );
+
+ m_loc_Buffer[0] = '\0';
+
+ if ( loc_Format )
+ {
+ ::ILocalize::ConstructString( m_loc_Buffer,
+ sizeof( m_loc_Buffer ),
+ loc_Format,
+ 6,
+ CLocalizedStringArg<T>( arg0 ).GetLocArg(),
+ CLocalizedStringArg<U>( arg1 ).GetLocArg(),
+ CLocalizedStringArg<V>( arg2 ).GetLocArg(),
+ CLocalizedStringArg<W>( arg3 ).GetLocArg(),
+ CLocalizedStringArg<X>( arg4 ).GetLocArg(),
+ CLocalizedStringArg<Y>( arg5 ).GetLocArg() );
+ }
+ }
+
+ template < typename T, typename U, typename V, typename W, typename X, typename Y, typename Z >
+ CConstructLocalizedString( const locchar_t *loc_Format, T arg0, U arg1, V arg2, W arg3, X arg4, Y arg5, Z arg6)
+ {
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<T>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<U>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<V>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<W>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<X>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<Y>::kIsValid );
+ COMPILE_TIME_ASSERT( CLocalizedStringArg<Z>::kIsValid );
+
+ m_loc_Buffer[0] = '\0';
+
+ if ( loc_Format )
+ {
+ ::ILocalize::ConstructString( m_loc_Buffer,
+ sizeof( m_loc_Buffer ),
+ loc_Format,
+ 7,
+ CLocalizedStringArg<T>( arg0 ).GetLocArg(),
+ CLocalizedStringArg<U>( arg1 ).GetLocArg(),
+ CLocalizedStringArg<V>( arg2 ).GetLocArg(),
+ CLocalizedStringArg<W>( arg3 ).GetLocArg(),
+ CLocalizedStringArg<X>( arg4 ).GetLocArg(),
+ CLocalizedStringArg<Y>( arg5 ).GetLocArg(),
+ CLocalizedStringArg<Z>( arg6 ).GetLocArg() );
+ }
+ }
+
+ CConstructLocalizedString( const locchar_t *loc_Format, KeyValues *pKeyValues )
+ {
+ m_loc_Buffer[0] = '\0';
+
+ if ( loc_Format && pKeyValues )
+ {
+ ::ILocalize::ConstructString( m_loc_Buffer, sizeof( m_loc_Buffer ), loc_Format, pKeyValues );
+ }
+ }
+
+ operator const locchar_t *() const
+ {
+ return m_loc_Buffer;
+ }
+
+private:
+ enum { kBufferSize = 512, };
+ locchar_t m_loc_Buffer[ kBufferSize ];
+};
+
+#endif // TIER1_ILOCALIZE_H
diff --git a/public/tier1/instancelog.h b/public/tier1/instancelog.h
new file mode 100644
index 0000000..bdfe670
--- /dev/null
+++ b/public/tier1/instancelog.h
@@ -0,0 +1,84 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+#pragma once
+
+#include <tuple>
+#include <string>
+#include <sstream>
+
+template <class Object, class RecordType>
+class InstanceLogger
+{
+public:
+ typedef RecordType RecordType_t;
+
+protected:
+ void InstanceLog( const char* pMsg )
+ {
+ m_records.AddToTail( BuildRecord( pMsg ) );
+ }
+
+ void DumpInstanceLog( )
+ {
+ CUtlString str;
+
+ Msg( "--------\nDumping instance log for 0x%08p\n", this );
+ for ( auto it : m_records )
+ {
+ FormatRecord( &str, it );
+ Msg( "%s\n", str.Get() );
+ }
+ Msg( "========\nInstance log complete for 0x%08p\n", this );
+ }
+
+ virtual RecordType_t BuildRecord( const char* pMsg ) = 0;
+
+private:
+ CUtlVector< RecordType > m_records;
+};
+
+// // Your class needs to implement something like this. You don't have to use a tuple,
+// // but if you don't you also need to implement FormatRecord for your type.
+// RecordType BuildRecord( const char* pMsg )
+// {
+// return std::make_tuple( this, pMsg, g_FrameNum, Plat_FloatTime(), m_nAllocatedWidth, m_nAllocatedHeight, m_nAllocatedDepth, m_nTargetResidence, m_nCurrentResidence );
+// }
+
+// helper function to print a tuple of any size
+template<class Tuple, std::size_t N>
+struct TuplePrinter {
+ static void print( std::stringstream& os, const Tuple& t )
+ {
+ TuplePrinter<Tuple, N - 1>::print( os, t );
+ os << ", " << std::get<N - 1>( t );
+ }
+};
+
+template<class Tuple>
+struct TuplePrinter < Tuple, 1 > {
+ static void print( std::stringstream& os, const Tuple& t )
+ {
+ os << std::get<0>( t );
+ }
+};
+
+template<class... Args>
+void format( std::stringstream& os, const std::tuple<Args...>& t )
+{
+ os << "( ";
+ TuplePrinter<decltype( t ), sizeof...( Args )>::print( os, t );
+ os << " )";
+}
+// end helper function
+
+template <class RecordType>
+void FormatRecord( CUtlString *pOutStr, const RecordType& rt )
+{
+ std::stringstream stream;
+ format( stream, rt );
+ ( *pOutStr ) = stream.str().c_str();
+}
diff --git a/public/tier1/interface.h b/public/tier1/interface.h
new file mode 100644
index 0000000..5453f67
--- /dev/null
+++ b/public/tier1/interface.h
@@ -0,0 +1,230 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+// This header defines the interface convention used in the valve engine.
+// To make an interface and expose it:
+// 1. The interface must be ALL pure virtuals, and have no data members.
+// 2. Define a name for it.
+// 3. In its implementation file, use EXPOSE_INTERFACE or EXPOSE_SINGLE_INTERFACE.
+
+// Versioning
+// There are two versioning cases that are handled by this:
+// 1. You add functions to the end of an interface, so it is binary compatible with the previous interface. In this case,
+// you need two EXPOSE_INTERFACEs: one to expose your class as the old interface and one to expose it as the new interface.
+// 2. You update an interface so it's not compatible anymore (but you still want to be able to expose the old interface
+// for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and
+// expose it for the old interface.
+
+// Static Linking:
+// Must mimic unique seperate class 'InterfaceReg' constructors per subsystem.
+// Each subsystem can then import and export interfaces as expected.
+// This is achieved through unique namespacing 'InterfaceReg' via symbol _SUBSYSTEM.
+// Static Linking also needs to generate unique symbols per interface so as to
+// provide a 'stitching' method whereby these interface symbols can be referenced
+// via the lib's primary module (usually the lib's interface exposure)
+// therby stitching all of that lib's code/data together for eventual final exe link inclusion.
+
+#ifndef INTERFACE_H
+#define INTERFACE_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#ifdef _LINUX
+#include <dlfcn.h> // dlopen,dlclose, et al
+#include <unistd.h>
+
+#define GetProcAddress dlsym
+
+#ifdef _snprintf
+#undef _snprintf
+#endif
+#define _snprintf snprintf
+#endif
+
+// TODO: move interface.cpp into tier0 library.
+#include "tier0/platform.h"
+
+// All interfaces derive from this.
+class IBaseInterface
+{
+public:
+ virtual ~IBaseInterface() {}
+};
+
+#if !defined( _X360 )
+#define CREATEINTERFACE_PROCNAME "CreateInterface"
+#else
+// x360 only allows ordinal exports, .def files export "CreateInterface" at 1
+#define CREATEINTERFACE_PROCNAME ((const char*)1)
+#endif
+
+typedef void* (*CreateInterfaceFn)(const char *pName, int *pReturnCode);
+typedef void* (*InstantiateInterfaceFn)();
+
+// Used internally to register classes.
+class InterfaceReg
+{
+public:
+ InterfaceReg(InstantiateInterfaceFn fn, const char *pName);
+
+public:
+ InstantiateInterfaceFn m_CreateFn;
+ const char *m_pName;
+
+ InterfaceReg *m_pNext; // For the global list.
+ static InterfaceReg *s_pInterfaceRegs;
+};
+
+// Use this to expose an interface that can have multiple instances.
+// e.g.:
+// EXPOSE_INTERFACE( CInterfaceImp, IInterface, "MyInterface001" )
+// This will expose a class called CInterfaceImp that implements IInterface (a pure class)
+// clients can receive a pointer to this class by calling CreateInterface( "MyInterface001" )
+//
+// In practice, the shared header file defines the interface (IInterface) and version name ("MyInterface001")
+// so that each component can use these names/vtables to communicate
+//
+// A single class can support multiple interfaces through multiple inheritance
+//
+// Use this if you want to write the factory function.
+#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM)
+#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \
+ static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName);
+#else
+#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \
+ namespace _SUBSYSTEM \
+ { \
+ static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName); \
+ }
+#endif
+
+#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM)
+#define EXPOSE_INTERFACE(className, interfaceName, versionName) \
+ static void* __Create##className##_interface() {return static_cast<interfaceName *>( new className );} \
+ static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName );
+#else
+#define EXPOSE_INTERFACE(className, interfaceName, versionName) \
+ namespace _SUBSYSTEM \
+ { \
+ static void* __Create##className##_interface() {return static_cast<interfaceName *>( new className );} \
+ static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); \
+ }
+#endif
+
+// Use this to expose a singleton interface with a global variable you've created.
+#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM)
+#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR_WITH_NAMESPACE(className, interfaceNamespace, interfaceName, versionName, globalVarName) \
+ static void* __Create##className##interfaceName##_interface() {return static_cast<interfaceNamespace interfaceName *>( &globalVarName );} \
+ static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName);
+#else
+#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR_WITH_NAMESPACE(className, interfaceNamespace, interfaceName, versionName, globalVarName) \
+ namespace _SUBSYSTEM \
+ { \
+ static void* __Create##className##interfaceName##_interface() {return static_cast<interfaceNamespace interfaceName *>( &globalVarName );} \
+ static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); \
+ }
+#endif
+
+#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \
+ EXPOSE_SINGLE_INTERFACE_GLOBALVAR_WITH_NAMESPACE(className, , interfaceName, versionName, globalVarName)
+
+// Use this to expose a singleton interface. This creates the global variable for you automatically.
+#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM)
+#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \
+ static className __g_##className##_singleton; \
+ EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton)
+#else
+#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \
+ namespace _SUBSYSTEM \
+ { \
+ static className __g_##className##_singleton; \
+ } \
+ EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton)
+#endif
+
+// load/unload components
+class CSysModule;
+
+// interface return status
+enum
+{
+ IFACE_OK = 0,
+ IFACE_FAILED
+};
+
+//-----------------------------------------------------------------------------
+// This function is automatically exported and allows you to access any interfaces exposed with the above macros.
+// if pReturnCode is set, it will return one of the following values (IFACE_OK, IFACE_FAILED)
+// extend this for other error conditions/code
+//-----------------------------------------------------------------------------
+DLL_EXPORT void* CreateInterface(const char *pName, int *pReturnCode);
+
+#if defined( _X360 )
+DLL_EXPORT void *CreateInterfaceThunk( const char *pName, int *pReturnCode );
+#endif
+
+//-----------------------------------------------------------------------------
+// UNDONE: This is obsolete, use the module load/unload/get instead!!!
+//-----------------------------------------------------------------------------
+extern CreateInterfaceFn Sys_GetFactory( CSysModule *pModule );
+extern CreateInterfaceFn Sys_GetFactory( const char *pModuleName );
+extern CreateInterfaceFn Sys_GetFactoryThis( void );
+
+enum Sys_Flags
+{
+ SYS_NOFLAGS = 0x00,
+ SYS_NOLOAD = 0x01 // no loading, no ref-counting, only returns handle if lib is loaded.
+};
+
+//-----------------------------------------------------------------------------
+// Load & Unload should be called in exactly one place for each module
+// The factory for that module should be passed on to dependent components for
+// proper versioning.
+//-----------------------------------------------------------------------------
+extern CSysModule *Sys_LoadModule( const char *pModuleName, Sys_Flags flags = SYS_NOFLAGS );
+extern void Sys_UnloadModule( CSysModule *pModule );
+
+// This is a helper function to load a module, get its factory, and get a specific interface.
+// You are expected to free all of these things.
+// Returns false and cleans up if any of the steps fail.
+bool Sys_LoadInterface(
+ const char *pModuleName,
+ const char *pInterfaceVersionName,
+ CSysModule **pOutModule,
+ void **pOutInterface );
+
+bool Sys_IsDebuggerPresent();
+
+//-----------------------------------------------------------------------------
+// Purpose: Place this as a singleton at module scope (e.g.) and use it to get the factory from the specified module name.
+//
+// When the singleton goes out of scope (.dll unload if at module scope),
+// then it'll call Sys_UnloadModule on the module so that the refcount is decremented
+// and the .dll actually can unload from memory.
+//-----------------------------------------------------------------------------
+class CDllDemandLoader
+{
+public:
+ CDllDemandLoader( char const *pchModuleName );
+ virtual ~CDllDemandLoader();
+ CreateInterfaceFn GetFactory();
+ void Unload();
+
+private:
+
+ char const *m_pchModuleName;
+ CSysModule *m_hModule;
+ bool m_bLoadAttempted;
+};
+
+#endif
+
+
+
diff --git a/public/tier1/keyvaluesjson.h b/public/tier1/keyvaluesjson.h
new file mode 100644
index 0000000..85cb75f
--- /dev/null
+++ b/public/tier1/keyvaluesjson.h
@@ -0,0 +1,70 @@
+//========= Copyright Valve Corporation, All rights reserved. =================//
+//
+// Read JSON-formatted data into KeyValues
+//
+//=============================================================================//
+
+#ifndef KEYVALUESJSON_H
+#define KEYVALUESJSON_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "KeyValues.h"
+
+class CUtlBuffer;
+
+/// JSON parser. Use this class when you need to customize the parsing.
+class KeyValuesJSONParser
+{
+public:
+ KeyValuesJSONParser( const CUtlBuffer &buf );
+ KeyValuesJSONParser( const char *pszText, int cbSize = -1 );
+ ~KeyValuesJSONParser();
+
+ /// Parse the whole string. If there's a problem, returns NULL and sets m_nLine,m_szErrMsg with more info.
+ KeyValues *ParseFile();
+
+ /// Error message is returned here, if there is one.
+ char m_szErrMsg[ 1024 ];
+
+ /// Line number of current token during parsing, or of the error, of pasring fails
+ int m_nLine;
+
+private:
+
+ bool ParseObject( KeyValues *pObject );
+ bool ParseArray( KeyValues *pArray );
+ bool ParseValue( KeyValues *pValue );
+ void Init( const char *pszText, int cbSize );
+
+ const char *m_cur;
+ const char *m_end;
+
+ enum
+ {
+ kToken_Err = -2, // An error has been discovered, don't parse anything else
+ kToken_EOF = -1,
+ kToken_String = 1,
+ kToken_NumberInt = 2,
+ kToken_NumberFloat = 3,
+ kToken_True = 4,
+ kToken_False = 5,
+ kToken_Null = 6,
+ };
+
+ int m_eToken;
+ CUtlVectorFixedGrowable<char,1024> m_vecTokenChars;
+
+ void NextToken();
+ void ParseNumberToken();
+ void ParseStringToken();
+ const char *GetTokenDebugText();
+};
+
+#ifdef _DEBUG
+extern void TestKeyValuesJSONParser();
+#endif
+
+#endif // KEYVALUESJSON_H
diff --git a/public/tier1/kvpacker.h b/public/tier1/kvpacker.h
new file mode 100644
index 0000000..7e47fa1
--- /dev/null
+++ b/public/tier1/kvpacker.h
@@ -0,0 +1,49 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef KVPACKER_H
+#define KVPACKER_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "KeyValues.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles packing KeyValues binary packing and unpacking in a a
+// consistent way across all branches, including Steam. If you change
+// this packing format you need to do so in a backward compatible way
+// so that the Steam servers and all the various GCs can still talk to
+// each other.
+//-----------------------------------------------------------------------------
+class KVPacker
+{
+public:
+ bool WriteAsBinary( KeyValues *pNode, CUtlBuffer &buffer );
+ bool ReadAsBinary( KeyValues *pNode, CUtlBuffer &buffer );
+
+private:
+ // These types are used for serialization of KeyValues nodes.
+ // Do not renumber them or you will break serialization across
+ // branches.
+ enum EPackType
+ {
+ PACKTYPE_NONE = 0,
+ PACKTYPE_STRING,
+ PACKTYPE_INT,
+ PACKTYPE_FLOAT,
+ PACKTYPE_PTR,
+ PACKTYPE_WSTRING,
+ PACKTYPE_COLOR,
+ PACKTYPE_UINT64,
+ PACKTYPE_NULLMARKER, // used to mark the end of a block in the binary format
+ };
+};
+
+
+#endif // KVPACKER_H
diff --git a/public/tier1/lzmaDecoder.h b/public/tier1/lzmaDecoder.h
new file mode 100644
index 0000000..6f4b87f
--- /dev/null
+++ b/public/tier1/lzmaDecoder.h
@@ -0,0 +1,102 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// LZMA Codec interface for engine.
+//
+// LZMA SDK 9.38 beta
+// 2015-01-03 : Igor Pavlov : Public domain
+// http://www.7-zip.org/
+//
+//========================================================================//
+
+#ifndef _LZMADECODER_H
+#define _LZMADECODER_H
+#pragma once
+
+// Thanks for the useful define namespacing, LZMA
+#include "../../utils/lzma/C/7zVersion.h"
+#define LZMA_SDK_VERSION_MAJOR MY_VER_MAJOR
+#define LZMA_SDK_VERSION_MINOR MY_VER_MINOR
+
+#if !defined( _X360 )
+#define LZMA_ID (('A'<<24)|('M'<<16)|('Z'<<8)|('L'))
+#else
+#define LZMA_ID (('L'<<24)|('Z'<<16)|('M'<<8)|('A'))
+#endif
+
+// bind the buffer for correct identification
+#pragma pack(1)
+struct lzma_header_t
+{
+ unsigned int id;
+ unsigned int actualSize; // always little endian
+ unsigned int lzmaSize; // always little endian
+ unsigned char properties[5];
+};
+#pragma pack()
+
+class CLZMAStream;
+
+class CLZMA
+{
+public:
+ static unsigned int Uncompress( unsigned char *pInput, unsigned char *pOutput );
+ static bool IsCompressed( unsigned char *pInput );
+ static unsigned int GetActualSize( unsigned char *pInput );
+};
+
+// For files besides the implementation, we forward declare a dummy struct. We can't unconditionally forward declare
+// this because LzmaEnc.h typedefs this directly to an unnamed struct :-/
+#ifndef CLzmaDec_t
+struct _CLzmaDec_t;
+#define CLzmaDec_t struct _CLzmaDec_t
+#endif
+
+class CLZMAStream
+{
+public:
+ CLZMAStream();
+ ~CLZMAStream();
+
+ // Initialize a stream to read data from a LZMA style zip file, passing the original size from the zip headers.
+ // Streams with a source-engine style header (lzma_header_t) do not need an init call.
+ void InitZIPHeader( unsigned int nCompressedSize, unsigned int nOriginalSize );
+
+ // Attempt to read up to nMaxInputBytes from the compressed stream, writing up to nMaxOutputBytes to pOutput.
+ // Makes progress until blocked on input or output.
+ // Returns false if read stops due to an error or if called at EOF (GetExpectedBytesRemaining == 0)
+ bool Read( unsigned char *pInput, unsigned int nMaxInputBytes,
+ unsigned char *pOutput, unsigned int nMaxOutputBytes,
+ /* out */ unsigned int &nCompressedBytesRead, /* out */ unsigned int &nOutputBytesWritten );
+
+ // Get the expected uncompressed bytes yet to be read from this stream. Returns false if not yet known, such as
+ // before being fed the header.
+ bool GetExpectedBytesRemaining( /* out */ unsigned int &nBytesRemaining );
+
+private:
+ enum eHeaderParse
+ {
+ eHeaderParse_OK,
+ eHeaderParse_Fail,
+ eHeaderParse_NeedMoreBytes
+ };
+
+ eHeaderParse TryParseHeader( unsigned char *pInput, unsigned int nBytesAvailable, /* out */ unsigned int &nBytesConsumed );
+
+ void FreeDecoderState();
+ bool CreateDecoderState( const unsigned char *pProperties );
+
+ // Init from a zip-embedded LZMA stream. Requires the original size be passed from zip headers.
+ CLzmaDec_t *m_pDecoderState;
+
+ unsigned int m_nActualSize;
+ unsigned int m_nActualBytesRead;
+ unsigned int m_nCompressedSize;
+ unsigned int m_nCompressedBytesRead;
+
+ // If we have read past the header
+ bool m_bParsedHeader : 1;
+ // If InitZIPHeader() was called. We're expecting a zip-style header and have size information.
+ bool m_bZIPStyleHeader : 1;
+};
+
+#endif
diff --git a/public/tier1/lzss.h b/public/tier1/lzss.h
new file mode 100644
index 0000000..8b3409a
--- /dev/null
+++ b/public/tier1/lzss.h
@@ -0,0 +1,69 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// LZSS Codec. Designed for fast cheap gametime encoding/decoding. Compression results
+// are not aggresive as other alogrithms, but gets 2:1 on most arbitrary uncompressed data.
+//
+//=====================================================================================//
+
+#ifndef _LZSS_H
+#define _LZSS_H
+#pragma once
+
+#define LZSS_ID uint32( BigLong( ('L'<<24)|('Z'<<16)|('S'<<8)|('S') ) )
+#define SNAPPY_ID uint32( BigLong( ('S'<<24)|('N'<<16)|('A'<<8)|('P') ) )
+
+// bind the buffer for correct identification
+struct lzss_header_t
+{
+ unsigned int id;
+ unsigned int actualSize; // always little endian
+};
+
+class CUtlBuffer;
+
+#define DEFAULT_LZSS_WINDOW_SIZE 4096
+
+class CLZSS
+{
+public:
+ unsigned char* Compress( const unsigned char *pInput, int inputlen, unsigned int *pOutputSize );
+ unsigned char* CompressNoAlloc( const unsigned char *pInput, int inputlen, unsigned char *pOutput, unsigned int *pOutputSize );
+ unsigned int Uncompress( const unsigned char *pInput, unsigned char *pOutput );
+ //unsigned int Uncompress( unsigned char *pInput, CUtlBuffer &buf );
+ unsigned int SafeUncompress( const unsigned char *pInput, unsigned char *pOutput, unsigned int unBufSize );
+
+ static bool IsCompressed( const unsigned char *pInput );
+ static unsigned int GetActualSize( const unsigned char *pInput );
+
+ // windowsize must be a power of two.
+ FORCEINLINE CLZSS( int nWindowSize = DEFAULT_LZSS_WINDOW_SIZE );
+
+private:
+ // expected to be sixteen bytes
+ struct lzss_node_t
+ {
+ const unsigned char *pData;
+ lzss_node_t *pPrev;
+ lzss_node_t *pNext;
+ char empty[4];
+ };
+
+ struct lzss_list_t
+ {
+ lzss_node_t *pStart;
+ lzss_node_t *pEnd;
+ };
+
+ void BuildHash( const unsigned char *pData );
+ lzss_list_t *m_pHashTable;
+ lzss_node_t *m_pHashTarget;
+ int m_nWindowSize;
+
+};
+
+FORCEINLINE CLZSS::CLZSS( int nWindowSize )
+{
+ m_nWindowSize = nWindowSize;
+}
+#endif
+
diff --git a/public/tier1/mempool.h b/public/tier1/mempool.h
new file mode 100644
index 0000000..01d3a33
--- /dev/null
+++ b/public/tier1/mempool.h
@@ -0,0 +1,559 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef MEMPOOL_H
+#define MEMPOOL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/memalloc.h"
+#include "tier0/tslist.h"
+#include "tier0/platform.h"
+#include "tier1/utlvector.h"
+#include "tier1/utlrbtree.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Optimized pool memory allocator
+//-----------------------------------------------------------------------------
+
+typedef void (*MemoryPoolReportFunc_t)( PRINTF_FORMAT_STRING char const* pMsg, ... );
+
+// Ways a memory pool can grow when it needs to make a new blob:
+enum MemoryPoolGrowType_t
+{
+ UTLMEMORYPOOL_GROW_NONE=0, // Don't allow new blobs.
+ UTLMEMORYPOOL_GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates
+ // get larger and larger each time it allocates one).
+ UTLMEMORYPOOL_GROW_SLOW=2 // New blob size is numElements.
+};
+
+class CUtlMemoryPool
+{
+public:
+ // !KLUDGE! For legacy code support, import the global enum into this scope
+ enum MemoryPoolGrowType_t
+ {
+ GROW_NONE=UTLMEMORYPOOL_GROW_NONE,
+ GROW_FAST=UTLMEMORYPOOL_GROW_FAST,
+ GROW_SLOW=UTLMEMORYPOOL_GROW_SLOW
+ };
+
+ CUtlMemoryPool( int blockSize, int numElements, int growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0 );
+ ~CUtlMemoryPool();
+
+ void* Alloc(); // Allocate the element size you specified in the constructor.
+ void* Alloc( size_t amount );
+ void* AllocZero(); // Allocate the element size you specified in the constructor, zero the memory before construction
+ void* AllocZero( size_t amount );
+ void Free(void *pMem);
+
+ // Frees everything
+ void Clear();
+
+ // Error reporting...
+ static void SetErrorReportFunc( MemoryPoolReportFunc_t func );
+
+ // returns number of allocated blocks
+ int Count() { return m_BlocksAllocated; }
+ int PeakCount() { return m_PeakAlloc; }
+
+protected:
+ class CBlob
+ {
+ public:
+ CBlob *m_pPrev, *m_pNext;
+ int m_NumBytes; // Number of bytes in this blob.
+ char m_Data[1];
+ char m_Padding[3]; // to int align the struct
+ };
+
+ // Resets the pool
+ void Init();
+ void AddNewBlob();
+ void ReportLeaks();
+
+ int m_BlockSize;
+ int m_BlocksPerBlob;
+
+ int m_GrowMode; // GROW_ enum.
+
+ // Put m_BlocksAllocated in front of m_pHeadOfFreeList for better
+ // packing on 64-bit where pointers are 8-byte aligned.
+ int m_BlocksAllocated;
+ // FIXME: Change m_ppMemBlob into a growable array?
+ void *m_pHeadOfFreeList;
+ int m_PeakAlloc;
+ unsigned short m_nAlignment;
+ unsigned short m_NumBlobs;
+ const char * m_pszAllocOwner;
+ // CBlob could be not a multiple of 4 bytes so stuff it at the end here to keep us otherwise aligned
+ CBlob m_BlobHead;
+
+ static MemoryPoolReportFunc_t g_ReportFunc;
+};
+
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+class CMemoryPoolMT : public CUtlMemoryPool
+{
+public:
+ CMemoryPoolMT(int blockSize, int numElements, int growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = NULL) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner) {}
+
+
+ void* Alloc() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc(); }
+ void* Alloc( size_t amount ) { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc( amount ); }
+ void* AllocZero() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::AllocZero(); }
+ void* AllocZero( size_t amount ) { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::AllocZero( amount ); }
+ void Free(void *pMem) { AUTO_LOCK( m_mutex ); CUtlMemoryPool::Free( pMem ); }
+
+ // Frees everything
+ void Clear() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Clear(); }
+private:
+ CThreadFastMutex m_mutex; // @TODO: Rework to use tslist (toml 7/6/2007)
+};
+
+
+//-----------------------------------------------------------------------------
+// Wrapper macro to make an allocator that returns particular typed allocations
+// and construction and destruction of objects.
+//-----------------------------------------------------------------------------
+template< class T >
+class CClassMemoryPool : public CUtlMemoryPool
+{
+public:
+ CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = 0 ) :
+ CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) {
+ #ifdef PLATFORM_64BITS
+ COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 64 );
+ #else
+ COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 48 );
+ #endif
+ }
+
+ T* Alloc();
+ T* AllocZero();
+ void Free( T *pMem );
+
+ void Clear();
+};
+
+
+//-----------------------------------------------------------------------------
+// Specialized pool for aligned data management (e.g., Xbox cubemaps)
+//-----------------------------------------------------------------------------
+template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD = 4 >
+class CAlignedMemPool
+{
+ enum
+ {
+ BLOCK_SIZE = ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ) > 8 ? ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ) : 8
+ };
+
+public:
+ CAlignedMemPool();
+
+ void *Alloc();
+ void Free( void *p );
+
+ static int __cdecl CompareChunk( void * const *ppLeft, void * const *ppRight );
+ void Compact();
+
+ int NumTotal() { return m_Chunks.Count() * ( CHUNK_SIZE / BLOCK_SIZE ); }
+ int NumAllocated() { return NumTotal() - m_nFree; }
+ int NumFree() { return m_nFree; }
+
+ int BytesTotal() { return NumTotal() * BLOCK_SIZE; }
+ int BytesAllocated() { return NumAllocated() * BLOCK_SIZE; }
+ int BytesFree() { return NumFree() * BLOCK_SIZE; }
+
+ int ItemSize() { return ITEM_SIZE; }
+ int BlockSize() { return BLOCK_SIZE; }
+ int ChunkSize() { return CHUNK_SIZE; }
+
+private:
+ struct FreeBlock_t
+ {
+ FreeBlock_t *pNext;
+ byte reserved[ BLOCK_SIZE - sizeof( FreeBlock_t *) ];
+ };
+
+ CUtlVector<void *> m_Chunks; // Chunks are tracked outside blocks (unlike CUtlMemoryPool) to simplify alignment issues
+ FreeBlock_t * m_pFirstFree;
+ int m_nFree;
+ CAllocator m_Allocator;
+ float m_TimeLastCompact;
+};
+
+//-----------------------------------------------------------------------------
+// Pool variant using standard allocation
+//-----------------------------------------------------------------------------
+template <typename T, int nInitialCount = 0, bool bDefCreateNewIfEmpty = true >
+class CObjectPool
+{
+public:
+ CObjectPool()
+ {
+ int i = nInitialCount;
+ while ( i-- > 0 )
+ {
+ m_AvailableObjects.PushItem( new T );
+ }
+ }
+
+ ~CObjectPool()
+ {
+ Purge();
+ }
+
+ int NumAvailable()
+ {
+ return m_AvailableObjects.Count();
+ }
+
+ void Purge()
+ {
+ T *p;
+ while ( m_AvailableObjects.PopItem( &p ) )
+ {
+ delete p;
+ }
+ }
+
+ T *GetObject( bool bCreateNewIfEmpty = bDefCreateNewIfEmpty )
+ {
+ T *p;
+ if ( !m_AvailableObjects.PopItem( &p ) )
+ {
+ p = ( bCreateNewIfEmpty ) ? new T : NULL;
+ }
+ return p;
+ }
+
+ void PutObject( T *p )
+ {
+ m_AvailableObjects.PushItem( p );
+ }
+
+private:
+ CTSList<T *> m_AvailableObjects;
+};
+
+//-----------------------------------------------------------------------------
+
+
+template< class T >
+inline T* CClassMemoryPool<T>::Alloc()
+{
+ T *pRet;
+
+ {
+ MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T));
+ pRet = (T*)CUtlMemoryPool::Alloc();
+ }
+
+ if ( pRet )
+ {
+ Construct( pRet );
+ }
+ return pRet;
+}
+
+template< class T >
+inline T* CClassMemoryPool<T>::AllocZero()
+{
+ T *pRet;
+
+ {
+ MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T));
+ pRet = (T*)CUtlMemoryPool::AllocZero();
+ }
+
+ if ( pRet )
+ {
+ Construct( pRet );
+ }
+ return pRet;
+}
+
+template< class T >
+inline void CClassMemoryPool<T>::Free(T *pMem)
+{
+ if ( pMem )
+ {
+ Destruct( pMem );
+ }
+
+ CUtlMemoryPool::Free( pMem );
+}
+
+template< class T >
+inline void CClassMemoryPool<T>::Clear()
+{
+ CUtlRBTree<void *> freeBlocks;
+ SetDefLessFunc( freeBlocks );
+
+ void *pCurFree = m_pHeadOfFreeList;
+ while ( pCurFree != NULL )
+ {
+ freeBlocks.Insert( pCurFree );
+ pCurFree = *((void**)pCurFree);
+ }
+
+ for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
+ {
+ T *p = (T *)pCur->m_Data;
+ T *pLimit = (T *)(pCur->m_Data + pCur->m_NumBytes);
+ while ( p < pLimit )
+ {
+ if ( freeBlocks.Find( p ) == freeBlocks.InvalidIndex() )
+ {
+ Destruct( p );
+ }
+ p++;
+ }
+ }
+
+ CUtlMemoryPool::Clear();
+}
+
+
+//-----------------------------------------------------------------------------
+// Macros that make it simple to make a class use a fixed-size allocator
+// Put DECLARE_FIXEDSIZE_ALLOCATOR in the private section of a class,
+// Put DEFINE_FIXEDSIZE_ALLOCATOR in the CPP file
+//-----------------------------------------------------------------------------
+#define DECLARE_FIXEDSIZE_ALLOCATOR( _class ) \
+ public: \
+ inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
+ inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
+ inline void operator delete( void* p ) { s_Allocator.Free(p); } \
+ inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \
+ private: \
+ static CUtlMemoryPool s_Allocator
+
+#define DEFINE_FIXEDSIZE_ALLOCATOR( _class, _initsize, _grow ) \
+ CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool")
+
+#define DEFINE_FIXEDSIZE_ALLOCATOR_ALIGNED( _class, _initsize, _grow, _alignment ) \
+ CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool", _alignment )
+
+#define DECLARE_FIXEDSIZE_ALLOCATOR_MT( _class ) \
+ public: \
+ inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
+ inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
+ inline void operator delete( void* p ) { s_Allocator.Free(p); } \
+ inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \
+ private: \
+ static CMemoryPoolMT s_Allocator
+
+#define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \
+ CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool")
+
+//-----------------------------------------------------------------------------
+// Macros that make it simple to make a class use a fixed-size allocator
+// This version allows us to use a memory pool which is externally defined...
+// Put DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL in the private section of a class,
+// Put DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL in the CPP file
+//-----------------------------------------------------------------------------
+
+#define DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class ) \
+ public: \
+ inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \
+ inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \
+ inline void operator delete( void* p ) { s_pAllocator->Free(p); } \
+ private: \
+ static CUtlMemoryPool* s_pAllocator
+
+#define DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class, _allocator ) \
+ CUtlMemoryPool* _class::s_pAllocator = _allocator
+
+
+template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
+inline CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::CAlignedMemPool()
+ : m_pFirstFree( 0 ),
+ m_nFree( 0 ),
+ m_TimeLastCompact( 0 )
+{
+ COMPILE_TIME_ASSERT( sizeof( FreeBlock_t ) >= BLOCK_SIZE );
+ COMPILE_TIME_ASSERT( ALIGN_VALUE( sizeof( FreeBlock_t ), ALIGNMENT ) == sizeof( FreeBlock_t ) );
+}
+
+template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
+inline void *CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::Alloc()
+{
+ if ( !m_pFirstFree )
+ {
+ FreeBlock_t *pNew = (FreeBlock_t *)m_Allocator.Alloc( CHUNK_SIZE );
+ Assert( (unsigned)pNew % ALIGNMENT == 0 );
+ m_Chunks.AddToTail( pNew );
+ m_nFree = CHUNK_SIZE / BLOCK_SIZE;
+ m_pFirstFree = pNew;
+ for ( int i = 0; i < m_nFree - 1; i++ )
+ {
+ pNew->pNext = pNew + 1;
+ pNew++;
+ }
+ pNew->pNext = NULL;
+ }
+
+ void *p = m_pFirstFree;
+ m_pFirstFree = m_pFirstFree->pNext;
+ m_nFree--;
+
+ return p;
+}
+
+template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
+inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::Free( void *p )
+{
+ // Insertion sort to encourage allocation clusters in chunks
+ FreeBlock_t *pFree = ((FreeBlock_t *)p);
+ FreeBlock_t *pCur = m_pFirstFree;
+ FreeBlock_t *pPrev = NULL;
+
+ while ( pCur && pFree > pCur )
+ {
+ pPrev = pCur;
+ pCur = pCur->pNext;
+ }
+
+ pFree->pNext = pCur;
+
+ if ( pPrev )
+ {
+ pPrev->pNext = pFree;
+ }
+ else
+ {
+ m_pFirstFree = pFree;
+ }
+ m_nFree++;
+
+ if ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD )
+ {
+ float time = Plat_FloatTime();
+ float compactTime = ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0;
+ if ( m_TimeLastCompact > time || m_TimeLastCompact + compactTime < Plat_FloatTime() )
+ {
+ Compact();
+ m_TimeLastCompact = time;
+ }
+ }
+}
+
+template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
+inline int __cdecl CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::CompareChunk( void * const *ppLeft, void * const *ppRight )
+{
+ return ((unsigned)*ppLeft) - ((unsigned)*ppRight);
+}
+
+template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
+inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::Compact()
+{
+ FreeBlock_t *pCur = m_pFirstFree;
+ FreeBlock_t *pPrev = NULL;
+
+ m_Chunks.Sort( CompareChunk );
+
+#ifdef VALIDATE_ALIGNED_MEM_POOL
+ {
+ FreeBlock_t *p = m_pFirstFree;
+ while ( p )
+ {
+ if ( p->pNext && p > p->pNext )
+ {
+ __asm { int 3 }
+ }
+ p = p->pNext;
+ }
+
+ for ( int i = 0; i < m_Chunks.Count(); i++ )
+ {
+ if ( i + 1 < m_Chunks.Count() )
+ {
+ if ( m_Chunks[i] > m_Chunks[i + 1] )
+ {
+ __asm { int 3 }
+ }
+ }
+ }
+ }
+#endif
+
+ int i;
+
+ for ( i = 0; i < m_Chunks.Count(); i++ )
+ {
+ int nBlocksPerChunk = CHUNK_SIZE / BLOCK_SIZE;
+ FreeBlock_t *pChunkLimit = ((FreeBlock_t *)m_Chunks[i]) + nBlocksPerChunk;
+ int nFromChunk = 0;
+ if ( pCur == m_Chunks[i] )
+ {
+ FreeBlock_t *pFirst = pCur;
+ while ( pCur && pCur >= m_Chunks[i] && pCur < pChunkLimit )
+ {
+ pCur = pCur->pNext;
+ nFromChunk++;
+ }
+ pCur = pFirst;
+
+ }
+
+ while ( pCur && pCur >= m_Chunks[i] && pCur < pChunkLimit )
+ {
+ if ( nFromChunk != nBlocksPerChunk )
+ {
+ if ( pPrev )
+ {
+ pPrev->pNext = pCur;
+ }
+ else
+ {
+ m_pFirstFree = pCur;
+ }
+ pPrev = pCur;
+ }
+ else if ( pPrev )
+ {
+ pPrev->pNext = NULL;
+ }
+ else
+ {
+ m_pFirstFree = NULL;
+ }
+
+ pCur = pCur->pNext;
+ }
+
+ if ( nFromChunk == nBlocksPerChunk )
+ {
+ m_Allocator.Free( m_Chunks[i] );
+ m_nFree -= nBlocksPerChunk;
+ m_Chunks[i] = 0;
+ }
+ }
+
+ for ( i = m_Chunks.Count() - 1; i >= 0 ; i-- )
+ {
+ if ( !m_Chunks[i] )
+ {
+ m_Chunks.FastRemove( i );
+ }
+ }
+}
+
+#endif // MEMPOOL_H
diff --git a/public/tier1/memstack.h b/public/tier1/memstack.h
new file mode 100644
index 0000000..e5f0885
--- /dev/null
+++ b/public/tier1/memstack.h
@@ -0,0 +1,207 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A fast stack memory allocator that uses virtual memory if available
+//
+//=============================================================================//
+
+#ifndef MEMSTACK_H
+#define MEMSTACK_H
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+
+//-----------------------------------------------------------------------------
+
+typedef unsigned MemoryStackMark_t;
+
+class CMemoryStack
+{
+public:
+ CMemoryStack();
+ ~CMemoryStack();
+
+ bool Init( unsigned maxSize = 0, unsigned commitSize = 0, unsigned initialCommit = 0, unsigned alignment = 16 );
+#ifdef _X360
+ bool InitPhysical( unsigned size = 0, unsigned alignment = 16 );
+#endif
+ void Term();
+
+ int GetSize();
+ int GetMaxSize();
+ int GetUsed();
+
+ void *Alloc( unsigned bytes, bool bClear = false ) RESTRICT;
+
+ MemoryStackMark_t GetCurrentAllocPoint();
+ void FreeToAllocPoint( MemoryStackMark_t mark, bool bDecommit = true );
+ void FreeAll( bool bDecommit = true );
+
+ void Access( void **ppRegion, unsigned *pBytes );
+
+ void PrintContents();
+
+ void *GetBase();
+ const void *GetBase() const { return const_cast<CMemoryStack *>(this)->GetBase(); }
+
+private:
+ bool CommitTo( byte * ) RESTRICT;
+
+ byte *m_pNextAlloc;
+ byte *m_pCommitLimit;
+ byte *m_pAllocLimit;
+
+ byte *m_pBase;
+
+ unsigned m_maxSize;
+ unsigned m_alignment;
+#ifdef _WIN32
+ unsigned m_commitSize;
+ unsigned m_minCommit;
+#endif
+#ifdef _X360
+ bool m_bPhysical;
+#endif
+};
+
+//-------------------------------------
+
+FORCEINLINE void *CMemoryStack::Alloc( unsigned bytes, bool bClear ) RESTRICT
+{
+ Assert( m_pBase );
+
+ int alignment = m_alignment;
+ if ( bytes )
+ {
+ bytes = AlignValue( bytes, alignment );
+ }
+ else
+ {
+ bytes = alignment;
+ }
+
+
+ void *pResult = m_pNextAlloc;
+ byte *pNextAlloc = m_pNextAlloc + bytes;
+
+ if ( pNextAlloc > m_pCommitLimit )
+ {
+ if ( !CommitTo( pNextAlloc ) )
+ {
+ return NULL;
+ }
+ }
+
+ if ( bClear )
+ {
+ memset( pResult, 0, bytes );
+ }
+
+ m_pNextAlloc = pNextAlloc;
+
+ return pResult;
+}
+
+//-------------------------------------
+
+inline int CMemoryStack::GetMaxSize()
+{
+ return m_maxSize;
+}
+
+//-------------------------------------
+
+inline int CMemoryStack::GetUsed()
+{
+ return ( m_pNextAlloc - m_pBase );
+}
+
+//-------------------------------------
+
+inline void *CMemoryStack::GetBase()
+{
+ return m_pBase;
+}
+
+//-------------------------------------
+
+inline MemoryStackMark_t CMemoryStack::GetCurrentAllocPoint()
+{
+ return ( m_pNextAlloc - m_pBase );
+}
+
+//-----------------------------------------------------------------------------
+// The CUtlMemoryStack class:
+// A fixed memory class
+//-----------------------------------------------------------------------------
+template< typename T, typename I, size_t MAX_SIZE, size_t COMMIT_SIZE = 0, size_t INITIAL_COMMIT = 0 >
+class CUtlMemoryStack
+{
+public:
+ // constructor, destructor
+ CUtlMemoryStack( int nGrowSize = 0, int nInitSize = 0 ) { m_MemoryStack.Init( MAX_SIZE * sizeof(T), COMMIT_SIZE * sizeof(T), INITIAL_COMMIT * sizeof(T), 4 ); COMPILE_TIME_ASSERT( sizeof(T) % 4 == 0 ); }
+ CUtlMemoryStack( T* pMemory, int numElements ) { Assert( 0 ); }
+
+ // Can we use this index?
+ bool IsIdxValid( I i ) const { return (i >= 0) && (i < m_nAllocated); }
+
+ // Specify the invalid ('null') index that we'll only return on failure
+ static const I INVALID_INDEX = ( I )-1; // For use with COMPILE_TIME_ASSERT
+ static I InvalidIndex() { return INVALID_INDEX; }
+
+ class Iterator_t
+ {
+ Iterator_t( I i ) : index( i ) {}
+ I index;
+ friend class CUtlMemoryStack<T,I,MAX_SIZE, COMMIT_SIZE, INITIAL_COMMIT>;
+ public:
+ bool operator==( const Iterator_t it ) const { return index == it.index; }
+ bool operator!=( const Iterator_t it ) const { return index != it.index; }
+ };
+ Iterator_t First() const { return Iterator_t( m_nAllocated ? 0 : InvalidIndex() ); }
+ Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( it.index < m_nAllocated ? it.index + 1 : InvalidIndex() ); }
+ I GetIndex( const Iterator_t &it ) const { return it.index; }
+ bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; }
+ bool IsValidIterator( const Iterator_t &it ) const { return it.index >= 0 && it.index < m_nAllocated; }
+ Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); }
+
+ // Gets the base address
+ T* Base() { return (T*)m_MemoryStack.GetBase(); }
+ const T* Base() const { return (const T*)m_MemoryStack.GetBase(); }
+
+ // element access
+ T& operator[]( I i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
+ const T& operator[]( I i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
+ T& Element( I i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
+ const T& Element( I i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
+
+ // Attaches the buffer to external memory....
+ void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); }
+
+ // Size
+ int NumAllocated() const { return m_nAllocated; }
+ int Count() const { return m_nAllocated; }
+
+ // Grows the memory, so that at least allocated + num elements are allocated
+ void Grow( int num = 1 ) { Assert( num > 0 ); m_nAllocated += num; m_MemoryStack.Alloc( num * sizeof(T) ); }
+
+ // Makes sure we've got at least this much memory
+ void EnsureCapacity( int num ) { Assert( num <= MAX_SIZE ); if ( m_nAllocated < num ) Grow( num - m_nAllocated ); }
+
+ // Memory deallocation
+ void Purge() { m_MemoryStack.FreeAll(); m_nAllocated = 0; }
+
+ // is the memory externally allocated?
+ bool IsExternallyAllocated() const { return false; }
+
+ // Set the size by which the memory grows
+ void SetGrowSize( int size ) {}
+
+private:
+ CMemoryStack m_MemoryStack;
+ int m_nAllocated;
+};
+
+//-----------------------------------------------------------------------------
+
+#endif // MEMSTACK_H
diff --git a/public/tier1/netadr.h b/public/tier1/netadr.h
new file mode 100644
index 0000000..c15171f
--- /dev/null
+++ b/public/tier1/netadr.h
@@ -0,0 +1,136 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// netadr.h
+#ifndef NETADR_H
+#define NETADR_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/platform.h"
+#undef SetPort
+
+class bf_read;
+class bf_write;
+
+typedef enum
+{
+ NA_NULL = 0,
+ NA_LOOPBACK,
+ NA_BROADCAST,
+ NA_IP,
+} netadrtype_t;
+
+typedef struct netadr_s
+{
+public:
+ netadr_s() { SetIP( 0 ); SetPort( 0 ); SetType( NA_IP ); }
+ netadr_s( uint unIP, uint16 usPort ) { SetIP( unIP ); SetPort( usPort ); SetType( NA_IP ); }
+ netadr_s( const char *pch ) { SetFromString( pch ); }
+ void Clear(); // invalids Address
+
+ void SetType( netadrtype_t type );
+ void SetPort( unsigned short port );
+ bool SetFromSockadr(const struct sockaddr *s);
+ void SetIP(uint8 b1, uint8 b2, uint8 b3, uint8 b4);
+ void SetIP(uint unIP); // Sets IP. unIP is in host order (little-endian)
+ void SetIPAndPort( uint unIP, unsigned short usPort ) { SetIP( unIP ); SetPort( usPort ); }
+ bool SetFromString(const char *pch, bool bUseDNS = false ); // if bUseDNS is true then do a DNS lookup if needed
+
+ bool CompareAdr (const netadr_s &a, bool onlyBase = false) const;
+ bool CompareClassBAdr (const netadr_s &a) const;
+ bool CompareClassCAdr (const netadr_s &a) const;
+
+ netadrtype_t GetType() const;
+ unsigned short GetPort() const;
+
+ // DON'T CALL THIS
+ const char* ToString( bool onlyBase = false ) const; // returns xxx.xxx.xxx.xxx:ppppp
+
+ void ToString( char *pchBuffer, uint32 unBufferSize, bool onlyBase = false ) const; // returns xxx.xxx.xxx.xxx:ppppp
+ template< size_t maxLenInChars >
+ void ToString_safe( char (&pDest)[maxLenInChars], bool onlyBase = false ) const
+ {
+ ToString( &pDest[0], maxLenInChars, onlyBase );
+ }
+
+ void ToSockadr(struct sockaddr *s) const;
+
+ // Returns 0xAABBCCDD for AA.BB.CC.DD on all platforms, which is the same format used by SetIP().
+ // (So why isn't it just named GetIP()? Because previously there was a fucntion named GetIP(), and
+ // it did NOT return back what you put into SetIP(). So we nuked that guy.)
+ unsigned int GetIPHostByteOrder() const;
+
+ // Returns a number that depends on the platform. In most cases, this probably should not be used.
+ unsigned int GetIPNetworkByteOrder() const;
+
+ bool IsLocalhost() const; // true, if this is the localhost IP
+ bool IsLoopback() const; // true if engine loopback buffers are used
+ bool IsReservedAdr() const; // true, if this is a private LAN IP
+ bool IsValid() const; // ip & port != 0
+ bool IsBaseAdrValid() const; // ip != 0
+
+ void SetFromSocket( int hSocket );
+
+ bool Unserialize( bf_read &readBuf );
+ bool Serialize( bf_write &writeBuf );
+
+ bool operator==(const netadr_s &netadr) const {return ( CompareAdr( netadr ) );}
+ bool operator!=(const netadr_s &netadr) const {return !( CompareAdr( netadr ) );}
+ bool operator<(const netadr_s &netadr) const;
+
+public: // members are public to avoid to much changes
+
+ netadrtype_t type;
+ unsigned char ip[4];
+ unsigned short port;
+} netadr_t;
+
+
+/// Helper class to render a netadr_t. Use this when formatting a net address
+/// in a printf. Don't use adr.ToString()!
+class CUtlNetAdrRender
+{
+public:
+ CUtlNetAdrRender( const netadr_t &obj, bool bBaseOnly = false )
+ {
+ obj.ToString( m_rgchString, sizeof(m_rgchString), bBaseOnly );
+ }
+
+ CUtlNetAdrRender( uint32 unIP )
+ {
+ netadr_t addr( unIP, 0 );
+ addr.ToString( m_rgchString, sizeof(m_rgchString), true );
+ }
+
+ CUtlNetAdrRender( uint32 unIP, uint16 unPort )
+ {
+ netadr_t addr( unIP, unPort );
+ addr.ToString( m_rgchString, sizeof(m_rgchString), false );
+ }
+
+ CUtlNetAdrRender( const struct sockaddr &s )
+ {
+ netadr_t addr;
+ if ( addr.SetFromSockadr( &s ) )
+ addr.ToString( m_rgchString, sizeof(m_rgchString), false );
+ else
+ m_rgchString[0] = '\0';
+ }
+
+ const char * String() const
+ {
+ return m_rgchString;
+ }
+
+private:
+
+ char m_rgchString[32];
+};
+
+#endif // NETADR_H
diff --git a/public/tier1/passwordhash.h b/public/tier1/passwordhash.h
new file mode 100644
index 0000000..f557c7f
--- /dev/null
+++ b/public/tier1/passwordhash.h
@@ -0,0 +1,94 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Cryptographic hash agility helper definitions
+//
+//=============================================================================
+
+#ifndef PASSWORDHASH_H
+#define PASSWORDHASH_H
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+
+
+#include "checksum_sha1.h"
+
+typedef unsigned char BigPasswordHash_t[32];
+typedef unsigned char PBKDF2Hash_t[32];
+
+//
+// A union of all the possible password hash types.
+// When adding to this, if the maximum size of the
+// structure has changed then the Account table and
+// the AccountSecurityHistory table need to be manually
+// revised using something like the following SQL:
+//
+// ALTER TABLE Account ALTER COLUMN PasswordHash binary(32)
+// ALTER TABLE AccountSecurityHistory ALTER COLUMN PasswordHashOld binary(32)
+// ALTER TABLE AccountSecurityHistory ALTER COLUMN PasswordHashNew binary(32)
+//
+// Replace 32 with the new size of PasswordHash_t.
+//
+// If the width of those columns does not match sizeof(PasswordHash_t), many
+// database operations will fail.
+//
+// Note that while this query was correct at the time this code was checked in,
+// it may not be sufficient at the time you actually change the size of the
+// type, so look around.
+//
+typedef union
+{
+ SHADigest_t sha;
+ BigPasswordHash_t bigpassword;
+ PBKDF2Hash_t pbkdf2;
+} PasswordHash_t;
+
+
+//
+// Enum of all available password hash algorithms. These should
+// be consecutive and ordinals should never be reused.
+//
+// k_EHashSHA1: A salted SHA-1 hash, width 20 bytes.
+// k_EHashBigPassword: For testing purposes, a salted SHA-1 hash extended to 32 bytes, with 6 bytes of 0x1 on either side.
+// k_EHashPBKDF2_1000: A PKCS#5 v2.0 Password-Based Key Derivation Function hash (PBKDF2-HMAC-SHA256) with 1,000 iterations.
+// The digest width is 32 bytes.
+// k_EHashPBKDF2_5000: A PKCS#5 v2.0 Password-Based Key Derivation Function hash (PBKDF2-HMAC-SHA256) with 5,000 iterations.
+// k_EHashPBKDF2_10000: A PKCS#5 v2.0 Password-Based Key Derivation Function hash (PBKDF2-HMAC-SHA256) with 10,000 iterations.
+// k_EHashSHA1WrappedWithPBKDF2_10000: A SHA-1 hash which is then further hashed with PBKDF2 at 10,000 rounds. Used for
+// strengthening old hashes in the database that haven't been logged in in a long time.
+//
+// Make sure to update k_EHashMax when adding new hash types. Also add the length into the k_HashLengths array below.
+enum EPasswordHashAlg
+{
+ k_EHashSHA1 = 0,
+ k_EHashBigPassword = 1,
+ k_EHashPBKDF2_1000 = 2,
+ k_EHashPBKDF2_5000 = 3,
+ k_EHashPBKDF2_10000 = 4,
+ k_EHashSHA1WrappedWithPBKDF2_10000 = 5,
+ k_EHashMax = 5,
+};
+
+//
+// Hash sizes for the various available hash algorithms,
+// indexed by EPasswordHashAlg.
+const size_t k_HashLengths[] = {
+ sizeof(SHADigest_t),
+ sizeof(BigPasswordHash_t),
+ sizeof(PBKDF2Hash_t),
+ sizeof(PBKDF2Hash_t),
+ sizeof(PBKDF2Hash_t),
+ sizeof(PBKDF2Hash_t),
+};
+
+#if defined(C_ASSERT)
+//
+// If you're hitting this assert at compile time, it means that you've added a new
+// hash type and properly updated k_EHashMax, but you forgot to add the length
+// of the new hash type into k_HashLengths. So do that.
+//
+C_ASSERT( ( ( sizeof(k_HashLengths) / sizeof(size_t) ) == k_EHashMax + 1 ) );
+#endif
+
+#endif // PASSWORDHASH_H
diff --git a/public/tier1/processor_detect.h b/public/tier1/processor_detect.h
new file mode 100644
index 0000000..cb4cc37
--- /dev/null
+++ b/public/tier1/processor_detect.h
@@ -0,0 +1,12 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: functions to expose CPU capabilities
+//
+// $NoKeywords: $
+//=============================================================================//
+
+bool CheckMMXTechnology(void);
+bool CheckSSETechnology(void);
+bool CheckSSE2Technology(void);
+bool Check3DNowTechnology(void);
+
diff --git a/public/tier1/rangecheckedvar.h b/public/tier1/rangecheckedvar.h
new file mode 100644
index 0000000..52313f8
--- /dev/null
+++ b/public/tier1/rangecheckedvar.h
@@ -0,0 +1,118 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef RANGECHECKEDVAR_H
+#define RANGECHECKEDVAR_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "tier0/dbg.h"
+#include "tier0/threadtools.h"
+#include "mathlib/vector.h"
+#include <float.h>
+
+
+// Use this to disable range checks within a scope.
+class CDisableRangeChecks
+{
+public:
+ CDisableRangeChecks();
+ ~CDisableRangeChecks();
+};
+
+
+template< class T >
+inline void RangeCheck( const T &value, int minValue, int maxValue )
+{
+#ifdef _DEBUG
+ extern bool g_bDoRangeChecks;
+ if ( ThreadInMainThread() && g_bDoRangeChecks )
+ {
+ // Ignore the min/max stuff for now.. just make sure it's not a NAN.
+ Assert( _finite( value ) );
+ }
+#endif
+}
+
+inline void RangeCheck( const Vector &value, int minValue, int maxValue )
+{
+#ifdef _DEBUG
+ RangeCheck( value.x, minValue, maxValue );
+ RangeCheck( value.y, minValue, maxValue );
+ RangeCheck( value.z, minValue, maxValue );
+#endif
+}
+
+
+template< class T, int minValue, int maxValue, int startValue >
+class CRangeCheckedVar
+{
+public:
+
+ inline CRangeCheckedVar()
+ {
+ m_Val = startValue;
+ }
+
+ inline CRangeCheckedVar( const T &value )
+ {
+ *this = value;
+ }
+
+ T GetRaw() const
+ {
+ return m_Val;
+ }
+
+ // Clamp the value to its limits. Interpolation code uses this after interpolating.
+ inline void Clamp()
+ {
+ if ( m_Val < minValue )
+ m_Val = minValue;
+ else if ( m_Val > maxValue )
+ m_Val = maxValue;
+ }
+
+ inline operator const T&() const
+ {
+ return m_Val;
+ }
+
+ inline CRangeCheckedVar<T, minValue, maxValue, startValue>& operator=( const T &value )
+ {
+ RangeCheck( value, minValue, maxValue );
+ m_Val = value;
+ return *this;
+ }
+
+ inline CRangeCheckedVar<T, minValue, maxValue, startValue>& operator+=( const T &value )
+ {
+ return (*this = m_Val + value);
+ }
+
+ inline CRangeCheckedVar<T, minValue, maxValue, startValue>& operator-=( const T &value )
+ {
+ return (*this = m_Val - value);
+ }
+
+ inline CRangeCheckedVar<T, minValue, maxValue, startValue>& operator*=( const T &value )
+ {
+ return (*this = m_Val * value);
+ }
+
+ inline CRangeCheckedVar<T, minValue, maxValue, startValue>& operator/=( const T &value )
+ {
+ return (*this = m_Val / value);
+ }
+
+private:
+
+ T m_Val;
+};
+
+#endif // RANGECHECKEDVAR_H
diff --git a/public/tier1/refcount.h b/public/tier1/refcount.h
new file mode 100644
index 0000000..9c756b8
--- /dev/null
+++ b/public/tier1/refcount.h
@@ -0,0 +1,419 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Tools for correctly implementing & handling reference counted
+// objects
+//
+//=============================================================================
+
+#ifndef REFCOUNT_H
+#define REFCOUNT_H
+
+#include "tier0/threadtools.h"
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+
+template <typename T>
+inline void SafeAssign(T** ppInoutDst, T* pInoutSrc )
+{
+ Assert( ppInoutDst );
+
+ // Do addref before release
+ if ( pInoutSrc )
+ ( pInoutSrc )->AddRef();
+
+ // Do addref before release
+ if ( *ppInoutDst )
+ ( *ppInoutDst )->Release();
+
+ // Do the assignment
+ ( *ppInoutDst ) = pInoutSrc;
+}
+
+template <typename T>
+inline void SafeAddRef( T* pObj )
+{
+ if ( pObj )
+ pObj->AddRef();
+}
+
+template <typename T>
+inline void SafeRelease( T** ppInoutPtr )
+{
+ Assert( ppInoutPtr );
+ if ( *ppInoutPtr )
+ ( *ppInoutPtr )->Release();
+
+ ( *ppInoutPtr ) = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Implement a standard reference counted interface. Use of this
+// is optional insofar as all the concrete tools only require
+// at compile time that the function signatures match.
+//-----------------------------------------------------------------------------
+
+class IRefCounted
+{
+public:
+ virtual int AddRef() = 0;
+ virtual int Release() = 0;
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Release a pointer and mark it NULL
+//-----------------------------------------------------------------------------
+
+template <class REFCOUNTED_ITEM_PTR>
+inline int SafeRelease( REFCOUNTED_ITEM_PTR &pRef )
+{
+ // Use funny syntax so that this works on "auto pointers"
+ REFCOUNTED_ITEM_PTR *ppRef = &pRef;
+ if ( *ppRef )
+ {
+ int result = (*ppRef)->Release();
+ *ppRef = NULL;
+ return result;
+ }
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Maintain a reference across a scope
+//-----------------------------------------------------------------------------
+
+template <class T = IRefCounted>
+class CAutoRef
+{
+public:
+ CAutoRef( T *pRef )
+ : m_pRef( pRef )
+ {
+ if ( m_pRef )
+ m_pRef->AddRef();
+ }
+
+ ~CAutoRef()
+ {
+ if (m_pRef)
+ m_pRef->Release();
+ }
+
+private:
+ T *m_pRef;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Do a an inline AddRef then return the pointer, useful when
+// returning an object from a function
+//-----------------------------------------------------------------------------
+
+#define RetAddRef( p ) ( (p)->AddRef(), (p) )
+#define InlineAddRef( p ) ( (p)->AddRef(), (p) )
+
+
+//-----------------------------------------------------------------------------
+// Purpose: A class to both hold a pointer to an object and its reference.
+// Base exists to support other cleanup models
+//-----------------------------------------------------------------------------
+
+template <class T>
+class CBaseAutoPtr
+{
+public:
+ CBaseAutoPtr() : m_pObject(0) {}
+ CBaseAutoPtr(T *pFrom) : m_pObject(pFrom) {}
+
+ operator const void *() const { return m_pObject; }
+ operator void *() { return m_pObject; }
+
+ operator const T *() const { return m_pObject; }
+ operator const T *() { return m_pObject; }
+ operator T *() { return m_pObject; }
+
+ int operator=( int i ) { AssertMsg( i == 0, "Only NULL allowed on integer assign" ); m_pObject = 0; return 0; }
+ T * operator=( T *p ) { m_pObject = p; return p; }
+
+ bool operator !() const { return ( !m_pObject ); }
+ bool operator!=( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (m_pObject != NULL); }
+ bool operator==( const void *p ) const { return ( m_pObject == p ); }
+ bool operator!=( const void *p ) const { return ( m_pObject != p ); }
+ bool operator==( T *p ) const { return operator==( (void *)p ); }
+ bool operator!=( T *p ) const { return operator!=( (void *)p ); }
+ bool operator==( const CBaseAutoPtr<T> &p ) const { return operator==( (const void *)p ); }
+ bool operator!=( const CBaseAutoPtr<T> &p ) const { return operator!=( (const void *)p ); }
+
+ T * operator->() { return m_pObject; }
+ T & operator *() { return *m_pObject; }
+ T ** operator &() { return &m_pObject; }
+
+ const T * operator->() const { return m_pObject; }
+ const T & operator *() const { return *m_pObject; }
+ T * const * operator &() const { return &m_pObject; }
+
+protected:
+ CBaseAutoPtr( const CBaseAutoPtr<T> &from ) : m_pObject( from.m_pObject ) {}
+ void operator=( const CBaseAutoPtr<T> &from ) { m_pObject = from.m_pObject; }
+
+ T *m_pObject;
+};
+
+//---------------------------------------------------------
+
+template <class T>
+class CRefPtr : public CBaseAutoPtr<T>
+{
+ typedef CBaseAutoPtr<T> BaseClass;
+public:
+ CRefPtr() {}
+ CRefPtr( T *pInit ) : BaseClass( pInit ) {}
+ CRefPtr( const CRefPtr<T> &from ) : BaseClass( from ) {}
+ ~CRefPtr() { if ( BaseClass::m_pObject ) BaseClass::m_pObject->Release(); }
+
+ void operator=( const CRefPtr<T> &from ) { BaseClass::operator=( from ); }
+
+ int operator=( int i ) { return BaseClass::operator=( i ); }
+ T *operator=( T *p ) { return BaseClass::operator=( p ); }
+
+ operator bool() const { return !BaseClass::operator!(); }
+ operator bool() { return !BaseClass::operator!(); }
+
+ void SafeRelease() { if ( BaseClass::m_pObject ) BaseClass::m_pObject->Release(); BaseClass::m_pObject = 0; }
+ void AssignAddRef( T *pFrom ) { SafeRelease(); if (pFrom) pFrom->AddRef(); BaseClass::m_pObject = pFrom; }
+ void AddRefAssignTo( T *&pTo ) { ::SafeRelease( pTo ); if ( BaseClass::m_pObject ) BaseClass::m_pObject->AddRef(); pTo = BaseClass::m_pObject; }
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Traits classes defining reference count threading model
+//-----------------------------------------------------------------------------
+
+class CRefMT
+{
+public:
+ static int Increment( int *p) { return ThreadInterlockedIncrement( (long *)p ); }
+ static int Decrement( int *p) { return ThreadInterlockedDecrement( (long *)p ); }
+};
+
+class CRefST
+{
+public:
+ static int Increment( int *p) { return ++(*p); }
+ static int Decrement( int *p) { return --(*p); }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Actual reference counting implementation. Pulled out to reduce
+// code bloat.
+//-----------------------------------------------------------------------------
+
+template <const bool bSelfDelete, typename CRefThreading = CRefMT>
+class NO_VTABLE CRefCountServiceBase
+{
+protected:
+ CRefCountServiceBase()
+ : m_iRefs( 1 )
+ {
+ }
+
+ virtual ~CRefCountServiceBase()
+ {
+ }
+
+ virtual bool OnFinalRelease()
+ {
+ return true;
+ }
+
+ int GetRefCount() const
+ {
+ return m_iRefs;
+ }
+
+ int DoAddRef()
+ {
+ return CRefThreading::Increment( &m_iRefs );
+ }
+
+ int DoRelease()
+ {
+ int result = CRefThreading::Decrement( &m_iRefs );
+ if ( result )
+ return result;
+ if ( OnFinalRelease() && bSelfDelete )
+ delete this;
+ return 0;
+ }
+
+private:
+ int m_iRefs;
+};
+
+class CRefCountServiceNull
+{
+protected:
+ static int DoAddRef() { return 1; }
+ static int DoRelease() { return 1; }
+};
+
+template <typename CRefThreading = CRefMT>
+class NO_VTABLE CRefCountServiceDestruct
+{
+protected:
+ CRefCountServiceDestruct()
+ : m_iRefs( 1 )
+ {
+ }
+
+ virtual ~CRefCountServiceDestruct()
+ {
+ }
+
+ int GetRefCount() const
+ {
+ return m_iRefs;
+ }
+
+ int DoAddRef()
+ {
+ return CRefThreading::Increment( &m_iRefs );
+ }
+
+ int DoRelease()
+ {
+ int result = CRefThreading::Decrement( &m_iRefs );
+ if ( result )
+ return result;
+ this->~CRefCountServiceDestruct();
+ return 0;
+ }
+
+private:
+ int m_iRefs;
+};
+
+
+typedef CRefCountServiceBase<true, CRefST> CRefCountServiceST;
+typedef CRefCountServiceBase<false, CRefST> CRefCountServiceNoDeleteST;
+
+typedef CRefCountServiceBase<true, CRefMT> CRefCountServiceMT;
+typedef CRefCountServiceBase<false, CRefMT> CRefCountServiceNoDeleteMT;
+
+// Default to threadsafe
+typedef CRefCountServiceNoDeleteMT CRefCountServiceNoDelete;
+typedef CRefCountServiceMT CRefCountService;
+
+//-----------------------------------------------------------------------------
+// Purpose: Base classes to implement reference counting
+//-----------------------------------------------------------------------------
+
+template < class REFCOUNT_SERVICE = CRefCountService >
+class NO_VTABLE CRefCounted : public REFCOUNT_SERVICE
+{
+public:
+ virtual ~CRefCounted() {}
+ int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
+ int Release() { return REFCOUNT_SERVICE::DoRelease(); }
+};
+
+//-------------------------------------
+
+template < class BASE1, class REFCOUNT_SERVICE = CRefCountService >
+class NO_VTABLE CRefCounted1 : public BASE1,
+ public REFCOUNT_SERVICE
+{
+public:
+ virtual ~CRefCounted1() {}
+ int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
+ int Release() { return REFCOUNT_SERVICE::DoRelease(); }
+};
+
+//-------------------------------------
+
+template < class BASE1, class BASE2, class REFCOUNT_SERVICE = CRefCountService >
+class NO_VTABLE CRefCounted2 : public BASE1, public BASE2,
+ public REFCOUNT_SERVICE
+{
+public:
+ virtual ~CRefCounted2() {}
+ int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
+ int Release() { return REFCOUNT_SERVICE::DoRelease(); }
+};
+
+//-------------------------------------
+
+template < class BASE1, class BASE2, class BASE3, class REFCOUNT_SERVICE = CRefCountService >
+class NO_VTABLE CRefCounted3 : public BASE1, public BASE2, public BASE3,
+ public REFCOUNT_SERVICE
+{
+ virtual ~CRefCounted3() {}
+ int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
+ int Release() { return REFCOUNT_SERVICE::DoRelease(); }
+};
+
+//-------------------------------------
+
+template < class BASE1, class BASE2, class BASE3, class BASE4, class REFCOUNT_SERVICE = CRefCountService >
+class NO_VTABLE CRefCounted4 : public BASE1, public BASE2, public BASE3, public BASE4,
+ public REFCOUNT_SERVICE
+{
+public:
+ virtual ~CRefCounted4() {}
+ int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
+ int Release() { return REFCOUNT_SERVICE::DoRelease(); }
+};
+
+//-------------------------------------
+
+template < class BASE1, class BASE2, class BASE3, class BASE4, class BASE5, class REFCOUNT_SERVICE = CRefCountService >
+class NO_VTABLE CRefCounted5 : public BASE1, public BASE2, public BASE3, public BASE4, public BASE5,
+ public REFCOUNT_SERVICE
+{
+public:
+ virtual ~CRefCounted5() {}
+ int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); }
+ int Release() { return REFCOUNT_SERVICE::DoRelease(); }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Class to throw around a reference counted item to debug
+// referencing problems
+//-----------------------------------------------------------------------------
+
+template <class BASE_REFCOUNTED, int FINAL_REFS, const char *pszName>
+class CRefDebug : public BASE_REFCOUNTED
+{
+public:
+#ifdef _DEBUG
+ CRefDebug()
+ {
+ AssertMsg( this->GetRefCount() == 1, "Expected initial ref count of 1" );
+ DevMsg( "%s:create 0x%x\n", ( pszName ) ? pszName : "", this );
+ }
+
+ virtual ~CRefDebug()
+ {
+ AssertDevMsg( this->GetRefCount() == FINAL_REFS, "Object still referenced on destroy?" );
+ DevMsg( "%s:destroy 0x%x\n", ( pszName ) ? pszName : "", this );
+ }
+
+ int AddRef()
+ {
+ DevMsg( "%s:(0x%x)->AddRef() --> %d\n", ( pszName ) ? pszName : "", this, this->GetRefCount() + 1 );
+ return BASE_REFCOUNTED::AddRef();
+ }
+
+ int Release()
+ {
+ DevMsg( "%s:(0x%x)->Release() --> %d\n", ( pszName ) ? pszName : "", this, this->GetRefCount() - 1 );
+ Assert( this->GetRefCount() > 0 );
+ return BASE_REFCOUNTED::Release();
+ }
+#endif
+};
+
+//-----------------------------------------------------------------------------
+
+#endif // REFCOUNT_H
diff --git a/public/tier1/reliabletimer.h b/public/tier1/reliabletimer.h
new file mode 100644
index 0000000..c830fbe
--- /dev/null
+++ b/public/tier1/reliabletimer.h
@@ -0,0 +1,183 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef RELIABLETIMER_H
+#define RELIABLETIMER_H
+
+#include "tier0/dbg.h"
+//#include "constants.h"
+#include "tier0/fasttimer.h"
+#include "tier1/tier1.h"
+#include "tier1/strtools.h"
+
+#define DbgAssert Assert
+#define kMILLION (1000000)
+#define kTHOUSAND (1000)
+
+// Timer class that uses QueryPerformanceCounter. This is heavier-weight than CFastTimer which uses rdtsc,
+// but this is reliable on multi-core systems whereas CFastTimer is not.
+
+class CReliableTimer
+{
+public:
+ CReliableTimer();
+ void Start();
+ void End();
+ int64 GetMicroseconds();
+ int64 GetMilliseconds();
+ void SetLimit( uint64 m_cMicroSecDuration );
+ bool BLimitReached();
+ int64 CMicroSecOverage();
+ int64 CMicroSecLeft();
+ int64 CMilliSecLeft();
+private:
+ int64 GetPerformanceCountNow();
+
+ int64 m_nPerformanceCounterStart;
+ int64 m_nPerformanceCounterEnd;
+ int64 m_nPerformanceCounterLimit;
+
+ static int64 sm_nPerformanceFrequency;
+ static bool sm_bUseQPC;
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Records timer start time
+//-----------------------------------------------------------------------------
+inline void CReliableTimer::Start()
+{
+ m_nPerformanceCounterStart = GetPerformanceCountNow();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Records timer end time
+//-----------------------------------------------------------------------------
+inline void CReliableTimer::End()
+{
+ m_nPerformanceCounterEnd = GetPerformanceCountNow();
+
+ // enforce that we've advanced at least one cycle
+ if ( m_nPerformanceCounterEnd < m_nPerformanceCounterStart )
+ {
+#ifdef _SERVER
+ if ( m_nPerformanceCounterEnd+10000 < m_nPerformanceCounterStart )
+ AssertMsgOnce( false, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() );
+#endif
+ m_nPerformanceCounterEnd = m_nPerformanceCounterStart + 1;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets microseconds elapsed between start and end
+//-----------------------------------------------------------------------------
+inline int64 CReliableTimer::GetMicroseconds()
+{
+ DbgAssert( m_nPerformanceCounterStart ); // timer must have been started
+ DbgAssert( m_nPerformanceCounterEnd ); // timer must have been ended
+ DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
+ return ( ( m_nPerformanceCounterEnd - m_nPerformanceCounterStart ) * kMILLION / sm_nPerformanceFrequency );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets microseconds elapsed between start and end
+//-----------------------------------------------------------------------------
+inline int64 CReliableTimer::GetMilliseconds()
+{
+ DbgAssert( m_nPerformanceCounterStart ); // timer must have been started
+ DbgAssert( m_nPerformanceCounterEnd ); // timer must have been ended
+ DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
+ return ( ( m_nPerformanceCounterEnd - m_nPerformanceCounterStart ) * kTHOUSAND / sm_nPerformanceFrequency );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets a limit on this timer that can subsequently be checked against
+//-----------------------------------------------------------------------------
+inline void CReliableTimer::SetLimit( uint64 cMicroSecDuration )
+{
+ DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
+ m_nPerformanceCounterStart = GetPerformanceCountNow();
+ m_nPerformanceCounterLimit = m_nPerformanceCounterStart + ( ( cMicroSecDuration * sm_nPerformanceFrequency ) / kMILLION );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns if previously set limit has been reached
+//-----------------------------------------------------------------------------
+inline bool CReliableTimer::BLimitReached()
+{
+ DbgAssert( m_nPerformanceCounterStart ); // SetLimit must have been called
+ DbgAssert( m_nPerformanceCounterLimit ); // SetLimit must have been called
+ int64 nPerformanceCountNow = GetPerformanceCountNow();
+
+ // make sure time advances
+ if ( nPerformanceCountNow < m_nPerformanceCounterStart )
+ {
+#ifdef _SERVER
+ if ( nPerformanceCountNow+10000 < m_nPerformanceCounterStart )
+ AssertMsgOnce( false, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() );
+#endif
+ // reset the limit to be lower, to match our new clock
+ m_nPerformanceCounterLimit = nPerformanceCountNow + (m_nPerformanceCounterLimit - m_nPerformanceCounterStart);
+ }
+
+ return ( nPerformanceCountNow >= m_nPerformanceCounterLimit );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns microseconds current time is past limit, or 0 if not past limit
+//-----------------------------------------------------------------------------
+inline int64 CReliableTimer::CMicroSecOverage()
+{
+ DbgAssert( m_nPerformanceCounterStart ); // SetLimit must have been called
+ DbgAssert( m_nPerformanceCounterLimit ); // SetLimit must have been called
+ int64 nPerformanceCountNow = GetPerformanceCountNow();
+#ifdef _SERVER
+ if ( nPerformanceCountNow+10000 < m_nPerformanceCounterStart )
+ AssertMsgOnce( nPerformanceCountNow >= m_nPerformanceCounterStart, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() );
+#endif
+ int64 nPerformanceCountOver = ( nPerformanceCountNow > m_nPerformanceCounterLimit ?
+ nPerformanceCountNow - m_nPerformanceCounterLimit : 0 );
+
+ Assert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
+ return ( nPerformanceCountOver * kMILLION / sm_nPerformanceFrequency );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns microseconds remaining until limit
+//-----------------------------------------------------------------------------
+inline int64 CReliableTimer::CMicroSecLeft()
+{
+ DbgAssert( m_nPerformanceCounterStart ); // SetLimit must have been called
+ DbgAssert( m_nPerformanceCounterLimit ); // SetLimit must have been called
+ int64 nPerformanceCountNow = GetPerformanceCountNow();
+#ifdef _SERVER
+ if ( nPerformanceCountNow+10000 < m_nPerformanceCounterStart )
+ AssertMsgOnce( nPerformanceCountNow >= m_nPerformanceCounterStart, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() );
+#endif
+ int64 nPerformanceCountLeft = ( nPerformanceCountNow < m_nPerformanceCounterLimit ?
+ m_nPerformanceCounterLimit - nPerformanceCountNow : 0 );
+
+ DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
+ return ( nPerformanceCountLeft * kMILLION / sm_nPerformanceFrequency );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns milliseconds remaining until limit
+//-----------------------------------------------------------------------------
+inline int64 CReliableTimer::CMilliSecLeft()
+{
+ return CMicroSecLeft() / 1000;
+}
+
+
+#endif // TICKLIMITTIMER_H
diff --git a/public/tier1/smartptr.h b/public/tier1/smartptr.h
new file mode 100644
index 0000000..466ca0b
--- /dev/null
+++ b/public/tier1/smartptr.h
@@ -0,0 +1,279 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef SMARTPTR_H
+#define SMARTPTR_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+class CRefCountAccessor
+{
+public:
+ template< class T >
+ static void AddRef( T *pObj )
+ {
+ pObj->AddRef();
+ }
+
+ template< class T >
+ static void Release( T *pObj )
+ {
+ pObj->Release();
+ }
+};
+
+// This can be used if your objects use AddReference/ReleaseReference function names.
+class CRefCountAccessorLongName
+{
+public:
+ template< class T >
+ static void AddRef( T *pObj )
+ {
+ pObj->AddReference();
+ }
+
+ template< class T >
+ static void Release( T *pObj )
+ {
+ pObj->ReleaseReference();
+ }
+};
+
+
+//
+// CPlainAutoPtr
+// is a smart wrapper for a pointer on the stack that performs "delete" upon destruction.
+//
+// No reference counting is performed, copying is prohibited "s_p2.Attach( s_p1.Detach() )" should be used
+// for readability and ease of maintenance.
+//
+// Auto pointer supports an "arrow" operator for invoking methods on the pointee and a "dereference" operator
+// for getting a pointee reference.
+//
+// No automatic casting to bool/ptrtype is performed to avoid bugs and problems (read on "safe bool idiom"
+// if casting to bool or pointer happens to be useful).
+//
+// Test for validity with "IsValid", get the pointer with "Get".
+//
+template < typename T >
+class CPlainAutoPtr
+{
+public:
+ explicit CPlainAutoPtr( T *p = NULL ) : m_p( p ) {}
+ ~CPlainAutoPtr( void ) { Delete(); }
+
+public:
+ void Delete( void ) { delete Detach(); }
+
+private: // Disallow copying, use Detach() instead to avoid ambiguity
+ CPlainAutoPtr( CPlainAutoPtr const &x );
+ CPlainAutoPtr & operator = ( CPlainAutoPtr const &x );
+
+public:
+ void Attach( T *p ) { m_p = p; }
+ T * Detach( void ) { T * p( m_p ); m_p = NULL; return p; }
+
+public:
+ bool IsValid( void ) const { return m_p != NULL; }
+ T * Get( void ) const { return m_p; }
+ T * operator -> ( void ) const { return Get(); }
+ T & operator * ( void ) const { return *Get(); }
+
+private:
+ T * m_p;
+};
+
+//
+// CArrayAutoPtr
+// is a smart wrapper for an array pointer on the stack that performs "delete []" upon destruction.
+//
+// No reference counting is performed, copying is prohibited "s_p2.Attach( s_p1.Detach() )" should be used
+// for readability and ease of maintenance.
+//
+// Auto pointer supports an "indexing" operator for accessing array elements.
+//
+// No automatic casting to bool/ptrtype is performed to avoid bugs and problems (read on "safe bool idiom"
+// if casting to bool or pointer happens to be useful).
+//
+// Test for validity with "IsValid", get the array pointer with "Get".
+//
+template < typename T >
+class CArrayAutoPtr : public CPlainAutoPtr < T > // Warning: no polymorphic destructor (delete on base class will be a mistake)
+{
+public:
+ explicit CArrayAutoPtr( T *p = NULL ) { this->Attach( p ); }
+ ~CArrayAutoPtr( void ) { this->Delete(); }
+
+public:
+ void Delete( void ) { delete [] CPlainAutoPtr < T >::Detach(); }
+
+public:
+ T & operator [] ( int k ) const { return CPlainAutoPtr < T >::Get()[ k ]; }
+};
+
+
+// Smart pointers can be used to automatically free an object when nobody points
+// at it anymore. Things contained in smart pointers must implement AddRef and Release
+// functions. If those functions are private, then the class must make
+// CRefCountAccessor a friend.
+template<class T, class RefCountAccessor=CRefCountAccessor>
+class CSmartPtr
+{
+public:
+ CSmartPtr();
+ CSmartPtr( T *pObj );
+ CSmartPtr( const CSmartPtr<T,RefCountAccessor> &other );
+ ~CSmartPtr();
+
+ T* operator=( T *pObj );
+ void operator=( const CSmartPtr<T,RefCountAccessor> &other );
+ const T* operator->() const;
+ T* operator->();
+ bool operator!() const;
+ bool operator==( const T *pOther ) const;
+ bool IsValid() const; // Tells if the pointer is valid.
+ T* GetObject() const; // Get temporary object pointer, don't store it for later reuse!
+ void MarkDeleted();
+
+private:
+ T *m_pObj;
+};
+
+
+template< class T, class RefCountAccessor >
+inline CSmartPtr<T,RefCountAccessor>::CSmartPtr()
+{
+ m_pObj = NULL;
+}
+
+template< class T, class RefCountAccessor >
+inline CSmartPtr<T,RefCountAccessor>::CSmartPtr( T *pObj )
+{
+ m_pObj = NULL;
+ *this = pObj;
+}
+
+template< class T, class RefCountAccessor >
+inline CSmartPtr<T,RefCountAccessor>::CSmartPtr( const CSmartPtr<T,RefCountAccessor> &other )
+{
+ m_pObj = NULL;
+ *this = other;
+}
+
+template< class T, class RefCountAccessor >
+inline CSmartPtr<T,RefCountAccessor>::~CSmartPtr()
+{
+ if ( m_pObj )
+ {
+ RefCountAccessor::Release( m_pObj );
+ }
+}
+
+template< class T, class RefCountAccessor >
+inline T* CSmartPtr<T,RefCountAccessor>::operator=( T *pObj )
+{
+ if ( pObj == m_pObj )
+ return pObj;
+
+ if ( pObj )
+ {
+ RefCountAccessor::AddRef( pObj );
+ }
+ if ( m_pObj )
+ {
+ RefCountAccessor::Release( m_pObj );
+ }
+ m_pObj = pObj;
+ return pObj;
+}
+
+template< class T, class RefCountAccessor >
+inline void CSmartPtr<T,RefCountAccessor>::MarkDeleted()
+{
+ m_pObj = NULL;
+}
+
+template< class T, class RefCountAccessor >
+inline void CSmartPtr<T,RefCountAccessor>::operator=( const CSmartPtr<T,RefCountAccessor> &other )
+{
+ *this = other.m_pObj;
+}
+
+template< class T, class RefCountAccessor >
+inline const T* CSmartPtr<T,RefCountAccessor>::operator->() const
+{
+ return m_pObj;
+}
+
+template< class T, class RefCountAccessor >
+inline T* CSmartPtr<T,RefCountAccessor>::operator->()
+{
+ return m_pObj;
+}
+
+template< class T, class RefCountAccessor >
+inline bool CSmartPtr<T,RefCountAccessor>::operator!() const
+{
+ return !m_pObj;
+}
+
+template< class T, class RefCountAccessor >
+inline bool CSmartPtr<T,RefCountAccessor>::operator==( const T *pOther ) const
+{
+ return m_pObj == pOther;
+}
+
+template< class T, class RefCountAccessor >
+inline bool CSmartPtr<T,RefCountAccessor>::IsValid() const
+{
+ return m_pObj != NULL;
+}
+
+template< class T, class RefCountAccessor >
+inline T* CSmartPtr<T,RefCountAccessor>::GetObject() const
+{
+ return m_pObj;
+}
+
+
+//
+// CAutoPushPop
+// allows you to set value of a variable upon construction and destruction.
+// Constructors:
+// CAutoPushPop x( myvar )
+// saves the value and restores upon destruction.
+// CAutoPushPop x( myvar, newvalue )
+// saves the value, assigns new value upon construction, restores saved value upon destruction.
+// CAutoPushPop x( myvar, newvalue, restorevalue )
+// assigns new value upon construction, assignes restorevalue upon destruction.
+//
+template < typename T >
+class CAutoPushPop
+{
+public:
+ explicit CAutoPushPop( T& var ) : m_rVar( var ), m_valPop( var ) {}
+ CAutoPushPop( T& var, T const &valPush ) : m_rVar( var ), m_valPop( var ) { m_rVar = valPush; }
+ CAutoPushPop( T& var, T const &valPush, T const &valPop ) : m_rVar( var ), m_valPop( var ) { m_rVar = valPush; }
+
+ ~CAutoPushPop() { m_rVar = m_valPop; }
+
+private: // forbid copying
+ CAutoPushPop( CAutoPushPop const &x );
+ CAutoPushPop & operator = ( CAutoPushPop const &x );
+
+public:
+ T & Get() { return m_rVar; }
+
+private:
+ T &m_rVar;
+ T m_valPop;
+};
+
+
+#endif // SMARTPTR_H
diff --git a/public/tier1/snappy-sinksource.h b/public/tier1/snappy-sinksource.h
new file mode 100644
index 0000000..faabfa1
--- /dev/null
+++ b/public/tier1/snappy-sinksource.h
@@ -0,0 +1,137 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_
+#define UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_
+
+#include <stddef.h>
+
+
+namespace snappy {
+
+// A Sink is an interface that consumes a sequence of bytes.
+class Sink {
+ public:
+ Sink() { }
+ virtual ~Sink();
+
+ // Append "bytes[0,n-1]" to this.
+ virtual void Append(const char* bytes, size_t n) = 0;
+
+ // Returns a writable buffer of the specified length for appending.
+ // May return a pointer to the caller-owned scratch buffer which
+ // must have at least the indicated length. The returned buffer is
+ // only valid until the next operation on this Sink.
+ //
+ // After writing at most "length" bytes, call Append() with the
+ // pointer returned from this function and the number of bytes
+ // written. Many Append() implementations will avoid copying
+ // bytes if this function returned an internal buffer.
+ //
+ // If a non-scratch buffer is returned, the caller may only pass a
+ // prefix of it to Append(). That is, it is not correct to pass an
+ // interior pointer of the returned array to Append().
+ //
+ // The default implementation always returns the scratch buffer.
+ virtual char* GetAppendBuffer(size_t length, char* scratch);
+
+
+ private:
+ // No copying
+ Sink(const Sink&);
+ void operator=(const Sink&);
+};
+
+// A Source is an interface that yields a sequence of bytes
+class Source {
+ public:
+ Source() { }
+ virtual ~Source();
+
+ // Return the number of bytes left to read from the source
+ virtual size_t Available() const = 0;
+
+ // Peek at the next flat region of the source. Does not reposition
+ // the source. The returned region is empty iff Available()==0.
+ //
+ // Returns a pointer to the beginning of the region and store its
+ // length in *len.
+ //
+ // The returned region is valid until the next call to Skip() or
+ // until this object is destroyed, whichever occurs first.
+ //
+ // The returned region may be larger than Available() (for example
+ // if this ByteSource is a view on a substring of a larger source).
+ // The caller is responsible for ensuring that it only reads the
+ // Available() bytes.
+ virtual const char* Peek(size_t* len) = 0;
+
+ // Skip the next n bytes. Invalidates any buffer returned by
+ // a previous call to Peek().
+ // REQUIRES: Available() >= n
+ virtual void Skip(size_t n) = 0;
+
+ private:
+ // No copying
+ Source(const Source&);
+ void operator=(const Source&);
+};
+
+// A Source implementation that yields the contents of a flat array
+class ByteArraySource : public Source {
+ public:
+ ByteArraySource(const char* p, size_t n) : ptr_(p), left_(n) { }
+ virtual ~ByteArraySource();
+ virtual size_t Available() const;
+ virtual const char* Peek(size_t* len);
+ virtual void Skip(size_t n);
+ private:
+ const char* ptr_;
+ size_t left_;
+};
+
+// A Sink implementation that writes to a flat array without any bound checks.
+class UncheckedByteArraySink : public Sink {
+ public:
+ explicit UncheckedByteArraySink(char* dest) : dest_(dest) { }
+ virtual ~UncheckedByteArraySink();
+ virtual void Append(const char* data, size_t n);
+ virtual char* GetAppendBuffer(size_t len, char* scratch);
+
+ // Return the current output pointer so that a caller can see how
+ // many bytes were produced.
+ // Note: this is not a Sink method.
+ char* CurrentDestination() const { return dest_; }
+ private:
+ char* dest_;
+};
+
+
+}
+
+#endif // UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_
diff --git a/public/tier1/snappy-stubs-public.h b/public/tier1/snappy-stubs-public.h
new file mode 100644
index 0000000..6b41bbe
--- /dev/null
+++ b/public/tier1/snappy-stubs-public.h
@@ -0,0 +1,98 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+// Author: [email protected] (Steinar H. Gunderson)
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Various type stubs for the open-source version of Snappy.
+//
+// This file cannot include config.h, as it is included from snappy.h,
+// which is a public header. Instead, snappy-stubs-public.h is generated by
+// from snappy-stubs-public.h.in at configure time.
+
+#ifndef UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_
+#define UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_
+
+#if 1
+#include <stdint.h>
+#endif
+
+#if 1
+#include <stddef.h>
+#endif
+
+#if 0
+#include <sys/uio.h>
+#endif
+
+#define SNAPPY_MAJOR 1
+#define SNAPPY_MINOR 1
+#define SNAPPY_PATCHLEVEL 2
+#define SNAPPY_VERSION \
+ ((SNAPPY_MAJOR << 16) | (SNAPPY_MINOR << 8) | SNAPPY_PATCHLEVEL)
+
+#include <string>
+
+namespace snappy {
+
+#if 1
+typedef int8_t int8;
+typedef uint8_t uint8;
+typedef int16_t int16;
+typedef uint16_t uint16;
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef int64_t int64;
+typedef uint64_t uint64;
+#else
+typedef signed char int8;
+typedef unsigned char uint8;
+typedef short int16;
+typedef unsigned short uint16;
+typedef int int32;
+typedef unsigned int uint32;
+typedef long long int64;
+typedef unsigned long long uint64;
+#endif
+
+typedef std::string string;
+
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+
+#if !0
+// Windows does not have an iovec type, yet the concept is universally useful.
+// It is simple to define it ourselves, so we put it inside our own namespace.
+struct iovec {
+ void* iov_base;
+ size_t iov_len;
+};
+#endif
+
+} // namespace snappy
+
+#endif // UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_
diff --git a/public/tier1/snappy.h b/public/tier1/snappy.h
new file mode 100644
index 0000000..fbb1af7
--- /dev/null
+++ b/public/tier1/snappy.h
@@ -0,0 +1,191 @@
+// Copyright 2005 and onwards Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// A light-weight compression algorithm. It is designed for speed of
+// compression and decompression, rather than for the utmost in space
+// savings.
+//
+// For getting better compression ratios when you are compressing data
+// with long repeated sequences or compressing data that is similar to
+// other data, while still compressing fast, you might look at first
+// using BMDiff and then compressing the output of BMDiff with
+// Snappy.
+
+#ifndef UTIL_SNAPPY_SNAPPY_H__
+#define UTIL_SNAPPY_SNAPPY_H__
+
+// [email protected]: Added this kludge. We really need to stop #defining this in our code.
+#undef min
+#undef max
+
+#include <stddef.h>
+#ifdef _WIN32
+#pragma warning(disable:4530) // warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
+#endif //_WIN32
+#include <string>
+
+#include "snappy-stubs-public.h"
+
+namespace snappy {
+ class Source;
+ class Sink;
+
+ // ------------------------------------------------------------------------
+ // Generic compression/decompression routines.
+ // ------------------------------------------------------------------------
+
+ // Compress the bytes read from "*source" and append to "*sink". Return the
+ // number of bytes written.
+ size_t Compress(Source* source, Sink* sink);
+
+ // Find the uncompressed length of the given stream, as given by the header.
+ // Note that the true length could deviate from this; the stream could e.g.
+ // be truncated.
+ //
+ // Also note that this leaves "*source" in a state that is unsuitable for
+ // further operations, such as RawUncompress(). You will need to rewind
+ // or recreate the source yourself before attempting any further calls.
+ bool GetUncompressedLength(Source* source, uint32* result);
+
+ // ------------------------------------------------------------------------
+ // Higher-level string based routines (should be sufficient for most users)
+ // ------------------------------------------------------------------------
+
+ // Sets "*output" to the compressed version of "input[0,input_length-1]".
+ // Original contents of *output are lost.
+ //
+ // REQUIRES: "input[]" is not an alias of "*output".
+ size_t Compress(const char* input, size_t input_length, std::string* output);
+
+ // Decompresses "compressed[0,compressed_length-1]" to "*uncompressed".
+ // Original contents of "*uncompressed" are lost.
+ //
+ // REQUIRES: "compressed[]" is not an alias of "*uncompressed".
+ //
+ // returns false if the message is corrupted and could not be decompressed
+ bool Uncompress(const char* compressed, size_t compressed_length,
+ std::string* uncompressed);
+
+
+ // ------------------------------------------------------------------------
+ // Lower-level character array based routines. May be useful for
+ // efficiency reasons in certain circumstances.
+ // ------------------------------------------------------------------------
+
+ // REQUIRES: "compressed" must point to an area of memory that is at
+ // least "MaxCompressedLength(input_length)" bytes in length.
+ //
+ // Takes the data stored in "input[0..input_length]" and stores
+ // it in the array pointed to by "compressed".
+ //
+ // "*compressed_length" is set to the length of the compressed output.
+ //
+ // Example:
+ // char* output = new char[snappy::MaxCompressedLength(input_length)];
+ // size_t output_length;
+ // RawCompress(input, input_length, output, &output_length);
+ // ... Process(output, output_length) ...
+ // delete [] output;
+ void RawCompress(const char* input,
+ size_t input_length,
+ char* compressed,
+ size_t* compressed_length);
+
+ // Given data in "compressed[0..compressed_length-1]" generated by
+ // calling the Snappy::Compress routine, this routine
+ // stores the uncompressed data to
+ // uncompressed[0..GetUncompressedLength(compressed)-1]
+ // returns false if the message is corrupted and could not be decrypted
+ bool RawUncompress(const char* compressed, size_t compressed_length,
+ char* uncompressed);
+
+ // Given data from the byte source 'compressed' generated by calling
+ // the Snappy::Compress routine, this routine stores the uncompressed
+ // data to
+ // uncompressed[0..GetUncompressedLength(compressed,compressed_length)-1]
+ // returns false if the message is corrupted and could not be decrypted
+ bool RawUncompress(Source* compressed, char* uncompressed);
+
+ // Given data in "compressed[0..compressed_length-1]" generated by
+ // calling the Snappy::Compress routine, this routine
+ // stores the uncompressed data to the iovec "iov". The number of physical
+ // buffers in "iov" is given by iov_cnt and their cumulative size
+ // must be at least GetUncompressedLength(compressed). The individual buffers
+ // in "iov" must not overlap with each other.
+ //
+ // returns false if the message is corrupted and could not be decrypted
+ bool RawUncompressToIOVec(const char* compressed, size_t compressed_length,
+ const struct iovec* iov, size_t iov_cnt);
+
+ // Given data from the byte source 'compressed' generated by calling
+ // the Snappy::Compress routine, this routine stores the uncompressed
+ // data to the iovec "iov". The number of physical
+ // buffers in "iov" is given by iov_cnt and their cumulative size
+ // must be at least GetUncompressedLength(compressed). The individual buffers
+ // in "iov" must not overlap with each other.
+ //
+ // returns false if the message is corrupted and could not be decrypted
+ bool RawUncompressToIOVec(Source* compressed, const struct iovec* iov,
+ size_t iov_cnt);
+
+ // Returns the maximal size of the compressed representation of
+ // input data that is "source_bytes" bytes in length;
+ size_t MaxCompressedLength(size_t source_bytes);
+
+ // REQUIRES: "compressed[]" was produced by RawCompress() or Compress()
+ // Returns true and stores the length of the uncompressed data in
+ // *result normally. Returns false on parsing error.
+ // This operation takes O(1) time.
+ bool GetUncompressedLength(const char* compressed, size_t compressed_length,
+ size_t* result);
+
+ // Returns true iff the contents of "compressed[]" can be uncompressed
+ // successfully. Does not return the uncompressed data. Takes
+ // time proportional to compressed_length, but is usually at least
+ // a factor of four faster than actual decompression.
+ bool IsValidCompressedBuffer(const char* compressed,
+ size_t compressed_length);
+
+ // The size of a compression block. Note that many parts of the compression
+ // code assumes that kBlockSize <= 65536; in particular, the hash table
+ // can only store 16-bit offsets, and EmitCopy() also assumes the offset
+ // is 65535 bytes or less. Note also that if you change this, it will
+ // affect the framing format (see framing_format.txt).
+ //
+ // Note that there might be older data around that is compressed with larger
+ // block sizes, so the decompression code should not rely on the
+ // non-existence of long backreferences.
+ static const int kBlockLog = 16;
+ static const size_t kBlockSize = 1 << kBlockLog;
+
+ static const int kMaxHashTableBits = 14;
+ static const size_t kMaxHashTableSize = 1 << kMaxHashTableBits;
+} // end namespace snappy
+
+
+#endif // UTIL_SNAPPY_SNAPPY_H__
diff --git a/public/tier1/sparsematrix.h b/public/tier1/sparsematrix.h
new file mode 100644
index 0000000..d882e5f
--- /dev/null
+++ b/public/tier1/sparsematrix.h
@@ -0,0 +1,123 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// A class allowing storage of a sparse NxN matirx as an array of sparse rows
+//===========================================================================//
+
+#ifndef SPARSEMATRIX_H
+#define SPARSEMATRIX_H
+
+#include "tier1/utlvector.h"
+
+/// CSparseMatrix is a matrix which compresses each row individually, not storing the zeros. NOte,
+/// that while you can randomly set any element in a CSparseMatrix, you really want to do it top to
+/// bottom or you will have bad perf as data is moved around to insert new elements.
+class CSparseMatrix
+{
+public:
+ struct NonZeroValueDescriptor_t
+ {
+ int m_nColumnNumber;
+ float m_flValue;
+ };
+
+ struct RowDescriptor_t
+ {
+ int m_nNonZeroCount; // number of non-zero elements in the row
+ int m_nDataIndex; // index of NonZeroValueDescriptor_t for the first non-zero value
+ };
+
+ int m_nNumRows;
+ int m_nNumCols;
+ CUtlVector<RowDescriptor_t> m_rowDescriptors;
+ CUtlVector<NonZeroValueDescriptor_t> m_entries;
+ int m_nHighestRowAppendedTo;
+
+ void AdjustAllRowIndicesAfter( int nStartRow, int nDelta );
+public:
+ FORCEINLINE float Element( int nRow, int nCol ) const;
+ void SetElement( int nRow, int nCol, float flValue );
+ void SetDimensions( int nNumRows, int nNumCols );
+ void AppendElement( int nRow, int nCol, float flValue );
+ void FinishedAppending( void );
+
+ FORCEINLINE int Height( void ) const { return m_nNumRows; }
+ FORCEINLINE int Width( void ) const { return m_nNumCols; }
+
+};
+
+
+
+FORCEINLINE float CSparseMatrix::Element( int nRow, int nCol ) const
+{
+ Assert( nCol < m_nNumCols );
+ int nCount = m_rowDescriptors[nRow].m_nNonZeroCount;
+ if ( nCount )
+ {
+ NonZeroValueDescriptor_t const *pValue = &(m_entries[m_rowDescriptors[nRow].m_nDataIndex]);
+ do
+ {
+ int nIdx = pValue->m_nColumnNumber;
+ if ( nIdx == nCol )
+ {
+ return pValue->m_flValue;
+ }
+ if ( nIdx > nCol )
+ {
+ break;
+ }
+ pValue++;
+ } while( --nCount );
+ }
+ return 0;
+}
+
+
+
+// type-specific overrides of matrixmath template for special case sparse routines
+
+namespace MatrixMath
+{
+ /// sparse * dense matrix x matrix multiplication
+ template<class BTYPE, class OUTTYPE>
+ void MatrixMultiply( CSparseMatrix const &matA, BTYPE const &matB, OUTTYPE *pMatrixOut )
+ {
+ Assert( matA.Width() == matB.Height() );
+ pMatrixOut->SetDimensions( matA.Height(), matB.Width() );
+ for( int i = 0; i < matA.Height(); i++ )
+ {
+ for( int j = 0; j < matB.Width(); j++ )
+ {
+ // compute inner product efficiently because of sparsity
+ int nCnt = matA.m_rowDescriptors[i].m_nNonZeroCount;
+ int nDataIdx = matA.m_rowDescriptors[i].m_nDataIndex;
+ float flDot = 0.0;
+ for( int nIdx = 0; nIdx < nCnt; nIdx++ )
+ {
+ float flAValue = matA.m_entries[nIdx + nDataIdx].m_flValue;
+ int nCol = matA.m_entries[nIdx + nDataIdx].m_nColumnNumber;
+ flDot += flAValue * matB.Element( nCol, j );
+ }
+ pMatrixOut->SetElement( i, j, flDot );
+ }
+ }
+ }
+
+ FORCEINLINE void AppendElement( CSparseMatrix &matrix, int nRow, int nCol, float flValue )
+ {
+ matrix.AppendElement( nRow, nCol, flValue ); // default implementation
+ }
+
+ FORCEINLINE void FinishedAppending( CSparseMatrix &matrix )
+ {
+ matrix.FinishedAppending();
+ }
+
+};
+
+
+
+
+
+#endif // SPARSEMATRIX_H
diff --git a/public/tier1/stringpool.h b/public/tier1/stringpool.h
new file mode 100644
index 0000000..6b1dfae
--- /dev/null
+++ b/public/tier1/stringpool.h
@@ -0,0 +1,91 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef STRINGPOOL_H
+#define STRINGPOOL_H
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+
+#include "utlrbtree.h"
+#include "utlvector.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Allocates memory for strings, checking for duplicates first,
+// reusing exising strings if duplicate found.
+//-----------------------------------------------------------------------------
+
+class CStringPool
+{
+public:
+ CStringPool();
+ ~CStringPool();
+
+ unsigned int Count() const;
+
+ const char * Allocate( const char *pszValue );
+ void FreeAll();
+
+ // searches for a string already in the pool
+ const char * Find( const char *pszValue );
+
+protected:
+ typedef CUtlRBTree<const char *, unsigned short> CStrSet;
+
+ CStrSet m_Strings;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: A reference counted string pool.
+//
+// Elements are stored more efficiently than in the conventional string pool,
+// quicker to look up, and storage is tracked via reference counts.
+//
+// At some point this should replace CStringPool
+//-----------------------------------------------------------------------------
+class CCountedStringPool
+{
+public: // HACK, hash_item_t structure should not be public.
+
+ struct hash_item_t
+ {
+ char* pString;
+ unsigned short nNextElement;
+ unsigned char nReferenceCount;
+ unsigned char pad;
+ };
+
+ enum
+ {
+ INVALID_ELEMENT = 0,
+ MAX_REFERENCE = 0xFF,
+ HASH_TABLE_SIZE = 1024
+ };
+
+ CUtlVector<unsigned short> m_HashTable; // Points to each element
+ CUtlVector<hash_item_t> m_Elements;
+ unsigned short m_FreeListStart;
+
+public:
+ CCountedStringPool();
+ virtual ~CCountedStringPool();
+
+ void FreeAll();
+
+ char *FindString( const char* pIntrinsic );
+ char *ReferenceString( const char* pIntrinsic );
+ void DereferenceString( const char* pIntrinsic );
+
+ // These are only reliable if there are less than 64k strings in your string pool
+ unsigned short FindStringHandle( const char* pIntrinsic );
+ unsigned short ReferenceStringHandle( const char* pIntrinsic );
+ char *HandleToString( unsigned short handle );
+ void SpewStrings();
+};
+
+#endif // STRINGPOOL_H
diff --git a/public/tier1/strtools.h b/public/tier1/strtools.h
new file mode 100644
index 0000000..e94d9ce
--- /dev/null
+++ b/public/tier1/strtools.h
@@ -0,0 +1,1285 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef TIER1_STRTOOLS_H
+#define TIER1_STRTOOLS_H
+
+#include "tier0/platform.h"
+
+#include <ctype.h>
+#include <stdarg.h>
+#ifdef _WIN32
+#pragma once
+#elif POSIX
+#include <wchar.h>
+#include <math.h>
+#include <wctype.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+class CUtlBuffer;
+class CUtlString;
+
+#ifdef _WIN64
+#define str_size unsigned int
+#else
+#define str_size size_t
+#endif
+
+template< class T, class I > class CUtlMemory;
+template< class T, class A > class CUtlVector;
+
+
+//-----------------------------------------------------------------------------
+// Portable versions of standard string functions
+//-----------------------------------------------------------------------------
+void _V_memset ( const char* file, int line, void *dest, int fill, int count );
+void _V_memcpy ( const char* file, int line, void *dest, const void *src, int count );
+void _V_memmove ( const char* file, int line, void *dest, const void *src, int count );
+int _V_memcmp ( const char* file, int line, const void *m1, const void *m2, int count );
+int _V_strlen ( const char* file, int line, const char *str );
+void _V_strcpy ( const char* file, int line, char *dest, const char *src );
+char* _V_strrchr ( const char* file, int line, const char *s, char c );
+int _V_strcmp ( const char* file, int line, const char *s1, const char *s2 );
+int _V_wcscmp ( const char* file, int line, const wchar_t *s1, const wchar_t *s2 );
+char* _V_strstr ( const char* file, int line, const char *s1, const char *search );
+int _V_wcslen ( const char* file, int line, const wchar_t *pwch );
+wchar_t* _V_wcslower (const char* file, int line, wchar_t *start);
+wchar_t* _V_wcsupr (const char* file, int line, wchar_t *start);
+
+// ASCII-optimized functions which fall back to CRT only when necessary
+char *V_strupr( char *start );
+char *V_strlower( char *start );
+int V_stricmp( const char *s1, const char *s2 );
+int V_strncmp( const char *s1, const char *s2, int count );
+int V_strnicmp( const char *s1, const char *s2, int n );
+
+//-----------------------------------------------------------------------------
+// Purpose: Slightly modified strtok. Does not modify the input string. Does
+// not skip over more than one separator at a time. This allows parsing
+// strings where tokens between separators may or may not be present:
+//
+// Door01,,,0 would be parsed as "Door01" "" "" "0"
+// Door01,Open,,0 would be parsed as "Door01" "Open" "" "0"
+//
+// Input : token - Returns with a token, or zero length if the token was missing.
+// str - String to parse.
+// sep - Character to use as separator. UNDONE: allow multiple separator chars
+// Output : Returns a pointer to the next token to be parsed.
+//-----------------------------------------------------------------------------
+const char *nexttoken(char *token, size_t nMaxTokenLen, const char *str, char sep);
+template <size_t maxLenInChars> inline const char *nexttoken( OUT_Z_ARRAY char (&pToken)[maxLenInChars], const char *str, char sep)
+{
+ return nexttoken( pToken, maxLenInChars, str, sep );
+}
+
+
+#ifdef POSIX
+
+inline char *strupr( char *start )
+{
+ return V_strupr( start );
+}
+
+inline char *strlwr( char *start )
+{
+ return V_strlower( start );
+}
+
+inline wchar_t *_wcslwr( wchar_t *start )
+{
+ wchar_t *str = start;
+ while( str && *str )
+ {
+ *str = (wchar_t)towlower(static_cast<wint_t>(*str));
+ str++;
+ }
+ return start;
+};
+
+inline wchar_t *_wcsupr( wchar_t *start )
+{
+ wchar_t *str = start;
+ while( str && *str )
+ {
+ *str = (wchar_t)towupper(static_cast<wint_t>(*str));
+ str++;
+ }
+ return start;
+};
+
+#endif // POSIX
+
+
+#ifdef _DEBUG
+
+#define V_memset(dest, fill, count) _V_memset (__FILE__, __LINE__, (dest), (fill), (count))
+#define V_memcpy(dest, src, count) _V_memcpy (__FILE__, __LINE__, (dest), (src), (count))
+#define V_memmove(dest, src, count) _V_memmove (__FILE__, __LINE__, (dest), (src), (count))
+#define V_memcmp(m1, m2, count) _V_memcmp (__FILE__, __LINE__, (m1), (m2), (count))
+#define V_strlen(str) _V_strlen (__FILE__, __LINE__, (str))
+#define V_strcpy(dest, src) _V_strcpy (__FILE__, __LINE__, (dest), (src))
+#define V_strrchr(s, c) _V_strrchr (__FILE__, __LINE__, (s), (c))
+#define V_strcmp(s1, s2) _V_strcmp (__FILE__, __LINE__, (s1), (s2))
+#define V_wcscmp(s1, s2) _V_wcscmp (__FILE__, __LINE__, (s1), (s2))
+#define V_strstr(s1, search ) _V_strstr (__FILE__, __LINE__, (s1), (search) )
+#define V_wcslen(pwch) _V_wcslen (__FILE__, __LINE__, (pwch))
+#define V_wcslower(start) _V_wcslower (__FILE__, __LINE__, (start))
+#define V_wcsupr(start) _V_wcsupr (__FILE__, __LINE__, (start))
+
+#else
+
+
+inline void V_memset (void *dest, int fill, int count) { memset( dest, fill, count ); }
+inline void V_memcpy (void *dest, const void *src, int count) { memcpy( dest, src, count ); }
+inline void V_memmove (void *dest, const void *src, int count) { memmove( dest, src, count ); }
+inline int V_memcmp (const void *m1, const void *m2, int count){ return memcmp( m1, m2, count ); }
+inline int V_strlen (const char *str) { return (int) strlen ( str ); }
+inline void V_strcpy (char *dest, const char *src) { strcpy( dest, src ); }
+inline int V_wcslen(const wchar_t *pwch) { return (int)wcslen(pwch); }
+inline char* V_strrchr (const char *s, char c) { return (char*)strrchr( s, c ); }
+inline int V_strcmp (const char *s1, const char *s2) { return strcmp( s1, s2 ); }
+inline int V_wcscmp (const wchar_t *s1, const wchar_t *s2) { return wcscmp( s1, s2 ); }
+inline char* V_strstr( const char *s1, const char *search ) { return (char*)strstr( s1, search ); }
+inline wchar_t* V_wcslower (wchar_t *start) { return _wcslwr( start ); }
+inline wchar_t* V_wcsupr (wchar_t *start) { return _wcsupr( start ); }
+
+#endif
+
+int V_atoi (const char *str);
+int64 V_atoi64(const char *str);
+uint64 V_atoui64(const char *str);
+int64 V_strtoi64( const char *nptr, char **endptr, int base );
+uint64 V_strtoui64( const char *nptr, char **endptr, int base );
+float V_atof(const char *str);
+char* V_stristr( char* pStr, const char* pSearch );
+const char* V_stristr( const char* pStr, const char* pSearch );
+const char* V_strnistr( const char* pStr, const char* pSearch, int n );
+const char* V_strnchr( const char* pStr, char c, int n );
+inline int V_strcasecmp (const char *s1, const char *s2) { return V_stricmp(s1, s2); }
+inline int V_strncasecmp (const char *s1, const char *s2, int n) { return V_strnicmp(s1, s2, n); }
+void V_qsort_s( void *base, size_t num, size_t width, int ( __cdecl *compare )(void *, const void *,
+const void *), void *context );
+
+
+// returns string immediately following prefix, (ie str+strlen(prefix)) or NULL if prefix not found
+const char *StringAfterPrefix ( const char *str, const char *prefix );
+const char *StringAfterPrefixCaseSensitive( const char *str, const char *prefix );
+inline bool StringHasPrefix ( const char *str, const char *prefix ) { return StringAfterPrefix ( str, prefix ) != NULL; }
+inline bool StringHasPrefixCaseSensitive( const char *str, const char *prefix ) { return StringAfterPrefixCaseSensitive( str, prefix ) != NULL; }
+
+
+template< bool CASE_SENSITIVE > inline bool _V_strEndsWithInner( const char *pStr, const char *pSuffix )
+{
+ int nSuffixLen = V_strlen( pSuffix );
+ int nStringLen = V_strlen( pStr );
+ if ( nSuffixLen == 0 )
+ return true; // All strings end with the empty string (matches Java & .NET behaviour)
+ if ( nStringLen < nSuffixLen )
+ return false;
+ pStr += nStringLen - nSuffixLen;
+ if ( CASE_SENSITIVE )
+ return !V_strcmp( pStr, pSuffix );
+ else
+ return !V_stricmp( pStr, pSuffix );
+}
+
+// Does 'pStr' end with 'pSuffix'? (case sensitive/insensitive variants)
+inline bool V_strEndsWith( const char *pStr, const char *pSuffix ) { return _V_strEndsWithInner<TRUE>( pStr, pSuffix ); }
+inline bool V_striEndsWith( const char *pStr, const char *pSuffix ) { return _V_strEndsWithInner<FALSE>( pStr, pSuffix ); }
+
+
+// Normalizes a float string in place.
+// (removes leading zeros, trailing zeros after the decimal point, and the decimal point itself where possible)
+void V_normalizeFloatString( char* pFloat );
+
+// this is locale-unaware and therefore faster version of standard isdigit()
+// It also avoids sign-extension errors.
+inline bool V_isdigit( char c )
+{
+ return c >= '0' && c <= '9';
+}
+
+inline bool V_iswdigit( int c )
+{
+ return ( ( (uint)( c - '0' ) ) < 10 );
+}
+
+inline bool V_isempty( const char* pszString ) { return !pszString || !pszString[ 0 ]; }
+
+// The islower/isdigit/etc. functions all expect a parameter that is either
+// 0-0xFF or EOF. It is easy to violate this constraint simply by passing
+// 'char' to these functions instead of unsigned char.
+// The V_ functions handle the char/unsigned char mismatch by taking a
+// char parameter and casting it to unsigned char so that chars with the
+// sign bit set will be zero extended instead of sign extended.
+// Not that EOF cannot be passed to these functions.
+//
+// These functions could also be used for optimizations if locale
+// considerations make some of the CRT functions slow.
+//#undef isdigit // In case this is implemented as a macro
+//#define isdigit use_V_isdigit_instead_of_isdigit
+inline bool V_isalpha(char c) { return isalpha( (unsigned char)c ) != 0; }
+//#undef isalpha
+//#define isalpha use_V_isalpha_instead_of_isalpha
+inline bool V_isalnum(char c) { return isalnum( (unsigned char)c ) != 0; }
+//#undef isalnum
+//#define isalnum use_V_isalnum_instead_of_isalnum
+inline bool V_isprint(char c) { return isprint( (unsigned char)c ) != 0; }
+//#undef isprint
+//#define isprint use_V_isprint_instead_of_isprint
+inline bool V_isxdigit(char c) { return isxdigit( (unsigned char)c ) != 0; }
+//#undef isxdigit
+//#define isxdigit use_V_isxdigit_instead_of_isxdigit
+inline bool V_ispunct(char c) { return ispunct( (unsigned char)c ) != 0; }
+//#undef ispunct
+//#define ispunct use_V_ispunct_instead_of_ispunct
+inline bool V_isgraph(char c) { return isgraph( (unsigned char)c ) != 0; }
+//#undef isgraph
+//#define isgraph use_V_isgraph_instead_of_isgraph
+inline bool V_isupper(char c) { return isupper( (unsigned char)c ) != 0; }
+//#undef isupper
+//#define isupper use_V_isupper_instead_of_isupper
+inline bool V_islower(char c) { return islower( (unsigned char)c ) != 0; }
+//#undef islower
+//#define islower use_V_islower_instead_of_islower
+inline bool V_iscntrl(char c) { return iscntrl( (unsigned char)c ) != 0; }
+//#undef iscntrl
+//#define iscntrl use_V_iscntrl_instead_of_iscntrl
+inline bool V_isspace(char c) { return isspace( (unsigned char)c ) != 0; }
+//#undef isspace
+//#define isspace use_V_isspace_instead_of_isspace
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if it's a valid hex string
+//-----------------------------------------------------------------------------
+inline bool V_isvalidhex( char const *in, int inputchars )
+{
+ if ( inputchars < 2 )
+ return false;
+ if ( inputchars % 2 == 1 )
+ return false;
+
+ for ( int i = 0; i < inputchars; i++ )
+ {
+ char c = in[i];
+ if ( !(
+ (c >= '0' && c <= '9') ||
+ (c >= 'a' && c <= 'f') ||
+ (c >= 'A' && c <= 'F')
+ ) )
+ {
+ return false;
+ }
+
+ }
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks if the string is lower case
+// NOTE: Only works with ASCII strings
+//-----------------------------------------------------------------------------
+inline bool V_isstrlower( const char *pch )
+{
+ const char *pCurrent = pch;
+ while ( *pCurrent != '\0' )
+ {
+ if ( *pCurrent >= 'A' && *pCurrent <= 'Z' )
+ return false;
+
+ pCurrent++;
+ }
+
+ return true;
+}
+
+
+
+// These are versions of functions that guarantee NULL termination.
+//
+// maxLen is the maximum number of bytes in the destination string.
+// pDest[maxLen-1] is always NULL terminated if pSrc's length is >= maxLen.
+//
+// This means the last parameter can usually be a sizeof() of a string.
+void V_strncpy( OUT_Z_CAP(maxLenInChars) char *pDest, const char *pSrc, int maxLenInChars );
+
+// Ultimate safe strcpy function, for arrays only -- buffer size is inferred by the compiler
+template <size_t maxLenInChars> void V_strcpy_safe( OUT_Z_ARRAY char (&pDest)[maxLenInChars], const char *pSrc )
+{
+ V_strncpy( pDest, pSrc, (int)maxLenInChars );
+}
+
+// A function which duplicates a string using new[] to allocate the new string.
+inline char *V_strdup( const char *pSrc )
+{
+ int nLen = V_strlen( pSrc );
+ char *pResult = new char [ nLen+1 ];
+ V_memcpy( pResult, pSrc, nLen+1 );
+ return pResult;
+}
+
+void V_wcsncpy( OUT_Z_BYTECAP(maxLenInBytes) wchar_t *pDest, wchar_t const *pSrc, int maxLenInBytes );
+template <size_t maxLenInChars> void V_wcscpy_safe( OUT_Z_ARRAY wchar_t (&pDest)[maxLenInChars], wchar_t const *pSrc )
+{
+ V_wcsncpy( pDest, pSrc, maxLenInChars * sizeof(*pDest) );
+}
+
+#define COPY_ALL_CHARACTERS -1
+char *V_strncat( INOUT_Z_CAP(cchDest) char *pDest, const char *pSrc, size_t cchDest, int max_chars_to_copy=COPY_ALL_CHARACTERS );
+template <size_t cchDest> char *V_strcat_safe( INOUT_Z_ARRAY char (&pDest)[cchDest], const char *pSrc, int nMaxCharsToCopy=COPY_ALL_CHARACTERS )
+{
+ return V_strncat( pDest, pSrc, (int)cchDest, nMaxCharsToCopy );
+}
+
+wchar_t *V_wcsncat( INOUT_Z_CAP(cchDest) wchar_t *pDest, const wchar_t *pSrc, size_t cchDest, int nMaxCharsToCopy=COPY_ALL_CHARACTERS );
+template <size_t cchDest> wchar_t *V_wcscat_safe( INOUT_Z_ARRAY wchar_t (&pDest)[cchDest], const wchar_t *pSrc, int nMaxCharsToCopy=COPY_ALL_CHARACTERS )
+{
+ return V_wcsncat( pDest, pSrc, (int)cchDest, nMaxCharsToCopy );
+}
+
+char *V_strnlwr( INOUT_Z_CAP(cchBuf) char *pBuf, size_t cchBuf);
+template <size_t cchDest> char *V_strlwr_safe( INOUT_Z_ARRAY char (&pBuf)[cchDest] )
+{
+ return _V_strnlwr( pBuf, (int)cchDest );
+}
+
+// Unicode string conversion policies - what to do if an illegal sequence is encountered
+enum EStringConvertErrorPolicy
+{
+ _STRINGCONVERTFLAG_SKIP = 1,
+ _STRINGCONVERTFLAG_FAIL = 2,
+ _STRINGCONVERTFLAG_ASSERT = 4,
+
+ STRINGCONVERT_REPLACE = 0,
+ STRINGCONVERT_SKIP = _STRINGCONVERTFLAG_SKIP,
+ STRINGCONVERT_FAIL = _STRINGCONVERTFLAG_FAIL,
+
+ STRINGCONVERT_ASSERT_REPLACE = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_REPLACE,
+ STRINGCONVERT_ASSERT_SKIP = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_SKIP,
+ STRINGCONVERT_ASSERT_FAIL = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_FAIL,
+};
+
+// Unicode (UTF-8, UTF-16, UTF-32) fundamental conversion functions.
+bool Q_IsValidUChar32( uchar32 uValue );
+int Q_UChar32ToUTF8Len( uchar32 uValue );
+int Q_UChar32ToUTF8( uchar32 uValue, char *pOut );
+int Q_UChar32ToUTF16Len( uchar32 uValue );
+int Q_UChar32ToUTF16( uchar32 uValue, uchar16 *pOut );
+
+// Validate that a Unicode string is well-formed and contains only valid code points
+bool Q_UnicodeValidate( const char *pUTF8 );
+bool Q_UnicodeValidate( const uchar16 *pUTF16 );
+bool Q_UnicodeValidate( const uchar32 *pUTF32 );
+
+// Returns length of string in Unicode code points (printed glyphs or non-printing characters)
+int Q_UnicodeLength( const char *pUTF8 );
+int Q_UnicodeLength( const uchar16 *pUTF16 );
+int Q_UnicodeLength( const uchar32 *pUTF32 );
+
+// Returns length of string in elements, not characters! These are analogous to Q_strlen and Q_wcslen
+inline int Q_strlen16( const uchar16 *puc16 ) { int nElems = 0; while ( puc16[nElems] ) ++nElems; return nElems; }
+inline int Q_strlen32( const uchar32 *puc32 ) { int nElems = 0; while ( puc32[nElems] ) ++nElems; return nElems; }
+
+
+// Repair invalid Unicode strings by dropping truncated characters and fixing improperly-double-encoded UTF-16 sequences.
+// Unlike conversion functions which replace with '?' by default, a repair operation assumes that you know that something
+// is wrong with the string (eg, mid-sequence truncation) and you just want to do the best possible job of cleaning it up.
+// You can pass a REPLACE or FAIL policy if you would prefer to replace characters with '?' or clear the entire string.
+// Returns nonzero on success, or 0 if the policy is FAIL and an invalid sequence was found.
+int Q_UnicodeRepair( char *pUTF8, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_SKIP );
+int Q_UnicodeRepair( uchar16 *pUTF16, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_SKIP );
+int Q_UnicodeRepair( uchar32 *pUTF32, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_SKIP );
+
+// Advance pointer forward by N Unicode code points (printed glyphs or non-printing characters), stopping at terminating null if encountered.
+char *Q_UnicodeAdvance( char *pUTF8, int nCharacters );
+uchar16 *Q_UnicodeAdvance( uchar16 *pUTF16, int nCharactersnCharacters );
+uchar32 *Q_UnicodeAdvance( uchar32 *pUTF32, int nChars );
+inline const char *Q_UnicodeAdvance( const char *pUTF8, int nCharacters ) { return Q_UnicodeAdvance( (char*) pUTF8, nCharacters ); }
+inline const uchar16 *Q_UnicodeAdvance( const uchar16 *pUTF16, int nCharacters ) { return Q_UnicodeAdvance( (uchar16*) pUTF16, nCharacters ); }
+inline const uchar32 *Q_UnicodeAdvance( const uchar32 *pUTF32, int nCharacters ) { return Q_UnicodeAdvance( (uchar32*) pUTF32, nCharacters ); }
+
+// Truncate to maximum of N Unicode code points (printed glyphs or non-printing characters)
+inline void Q_UnicodeTruncate( char *pUTF8, int nCharacters ) { *Q_UnicodeAdvance( pUTF8, nCharacters ) = 0; }
+inline void Q_UnicodeTruncate( uchar16 *pUTF16, int nCharacters ) { *Q_UnicodeAdvance( pUTF16, nCharacters ) = 0; }
+inline void Q_UnicodeTruncate( uchar32 *pUTF32, int nCharacters ) { *Q_UnicodeAdvance( pUTF32, nCharacters ) = 0; }
+
+
+// Conversion between Unicode string types (UTF-8, UTF-16, UTF-32). Deals with bytes, not element counts,
+// to minimize harm from the programmer mistakes which continue to plague our wide-character string code.
+// Returns the number of bytes written to the output, or if output is NULL, the number of bytes required.
+int Q_UTF8ToUTF16( const char *pUTF8, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE );
+int Q_UTF8ToUTF32( const char *pUTF8, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE );
+int Q_UTF16ToUTF8( const uchar16 *pUTF16, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE );
+int Q_UTF16ToUTF32( const uchar16 *pUTF16, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE );
+int Q_UTF32ToUTF8( const uchar32 *pUTF32, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE );
+int Q_UTF32ToUTF16( const uchar32 *pUTF32, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE );
+
+// This is disgusting and exist only easily to facilitate having 16-bit and 32-bit wchar_t's on different platforms
+int Q_UTF32ToUTF32( const uchar32 *pUTF32Source, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32Dest, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE );
+
+// Conversion between count-limited UTF-n character arrays, including any potential NULL characters.
+// Output has a terminating NULL for safety; strip the last character if you want an unterminated string.
+// Returns the number of bytes written to the output, or if output is NULL, the number of bytes required.
+int Q_UTF8CharsToUTF16( const char *pUTF8, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE );
+int Q_UTF8CharsToUTF32( const char *pUTF8, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE );
+int Q_UTF16CharsToUTF8( const uchar16 *pUTF16, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE );
+int Q_UTF16CharsToUTF32( const uchar16 *pUTF16, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE );
+int Q_UTF32CharsToUTF8( const uchar32 *pUTF32, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE );
+int Q_UTF32CharsToUTF16( const uchar32 *pUTF32, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE );
+
+// Decode a single UTF-8 character to a uchar32, returns number of UTF-8 bytes parsed
+int Q_UTF8ToUChar32( const char *pUTF8_, uchar32 &uValueOut, bool &bErrorOut );
+
+// Decode a single UTF-16 character to a uchar32, returns number of UTF-16 characters (NOT BYTES) consumed
+int Q_UTF16ToUChar32( const uchar16 *pUTF16, uchar32 &uValueOut, bool &bErrorOut );
+
+
+// NOTE: WString means either UTF32 or UTF16 depending on the platform and compiler settings.
+#if defined( _MSC_VER ) || defined( _WIN32 )
+#define Q_UTF8ToWString Q_UTF8ToUTF16
+#define Q_UTF8CharsToWString Q_UTF8CharsToUTF16
+#define Q_UTF32ToWString Q_UTF32ToUTF16
+#define Q_WStringToUTF8 Q_UTF16ToUTF8
+#define Q_WStringCharsToUTF8 Q_UTF16CharsToUTF8
+#define Q_WStringToUTF32 Q_UTF16ToUTF32
+#else
+#define Q_UTF8ToWString Q_UTF8ToUTF32
+#define Q_UTF8CharsToWString Q_UTF8CharsToUTF32
+#define Q_UTF32ToWString Q_UTF32ToUTF32
+#define Q_WStringToUTF8 Q_UTF32ToUTF8
+#define Q_WStringCharsToUTF8 Q_UTF32CharsToUTF8
+#define Q_WStringToUTF32 Q_UTF32ToUTF32
+#endif
+
+// These are legacy names which don't make a lot of sense but are used everywhere. Prefer the WString convention wherever possible
+#define V_UTF8ToUnicode Q_UTF8ToWString
+#define V_UnicodeToUTF8 Q_WStringToUTF8
+
+
+#ifdef WIN32
+// This function is ill-defined as it relies on the current ANSI code page. Currently Win32 only for tools.
+int Q_LocaleSpecificANSIToUTF8( const char *pANSI, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes );
+#endif
+
+// Windows-1252 is mostly the same as ISO Latin-1, and probably what you want if you are
+// saddled with an 8-bit ANSI string that originated on a Windows system.
+int Q_Windows1252CharsToUTF8( const char *pchSrc, int cchSrc, OUT_Z_BYTECAP(cchDestUTF8) char *pchDestUTF8, int cchDestUTF8 );
+
+// CP 437 is used for VGA console text and some old-school file formats such as ZIP. It
+// is also known as the "IBM PC OEM code page" and various related names. You probably
+// don't want to use this function unless you know for a fact that you're dealing with
+// old-school OEM code pages. Otherwise try the Windows-1252 function above.
+int Q_CP437CharsToUTF8( const char *pchSrc, int cchSrc, OUT_Z_BYTECAP(cchDestUTF8) char *pchDestUTF8, int cchDestUTF8 );
+
+// replaces characters in a UTF8 string with their identical-looking equivalent (non-roundtrippable)
+//
+// older version of API uses a small homoglyph table; newer version uses a larger one
+//
+// strings using old version are baked into the database, so we won't toss it quite yet,
+// but don't use it for new features.
+int Q_NormalizeUTF8Old( const char *pchSrc, OUT_Z_CAP(cchDest) char *pchDest, int cchDest );
+int Q_NormalizeUTF8( const char *pchSrc, OUT_Z_CAP(cchDest) char *pchDest, int cchDest );
+
+//-----------------------------------------------------------------------------
+// Purpose: replaces characters in a UTF8 string with similar-looking equivalents.
+// Only replaces with ASCII characters.. non-recognized characters will be replaced with ?
+// This operation is destructive (i.e. you can't roundtrip through the normalized
+// form).
+//-----------------------------------------------------------------------------
+template <size_t maxLenInChars> int Q_NormalizeUTF8ToASCII( OUT_Z_ARRAY char (&pchDest)[maxLenInChars], const char *pchSrc )
+{
+ int nResult = Q_NormalizeUTF8( pchSrc, pchDest, maxLenInChars );
+
+ // replace non ASCII characters with ?
+ for ( int i = 0; i < nResult; i++ )
+ {
+ if ( pchDest[i] > 127 || pchDest[i] < 0 )
+ {
+ pchDest[i] = '?';
+ }
+ }
+
+ return nResult;
+}
+
+// UNDONE: Find a non-compiler-specific way to do this
+#ifdef _WIN32
+#ifndef _VA_LIST_DEFINED
+
+#ifdef _M_ALPHA
+
+struct va_list
+{
+ char *a0; /* pointer to first homed integer argument */
+ int offset; /* byte offset of next parameter */
+};
+
+#else // !_M_ALPHA
+
+typedef char * va_list;
+
+#endif // !_M_ALPHA
+
+#define _VA_LIST_DEFINED
+
+#endif // _VA_LIST_DEFINED
+
+#elif POSIX
+#include <stdarg.h>
+#endif
+
+#ifdef _WIN32
+#define CORRECT_PATH_SEPARATOR '\\'
+#define CORRECT_PATH_SEPARATOR_S "\\"
+#define INCORRECT_PATH_SEPARATOR '/'
+#define INCORRECT_PATH_SEPARATOR_S "/"
+#elif POSIX
+#define CORRECT_PATH_SEPARATOR '/'
+#define CORRECT_PATH_SEPARATOR_S "/"
+#define INCORRECT_PATH_SEPARATOR '\\'
+#define INCORRECT_PATH_SEPARATOR_S "\\"
+#endif
+
+int V_vsnprintf( OUT_Z_CAP(maxLenInCharacters) char *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const char *pFormat, va_list params );
+template <size_t maxLenInCharacters> int V_vsprintf_safe( OUT_Z_ARRAY char (&pDest)[maxLenInCharacters], PRINTF_FORMAT_STRING const char *pFormat, va_list params ) { return V_vsnprintf( pDest, maxLenInCharacters, pFormat, params ); }
+
+int V_snprintf( OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars, PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 3, 4 );
+// gcc insists on only having format annotations on declarations, not definitions, which is why I have both.
+template <size_t maxLenInChars> int V_sprintf_safe( OUT_Z_ARRAY char (&pDest)[maxLenInChars], PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 2, 3 );
+template <size_t maxLenInChars> int V_sprintf_safe( OUT_Z_ARRAY char (&pDest)[maxLenInChars], PRINTF_FORMAT_STRING const char *pFormat, ... )
+{
+ va_list params;
+ va_start( params, pFormat );
+ int result = V_vsnprintf( pDest, maxLenInChars, pFormat, params );
+ va_end( params );
+ return result;
+}
+
+// gcc insists on only having format annotations on declarations, not definitions, which is why I have both.
+// Append formatted text to an array in a safe manner -- always null-terminated, truncation rather than buffer overrun.
+template <size_t maxLenInChars> int V_sprintfcat_safe( INOUT_Z_ARRAY char (&pDest)[maxLenInChars], PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 2, 3 );
+template <size_t maxLenInChars> int V_sprintfcat_safe( INOUT_Z_ARRAY char (&pDest)[maxLenInChars], PRINTF_FORMAT_STRING const char *pFormat, ... )
+{
+ va_list params;
+ va_start( params, pFormat );
+ size_t usedLength = V_strlen(pDest);
+ // This code is here to check against buffer overruns when uninitialized arrays are passed in.
+ // It should never be executed. Unfortunately we can't assert in this header file.
+ if ( usedLength >= maxLenInChars )
+ usedLength = 0;
+ int result = V_vsnprintf( pDest + usedLength, maxLenInChars - usedLength, pFormat, params );
+ va_end( params );
+ return result;
+}
+
+int V_vsnwprintf( OUT_Z_CAP(maxLenInCharacters) wchar_t *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const wchar_t *pFormat, va_list params );
+template <size_t maxLenInCharacters> int V_vswprintf_safe( OUT_Z_ARRAY wchar_t (&pDest)[maxLenInCharacters], PRINTF_FORMAT_STRING const wchar_t *pFormat, va_list params ) { return V_vsnwprintf( pDest, maxLenInCharacters, pFormat, params ); }
+int V_vsnprintfRet( OUT_Z_CAP(maxLenInCharacters) char *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const char *pFormat, va_list params, bool *pbTruncated );
+template <size_t maxLenInCharacters> int V_vsprintfRet_safe( OUT_Z_ARRAY char (&pDest)[maxLenInCharacters], PRINTF_FORMAT_STRING const char *pFormat, va_list params, bool *pbTruncated ) { return V_vsnprintfRet( pDest, maxLenInCharacters, pFormat, params, pbTruncated ); }
+
+// FMTFUNCTION can only be used on ASCII functions, not wide-char functions.
+int V_snwprintf( OUT_Z_CAP(maxLenInCharacters) wchar_t *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const wchar_t *pFormat, ... );
+template <size_t maxLenInChars> int V_swprintf_safe( OUT_Z_ARRAY wchar_t (&pDest)[maxLenInChars], PRINTF_FORMAT_STRING const wchar_t *pFormat, ... )
+{
+ va_list params;
+ va_start( params, pFormat );
+ int result = V_vsnwprintf( pDest, maxLenInChars, pFormat, params );
+ va_end( params );
+ return result;
+}
+
+// Prints out a pretified memory counter string value ( e.g., 7,233.27 Mb, 1,298.003 Kb, 127 bytes )
+char *V_pretifymem( float value, int digitsafterdecimal = 2, bool usebinaryonek = false );
+
+// Prints out a pretified integer with comma separators (eg, 7,233,270,000)
+char *V_pretifynum( int64 value );
+
+int _V_UCS2ToUnicode( const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) wchar_t *pUnicode, int cubDestSizeInBytes );
+template< typename T > inline int V_UCS2ToUnicode( const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) wchar_t *pUnicode, T cubDestSizeInBytes )
+{
+ return _V_UCS2ToUnicode( pUCS2, pUnicode, static_cast<int>(cubDestSizeInBytes) );
+}
+
+int _V_UCS2ToUTF8( const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes );
+template< typename T > inline int V_UCS2ToUTF8( const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, T cubDestSizeInBytes )
+{
+ return _V_UCS2ToUTF8( pUCS2, pUTF8, static_cast<int>(cubDestSizeInBytes) );
+}
+
+int _V_UnicodeToUCS2( const wchar_t *pUnicode, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUCS2, int cubDestSizeInBytes );
+template< typename T, typename U > inline int V_UnicodeToUCS2( const wchar_t *pUnicode, T cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUCS2, U cubDestSizeInBytes )
+{
+ return _V_UnicodeToUCS2( pUnicode, static_cast<int>(cubSrcInBytes), pUCS2, static_cast<int>(cubDestSizeInBytes) );
+}
+
+int _V_UTF8ToUCS2( const char *pUTF8, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) ucs2 *pUCS2, int cubDestSizeInBytes );
+template< typename T, typename U > inline int V_UTF8ToUCS2( const char *pUTF8, T cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) ucs2 *pUCS2, U cubDestSizeInBytes )
+{
+ return _V_UTF8ToUCS2( pUTF8, static_cast<int>(cubSrcInBytes), pUCS2, static_cast<int>(cubDestSizeInBytes) );
+}
+
+// strips leading and trailing whitespace; returns true if any characters were removed. UTF-8 and UTF-16 versions.
+bool Q_StripPrecedingAndTrailingWhitespace( char *pch );
+bool Q_StripPrecedingAndTrailingWhitespaceW( wchar_t *pwch );
+
+// strips leading and trailing whitespace, also taking "aggressive" characters
+// like punctuation spaces, non-breaking spaces, composing characters, and so on
+bool Q_AggressiveStripPrecedingAndTrailingWhitespace( char *pch );
+bool Q_AggressiveStripPrecedingAndTrailingWhitespaceW( wchar_t *pwch );
+bool Q_RemoveAllEvilCharacters( char *pch );
+
+// Functions for converting hexidecimal character strings back into binary data etc.
+//
+// e.g.,
+// int output;
+// V_hextobinary( "ffffffff", 8, &output, sizeof( output ) );
+// would make output == 0xfffffff or -1
+// Similarly,
+// char buffer[ 9 ];
+// V_binarytohex( &output, sizeof( output ), buffer, sizeof( buffer ) );
+// would put "ffffffff" into buffer (note null terminator!!!)
+unsigned char V_nibble( char c );
+void V_hextobinary( char const *in, int numchars, byte *out, int maxoutputbytes );
+void V_binarytohex( const byte *in, int inputbytes, char *out, int outsize );
+
+// Tools for working with filenames
+// Extracts the base name of a file (no path, no extension, assumes '/' or '\' as path separator)
+void V_FileBase( const char *in, char *out,int maxlen );
+// Remove the final characters of ppath if it's '\' or '/'.
+void V_StripTrailingSlash( char *ppath );
+
+// Remove the final characters of ppline if they are whitespace (uses V_isspace)
+void V_StripTrailingWhitespace( char *ppline );
+
+// Remove the initial characters of ppline if they are whitespace (uses V_isspace)
+void V_StripLeadingWhitespace( char *ppline );
+
+// Remove the initial/final characters of ppline if they are " quotes
+void V_StripSurroundingQuotes( char *ppline );
+
+// Remove any extension from in and return resulting string in out
+void V_StripExtension( const char *in, char *out, int outLen );
+// Make path end with extension if it doesn't already have an extension
+void V_DefaultExtension( char *path, const char *extension, int pathStringLength );
+// Strips any current extension from path and ensures that extension is the new extension
+void V_SetExtension( char *path, const char *extension, int pathStringLength );
+// Removes any filename from path ( strips back to previous / or \ character )
+void V_StripFilename( char *path );
+// Remove the final directory from the path
+bool V_StripLastDir( char *dirName, int maxlen );
+// Returns a pointer to the unqualified file name (no path) of a file name
+const char * V_UnqualifiedFileName( const char * in );
+// Given a path and a filename, composes "path\filename", inserting the (OS correct) separator if necessary
+void V_ComposeFileName( const char *path, const char *filename, char *dest, int destSize );
+
+// Copy out the path except for the stuff after the final pathseparator
+bool V_ExtractFilePath( const char *path, char *dest, int destSize );
+// Copy out the file extension into dest
+void V_ExtractFileExtension( const char *path, char *dest, int destSize );
+
+const char *V_GetFileExtension( const char * path );
+
+// returns a pointer to just the filename part of the path
+// (everything after the last path seperator)
+const char *V_GetFileName( const char * path );
+
+// This removes "./" and "../" from the pathname. pFilename should be a full pathname.
+// Also incorporates the behavior of V_FixSlashes and optionally V_FixDoubleSlashes.
+// Returns false if it tries to ".." past the root directory in the drive (in which case
+// it is an invalid path).
+bool V_RemoveDotSlashes( char *pFilename, char separator = CORRECT_PATH_SEPARATOR, bool bRemoveDoubleSlashes = true );
+
+// If pPath is a relative path, this function makes it into an absolute path
+// using the current working directory as the base, or pStartingDir if it's non-NULL.
+// Returns false if it runs out of room in the string, or if pPath tries to ".." past the root directory.
+void V_MakeAbsolutePath( char *pOut, int outLen, const char *pPath, const char *pStartingDir = NULL );
+inline void V_MakeAbsolutePath( char *pOut, int outLen, const char *pPath, const char *pStartingDir, bool bLowercaseName )
+{
+ V_MakeAbsolutePath( pOut, outLen, pPath, pStartingDir );
+ if ( bLowercaseName )
+ {
+ V_strlower( pOut );
+ }
+}
+
+
+// Creates a relative path given two full paths
+// The first is the full path of the file to make a relative path for.
+// The second is the full path of the directory to make the first file relative to
+// Returns false if they can't be made relative (on separate drives, for example)
+bool V_MakeRelativePath( const char *pFullPath, const char *pDirectory, char *pRelativePath, int nBufLen );
+
+// Fixes up a file name, removing dot slashes, fixing slashes, converting to lowercase, etc.
+void V_FixupPathName( OUT_Z_CAP(nOutLen) char *pOut, size_t nOutLen, const char *pPath );
+
+// Adds a path separator to the end of the string if there isn't one already. Returns false if it would run out of space.
+void V_AppendSlash( INOUT_Z_CAP(strSize) char *pStr, int strSize );
+
+// Returns true if the path is an absolute path.
+bool V_IsAbsolutePath( IN_Z const char *pPath );
+
+// Scans pIn and replaces all occurences of pMatch with pReplaceWith.
+// Writes the result to pOut.
+// Returns true if it completed successfully.
+// If it would overflow pOut, it fills as much as it can and returns false.
+bool V_StrSubst( IN_Z const char *pIn, IN_Z const char *pMatch, const char *pReplaceWith,
+ OUT_Z_CAP(outLen) char *pOut, int outLen, bool bCaseSensitive=false );
+
+// Split the specified string on the specified separator.
+// Returns a list of strings separated by pSeparator.
+// You are responsible for freeing the contents of outStrings (call outStrings.PurgeAndDeleteElements).
+void V_SplitString( IN_Z const char *pString, IN_Z const char *pSeparator, CUtlVector<char*, CUtlMemory<char*, int> > &outStrings );
+
+void V_SplitString( const char *pString, const char *pSeparator, CUtlVector< CUtlString, CUtlMemory<CUtlString, int> > &outStrings, bool bIncludeEmptyStrings = false );
+
+// Just like V_SplitString, but it can use multiple possible separators.
+void V_SplitString2( IN_Z const char *pString, const char **pSeparators, int nSeparators, CUtlVector<char*, CUtlMemory<char*, int> > &outStrings );
+
+// Returns false if the buffer is not large enough to hold the working directory name.
+bool V_GetCurrentDirectory( OUT_Z_CAP(maxLen) char *pOut, int maxLen );
+
+// Set the working directory thus.
+bool V_SetCurrentDirectory( const char *pDirName );
+
+
+// This function takes a slice out of pStr and stores it in pOut.
+// It follows the Python slice convention:
+// Negative numbers wrap around the string (-1 references the last character).
+// Large numbers are clamped to the end of the string.
+void V_StrSlice( const char *pStr, int firstChar, int lastCharNonInclusive, OUT_Z_CAP(outSize) char *pOut, int outSize );
+
+// Chop off the left nChars of a string.
+void V_StrLeft( const char *pStr, int nChars, OUT_Z_CAP(outSize) char *pOut, int outSize );
+
+// Chop off the right nChars of a string.
+void V_StrRight( const char *pStr, int nChars, OUT_Z_CAP(outSize) char *pOut, int outSize );
+
+// change "special" characters to have their c-style backslash sequence. like \n, \r, \t, ", etc.
+// returns a pointer to a newly allocated string, which you must delete[] when finished with.
+char *V_AddBackSlashesToSpecialChars( char const *pSrc );
+
+// Force slashes of either type to be = separator character
+void V_FixSlashes( char *pname, char separator = CORRECT_PATH_SEPARATOR );
+
+// This function fixes cases of filenames like materials\\blah.vmt or somepath\otherpath\\ and removes the extra double slash.
+void V_FixDoubleSlashes( char *pStr );
+
+// Convert multibyte to wchar + back
+// Specify -1 for nInSize for null-terminated string
+void V_strtowcs( const char *pString, int nInSize, OUT_Z_BYTECAP(nOutSizeInBytes) wchar_t *pWString, int nOutSizeInBytes );
+void V_wcstostr( const wchar_t *pWString, int nInSize, OUT_Z_CAP(nOutSizeInBytes) char *pString, int nOutSizeInBytes );
+
+// buffer-safe strcat
+inline void V_strcat( INOUT_Z_CAP(cchDest) char *dest, const char *src, int cchDest )
+{
+ V_strncat( dest, src, cchDest, COPY_ALL_CHARACTERS );
+}
+
+// Buffer safe wcscat
+inline void V_wcscat( INOUT_Z_CAP(cchDest) wchar_t *dest, const wchar_t *src, int cchDest )
+{
+ V_wcsncat( dest, src, cchDest, COPY_ALL_CHARACTERS );
+}
+
+// Encode a string for display as HTML -- this only encodes ' " & < >, which are the important ones to encode for
+// security and ensuring HTML display doesn't break. Other special chars like the ? sign and so forth will not
+// be encoded
+//
+// Returns false if there was not enough room in pDest to encode the entire source string, otherwise true
+bool V_BasicHtmlEntityEncode( OUT_Z_CAP( nDestSize ) char *pDest, const int nDestSize, char const *pIn, const int nInSize, bool bPreserveWhitespace = false );
+
+// Decode a string with htmlentities HTML -- this should handle all special chars, not just the ones Q_BasicHtmlEntityEncode uses.
+//
+// Returns false if there was not enough room in pDest to decode the entire source string, otherwise true
+bool V_HtmlEntityDecodeToUTF8( OUT_Z_CAP( nDestSize ) char *pDest, const int nDestSize, char const *pIn, const int nInSize );
+
+// strips HTML from a string. Should call Q_HTMLEntityDecodeToUTF8 afterward.
+void V_StripAndPreserveHTML( CUtlBuffer *pbuffer, const char *pchHTML, const char **rgszPreserveTags, uint cPreserveTags, uint cMaxResultSize );
+void V_StripAndPreserveHTMLCore( CUtlBuffer *pbuffer, const char *pchHTML, const char **rgszPreserveTags, uint cPreserveTags, const char **rgszNoCloseTags, uint cNoCloseTags, uint cMaxResultSize );
+
+// Extracts the domain from a URL
+bool V_ExtractDomainFromURL( const char *pchURL, OUT_Z_CAP( cchDomain ) char *pchDomain, int cchDomain );
+
+// returns true if the url passed in is on the specified domain
+bool V_URLContainsDomain( const char *pchURL, const char *pchDomain );
+
+//-----------------------------------------------------------------------------
+// returns true if the character is allowed in a URL, false otherwise
+//-----------------------------------------------------------------------------
+bool V_IsValidURLCharacter( const char *pch, int *pAdvanceBytes );
+
+//-----------------------------------------------------------------------------
+// returns true if the character is allowed in a DNS doman name, false otherwise
+//-----------------------------------------------------------------------------
+bool V_IsValidDomainNameCharacter( const char *pch, int *pAdvanceBytes );
+
+ // Converts BBCode tags to HTML tags
+bool V_BBCodeToHTML( OUT_Z_CAP( nDestSize ) char *pDest, const int nDestSize, char const *pIn, const int nInSize );
+
+
+// helper to identify "mean" spaces, which we don't like in visible identifiers
+// such as player Name
+bool V_IsMeanSpaceW( wchar_t wch );
+
+// helper to identify characters which are deprecated in Unicode,
+// and we simply don't accept
+bool V_IsDeprecatedW( wchar_t wch );
+
+//-----------------------------------------------------------------------------
+// generic unique name helper functions
+//-----------------------------------------------------------------------------
+
+// returns startindex if none found, 2 if "prefix" found, and n+1 if "prefixn" found
+template < class NameArray >
+int V_GenerateUniqueNameIndex( const char *prefix, const NameArray &nameArray, int startindex = 0 )
+{
+ if ( prefix == NULL )
+ return 0;
+
+ int freeindex = startindex;
+
+ int nNames = nameArray.Count();
+ for ( int i = 0; i < nNames; ++i )
+ {
+ const char *pName = nameArray[ i ];
+ if ( !pName )
+ continue;
+
+ const char *pIndexStr = StringAfterPrefix( pName, prefix );
+ if ( pIndexStr )
+ {
+ int index = *pIndexStr ? atoi( pIndexStr ) : 1;
+ if ( index >= freeindex )
+ {
+ // TODO - check that there isn't more junk after the index in pElementName
+ freeindex = index + 1;
+ }
+ }
+ }
+
+ return freeindex;
+}
+
+template < class NameArray >
+bool V_GenerateUniqueName( OUT_Z_CAP(memsize) char *name, int memsize, const char *prefix, const NameArray &nameArray )
+{
+ if ( name == NULL || memsize == 0 )
+ return false;
+
+ if ( prefix == NULL )
+ {
+ name[ 0 ] = '\0';
+ return false;
+ }
+
+ int prefixLength = V_strlen( prefix );
+ if ( prefixLength + 1 > memsize )
+ {
+ name[ 0 ] = '\0';
+ return false;
+ }
+
+ int i = V_GenerateUniqueNameIndex( prefix, nameArray );
+ if ( i <= 0 )
+ {
+ V_strncpy( name, prefix, memsize );
+ return true;
+ }
+
+ int newlen = prefixLength + ( int )log10( ( float )i ) + 1;
+ if ( newlen + 1 > memsize )
+ {
+ V_strncpy( name, prefix, memsize );
+ return false;
+ }
+
+ V_snprintf( name, memsize, "%s%d", prefix, i );
+ return true;
+}
+
+
+//
+// This utility class is for performing UTF-8 <-> UTF-16 conversion.
+// It is intended for use with function/method parameters.
+//
+// For example, you can call
+// FunctionTakingUTF16( CStrAutoEncode( utf8_string ).ToWString() )
+// or
+// FunctionTakingUTF8( CStrAutoEncode( utf16_string ).ToString() )
+//
+// The converted string is allocated off the heap, and destroyed when
+// the object goes out of scope.
+//
+// if the string cannot be converted, NULL is returned.
+//
+// This class doesn't have any conversion operators; the intention is
+// to encourage the developer to get used to having to think about which
+// encoding is desired.
+//
+class CStrAutoEncode
+{
+public:
+
+ // ctor
+ explicit CStrAutoEncode( const char *pch )
+ {
+ m_pch = pch;
+ m_pwch = NULL;
+#if !defined( WIN32 ) && !defined(_WIN32)
+ m_pucs2 = NULL;
+ m_bCreatedUCS2 = false;
+#endif
+ m_bCreatedUTF16 = false;
+ }
+
+ // ctor
+ explicit CStrAutoEncode( const wchar_t *pwch )
+ {
+ m_pch = NULL;
+ m_pwch = pwch;
+#if !defined( WIN32 ) && !defined(_WIN32)
+ m_pucs2 = NULL;
+ m_bCreatedUCS2 = false;
+#endif
+ m_bCreatedUTF16 = true;
+ }
+
+#if !defined(WIN32) && !defined(_WINDOWS) && !defined(_WIN32)
+ explicit CStrAutoEncode( const ucs2 *pwch )
+ {
+ m_pch = NULL;
+ m_pwch = NULL;
+ m_pucs2 = pwch;
+ m_bCreatedUCS2 = true;
+ m_bCreatedUTF16 = false;
+ }
+#endif
+
+ // returns the UTF-8 string, converting on the fly.
+ const char* ToString()
+ {
+ PopulateUTF8();
+ return m_pch;
+ }
+
+ // returns the UTF-8 string - a writable pointer.
+ // only use this if you don't want to call const_cast
+ // yourself. We need this for cases like CreateProcess.
+ char* ToStringWritable()
+ {
+ PopulateUTF8();
+ return const_cast< char* >( m_pch );
+ }
+
+ // returns the UTF-16 string, converting on the fly.
+ const wchar_t* ToWString()
+ {
+ PopulateUTF16();
+ return m_pwch;
+ }
+
+#if !defined( WIN32 ) && !defined(_WIN32)
+ // returns the UTF-16 string, converting on the fly.
+ const ucs2* ToUCS2String()
+ {
+ PopulateUCS2();
+ return m_pucs2;
+ }
+#endif
+
+ // returns the UTF-16 string - a writable pointer.
+ // only use this if you don't want to call const_cast
+ // yourself. We need this for cases like CreateProcess.
+ wchar_t* ToWStringWritable()
+ {
+ PopulateUTF16();
+ return const_cast< wchar_t* >( m_pwch );
+ }
+
+ // dtor
+ ~CStrAutoEncode()
+ {
+ // if we're "native unicode" then the UTF-8 string is something we allocated,
+ // and vice versa.
+ if ( m_bCreatedUTF16 )
+ {
+ delete [] m_pch;
+ }
+ else
+ {
+ delete [] m_pwch;
+ }
+#if !defined( WIN32 ) && !defined(_WIN32)
+ if ( !m_bCreatedUCS2 && m_pucs2 )
+ delete [] m_pucs2;
+#endif
+ }
+
+private:
+ // ensure we have done any conversion work required to farm out a
+ // UTF-8 encoded string.
+ //
+ // We perform two heap allocs here; the first one is the worst-case
+ // (four bytes per Unicode code point). This is usually quite pessimistic,
+ // so we perform a second allocation that's just the size we need.
+ void PopulateUTF8()
+ {
+ if ( !m_bCreatedUTF16 )
+ return; // no work to do
+ if ( m_pwch == NULL )
+ return; // don't have a UTF-16 string to convert
+ if ( m_pch != NULL )
+ return; // already been converted to UTF-8; no work to do
+
+ // each Unicode code point can expand to as many as four bytes in UTF-8; we
+ // also need to leave room for the terminating NUL.
+ uint32 cbMax = 4 * static_cast<uint32>( V_wcslen( m_pwch ) ) + 1;
+ char *pchTemp = new char[ cbMax ];
+ if ( V_UnicodeToUTF8( m_pwch, pchTemp, cbMax ) )
+ {
+ uint32 cchAlloc = static_cast<uint32>( V_strlen( pchTemp ) ) + 1;
+ char *pchHeap = new char[ cchAlloc ];
+ V_strncpy( pchHeap, pchTemp, cchAlloc );
+ delete [] pchTemp;
+ m_pch = pchHeap;
+ }
+ else
+ {
+ // do nothing, and leave the UTF-8 string NULL
+ delete [] pchTemp;
+ }
+ }
+
+ // ensure we have done any conversion work required to farm out a
+ // UTF-16 encoded string.
+ //
+ // We perform two heap allocs here; the first one is the worst-case
+ // (one code point per UTF-8 byte). This is sometimes pessimistic,
+ // so we perform a second allocation that's just the size we need.
+ void PopulateUTF16()
+ {
+ if ( m_bCreatedUTF16 )
+ return; // no work to do
+ if ( m_pch == NULL )
+ return; // no UTF-8 string to convert
+ if ( m_pwch != NULL )
+ return; // already been converted to UTF-16; no work to do
+
+ uint32 cchMax = static_cast<uint32>( V_strlen( m_pch ) ) + 1;
+ wchar_t *pwchTemp = new wchar_t[ cchMax ];
+ if ( V_UTF8ToUnicode( m_pch, pwchTemp, cchMax * sizeof( wchar_t ) ) )
+ {
+ uint32 cchAlloc = static_cast<uint32>( V_wcslen( pwchTemp ) ) + 1;
+ wchar_t *pwchHeap = new wchar_t[ cchAlloc ];
+ V_wcsncpy( pwchHeap, pwchTemp, cchAlloc * sizeof( wchar_t ) );
+ delete [] pwchTemp;
+ m_pwch = pwchHeap;
+ }
+ else
+ {
+ // do nothing, and leave the UTF-16 string NULL
+ delete [] pwchTemp;
+ }
+ }
+
+#if !defined( WIN32 ) && !defined(_WIN32)
+ // ensure we have done any conversion work required to farm out a
+ // UTF-16 encoded string.
+ //
+ // We perform two heap allocs here; the first one is the worst-case
+ // (one code point per UTF-8 byte). This is sometimes pessimistic,
+ // so we perform a second allocation that's just the size we need.
+ void PopulateUCS2()
+ {
+ if ( m_bCreatedUCS2 )
+ return;
+ if ( m_pch == NULL )
+ return; // no UTF-8 string to convert
+ if ( m_pucs2 != NULL )
+ return; // already been converted to UTF-16; no work to do
+
+ uint32 cchMax = static_cast<uint32>( V_strlen( m_pch ) ) + 1;
+ ucs2 *pwchTemp = new ucs2[ cchMax ];
+ if ( V_UTF8ToUCS2( m_pch, cchMax, pwchTemp, cchMax * sizeof( ucs2 ) ) )
+ {
+ uint32 cchAlloc = cchMax;
+ ucs2 *pwchHeap = new ucs2[ cchAlloc ];
+ memcpy( pwchHeap, pwchTemp, cchAlloc * sizeof( ucs2 ) );
+ delete [] pwchTemp;
+ m_pucs2 = pwchHeap;
+ }
+ else
+ {
+ // do nothing, and leave the UTF-16 string NULL
+ delete [] pwchTemp;
+ }
+ }
+#endif
+
+ // one of these pointers is an owned pointer; whichever
+ // one is the encoding OTHER than the one we were initialized
+ // with is the pointer we've allocated and must free.
+ const char *m_pch;
+ const wchar_t *m_pwch;
+#if !defined( WIN32 ) && !defined(_WIN32)
+ const ucs2 *m_pucs2;
+ bool m_bCreatedUCS2;
+#endif
+ // "created as UTF-16", means our owned string is the UTF-8 string not the UTF-16 one.
+ bool m_bCreatedUTF16;
+
+};
+
+// Encodes a string (or binary data) in URL encoding format, see rfc1738 section 2.2.
+// Dest buffer should be 3 times the size of source buffer to guarantee it has room to encode.
+void Q_URLEncodeRaw( OUT_Z_CAP(nDestLen) char *pchDest, int nDestLen, const char *pchSource, int nSourceLen );
+
+// Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
+// Dest buffer should be at least as large as source buffer to gurantee room for decode.
+// Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed.
+//
+// Returns the amount of space actually used in the output buffer.
+size_t Q_URLDecodeRaw( OUT_CAP(nDecodeDestLen) char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen );
+
+// trim right whitespace
+inline char* TrimRight( char *pString )
+{
+ char *pEnd = pString + V_strlen( pString );
+ // trim
+ while ( pString < ( pEnd-- ) )
+ {
+ if ( uint( *pEnd ) <= uint( ' ' ) )
+ {
+ *pEnd = '\0';
+ }
+ else
+ break;
+ }
+ return pString;
+}
+
+inline const char * SkipBlanks( const char *pString )
+{
+ const char *p = pString;
+ while ( *p && uint( *p ) <= uint( ' ' ) )
+ {
+ p++;
+ }
+ return p;
+}
+
+inline int V_strcspn( const char *s1, const char *search ) { return (int)( strcspn( s1, search ) ); }
+// Encodes a string (or binary data) in URL encoding format, this isn't the strict rfc1738 format, but instead uses + for spaces.
+// This is for historical reasons and HTML spec foolishness that lead to + becoming a de facto standard for spaces when encoding form data.
+// Dest buffer should be 3 times the size of source buffer to guarantee it has room to encode.
+void Q_URLEncode( OUT_Z_CAP(nDestLen) char *pchDest, int nDestLen, const char *pchSource, int nSourceLen );
+
+// Decodes a string (or binary data) in URL encoding format, this isn't the strict rfc1738 format, but instead uses + for spaces.
+// This is for historical reasons and HTML spec foolishness that lead to + becoming a de facto standard for spaces when encoding form data.
+// Dest buffer should be at least as large as source buffer to gurantee room for decode.
+// Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed.
+//
+// Returns the amount of space actually used in the output buffer.
+size_t Q_URLDecode( OUT_CAP(nDecodeDestLen) char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen );
+
+
+// NOTE: This is for backward compatability!
+// We need to DLL-export the Q methods in vstdlib but not link to them in other projects
+#if !defined( VSTDLIB_BACKWARD_COMPAT )
+
+#define Q_memset V_memset
+#define Q_memcpy V_memcpy
+#define Q_memmove V_memmove
+#define Q_memcmp V_memcmp
+#define Q_strlen V_strlen
+#define Q_strcpy V_strcpy
+#define Q_strrchr V_strrchr
+#define Q_strcmp V_strcmp
+#define Q_wcscmp V_wcscmp
+#define Q_stricmp V_stricmp
+#define Q_strstr V_strstr
+#define Q_strupr V_strupr
+#define Q_strlower V_strlower
+#define Q_wcslen V_wcslen
+#define Q_strncmp V_strncmp
+#define Q_strcasecmp V_strcasecmp
+#define Q_strncasecmp V_strncasecmp
+#define Q_strnicmp V_strnicmp
+#define Q_atoi V_atoi
+#define Q_atoi64 V_atoi64
+#define Q_atoui64 V_atoui64
+#define Q_atof V_atof
+#define Q_stristr V_stristr
+#define Q_strnistr V_strnistr
+#define Q_strnchr V_strnchr
+#define Q_normalizeFloatString V_normalizeFloatString
+#define Q_strncpy V_strncpy
+#define Q_snprintf V_snprintf
+#define Q_wcsncpy V_wcsncpy
+#define Q_strncat V_strncat
+#define Q_strnlwr V_strnlwr
+#define Q_vsnprintf V_vsnprintf
+#define Q_vsnprintfRet V_vsnprintfRet
+#define Q_pretifymem V_pretifymem
+#define Q_pretifynum V_pretifynum
+#define Q_UTF8ToUnicode V_UTF8ToUnicode
+#define Q_UnicodeToUTF8 V_UnicodeToUTF8
+#define Q_hextobinary V_hextobinary
+#define Q_binarytohex V_binarytohex
+#define Q_FileBase V_FileBase
+#define Q_StripTrailingSlash V_StripTrailingSlash
+#define Q_StripExtension V_StripExtension
+#define Q_DefaultExtension V_DefaultExtension
+#define Q_SetExtension V_SetExtension
+#define Q_StripFilename V_StripFilename
+#define Q_StripLastDir V_StripLastDir
+#define Q_UnqualifiedFileName V_UnqualifiedFileName
+#define Q_ComposeFileName V_ComposeFileName
+#define Q_ExtractFilePath V_ExtractFilePath
+#define Q_ExtractFileExtension V_ExtractFileExtension
+#define Q_GetFileExtension V_GetFileExtension
+#define Q_RemoveDotSlashes V_RemoveDotSlashes
+#define Q_MakeAbsolutePath V_MakeAbsolutePath
+#define Q_AppendSlash V_AppendSlash
+#define Q_IsAbsolutePath V_IsAbsolutePath
+#define Q_StrSubst V_StrSubst
+#define Q_SplitString V_SplitString
+#define Q_SplitString2 V_SplitString2
+#define Q_StrSlice V_StrSlice
+#define Q_StrLeft V_StrLeft
+#define Q_StrRight V_StrRight
+#define Q_FixSlashes V_FixSlashes
+#define Q_strtowcs V_strtowcs
+#define Q_wcstostr V_wcstostr
+#define Q_strcat V_strcat
+#define Q_GenerateUniqueNameIndex V_GenerateUniqueNameIndex
+#define Q_GenerateUniqueName V_GenerateUniqueName
+#define Q_MakeRelativePath V_MakeRelativePath
+#define Q_qsort_s V_qsort_s
+
+#endif // !defined( VSTDLIB_DLL_EXPORT )
+
+
+#ifdef POSIX
+#define FMT_WS L"%ls"
+#else
+#define FMT_WS L"%s"
+#endif
+
+
+
+// Strip white space at the beginning and end of a string
+int V_StrTrim( char *pStr );
+
+
+#endif // TIER1_STRTOOLS_H
diff --git a/public/tier1/thash.h b/public/tier1/thash.h
new file mode 100644
index 0000000..5102074
--- /dev/null
+++ b/public/tier1/thash.h
@@ -0,0 +1,698 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef THASH_H
+#define THASH_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <typeinfo>
+
+//#define DBGFLAG_THASH // Perform extra sanity checks on the THash
+
+
+// THash
+// This is a heavyweight, templatized version of DHash.
+// It differs from DHash in the following ways:
+// - It's templetized, and automatically constructs and destructs its records as appropriate
+// - It provides a scheduling service, which can be used to touch every record in the table
+// at a specified interval. The scheduler is low-overhead, and provides a very smooth
+// distribution of touches across frames.
+
+// Template arguments:
+// Data: the class to be stored in the hash table
+// I: the type of the primary key (uint32 by default)
+template<class Data, typename I=uint32>
+class CTHash
+{
+private:
+ // RecHdr
+ // We insert one of these at the beginning of every record. It's used for
+ // keeping the records in a linked list.
+ typedef struct RecHdr_t
+ {
+ RecHdr_t *m_pRecHdrNext; // Next item in our linked list
+ RecHdr_t *m_pRecHdrPrev; // Previous item in our linked list
+ I m_unKey; // Key of this item
+ int m_iBucket; // The bucket we're in
+ int m_nRunRatio; // We want to run 1 cycle out of every m_nRunRatio
+ // cycles (not at all if 0).
+#ifdef DBGFLAG_THASH
+ uint m_iCycleLast; // Last cycle we were visited (whether or not we ran)
+#endif
+ } RecHdr_t;
+
+ // Bucket
+ // Each hash bucket is represented by a Bucket structure, which points to the
+ // first record with the bucket's hash.
+ typedef struct Bucket_t
+ {
+ RecHdr_t *m_pRecHdrFirst; // First record in our list
+ } Bucket_t;
+
+
+public:
+ // Constructors & destructors
+ CTHash( int cFramesPerCycle );
+ ~CTHash();
+
+ // Initializer
+ void Init( int cRecordInit, int cBuckets );
+
+ // Insert a record into the table
+ Data *PvRecordInsert( I unKey );
+ // Insert a record into the table and set the allocated object's pointer as the hash key
+ Data *PvRecordInsertAutoKey();
+ // Changes the key for a previously inserted item
+ void ChangeKey( Data * pvRecord, I unOldKey, I unNewKey );
+
+ // Remove a record
+ void Remove( I unKey );
+ // Remove a record
+ void Remove( Data * pvRecord );
+ // Remove all records
+ void RemoveAll();
+
+ // Find a record
+ Data *PvRecordFind( I unKey ) const;
+
+ // How many records do we have
+ int Count() const { return m_cRecordInUse; }
+
+ // Iterate through our members
+ Data *PvRecordFirst() const;
+ Data *PvRecordNext( Data *pvRecordCur ) const;
+
+ // We provide a scheduling service. Call StartFrameSchedule when you want to start running
+ // records in a given frame, and repeatedly call PvRecordRun until it returns NULL (or you
+ // run our of time).
+ void SetRunRatio( Data *pvRecord, int nRunRatio );
+ void SetMicroSecPerCycle( int cMicroSecPerCycle, int cMicroSecPerFrame ) { m_cFramesPerCycle = cMicroSecPerCycle / cMicroSecPerFrame; }
+ void StartFrameSchedule( bool bNewFrame );
+ Data *PvRecordRun();
+
+ bool BCompletedPass();
+
+#ifdef DBGFLAG_VALIDATE
+ virtual void Validate( CValidator &validator, const char *pchName );
+#endif // DBGFLAG_VALIDATE
+
+
+private:
+ // Insert a record into the table
+ Data *PvRecordInsertInternal( RecHdr_t *pRecHdr, I unKey );
+
+ // Get the record associated with a THashHdr
+ Data *PvRecordFromPRecHdr( RecHdr_t *pRecHdr ) const { return ( Data * ) ( ( ( uint8 * ) pRecHdr + sizeof( RecHdr_t ) ) ); }
+
+ // Get the RecHdr preceding a PvRecord
+ RecHdr_t *PRecHdrFromPvRecord( Data *pvRecord ) const { return ( ( ( RecHdr_t * ) pvRecord ) - 1 ); }
+
+ // Get the hash bucket corresponding to a key
+ int IBucket( I unKey ) const;
+
+ void InsertIntoHash( RecHdr_t *pRecHdr, I unKey );
+ void RemoveFromHash( Data * pvRecord );
+
+ int m_cBucket; // # of hash buckets we have
+ Bucket_t *m_pBucket; // Big array of hash buckets
+
+ CUtlMemoryPool *m_pMemoryPoolRecord; // All our data records
+
+ int m_cRecordInUse; // # of records in use
+ RecHdr_t m_RecHdrHead; // Head of our linked list
+ RecHdr_t m_RecHdrTail; // Tail of our linked list
+
+ int m_cFramesPerCycle; // Run each of our records once every m_cFramesPerCycle frames
+ RecHdr_t *m_pRecHdrRunNext; // Next record to run (be careful-- this is more complicated than it sounds)
+ int m_iBucketRunMax; // Stop running when we get to this bucket
+ uint m_iCycleCur; // Current cycle (ie, how many times we've made a complete scheduler pass)
+ uint m_iCycleLast; // Our previous cycle
+ uint m_iFrameCur; // Our current frame (incremented once each StartFrameSchedule)
+ uint m_iCycleLastReported; // Last cycle checked by BCompletedPass()
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input: cMicroSecRunInterval - How often we want the scheduler to run each of our records
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+CTHash<Data,I>::CTHash( int cFramesPerCycle )
+{
+ m_cBucket = 0;
+ m_pBucket = NULL;
+ m_pMemoryPoolRecord = NULL;
+ m_cRecordInUse = 0;
+
+ m_cFramesPerCycle = cFramesPerCycle;
+ m_pRecHdrRunNext = &m_RecHdrTail; // This will make us start at the beginning on our first frame
+ m_iBucketRunMax = 0;
+ m_iCycleCur = 0;
+ m_iCycleLast = 0;
+ m_iFrameCur = 0;
+ m_iCycleLastReported = 0;
+
+ m_RecHdrHead.m_pRecHdrPrev = NULL;
+ m_RecHdrHead.m_pRecHdrNext = &m_RecHdrTail;
+ m_RecHdrHead.m_iBucket = -1;
+
+ m_RecHdrTail.m_pRecHdrPrev = &m_RecHdrHead;
+ m_RecHdrTail.m_pRecHdrNext = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+CTHash<Data,I>::~CTHash()
+{
+ RemoveAll();
+
+ if ( NULL != m_pBucket )
+ FreePv( m_pBucket );
+ m_pBucket = NULL;
+
+ if ( NULL != m_pMemoryPoolRecord )
+ delete( m_pMemoryPoolRecord );
+ m_pMemoryPoolRecord = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Initializer. Allocate our various arrays, and set up the free
+// list.
+// Input: cRecordInit - Initial # of data records we can contain
+// cBucket - # of hash buckets we should use
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+void CTHash<Data,I>::Init( int cRecordInit, int cBucket )
+{
+ Assert( cRecordInit > 0 ); // need to init with non-zero value or memory pool will never grow
+
+ // Copy our parameters
+ m_cBucket = cBucket;
+
+ // Alloc our arrays
+ m_pBucket = ( Bucket_t * ) PvAlloc( sizeof( Bucket_t ) * m_cBucket );
+ m_pMemoryPoolRecord = new CUtlMemoryPool( sizeof( Data ) + sizeof( RecHdr_t ), cRecordInit,
+ CUtlMemoryPool::GROW_SLOW );
+
+ // Init the hash buckets
+ for ( int iBucket = 0; iBucket < m_cBucket; iBucket++ )
+ m_pBucket[iBucket].m_pRecHdrFirst = NULL;
+
+ // Make the tail have an illegally large bucket
+ m_RecHdrTail.m_iBucket = m_cBucket + 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Inserts a new record into the table
+// Input: unKey - Primary key of the new record
+// Output: Pointer to the new record
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+Data *CTHash<Data,I>::PvRecordInsert( I unKey )
+{
+ Assert( PvRecordFind( unKey ) == NULL ); // keys are unique; no record with this key may exist
+
+ // Find a free record
+ RecHdr_t *pRecHdr = ( RecHdr_t * ) m_pMemoryPoolRecord->Alloc();
+
+ return PvRecordInsertInternal( pRecHdr, unKey );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Inserts a new record into the table and sets its key to the pointer
+// value of the record
+// Output: Pointer to the new record
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+Data *CTHash<Data,I>::PvRecordInsertAutoKey()
+{
+ // Find a free record
+ RecHdr_t *pRecHdr = ( RecHdr_t * ) m_pMemoryPoolRecord->Alloc();
+
+ return PvRecordInsertInternal( pRecHdr, (I) PvRecordFromPRecHdr( pRecHdr ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Inserts an allocated record into the hash table with specified key
+// and calls the constructor of the allocated object
+// Input: pRecHdr - record to insert
+// unKey - hash key to use for record
+// Output: Pointer to the new record
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+Data *CTHash<Data,I>::PvRecordInsertInternal( RecHdr_t *pRecHdr, I unKey )
+{
+ InsertIntoHash( pRecHdr, unKey );
+
+ // assert that we don't have too many items per bucket
+ static bool s_bPerfWarning = false;
+ if ( !s_bPerfWarning && Count() >= ( 5 * m_cBucket ) )
+ {
+ s_bPerfWarning = true;
+ AssertMsg( false, "Performance warning: too many items, not enough buckets" );
+ Msg( "not enough buckets in thash class %s (%d records, %d buckets)\n",
+#ifdef _WIN32
+ typeid(*this).raw_name(),
+#else
+ typeid(*this).name(),
+#endif
+ Count(), m_cBucket );
+ }
+
+ // Construct ourselves
+ Data *pData = PvRecordFromPRecHdr( pRecHdr );
+ Construct<Data>( pData );
+ return pData;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Changes key on previously inserted item
+// Input: pvRecord - record to change key for
+// unOldKey - old key (not strictly needed, but helpful consistency check)
+// unNewKey - new key to use
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+void CTHash<Data,I>::ChangeKey( Data * pvRecord, I unOldKey, I unNewKey )
+{
+ Data * pvRecordFound = PvRecordFind( unOldKey );
+ Assert( pvRecordFound == pvRecord );
+ if ( pvRecordFound == pvRecord )
+ {
+ RemoveFromHash( pvRecord );
+ InsertIntoHash( PRecHdrFromPvRecord( pvRecord), unNewKey );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Removes the entry with a specified key from the table
+// Input: unKey - Key of the entry to remove
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+void CTHash<Data,I>::Remove( I unKey )
+{
+ Data *pvRemove = ( Data * ) PvRecordFind( unKey );
+ Assert( pvRemove );
+ if ( !pvRemove )
+ return;
+ Remove( pvRemove );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Removes the specified entry from the table
+// Input: pvRemove - Pointer to the entry to remove
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+void CTHash<Data,I>::Remove( Data * pvRemove )
+{
+ // Destruct the record we're removing
+ Destruct<Data>( pvRemove );
+
+ RemoveFromHash( pvRemove );
+ m_pMemoryPoolRecord->Free( PRecHdrFromPvRecord( pvRemove ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Removes all entries from the table
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+void CTHash<Data,I>::RemoveAll()
+{
+ Data * pvRecord = PvRecordFirst();
+ while ( pvRecord )
+ {
+ Data *pvRecordNext = PvRecordNext( pvRecord );
+ Remove( pvRecord );
+ pvRecord = pvRecordNext;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Finds the entry with a specified key
+// Input: unKey - Key to find
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+Data *CTHash<Data,I>::PvRecordFind( I unKey ) const
+{
+ // Find our hash bucket
+ int iBucket = IBucket( unKey );
+
+ // Walk the bucket's list looking for an exact match
+ for ( RecHdr_t *pRecHdr = m_pBucket[iBucket].m_pRecHdrFirst;
+ NULL != pRecHdr && pRecHdr->m_iBucket == iBucket;
+ pRecHdr = pRecHdr->m_pRecHdrNext )
+ {
+ if ( unKey == pRecHdr->m_unKey )
+ return PvRecordFromPRecHdr( pRecHdr );
+ }
+
+ // Didn't find a match
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Finds our first record
+// Output: Pointer to our first record
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+Data *CTHash<Data,I>::PvRecordFirst() const
+{
+ if ( &m_RecHdrTail != m_RecHdrHead.m_pRecHdrNext )
+ return PvRecordFromPRecHdr( m_RecHdrHead.m_pRecHdrNext );
+ else
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Iterates to the record after a given record
+// Input: Pointer to a current record
+// Output: Pointer to the next record
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+Data *CTHash<Data,I>::PvRecordNext( Data *pvRecordCur ) const
+{
+ RecHdr_t *pRecHdr = PRecHdrFromPvRecord( pvRecordCur );
+ if ( &m_RecHdrTail == pRecHdr->m_pRecHdrNext )
+ return NULL;
+
+ return PvRecordFromPRecHdr( pRecHdr->m_pRecHdrNext );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the run ratio of a particular record in the hash table.
+// The record will be run 1 cycle out of every nRunRatio cycles.
+// Input: pvRecord - The record we're setting
+// nRunRatio - The run ratio for this record
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+void CTHash<Data,I>::SetRunRatio( Data *pvRecord, int nRunRatio )
+{
+ PRecHdrFromPvRecord( pvRecord )->m_nRunRatio = nRunRatio;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Prepares us to run all records that are due to be run this frame.
+// Records are run at a particular time dependent on their hash bucket,
+// regardless of when they were last run.
+// Input: bNewFrame - True if this is a new frame. If false, we've run
+// off the end of the list and are checking whether
+// we need to keep going at the beginning.
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+void CTHash<Data,I>::StartFrameSchedule( bool bNewFrame )
+{
+ // Calculate our current frame and cycle cycle
+ if ( bNewFrame )
+ {
+ m_iCycleLast = m_iCycleCur;
+ m_iFrameCur++;
+ m_iCycleCur = m_iFrameCur / m_cFramesPerCycle;
+ }
+
+ // Calculate the last bucket to run
+ int iFrameInCycle = m_iFrameCur % m_cFramesPerCycle;
+ m_iBucketRunMax = ( int ) ( ( ( int64 ) ( iFrameInCycle + 1 ) * ( int64 ) m_cBucket )
+ / ( int64 ) m_cFramesPerCycle );
+ AssertFatal( m_iBucketRunMax >= 0 && m_iBucketRunMax <= m_cBucket );
+
+ // Are we starting a new cycle?
+ if ( m_iCycleCur > m_iCycleLast )
+ {
+#ifdef DBGFLAG_THASH
+ Assert( m_iCycleCur == m_iCycleLast + 1 );
+#endif
+
+ // Did we finish the last cycle?
+ if ( &m_RecHdrTail == m_pRecHdrRunNext )
+ {
+ m_pRecHdrRunNext = m_RecHdrHead.m_pRecHdrNext;
+ }
+ // No-- finish it up before moving on
+ else
+ {
+ m_iBucketRunMax = m_cBucket + 1;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the next record to run, if any
+// Output: Pointer to the next record that needs to run (NULL if we're done)
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+Data *CTHash<Data,I>::PvRecordRun()
+{
+ // Loop until we find a record to run, or until we pass m_iBucketRunMax
+ for ( ; ; )
+ {
+ // Are we past our stopping point?
+ if ( m_pRecHdrRunNext->m_iBucket >= m_iBucketRunMax )
+ {
+ // If this cycle ran to the very end, see if we need to start over
+ if ( m_iBucketRunMax > m_cBucket )
+ {
+ StartFrameSchedule( false );
+ continue;
+ }
+
+ return NULL;
+ }
+
+#ifdef DBGFLAG_THASH
+ Assert( m_pRecHdrRunNext->m_iBucket >= m_iBucketRunFirst );
+ if ( 0 != m_pRecHdrRunNext->m_iCycleLast )
+ {
+ if ( m_pRecHdrRunNext->m_iCycleLast == m_iCycleCur )
+ {
+ DMsg( SPEW_CONSOLE, 1, "Double cycle: hdr = 0x%x, last frame = %d, curFrame = %d, first = %d, last = %d, bucket = %d\n",
+ m_pRecHdrRunNext, m_pRecHdrRunNext->m_iFrameLast, m_iFrame,
+ m_iBucketRunFirst, m_iBucketRunMax, m_pRecHdrRunNext->m_iBucket );
+ }
+ else if ( m_pRecHdrRunNext->m_iCycleLast != m_iCycleCur - 1 )
+ {
+ DMsg( SPEW_CONSOLE, 1, "Skipped cycle: hdr = 0x%x, cycleLast = %u, cycleCur = %u (missed %u cycles)\n",
+ m_pRecHdrRunNext, m_pRecHdrRunNext->m_iCycleLast, m_iCycleCur,
+ m_iCycleCur - m_pRecHdrRunNext->m_iCycleLast );
+ Assert( false );
+ }
+ }
+ m_pRecHdrRunNext->m_iCycleLast = m_iCycleCur;
+ m_pRecHdrRunNext->m_iFrameLast = m_iFrame;
+#endif
+
+ // Set up the record to run next time
+ RecHdr_t *pRecHdrCur = m_pRecHdrRunNext;
+ m_pRecHdrRunNext = m_pRecHdrRunNext->m_pRecHdrNext;
+
+ // Does this record need to run?
+ if ( 0 == pRecHdrCur->m_nRunRatio )
+ continue;
+
+ if ( 0 == m_iCycleCur % pRecHdrCur->m_nRunRatio )
+ return PvRecordFromPRecHdr( pRecHdrCur );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Return true if we've completed a scheduler pass since last called
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+bool CTHash<Data,I>::BCompletedPass()
+{
+ if ( m_iCycleCur != m_iCycleLastReported )
+ {
+ m_iCycleLastReported = m_iCycleCur;
+ return true;
+ }
+ return false;
+}
+
+
+extern const unsigned char g_CTHashRandomValues[256]; // definition lives in globals.cpp
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the index of the hash bucket corresponding to a particular key
+// Input: unKey - Key to find
+// Output: Index of the hash bucket corresponding to unKey
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+int CTHash<Data,I>::IBucket( I unKey ) const
+{
+ AssertFatal( m_cBucket > 0 );
+
+ // This is a pearsons hash variant that returns a maximum of 32 bits
+ size_t size = sizeof(I);
+ const uint8 * k = (const uint8 *) &unKey;
+ uint32 byte_one = 0, byte_two = 0, byte_three = 0, byte_four = 0, n;
+
+ while (size)
+ {
+ --size;
+ n = *k++;
+ byte_one = g_CTHashRandomValues[byte_one ^ n];
+
+ if (size)
+ {
+ --size;
+ n = *k++;
+ byte_two = g_CTHashRandomValues[byte_two ^ n];
+ }
+ else
+ break;
+
+ if (size)
+ {
+ --size;
+ n = *k++;
+ byte_three = g_CTHashRandomValues[byte_three ^ n];
+ }
+ else
+ break;
+
+ if (size)
+ {
+ --size;
+ n = *k++;
+ byte_four = g_CTHashRandomValues[byte_four ^ n];
+ }
+ else
+ break;
+ }
+
+ uint32 idx = ( byte_four << 24 ) | ( byte_three << 16 ) | ( byte_two << 8 ) | byte_one;
+ idx = idx % m_cBucket;
+ return ( (int) idx );
+}
+
+
+#ifdef DBGFLAG_VALIDATE
+//-----------------------------------------------------------------------------
+// Purpose: Run a global validation pass on all of our data structures and memory
+// allocations.
+// Input: validator - Our global validator object
+// pchName - Our name (typically a member var in our container)
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+void CTHash<Data,I>::Validate( CValidator &validator, const char *pchName )
+{
+ VALIDATE_SCOPE();
+
+ validator.ClaimMemory( m_pBucket );
+ ValidatePtr( m_pMemoryPoolRecord );
+
+#if defined( _DEBUG )
+ // first verify m_cRecordInUse
+ Data * pvRecord = PvRecordFirst();
+ int cItems = 0;
+ while ( pvRecord )
+ {
+ Data *pvRecordNext = PvRecordNext( pvRecord );
+ cItems++;
+ pvRecord = pvRecordNext;
+ }
+ Assert( m_cRecordInUse == cItems );
+ // then ask the mempool to verify this
+ if ( m_pMemoryPoolRecord )
+ m_pMemoryPoolRecord->LeakCheck( cItems );
+#endif // _DEBUG
+}
+#endif // DBGFLAG_VALIDATE
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Inserts a new record into the table
+// Input: unKey - Primary key of the new record
+// Output: Pointer to the new record
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+void CTHash<Data,I>::InsertIntoHash( RecHdr_t *pRecHdr, I unKey )
+{
+ m_cRecordInUse++;
+
+ // Init the RecHdr
+ pRecHdr->m_unKey = unKey;
+ pRecHdr->m_nRunRatio = 1;
+
+ // Find our hash bucket
+ int iBucket = IBucket( unKey );
+ pRecHdr->m_iBucket = iBucket;
+#ifdef DBGFLAG_THASH
+ pRecHdr->m_iCycleLast = 0;
+#endif
+
+ // Find where to insert ourselves in the linked list
+ RecHdr_t *pRecHdrInsertBefore = &m_RecHdrTail;
+ // Find the first bucket with anything in it that's at or after our bucket
+ for ( int iBucketT = iBucket; iBucketT < m_cBucket; iBucketT++ )
+ {
+ if ( NULL != m_pBucket[iBucketT].m_pRecHdrFirst )
+ {
+ pRecHdrInsertBefore = m_pBucket[iBucketT].m_pRecHdrFirst;
+ break;
+ }
+ }
+
+ // Insert ourselves
+ pRecHdr->m_pRecHdrNext = pRecHdrInsertBefore;
+ pRecHdr->m_pRecHdrPrev = pRecHdrInsertBefore->m_pRecHdrPrev;
+ pRecHdrInsertBefore->m_pRecHdrPrev = pRecHdr;
+ pRecHdr->m_pRecHdrPrev->m_pRecHdrNext = pRecHdr;
+
+ // Our bucket should point to us
+ m_pBucket[iBucket].m_pRecHdrFirst = pRecHdr;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Removes the specified entry from the table
+// Input: pvRemove - Pointer to the entry to remove
+//-----------------------------------------------------------------------------
+template<class Data, class I>
+void CTHash<Data,I>::RemoveFromHash( Data * pvRemove )
+{
+ // Find our RecHdr
+ RecHdr_t *pRecHdr = PRecHdrFromPvRecord( pvRemove );
+
+ // If our bucket points to us, point it to the next record (or else NULL)
+ int iBucket = IBucket( pRecHdr->m_unKey );
+ if ( pRecHdr == m_pBucket[iBucket].m_pRecHdrFirst )
+ {
+ if ( pRecHdr->m_pRecHdrNext->m_iBucket == iBucket )
+ m_pBucket[iBucket].m_pRecHdrFirst = pRecHdr->m_pRecHdrNext;
+ else
+ m_pBucket[iBucket].m_pRecHdrFirst = NULL;
+ }
+
+ // Remove us from the linked list
+ pRecHdr->m_pRecHdrPrev->m_pRecHdrNext = pRecHdr->m_pRecHdrNext;
+ pRecHdr->m_pRecHdrNext->m_pRecHdrPrev = pRecHdr->m_pRecHdrPrev;
+
+ // Are we the next record to run?
+ if ( pRecHdr == m_pRecHdrRunNext )
+ m_pRecHdrRunNext = pRecHdr->m_pRecHdrNext;
+
+ m_cRecordInUse--;
+}
+
+#endif // THASH_H
diff --git a/public/tier1/tier1.h b/public/tier1/tier1.h
new file mode 100644
index 0000000..ac79067
--- /dev/null
+++ b/public/tier1/tier1.h
@@ -0,0 +1,106 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A higher level link library for general use in the game and tools.
+//
+//===========================================================================//
+
+
+#ifndef TIER1_H
+#define TIER1_H
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+
+#include "appframework/IAppSystem.h"
+#include "tier1/convar.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class ICvar;
+class IProcessUtils;
+
+
+//-----------------------------------------------------------------------------
+// These tier1 libraries must be set by any users of this library.
+// They can be set by calling ConnectTier1Libraries.
+// It is hoped that setting this, and using this library will be the common mechanism for
+// allowing link libraries to access tier1 library interfaces
+//-----------------------------------------------------------------------------
+
+// These are marked DLL_EXPORT for Linux.
+DLL_EXPORT ICvar *cvar;
+extern ICvar *g_pCVar;
+extern IProcessUtils *g_pProcessUtils;
+
+
+//-----------------------------------------------------------------------------
+// Call this to connect to/disconnect from all tier 1 libraries.
+// It's up to the caller to check the globals it cares about to see if ones are missing
+//-----------------------------------------------------------------------------
+void ConnectTier1Libraries( CreateInterfaceFn *pFactoryList, int nFactoryCount );
+void DisconnectTier1Libraries();
+
+
+//-----------------------------------------------------------------------------
+// Helper empty implementation of an IAppSystem for tier2 libraries
+//-----------------------------------------------------------------------------
+template< class IInterface, int ConVarFlag = 0 >
+class CTier1AppSystem : public CTier0AppSystem< IInterface >
+{
+ typedef CTier0AppSystem< IInterface > BaseClass;
+
+public:
+ CTier1AppSystem( bool bIsPrimaryAppSystem = true ) : BaseClass( bIsPrimaryAppSystem )
+ {
+ }
+
+ virtual bool Connect( CreateInterfaceFn factory )
+ {
+ if ( !BaseClass::Connect( factory ) )
+ return false;
+
+ if ( BaseClass::IsPrimaryAppSystem() )
+ {
+ ConnectTier1Libraries( &factory, 1 );
+ }
+ return true;
+ }
+
+ virtual void Disconnect()
+ {
+ if ( BaseClass::IsPrimaryAppSystem() )
+ {
+ DisconnectTier1Libraries();
+ }
+ BaseClass::Disconnect();
+ }
+
+ virtual InitReturnVal_t Init()
+ {
+ InitReturnVal_t nRetVal = BaseClass::Init();
+ if ( nRetVal != INIT_OK )
+ return nRetVal;
+
+ if ( g_pCVar && BaseClass::IsPrimaryAppSystem() )
+ {
+ ConVar_Register( ConVarFlag );
+ }
+ return INIT_OK;
+ }
+
+ virtual void Shutdown()
+ {
+ if ( g_pCVar && BaseClass::IsPrimaryAppSystem() )
+ {
+ ConVar_Unregister( );
+ }
+ BaseClass::Shutdown( );
+ }
+};
+
+
+#endif // TIER1_H
+
diff --git a/public/tier1/tokenreader.h b/public/tier1/tokenreader.h
new file mode 100644
index 0000000..b174869
--- /dev/null
+++ b/public/tier1/tokenreader.h
@@ -0,0 +1,99 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef TOKENREADER_H
+#define TOKENREADER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/basetypes.h"
+
+#ifdef _WIN32
+#pragma warning(push, 1)
+#pragma warning(disable:4701 4702 4530)
+#endif
+
+#undef min
+#undef max
+#include <fstream>
+#include "valve_minmax_on.h"
+
+#ifdef _WIN32
+#pragma warning(pop)
+#endif
+
+#include <assert.h>
+
+
+typedef enum
+{
+ TOKENSTRINGTOOLONG = -4,
+ TOKENERROR = -3,
+ TOKENNONE = -2,
+ TOKENEOF = -1,
+ OPERATOR,
+ INTEGER,
+ STRING,
+ IDENT
+} trtoken_t;
+
+
+#define IsToken(s1, s2) !strcmpi(s1, s2)
+
+#define MAX_TOKEN 128 + 1
+#define MAX_IDENT 64 + 1
+#define MAX_STRING 128 + 1
+
+
+class TokenReader : private std::ifstream
+{
+public:
+
+ TokenReader();
+
+ bool Open(const char *pszFilename);
+ trtoken_t NextToken(char *pszStore, int nSize);
+ trtoken_t NextTokenDynamic(char **ppszStore);
+ void Close();
+
+ void IgnoreTill(trtoken_t ttype, const char *pszToken);
+ void Stuff(trtoken_t ttype, const char *pszToken);
+ bool Expecting(trtoken_t ttype, const char *pszToken);
+ const char *Error(char *error, ...);
+ trtoken_t PeekTokenType(char* = NULL, int maxlen = 0);
+
+ inline int GetErrorCount(void);
+
+private:
+ // compiler can't generate an assignment operator since descended from std::ifstream
+ inline TokenReader(TokenReader const &);
+ inline int operator=(TokenReader const &);
+
+ trtoken_t GetString(char *pszStore, int nSize);
+ bool SkipWhiteSpace(void);
+
+ int m_nLine;
+ int m_nErrorCount;
+
+ char m_szFilename[128];
+ char m_szStuffed[128];
+ bool m_bStuffed;
+ trtoken_t m_eStuffed;
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the total number of parsing errors since this file was opened.
+//-----------------------------------------------------------------------------
+int TokenReader::GetErrorCount(void)
+{
+ return(m_nErrorCount);
+}
+
+
+#endif // TOKENREADER_H
diff --git a/public/tier1/uniqueid.h b/public/tier1/uniqueid.h
new file mode 100644
index 0000000..fd3fe26
--- /dev/null
+++ b/public/tier1/uniqueid.h
@@ -0,0 +1,56 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+// Utilities for globally unique IDs
+//=============================================================================//
+
+#ifndef UNIQUEID_H
+#define UNIQUEID_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier1/utlvector.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+struct UniqueId_t;
+class CUtlBuffer;
+
+
+//-----------------------------------------------------------------------------
+// Defines a globally unique ID
+//-----------------------------------------------------------------------------
+struct UniqueId_t
+{
+ unsigned char m_Value[16];
+};
+
+
+//-----------------------------------------------------------------------------
+// Methods related to unique ids
+//-----------------------------------------------------------------------------
+void CreateUniqueId( UniqueId_t *pDest );
+void InvalidateUniqueId( UniqueId_t *pDest );
+bool IsUniqueIdValid( const UniqueId_t &id );
+bool IsUniqueIdEqual( const UniqueId_t &id1, const UniqueId_t &id2 );
+void UniqueIdToString( const UniqueId_t &id, char *pBuf, int nMaxLen );
+bool UniqueIdFromString( UniqueId_t *pDest, const char *pBuf, int nMaxLen = 0 );
+void CopyUniqueId( const UniqueId_t &src, UniqueId_t *pDest );
+bool Serialize( CUtlBuffer &buf, const UniqueId_t &src );
+bool Unserialize( CUtlBuffer &buf, UniqueId_t &dest );
+
+inline bool operator ==( const UniqueId_t& lhs, const UniqueId_t& rhs )
+{
+ return !Q_memcmp( (void *)&lhs.m_Value[ 0 ], (void *)&rhs.m_Value[ 0 ], sizeof( lhs.m_Value ) );
+}
+
+
+#endif // UNIQUEID_H
+
diff --git a/public/tier1/utlallocation.h b/public/tier1/utlallocation.h
new file mode 100644
index 0000000..65416bc
--- /dev/null
+++ b/public/tier1/utlallocation.h
@@ -0,0 +1,134 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+// The CUtlAllocation class:
+// A single allocation in the style of CUtlMemory/CUtlString/CUtlBuffer
+// as compact as possible, no virtuals or extraneous data
+// to be used primarily to replace CUtlBuffer
+//=============================================================================
+
+#ifndef UTLALLOCATION_H
+#define UTLALLOCATION_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier1/utlmemory.h"
+
+class CUtlAllocation
+{
+public:
+
+ // constructor, destructor
+ CUtlAllocation()
+ {
+ m_pMemory = NULL;
+ }
+
+ CUtlAllocation( const void *pMemory, int cub )
+ {
+ m_pMemory = NULL;
+ Copy( pMemory, cub );
+ }
+
+ CUtlAllocation( CUtlAllocation const &src )
+ {
+ m_pMemory = NULL;
+ Copy( src );
+ }
+
+ ~CUtlAllocation()
+ {
+ Purge();
+ }
+
+ CUtlAllocation &operator=( CUtlAllocation const &src )
+ {
+ Copy( src );
+ return *this;
+ }
+
+ bool operator==( CUtlAllocation const &src )
+ {
+ if ( Count() != src.Count() )
+ return false;
+ return Q_memcmp( Base(), src.Base(), Count() ) == 0;
+ }
+
+ void Copy( const void *pMemory, int cub )
+ {
+ if ( cub == 0 || pMemory == NULL )
+ {
+ Purge();
+ return;
+ }
+ if ( cub != Count() )
+ {
+ Purge();
+ m_pMemory = (ActualMemory_t *)malloc( cub + sizeof( int ) );
+ m_pMemory->cub = cub;
+ }
+ Q_memcpy( Base(), pMemory, cub );
+ }
+
+ // Gets the base address
+ uint8* Base()
+ {
+ if ( m_pMemory == NULL )
+ return NULL;
+ return m_pMemory->rgub;
+ }
+
+ const uint8* Base() const
+ {
+ if ( m_pMemory == NULL )
+ return NULL;
+ return m_pMemory->rgub;
+ }
+
+ // Size
+ int Count() const
+ {
+ if ( m_pMemory == NULL )
+ return 0;
+ return m_pMemory->cub;
+ }
+
+ // Memory deallocation
+ void Purge()
+ {
+ if ( m_pMemory )
+ free(m_pMemory);
+ m_pMemory = NULL;
+ }
+
+ void Copy( const CUtlAllocation &alloc )
+ {
+ Copy( alloc.Base(), alloc.Count() );
+ }
+
+ void Swap( CUtlAllocation &alloc )
+ {
+ ActualMemory_t *pTemp = m_pMemory;
+ m_pMemory = alloc.m_pMemory;
+ alloc.m_pMemory = pTemp;
+ }
+
+ void Alloc( int cub )
+ {
+ Purge();
+ m_pMemory = (ActualMemory_t *)malloc( cub + sizeof( int ) );
+ m_pMemory->cub = cub;
+ }
+
+private:
+ struct ActualMemory_t
+ {
+ int cub;
+ uint8 rgub[4]; // i'd prefer to make this 0 but the compiler whines when i do
+ };
+
+ ActualMemory_t *m_pMemory;
+};
+
+#endif // UTLALLOCATION_H
diff --git a/public/tier1/utlarray.h b/public/tier1/utlarray.h
new file mode 100644
index 0000000..ce5ffe8
--- /dev/null
+++ b/public/tier1/utlarray.h
@@ -0,0 +1,332 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+// A growable array class that maintains a free list and keeps elements
+// in the same location
+//=============================================================================//
+
+#ifndef UTLARRAY_H
+#define UTLARRAY_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/platform.h"
+#include "tier0/dbg.h"
+#include "vstdlib/random.h"
+
+#define FOR_EACH_ARRAY( vecName, iteratorName ) \
+ for ( int iteratorName = 0; (vecName).IsUtlArray && iteratorName < (vecName).Count(); iteratorName++ )
+#define FOR_EACH_ARRAY_BACK( vecName, iteratorName ) \
+ for ( int iteratorName = (vecName).Count()-1; (vecName).IsUtlArray && iteratorName >= 0; iteratorName-- )
+
+// utlarray derives from this so we can do the type check above
+struct base_array_t
+{
+public:
+ static const bool IsUtlArray = true; // Used to match this at compiletime
+};
+
+#if defined( GNUC ) && defined( DEBUG )
+// gcc in debug doesn't optimize away the need for the storage of IsUtlArray so make one here
+// as this is in a shared header use SELECTANY to make it throw away the dupe symbols
+const bool base_array_t::IsUtlArray SELECTANY;
+#endif
+
+//-----------------------------------------------------------------------------
+template< class T, size_t MAX_SIZE >
+class CUtlArray : public base_array_t
+{
+public:
+ typedef T ElemType_t;
+ typedef T* iterator;
+ typedef const T* const_iterator;
+
+ CUtlArray();
+ CUtlArray( T* pMemory, size_t count );
+ ~CUtlArray();
+
+ CUtlArray<T, MAX_SIZE>& operator=( const CUtlArray<T, MAX_SIZE> &other );
+ CUtlArray( CUtlArray const& vec );
+
+ // element access
+ T& operator[]( int i );
+ const T& operator[]( int i ) const;
+ T& Element( int i );
+ const T& Element( int i ) const;
+ T& Random();
+ const T& Random() const;
+
+ // STL compatible member functions. These allow easier use of std::sort
+ // and they are forward compatible with the C++ 11 range-based for loops.
+ iterator begin();
+ const_iterator begin() const;
+ iterator end();
+ const_iterator end() const;
+
+ T* Base();
+ const T* Base() const;
+
+ // Returns the number of elements in the array, NumAllocated() is included for consistency with UtlVector
+ int Count() const;
+ int NumAllocated() const;
+
+ // Is element index valid?
+ bool IsValidIndex( int i ) const;
+ static int InvalidIndex();
+
+ void CopyArray( const T *pArray, size_t count );
+
+ void Swap( CUtlArray< T, MAX_SIZE > &vec );
+
+ // Finds an element (element needs operator== defined)
+ int Find( const T& src ) const;
+ void FillWithValue( const T& src );
+
+ bool HasElement( const T& src ) const;
+
+ // calls delete on each element in it.
+ void DeleteElements();
+
+ void Sort( int (__cdecl *pfnCompare)(const T *, const T *) );
+
+protected:
+ T m_Memory[ MAX_SIZE ];
+};
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+template< typename T, size_t MAX_SIZE >
+inline CUtlArray<T, MAX_SIZE>::CUtlArray()
+{
+}
+
+template< typename T, size_t MAX_SIZE >
+inline CUtlArray<T, MAX_SIZE>::CUtlArray( T* pMemory, size_t count )
+{
+ CopyArray( pMemory, count );
+}
+
+template< typename T, size_t MAX_SIZE >
+inline CUtlArray<T, MAX_SIZE>::~CUtlArray()
+{
+}
+
+template< typename T, size_t MAX_SIZE >
+inline CUtlArray<T, MAX_SIZE>& CUtlArray<T, MAX_SIZE>::operator=( const CUtlArray<T, MAX_SIZE> &other )
+{
+ if ( this != &other )
+ {
+ for ( size_t n = 0; n < MAX_SIZE; ++n )
+ {
+ m_Memory[n] = other.m_Memory[n];
+ }
+ }
+ return *this;
+}
+
+template< typename T, size_t MAX_SIZE >
+inline CUtlArray<T, MAX_SIZE>::CUtlArray( CUtlArray const& vec )
+{
+ for ( size_t n = 0; n < MAX_SIZE; ++n )
+ {
+ m_Memory[n] = vec.m_Memory[n];
+ }
+}
+
+template< typename T, size_t MAX_SIZE >
+typename CUtlArray<T, MAX_SIZE>::iterator CUtlArray<T, MAX_SIZE>::begin()
+{
+ return Base();
+}
+
+template< typename T, size_t MAX_SIZE >
+typename CUtlArray<T, MAX_SIZE>::const_iterator CUtlArray<T, MAX_SIZE>::begin() const
+{
+ return Base();
+}
+
+template< typename T, size_t MAX_SIZE >
+typename CUtlArray<T, MAX_SIZE>::iterator CUtlArray<T, MAX_SIZE>::end()
+{
+ return Base() + Count();
+}
+
+template< typename T, size_t MAX_SIZE >
+typename CUtlArray<T, MAX_SIZE>::const_iterator CUtlArray<T, MAX_SIZE>::end() const
+{
+ return Base() + Count();
+}
+
+template< typename T, size_t MAX_SIZE >
+inline T *CUtlArray<T, MAX_SIZE>::Base()
+{
+ return &m_Memory[0];
+}
+
+template< typename T, size_t MAX_SIZE >
+inline const T *CUtlArray<T, MAX_SIZE>::Base() const
+{
+ return &m_Memory[0];
+}
+
+//-----------------------------------------------------------------------------
+// element access
+//-----------------------------------------------------------------------------
+template< typename T, size_t MAX_SIZE >
+inline T& CUtlArray<T, MAX_SIZE>::operator[]( int i )
+{
+ Assert( IsValidIndex( i ) );
+ return m_Memory[ i ];
+}
+
+template< typename T, size_t MAX_SIZE >
+inline const T& CUtlArray<T, MAX_SIZE>::operator[]( int i ) const
+{
+ Assert( IsValidIndex( i ) );
+ return m_Memory[ i ];
+}
+
+template< typename T, size_t MAX_SIZE >
+inline T& CUtlArray<T, MAX_SIZE>::Element( int i )
+{
+ Assert( IsValidIndex( i ) );
+ return m_Memory[ i ];
+}
+
+template< typename T, size_t MAX_SIZE >
+inline const T& CUtlArray<T, MAX_SIZE>::Element( int i ) const
+{
+ Assert( IsValidIndex( i ) );
+ return m_Memory[ i ];
+}
+
+template< typename T, size_t MAX_SIZE >
+inline T& CUtlArray<T, MAX_SIZE>::Random()
+{
+ Assert( MAX_SIZE > 0 );
+ return m_Memory[ RandomInt( 0, MAX_SIZE - 1 ) ];
+}
+
+template< typename T, size_t MAX_SIZE >
+inline const T& CUtlArray<T, MAX_SIZE>::Random() const
+{
+ Assert( MAX_SIZE > 0 );
+ return m_Memory[ RandomInt( 0, MAX_SIZE - 1 ) ];
+}
+
+
+//-----------------------------------------------------------------------------
+// Count
+//-----------------------------------------------------------------------------
+template< typename T, size_t MAX_SIZE >
+inline int CUtlArray<T, MAX_SIZE>::Count() const
+{
+ return (int)MAX_SIZE;
+}
+
+
+//-----------------------------------------------------------------------------
+template< typename T, size_t MAX_SIZE >
+inline int CUtlArray<T, MAX_SIZE>::NumAllocated() const
+{
+ return (int)MAX_SIZE;
+}
+
+//-----------------------------------------------------------------------------
+// Is element index valid?
+//-----------------------------------------------------------------------------
+template< typename T, size_t MAX_SIZE >
+inline bool CUtlArray<T, MAX_SIZE>::IsValidIndex( int i ) const
+{
+ return (i >= 0) && (i < MAX_SIZE);
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns in invalid index
+//-----------------------------------------------------------------------------
+template< typename T, size_t MAX_SIZE >
+inline int CUtlArray<T, MAX_SIZE>::InvalidIndex()
+{
+ return -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sorts the vector
+//-----------------------------------------------------------------------------
+template< typename T, size_t MAX_SIZE >
+void CUtlArray<T, MAX_SIZE>::Sort( int (__cdecl *pfnCompare)(const T *, const T *) )
+{
+ typedef int (__cdecl *QSortCompareFunc_t)(const void *, const void *);
+ if ( Count() <= 1 )
+ return;
+
+ qsort( Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare) );
+}
+
+template< typename T, size_t MAX_SIZE >
+void CUtlArray<T, MAX_SIZE>::CopyArray( const T *pArray, size_t count )
+{
+ Assert( count < MAX_SIZE );
+
+ for ( size_t n = 0; n < count; ++n )
+ {
+ m_Memory[n] = pArray[n];
+ }
+}
+
+template< typename T, size_t MAX_SIZE >
+void CUtlArray<T, MAX_SIZE>::Swap( CUtlArray< T, MAX_SIZE > &vec )
+{
+ for ( size_t n = 0; n < MAX_SIZE; ++n )
+ {
+ V_swap( m_Memory[n], vec.m_Memory[n] );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Finds an element (element needs operator== defined)
+//-----------------------------------------------------------------------------
+template< typename T, size_t MAX_SIZE >
+int CUtlArray<T, MAX_SIZE>::Find( const T& src ) const
+{
+ for ( int i = 0; i < Count(); ++i )
+ {
+ if (Element(i) == src)
+ return i;
+ }
+ return -1;
+}
+
+template< typename T, size_t MAX_SIZE >
+void CUtlArray<T, MAX_SIZE>::FillWithValue( const T& src )
+{
+ for ( int i = 0; i < Count(); i++ )
+ {
+ Element(i) = src;
+ }
+}
+
+template< typename T, size_t MAX_SIZE >
+bool CUtlArray<T, MAX_SIZE>::HasElement( const T& src ) const
+{
+ return ( Find(src) >= 0 );
+}
+
+template< typename T, size_t MAX_SIZE >
+inline void CUtlArray<T, MAX_SIZE>::DeleteElements()
+{
+ for( int i=0; i < MAX_SIZE; i++ )
+ {
+ delete Element(i);
+ }
+}
+
+#endif // UTLARRAY_H
diff --git a/public/tier1/utlbidirectionalset.h b/public/tier1/utlbidirectionalset.h
new file mode 100644
index 0000000..36aea62
--- /dev/null
+++ b/public/tier1/utlbidirectionalset.h
@@ -0,0 +1,394 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Bi-directional set. A Bucket knows about the elements that lie
+// in it, and the elements know about the buckets they lie in.
+//
+// $Revision: $
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef UTLBIDIRECTIONALSET_H
+#define UTLBIDIRECTIONALSET_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/dbg.h"
+#include "utllinkedlist.h"
+
+//-----------------------------------------------------------------------------
+// Templatized helper class to deal with the kinds of things that spatial
+// partition code always seems to have; buckets with lists of lots of elements
+// and elements that live in lots of buckets. This makes it really quick to
+// add and remove elements, and to iterate over all elements in a bucket.
+//
+// For this to work, you must initialize the set with two functions one that
+// maps from bucket to the index of the first element in that bucket, and one
+// that maps from element to the index of the first bucket that element lies in.
+// The set will completely manage the index, it's just expected that those
+// indices will be stored outside the set.
+//
+// S is the storage type of the index; it is the type that you may use to
+// save indices into memory. I is the local iterator type, which you should
+// use in any local scope (eg, inside a for() loop.) The reason for this is
+// that you may wish to use unsigned shorts inside the structs you are
+// saving with a CBidirectionalSet; but 16-bit arithmetic is catastrophically
+// slow on a PowerPC -- during testing we saw CBidirectionalSet:: operations
+// consume as much as 8% of the frame.
+//
+// For this reason, on the 360, the handles have been typedef'd to native
+// register types (U32) which are accepted as parameters by the functions.
+// The implicit assumption is that CBucketHandle and CElementHandle can
+// be safely cast to ints! You can increase to U64 without performance
+// penalty if necessary; the PowerPC is a 64-bit processor.
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I = S >
+class CBidirectionalSet
+{
+public:
+ // Install methods to get at the first bucket given a element
+ // and vice versa...
+ typedef S& (*FirstElementFunc_t)(CBucketHandle);
+ typedef S& (*FirstBucketFunc_t)(CElementHandle);
+
+#ifdef _X360
+ typedef uint32 CBucketHandlePram;
+ typedef uint32 CElementHandlePram;
+#else
+ typedef CBucketHandle CBucketHandlePram;
+ typedef CElementHandle CElementHandlePram;
+#endif
+
+ // Constructor
+ CBidirectionalSet();
+
+ // Call this before using the set
+ void Init( FirstElementFunc_t elemFunc, FirstBucketFunc_t bucketFunc );
+
+ // Add an element to a particular bucket
+ void AddElementToBucket( CBucketHandlePram bucket, CElementHandlePram element );
+
+ // Prevalidate an add to a particular bucket
+ // NOTE: EXPENSIVE!!!
+ void ValidateAddElementToBucket( CBucketHandlePram bucket, CElementHandlePram element );
+
+ // Test if an element is in a particular bucket.
+ // NOTE: EXPENSIVE!!!
+ bool IsElementInBucket( CBucketHandlePram bucket, CElementHandlePram element );
+
+ // Remove an element from a particular bucket
+ void RemoveElementFromBucket( CBucketHandlePram bucket, CElementHandlePram element );
+
+ // Remove an element from all buckets
+ void RemoveElement( CElementHandlePram element );
+ void RemoveBucket( CBucketHandlePram element );
+
+ // Used to iterate elements in a bucket; I is the iterator
+ I FirstElement( CBucketHandlePram bucket ) const;
+ I NextElement( I idx ) const;
+ CElementHandle Element( I idx ) const;
+
+ // Used to iterate buckets associated with an element; I is the iterator
+ I FirstBucket( CElementHandlePram bucket ) const;
+ I NextBucket( I idx ) const;
+ CBucketHandle Bucket( I idx ) const;
+
+ static S InvalidIndex();
+
+ // Ensure capacity
+ void EnsureCapacity( int count );
+
+ // Deallocate....
+ void Purge();
+
+ int NumAllocated( void ) const;
+
+private:
+ struct BucketListInfo_t
+ {
+ CElementHandle m_Element;
+ S m_BucketListIndex; // what's the m_BucketsUsedByElement index of the entry?
+ };
+
+ struct ElementListInfo_t
+ {
+ CBucketHandle m_Bucket;
+ S m_ElementListIndex; // what's the m_ElementsInBucket index of the entry?
+ };
+
+ // Maintains a list of all elements in a particular bucket
+ CUtlLinkedList< BucketListInfo_t, S, true, I > m_ElementsInBucket;
+
+ // Maintains a list of all buckets a particular element lives in
+ CUtlLinkedList< ElementListInfo_t, S, true, I > m_BucketsUsedByElement;
+
+ FirstBucketFunc_t m_FirstBucket;
+ FirstElementFunc_t m_FirstElement;
+};
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I >
+CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::CBidirectionalSet( )
+{
+ m_FirstBucket = NULL;
+ m_FirstElement = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Call this before using the set
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I >
+void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::Init( FirstElementFunc_t elemFunc, FirstBucketFunc_t bucketFunc )
+{
+ m_FirstBucket = bucketFunc;
+ m_FirstElement = elemFunc;
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds an element to the bucket
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I >
+void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::ValidateAddElementToBucket( CBucketHandlePram bucket, CElementHandlePram element )
+{
+#ifdef _DEBUG
+ // Make sure that this element doesn't already exist in the list of elements in the bucket
+ I elementInBucket = m_FirstElement( bucket );
+ while( elementInBucket != m_ElementsInBucket.InvalidIndex() )
+ {
+ // If you hit an Assert here, fix the calling code. It's too expensive to ensure
+ // that each item only shows up once here. Hopefully you can do something better
+ // outside of here.
+ Assert( m_ElementsInBucket[elementInBucket].m_Element != element );
+ elementInBucket = m_ElementsInBucket.Next( elementInBucket );
+ }
+ // Make sure that this bucket doesn't already exist in the element's list of buckets.
+ I bucketInElement = m_FirstBucket( element );
+ while( bucketInElement != m_BucketsUsedByElement.InvalidIndex() )
+ {
+ // If you hit an Assert here, fix the calling code. It's too expensive to ensure
+ // that each item only shows up once here. Hopefully you can do something better
+ // outside of here.
+ Assert( m_BucketsUsedByElement[bucketInElement].m_Bucket != bucket );
+ bucketInElement = m_BucketsUsedByElement.Next( bucketInElement );
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds an element to the bucket
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I >
+void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::AddElementToBucket( CBucketHandlePram bucket, CElementHandlePram element )
+{
+ Assert( m_FirstBucket && m_FirstElement );
+
+ // Allocate new element + bucket entries
+ I idx = m_ElementsInBucket.Alloc(true);
+ I list = m_BucketsUsedByElement.Alloc( true );
+
+ // Store off the element data
+ m_ElementsInBucket[idx].m_Element = element;
+ m_ElementsInBucket[idx].m_BucketListIndex = list;
+
+ // Here's the bucket data
+ m_BucketsUsedByElement[list].m_Bucket = bucket;
+ m_BucketsUsedByElement[list].m_ElementListIndex = idx;
+
+ // Insert the element into the list of elements in the bucket
+ S& firstElementInBucket = m_FirstElement( bucket );
+ if ( firstElementInBucket != m_ElementsInBucket.InvalidIndex() )
+ m_ElementsInBucket.LinkBefore( firstElementInBucket, idx );
+ firstElementInBucket = idx;
+
+ // Insert the bucket into the element's list of buckets
+ S& firstBucketInElement = m_FirstBucket( element );
+ if ( firstBucketInElement != m_BucketsUsedByElement.InvalidIndex() )
+ m_BucketsUsedByElement.LinkBefore( firstBucketInElement, list );
+ firstBucketInElement = list;
+}
+
+//-----------------------------------------------------------------------------
+// Test if an element is in a particular bucket.
+// NOTE: EXPENSIVE!!!
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I >
+bool CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::IsElementInBucket( CBucketHandlePram bucket, CElementHandlePram element )
+{
+ // Search through all elements in this bucket to see if element is in there.
+ I elementInBucket = m_FirstElement( bucket );
+ while( elementInBucket != m_ElementsInBucket.InvalidIndex() )
+ {
+ if( m_ElementsInBucket[elementInBucket].m_Element == element )
+ {
+ return true;
+ }
+ elementInBucket = m_ElementsInBucket.Next( elementInBucket );
+ }
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Remove an element from a particular bucket
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I >
+void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::RemoveElementFromBucket( CBucketHandlePram bucket, CElementHandlePram element )
+{
+ // FIXME: Implement me!
+ Assert(0);
+}
+
+
+//-----------------------------------------------------------------------------
+// Removes an element from all buckets
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I >
+void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::RemoveElement( CElementHandlePram element )
+{
+ Assert( m_FirstBucket && m_FirstElement );
+
+ // Iterate over the list of all buckets the element is in
+ I i = m_FirstBucket( element );
+ while (i != m_BucketsUsedByElement.InvalidIndex())
+ {
+ CBucketHandlePram bucket = m_BucketsUsedByElement[i].m_Bucket;
+ I elementListIndex = m_BucketsUsedByElement[i].m_ElementListIndex;
+
+ // Unhook the element from the bucket's list of elements
+ if (elementListIndex == m_FirstElement(bucket))
+ m_FirstElement(bucket) = m_ElementsInBucket.Next(elementListIndex);
+ m_ElementsInBucket.Free(elementListIndex);
+
+ I prevNode = i;
+ i = m_BucketsUsedByElement.Next(i);
+ m_BucketsUsedByElement.Free(prevNode);
+ }
+
+ // Mark the list as empty
+ m_FirstBucket( element ) = m_BucketsUsedByElement.InvalidIndex();
+}
+
+//-----------------------------------------------------------------------------
+// Removes a bucket from all elements
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I >
+void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::RemoveBucket( CBucketHandlePram bucket )
+{
+ // Iterate over the list of all elements in the bucket
+ I i = m_FirstElement( bucket );
+ while (i != m_ElementsInBucket.InvalidIndex())
+ {
+ CElementHandlePram element = m_ElementsInBucket[i].m_Element;
+ I bucketListIndex = m_ElementsInBucket[i].m_BucketListIndex;
+
+ // Unhook the bucket from the element's list of buckets
+ if (bucketListIndex == m_FirstBucket(element))
+ m_FirstBucket(element) = m_BucketsUsedByElement.Next(bucketListIndex);
+ m_BucketsUsedByElement.Free(bucketListIndex);
+
+ // Remove the list element
+ I prevNode = i;
+ i = m_ElementsInBucket.Next(i);
+ m_ElementsInBucket.Free(prevNode);
+ }
+
+ // Mark the bucket list as empty
+ m_FirstElement( bucket ) = m_ElementsInBucket.InvalidIndex();
+}
+
+
+//-----------------------------------------------------------------------------
+// Ensure capacity
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I >
+void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::EnsureCapacity( int count )
+{
+ m_ElementsInBucket.EnsureCapacity( count );
+ m_BucketsUsedByElement.EnsureCapacity( count );
+}
+
+
+//-----------------------------------------------------------------------------
+// Deallocate....
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I >
+void CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::Purge()
+{
+ m_ElementsInBucket.Purge( );
+ m_BucketsUsedByElement.Purge( );
+}
+
+
+//-----------------------------------------------------------------------------
+// Number of elements allocated in each linked list (should be the same)
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I >
+int CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::NumAllocated( void ) const
+{
+ Assert( m_ElementsInBucket.NumAllocated() == m_BucketsUsedByElement.NumAllocated() );
+ return m_ElementsInBucket.NumAllocated();
+}
+
+
+//-----------------------------------------------------------------------------
+// Invalid index for iteration..
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I >
+inline S CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::InvalidIndex()
+{
+ return CUtlLinkedList< CElementHandle, I >::InvalidIndex();
+}
+
+
+//-----------------------------------------------------------------------------
+// Used to iterate elements in a bucket; I is the iterator
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I >
+inline I CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::FirstElement( CBucketHandlePram bucket ) const
+{
+ Assert( m_FirstElement );
+ return m_FirstElement(bucket);
+}
+
+template< class CBucketHandle, class CElementHandle, class S, class I >
+inline I CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::NextElement( I idx ) const
+{
+ return m_ElementsInBucket.Next(idx);
+}
+
+template< class CBucketHandle, class CElementHandle, class S, class I >
+inline CElementHandle CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::Element( I idx ) const
+{
+ return m_ElementsInBucket[idx].m_Element;
+}
+
+//-----------------------------------------------------------------------------
+// Used to iterate buckets an element lies in; I is the iterator
+//-----------------------------------------------------------------------------
+template< class CBucketHandle, class CElementHandle, class S, class I >
+inline I CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::FirstBucket( CElementHandlePram element ) const
+{
+ Assert( m_FirstBucket );
+ return m_FirstBucket(element);
+}
+
+template< class CBucketHandle, class CElementHandle, class S, class I >
+inline I CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::NextBucket( I idx ) const
+{
+ return m_BucketsUsedByElement.Next(idx);
+}
+
+template< class CBucketHandle, class CElementHandle, class S, class I >
+inline CBucketHandle CBidirectionalSet<CBucketHandle,CElementHandle,S,I>::Bucket( I idx ) const
+{
+ return m_BucketsUsedByElement[idx].m_Bucket;
+}
+
+#endif // UTLBIDIRECTIONALSET_H
diff --git a/public/tier1/utlbinaryblock.h b/public/tier1/utlbinaryblock.h
new file mode 100644
index 0000000..93c6e68
--- /dev/null
+++ b/public/tier1/utlbinaryblock.h
@@ -0,0 +1,107 @@
+//====== Copyright � 1996-2004, Valve Corporation, All rights reserved. =======
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef UTLBINARYBLOCK_H
+#define UTLBINARYBLOCK_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier1/utlmemory.h"
+#include "tier1/strtools.h"
+#include "limits.h"
+
+//-----------------------------------------------------------------------------
+// Base class, containing simple memory management
+//-----------------------------------------------------------------------------
+class CUtlBinaryBlock
+{
+public:
+ CUtlBinaryBlock( int growSize = 0, int initSize = 0 );
+
+ // NOTE: nInitialLength indicates how much of the buffer starts full
+ CUtlBinaryBlock( void* pMemory, int nSizeInBytes, int nInitialLength );
+ CUtlBinaryBlock( const void* pMemory, int nSizeInBytes );
+ CUtlBinaryBlock( const CUtlBinaryBlock& src );
+
+ void Get( void *pValue, int nMaxLen ) const;
+ void Set( const void *pValue, int nLen );
+ const void *Get( ) const;
+ void *Get( );
+
+ unsigned char& operator[]( int i );
+ const unsigned char& operator[]( int i ) const;
+
+ int Length() const;
+ void SetLength( int nLength ); // Undefined memory will result
+ bool IsEmpty() const;
+ void Clear();
+ void Purge();
+
+ bool IsReadOnly() const;
+
+ CUtlBinaryBlock &operator=( const CUtlBinaryBlock &src );
+
+ // Test for equality
+ bool operator==( const CUtlBinaryBlock &src ) const;
+
+private:
+ CUtlMemory<unsigned char> m_Memory;
+ int m_nActualLength;
+};
+
+
+//-----------------------------------------------------------------------------
+// class inlines
+//-----------------------------------------------------------------------------
+inline const void *CUtlBinaryBlock::Get( ) const
+{
+ return m_Memory.Base();
+}
+
+inline void *CUtlBinaryBlock::Get( )
+{
+ return m_Memory.Base();
+}
+
+inline int CUtlBinaryBlock::Length() const
+{
+ return m_nActualLength;
+}
+
+inline unsigned char& CUtlBinaryBlock::operator[]( int i )
+{
+ return m_Memory[i];
+}
+
+inline const unsigned char& CUtlBinaryBlock::operator[]( int i ) const
+{
+ return m_Memory[i];
+}
+
+inline bool CUtlBinaryBlock::IsReadOnly() const
+{
+ return m_Memory.IsReadOnly();
+}
+
+inline bool CUtlBinaryBlock::IsEmpty() const
+{
+ return Length() == 0;
+}
+
+inline void CUtlBinaryBlock::Clear()
+{
+ SetLength( 0 );
+}
+
+inline void CUtlBinaryBlock::Purge()
+{
+ SetLength( 0 );
+ m_Memory.Purge();
+}
+
+#endif // UTLBINARYBLOCK_H
+
diff --git a/public/tier1/utlblockmemory.h b/public/tier1/utlblockmemory.h
new file mode 100644
index 0000000..b4a254f
--- /dev/null
+++ b/public/tier1/utlblockmemory.h
@@ -0,0 +1,350 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+// A growable memory class.
+//===========================================================================//
+
+#ifndef UTLBLOCKMEMORY_H
+#define UTLBLOCKMEMORY_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/dbg.h"
+#include "tier0/platform.h"
+#include "mathlib/mathlib.h"
+
+#include "tier0/memalloc.h"
+#include "tier0/memdbgon.h"
+
+#pragma warning (disable:4100)
+#pragma warning (disable:4514)
+
+//-----------------------------------------------------------------------------
+
+#ifdef UTBLOCKLMEMORY_TRACK
+#define UTLBLOCKMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlBlockMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
+#define UTLBLOCKMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlBlockMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
+#else
+#define UTLBLOCKMEMORY_TRACK_ALLOC() ((void)0)
+#define UTLBLOCKMEMORY_TRACK_FREE() ((void)0)
+#endif
+
+
+//-----------------------------------------------------------------------------
+// The CUtlBlockMemory class:
+// A growable memory class that allocates non-sequential blocks, but is indexed sequentially
+//-----------------------------------------------------------------------------
+template< class T, class I >
+class CUtlBlockMemory
+{
+public:
+ // constructor, destructor
+ CUtlBlockMemory( int nGrowSize = 0, int nInitSize = 0 );
+ ~CUtlBlockMemory();
+
+ // Set the size by which the memory grows - round up to the next power of 2
+ void Init( int nGrowSize = 0, int nInitSize = 0 );
+
+ // here to match CUtlMemory, but only used by ResetDbgInfo, so it can just return NULL
+ T* Base() { return NULL; }
+ const T* Base() const { return NULL; }
+
+ class Iterator_t
+ {
+ public:
+ Iterator_t( I i ) : index( i ) {}
+ I index;
+
+ bool operator==( const Iterator_t it ) const { return index == it.index; }
+ bool operator!=( const Iterator_t it ) const { return index != it.index; }
+ };
+ Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); }
+ Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); }
+ I GetIndex( const Iterator_t &it ) const { return it.index; }
+ bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; }
+ bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); }
+ Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); }
+
+ // element access
+ T& operator[]( I i );
+ const T& operator[]( I i ) const;
+ T& Element( I i );
+ const T& Element( I i ) const;
+
+ // Can we use this index?
+ bool IsIdxValid( I i ) const;
+ static I InvalidIndex() { return ( I )-1; }
+
+ void Swap( CUtlBlockMemory< T, I > &mem );
+
+ // Size
+ int NumAllocated() const;
+ int Count() const { return NumAllocated(); }
+
+ // Grows memory by max(num,growsize) rounded up to the next power of 2, and returns the allocation index/ptr
+ void Grow( int num = 1 );
+
+ // Makes sure we've got at least this much memory
+ void EnsureCapacity( int num );
+
+ // Memory deallocation
+ void Purge();
+
+ // Purge all but the given number of elements
+ void Purge( int numElements );
+
+protected:
+ int Index( int major, int minor ) const { return ( major << m_nIndexShift ) | minor; }
+ int MajorIndex( int i ) const { return i >> m_nIndexShift; }
+ int MinorIndex( int i ) const { return i & m_nIndexMask; }
+ void ChangeSize( int nBlocks );
+ int NumElementsInBlock() const { return m_nIndexMask + 1; }
+
+ T** m_pMemory;
+ int m_nBlocks;
+ int m_nIndexMask : 27;
+ int m_nIndexShift : 5;
+};
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+
+template< class T, class I >
+CUtlBlockMemory<T,I>::CUtlBlockMemory( int nGrowSize, int nInitAllocationCount )
+: m_pMemory( 0 ), m_nBlocks( 0 ), m_nIndexMask( 0 ), m_nIndexShift( 0 )
+{
+ Init( nGrowSize, nInitAllocationCount );
+}
+
+template< class T, class I >
+CUtlBlockMemory<T,I>::~CUtlBlockMemory()
+{
+ Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+// Fast swap
+//-----------------------------------------------------------------------------
+template< class T, class I >
+void CUtlBlockMemory<T,I>::Swap( CUtlBlockMemory< T, I > &mem )
+{
+ swap( m_pMemory, mem.m_pMemory );
+ swap( m_nBlocks, mem.m_nBlocks );
+ swap( m_nIndexMask, mem.m_nIndexMask );
+ swap( m_nIndexShift, mem.m_nIndexShift );
+}
+
+
+//-----------------------------------------------------------------------------
+// Set the size by which the memory grows - round up to the next power of 2
+//-----------------------------------------------------------------------------
+template< class T, class I >
+void CUtlBlockMemory<T,I>::Init( int nGrowSize /* = 0 */, int nInitSize /* = 0 */ )
+{
+ Purge();
+
+ if ( nGrowSize == 0)
+ {
+ // default grow size is smallest size s.t. c++ allocation overhead is ~6% of block size
+ nGrowSize = ( 127 + sizeof( T ) ) / sizeof( T );
+ }
+ nGrowSize = SmallestPowerOfTwoGreaterOrEqual( nGrowSize );
+ m_nIndexMask = nGrowSize - 1;
+
+ m_nIndexShift = 0;
+ while ( nGrowSize > 1 )
+ {
+ nGrowSize >>= 1;
+ ++m_nIndexShift;
+ }
+ Assert( m_nIndexMask + 1 == ( 1 << m_nIndexShift ) );
+
+ Grow( nInitSize );
+}
+
+
+//-----------------------------------------------------------------------------
+// element access
+//-----------------------------------------------------------------------------
+template< class T, class I >
+inline T& CUtlBlockMemory<T,I>::operator[]( I i )
+{
+ Assert( IsIdxValid(i) );
+ T *pBlock = m_pMemory[ MajorIndex( i ) ];
+ return pBlock[ MinorIndex( i ) ];
+}
+
+template< class T, class I >
+inline const T& CUtlBlockMemory<T,I>::operator[]( I i ) const
+{
+ Assert( IsIdxValid(i) );
+ const T *pBlock = m_pMemory[ MajorIndex( i ) ];
+ return pBlock[ MinorIndex( i ) ];
+}
+
+template< class T, class I >
+inline T& CUtlBlockMemory<T,I>::Element( I i )
+{
+ Assert( IsIdxValid(i) );
+ T *pBlock = m_pMemory[ MajorIndex( i ) ];
+ return pBlock[ MinorIndex( i ) ];
+}
+
+template< class T, class I >
+inline const T& CUtlBlockMemory<T,I>::Element( I i ) const
+{
+ Assert( IsIdxValid(i) );
+ const T *pBlock = m_pMemory[ MajorIndex( i ) ];
+ return pBlock[ MinorIndex( i ) ];
+}
+
+
+//-----------------------------------------------------------------------------
+// Size
+//-----------------------------------------------------------------------------
+template< class T, class I >
+inline int CUtlBlockMemory<T,I>::NumAllocated() const
+{
+ return m_nBlocks * NumElementsInBlock();
+}
+
+
+//-----------------------------------------------------------------------------
+// Is element index valid?
+//-----------------------------------------------------------------------------
+template< class T, class I >
+inline bool CUtlBlockMemory<T,I>::IsIdxValid( I i ) const
+{
+ return ( i >= 0 ) && ( MajorIndex( i ) < m_nBlocks );
+}
+
+template< class T, class I >
+void CUtlBlockMemory<T,I>::Grow( int num )
+{
+ if ( num <= 0 )
+ return;
+
+ int nBlockSize = NumElementsInBlock();
+ int nBlocks = ( num + nBlockSize - 1 ) / nBlockSize;
+
+ ChangeSize( m_nBlocks + nBlocks );
+}
+
+template< class T, class I >
+void CUtlBlockMemory<T,I>::ChangeSize( int nBlocks )
+{
+ UTLBLOCKMEMORY_TRACK_FREE(); // this must stay before the recalculation of m_nBlocks, since it implicitly uses the old value
+
+ int nBlocksOld = m_nBlocks;
+ m_nBlocks = nBlocks;
+
+ UTLBLOCKMEMORY_TRACK_ALLOC(); // this must stay after the recalculation of m_nBlocks, since it implicitly uses the new value
+
+ if ( m_pMemory )
+ {
+ // free old blocks if shrinking
+ // Only possible if m_pMemory is non-NULL (and avoids PVS-Studio warning)
+ for ( int i = m_nBlocks; i < nBlocksOld; ++i )
+ {
+ UTLBLOCKMEMORY_TRACK_FREE();
+ free( (void*)m_pMemory[ i ] );
+ }
+
+ MEM_ALLOC_CREDIT_CLASS();
+ m_pMemory = (T**)realloc( m_pMemory, m_nBlocks * sizeof(T*) );
+ Assert( m_pMemory );
+ }
+ else
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ m_pMemory = (T**)malloc( m_nBlocks * sizeof(T*) );
+ Assert( m_pMemory );
+ }
+
+ if ( !m_pMemory )
+ {
+ Error( "CUtlBlockMemory overflow!\n" );
+ }
+
+ // allocate new blocks if growing
+ int nBlockSize = NumElementsInBlock();
+ for ( int i = nBlocksOld; i < m_nBlocks; ++i )
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ m_pMemory[ i ] = (T*)malloc( nBlockSize * sizeof( T ) );
+ Assert( m_pMemory[ i ] );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Makes sure we've got at least this much memory
+//-----------------------------------------------------------------------------
+template< class T, class I >
+inline void CUtlBlockMemory<T,I>::EnsureCapacity( int num )
+{
+ Grow( num - NumAllocated() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Memory deallocation
+//-----------------------------------------------------------------------------
+template< class T, class I >
+void CUtlBlockMemory<T,I>::Purge()
+{
+ if ( !m_pMemory )
+ return;
+
+ for ( int i = 0; i < m_nBlocks; ++i )
+ {
+ UTLBLOCKMEMORY_TRACK_FREE();
+ free( (void*)m_pMemory[ i ] );
+ }
+ m_nBlocks = 0;
+
+ UTLBLOCKMEMORY_TRACK_FREE();
+ free( (void*)m_pMemory );
+ m_pMemory = 0;
+}
+
+template< class T, class I >
+void CUtlBlockMemory<T,I>::Purge( int numElements )
+{
+ Assert( numElements >= 0 );
+
+ int nAllocated = NumAllocated();
+ if ( numElements > nAllocated )
+ {
+ // Ensure this isn't a grow request in disguise.
+ Assert( numElements <= nAllocated );
+ return;
+ }
+
+ if ( numElements <= 0 )
+ {
+ Purge();
+ return;
+ }
+
+ int nBlockSize = NumElementsInBlock();
+ int nBlocksOld = m_nBlocks;
+ int nBlocks = ( numElements + nBlockSize - 1 ) / nBlockSize;
+
+ // If the number of blocks is the same as the allocated number of blocks, we are done.
+ if ( nBlocks == m_nBlocks )
+ return;
+
+ ChangeSize( nBlocks );
+}
+
+#include "tier0/memdbgoff.h"
+
+#endif // UTLBLOCKMEMORY_H
diff --git a/public/tier1/utlbuffer.h b/public/tier1/utlbuffer.h
new file mode 100644
index 0000000..0de85fd
--- /dev/null
+++ b/public/tier1/utlbuffer.h
@@ -0,0 +1,1094 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+// Serialization/unserialization buffer
+//=============================================================================//
+
+#ifndef UTLBUFFER_H
+#define UTLBUFFER_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier1/utlmemory.h"
+#include "tier1/byteswap.h"
+#include <stdarg.h>
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+struct characterset_t;
+
+
+//-----------------------------------------------------------------------------
+// Description of character conversions for string output
+// Here's an example of how to use the macros to define a character conversion
+// BEGIN_CHAR_CONVERSION( CStringConversion, '\\' )
+// { '\n', "n" },
+// { '\t', "t" }
+// END_CHAR_CONVERSION( CStringConversion, '\\' )
+//-----------------------------------------------------------------------------
+class CUtlCharConversion
+{
+public:
+ struct ConversionArray_t
+ {
+ char m_nActualChar;
+ const char *m_pReplacementString;
+ };
+
+ CUtlCharConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray );
+ char GetEscapeChar() const;
+ const char *GetDelimiter() const;
+ int GetDelimiterLength() const;
+
+ const char *GetConversionString( char c ) const;
+ int GetConversionLength( char c ) const;
+ int MaxConversionLength() const;
+
+ // Finds a conversion for the passed-in string, returns length
+ virtual char FindConversion( const char *pString, int *pLength );
+
+protected:
+ struct ConversionInfo_t
+ {
+ int m_nLength;
+ const char *m_pReplacementString;
+ };
+
+ char m_nEscapeChar;
+ const char *m_pDelimiter;
+ int m_nDelimiterLength;
+ int m_nCount;
+ int m_nMaxConversionLength;
+ char m_pList[256];
+ ConversionInfo_t m_pReplacements[256];
+};
+
+#define BEGIN_CHAR_CONVERSION( _name, _delimiter, _escapeChar ) \
+ static CUtlCharConversion::ConversionArray_t s_pConversionArray ## _name[] = {
+
+#define END_CHAR_CONVERSION( _name, _delimiter, _escapeChar ) \
+ }; \
+ CUtlCharConversion _name( _escapeChar, _delimiter, sizeof( s_pConversionArray ## _name ) / sizeof( CUtlCharConversion::ConversionArray_t ), s_pConversionArray ## _name );
+
+#define BEGIN_CUSTOM_CHAR_CONVERSION( _className, _name, _delimiter, _escapeChar ) \
+ static CUtlCharConversion::ConversionArray_t s_pConversionArray ## _name[] = {
+
+#define END_CUSTOM_CHAR_CONVERSION( _className, _name, _delimiter, _escapeChar ) \
+ }; \
+ _className _name( _escapeChar, _delimiter, sizeof( s_pConversionArray ## _name ) / sizeof( CUtlCharConversion::ConversionArray_t ), s_pConversionArray ## _name );
+
+//-----------------------------------------------------------------------------
+// Character conversions for C strings
+//-----------------------------------------------------------------------------
+CUtlCharConversion *GetCStringCharConversion();
+
+//-----------------------------------------------------------------------------
+// Character conversions for quoted strings, with no escape sequences
+//-----------------------------------------------------------------------------
+CUtlCharConversion *GetNoEscCharConversion();
+
+
+//-----------------------------------------------------------------------------
+// Macro to set overflow functions easily
+//-----------------------------------------------------------------------------
+#define SetUtlBufferOverflowFuncs( _get, _put ) \
+ SetOverflowFuncs( static_cast <UtlBufferOverflowFunc_t>( _get ), static_cast <UtlBufferOverflowFunc_t>( _put ) )
+
+
+//-----------------------------------------------------------------------------
+// Command parsing..
+//-----------------------------------------------------------------------------
+class CUtlBuffer
+{
+public:
+ enum SeekType_t
+ {
+ SEEK_HEAD = 0,
+ SEEK_CURRENT,
+ SEEK_TAIL
+ };
+
+ // flags
+ enum BufferFlags_t
+ {
+ TEXT_BUFFER = 0x1, // Describes how get + put work (as strings, or binary)
+ EXTERNAL_GROWABLE = 0x2, // This is used w/ external buffers and causes the utlbuf to switch to reallocatable memory if an overflow happens when Putting.
+ CONTAINS_CRLF = 0x4, // For text buffers only, does this contain \n or \n\r?
+ READ_ONLY = 0x8, // For external buffers; prevents null termination from happening.
+ AUTO_TABS_DISABLED = 0x10, // Used to disable/enable push/pop tabs
+ };
+
+ // Overflow functions when a get or put overflows
+ typedef bool (CUtlBuffer::*UtlBufferOverflowFunc_t)( int nSize );
+
+ // Constructors for growable + external buffers for serialization/unserialization
+ 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 );
+
+ unsigned char GetFlags() const;
+
+ // NOTE: This will assert if you attempt to recast it in a way that
+ // is not compatible. The only valid conversion is binary-> text w/CRLF
+ void SetBufferType( bool bIsText, bool bContainsCRLF );
+
+ // Makes sure we've got at least this much memory
+ void EnsureCapacity( int num );
+
+ // 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 );
+
+ // copies data from another buffer
+ void CopyBuffer( const CUtlBuffer &buffer );
+ void CopyBuffer( const void *pubData, int cubData );
+
+ void Swap( CUtlBuffer &buf );
+ void Swap( CUtlMemory<uint8> &mem );
+
+ FORCEINLINE void ActivateByteSwappingIfBigEndian( void )
+ {
+ if ( IsX360() )
+ ActivateByteSwapping( true );
+ }
+
+
+ // Controls endian-ness of binary utlbufs - default matches the current platform
+ void ActivateByteSwapping( bool bActivate );
+ void SetBigEndian( bool bigEndian );
+ bool IsBigEndian( void );
+
+ // Resets the buffer; but doesn't free memory
+ void Clear();
+
+ // Clears out the buffer; frees memory
+ void Purge();
+
+ // 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.
+ // Text mode: it'll parse the file, turning text #s into real numbers.
+ // GetString will read a string until a space is reached
+ char GetChar( );
+ unsigned char GetUnsignedChar( );
+ short GetShort( );
+ unsigned short GetUnsignedShort( );
+ int GetInt( );
+ int64 GetInt64( );
+ int GetIntHex( );
+ unsigned int GetUnsignedInt( );
+ float GetFloat( );
+ double GetDouble( );
+ template <size_t maxLenInChars> void GetString( char( &pString )[maxLenInChars] )
+ {
+ GetStringInternal( pString, maxLenInChars );
+ }
+
+ void GetStringManualCharCount( char *pString, size_t maxLenInChars )
+ {
+ GetStringInternal( pString, maxLenInChars );
+ }
+
+ void Get( void* pMem, int size );
+ void GetLine( char* pLine, int nMaxChars = 0 );
+
+ // Used for getting objects that have a byteswap datadesc defined
+ template <typename T> void GetObjects( T *dest, int count = 1 );
+
+ // This will get at least 1 byte and up to nSize bytes.
+ // It will return the number of bytes actually read.
+ int GetUpTo( void *pMem, int nSize );
+
+ // This version of GetString converts \" to \\ and " to \, etc.
+ // It also reads a " at the beginning and end of the string
+ void GetDelimitedString( CUtlCharConversion *pConv, char *pString, int nMaxChars = 0 );
+ char GetDelimitedChar( CUtlCharConversion *pConv );
+
+ // This will return the # of characters of the string about to be read out
+ // NOTE: The count will *include* the terminating 0!!
+ // In binary mode, it's the number of characters until the next 0
+ // In text mode, it's the number of characters until the next space.
+ int PeekStringLength();
+
+ // This version of PeekStringLength converts \" to \\ and " to \, etc.
+ // It also reads a " at the beginning and end of the string
+ // NOTE: The count will *include* the terminating 0!!
+ // In binary mode, it's the number of characters until the next 0
+ // In text mode, it's the number of characters between "s (checking for \")
+ // Specifying false for bActualSize will return the pre-translated number of characters
+ // including the delimiters and the escape characters. So, \n counts as 2 characters when bActualSize == false
+ // and only 1 character when bActualSize == true
+ int PeekDelimitedStringLength( CUtlCharConversion *pConv, bool bActualSize = true );
+
+ // 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 );
+
+ // Eats white space, advances Get index
+ void EatWhiteSpace();
+
+ // Eats C++ style comments
+ bool EatCPPComment();
+
+ // (For text buffers only)
+ // Parse a token from the buffer:
+ // Grab all text that lies between a starting delimiter + ending delimiter
+ // (skipping whitespace that leads + trails both delimiters).
+ // If successful, the get index is advanced and the function returns true,
+ // otherwise the index is not advanced and the function returns false.
+ bool ParseToken( const char *pStartingDelim, const char *pEndingDelim, char* pString, int nMaxLen );
+
+ // Advance the get index until after the particular string is found
+ // Do not eat whitespace before starting. Return false if it failed
+ // String test is case-insensitive.
+ bool GetToken( const char *pToken );
+
+ // Parses the next token, given a set of character breaks to stop at
+ // Returns the length of the token parsed in bytes (-1 if none parsed)
+ int ParseToken( characterset_t *pBreaks, char *pTokenBuf, int nMaxLen, bool bParseComments = true );
+
+ // Write stuff in
+ // Binary mode: it'll just write the bits directly in, and strings will be
+ // written with a null terminating character
+ // Text mode: it'll convert the numbers to text versions
+ // 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 PutFloat( float f );
+ void PutDouble( double d );
+ void PutString( const char* pString );
+ void Put( const void* pMem, int size );
+
+ // Used for putting objects that have a byteswap datadesc defined
+ template <typename T> void PutObjects( T *src, int count = 1 );
+
+ // This version of PutString converts \ to \\ and " to \", etc.
+ // It also places " at the beginning and end of the string
+ void PutDelimitedString( CUtlCharConversion *pConv, const char *pString );
+ void PutDelimitedChar( CUtlCharConversion *pConv, char c );
+
+ // Just like printf, writes a terminating zero in binary mode
+ void Printf( PRINTF_FORMAT_STRING const char* pFmt, ... ) FMTFUNCTION( 2, 3 );
+ void VaPrintf( const char* pFmt, va_list list );
+
+ // What am I writing (put)/reading (get)?
+ void* PeekPut( int offset = 0 );
+ const void* PeekGet( int offset = 0 ) const;
+ const void* PeekGet( int nMaxSize, int nOffset );
+
+ // Where am I writing (put)/reading (get)?
+ int TellPut( ) const;
+ int TellGet( ) const;
+
+ // What's the most I've ever written?
+ int TellMaxPut( ) const;
+
+ // How many bytes remain to be read?
+ // NOTE: This is not accurate for streaming text files; it overshoots
+ int GetBytesRemaining() const;
+
+ // Change where I'm writing (put)/reading (get)
+ void SeekPut( SeekType_t type, int offset );
+ void SeekGet( SeekType_t type, int offset );
+
+ // Buffer base
+ const void* Base() const;
+ void* Base();
+ // Returns the base as a const char*, only valid in text mode.
+ const char *String() const;
+
+ // memory allocation size, does *not* reflect size written or read,
+ // use TellPut or TellGet for that
+ int Size() const;
+
+ // Am I a text buffer?
+ bool IsText() const;
+
+ // Can I grow if I'm externally allocated?
+ bool IsGrowable() const;
+
+ // Am I valid? (overflow or underflow error), Once invalid it stays invalid
+ bool IsValid() const;
+
+ // Do I contain carriage return/linefeeds?
+ bool ContainsCRLF() const;
+
+ // Am I read-only
+ bool IsReadOnly() const;
+
+ // Converts a buffer from a CRLF buffer to a CR buffer (and back)
+ // Returns false if no conversion was necessary (and outBuf is left untouched)
+ // If the conversion occurs, outBuf will be cleared.
+ bool ConvertCRLF( CUtlBuffer &outBuf );
+
+ // Push/pop pretty-printing tabs
+ void PushTab();
+ void PopTab();
+
+ // Temporarily disables pretty print
+ void EnableTabs( bool bEnable );
+
+protected:
+ // error flags
+ enum
+ {
+ PUT_OVERFLOW = 0x1,
+ GET_OVERFLOW = 0x2,
+ MAX_ERROR_FLAG = GET_OVERFLOW,
+ };
+
+ void SetOverflowFuncs( UtlBufferOverflowFunc_t getFunc, UtlBufferOverflowFunc_t putFunc );
+
+ bool OnPutOverflow( int nSize );
+ bool OnGetOverflow( int nSize );
+
+protected:
+ // Checks if a get/put is ok
+ bool CheckPut( int size );
+ bool CheckGet( int size );
+
+ void AddNullTermination( );
+
+ // Methods to help with pretty-printing
+ bool WasLastCharacterCR();
+ void PutTabs();
+
+ // Help with delimited stuff
+ char GetDelimitedCharInternal( CUtlCharConversion *pConv );
+ void PutDelimitedCharInternal( CUtlCharConversion *pConv, char c );
+
+ // Default overflow funcs
+ bool PutOverflow( int nSize );
+ bool GetOverflow( int nSize );
+
+ // Does the next bytes of the buffer match a pattern?
+ bool PeekStringMatch( int nOffset, const char *pString, int nLen );
+
+ // Peek size of line to come, check memory bound
+ int PeekLineLength();
+
+ // How much whitespace should I skip?
+ int PeekWhiteSpace( int nOffset );
+
+ // Checks if a peek get is ok
+ bool CheckPeekGet( int nOffset, int nSize );
+
+ // 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 GetTypeBin( T& dest );
+ template <typename T> void GetObject( T *src );
+
+ template <typename T> void PutType( T src, const char *pszFmt );
+ template <typename T> void PutTypeBin( T src );
+ template <typename T> void PutObject( T *src );
+
+ CUtlMemory<unsigned char> m_Memory;
+ int m_Get;
+ int m_Put;
+
+ unsigned char m_Error;
+ unsigned char m_Flags;
+ unsigned char m_Reserved;
+#if defined( _X360 )
+ unsigned char pad;
+#endif
+
+ int m_nTab;
+ int m_nMaxPut;
+ int m_nOffset;
+
+ UtlBufferOverflowFunc_t m_GetOverflowFunc;
+ UtlBufferOverflowFunc_t m_PutOverflowFunc;
+
+ CByteswap m_Byteswap;
+};
+
+
+// Stream style output operators for CUtlBuffer
+inline CUtlBuffer &operator<<( CUtlBuffer &b, char v )
+{
+ b.PutChar( v );
+ return b;
+}
+
+inline CUtlBuffer &operator<<( CUtlBuffer &b, unsigned char v )
+{
+ b.PutUnsignedChar( v );
+ return b;
+}
+
+inline CUtlBuffer &operator<<( CUtlBuffer &b, short v )
+{
+ b.PutShort( v );
+ return b;
+}
+
+inline CUtlBuffer &operator<<( CUtlBuffer &b, unsigned short v )
+{
+ b.PutUnsignedShort( v );
+ return b;
+}
+
+inline CUtlBuffer &operator<<( CUtlBuffer &b, int v )
+{
+ b.PutInt( v );
+ return b;
+}
+
+inline CUtlBuffer &operator<<( CUtlBuffer &b, unsigned int v )
+{
+ b.PutUnsignedInt( v );
+ return b;
+}
+
+inline CUtlBuffer &operator<<( CUtlBuffer &b, float v )
+{
+ b.PutFloat( v );
+ return b;
+}
+
+inline CUtlBuffer &operator<<( CUtlBuffer &b, double v )
+{
+ b.PutDouble( v );
+ return b;
+}
+
+inline CUtlBuffer &operator<<( CUtlBuffer &b, const char *pv )
+{
+ b.PutString( pv );
+ return b;
+}
+
+inline CUtlBuffer &operator<<( CUtlBuffer &b, const Vector &v )
+{
+ b << v.x << " " << v.y << " " << v.z;
+ return b;
+}
+
+inline CUtlBuffer &operator<<( CUtlBuffer &b, const Vector2D &v )
+{
+ b << v.x << " " << v.y;
+ return b;
+}
+
+
+class CUtlInplaceBuffer : public CUtlBuffer
+{
+public:
+ CUtlInplaceBuffer( int growSize = 0, int initSize = 0, int nFlags = 0 );
+
+ //
+ // Routines returning buffer-inplace-pointers
+ //
+public:
+ //
+ // Upon success, determines the line length, fills out the pointer to the
+ // beginning of the line and the line length, advances the "get" pointer
+ // offset by the line length and returns "true".
+ //
+ // If end of file is reached or upon error returns "false".
+ //
+ // Note: the returned length of the line is at least one character because the
+ // trailing newline characters are also included as part of the line.
+ //
+ // Note: the pointer returned points into the local memory of this buffer, in
+ // case the buffer gets relocated or destroyed the pointer becomes invalid.
+ //
+ // e.g.: -------------
+ //
+ // char *pszLine;
+ // int nLineLen;
+ // while ( pUtlInplaceBuffer->InplaceGetLinePtr( &pszLine, &nLineLen ) )
+ // {
+ // ...
+ // }
+ //
+ // -------------
+ //
+ // @param ppszInBufferPtr on return points into this buffer at start of line
+ // @param pnLineLength on return holds num bytes accessible via (*ppszInBufferPtr)
+ //
+ // @returns true if line was successfully read
+ // false when EOF is reached or error occurs
+ //
+ bool InplaceGetLinePtr( /* out */ char **ppszInBufferPtr, /* out */ int *pnLineLength );
+
+ //
+ // Determines the line length, advances the "get" pointer offset by the line length,
+ // replaces the newline character with null-terminator and returns the initial pointer
+ // to now null-terminated line.
+ //
+ // If end of file is reached or upon error returns NULL.
+ //
+ // Note: the pointer returned points into the local memory of this buffer, in
+ // case the buffer gets relocated or destroyed the pointer becomes invalid.
+ //
+ // e.g.: -------------
+ //
+ // while ( char *pszLine = pUtlInplaceBuffer->InplaceGetLinePtr() )
+ // {
+ // ...
+ // }
+ //
+ // -------------
+ //
+ // @returns ptr-to-zero-terminated-line if line was successfully read and buffer modified
+ // NULL when EOF is reached or error occurs
+ //
+ char * InplaceGetLinePtr( void );
+};
+
+
+//-----------------------------------------------------------------------------
+// Where am I reading?
+//-----------------------------------------------------------------------------
+inline int CUtlBuffer::TellGet( ) const
+{
+ return m_Get;
+}
+
+
+//-----------------------------------------------------------------------------
+// How many bytes remain to be read?
+//-----------------------------------------------------------------------------
+inline int CUtlBuffer::GetBytesRemaining() const
+{
+ return m_nMaxPut - TellGet();
+}
+
+
+//-----------------------------------------------------------------------------
+// What am I reading?
+//-----------------------------------------------------------------------------
+inline const void* CUtlBuffer::PeekGet( int offset ) const
+{
+ return &m_Memory[ m_Get + offset - m_nOffset ];
+}
+
+
+//-----------------------------------------------------------------------------
+// Unserialization
+//-----------------------------------------------------------------------------
+
+template <typename T>
+inline void CUtlBuffer::GetObject( T *dest )
+{
+ if ( CheckGet( sizeof(T) ) )
+ {
+ if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) )
+ {
+ *dest = *(T *)PeekGet();
+ }
+ else
+ {
+ m_Byteswap.SwapFieldsToTargetEndian<T>( dest, (T*)PeekGet() );
+ }
+ m_Get += sizeof(T);
+ }
+ else
+ {
+ Q_memset( dest, 0, sizeof(T) );
+ }
+}
+
+
+template <typename T>
+inline void CUtlBuffer::GetObjects( T *dest, int count )
+{
+ for ( int i = 0; i < count; ++i, ++dest )
+ {
+ GetObject<T>( dest );
+ }
+}
+
+
+template <typename T>
+inline void CUtlBuffer::GetTypeBin( T &dest )
+{
+ if ( CheckGet( sizeof(T) ) )
+ {
+ if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) )
+ {
+ dest = *(T *)PeekGet();
+ }
+ else
+ {
+ m_Byteswap.SwapBufferToTargetEndian<T>( &dest, (T*)PeekGet() );
+ }
+ m_Get += sizeof(T);
+ }
+ else
+ {
+ dest = 0;
+ }
+}
+
+template <>
+inline void CUtlBuffer::GetTypeBin< float >( float &dest )
+{
+ if ( CheckGet( sizeof( float ) ) )
+ {
+ uintptr_t pData = (uintptr_t)PeekGet();
+ if ( IsX360() && ( pData & 0x03 ) )
+ {
+ // 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];
+ }
+ else
+ {
+ // aligned read
+ dest = *(float *)pData;
+ }
+ if ( m_Byteswap.IsSwappingBytes() )
+ {
+ m_Byteswap.SwapBufferToTargetEndian< float >( &dest, &dest );
+ }
+ m_Get += sizeof( float );
+ }
+ else
+ {
+ dest = 0;
+ }
+}
+
+template <typename T>
+inline void CUtlBuffer::GetType( T &dest, const char *pszFmt )
+{
+ if (!IsText())
+ {
+ GetTypeBin( dest );
+ }
+ else
+ {
+ dest = 0;
+ Scanf( pszFmt, &dest );
+ }
+}
+
+inline char CUtlBuffer::GetChar( )
+{
+ char c;
+ GetType( c, "%c" );
+ return c;
+}
+
+inline unsigned char CUtlBuffer::GetUnsignedChar( )
+{
+ unsigned char c;
+ GetType( c, "%u" );
+ return c;
+}
+
+inline short CUtlBuffer::GetShort( )
+{
+ short s;
+ GetType( s, "%d" );
+ return s;
+}
+
+inline unsigned short CUtlBuffer::GetUnsignedShort( )
+{
+ unsigned short s;
+ GetType( s, "%u" );
+ return s;
+}
+
+inline int CUtlBuffer::GetInt( )
+{
+ int i;
+ GetType( i, "%d" );
+ return i;
+}
+
+inline int64 CUtlBuffer::GetInt64( )
+{
+ int64 i;
+ GetType( i, "%lld" );
+ return i;
+}
+
+inline int CUtlBuffer::GetIntHex( )
+{
+ int i;
+ GetType( i, "%x" );
+ return i;
+}
+
+inline unsigned int CUtlBuffer::GetUnsignedInt( )
+{
+ unsigned int u;
+ GetType( u, "%u" );
+ return u;
+}
+
+inline float CUtlBuffer::GetFloat( )
+{
+ float f;
+ GetType( f, "%f" );
+ return f;
+}
+
+inline double CUtlBuffer::GetDouble( )
+{
+ double d;
+ GetType( d, "%f" );
+ return d;
+}
+
+
+//-----------------------------------------------------------------------------
+// Where am I writing?
+//-----------------------------------------------------------------------------
+inline unsigned char CUtlBuffer::GetFlags() const
+{
+ return m_Flags;
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+inline bool CUtlBuffer::IsExternallyAllocated() const
+{
+ return m_Memory.IsExternallyAllocated();
+}
+
+
+//-----------------------------------------------------------------------------
+// Where am I writing?
+//-----------------------------------------------------------------------------
+inline int CUtlBuffer::TellPut( ) const
+{
+ return m_Put;
+}
+
+
+//-----------------------------------------------------------------------------
+// What's the most I've ever written?
+//-----------------------------------------------------------------------------
+inline int CUtlBuffer::TellMaxPut( ) const
+{
+ return m_nMaxPut;
+}
+
+
+//-----------------------------------------------------------------------------
+// What am I reading?
+//-----------------------------------------------------------------------------
+inline void* CUtlBuffer::PeekPut( int offset )
+{
+ return &m_Memory[m_Put + offset - m_nOffset];
+}
+
+
+//-----------------------------------------------------------------------------
+// Various put methods
+//-----------------------------------------------------------------------------
+
+template <typename T>
+inline void CUtlBuffer::PutObject( T *src )
+{
+ if ( CheckPut( sizeof(T) ) )
+ {
+ if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) )
+ {
+ *(T *)PeekPut() = *src;
+ }
+ else
+ {
+ m_Byteswap.SwapFieldsToTargetEndian<T>( (T*)PeekPut(), src );
+ }
+ m_Put += sizeof(T);
+ AddNullTermination();
+ }
+}
+
+
+template <typename T>
+inline void CUtlBuffer::PutObjects( T *src, int count )
+{
+ for ( int i = 0; i < count; ++i, ++src )
+ {
+ PutObject<T>( src );
+ }
+}
+
+
+template <typename T>
+inline void CUtlBuffer::PutTypeBin( T src )
+{
+ if ( CheckPut( sizeof(T) ) )
+ {
+ if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) )
+ {
+ *(T *)PeekPut() = src;
+ }
+ else
+ {
+ m_Byteswap.SwapBufferToTargetEndian<T>( (T*)PeekPut(), &src );
+ }
+ m_Put += sizeof(T);
+ AddNullTermination();
+ }
+}
+
+template <typename T>
+inline void CUtlBuffer::PutType( T src, const char *pszFmt )
+{
+ if (!IsText())
+ {
+ PutTypeBin( src );
+ }
+ else
+ {
+ Printf( pszFmt, src );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Methods to help with pretty-printing
+//-----------------------------------------------------------------------------
+inline bool CUtlBuffer::WasLastCharacterCR()
+{
+ if ( !IsText() || (TellPut() == 0) )
+ return false;
+ return ( *( const char * )PeekPut( -1 ) == '\n' );
+}
+
+inline void CUtlBuffer::PutTabs()
+{
+ int nTabCount = ( m_Flags & AUTO_TABS_DISABLED ) ? 0 : m_nTab;
+ for (int i = nTabCount; --i >= 0; )
+ {
+ PutTypeBin<char>( '\t' );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Push/pop pretty-printing tabs
+//-----------------------------------------------------------------------------
+inline void CUtlBuffer::PushTab( )
+{
+ ++m_nTab;
+}
+
+inline void CUtlBuffer::PopTab()
+{
+ if ( --m_nTab < 0 )
+ {
+ m_nTab = 0;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Temporarily disables pretty print
+//-----------------------------------------------------------------------------
+inline void CUtlBuffer::EnableTabs( bool bEnable )
+{
+ if ( bEnable )
+ {
+ m_Flags &= ~AUTO_TABS_DISABLED;
+ }
+ else
+ {
+ m_Flags |= AUTO_TABS_DISABLED;
+ }
+}
+
+inline void CUtlBuffer::PutChar( char c )
+{
+ if ( WasLastCharacterCR() )
+ {
+ PutTabs();
+ }
+
+ PutTypeBin( 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" );
+}
+
+inline void CUtlBuffer::PutShort( short s )
+{
+ PutType( s, "%d" );
+}
+
+inline void CUtlBuffer::PutUnsignedShort( unsigned short s )
+{
+ PutType( s, "%u" );
+}
+
+inline void CUtlBuffer::PutInt( int i )
+{
+ PutType( i, "%d" );
+}
+
+inline void CUtlBuffer::PutInt64( int64 i )
+{
+ PutType( i, "%llu" );
+}
+
+inline void CUtlBuffer::PutUnsignedInt( unsigned int u )
+{
+ PutType( u, "%u" );
+}
+
+inline void CUtlBuffer::PutFloat( float f )
+{
+ PutType( f, "%f" );
+}
+
+inline void CUtlBuffer::PutDouble( double d )
+{
+ PutType( d, "%f" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Am I a text buffer?
+//-----------------------------------------------------------------------------
+inline bool CUtlBuffer::IsText() const
+{
+ return (m_Flags & TEXT_BUFFER) != 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Can I grow if I'm externally allocated?
+//-----------------------------------------------------------------------------
+inline bool CUtlBuffer::IsGrowable() const
+{
+ return (m_Flags & EXTERNAL_GROWABLE) != 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Am I valid? (overflow or underflow error), Once invalid it stays invalid
+//-----------------------------------------------------------------------------
+inline bool CUtlBuffer::IsValid() const
+{
+ return m_Error == 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Do I contain carriage return/linefeeds?
+//-----------------------------------------------------------------------------
+inline bool CUtlBuffer::ContainsCRLF() const
+{
+ return IsText() && ((m_Flags & CONTAINS_CRLF) != 0);
+}
+
+
+//-----------------------------------------------------------------------------
+// Am I read-only
+//-----------------------------------------------------------------------------
+inline bool CUtlBuffer::IsReadOnly() const
+{
+ return (m_Flags & READ_ONLY) != 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Buffer base and size
+//-----------------------------------------------------------------------------
+inline const void* CUtlBuffer::Base() const
+{
+ return m_Memory.Base();
+}
+
+inline void* CUtlBuffer::Base()
+{
+ return m_Memory.Base();
+}
+
+// Returns the base as a const char*, only valid in text mode.
+inline const char *CUtlBuffer::String() const
+{
+ Assert( IsText() );
+ return reinterpret_cast<const char*>( m_Memory.Base() );
+}
+
+inline int CUtlBuffer::Size() const
+{
+ return m_Memory.NumAllocated();
+}
+
+
+//-----------------------------------------------------------------------------
+// Clears out the buffer; frees memory
+//-----------------------------------------------------------------------------
+inline void CUtlBuffer::Clear()
+{
+ m_Get = 0;
+ m_Put = 0;
+ m_Error = 0;
+ m_nOffset = 0;
+ m_nMaxPut = -1;
+ AddNullTermination();
+}
+
+inline void CUtlBuffer::Purge()
+{
+ m_Get = 0;
+ m_Put = 0;
+ m_nOffset = 0;
+ m_nMaxPut = 0;
+ m_Error = 0;
+ m_Memory.Purge();
+}
+
+inline void CUtlBuffer::CopyBuffer( const CUtlBuffer &buffer )
+{
+ CopyBuffer( buffer.Base(), buffer.TellPut() );
+}
+
+inline void CUtlBuffer::CopyBuffer( const void *pubData, int cubData )
+{
+ Clear();
+ if ( cubData )
+ {
+ Put( pubData, cubData );
+ }
+}
+
+#endif // UTLBUFFER_H
+
diff --git a/public/tier1/utlbufferutil.h b/public/tier1/utlbufferutil.h
new file mode 100644
index 0000000..a52a528
--- /dev/null
+++ b/public/tier1/utlbufferutil.h
@@ -0,0 +1,192 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+// Utilities for serialization/unserialization buffer
+//=============================================================================//
+
+#ifndef UTLBUFFERUTIL_H
+#define UTLBUFFERUTIL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier1/utlvector.h"
+#include "tier1/utlbuffer.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class Vector2D;
+class Vector;
+class Vector4D;
+class QAngle;
+class Quaternion;
+class VMatrix;
+class Color;
+class CUtlBinaryBlock;
+class CUtlString;
+class CUtlCharConversion;
+
+
+//-----------------------------------------------------------------------------
+// For string serialization, set the delimiter rules
+//-----------------------------------------------------------------------------
+void SetSerializationDelimiter( CUtlCharConversion *pConv );
+void SetSerializationArrayDelimiter( const char *pDelimiter );
+
+
+//-----------------------------------------------------------------------------
+// Standard serialization methods for basic types
+//-----------------------------------------------------------------------------
+bool Serialize( CUtlBuffer &buf, const bool &src );
+bool Unserialize( CUtlBuffer &buf, bool &dest );
+
+bool Serialize( CUtlBuffer &buf, const int &src );
+bool Unserialize( CUtlBuffer &buf, int &dest );
+
+bool Serialize( CUtlBuffer &buf, const float &src );
+bool Unserialize( CUtlBuffer &buf, float &dest );
+
+bool Serialize( CUtlBuffer &buf, const Vector2D &src );
+bool Unserialize( CUtlBuffer &buf, Vector2D &dest );
+
+bool Serialize( CUtlBuffer &buf, const Vector &src );
+bool Unserialize( CUtlBuffer &buf, Vector &dest );
+
+bool Serialize( CUtlBuffer &buf, const Vector4D &src );
+bool Unserialize( CUtlBuffer &buf, Vector4D &dest );
+
+bool Serialize( CUtlBuffer &buf, const QAngle &src );
+bool Unserialize( CUtlBuffer &buf, QAngle &dest );
+
+bool Serialize( CUtlBuffer &buf, const Quaternion &src );
+bool Unserialize( CUtlBuffer &buf, Quaternion &dest );
+
+bool Serialize( CUtlBuffer &buf, const VMatrix &src );
+bool Unserialize( CUtlBuffer &buf, VMatrix &dest );
+
+bool Serialize( CUtlBuffer &buf, const Color &src );
+bool Unserialize( CUtlBuffer &buf, Color &dest );
+
+bool Serialize( CUtlBuffer &buf, const CUtlBinaryBlock &src );
+bool Unserialize( CUtlBuffer &buf, CUtlBinaryBlock &dest );
+
+bool Serialize( CUtlBuffer &buf, const CUtlString &src );
+bool Unserialize( CUtlBuffer &buf, CUtlString &dest );
+
+
+//-----------------------------------------------------------------------------
+// You can use this to check if a type serializes on multiple lines
+//-----------------------------------------------------------------------------
+template< class T >
+inline bool SerializesOnMultipleLines()
+{
+ return false;
+}
+
+template< >
+inline bool SerializesOnMultipleLines<VMatrix>()
+{
+ return true;
+}
+
+template< >
+inline bool SerializesOnMultipleLines<CUtlBinaryBlock>()
+{
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Vector serialization
+//-----------------------------------------------------------------------------
+template< class T >
+bool Serialize( CUtlBuffer &buf, const CUtlVector<T> &src )
+{
+ extern const char *s_pUtlBufferUtilArrayDelim;
+
+ int nCount = src.Count();
+
+ if ( !buf.IsText() )
+ {
+ buf.PutInt( nCount );
+ for ( int i = 0; i < nCount; ++i )
+ {
+ ::Serialize( buf, src[i] );
+ }
+ return buf.IsValid();
+ }
+
+ if ( !SerializesOnMultipleLines<T>() )
+ {
+ buf.PutChar('\n');
+ for ( int i = 0; i < nCount; ++i )
+ {
+ ::Serialize( buf, src[i] );
+ if ( s_pUtlBufferUtilArrayDelim && (i != nCount-1) )
+ {
+ buf.PutString( s_pUtlBufferUtilArrayDelim );
+ }
+ buf.PutChar('\n');
+ }
+ }
+ else
+ {
+ for ( int i = 0; i < nCount; ++i )
+ {
+ ::Serialize( buf, src[i] );
+ if ( s_pUtlBufferUtilArrayDelim && (i != nCount-1) )
+ {
+ buf.PutString( s_pUtlBufferUtilArrayDelim );
+ }
+ buf.PutChar(' ');
+ }
+ }
+
+ return buf.IsValid();
+}
+
+template< class T >
+bool Unserialize( CUtlBuffer &buf, CUtlVector<T> &dest )
+{
+ dest.RemoveAll();
+
+ MEM_ALLOC_CREDIT_FUNCTION();
+
+ if ( !buf.IsText() )
+ {
+ int nCount = buf.GetInt();
+ if ( nCount )
+ {
+ dest.EnsureCapacity( nCount );
+ for ( int i = 0; i < nCount; ++i )
+ {
+ VerifyEquals( dest.AddToTail(), i );
+ if ( !::Unserialize( buf, dest[i] ) )
+ return false;
+ }
+ }
+ return buf.IsValid();
+ }
+
+ while ( true )
+ {
+ buf.EatWhiteSpace();
+ if ( !buf.IsValid() )
+ break;
+
+ int i = dest.AddToTail( );
+ if ( ! ::Unserialize( buf, dest[i] ) )
+ return false;
+ }
+ return true;
+}
+
+
+#endif // UTLBUFFERUTIL_H
+
diff --git a/public/tier1/utlcommon.h b/public/tier1/utlcommon.h
new file mode 100644
index 0000000..23e67f0
--- /dev/null
+++ b/public/tier1/utlcommon.h
@@ -0,0 +1,371 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: common helpers for reuse among various Utl containers
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#ifndef UTLCOMMON_H
+#define UTLCOMMON_H
+#pragma once
+
+//-----------------------------------------------------------------------------
+// Henry Goffin (henryg) was here. Questions? Bugs? Go slap him around a bit.
+//-----------------------------------------------------------------------------
+
+// empty_t is the canonical "no-value" type which is fully defined but empty.
+struct empty_t {};
+
+// undefined_t is the canonical "undefined" type, used mostly for typedefs;
+// parameters of type undefined_t will not compile, which is actually useful
+// behavior when it comes to template programming. Google "SFINAE" for info.
+struct undefined_t;
+
+// CTypeSelect<sel,A,B>::type is a typedef of A if sel is nonzero, else B
+template <int sel, typename A, typename B>
+struct CTypeSelect { typedef A type; };
+
+template <typename A, typename B>
+struct CTypeSelect<0, A, B> { typedef B type; };
+
+// CTypeEquals<A, B>::value is nonzero if A and B are the same type
+template <typename A, typename B, bool bIgnoreConstVolatile = false, bool bIgnoreReference = false>
+struct CTypeEquals { enum { value = 0 }; };
+
+template <typename Same>
+struct CTypeEquals<Same, Same, false, false> { enum { value = 1 }; };
+
+template <typename A, typename B>
+struct CTypeEquals<A, B, true, true> : CTypeEquals< const volatile A&, const volatile B& > {};
+
+template <typename A, typename B>
+struct CTypeEquals<A, B, true, false> : CTypeEquals< const volatile A, const volatile B > {};
+
+template <typename A, typename B>
+struct CTypeEquals<A, B, false, true> : CTypeEquals< A&, B& > {};
+
+// CUtlKeyValuePair is intended for use with key-lookup containers.
+// Because it is specialized for "empty_t" values, one container can
+// function as either a set of keys OR a key-value dictionary while
+// avoiding storage waste or padding for the empty_t value objects.
+template <typename K, typename V>
+class CUtlKeyValuePair
+{
+public:
+ typedef V ValueReturn_t;
+ K m_key;
+ V m_value;
+
+ CUtlKeyValuePair() {}
+
+ template < typename KInit >
+ explicit CUtlKeyValuePair( const KInit &k ) : m_key( k ) {}
+
+ template < typename KInit, typename VInit >
+ CUtlKeyValuePair( const KInit &k, const VInit &v ) : m_key( k ), m_value( v ) {}
+
+ V &GetValue() { return m_value; }
+ const V &GetValue() const { return m_value; }
+};
+
+template <typename K>
+class CUtlKeyValuePair<K, empty_t>
+{
+public:
+ typedef const K ValueReturn_t;
+ K m_key;
+
+ CUtlKeyValuePair() {}
+
+ template < typename KInit >
+ explicit CUtlKeyValuePair( const KInit &k ) : m_key( k ) {}
+
+ template < typename KInit >
+ CUtlKeyValuePair( const KInit &k, empty_t ) : m_key( k ) {}
+
+ CUtlKeyValuePair( const K &k, const empty_t& ) : m_key( k ) {}
+ const K &GetValue() const { return m_key; }
+};
+
+
+// Default functors. You can specialize these if your type does
+// not implement operator== or operator< in an efficient way for
+// some odd reason.
+template <typename T> struct DefaultLessFunctor;
+template <typename T> struct DefaultEqualFunctor;
+
+// Hashing functor used by hash tables. You can either specialize
+// for types which are widely used, or plug a custom functor directly
+// into the hash table. If you do roll your own, please read up on
+// bit-mixing and the avalanche property; be sure that your values
+// are reasonably well-distributed across the entire 32-bit range.
+// http://en.wikipedia.org/wiki/Avalanche_effect
+// http://home.comcast.net/~bretm/hash/5.html
+//
+template <typename T> struct DefaultHashFunctor;
+
+// Argument type information. Struct currently contains one or two typedefs:
+// typename Arg_t = primary argument type. Usually const T&, sometimes T.
+// typename Alt_t = optional alternate type. Usually *undefined*.
+//
+// Any specializations should be implemented via simple inheritance
+// from ArgumentTypeInfoImpl< BestArgType, [optional] AlternateArgType >
+//
+template <typename T> struct ArgumentTypeInfo;
+
+
+// Some fundamental building-block functors...
+struct StringLessFunctor { bool operator()( const char *a, const char *b ) const { return Q_strcmp( a, b ) < 0; } };
+struct StringEqualFunctor { bool operator()( const char *a, const char *b ) const { return Q_strcmp( a, b ) == 0; } };
+struct CaselessStringLessFunctor { bool operator()( const char *a, const char *b ) const { return Q_strcasecmp( a, b ) < 0; } };
+struct CaselessStringEqualFunctor { bool operator()( const char *a, const char *b ) const { return Q_strcasecmp( a, b ) == 0; } };
+
+struct Mix32HashFunctor { unsigned int operator()( uint32 s ) const; };
+struct Mix64HashFunctor { unsigned int operator()( uint64 s ) const; };
+struct StringHashFunctor { unsigned int operator()( const char* s ) const; };
+struct CaselessStringHashFunctor { unsigned int operator()( const char* s ) const; };
+
+struct PointerLessFunctor { bool operator()( const void *a, const void *b ) const { return a < b; } };
+struct PointerEqualFunctor { bool operator()( const void *a, const void *b ) const { return a == b; } };
+#if defined( PLATFORM_64BITS )
+struct PointerHashFunctor { unsigned int operator()( const void* s ) const { return Mix64HashFunctor()( ( uintp ) s ); } };
+#else
+struct PointerHashFunctor { unsigned int operator()( const void* s ) const { return Mix32HashFunctor()( ( uintp ) s ); } };
+#endif
+
+
+// Generic implementation of Less and Equal functors
+template < typename T >
+struct DefaultLessFunctor
+{
+ bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a < b; }
+ bool operator()( typename ArgumentTypeInfo< T >::Alt_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a < b; }
+ bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Alt_t b ) const { return a < b; }
+};
+
+template < typename T >
+struct DefaultEqualFunctor
+{
+ bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a == b; }
+ bool operator()( typename ArgumentTypeInfo< T >::Alt_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a == b; }
+ bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Alt_t b ) const { return a == b; }
+};
+
+// Hashes for basic types
+template <> struct DefaultHashFunctor<char> : Mix32HashFunctor { };
+template <> struct DefaultHashFunctor<signed char> : Mix32HashFunctor { };
+template <> struct DefaultHashFunctor<unsigned char> : Mix32HashFunctor { };
+template <> struct DefaultHashFunctor<signed short> : Mix32HashFunctor { };
+template <> struct DefaultHashFunctor<unsigned short> : Mix32HashFunctor { };
+template <> struct DefaultHashFunctor<signed int> : Mix32HashFunctor { };
+template <> struct DefaultHashFunctor<unsigned int> : Mix32HashFunctor { };
+#if !defined(PLATFORM_64BITS) || defined(_WIN32)
+template <> struct DefaultHashFunctor<signed long> : Mix32HashFunctor { };
+template <> struct DefaultHashFunctor<unsigned long> : Mix32HashFunctor { };
+#elif defined(POSIX)
+template <> struct DefaultHashFunctor<signed long> : Mix64HashFunctor { };
+template <> struct DefaultHashFunctor<unsigned long> : Mix64HashFunctor { };
+#endif
+template <> struct DefaultHashFunctor<signed long long> : Mix64HashFunctor { };
+template <> struct DefaultHashFunctor<unsigned long long> : Mix64HashFunctor { };
+template <> struct DefaultHashFunctor<void*> : PointerHashFunctor { };
+template <> struct DefaultHashFunctor<const void*> : PointerHashFunctor { };
+#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+template <> struct DefaultHashFunctor<wchar_t> : Mix32HashFunctor { };
+#endif
+
+// String specializations. If you want to operate on raw values, use
+// PointerLessFunctor and friends from the "building-block" section above
+template <> struct DefaultLessFunctor<char*> : StringLessFunctor { };
+template <> struct DefaultLessFunctor<const char*> : StringLessFunctor { };
+template <> struct DefaultEqualFunctor<char*> : StringEqualFunctor { };
+template <> struct DefaultEqualFunctor<const char*> : StringEqualFunctor { };
+template <> struct DefaultHashFunctor<char*> : StringHashFunctor { };
+template <> struct DefaultHashFunctor<const char*> : StringHashFunctor { };
+
+// CUtlString/CUtlConstString are specialized here and not in utlstring.h
+// because I consider string datatypes to be fundamental, and don't feel
+// comfortable making that header file dependent on this one. (henryg)
+class CUtlString;
+template < typename T > class CUtlConstStringBase;
+
+template <> struct DefaultLessFunctor<CUtlString> : StringLessFunctor { };
+template <> struct DefaultHashFunctor<CUtlString> : StringHashFunctor { };
+template < typename T > struct DefaultLessFunctor< CUtlConstStringBase<T> > : StringLessFunctor { };
+template < typename T > struct DefaultHashFunctor< CUtlConstStringBase<T> > : StringHashFunctor { };
+
+
+// Helpers to deduce if a type defines a public AltArgumentType_t typedef:
+template < typename T >
+struct HasClassAltArgumentType
+{
+ template < typename X > static long Test( typename X::AltArgumentType_t* );
+ template < typename X > static char Test( ... );
+ enum { value = ( sizeof( Test< T >( NULL ) ) != sizeof( char ) ) };
+};
+
+template < typename T, bool = HasClassAltArgumentType< T >::value >
+struct GetClassAltArgumentType { typedef typename T::AltArgumentType_t Result_t; };
+
+template < typename T >
+struct GetClassAltArgumentType< T, false > { typedef undefined_t Result_t; };
+
+// Unwrap references; reference types don't have member typedefs.
+template < typename T >
+struct GetClassAltArgumentType< T&, false > : GetClassAltArgumentType< T > { };
+
+// ArgumentTypeInfoImpl is the base for all ArgumentTypeInfo specializations.
+template < typename ArgT, typename AltT = typename GetClassAltArgumentType<ArgT>::Result_t >
+struct ArgumentTypeInfoImpl
+{
+ enum { has_alt = 1 };
+ typedef ArgT Arg_t;
+ typedef AltT Alt_t;
+};
+
+// Handle cases where AltArgumentType_t is typedef'd to undefined_t
+template < typename ArgT >
+struct ArgumentTypeInfoImpl< ArgT, undefined_t >
+{
+ enum { has_alt = 0 };
+ typedef ArgT Arg_t;
+ typedef undefined_t Alt_t;
+};
+
+// Handle cases where AltArgumentType_t is typedef'd to the primary type
+template < typename ArgT >
+struct ArgumentTypeInfoImpl< ArgT, ArgT >
+{
+ enum { has_alt = 0 };
+ typedef ArgT Arg_t;
+ typedef undefined_t Alt_t;
+};
+
+
+// By default, everything is passed via const ref and doesn't define an alternate type.
+template <typename T> struct ArgumentTypeInfo : ArgumentTypeInfoImpl< const T& > { };
+
+// Small native types are most efficiently passed by value.
+template <> struct ArgumentTypeInfo< bool > : ArgumentTypeInfoImpl< bool > { };
+template <> struct ArgumentTypeInfo< char > : ArgumentTypeInfoImpl< char > { };
+template <> struct ArgumentTypeInfo< signed char > : ArgumentTypeInfoImpl< signed char > { };
+template <> struct ArgumentTypeInfo< unsigned char > : ArgumentTypeInfoImpl< unsigned char > { };
+template <> struct ArgumentTypeInfo< signed short > : ArgumentTypeInfoImpl< signed short > { };
+template <> struct ArgumentTypeInfo< unsigned short > : ArgumentTypeInfoImpl< unsigned short > { };
+template <> struct ArgumentTypeInfo< signed int > : ArgumentTypeInfoImpl< signed int > { };
+template <> struct ArgumentTypeInfo< unsigned int > : ArgumentTypeInfoImpl< unsigned int > { };
+template <> struct ArgumentTypeInfo< signed long > : ArgumentTypeInfoImpl< signed long > { };
+template <> struct ArgumentTypeInfo< unsigned long > : ArgumentTypeInfoImpl< unsigned long > { };
+template <> struct ArgumentTypeInfo< signed long long > : ArgumentTypeInfoImpl< signed long long > { };
+template <> struct ArgumentTypeInfo< unsigned long long > : ArgumentTypeInfoImpl< unsigned long long > { };
+template <> struct ArgumentTypeInfo< float > : ArgumentTypeInfoImpl< float > { };
+template <> struct ArgumentTypeInfo< double > : ArgumentTypeInfoImpl< double > { };
+template <> struct ArgumentTypeInfo< long double > : ArgumentTypeInfoImpl< long double > { };
+#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+template <> struct ArgumentTypeInfo< wchar_t > : ArgumentTypeInfoImpl< wchar_t > { };
+#endif
+
+// Pointers are also most efficiently passed by value.
+template < typename T > struct ArgumentTypeInfo< T* > : ArgumentTypeInfoImpl< T* > { };
+
+
+// Specializations to unwrap const-decorated types and references
+template <typename T> struct ArgumentTypeInfo<const T> : ArgumentTypeInfo<T> { };
+template <typename T> struct ArgumentTypeInfo<volatile T> : ArgumentTypeInfo<T> { };
+template <typename T> struct ArgumentTypeInfo<const volatile T> : ArgumentTypeInfo<T> { };
+template <typename T> struct ArgumentTypeInfo<T&> : ArgumentTypeInfo<T> { };
+
+template <typename T> struct DefaultLessFunctor<const T> : DefaultLessFunctor<T> { };
+template <typename T> struct DefaultLessFunctor<volatile T> : DefaultLessFunctor<T> { };
+template <typename T> struct DefaultLessFunctor<const volatile T> : DefaultLessFunctor<T> { };
+template <typename T> struct DefaultLessFunctor<T&> : DefaultLessFunctor<T> { };
+
+template <typename T> struct DefaultEqualFunctor<const T> : DefaultEqualFunctor<T> { };
+template <typename T> struct DefaultEqualFunctor<volatile T> : DefaultEqualFunctor<T> { };
+template <typename T> struct DefaultEqualFunctor<const volatile T> : DefaultEqualFunctor<T> { };
+template <typename T> struct DefaultEqualFunctor<T&> : DefaultEqualFunctor<T> { };
+
+template <typename T> struct DefaultHashFunctor<const T> : DefaultHashFunctor<T> { };
+template <typename T> struct DefaultHashFunctor<volatile T> : DefaultHashFunctor<T> { };
+template <typename T> struct DefaultHashFunctor<const volatile T> : DefaultHashFunctor<T> { };
+template <typename T> struct DefaultHashFunctor<T&> : DefaultHashFunctor<T> { };
+
+
+// Hash all pointer types as raw pointers by default
+template <typename T> struct DefaultHashFunctor< T * > : PointerHashFunctor { };
+
+
+// Here follow the useful implementations.
+
+// Bob Jenkins's 32-bit mix function.
+inline unsigned int Mix32HashFunctor::operator()( uint32 n ) const
+{
+ // Perform a mixture of the bits in n, where each bit
+ // of the input value has an equal chance to affect each
+ // bit of the output. This turns tightly clustered input
+ // values into a smooth distribution.
+ //
+ // This takes 16-20 cycles on modern x86 architectures;
+ // that's roughly the same cost as a mispredicted branch.
+ // It's also reasonably efficient on PPC-based consoles.
+ //
+ // If you're still thinking, "too many instructions!",
+ // do keep in mind that reading one byte of uncached RAM
+ // is about 30x slower than executing this code. It pays
+ // to have a good hash function which minimizes collisions
+ // (and therefore long lookup chains).
+ n = ( n + 0x7ed55d16 ) + ( n << 12 );
+ n = ( n ^ 0xc761c23c ) ^ ( n >> 19 );
+ n = ( n + 0x165667b1 ) + ( n << 5 );
+ n = ( n + 0xd3a2646c ) ^ ( n << 9 );
+ n = ( n + 0xfd7046c5 ) + ( n << 3 );
+ n = ( n ^ 0xb55a4f09 ) ^ ( n >> 16 );
+ return n;
+}
+
+inline unsigned int Mix64HashFunctor::operator()( uint64 s ) const
+{
+ // Thomas Wang hash, http://www.concentric.net/~ttwang/tech/inthash.htm
+ s = ( ~s ) + ( s << 21 ); // s = (s << 21) - s - 1;
+ s = s ^ ( s >> 24 );
+ s = (s + ( s << 3 ) ) + ( s << 8 ); // s * 265
+ s = s ^ ( s >> 14 );
+ s = ( s + ( s << 2 ) ) + ( s << 4 ); // s * 21
+ s = s ^ ( s >> 28 );
+ s = s + ( s << 31 );
+ return (unsigned int)s;
+}
+
+
+// Based on the widely-used FNV-1A string hash with a final
+// mixing step to improve dispersion for very small and very
+// large hash table sizes.
+inline unsigned int StringHashFunctor::operator()( const char* s ) const
+{
+ uint32 h = 2166136261u;
+ for ( ; *s; ++s )
+ {
+ uint32 c = (unsigned char) *s;
+ h = (h ^ c) * 16777619;
+ }
+ return (h ^ (h << 17)) + (h >> 21);
+}
+
+// Equivalent to StringHashFunctor on lower-case strings.
+inline unsigned int CaselessStringHashFunctor::operator()( const char* s ) const
+{
+ uint32 h = 2166136261u;
+ for ( ; *s; ++s )
+ {
+ uint32 c = (unsigned char) *s;
+ // Brutally fast branchless ASCII tolower():
+ // if ((c >= 'A') && (c <= 'Z')) c += ('a' - 'A');
+ c += (((('A'-1) - c) & (c - ('Z'+1))) >> 26) & 32;
+ h = (h ^ c) * 16777619;
+ }
+ return (h ^ (h << 17)) + (h >> 21);
+}
+
+
+#endif // UTLCOMMON_H
diff --git a/public/tier1/utldelegate.h b/public/tier1/utldelegate.h
new file mode 100644
index 0000000..04c5dad
--- /dev/null
+++ b/public/tier1/utldelegate.h
@@ -0,0 +1,97 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A header describing use of the delegate system. It's hiding
+// the highly complex implementation details of the delegate system
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef UTLDELEGATE_H
+#define UTLDELEGATE_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+//-----------------------------------------------------------------------------
+// The delegate system: A method of invoking methods, whether they are
+// member methods of classes, static methods of classes, or free functions,
+// dealing with all the nastiness in differences between how the calls have
+// to happen yet works in a highly optimal fashion. For details, see
+//
+// http://www.codeproject.com/cpp/FastDelegate.asp
+//
+// The delegate design pattern is described here
+//
+// http://en.wikipedia.org/wiki/Delegation_(programming)
+//-----------------------------------------------------------------------------
+
+#ifdef UTLDELEGATE_USAGE_DEMONSTRATION
+
+//-----------------------------------------------------------------------------
+// Here, we show how to use this system (the ifdef UTLDELEGATE_USAGE_DEMONSTRATION is used to get syntax coloring).
+//-----------------------------------------------------------------------------
+
+// First, define the functions you wish to call.
+int Test1( char *pString, float x );
+class CTestClass
+{
+public:
+ void Test2();
+ static float Test3( int x );
+};
+
+void Test()
+{
+ CTestClass testClass;
+
+ // CUtlDelegate is a class that can be used to invoke methods of classes
+ // or static functions in a highly efficient manner.
+
+ // There are a couple ways to hook up a delegate. One is in a constructor
+ // Note that the template parameter of CUtlFastDelegate looks like the
+ // function type: first, you have the return type, then ( parameter list )
+ CUtlDelegate< int ( char *, float ) > delegate1( &Test1 );
+
+ // Another way is to use the UtlMakeDelegate method, allowing you to
+ // define the delegate later. Note that UtlMakeDelegate does *not* do a heap allocation
+ CUtlDelegate< void () > delegate2;
+ delegate2 = UtlMakeDelegate( &testClass, &CTestClass::Test2 );
+
+ // A third method is to use the Bind() method of CUtlFastDelegate
+ // Note that you do not pass in the class pointer for static functions
+ CUtlDelegate< float ( int ) > delegate3;
+ delegate3.Bind( &CTestClass::Test3 );
+
+ // Use the () operator to invoke the function calls.
+ int x = delegate1( "hello", 1.0f );
+ delegate2();
+ float y = delegate3( 5 );
+
+ // Use the Clear() method to unbind a delegate.
+ delegate1.Clear();
+
+ // You can use operator! or IsEmpty() to see if a delegate is bound
+ if ( !delegate1.IsEmpty() )
+ {
+ delegate1( "hello2" );
+ }
+
+ // Delegates maintain an internal non-templatized representation of the
+ // functions they are bound to called CUtlAbstractDelegate. These are
+ // useful when keeping a list of untyped delegates or when passing
+ // delegates across interface boundaries.
+ const CUtlAbstractDelegate &abstractDelegate3 = delegate3.GetAbstractDelegate();
+ CUtlDelegate< float ( int ) > delegate4;
+ delegate4.SetAbstractDelegate( abstractDelegate3 );
+ delegate4( 10 );
+}
+
+#endif // UTLDELEGATE_USAGE_DEMONSTRATION
+
+// Looking in this file may cause blindness.
+#include "tier1/utldelegateimpl.h"
+
+#endif // UTLDELEGATE_H
diff --git a/public/tier1/utldelegateimpl.h b/public/tier1/utldelegateimpl.h
new file mode 100644
index 0000000..cf9809d
--- /dev/null
+++ b/public/tier1/utldelegateimpl.h
@@ -0,0 +1,2656 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+// FastDelegate.h
+// Efficient delegates in C++ that generate only two lines of asm code!
+// Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp
+//
+// - Don Clugston, Mar 2004.
+// Major contributions were made by Jody Hagins.
+// History:
+// 24-Apr-04 1.0 * Submitted to CodeProject.
+// 28-Apr-04 1.1 * Prevent most unsafe uses of evil static function hack.
+// * Improved syntax for horrible_cast (thanks Paul Bludov).
+// * Tested on Metrowerks MWCC and Intel ICL (IA32)
+// * Compiled, but not run, on Comeau C++ and Intel Itanium ICL.
+// 27-Jun-04 1.2 * Now works on Borland C++ Builder 5.5
+// * Now works on /clr "managed C++" code on VC7, VC7.1
+// * Comeau C++ now compiles without warnings.
+// * Prevent the virtual inheritance case from being used on
+// VC6 and earlier, which generate incorrect code.
+// * Improved warning and error messages. Non-standard hacks
+// now have compile-time checks to make them safer.
+// * implicit_cast used instead of static_cast in many cases.
+// * If calling a const member function, a const class pointer can be used.
+// * UtlMakeDelegate() global helper function added to simplify pass-by-value.
+// * Added fastdelegate.Clear()
+// 16-Jul-04 1.2.1* Workaround for gcc bug (const member function pointers in templates)
+// 30-Oct-04 1.3 * Support for (non-void) return values.
+// * No more workarounds in client code!
+// MSVC and Intel now use a clever hack invented by John Dlugosz:
+// - The FASTDELEGATEDECLARE workaround is no longer necessary.
+// - No more warning messages for VC6
+// * Less use of macros. Error messages should be more comprehensible.
+// * Added include guards
+// * Added FastDelegate::IsEmpty() to test if invocation is safe (Thanks Neville Franks).
+// * Now tested on VS 2005 Express Beta, PGI C++
+// 24-Dec-04 1.4 * Added CUtlAbstractDelegate, to allow collections of disparate delegates.
+// * <,>,<=,>= comparison operators to allow storage in ordered containers.
+// * Substantial reduction of code size, especially the 'Closure' class.
+// * Standardised all the compiler-specific workarounds.
+// * MFP conversion now works for CodePlay (but not yet supported in the full code).
+// * Now compiles without warnings on _any_ supported compiler, including BCC 5.5.1
+// * New syntax: FastDelegate< int (char *, double) >.
+// 14-Feb-05 1.4.1* Now treats =0 as equivalent to .Clear(), ==0 as equivalent to .IsEmpty(). (Thanks elfric).
+// * Now tested on Intel ICL for AMD64, VS2005 Beta for AMD64 and Itanium.
+// 30-Mar-05 1.5 * Safebool idiom: "if (dg)" is now equivalent to "if (!dg.IsEmpty())"
+// * Fully supported by CodePlay VectorC
+// * Bugfix for Metrowerks: IsEmpty() was buggy because a valid MFP can be 0 on MWCC!
+// * More optimal assignment,== and != operators for static function pointers.
+// 22-Jul-10 xxx * Reformatted + renamed to match valve coding standards
+// * Added UtlMakeDelegate for static functions
+
+#ifndef UTLDELEGATEIMPL_H
+#define UTLDELEGATEIMPL_H
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include <memory.h> // to allow <,> comparisons
+
+////////////////////////////////////////////////////////////////////////////////
+// Configuration options
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Uncomment the following #define for optimally-sized delegates.
+// In this case, the generated asm code is almost identical to the code you'd get
+// if the compiler had native support for delegates.
+// It will not work on systems where sizeof(dataptr) < sizeof(codeptr).
+// Thus, it will not work for DOS compilers using the medium model.
+// It will also probably fail on some DSP systems.
+#define FASTDELEGATE_USESTATICFUNCTIONHACK
+
+// Uncomment the next line to allow function declarator syntax.
+// It is automatically enabled for those compilers where it is known to work.
+//#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
+
+////////////////////////////////////////////////////////////////////////////////
+// Compiler identification for workarounds
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Compiler identification. It's not easy to identify Visual C++ because
+// many vendors fraudulently define Microsoft's identifiers.
+#if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__VECTOR_C) && !defined(__ICL) && !defined(__BORLANDC__)
+#define FASTDLGT_ISMSVC
+
+#if (_MSC_VER <1300) // Many workarounds are required for VC6.
+#define FASTDLGT_VC6
+#pragma warning(disable:4786) // disable this ridiculous warning
+#endif
+
+#endif
+
+// Does the compiler uses Microsoft's member function pointer structure?
+// If so, it needs special treatment.
+// Metrowerks CodeWarrior, Intel, and CodePlay fraudulently define Microsoft's
+// identifier, _MSC_VER. We need to filter Metrowerks out.
+#if defined(_MSC_VER) && !defined(__MWERKS__)
+#define FASTDLGT_MICROSOFT_MFP
+
+#if !defined(__VECTOR_C)
+// CodePlay doesn't have the __single/multi/virtual_inheritance keywords
+#define FASTDLGT_HASINHERITANCE_KEYWORDS
+#endif
+#endif
+
+// Does it allow function declarator syntax? The following compilers are known to work:
+#if defined(FASTDLGT_ISMSVC) && (_MSC_VER >=1310) // VC 7.1
+#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
+#endif
+
+// Gcc(2.95+), and versions of Digital Mars, Intel and Comeau in common use.
+#if defined (__DMC__) || defined(__GNUC__) || defined(__ICL) || defined(__COMO__)
+#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
+#endif
+
+// It works on Metrowerks MWCC 3.2.2. From boost.Config it should work on earlier ones too.
+#if defined (__MWERKS__)
+#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
+#endif
+
+#ifdef __GNUC__ // Workaround GCC bug #8271
+ // At present, GCC doesn't recognize constness of MFPs in templates
+#define FASTDELEGATE_GCC_BUG_8271
+#endif
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// General tricks used in this code
+//
+// (a) Error messages are generated by typdefing an array of negative size to
+// generate compile-time errors.
+// (b) Warning messages on MSVC are generated by declaring unused variables, and
+// enabling the "variable XXX is never used" warning.
+// (c) Unions are used in a few compiler-specific cases to perform illegal casts.
+// (d) For Microsoft and Intel, when adjusting the 'this' pointer, it's cast to
+// (char *) first to ensure that the correct number of *bytes* are added.
+//
+////////////////////////////////////////////////////////////////////////////////
+// Helper templates
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+namespace detail // we'll hide the implementation details in a nested namespace.
+{
+
+// implicit_cast< >
+// I believe this was originally going to be in the C++ standard but
+// was left out by accident. It's even milder than static_cast.
+// I use it instead of static_cast<> to emphasize that I'm not doing
+// anything nasty.
+// Usage is identical to static_cast<>
+template <class OutputClass, class InputClass>
+inline OutputClass implicit_cast(InputClass input)
+{
+ return input;
+}
+
+// horrible_cast< >
+// This is truly evil. It completely subverts C++'s type system, allowing you
+// to cast from any class to any other class. Technically, using a union
+// to perform the cast is undefined behaviour (even in C). But we can see if
+// it is OK by checking that the union is the same size as each of its members.
+// horrible_cast<> should only be used for compiler-specific workarounds.
+// Usage is identical to reinterpret_cast<>.
+
+// This union is declared outside the horrible_cast because BCC 5.5.1
+// can't inline a function with a nested class, and gives a warning.
+template <class OutputClass, class InputClass>
+union horrible_union
+{
+ OutputClass out;
+ InputClass in;
+};
+
+template <class OutputClass, class InputClass>
+inline OutputClass horrible_cast(const InputClass input)
+{
+ horrible_union<OutputClass, InputClass> u;
+ // Cause a compile-time error if in, out and u are not the same size.
+ // If the compile fails here, it means the compiler has peculiar
+ // unions which would prevent the cast from working.
+ typedef int ERROR_CantUseHorrible_cast[sizeof(InputClass)==sizeof(u)
+ && sizeof(InputClass)==sizeof(OutputClass) ? 1 : -1];
+ u.in = input;
+ return u.out;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Workarounds
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Backwards compatibility: This macro used to be necessary in the virtual inheritance
+// case for Intel and Microsoft. Now it just forward-declares the class.
+#define FASTDELEGATEDECLARE(CLASSNAME) class CLASSNAME;
+
+// Prevent use of the static function hack with the DOS medium model.
+#ifdef __MEDIUM__
+#undef FASTDELEGATE_USESTATICFUNCTIONHACK
+#endif
+
+// DefaultVoid - a workaround for 'void' templates in VC6.
+//
+// (1) VC6 and earlier do not allow 'void' as a default template argument.
+// (2) They also doesn't allow you to return 'void' from a function.
+//
+// Workaround for (1): Declare a dummy type 'DefaultVoid' which we use
+// when we'd like to use 'void'. We convert it into 'void' and back
+// using the templates DefaultVoidToVoid<> and VoidToDefaultVoid<>.
+// Workaround for (2): On VC6, the code for calling a void function is
+// identical to the code for calling a non-void function in which the
+// return value is never used, provided the return value is returned
+// in the EAX register, rather than on the stack.
+// This is true for most fundamental types such as int, enum, void *.
+// Const void * is the safest option since it doesn't participate
+// in any automatic conversions. But on a 16-bit compiler it might
+// cause extra code to be generated, so we disable it for all compilers
+// except for VC6 (and VC5).
+#ifdef FASTDLGT_VC6
+// VC6 workaround
+typedef const void * DefaultVoid;
+#else
+// On any other compiler, just use a normal void.
+typedef void DefaultVoid;
+#endif
+
+// Translate from 'DefaultVoid' to 'void'.
+// Everything else is unchanged
+template <class T>
+struct DefaultVoidToVoid { typedef T type; };
+
+template <>
+struct DefaultVoidToVoid<DefaultVoid> { typedef void type; };
+
+// Translate from 'void' into 'DefaultVoid'
+// Everything else is unchanged
+template <class T>
+struct VoidToDefaultVoid { typedef T type; };
+
+template <>
+struct VoidToDefaultVoid<void> { typedef DefaultVoid type; };
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Fast Delegates, part 1:
+//
+// Conversion of member function pointer to a standard form
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// GenericClass is a fake class, ONLY used to provide a type.
+// It is vitally important that it is never defined, so that the compiler doesn't
+// think it can optimize the invocation. For example, Borland generates simpler
+// code if it knows the class only uses single inheritance.
+
+// Compilers using Microsoft's structure need to be treated as a special case.
+#ifdef FASTDLGT_MICROSOFT_MFP
+
+#ifdef FASTDLGT_HASINHERITANCE_KEYWORDS
+ // For Microsoft and Intel, we want to ensure that it's the most efficient type of MFP
+ // (4 bytes), even when the /vmg option is used. Declaring an empty class
+ // would give 16 byte pointers in this case....
+ class __single_inheritance GenericClass;
+#endif
+ // ...but for Codeplay, an empty class *always* gives 4 byte pointers.
+ // If compiled with the /clr option ("managed C++"), the JIT compiler thinks
+ // it needs to load GenericClass before it can call any of its functions,
+ // (compiles OK but crashes at runtime!), so we need to declare an
+ // empty class to make it happy.
+ // Codeplay and VC4 can't cope with the unknown_inheritance case either.
+ class GenericClass {};
+#else
+ class GenericClass;
+#endif
+
+// The size of a single inheritance member function pointer.
+const int SINGLE_MEMFUNCPTR_SIZE = sizeof(void (GenericClass::*)());
+
+// SimplifyMemFunc< >::Convert()
+//
+// A template function that converts an arbitrary member function pointer into the
+// simplest possible form of member function pointer, using a supplied 'this' pointer.
+// According to the standard, this can be done legally with reinterpret_cast<>.
+// For (non-standard) compilers which use member function pointers which vary in size
+// depending on the class, we need to use knowledge of the internal structure of a
+// member function pointer, as used by the compiler. Template specialization is used
+// to distinguish between the sizes. Because some compilers don't support partial
+// template specialisation, I use full specialisation of a wrapper struct.
+
+// general case -- don't know how to convert it. Force a compile failure
+template <int N>
+struct SimplifyMemFunc
+{
+ template <class X, class XFuncType, class GenericMemFuncType>
+ inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
+ GenericMemFuncType &bound_func)
+ {
+ // Unsupported member function type -- force a compile failure.
+ // (it's illegal to have a array with negative size).
+ typedef char ERROR_Unsupported_member_function_pointer_on_this_compiler[N-100];
+ return 0;
+ }
+};
+
+// For compilers where all member func ptrs are the same size, everything goes here.
+// For non-standard compilers, only single_inheritance classes go here.
+template <>
+struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE>
+{
+ template <class X, class XFuncType, class GenericMemFuncType>
+ inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
+ GenericMemFuncType &bound_func)
+ {
+#if defined __DMC__
+ // Digital Mars doesn't allow you to cast between abitrary PMF's,
+ // even though the standard says you can. The 32-bit compiler lets you
+ // static_cast through an int, but the DOS compiler doesn't.
+ bound_func = horrible_cast<GenericMemFuncType>(function_to_bind);
+#else
+ bound_func = reinterpret_cast<GenericMemFuncType>(function_to_bind);
+#endif
+ return reinterpret_cast<GenericClass *>(pthis);
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Fast Delegates, part 1b:
+//
+// Workarounds for Microsoft and Intel
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+// Compilers with member function pointers which violate the standard (MSVC, Intel, Codeplay),
+// need to be treated as a special case.
+#ifdef FASTDLGT_MICROSOFT_MFP
+
+// We use unions to perform horrible_casts. I would like to use #pragma pack(push, 1)
+// at the start of each function for extra safety, but VC6 seems to ICE
+// intermittently if you do this inside a template.
+
+// __multiple_inheritance classes go here
+// Nasty hack for Microsoft and Intel (IA32 and Itanium)
+template<>
+struct SimplifyMemFunc< SINGLE_MEMFUNCPTR_SIZE + sizeof(int) >
+{
+ template <class X, class XFuncType, class GenericMemFuncType>
+ inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
+ GenericMemFuncType &bound_func)
+ {
+ // We need to use a horrible_cast to do this conversion.
+ // In MSVC, a multiple inheritance member pointer is internally defined as:
+ union
+ {
+ XFuncType func;
+ struct
+ {
+ GenericMemFuncType funcaddress; // points to the actual member function
+ int delta; // #BYTES to be added to the 'this' pointer
+ }s;
+ } u;
+ // Check that the horrible_cast will work
+ typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s)? 1 : -1];
+ u.func = function_to_bind;
+ bound_func = u.s.funcaddress;
+ return reinterpret_cast<GenericClass *>(reinterpret_cast<char *>(pthis) + u.s.delta);
+ }
+};
+
+// virtual inheritance is a real nuisance. It's inefficient and complicated.
+// On MSVC and Intel, there isn't enough information in the pointer itself to
+// enable conversion to a closure pointer. Earlier versions of this code didn't
+// work for all cases, and generated a compile-time error instead.
+// But a very clever hack invented by John M. Dlugosz solves this problem.
+// My code is somewhat different to his: I have no asm code, and I make no
+// assumptions about the calling convention that is used.
+
+// In VC++ and ICL, a virtual_inheritance member pointer
+// is internally defined as:
+struct MicrosoftVirtualMFP
+{
+ void (GenericClass::*codeptr)(); // points to the actual member function
+ int delta; // #bytes to be added to the 'this' pointer
+ int vtable_index; // or 0 if no virtual inheritance
+};
+// The CRUCIAL feature of Microsoft/Intel MFPs which we exploit is that the
+// m_codeptr member is *always* called, regardless of the values of the other
+// members. (This is *not* true for other compilers, eg GCC, which obtain the
+// function address from the vtable if a virtual function is being called).
+// Dlugosz's trick is to make the codeptr point to a probe function which
+// returns the 'this' pointer that was used.
+
+// Define a generic class that uses virtual inheritance.
+// It has a trival member function that returns the value of the 'this' pointer.
+struct GenericVirtualClass : virtual public GenericClass
+{
+ typedef GenericVirtualClass * (GenericVirtualClass::*ProbePtrType)();
+ GenericVirtualClass * GetThis() { return this; }
+};
+
+// __virtual_inheritance classes go here
+#ifdef _MSC_VER
+#pragma warning( disable : 4121 )
+#endif
+
+template <>
+struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 2*sizeof(int) >
+{
+ template <class X, class XFuncType, class GenericMemFuncType>
+ inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
+ GenericMemFuncType &bound_func)
+ {
+ union
+ {
+ XFuncType func;
+ GenericClass* (X::*ProbeFunc)();
+ MicrosoftVirtualMFP s;
+ } u;
+ u.func = function_to_bind;
+ bound_func = reinterpret_cast<GenericMemFuncType>(u.s.codeptr);
+ union
+ {
+ GenericVirtualClass::ProbePtrType virtfunc;
+ MicrosoftVirtualMFP s;
+ } u2;
+ // Check that the horrible_cast<>s will work
+ typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s)
+ && sizeof(function_to_bind)==sizeof(u.ProbeFunc)
+ && sizeof(u2.virtfunc)==sizeof(u2.s) ? 1 : -1];
+ // Unfortunately, taking the address of a MF prevents it from being inlined, so
+ // this next line can't be completely optimised away by the compiler.
+ u2.virtfunc = &GenericVirtualClass::GetThis;
+ u.s.codeptr = u2.s.codeptr;
+ return (pthis->*u.ProbeFunc)();
+ }
+};
+#ifdef _MSC_VER
+#pragma warning( default : 4121 )
+#endif
+
+#if (_MSC_VER <1300)
+
+// Nasty hack for Microsoft Visual C++ 6.0
+// unknown_inheritance classes go here
+// There is a compiler bug in MSVC6 which generates incorrect code in this case!!
+template <>
+struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >
+{
+ template <class X, class XFuncType, class GenericMemFuncType>
+ inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
+ GenericMemFuncType &bound_func)
+ {
+ // There is an apalling but obscure compiler bug in MSVC6 and earlier:
+ // vtable_index and 'vtordisp' are always set to 0 in the
+ // unknown_inheritance case!
+ // This means that an incorrect function could be called!!!
+ // Compiling with the /vmg option leads to potentially incorrect code.
+ // This is probably the reason that the IDE has a user interface for specifying
+ // the /vmg option, but it is disabled - you can only specify /vmg on
+ // the command line. In VC1.5 and earlier, the compiler would ICE if it ever
+ // encountered this situation.
+ // It is OK to use the /vmg option if /vmm or /vms is specified.
+
+ // Fortunately, the wrong function is only called in very obscure cases.
+ // It only occurs when a derived class overrides a virtual function declared
+ // in a virtual base class, and the member function
+ // points to the *Derived* version of that function. The problem can be
+ // completely averted in 100% of cases by using the *Base class* for the
+ // member fpointer. Ie, if you use the base class as an interface, you'll
+ // stay out of trouble.
+ // Occasionally, you might want to point directly to a derived class function
+ // that isn't an override of a base class. In this case, both vtable_index
+ // and 'vtordisp' are zero, but a virtual_inheritance pointer will be generated.
+ // We can generate correct code in this case. To prevent an incorrect call from
+ // ever being made, on MSVC6 we generate a warning, and call a function to
+ // make the program crash instantly.
+ typedef char ERROR_VC6CompilerBug[-100];
+ return 0;
+ }
+};
+
+
+#else
+
+// Nasty hack for Microsoft and Intel (IA32 and Itanium)
+// unknown_inheritance classes go here
+// This is probably the ugliest bit of code I've ever written. Look at the casts!
+// There is a compiler bug in MSVC6 which prevents it from using this code.
+template <>
+struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >
+{
+ template <class X, class XFuncType, class GenericMemFuncType>
+ inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
+ GenericMemFuncType &bound_func)
+ {
+ // The member function pointer is 16 bytes long. We can't use a normal cast, but
+ // we can use a union to do the conversion.
+ union
+ {
+ XFuncType func;
+ // In VC++ and ICL, an unknown_inheritance member pointer
+ // is internally defined as:
+ struct
+ {
+ GenericMemFuncType funcaddress; // points to the actual member function
+ int delta; // #bytes to be added to the 'this' pointer
+ int vtordisp; // #bytes to add to 'this' to find the vtable
+ int vtable_index; // or 0 if no virtual inheritance
+ } s;
+ } u;
+ // Check that the horrible_cast will work
+ typedef int ERROR_CantUsehorrible_cast[sizeof(XFuncType)==sizeof(u.s)? 1 : -1];
+ u.func = function_to_bind;
+ bound_func = u.s.funcaddress;
+ int virtual_delta = 0;
+ if (u.s.vtable_index)
+ { // Virtual inheritance is used
+ // First, get to the vtable.
+ // It is 'vtordisp' bytes from the start of the class.
+ const int * vtable = *reinterpret_cast<const int *const*>(
+ reinterpret_cast<const char *>(pthis) + u.s.vtordisp );
+
+ // 'vtable_index' tells us where in the table we should be looking.
+ virtual_delta = u.s.vtordisp + *reinterpret_cast<const int *>(
+ reinterpret_cast<const char *>(vtable) + u.s.vtable_index);
+ }
+ // The int at 'virtual_delta' gives us the amount to add to 'this'.
+ // Finally we can add the three components together. Phew!
+ return reinterpret_cast<GenericClass *>(
+ reinterpret_cast<char *>(pthis) + u.s.delta + virtual_delta);
+ };
+};
+#endif // MSVC 7 and greater
+
+#endif // MS/Intel hacks
+
+} // namespace detail
+
+////////////////////////////////////////////////////////////////////////////////
+// Fast Delegates, part 2:
+//
+// Define the delegate storage, and cope with static functions
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// CUtlAbstractDelegate -- an opaque structure which can hold an arbitary delegate.
+// It knows nothing about the calling convention or number of arguments used by
+// the function pointed to.
+// It supplies comparison operators so that it can be stored in STL collections.
+// It cannot be set to anything other than null, nor invoked directly:
+// it must be converted to a specific delegate.
+
+// Implementation:
+// There are two possible implementations: the Safe method and the Evil method.
+// CUtlAbstractDelegate - Safe version
+//
+// This implementation is standard-compliant, but a bit tricky.
+// A static function pointer is stored inside the class.
+// Here are the valid values:
+// +-- Static pointer --+--pThis --+-- pMemFunc-+-- Meaning------+
+// | 0 | 0 | 0 | Empty |
+// | !=0 |(dontcare)| Invoker | Static function|
+// | 0 | !=0 | !=0* | Method call |
+// +--------------------+----------+------------+----------------+
+// * For Metrowerks, this can be 0. (first virtual function in a
+// single_inheritance class).
+// When stored stored inside a specific delegate, the 'dontcare' entries are replaced
+// with a reference to the delegate itself. This complicates the = and == operators
+// for the delegate class.
+
+// CUtlAbstractDelegate - Evil version
+//
+// For compilers where data pointers are at least as big as code pointers, it is
+// possible to store the function pointer in the this pointer, using another
+// horrible_cast. In this case the CUtlAbstractDelegate implementation is simple:
+// +--pThis --+-- pMemFunc-+-- Meaning---------------------+
+// | 0 | 0 | Empty |
+// | !=0 | !=0* | Static function or method call|
+// +----------+------------+-------------------------------+
+// * For Metrowerks, this can be 0. (first virtual function in a
+// single_inheritance class).
+// Note that the Sun C++ and MSVC documentation explicitly state that they
+// support static_cast between void * and function pointers.
+
+class CUtlAbstractDelegate
+{
+protected:
+ // the data is protected, not private, because many
+ // compilers have problems with template friends.
+ typedef void (detail::GenericClass::*GenericMemFuncType)(); // arbitrary MFP.
+ detail::GenericClass *m_pthis;
+ GenericMemFuncType m_pFunction;
+
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ typedef void (*GenericFuncPtr)(); // arbitrary code pointer
+ GenericFuncPtr m_pStaticFunction;
+#endif
+
+public:
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ CUtlAbstractDelegate() : m_pthis(0), m_pFunction(0), m_pStaticFunction(0) {};
+ void Clear()
+ {
+ m_pthis=0; m_pFunction=0; m_pStaticFunction=0;
+ }
+#else
+ CUtlAbstractDelegate() : m_pthis(0), m_pFunction(0) {};
+ void Clear() { m_pthis=0; m_pFunction=0; }
+#endif
+public:
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ inline bool IsEqual (const CUtlAbstractDelegate &x) const
+ {
+ // We have to cope with the static function pointers as a special case
+ if (m_pFunction!=x.m_pFunction)
+ return false;
+ // the static function ptrs must either both be equal, or both be 0.
+ if (m_pStaticFunction!=x.m_pStaticFunction)
+ return false;
+ if (m_pStaticFunction!=0)
+ return m_pthis==x.m_pthis;
+ else
+ return true;
+ }
+#else // Evil Method
+ inline bool IsEqual (const CUtlAbstractDelegate &x) const
+ {
+ return m_pthis==x.m_pthis && m_pFunction==x.m_pFunction;
+ }
+#endif
+ // Provide a strict weak ordering for DelegateMementos.
+ inline bool IsLess(const CUtlAbstractDelegate &right) const
+ {
+ // deal with static function pointers first
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ if (m_pStaticFunction !=0 || right.m_pStaticFunction!=0)
+ return m_pStaticFunction < right.m_pStaticFunction;
+#endif
+ if (m_pthis !=right.m_pthis)
+ return m_pthis < right.m_pthis;
+ // There are no ordering operators for member function pointers,
+ // but we can fake one by comparing each byte. The resulting ordering is
+ // arbitrary (and compiler-dependent), but it permits storage in ordered STL containers.
+ return memcmp(&m_pFunction, &right.m_pFunction, sizeof(m_pFunction)) < 0;
+
+ }
+ // BUGFIX (Mar 2005):
+ // We can't just compare m_pFunction because on Metrowerks,
+ // m_pFunction can be zero even if the delegate is not empty!
+ inline bool operator ! () const // Is it bound to anything?
+ {
+ return m_pthis==0 && m_pFunction==0;
+ }
+ inline bool IsEmpty() const // Is it bound to anything?
+ {
+ return m_pthis==0 && m_pFunction==0;
+ }
+public:
+ CUtlAbstractDelegate & operator = (const CUtlAbstractDelegate &right)
+ {
+ SetMementoFrom(right);
+ return *this;
+ }
+ inline bool operator <(const CUtlAbstractDelegate &right)
+ {
+ return IsLess(right);
+ }
+ inline bool operator >(const CUtlAbstractDelegate &right)
+ {
+ return right.IsLess(*this);
+ }
+ CUtlAbstractDelegate (const CUtlAbstractDelegate &right) :
+ m_pFunction(right.m_pFunction), m_pthis(right.m_pthis)
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ , m_pStaticFunction (right.m_pStaticFunction)
+#endif
+ {}
+
+ // Only use this if you really know what you're doing.
+ // It's used in cases where I've cached off a delegate previously
+ void UnsafeThisPointerSlam( void *pThis )
+ {
+ m_pthis = (detail::GenericClass*)( pThis );
+ }
+
+ void *UnsafeGetThisPtr()
+ {
+ return m_pthis;
+ }
+
+protected:
+ void SetMementoFrom(const CUtlAbstractDelegate &right)
+ {
+ m_pFunction = right.m_pFunction;
+ m_pthis = right.m_pthis;
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ m_pStaticFunction = right.m_pStaticFunction;
+#endif
+ }
+};
+
+
+// ClosurePtr<>
+//
+// A private wrapper class that adds function signatures to CUtlAbstractDelegate.
+// It's the class that does most of the actual work.
+// The signatures are specified by:
+// GenericMemFunc: must be a type of GenericClass member function pointer.
+// StaticFuncPtr: must be a type of function pointer with the same signature
+// as GenericMemFunc.
+// UnvoidStaticFuncPtr: is the same as StaticFuncPtr, except on VC6
+// where it never returns void (returns DefaultVoid instead).
+
+// An outer class, FastDelegateN<>, handles the invoking and creates the
+// necessary typedefs.
+// This class does everything else.
+
+namespace detail
+{
+
+template < class GenericMemFunc, class StaticFuncPtr, class UnvoidStaticFuncPtr>
+class ClosurePtr : public CUtlAbstractDelegate
+{
+public:
+ // These functions are for setting the delegate to a member function.
+
+ // Here's the clever bit: we convert an arbitrary member function into a
+ // standard form. XMemFunc should be a member function of class X, but I can't
+ // enforce that here. It needs to be enforced by the wrapper class.
+ template < class X, class XMemFunc >
+ inline void bindmemfunc(X *pthis, XMemFunc function_to_bind )
+ {
+ m_pthis = SimplifyMemFunc< sizeof(function_to_bind) >
+ ::Convert(pthis, function_to_bind, m_pFunction);
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ m_pStaticFunction = 0;
+#endif
+ }
+ // For const member functions, we only need a const class pointer.
+ // Since we know that the member function is const, it's safe to
+ // remove the const qualifier from the 'this' pointer with a const_cast.
+ // VC6 has problems if we just overload 'bindmemfunc', so we give it a different name.
+ template < class X, class XMemFunc>
+ inline void bindconstmemfunc(const X *pthis, XMemFunc function_to_bind)
+ {
+ m_pthis= SimplifyMemFunc< sizeof(function_to_bind) >
+ ::Convert(const_cast<X*>(pthis), function_to_bind, m_pFunction);
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ m_pStaticFunction = 0;
+#endif
+ }
+#ifdef FASTDELEGATE_GCC_BUG_8271 // At present, GCC doesn't recognize constness of MFPs in templates
+ template < class X, class XMemFunc>
+ inline void bindmemfunc(const X *pthis, XMemFunc function_to_bind)
+ {
+ bindconstmemfunc(pthis, function_to_bind);
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ m_pStaticFunction = 0;
+#endif
+ }
+#endif
+ // These functions are required for invoking the stored function
+ inline GenericClass *GetClosureThis() const { return m_pthis; }
+ inline GenericMemFunc GetClosureMemPtr() const { return reinterpret_cast<GenericMemFunc>(m_pFunction); }
+
+// There are a few ways of dealing with static function pointers.
+// There's a standard-compliant, but tricky method.
+// There's also a straightforward hack, that won't work on DOS compilers using the
+// medium memory model. It's so evil that I can't recommend it, but I've
+// implemented it anyway because it produces very nice asm code.
+
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+
+// ClosurePtr<> - Safe version
+//
+// This implementation is standard-compliant, but a bit tricky.
+// I store the function pointer inside the class, and the delegate then
+// points to itself. Whenever the delegate is copied, these self-references
+// must be transformed, and this complicates the = and == operators.
+public:
+ // The next two functions are for operator ==, =, and the copy constructor.
+ // We may need to convert the m_pthis pointers, so that
+ // they remain as self-references.
+ template< class DerivedClass >
+ inline void CopyFrom (DerivedClass *pParent, const CUtlAbstractDelegate &x)
+ {
+ SetMementoFrom(x);
+ if (m_pStaticFunction!=0)
+ {
+ // transform self references...
+ m_pthis=reinterpret_cast<GenericClass *>(pParent);
+ }
+ }
+ // For static functions, the 'static_function_invoker' class in the parent
+ // will be called. The parent then needs to call GetStaticFunction() to find out
+ // the actual function to invoke.
+ template < class DerivedClass, class ParentInvokerSig >
+ inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker,
+ StaticFuncPtr function_to_bind )
+ {
+ if (function_to_bind==0)
+ { // cope with assignment to 0
+ m_pFunction=0;
+ }
+ else
+ {
+ bindmemfunc(pParent, static_function_invoker);
+ }
+ m_pStaticFunction=reinterpret_cast<GenericFuncPtr>(function_to_bind);
+ }
+ inline UnvoidStaticFuncPtr GetStaticFunction() const
+ {
+ return reinterpret_cast<UnvoidStaticFuncPtr>(m_pStaticFunction);
+ }
+#else
+
+// ClosurePtr<> - Evil version
+//
+// For compilers where data pointers are at least as big as code pointers, it is
+// possible to store the function pointer in the this pointer, using another
+// horrible_cast. Invocation isn't any faster, but it saves 4 bytes, and
+// speeds up comparison and assignment. If C++ provided direct language support
+// for delegates, they would produce asm code that was almost identical to this.
+// Note that the Sun C++ and MSVC documentation explicitly state that they
+// support static_cast between void * and function pointers.
+
+ template< class DerivedClass >
+ inline void CopyFrom (DerivedClass *pParent, const CUtlAbstractDelegate &right)
+ {
+ pParent;
+ SetMementoFrom(right);
+ }
+ // For static functions, the 'static_function_invoker' class in the parent
+ // will be called. The parent then needs to call GetStaticFunction() to find out
+ // the actual function to invoke.
+ // ******** EVIL, EVIL CODE! *******
+ template < class DerivedClass, class ParentInvokerSig>
+ inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker,
+ StaticFuncPtr function_to_bind)
+ {
+ if (function_to_bind==0)
+ { // cope with assignment to 0
+ m_pFunction=0;
+ }
+ else
+ {
+ // We'll be ignoring the 'this' pointer, but we need to make sure we pass
+ // a valid value to bindmemfunc().
+ bindmemfunc(pParent, static_function_invoker);
+ }
+
+ // WARNING! Evil hack. We store the function in the 'this' pointer!
+ // Ensure that there's a compilation failure if function pointers
+ // and data pointers have different sizes.
+ // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK.
+ typedef int ERROR_CantUseEvilMethod[sizeof(GenericClass *)==sizeof(function_to_bind) ? 1 : -1];
+ m_pthis = horrible_cast<GenericClass *>(function_to_bind);
+ // MSVC, SunC++ and DMC accept the following (non-standard) code:
+// m_pthis = static_cast<GenericClass *>(static_cast<void *>(function_to_bind));
+ // BCC32, Comeau and DMC accept this method. MSVC7.1 needs __int64 instead of long
+// m_pthis = reinterpret_cast<GenericClass *>(reinterpret_cast<long>(function_to_bind));
+ }
+ // ******** EVIL, EVIL CODE! *******
+ // This function will be called with an invalid 'this' pointer!!
+ // We're just returning the 'this' pointer, converted into
+ // a function pointer!
+ inline UnvoidStaticFuncPtr GetStaticFunction() const
+ {
+ // Ensure that there's a compilation failure if function pointers
+ // and data pointers have different sizes.
+ // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK.
+ typedef int ERROR_CantUseEvilMethod[sizeof(UnvoidStaticFuncPtr)==sizeof(this) ? 1 : -1];
+ return horrible_cast<UnvoidStaticFuncPtr>(this);
+ }
+#endif // !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+
+ // Does the closure contain this static function?
+ inline bool IsEqualToStaticFuncPtr(StaticFuncPtr funcptr)
+ {
+ if (funcptr==0) return IsEmpty();
+ // For the Evil method, if it doesn't actually contain a static function, this will return an arbitrary
+ // value that is not equal to any valid function pointer.
+ else return funcptr==reinterpret_cast<StaticFuncPtr>(GetStaticFunction());
+ }
+};
+
+
+} // namespace detail
+
+////////////////////////////////////////////////////////////////////////////////
+// Fast Delegates, part 3:
+//
+// Wrapper classes to ensure type safety
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+// Once we have the member function conversion templates, it's easy to make the
+// wrapper classes. So that they will work with as many compilers as possible,
+// the classes are of the form
+// FastDelegate3<int, char *, double>
+// They can cope with any combination of parameters. The max number of parameters
+// allowed is 8, but it is trivial to increase this limit.
+// Note that we need to treat const member functions seperately.
+// All this class does is to enforce type safety, and invoke the delegate with
+// the correct list of parameters.
+
+// Because of the weird rule about the class of derived member function pointers,
+// you sometimes need to apply a downcast to the 'this' pointer.
+// This is the reason for the use of "implicit_cast<X*>(pthis)" in the code below.
+// If CDerivedClass is derived from CBaseClass, but doesn't override SimpleVirtualFunction,
+// without this trick you'd need to write:
+// MyDelegate(static_cast<CBaseClass *>(&d), &CDerivedClass::SimpleVirtualFunction);
+// but with the trick you can write
+// MyDelegate(&d, &CDerivedClass::SimpleVirtualFunction);
+
+// RetType is the type the compiler uses in compiling the template. For VC6,
+// it cannot be void. DesiredRetType is the real type which is returned from
+// all of the functions. It can be void.
+
+// Implicit conversion to "bool" is achieved using the safe_bool idiom,
+// using member data pointers (MDP). This allows "if (dg)..." syntax
+// Because some compilers (eg codeplay) don't have a unique value for a zero
+// MDP, an extra padding member is added to the SafeBool struct.
+// Some compilers (eg VC6) won't implicitly convert from 0 to an MDP, so
+// in that case the static function constructor is not made explicit; this
+// allows "if (dg==0) ..." to compile.
+
+//N=0
+template<class RetType=detail::DefaultVoid>
+class FastDelegate0
+{
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)();
+ typedef RetType (*UnvoidStaticFunctionPtr)();
+ typedef RetType (detail::GenericClass::*GenericMemFn)();
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate0 type;
+
+ // Construction and comparison functions
+ FastDelegate0() { Clear(); }
+ FastDelegate0(const FastDelegate0 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ void operator = (const FastDelegate0 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ bool operator ==(const FastDelegate0 &x) const
+ {
+ return m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator !=(const FastDelegate0 &x) const
+ {
+ return !m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator <(const FastDelegate0 &x) const
+ {
+ return m_Closure.IsLess(x.m_Closure);
+ }
+ bool operator >(const FastDelegate0 &x) const
+ {
+ return x.m_Closure.IsLess(m_Closure);
+ }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate0(Y *pthis, DesiredRetType (X::* function_to_bind)() )
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)())
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate0(const Y *pthis, DesiredRetType (X::* function_to_bind)() const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)() const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);
+ }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate0(DesiredRetType (*function_to_bind)() )
+ {
+ Bind(function_to_bind);
+ }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)() )
+ {
+ Bind(function_to_bind);
+ }
+ inline void Bind(DesiredRetType (*function_to_bind)())
+ {
+ m_Closure.bindstaticfunc(this, &FastDelegate0::InvokeStaticFunction,
+ function_to_bind);
+ }
+ // Invoke the delegate
+ RetType operator() () const
+ {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))();
+ }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct
+ {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const
+ {
+ return IsEmpty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr)
+ {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator!=(StaticFunctionPtr funcptr)
+ {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator ! () const
+ { // Is it bound to anything?
+ return !m_Closure;
+ }
+ inline bool IsEmpty() const
+ {
+ return !m_Closure;
+ }
+ void Clear() { m_Closure.Clear();}
+ // Conversion to and from the CUtlAbstractDelegate storage class
+ const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; }
+ void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction() const
+ {
+ return (*(m_Closure.GetStaticFunction()))();
+ }
+};
+
+//N=1
+template<class Param1, class RetType=detail::DefaultVoid>
+class FastDelegate1
+{
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate1 type;
+
+ // Construction and comparison functions
+ FastDelegate1() { Clear(); }
+ FastDelegate1(const FastDelegate1 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ void operator = (const FastDelegate1 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ bool operator ==(const FastDelegate1 &x) const
+ {
+ return m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator !=(const FastDelegate1 &x) const
+ {
+ return !m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator <(const FastDelegate1 &x) const
+ {
+ return m_Closure.IsLess(x.m_Closure);
+ }
+ bool operator >(const FastDelegate1 &x) const
+ {
+ return x.m_Closure.IsLess(m_Closure);
+ }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate1(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) )
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1))
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate1(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);
+ }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate1(DesiredRetType (*function_to_bind)(Param1 p1) )
+ {
+ Bind(function_to_bind);
+ }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1) )
+ {
+ Bind(function_to_bind);
+ }
+ inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1))
+ {
+ m_Closure.bindstaticfunc(this, &FastDelegate1::InvokeStaticFunction,
+ function_to_bind);
+ }
+ // Invoke the delegate
+ RetType operator() (Param1 p1) const
+ {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1);
+ }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct
+ {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const
+ {
+ return IsEmpty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr)
+ {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator!=(StaticFunctionPtr funcptr)
+ {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator ! () const
+ { // Is it bound to anything?
+ return !m_Closure;
+ }
+ inline bool IsEmpty() const
+ {
+ return !m_Closure;
+ }
+ void Clear() { m_Closure.Clear();}
+ // Conversion to and from the CUtlAbstractDelegate storage class
+ const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; }
+ void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1) const
+ {
+ return (*(m_Closure.GetStaticFunction()))(p1);
+ }
+};
+
+//N=2
+template<class Param1, class Param2, class RetType=detail::DefaultVoid>
+class FastDelegate2
+{
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate2 type;
+
+ // Construction and comparison functions
+ FastDelegate2() { Clear(); }
+ FastDelegate2(const FastDelegate2 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ void operator = (const FastDelegate2 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ bool operator ==(const FastDelegate2 &x) const
+ {
+ return m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator !=(const FastDelegate2 &x) const
+ {
+ return !m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator <(const FastDelegate2 &x) const
+ {
+ return m_Closure.IsLess(x.m_Closure);
+ }
+ bool operator >(const FastDelegate2 &x) const
+ {
+ return x.m_Closure.IsLess(m_Closure);
+ }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate2(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) )
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2))
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate2(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);
+ }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate2(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2) )
+ {
+ Bind(function_to_bind);
+ }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2) )
+ {
+ Bind(function_to_bind);
+ }
+ inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2))
+ {
+ m_Closure.bindstaticfunc(this, &FastDelegate2::InvokeStaticFunction,
+ function_to_bind);
+ }
+ // Invoke the delegate
+ RetType operator() (Param1 p1, Param2 p2) const
+ {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2);
+ }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct
+ {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const
+ {
+ return IsEmpty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr)
+ {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator!=(StaticFunctionPtr funcptr)
+ {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator ! () const
+ { // Is it bound to anything?
+ return !m_Closure;
+ }
+ inline bool IsEmpty() const
+ {
+ return !m_Closure;
+ }
+ void Clear() { m_Closure.Clear();}
+ // Conversion to and from the CUtlAbstractDelegate storage class
+ const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; }
+ void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1, Param2 p2) const
+ {
+ return (*(m_Closure.GetStaticFunction()))(p1, p2);
+ }
+};
+
+//N=3
+template<class Param1, class Param2, class Param3, class RetType=detail::DefaultVoid>
+class FastDelegate3
+{
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate3 type;
+
+ // Construction and comparison functions
+ FastDelegate3() { Clear(); }
+ FastDelegate3(const FastDelegate3 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ void operator = (const FastDelegate3 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ bool operator ==(const FastDelegate3 &x) const
+ {
+ return m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator !=(const FastDelegate3 &x) const
+ {
+ return !m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator <(const FastDelegate3 &x) const
+ {
+ return m_Closure.IsLess(x.m_Closure);
+ }
+ bool operator >(const FastDelegate3 &x) const
+ {
+ return x.m_Closure.IsLess(m_Closure);
+ }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate3(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) )
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3))
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate3(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);
+ }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate3(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3) )
+ {
+ Bind(function_to_bind);
+ }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3) )
+ {
+ Bind(function_to_bind);
+ }
+ inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3))
+ {
+ m_Closure.bindstaticfunc(this, &FastDelegate3::InvokeStaticFunction,
+ function_to_bind);
+ }
+ // Invoke the delegate
+ RetType operator() (Param1 p1, Param2 p2, Param3 p3) const
+ {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3);
+ }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct
+ {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const
+ {
+ return IsEmpty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr)
+ {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator!=(StaticFunctionPtr funcptr)
+ {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator ! () const
+ { // Is it bound to anything?
+ return !m_Closure;
+ }
+ inline bool IsEmpty() const
+ {
+ return !m_Closure;
+ }
+ void Clear() { m_Closure.Clear();}
+ // Conversion to and from the CUtlAbstractDelegate storage class
+ const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; }
+ void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3) const
+ {
+ return (*(m_Closure.GetStaticFunction()))(p1, p2, p3);
+ }
+};
+
+//N=4
+template<class Param1, class Param2, class Param3, class Param4, class RetType=detail::DefaultVoid>
+class FastDelegate4
+{
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate4 type;
+
+ // Construction and comparison functions
+ FastDelegate4() { Clear(); }
+ FastDelegate4(const FastDelegate4 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ void operator = (const FastDelegate4 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ bool operator ==(const FastDelegate4 &x) const
+ {
+ return m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator !=(const FastDelegate4 &x) const
+ {
+ return !m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator <(const FastDelegate4 &x) const
+ {
+ return m_Closure.IsLess(x.m_Closure);
+ }
+ bool operator >(const FastDelegate4 &x) const
+ {
+ return x.m_Closure.IsLess(m_Closure);
+ }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate4(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) )
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4))
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate4(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);
+ }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate4(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) )
+ {
+ Bind(function_to_bind);
+ }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) )
+ {
+ Bind(function_to_bind);
+ }
+ inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4))
+ {
+ m_Closure.bindstaticfunc(this, &FastDelegate4::InvokeStaticFunction,
+ function_to_bind);
+ }
+ // Invoke the delegate
+ RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4) const
+ {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4);
+ }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct
+ {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const
+ {
+ return IsEmpty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr)
+ {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator!=(StaticFunctionPtr funcptr)
+ {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator ! () const
+ { // Is it bound to anything?
+ return !m_Closure;
+ }
+ inline bool IsEmpty() const
+ {
+ return !m_Closure;
+ }
+ void Clear() { m_Closure.Clear();}
+ // Conversion to and from the CUtlAbstractDelegate storage class
+ const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; }
+ void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const
+ {
+ return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4);
+ }
+};
+
+//N=5
+template<class Param1, class Param2, class Param3, class Param4, class Param5, class RetType=detail::DefaultVoid>
+class FastDelegate5
+{
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate5 type;
+
+ // Construction and comparison functions
+ FastDelegate5() { Clear(); }
+ FastDelegate5(const FastDelegate5 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ void operator = (const FastDelegate5 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ bool operator ==(const FastDelegate5 &x) const
+ {
+ return m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator !=(const FastDelegate5 &x) const
+ {
+ return !m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator <(const FastDelegate5 &x) const
+ {
+ return m_Closure.IsLess(x.m_Closure);
+ }
+ bool operator >(const FastDelegate5 &x) const
+ {
+ return x.m_Closure.IsLess(m_Closure);
+ }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate5(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) )
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5))
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate5(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);
+ }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate5(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) )
+ {
+ Bind(function_to_bind);
+ }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) )
+ {
+ Bind(function_to_bind);
+ }
+ inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5))
+ {
+ m_Closure.bindstaticfunc(this, &FastDelegate5::InvokeStaticFunction,
+ function_to_bind);
+ }
+ // Invoke the delegate
+ RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const
+ {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5);
+ }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct
+ {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const
+ {
+ return IsEmpty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr)
+ {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator!=(StaticFunctionPtr funcptr)
+ {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator ! () const
+ { // Is it bound to anything?
+ return !m_Closure;
+ }
+ inline bool IsEmpty() const
+ {
+ return !m_Closure;
+ }
+ void Clear() { m_Closure.Clear();}
+ // Conversion to and from the CUtlAbstractDelegate storage class
+ const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; }
+ void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const
+ {
+ return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5);
+ }
+};
+
+//N=6
+template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class RetType=detail::DefaultVoid>
+class FastDelegate6
+{
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate6 type;
+
+ // Construction and comparison functions
+ FastDelegate6() { Clear(); }
+ FastDelegate6(const FastDelegate6 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ void operator = (const FastDelegate6 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ bool operator ==(const FastDelegate6 &x) const
+ {
+ return m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator !=(const FastDelegate6 &x) const
+ {
+ return !m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator <(const FastDelegate6 &x) const
+ {
+ return m_Closure.IsLess(x.m_Closure);
+ }
+ bool operator >(const FastDelegate6 &x) const
+ {
+ return x.m_Closure.IsLess(m_Closure);
+ }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate6(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) )
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6))
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate6(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);
+ }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate6(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) )
+ {
+ Bind(function_to_bind);
+ }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) )
+ {
+ Bind(function_to_bind);
+ }
+ inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6))
+ {
+ m_Closure.bindstaticfunc(this, &FastDelegate6::InvokeStaticFunction,
+ function_to_bind);
+ }
+ // Invoke the delegate
+ RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const
+ {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6);
+ }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct
+ {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const
+ {
+ return IsEmpty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr)
+ {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator!=(StaticFunctionPtr funcptr)
+ {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator ! () const
+ { // Is it bound to anything?
+ return !m_Closure;
+ }
+ inline bool IsEmpty() const
+ {
+ return !m_Closure;
+ }
+ void Clear() { m_Closure.Clear();}
+ // Conversion to and from the CUtlAbstractDelegate storage class
+ const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; }
+ void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const
+ {
+ return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6);
+ }
+};
+
+//N=7
+template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class RetType=detail::DefaultVoid>
+class FastDelegate7
+{
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate7 type;
+
+ // Construction and comparison functions
+ FastDelegate7() { Clear(); }
+ FastDelegate7(const FastDelegate7 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ void operator = (const FastDelegate7 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ bool operator ==(const FastDelegate7 &x) const
+ {
+ return m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator !=(const FastDelegate7 &x) const
+ {
+ return !m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator <(const FastDelegate7 &x) const
+ {
+ return m_Closure.IsLess(x.m_Closure);
+ }
+ bool operator >(const FastDelegate7 &x) const
+ {
+ return x.m_Closure.IsLess(m_Closure);
+ }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate7(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) )
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7))
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate7(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);
+ }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate7(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) )
+ {
+ Bind(function_to_bind);
+ }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) )
+ {
+ Bind(function_to_bind);
+ }
+ inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7))
+ {
+ m_Closure.bindstaticfunc(this, &FastDelegate7::InvokeStaticFunction,
+ function_to_bind);
+ }
+ // Invoke the delegate
+ RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const
+ {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6, p7);
+ }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct
+ {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const
+ {
+ return IsEmpty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr)
+ {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator!=(StaticFunctionPtr funcptr)
+ {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator ! () const
+ { // Is it bound to anything?
+ return !m_Closure;
+ }
+ inline bool IsEmpty() const
+ {
+ return !m_Closure;
+ }
+ void Clear() { m_Closure.Clear();}
+ // Conversion to and from the CUtlAbstractDelegate storage class
+ const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; }
+ void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const
+ {
+ return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7);
+ }
+};
+
+//N=8
+template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class RetType=detail::DefaultVoid>
+class FastDelegate8
+{
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate8 type;
+
+ // Construction and comparison functions
+ FastDelegate8() { Clear(); }
+ FastDelegate8(const FastDelegate8 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ void operator = (const FastDelegate8 &x)
+ {
+ m_Closure.CopyFrom(this, x.m_Closure);
+ }
+ bool operator ==(const FastDelegate8 &x) const
+ {
+ return m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator !=(const FastDelegate8 &x) const
+ {
+ return !m_Closure.IsEqual(x.m_Closure);
+ }
+ bool operator <(const FastDelegate8 &x) const
+ {
+ return m_Closure.IsLess(x.m_Closure);
+ }
+ bool operator >(const FastDelegate8 &x) const
+ {
+ return x.m_Closure.IsLess(m_Closure);
+ }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate8(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) )
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8))
+ {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);
+ }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate8(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);
+ }
+ template < class X, class Y >
+ inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const)
+ {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);
+ }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate8(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) )
+ {
+ Bind(function_to_bind);
+ }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) )
+ {
+ Bind(function_to_bind);
+ }
+ inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8))
+ {
+ m_Closure.bindstaticfunc(this, &FastDelegate8::InvokeStaticFunction,
+ function_to_bind);
+ }
+ // Invoke the delegate
+ RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const
+ {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct
+ {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const
+ {
+ return IsEmpty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr)
+ {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator!=(StaticFunctionPtr funcptr)
+ {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr);
+ }
+ inline bool operator ! () const
+ { // Is it bound to anything?
+ return !m_Closure;
+ }
+ inline bool IsEmpty() const
+ {
+ return !m_Closure;
+ }
+ void Clear() { m_Closure.Clear();}
+ // Conversion to and from the CUtlAbstractDelegate storage class
+ const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; }
+ void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const
+ {
+ return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Fast Delegates, part 4:
+//
+// CUtlDelegate<> class (Original author: Jody Hagins)
+// Allows boost::function style syntax like:
+// CUtlDelegate< double (int, long) >
+// instead of:
+// FastDelegate2< int, long, double >
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
+
+// Declare CUtlDelegate as a class template. It will be specialized
+// later for all number of arguments.
+template <typename Signature>
+class CUtlDelegate;
+
+//N=0
+// Specialization to allow use of
+// CUtlDelegate< R ( ) >
+// instead of
+// FastDelegate0 < R >
+template<typename R>
+class CUtlDelegate< R ( ) >
+ // Inherit from FastDelegate0 so that it can be treated just like a FastDelegate0
+ : public FastDelegate0 < R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate0 < R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef CUtlDelegate SelfType;
+
+ // Mimic the base class constructors.
+ CUtlDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ CUtlDelegate(Y * pthis, R (X::* function_to_bind)( ))
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ template < class X, class Y >
+ CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ CUtlDelegate(R (*function_to_bind)( ))
+ : BaseType(function_to_bind)
+ { }
+
+ void operator = (const BaseType &x)
+ {
+ *static_cast<BaseType*>(this) = x;
+ }
+};
+
+//N=1
+// Specialization to allow use of
+// CUtlDelegate< R ( Param1 ) >
+// instead of
+// FastDelegate1 < Param1, R >
+template<typename R, class Param1>
+class CUtlDelegate< R ( Param1 ) >
+ // Inherit from FastDelegate1 so that it can be treated just like a FastDelegate1
+ : public FastDelegate1 < Param1, R >
+{
+ public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate1 < Param1, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef CUtlDelegate SelfType;
+
+ // Mimic the base class constructors.
+ CUtlDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1 ))
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ template < class X, class Y >
+ CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ CUtlDelegate(R (*function_to_bind)( Param1 p1 ))
+ : BaseType(function_to_bind)
+ { }
+
+ void operator = (const BaseType &x)
+ {
+ *static_cast<BaseType*>(this) = x;
+ }
+};
+
+//N=2
+// Specialization to allow use of
+// CUtlDelegate< R ( Param1, Param2 ) >
+// instead of
+// FastDelegate2 < Param1, Param2, R >
+template<typename R, class Param1, class Param2>
+class CUtlDelegate< R ( Param1, Param2 ) >
+ // Inherit from FastDelegate2 so that it can be treated just like a FastDelegate2
+ : public FastDelegate2 < Param1, Param2, R >
+{
+ public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate2 < Param1, Param2, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef CUtlDelegate SelfType;
+
+ // Mimic the base class constructors.
+ CUtlDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2 ))
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ template < class X, class Y >
+ CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ CUtlDelegate(R (*function_to_bind)( Param1 p1, Param2 p2 ))
+ : BaseType(function_to_bind)
+ { }
+
+ void operator = (const BaseType &x)
+ {
+ *static_cast<BaseType*>(this) = x;
+ }
+};
+
+//N=3
+// Specialization to allow use of
+// CUtlDelegate< R ( Param1, Param2, Param3 ) >
+// instead of
+// FastDelegate3 < Param1, Param2, Param3, R >
+template<typename R, class Param1, class Param2, class Param3>
+class CUtlDelegate< R ( Param1, Param2, Param3 ) >
+ // Inherit from FastDelegate3 so that it can be treated just like a FastDelegate3
+ : public FastDelegate3 < Param1, Param2, Param3, R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate3 < Param1, Param2, Param3, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef CUtlDelegate SelfType;
+
+ // Mimic the base class constructors.
+ CUtlDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3 ))
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ template < class X, class Y >
+ CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ CUtlDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3 ))
+ : BaseType(function_to_bind)
+ { }
+
+ void operator = (const BaseType &x)
+ {
+ *static_cast<BaseType*>(this) = x;
+ }
+};
+
+//N=4
+// Specialization to allow use of
+// CUtlDelegate< R ( Param1, Param2, Param3, Param4 ) >
+// instead of
+// FastDelegate4 < Param1, Param2, Param3, Param4, R >
+template<typename R, class Param1, class Param2, class Param3, class Param4>
+class CUtlDelegate< R ( Param1, Param2, Param3, Param4 ) >
+ // Inherit from FastDelegate4 so that it can be treated just like a FastDelegate4
+ : public FastDelegate4 < Param1, Param2, Param3, Param4, R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate4 < Param1, Param2, Param3, Param4, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef CUtlDelegate SelfType;
+
+ // Mimic the base class constructors.
+ CUtlDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ))
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ template < class X, class Y >
+ CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ CUtlDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ))
+ : BaseType(function_to_bind)
+ { }
+
+ void operator = (const BaseType &x)
+ {
+ *static_cast<BaseType*>(this) = x;
+ }
+};
+
+//N=5
+// Specialization to allow use of
+// CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5 ) >
+// instead of
+// FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R >
+template<typename R, class Param1, class Param2, class Param3, class Param4, class Param5>
+class CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5 ) >
+ // Inherit from FastDelegate5 so that it can be treated just like a FastDelegate5
+ : public FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef CUtlDelegate SelfType;
+
+ // Mimic the base class constructors.
+ CUtlDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ))
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ template < class X, class Y >
+ CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ CUtlDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ))
+ : BaseType(function_to_bind)
+ { }
+
+ void operator = (const BaseType &x)
+ {
+ *static_cast<BaseType*>(this) = x;
+ }
+};
+
+//N=6
+// Specialization to allow use of
+// CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6 ) >
+// instead of
+// FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R >
+template<typename R, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>
+class CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6 ) >
+ // Inherit from FastDelegate6 so that it can be treated just like a FastDelegate6
+ : public FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef CUtlDelegate SelfType;
+
+ // Mimic the base class constructors.
+ CUtlDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ))
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ template < class X, class Y >
+ CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ CUtlDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ))
+ : BaseType(function_to_bind)
+ { }
+
+ void operator = (const BaseType &x)
+ {
+ *static_cast<BaseType*>(this) = x;
+ }
+};
+
+//N=7
+// Specialization to allow use of
+// CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) >
+// instead of
+// FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R >
+template<typename R, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>
+class CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) >
+ // Inherit from FastDelegate7 so that it can be treated just like a FastDelegate7
+ : public FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef CUtlDelegate SelfType;
+
+ // Mimic the base class constructors.
+ CUtlDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ))
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ template < class X, class Y >
+ CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ CUtlDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ))
+ : BaseType(function_to_bind)
+ { }
+
+ void operator = (const BaseType &x)
+ {
+ *static_cast<BaseType*>(this) = x;
+ }
+};
+
+//N=8
+// Specialization to allow use of
+// CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) >
+// instead of
+// FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R >
+template<typename R, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>
+class CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) >
+ // Inherit from FastDelegate8 so that it can be treated just like a FastDelegate8
+ : public FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef CUtlDelegate SelfType;
+
+ // Mimic the base class constructors.
+ CUtlDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ))
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ template < class X, class Y >
+ CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ CUtlDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ))
+ : BaseType(function_to_bind)
+ { }
+
+ void operator = (const BaseType &x)
+ {
+ *static_cast<BaseType*>(this) = x;
+ }
+};
+
+
+#endif //FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
+
+////////////////////////////////////////////////////////////////////////////////
+// Fast Delegates, part 5:
+//
+// UtlMakeDelegate() helper function
+//
+// UtlMakeDelegate(&x, &X::func) returns a fastdelegate of the type
+// necessary for calling x.func() with the correct number of arguments.
+// This makes it possible to eliminate many typedefs from user code.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Also declare overloads of a UtlMakeDelegate() global function to
+// reduce the need for typedefs.
+// We need seperate overloads for const and non-const member functions.
+// Also, because of the weird rule about the class of derived member function pointers,
+// implicit downcasts may need to be applied later to the 'this' pointer.
+// That's why two classes (X and Y) appear in the definitions. Y must be implicitly
+// castable to X.
+
+// Workaround for VC6. VC6 needs void return types converted into DefaultVoid.
+// GCC 3.2 and later won't compile this unless it's preceded by 'typename',
+// but VC6 doesn't allow 'typename' in this context.
+// So, I have to use a macro.
+
+#ifdef FASTDLGT_VC6
+#define FASTDLGT_RETTYPE detail::VoidToDefaultVoid<RetType>::type
+#else
+#define FASTDLGT_RETTYPE RetType
+#endif
+
+
+//N=0
+template <class X, class Y, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( ) > UtlMakeDelegate(Y* x, RetType (X::*func)())
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( ) >(x, func);
+}
+
+template <class X, class Y, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( ) > UtlMakeDelegate(Y* x, RetType (X::*func)() const)
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( ) >(x, func);
+}
+
+template < class RetType >
+CUtlDelegate< FASTDLGT_RETTYPE ( ) > UtlMakeDelegate( RetType (*func)())
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( ) >( func );
+}
+
+//N=1
+template <class X, class Y, class Param1, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1 ) >(x, func);
+}
+
+template <class X, class Y, class Param1, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1) const)
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1 ) >(x, func);
+}
+
+template < class Param1, class RetType >
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1 ) > UtlMakeDelegate( RetType (*func)(Param1 p1))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1 ) >( func );
+}
+
+
+//N=2
+template <class X, class Y, class Param1, class Param2, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2 ) >(x, func);
+}
+
+template <class X, class Y, class Param1, class Param2, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2) const)
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2 ) >(x, func);
+}
+
+template <class Param1, class Param2, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2 ) > UtlMakeDelegate( RetType (*func)(Param1 p1, Param2 p2))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2 ) >(func);
+}
+
+//N=3
+template <class X, class Y, class Param1, class Param2, class Param3, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3 ) >(x, func);
+}
+
+template <class X, class Y, class Param1, class Param2, class Param3, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3) const)
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3 ) >(x, func);
+}
+
+template <class Param1, class Param2, class Param3, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3 ) > UtlMakeDelegate( RetType (*func)(Param1 p1, Param2 p2, Param3 p3))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3 ) >(func);
+}
+
+//N=4
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4 ) >(x, func);
+}
+
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const)
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4 ) >(x, func);
+}
+
+template <class Param1, class Param2, class Param3, class Param4, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4 ) > UtlMakeDelegate(RetType (*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4 ) >(func);
+}
+
+//N=5
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5 ) >(x, func);
+}
+
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const)
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5 ) >(x, func);
+}
+
+template <class Param1, class Param2, class Param3, class Param4, class Param5, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5 ) > UtlMakeDelegate(RetType (*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5 ) >(func);
+}
+
+//N=6
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6 ) >(x, func);
+}
+
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const)
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6 ) >(x, func);
+}
+
+template <class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6 ) > UtlMakeDelegate(RetType (*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6 ) >(func);
+}
+
+//N=7
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) >(x, func);
+}
+
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const)
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) >(x, func);
+}
+
+template <class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) > UtlMakeDelegate(RetType (*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) >(func);
+}
+
+//N=8
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) >(x, func);
+}
+
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const)
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) >(x, func);
+}
+
+template <class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class RetType>
+CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) > UtlMakeDelegate(RetType (*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8))
+{
+ return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) >(func);
+}
+
+
+// clean up after ourselves...
+#undef FASTDLGT_RETTYPE
+
+#endif // !defined(UTLDELEGATEIMPL_H)
+
diff --git a/public/tier1/utldict.h b/public/tier1/utldict.h
new file mode 100644
index 0000000..cb0455a
--- /dev/null
+++ b/public/tier1/utldict.h
@@ -0,0 +1,358 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A dictionary mapping from symbol to structure
+//
+// $Header: $
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef UTLDICT_H
+#define UTLDICT_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/dbg.h"
+#include "tier1/utlmap.h"
+
+// Include this because tons of code was implicitly getting utlsymbol or utlvector via utldict.h
+#include "tier1/utlsymbol.h"
+
+#include "tier0/memdbgon.h"
+
+enum EDictCompareType
+{
+ k_eDictCompareTypeCaseSensitive=0,
+ k_eDictCompareTypeCaseInsensitive=1,
+ k_eDictCompareTypeFilenames // Slashes and backslashes count as the same character..
+};
+
+//-----------------------------------------------------------------------------
+// A dictionary mapping from symbol to structure
+//-----------------------------------------------------------------------------
+#define FOR_EACH_DICT( dictName, iteratorName ) \
+ for( int iteratorName=dictName.First(); iteratorName != dictName.InvalidIndex(); iteratorName = dictName.Next( iteratorName ) )
+
+// faster iteration, but in an unspecified order
+#define FOR_EACH_DICT_FAST( dictName, iteratorName ) \
+ for ( int iteratorName = 0; iteratorName < dictName.MaxElement(); ++iteratorName ) if ( !dictName.IsValidIndex( iteratorName ) ) continue; else
+
+//-----------------------------------------------------------------------------
+// A dictionary mapping from symbol to structure
+//-----------------------------------------------------------------------------
+template <class T, class I = int >
+class CUtlDict
+{
+public:
+ // constructor, destructor
+ // Left at growSize = 0, the memory will first allocate 1 element and double in size
+ // at each increment.
+ CUtlDict( int compareType = k_eDictCompareTypeCaseInsensitive, int growSize = 0, int initSize = 0 );
+ ~CUtlDict( );
+
+ void EnsureCapacity( int );
+
+ // gets particular elements
+ T& Element( I i );
+ const T& Element( I i ) const;
+ T& operator[]( I i );
+ const T& operator[]( I i ) const;
+
+ // gets element names
+ char *GetElementName( I i );
+ char const *GetElementName( I i ) const;
+
+ void SetElementName( I i, char const *pName );
+
+ // Number of elements
+ unsigned int Count() const;
+
+ // Number of allocated slots
+ I MaxElement() const;
+
+ // Checks if a node is valid and in the tree
+ bool IsValidIndex( I i ) const;
+
+ // Invalid index
+ static I InvalidIndex();
+
+ // Insert method (inserts in order)
+ I Insert( const char *pName, const T &element );
+ I Insert( const char *pName );
+
+ // Find method
+ I Find( const char *pName ) const;
+ bool HasElement( const char *pName ) const;
+
+ // Remove methods
+ void RemoveAt( I i );
+ void Remove( const char *pName );
+ void RemoveAll( );
+
+ // Purge memory
+ void Purge();
+ void PurgeAndDeleteElements(); // Call delete on each element.
+
+ // Iteration methods
+ I First() const;
+ I Next( I i ) const;
+
+ // Nested typedefs, for code that might need
+ // to fish out the index type from a given dict
+ typedef I IndexType_t;
+
+protected:
+ typedef CUtlMap<const char *, T, I> DictElementMap_t;
+ DictElementMap_t m_Elements;
+};
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+template <class T, class I>
+CUtlDict<T, I>::CUtlDict( int compareType, int growSize, int initSize ) : m_Elements( growSize, initSize )
+{
+ if ( compareType == k_eDictCompareTypeFilenames )
+ {
+ m_Elements.SetLessFunc( CaselessStringLessThanIgnoreSlashes );
+ }
+ else if ( compareType == k_eDictCompareTypeCaseInsensitive )
+ {
+ m_Elements.SetLessFunc( CaselessStringLessThan );
+ }
+ else
+ {
+ m_Elements.SetLessFunc( StringLessThan );
+ }
+}
+
+template <class T, class I>
+CUtlDict<T, I>::~CUtlDict()
+{
+ Purge();
+}
+
+template <class T, class I>
+inline void CUtlDict<T, I>::EnsureCapacity( int num )
+{
+ return m_Elements.EnsureCapacity( num );
+}
+
+//-----------------------------------------------------------------------------
+// gets particular elements
+//-----------------------------------------------------------------------------
+template <class T, class I>
+inline T& CUtlDict<T, I>::Element( I i )
+{
+ return m_Elements[i];
+}
+
+template <class T, class I>
+inline const T& CUtlDict<T, I>::Element( I i ) const
+{
+ return m_Elements[i];
+}
+
+//-----------------------------------------------------------------------------
+// gets element names
+//-----------------------------------------------------------------------------
+template <class T, class I>
+inline char *CUtlDict<T, I>::GetElementName( I i )
+{
+ return (char *)m_Elements.Key( i );
+}
+
+template <class T, class I>
+inline char const *CUtlDict<T, I>::GetElementName( I i ) const
+{
+ return m_Elements.Key( i );
+}
+
+template <class T, class I>
+inline T& CUtlDict<T, I>::operator[]( I i )
+{
+ return Element(i);
+}
+
+template <class T, class I>
+inline const T & CUtlDict<T, I>::operator[]( I i ) const
+{
+ return Element(i);
+}
+
+template <class T, class I>
+inline void CUtlDict<T, I>::SetElementName( I i, char const *pName )
+{
+ MEM_ALLOC_CREDIT_CLASS();
+ // TODO: This makes a copy of the old element
+ // TODO: This relies on the rb tree putting the most recently
+ // removed element at the head of the insert list
+ free( (void *)m_Elements.Key( i ) );
+ m_Elements.Reinsert( strdup( pName ), i );
+}
+
+//-----------------------------------------------------------------------------
+// Num elements
+//-----------------------------------------------------------------------------
+template <class T, class I>
+inline unsigned int CUtlDict<T, I>::Count() const
+{
+ return m_Elements.Count();
+}
+
+//-----------------------------------------------------------------------------
+// Number of allocated slots
+//-----------------------------------------------------------------------------
+template <class T, class I>
+inline I CUtlDict<T, I>::MaxElement() const
+{
+ return m_Elements.MaxElement();
+}
+
+//-----------------------------------------------------------------------------
+// Checks if a node is valid and in the tree
+//-----------------------------------------------------------------------------
+template <class T, class I>
+inline bool CUtlDict<T, I>::IsValidIndex( I i ) const
+{
+ return m_Elements.IsValidIndex(i);
+}
+
+
+//-----------------------------------------------------------------------------
+// Invalid index
+//-----------------------------------------------------------------------------
+template <class T, class I>
+inline I CUtlDict<T, I>::InvalidIndex()
+{
+ return DictElementMap_t::InvalidIndex();
+}
+
+
+//-----------------------------------------------------------------------------
+// Delete a node from the tree
+//-----------------------------------------------------------------------------
+template <class T, class I>
+void CUtlDict<T, I>::RemoveAt(I elem)
+{
+ free( (void *)m_Elements.Key( elem ) );
+ m_Elements.RemoveAt(elem);
+}
+
+
+//-----------------------------------------------------------------------------
+// remove a node in the tree
+//-----------------------------------------------------------------------------
+template <class T, class I> void CUtlDict<T, I>::Remove( const char *search )
+{
+ I node = Find( search );
+ if (node != InvalidIndex())
+ {
+ RemoveAt(node);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Removes all nodes from the tree
+//-----------------------------------------------------------------------------
+template <class T, class I>
+void CUtlDict<T, I>::RemoveAll()
+{
+ typename DictElementMap_t::IndexType_t index = m_Elements.FirstInorder();
+ while ( index != m_Elements.InvalidIndex() )
+ {
+ free( (void *)m_Elements.Key( index ) );
+ index = m_Elements.NextInorder( index );
+ }
+
+ m_Elements.RemoveAll();
+}
+
+template <class T, class I>
+void CUtlDict<T, I>::Purge()
+{
+ RemoveAll();
+}
+
+
+template <class T, class I>
+void CUtlDict<T, I>::PurgeAndDeleteElements()
+{
+ // Delete all the elements.
+ I index = m_Elements.FirstInorder();
+ while ( index != m_Elements.InvalidIndex() )
+ {
+ free( (void *)m_Elements.Key( index ) );
+ delete m_Elements[index];
+ index = m_Elements.NextInorder( index );
+ }
+
+ m_Elements.RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// inserts a node into the tree
+//-----------------------------------------------------------------------------
+template <class T, class I>
+I CUtlDict<T, I>::Insert( const char *pName, const T &element )
+{
+ MEM_ALLOC_CREDIT_CLASS();
+ return m_Elements.Insert( strdup( pName ), element );
+}
+
+template <class T, class I>
+I CUtlDict<T, I>::Insert( const char *pName )
+{
+ MEM_ALLOC_CREDIT_CLASS();
+ return m_Elements.Insert( strdup( pName ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// finds a node in the tree
+//-----------------------------------------------------------------------------
+template <class T, class I>
+I CUtlDict<T, I>::Find( const char *pName ) const
+{
+ MEM_ALLOC_CREDIT_CLASS();
+ if ( pName )
+ return m_Elements.Find( pName );
+ else
+ return InvalidIndex();
+}
+
+//-----------------------------------------------------------------------------
+// returns true if we already have this node
+//-----------------------------------------------------------------------------
+template <class T, class I>
+bool CUtlDict<T, I>::HasElement( const char *pName ) const
+{
+ if ( pName )
+ return m_Elements.IsValidIndex( m_Elements.Find( pName ) );
+ else
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Iteration methods
+//-----------------------------------------------------------------------------
+template <class T, class I>
+I CUtlDict<T, I>::First() const
+{
+ return m_Elements.FirstInorder();
+}
+
+template <class T, class I>
+I CUtlDict<T, I>::Next( I i ) const
+{
+ return m_Elements.NextInorder(i);
+}
+
+#include "tier0/memdbgoff.h"
+
+#endif // UTLDICT_H
diff --git a/public/tier1/utlenvelope.h b/public/tier1/utlenvelope.h
new file mode 100644
index 0000000..3de254a
--- /dev/null
+++ b/public/tier1/utlenvelope.h
@@ -0,0 +1,241 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A class to wrap data for transport over a boundary like a thread
+// or window.
+//
+//=============================================================================
+
+#include "tier1/utlstring.h"
+#include "tier0/basetypes.h"
+
+#ifndef UTLENVELOPE_H
+#define UTLENVELOPE_H
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+
+//-----------------------------------------------------------------------------
+
+class CUtlDataEnvelope
+{
+public:
+ CUtlDataEnvelope( const void *pData, int nBytes );
+ CUtlDataEnvelope( const CUtlDataEnvelope &from );
+ ~CUtlDataEnvelope();
+
+ CUtlDataEnvelope &operator=( const CUtlDataEnvelope &from );
+
+ operator void *();
+ operator void *() const;
+
+private:
+ void Assign( const void *pData, int nBytes );
+ void Assign( const CUtlDataEnvelope &from );
+ void Purge();
+
+ // TODO: switch to a reference counted array?
+ union
+ {
+ byte *m_pData;
+ byte m_data[4];
+ };
+ int m_nBytes;
+};
+
+
+//-----------------------------------------------------------------------------
+
+template <typename T>
+class CUtlEnvelope : protected CUtlDataEnvelope
+{
+public:
+ CUtlEnvelope( const T *pData, int nElems = 1 );
+ CUtlEnvelope( const CUtlEnvelope<T> &from );
+
+ CUtlEnvelope<T> &operator=( const CUtlEnvelope<T> &from );
+
+ operator T *();
+ operator T *() const;
+
+ operator void *();
+ operator void *() const;
+};
+
+//-----------------------------------------------------------------------------
+
+template <>
+class CUtlEnvelope<const char *>
+{
+public:
+ CUtlEnvelope( const char *pData )
+ {
+ m_string = pData;
+ }
+
+ CUtlEnvelope( const CUtlEnvelope<const char *> &from )
+ {
+ m_string = from.m_string;
+ }
+
+ CUtlEnvelope<const char *> &operator=( const CUtlEnvelope<const char *> &from )
+ {
+ m_string = from.m_string;
+ return *this;
+ }
+
+ operator char *()
+ {
+ return (char *) m_string.Get();
+ }
+
+ operator char *() const
+ {
+ return (char *) m_string.Get();
+ }
+
+ operator void *()
+ {
+ return (void *) m_string.Get();
+ }
+
+ operator void *() const
+ {
+ return (void *) m_string.Get();
+ }
+
+private:
+ CUtlString m_string;
+};
+
+//-----------------------------------------------------------------------------
+
+#include "tier0/memdbgon.h"
+
+inline void CUtlDataEnvelope::Assign( const void *pData, int nBytes )
+{
+ if ( pData )
+ {
+ m_nBytes = nBytes;
+ if ( m_nBytes > 4 )
+ {
+ m_pData = new byte[nBytes];
+ memcpy( m_pData, pData, nBytes );
+ }
+ else
+ {
+ memcpy( m_data, pData, nBytes );
+ }
+ }
+ else
+ {
+ m_pData = NULL;
+ m_nBytes = 0;
+ }
+}
+
+inline void CUtlDataEnvelope::Assign( const CUtlDataEnvelope &from )
+{
+ Assign( from.operator void *(), from.m_nBytes );
+}
+
+inline void CUtlDataEnvelope::Purge()
+{
+ if (m_nBytes > 4)
+ delete [] m_pData;
+ m_nBytes = 0;
+}
+
+inline CUtlDataEnvelope::CUtlDataEnvelope( const void *pData, int nBytes )
+{
+ Assign( pData, nBytes );
+}
+
+inline CUtlDataEnvelope::CUtlDataEnvelope( const CUtlDataEnvelope &from )
+{
+ Assign( from );
+}
+
+inline CUtlDataEnvelope::~CUtlDataEnvelope()
+{
+ Purge();
+}
+
+inline CUtlDataEnvelope &CUtlDataEnvelope::operator=( const CUtlDataEnvelope &from )
+{
+ Purge();
+ Assign( from );
+ return *this;
+}
+
+inline CUtlDataEnvelope::operator void *()
+{
+ if ( !m_nBytes )
+ {
+ return NULL;
+ }
+
+ return ( m_nBytes > 4) ? m_pData : m_data;
+}
+
+inline CUtlDataEnvelope::operator void *() const
+{
+ if ( !m_nBytes )
+ {
+ return NULL;
+ }
+
+ return ( m_nBytes > 4) ? (void *)m_pData : (void *)m_data;
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T>
+inline CUtlEnvelope<T>::CUtlEnvelope( const T *pData, int nElems )
+ : CUtlDataEnvelope( pData, sizeof(T) * nElems )
+{
+}
+
+template <typename T>
+inline CUtlEnvelope<T>::CUtlEnvelope( const CUtlEnvelope<T> &from )
+ : CUtlDataEnvelope( from )
+{
+
+}
+
+template <typename T>
+inline CUtlEnvelope<T> &CUtlEnvelope<T>::operator=( const CUtlEnvelope<T> &from )
+{
+ CUtlDataEnvelope::operator=( from );
+ return *this;
+}
+
+template <typename T>
+inline CUtlEnvelope<T>::operator T *()
+{
+ return (T *)CUtlDataEnvelope::operator void *();
+}
+
+template <typename T>
+inline CUtlEnvelope<T>::operator T *() const
+{
+ return (T *)( (const_cast<CUtlEnvelope<T> *>(this))->operator T *() );
+}
+
+template <typename T>
+inline CUtlEnvelope<T>::operator void *()
+{
+ return CUtlDataEnvelope::operator void *();
+}
+
+template <typename T>
+inline CUtlEnvelope<T>::operator void *() const
+{
+ return ( (const_cast<CUtlEnvelope<T> *>(this))->operator void *() );
+}
+
+//-----------------------------------------------------------------------------
+
+#include "tier0/memdbgoff.h"
+
+#endif // UTLENVELOPE_H
diff --git a/public/tier1/utlfixedmemory.h b/public/tier1/utlfixedmemory.h
new file mode 100644
index 0000000..6ff8c19
--- /dev/null
+++ b/public/tier1/utlfixedmemory.h
@@ -0,0 +1,354 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+// A growable memory class.
+//===========================================================================//
+
+#ifndef UTLFIXEDMEMORY_H
+#define UTLFIXEDMEMORY_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/dbg.h"
+#include "tier0/platform.h"
+
+#include "tier0/memalloc.h"
+#include "tier0/memdbgon.h"
+
+#pragma warning (disable:4100)
+#pragma warning (disable:4514)
+
+//-----------------------------------------------------------------------------
+
+#ifdef UTLFIXEDMEMORY_TRACK
+#define UTLFIXEDMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
+#define UTLFIXEDMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
+#else
+#define UTLFIXEDMEMORY_TRACK_ALLOC() ((void)0)
+#define UTLFIXEDMEMORY_TRACK_FREE() ((void)0)
+#endif
+
+
+//-----------------------------------------------------------------------------
+// The CUtlFixedMemory class:
+// A growable memory class that allocates non-sequential blocks, but is indexed sequentially
+//-----------------------------------------------------------------------------
+template< class T >
+class CUtlFixedMemory
+{
+public:
+ // constructor, destructor
+ CUtlFixedMemory( int nGrowSize = 0, int nInitSize = 0 );
+ ~CUtlFixedMemory();
+
+ // Set the size by which the memory grows
+ void Init( int nGrowSize = 0, int nInitSize = 0 );
+
+ // here to match CUtlMemory, but only used by ResetDbgInfo, so it can just return NULL
+ T* Base() { return NULL; }
+ const T* Base() const { return NULL; }
+
+protected:
+ struct BlockHeader_t;
+
+public:
+ class Iterator_t
+ {
+ public:
+ Iterator_t( BlockHeader_t *p, int i ) : m_pBlockHeader( p ), m_nIndex( i ) {}
+ BlockHeader_t *m_pBlockHeader;
+ intp m_nIndex;
+
+ bool operator==( const Iterator_t it ) const { return m_pBlockHeader == it.m_pBlockHeader && m_nIndex == it.m_nIndex; }
+ bool operator!=( const Iterator_t it ) const { return m_pBlockHeader != it.m_pBlockHeader || m_nIndex != it.m_nIndex; }
+ };
+ Iterator_t First() const { return m_pBlocks ? Iterator_t( m_pBlocks, 0 ) : InvalidIterator(); }
+ Iterator_t Next( const Iterator_t &it ) const
+ {
+ Assert( IsValidIterator( it ) );
+ if ( !IsValidIterator( it ) )
+ return InvalidIterator();
+
+ BlockHeader_t * RESTRICT pHeader = it.m_pBlockHeader;
+ if ( it.m_nIndex + 1 < pHeader->m_nBlockSize )
+ return Iterator_t( pHeader, it.m_nIndex + 1 );
+
+ return pHeader->m_pNext ? Iterator_t( pHeader->m_pNext, 0 ) : InvalidIterator();
+ }
+ intp GetIndex( const Iterator_t &it ) const
+ {
+ Assert( IsValidIterator( it ) );
+ if ( !IsValidIterator( it ) )
+ return InvalidIndex();
+
+ return ( intp )( HeaderToBlock( it.m_pBlockHeader ) + it.m_nIndex );
+ }
+ bool IsIdxAfter( intp i, const Iterator_t &it ) const
+ {
+ Assert( IsValidIterator( it ) );
+ if ( !IsValidIterator( it ) )
+ return false;
+
+ if ( IsInBlock( i, it.m_pBlockHeader ) )
+ return i > GetIndex( it );
+
+ for ( BlockHeader_t * RESTRICT pbh = it.m_pBlockHeader->m_pNext; pbh; pbh = pbh->m_pNext )
+ {
+ if ( IsInBlock( i, pbh ) )
+ return true;
+ }
+ return false;
+ }
+ bool IsValidIterator( const Iterator_t &it ) const { return it.m_pBlockHeader && it.m_nIndex >= 0 && it.m_nIndex < it.m_pBlockHeader->m_nBlockSize; }
+ Iterator_t InvalidIterator() const { return Iterator_t( NULL, INVALID_INDEX ); }
+
+ // element access
+ T& operator[]( intp i );
+ const T& operator[]( intp i ) const;
+ T& Element( intp i );
+ const T& Element( intp i ) const;
+
+ // Can we use this index?
+ bool IsIdxValid( intp i ) const;
+
+ // Specify the invalid ('null') index that we'll only return on failure
+ static const intp INVALID_INDEX = 0; // For use with COMPILE_TIME_ASSERT
+ static intp InvalidIndex() { return INVALID_INDEX; }
+
+ // Size
+ int NumAllocated() const;
+ int Count() const { return NumAllocated(); }
+
+ // Grows memory by max(num,growsize), and returns the allocation index/ptr
+ void Grow( int num = 1 );
+
+ // Makes sure we've got at least this much memory
+ void EnsureCapacity( int num );
+
+ // Memory deallocation
+ void Purge();
+
+protected:
+ // Fast swap - WARNING: Swap invalidates all ptr-based indices!!!
+ void Swap( CUtlFixedMemory< T > &mem );
+
+ bool IsInBlock( intp i, BlockHeader_t *pBlockHeader ) const
+ {
+ T *p = ( T* )i;
+ const T *p0 = HeaderToBlock( pBlockHeader );
+ return p >= p0 && p < p0 + pBlockHeader->m_nBlockSize;
+ }
+
+ struct BlockHeader_t
+ {
+ BlockHeader_t *m_pNext;
+ intp m_nBlockSize;
+ };
+
+ const T *HeaderToBlock( const BlockHeader_t *pHeader ) const { return ( T* )( pHeader + 1 ); }
+ const BlockHeader_t *BlockToHeader( const T *pBlock ) const { return ( BlockHeader_t* )( pBlock ) - 1; }
+
+ BlockHeader_t* m_pBlocks;
+ int m_nAllocationCount;
+ int m_nGrowSize;
+};
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+
+template< class T >
+CUtlFixedMemory<T>::CUtlFixedMemory( int nGrowSize, int nInitAllocationCount )
+: m_pBlocks( 0 ), m_nAllocationCount( 0 ), m_nGrowSize( 0 )
+{
+ Init( nGrowSize, nInitAllocationCount );
+}
+
+template< class T >
+CUtlFixedMemory<T>::~CUtlFixedMemory()
+{
+ Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+// Fast swap - WARNING: Swap invalidates all ptr-based indices!!!
+//-----------------------------------------------------------------------------
+template< class T >
+void CUtlFixedMemory<T>::Swap( CUtlFixedMemory< T > &mem )
+{
+ V_swap( m_pBlocks, mem.m_pBlocks );
+ V_swap( m_nAllocationCount, mem.m_nAllocationCount );
+ V_swap( m_nGrowSize, mem.m_nGrowSize );
+}
+
+
+//-----------------------------------------------------------------------------
+// Set the size by which the memory grows - round up to the next power of 2
+//-----------------------------------------------------------------------------
+template< class T >
+void CUtlFixedMemory<T>::Init( int nGrowSize /* = 0 */, int nInitSize /* = 0 */ )
+{
+ Purge();
+
+ m_nGrowSize = nGrowSize;
+
+ Grow( nInitSize );
+}
+
+//-----------------------------------------------------------------------------
+// element access
+//-----------------------------------------------------------------------------
+template< class T >
+inline T& CUtlFixedMemory<T>::operator[]( intp i )
+{
+ Assert( IsIdxValid(i) );
+ return *( T* )i;
+}
+
+template< class T >
+inline const T& CUtlFixedMemory<T>::operator[]( intp i ) const
+{
+ Assert( IsIdxValid(i) );
+ return *( T* )i;
+}
+
+template< class T >
+inline T& CUtlFixedMemory<T>::Element( intp i )
+{
+ Assert( IsIdxValid(i) );
+ return *( T* )i;
+}
+
+template< class T >
+inline const T& CUtlFixedMemory<T>::Element( intp i ) const
+{
+ Assert( IsIdxValid(i) );
+ return *( T* )i;
+}
+
+
+//-----------------------------------------------------------------------------
+// Size
+//-----------------------------------------------------------------------------
+template< class T >
+inline int CUtlFixedMemory<T>::NumAllocated() const
+{
+ return m_nAllocationCount;
+}
+
+
+//-----------------------------------------------------------------------------
+// Is element index valid?
+//-----------------------------------------------------------------------------
+template< class T >
+inline bool CUtlFixedMemory<T>::IsIdxValid( intp i ) const
+{
+#ifdef _DEBUG
+ for ( BlockHeader_t *pbh = m_pBlocks; pbh; pbh = pbh->m_pNext )
+ {
+ if ( IsInBlock( i, pbh ) )
+ return true;
+ }
+ return false;
+#else
+ return i != InvalidIndex();
+#endif
+}
+
+template< class T >
+void CUtlFixedMemory<T>::Grow( int num )
+{
+ if ( num <= 0 )
+ return;
+
+ int nBlockSize = m_nGrowSize;
+ if ( nBlockSize == 0 )
+ {
+ if ( m_nAllocationCount )
+ {
+ nBlockSize = m_nAllocationCount;
+ }
+ else
+ {
+ // Compute an allocation which is at least as big as a cache line...
+ nBlockSize = ( 31 + sizeof( T ) ) / sizeof( T );
+ Assert( nBlockSize );
+ }
+ }
+ if ( nBlockSize < num )
+ {
+ int n = ( num + nBlockSize -1 ) / nBlockSize;
+ Assert( n * nBlockSize >= num );
+ Assert( ( n - 1 ) * nBlockSize < num );
+ nBlockSize *= n;
+ }
+ m_nAllocationCount += nBlockSize;
+
+ MEM_ALLOC_CREDIT_CLASS();
+ BlockHeader_t * RESTRICT pBlockHeader = ( BlockHeader_t* )malloc( sizeof( BlockHeader_t ) + nBlockSize * sizeof( T ) );
+ if ( !pBlockHeader )
+ {
+ Error( "CUtlFixedMemory overflow!\n" );
+ }
+ pBlockHeader->m_pNext = NULL;
+ pBlockHeader->m_nBlockSize = nBlockSize;
+
+ if ( !m_pBlocks )
+ {
+ m_pBlocks = pBlockHeader;
+ }
+ else
+ {
+#if 1 // IsIdxAfter assumes that newly allocated blocks are at the end
+ BlockHeader_t * RESTRICT pbh = m_pBlocks;
+ while ( pbh->m_pNext )
+ {
+ pbh = pbh->m_pNext;
+ }
+ pbh->m_pNext = pBlockHeader;
+#else
+ pBlockHeader = m_pBlocks;
+ pBlockHeader->m_pNext = m_pBlocks;
+#endif
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Makes sure we've got at least this much memory
+//-----------------------------------------------------------------------------
+template< class T >
+inline void CUtlFixedMemory<T>::EnsureCapacity( int num )
+{
+ Grow( num - NumAllocated() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Memory deallocation
+//-----------------------------------------------------------------------------
+template< class T >
+void CUtlFixedMemory<T>::Purge()
+{
+ if ( !m_pBlocks )
+ return;
+
+ for ( BlockHeader_t *pbh = m_pBlocks; pbh; )
+ {
+ BlockHeader_t *pFree = pbh;
+ pbh = pbh->m_pNext;
+ free( pFree );
+ }
+ m_pBlocks = NULL;
+ m_nAllocationCount = 0;
+}
+
+#include "tier0/memdbgoff.h"
+
+#endif // UTLFIXEDMEMORY_H
diff --git a/public/tier1/utlflags.h b/public/tier1/utlflags.h
new file mode 100644
index 0000000..e225b43
--- /dev/null
+++ b/public/tier1/utlflags.h
@@ -0,0 +1,124 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Simple class to make it easier to deal with flags
+//
+//=============================================================================
+
+#ifndef UTLFLAGS_H
+#define UTLFLAGS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/dbg.h"
+
+
+//-----------------------------------------------------------------------------
+// Simple class to make it easier to deal with flags
+//-----------------------------------------------------------------------------
+template< class T >
+class CUtlFlags
+{
+public:
+ CUtlFlags( int nInitialFlags = 0 );
+
+ // Flag setting
+ void SetFlag( int nFlagMask );
+ void SetFlag( int nFlagMask, bool bEnable );
+
+ // Flag clearing
+ void ClearFlag( int nFlagMask );
+ void ClearAllFlags();
+ bool IsFlagSet( int nFlagMask ) const;
+
+ // Is any flag set?
+ bool IsAnyFlagSet() const;
+
+private:
+ T m_nFlags;
+};
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+template< class T >
+CUtlFlags<T>::CUtlFlags( int nInitialFlags )
+{
+ // Makes sure we didn't truncate
+ Assert( nInitialFlags == (T)nInitialFlags );
+
+ m_nFlags = (T)nInitialFlags;
+}
+
+
+//-----------------------------------------------------------------------------
+// Set flags
+//-----------------------------------------------------------------------------
+template< class T >
+void CUtlFlags<T>::SetFlag( int nFlagMask )
+{
+ // Makes sure we didn't truncate
+ Assert( nFlagMask == (T)nFlagMask );
+
+ m_nFlags |= (T)nFlagMask;
+}
+
+template< class T >
+void CUtlFlags<T>::SetFlag( int nFlagMask, bool bEnable )
+{
+ // Makes sure we didn't truncate
+ Assert( nFlagMask == (T)nFlagMask );
+
+ if ( bEnable )
+ {
+ m_nFlags |= (T)nFlagMask;
+ }
+ else
+ {
+ m_nFlags &= ~((T)nFlagMask);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Clear flags
+//-----------------------------------------------------------------------------
+template< class T >
+void CUtlFlags<T>::ClearFlag( int nFlagMask )
+{
+ // Makes sure we didn't truncate
+ Assert( nFlagMask == (T)nFlagMask );
+ m_nFlags &= ~((T)nFlagMask);
+}
+
+template< class T >
+void CUtlFlags<T>::ClearAllFlags()
+{
+ m_nFlags = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Is a flag set?
+//-----------------------------------------------------------------------------
+template< class T >
+bool CUtlFlags<T>::IsFlagSet( int nFlagMask ) const
+{
+ // Makes sure we didn't truncate
+ Assert( nFlagMask == (T)nFlagMask );
+ return ( m_nFlags & nFlagMask ) != 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Is any flag set?
+//-----------------------------------------------------------------------------
+template< class T >
+bool CUtlFlags<T>::IsAnyFlagSet() const
+{
+ return m_nFlags != 0;
+}
+
+
+#endif // UTLFLAGS_H
diff --git a/public/tier1/utlhandletable.h b/public/tier1/utlhandletable.h
new file mode 100644
index 0000000..22f5435
--- /dev/null
+++ b/public/tier1/utlhandletable.h
@@ -0,0 +1,586 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef UTLHANDLETABLE_H
+#define UTLHANDLETABLE_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "tier1/utlvector.h"
+#include "tier1/utlqueue.h"
+
+
+//-----------------------------------------------------------------------------
+// Handles are 32 bits. Invalid handles are all 1s
+//-----------------------------------------------------------------------------
+typedef unsigned int UtlHandle_t;
+#define UTLHANDLE_INVALID ((UtlHandle_t)~0)
+
+
+//-----------------------------------------------------------------------------
+// Purpose: This is a table used to allocate handles
+// HandleBits specifies the max # of simultaneously allocated handles.
+// An extra bit is used for the validity state
+// The rest of the 32 bits are used for a serial number
+//-----------------------------------------------------------------------------
+template< class T, int HandleBits >
+class CUtlHandleTable
+{
+public:
+ CUtlHandleTable();
+
+ // Allocate, deallocate handles
+ UtlHandle_t AddHandle();
+ void RemoveHandle( UtlHandle_t h );
+
+ // Set/get handle values
+ void SetHandle( UtlHandle_t h, T *pData );
+ T *GetHandle( UtlHandle_t h ) const;
+ T *GetHandle( UtlHandle_t h, bool checkValidity ) const;
+
+ // Is a handle valid?
+ bool IsHandleValid( UtlHandle_t h ) const;
+
+ // Iterate over handles; they may not be valid
+ unsigned int GetValidHandleCount() const;
+ unsigned int GetHandleCount() const;
+ UtlHandle_t GetHandleFromIndex( int i ) const;
+ int GetIndexFromHandle( UtlHandle_t h ) const;
+
+ void MarkHandleInvalid( UtlHandle_t h );
+ void MarkHandleValid( UtlHandle_t h );
+
+private:
+ struct HandleType_t
+ {
+ HandleType_t( unsigned int i, unsigned int s ) : nIndex( i ), nSerial( s )
+ {
+ Assert( i < ( 1 << HandleBits ) );
+ Assert( s < ( 1 << ( 31 - HandleBits ) ) );
+ }
+ unsigned int nIndex : HandleBits;
+ unsigned int nSerial : 31 - HandleBits;
+ };
+
+ struct EntryType_t
+ {
+ EntryType_t() : m_nSerial( 0 ), nInvalid( 0 ), m_pData( 0 ) {}
+ unsigned int m_nSerial : 31;
+ unsigned int nInvalid : 1;
+ T *m_pData;
+ };
+
+ static unsigned int GetSerialNumber( UtlHandle_t handle );
+ static unsigned int GetListIndex( UtlHandle_t handle );
+ static UtlHandle_t CreateHandle( unsigned int nSerial, unsigned int nIndex );
+ const EntryType_t *GetEntry( UtlHandle_t handle, bool checkValidity ) const;
+
+ unsigned int m_nValidHandles;
+ CUtlVector< EntryType_t > m_list;
+ CUtlQueue< int > m_unused;
+};
+
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+template< class T, int HandleBits >
+CUtlHandleTable<T, HandleBits>::CUtlHandleTable() : m_nValidHandles( 0 )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Allocate, deallocate handles
+//-----------------------------------------------------------------------------
+template< class T, int HandleBits >
+UtlHandle_t CUtlHandleTable<T, HandleBits>::AddHandle()
+{
+ unsigned int nIndex = ( m_unused.Count() > 0 ) ? m_unused.RemoveAtHead() : m_list.AddToTail();
+
+ EntryType_t &entry = m_list[ nIndex ];
+ entry.nInvalid = 0;
+ entry.m_pData = NULL;
+
+ ++m_nValidHandles;
+
+ return CreateHandle( entry.m_nSerial, nIndex );
+}
+
+template< class T, int HandleBits >
+void CUtlHandleTable<T, HandleBits>::RemoveHandle( UtlHandle_t handle )
+{
+ unsigned int nIndex = GetListIndex( handle );
+ Assert( nIndex < ( unsigned int )m_list.Count() );
+ if ( nIndex >= ( unsigned int )m_list.Count() )
+ return;
+
+ EntryType_t &entry = m_list[ nIndex ];
+ ++entry.m_nSerial; // mark old serial# invalid
+ if ( !entry.nInvalid )
+ {
+ entry.nInvalid = 1;
+ --m_nValidHandles;
+ }
+ entry.m_pData = NULL;
+
+
+ // If a handle has been used this many times, then we need to take it out of service, otherwise if the
+ // serial # wraps around we'll possibly revalidate old handles and they'll start to point at the wrong objects. Unlikely, but possible.
+ bool bStopUsing = ( entry.m_nSerial >= ( (1 << ( 31 - HandleBits ) ) - 1 ) );
+ if ( !bStopUsing )
+ {
+ m_unused.Insert( nIndex );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Set/get handle values
+//-----------------------------------------------------------------------------
+template< class T, int HandleBits >
+void CUtlHandleTable<T, HandleBits>::SetHandle( UtlHandle_t handle, T *pData )
+{
+ EntryType_t *entry = const_cast< EntryType_t* >( GetEntry( handle, false ) );
+ Assert( entry );
+ if ( entry == NULL )
+ return;
+
+ // Validate the handle
+ if ( entry->nInvalid )
+ {
+ ++m_nValidHandles;
+ entry->nInvalid = 0;
+ }
+ entry->m_pData = pData;
+}
+
+template< class T, int HandleBits >
+T *CUtlHandleTable<T, HandleBits>::GetHandle( UtlHandle_t handle ) const
+{
+ const EntryType_t *entry = GetEntry( handle, true );
+ return entry ? entry->m_pData : NULL;
+}
+
+template< class T, int HandleBits >
+T *CUtlHandleTable<T, HandleBits>::GetHandle( UtlHandle_t handle, bool checkValidity ) const
+{
+ const EntryType_t *entry = GetEntry( handle, checkValidity );
+ return entry ? entry->m_pData : NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Is a handle valid?
+//-----------------------------------------------------------------------------
+template< class T, int HandleBits >
+bool CUtlHandleTable<T, HandleBits>::IsHandleValid( UtlHandle_t handle ) const
+{
+ if ( handle == UTLHANDLE_INVALID )
+ return false;
+
+ unsigned int nIndex = GetListIndex( handle );
+ AssertOnce( nIndex < ( unsigned int )m_list.Count() );
+ if ( nIndex >= ( unsigned int )m_list.Count() )
+ return false;
+
+ const EntryType_t &entry = m_list[ nIndex ];
+ if ( entry.m_nSerial != GetSerialNumber( handle ) )
+ return false;
+
+ if ( 1 == entry.nInvalid )
+ return false;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Current max handle
+//-----------------------------------------------------------------------------
+template< class T, int HandleBits >
+unsigned int CUtlHandleTable<T, HandleBits>::GetValidHandleCount() const
+{
+ return m_nValidHandles;
+}
+
+template< class T, int HandleBits >
+unsigned int CUtlHandleTable<T, HandleBits>::GetHandleCount() const
+{
+ return m_list.Count();
+}
+
+template< class T, int HandleBits >
+UtlHandle_t CUtlHandleTable<T, HandleBits>::GetHandleFromIndex( int i ) const
+{
+ if ( m_list[i].m_pData )
+ return CreateHandle( m_list[i].m_nSerial, i );
+ return UTLHANDLE_INVALID;
+}
+
+template< class T, int HandleBits >
+int CUtlHandleTable<T, HandleBits>::GetIndexFromHandle( UtlHandle_t h ) const
+{
+ if ( h == UTLHANDLE_INVALID )
+ return -1;
+
+ return GetListIndex( h );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Cracking handles into indices + serial numbers
+//-----------------------------------------------------------------------------
+template< class T, int HandleBits >
+unsigned int CUtlHandleTable<T, HandleBits>::GetSerialNumber( UtlHandle_t handle )
+{
+ return ( ( HandleType_t* )&handle )->nSerial;
+}
+
+template< class T, int HandleBits >
+unsigned int CUtlHandleTable<T, HandleBits>::GetListIndex( UtlHandle_t handle )
+{
+ return ( ( HandleType_t* )&handle )->nIndex;
+}
+
+template< class T, int HandleBits >
+UtlHandle_t CUtlHandleTable<T, HandleBits>::CreateHandle( unsigned int nSerial, unsigned int nIndex )
+{
+ HandleType_t h( nIndex, nSerial );
+ return *( UtlHandle_t* )&h;
+}
+
+
+//-----------------------------------------------------------------------------
+// Looks up a entry by handle
+//-----------------------------------------------------------------------------
+template< class T, int HandleBits >
+const typename CUtlHandleTable<T, HandleBits>::EntryType_t *CUtlHandleTable<T, HandleBits>::GetEntry( UtlHandle_t handle, bool checkValidity ) const
+{
+ if ( handle == UTLHANDLE_INVALID )
+ return NULL;
+
+ unsigned int nIndex = GetListIndex( handle );
+ Assert( nIndex < ( unsigned int )m_list.Count() );
+ if ( nIndex >= ( unsigned int )m_list.Count() )
+ return NULL;
+
+ const EntryType_t &entry = m_list[ nIndex ];
+ if ( entry.m_nSerial != GetSerialNumber( handle ) )
+ return NULL;
+
+ if ( checkValidity &&
+ ( 1 == entry.nInvalid ) )
+ return NULL;
+
+ return &entry;
+}
+
+template< class T, int HandleBits >
+void CUtlHandleTable<T, HandleBits>::MarkHandleInvalid( UtlHandle_t handle )
+{
+ if ( handle == UTLHANDLE_INVALID )
+ return;
+
+ unsigned int nIndex = GetListIndex( handle );
+ Assert( nIndex < ( unsigned int )m_list.Count() );
+ if ( nIndex >= ( unsigned int )m_list.Count() )
+ return;
+
+ EntryType_t &entry = m_list[ nIndex ];
+ if ( entry.m_nSerial != GetSerialNumber( handle ) )
+ return;
+
+ if ( !entry.nInvalid )
+ {
+ --m_nValidHandles;
+ entry.nInvalid = 1;
+ }
+}
+
+template< class T, int HandleBits >
+void CUtlHandleTable<T, HandleBits>::MarkHandleValid( UtlHandle_t handle )
+{
+ if ( handle == UTLHANDLE_INVALID )
+ return;
+
+ unsigned int nIndex = GetListIndex( handle );
+ Assert( nIndex < ( unsigned int )m_list.Count() );
+ if ( nIndex >= ( unsigned int )m_list.Count() )
+ return;
+
+ EntryType_t &entry = m_list[ nIndex ];
+ if ( entry.m_nSerial != GetSerialNumber( handle ) )
+ return;
+
+ if ( entry.nInvalid )
+ {
+ ++m_nValidHandles;
+ entry.nInvalid = 0;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Handle wrapper. Assumes 2 things
+// 1) That class T has a non-static method called GetHandle which returns a UtlHandle_t
+// 2) That class T has a static method called GetPtrFromHandle which returns a T* given a UtlHandle_t
+// 3) That class T has a static method called IsHandleValid which accepts a UtlHandle_t
+//-----------------------------------------------------------------------------
+template< class T >
+class CUtlHandle
+{
+public:
+ // Constructors
+ CUtlHandle();
+ explicit CUtlHandle( T *pObject );
+ CUtlHandle( UtlHandle_t h );
+ CUtlHandle( const CUtlHandle<T> &h );
+
+ // Assignment
+ void Set( T *pObject );
+ void Set( UtlHandle_t h );
+ const CUtlHandle<T> &operator=( UtlHandle_t h );
+ const CUtlHandle<T> &operator=( T *pObject );
+
+ // Retrieval
+ T *Get();
+ const T* Get() const;
+
+ // Is the handle valid?
+ bool IsValid() const;
+
+ // Casting
+ operator T*();
+ operator UtlHandle_t();
+ operator bool();
+ T* operator->();
+ const T* operator->() const;
+
+ // Equality
+ bool operator==( CUtlHandle<T> h ) const;
+ bool operator==( T *pObject ) const;
+ bool operator==( UtlHandle_t h ) const;
+ bool operator!=( CUtlHandle<T> h ) const;
+ bool operator!=( T *pObject ) const;
+ bool operator!=( UtlHandle_t h ) const;
+
+private:
+ UtlHandle_t m_handle;
+};
+
+
+//-----------------------------------------------------------------------------
+// Constructors
+//-----------------------------------------------------------------------------
+template< class T >
+CUtlHandle<T>::CUtlHandle() : m_handle( UTLHANDLE_INVALID )
+{
+}
+
+template< class T >
+CUtlHandle<T>::CUtlHandle( T *pObject )
+{
+ Set( pObject );
+}
+
+template< class T >
+CUtlHandle<T>::CUtlHandle( UtlHandle_t h )
+{
+ m_handle = h;
+}
+
+template< class T >
+CUtlHandle<T>::CUtlHandle( const CUtlHandle<T> &h )
+{
+ m_handle = h.m_handle;
+}
+
+
+//-----------------------------------------------------------------------------
+// Assignment
+//-----------------------------------------------------------------------------
+template< class T >
+void CUtlHandle<T>::Set( T *pObject )
+{
+ // Assumes T has a member function GetHandle
+ m_handle = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID;
+}
+
+template< class T >
+void CUtlHandle<T>::Set( UtlHandle_t h )
+{
+ m_handle = h;
+}
+
+template< class T >
+const CUtlHandle<T> &CUtlHandle<T>::operator=( UtlHandle_t h )
+{
+ Set( h );
+ return *this;
+}
+
+template< class T >
+const CUtlHandle<T> &CUtlHandle<T>::operator=( T *pObject )
+{
+ Set( pObject );
+ return *this;
+}
+
+
+//-----------------------------------------------------------------------------
+// Is the handle valid?
+//-----------------------------------------------------------------------------
+template< class T >
+bool CUtlHandle<T>::IsValid() const
+{
+ // Assumes T has a static member function IsHandleValid
+ return T::IsHandleValid( m_handle );
+}
+
+
+//-----------------------------------------------------------------------------
+// Retrieval
+//-----------------------------------------------------------------------------
+template< class T >
+T *CUtlHandle<T>::Get()
+{
+ // Assumes T has a static member function GetPtrFromHandle
+ return T::GetPtrFromHandle( m_handle );
+}
+
+template< class T >
+const T* CUtlHandle<T>::Get() const
+{
+ // Assumes T has a static member function GetPtrFromHandle
+ return T::GetPtrFromHandle( m_handle );
+}
+
+
+//-----------------------------------------------------------------------------
+// Casting
+//-----------------------------------------------------------------------------
+template< class T >
+CUtlHandle<T>::operator T*()
+{
+ return Get();
+}
+
+template< class T >
+CUtlHandle<T>::operator UtlHandle_t()
+{
+ return m_handle;
+}
+
+template< class T >
+T* CUtlHandle<T>::operator->()
+{
+ return Get();
+}
+
+template< class T >
+const T* CUtlHandle<T>::operator->() const
+{
+ return Get();
+}
+
+template< class T >
+CUtlHandle<T>::operator bool()
+{
+ return m_handle != UTLHANDLE_INVALID;
+}
+
+
+//-----------------------------------------------------------------------------
+// Equality
+//-----------------------------------------------------------------------------
+template< class T >
+bool CUtlHandle<T>::operator==( CUtlHandle<T> h ) const
+{
+ return m_handle == h.m_handle;
+}
+
+template< class T >
+bool CUtlHandle<T>::operator==( T *pObject ) const
+{
+ UtlHandle_t h = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID;
+ return m_handle == h;
+}
+
+template< class T >
+bool CUtlHandle<T>::operator==( UtlHandle_t h ) const
+{
+ return m_handle == h;
+}
+
+template< class T >
+bool CUtlHandle<T>::operator!=( CUtlHandle<T> h ) const
+{
+ return m_handle != h.m_handle;
+}
+
+template< class T >
+bool CUtlHandle<T>::operator!=( T *pObject ) const
+{
+ UtlHandle_t h = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID;
+ return m_handle != h;
+}
+
+template< class T >
+bool CUtlHandle<T>::operator!=( UtlHandle_t h ) const
+{
+ return m_handle != h;
+}
+
+
+//-----------------------------------------------------------------------------
+// Add this macro to a class definition to hook in handles for it!
+//-----------------------------------------------------------------------------
+#define DECLARE_HANDLES( _className, _handleBitCount ) \
+ public: \
+ UtlHandle_t GetHandle() \
+ { \
+ return m_Handle; \
+ } \
+ static _className* GetPtrFromHandle( UtlHandle_t h ) \
+ { \
+ return m_HandleTable.GetHandle( h ); \
+ } \
+ static bool IsHandleValid( UtlHandle_t h ) \
+ { \
+ return m_HandleTable.IsHandleValid( h ); \
+ } \
+ private: \
+ UtlHandle_t m_Handle; \
+ static CUtlHandleTable< _className, _handleBitCount > m_HandleTable
+
+
+//-----------------------------------------------------------------------------
+// Add this macro to a .cpp file to hook in handles for it!
+//-----------------------------------------------------------------------------
+#define IMPLEMENT_HANDLES( _className, _handleBitCount ) \
+ CUtlHandleTable< _className, _handleBitCount > _className::m_HandleTable;
+
+
+//-----------------------------------------------------------------------------
+// Add these macro to the class constructor + destructor
+//-----------------------------------------------------------------------------
+#define CONSTRUCT_HANDLE( ) \
+ m_Handle = m_HandleTable.AddHandle(); \
+ m_HandleTable.SetHandle( m_Handle, this )
+
+#define DESTRUCT_HANDLE() \
+ m_HandleTable.RemoveHandle( m_Handle ); \
+ m_Handle = UTLHANDLE_INVALID
+
+
+
+#endif // UTLHANDLETABLE_H
+
diff --git a/public/tier1/utlhash.h b/public/tier1/utlhash.h
new file mode 100644
index 0000000..7207b59
--- /dev/null
+++ b/public/tier1/utlhash.h
@@ -0,0 +1,936 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+// Serialization/unserialization buffer
+//=============================================================================//
+
+#ifndef UTLHASH_H
+#define UTLHASH_H
+#pragma once
+
+#include <assert.h>
+#include <limits.h>
+#include "utlmemory.h"
+#include "utlvector.h"
+#include "utllinkedlist.h"
+#include "utllinkedlist.h"
+#include "commonmacros.h"
+#include "generichash.h"
+
+typedef unsigned int UtlHashHandle_t;
+
+template<class Data, typename C = bool (*)( Data const&, Data const& ), typename K = unsigned int (*)( Data const& ) >
+class CUtlHash
+{
+public:
+ // compare and key functions - implemented by the
+ typedef C CompareFunc_t;
+ typedef K KeyFunc_t;
+
+ // constructor/deconstructor
+ CUtlHash( int bucketCount = 0, int growCount = 0, int initCount = 0,
+ CompareFunc_t compareFunc = 0, KeyFunc_t keyFunc = 0 );
+ ~CUtlHash();
+
+ // invalid handle
+ static UtlHashHandle_t InvalidHandle( void ) { return ( UtlHashHandle_t )~0; }
+ bool IsValidHandle( UtlHashHandle_t handle ) const;
+
+ // size
+ int Count( void ) const;
+
+ // memory
+ void Purge( void );
+
+ // insertion methods
+ UtlHashHandle_t Insert( Data const &src );
+ UtlHashHandle_t Insert( Data const &src, bool *pDidInsert );
+ UtlHashHandle_t AllocEntryFromKey( Data const &src );
+
+ // removal methods
+ void Remove( UtlHashHandle_t handle );
+ void RemoveAll();
+
+ // retrieval methods
+ UtlHashHandle_t Find( Data const &src ) const;
+
+ Data &Element( UtlHashHandle_t handle );
+ Data const &Element( UtlHashHandle_t handle ) const;
+ Data &operator[]( UtlHashHandle_t handle );
+ Data const &operator[]( UtlHashHandle_t handle ) const;
+
+ UtlHashHandle_t GetFirstHandle() const;
+ UtlHashHandle_t GetNextHandle( UtlHashHandle_t h ) const;
+
+ // debugging!!
+ void Log( const char *filename );
+
+protected:
+
+ int GetBucketIndex( UtlHashHandle_t handle ) const;
+ int GetKeyDataIndex( UtlHashHandle_t handle ) const;
+ UtlHashHandle_t BuildHandle( int ndxBucket, int ndxKeyData ) const;
+
+ bool DoFind( Data const &src, unsigned int *pBucket, int *pIndex ) const;
+
+protected:
+
+ // handle upper 16 bits = bucket index (bucket heads)
+ // handle lower 16 bits = key index (bucket list)
+ typedef CUtlVector<Data> HashBucketList_t;
+ CUtlVector<HashBucketList_t> m_Buckets;
+
+ CompareFunc_t m_CompareFunc; // function used to handle unique compares on data
+ KeyFunc_t m_KeyFunc; // function used to generate the key value
+
+ bool m_bPowerOfTwo; // if the bucket value is a power of two,
+ unsigned int m_ModMask; // use the mod mask to "mod"
+};
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+CUtlHash<Data, C, K>::CUtlHash( int bucketCount, int growCount, int initCount,
+ CompareFunc_t compareFunc, KeyFunc_t keyFunc ) :
+ m_CompareFunc( compareFunc ),
+ m_KeyFunc( keyFunc )
+{
+ m_Buckets.SetSize( bucketCount );
+ for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
+ {
+ m_Buckets[ndxBucket].SetSize( initCount );
+ m_Buckets[ndxBucket].SetGrowSize( growCount );
+ }
+
+ // check to see if the bucket count is a power of 2 and set up
+ // optimizations appropriately
+ m_bPowerOfTwo = IsPowerOfTwo( bucketCount );
+ m_ModMask = m_bPowerOfTwo ? (bucketCount-1) : 0;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+CUtlHash<Data, C, K>::~CUtlHash()
+{
+ Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline bool CUtlHash<Data, C, K>::IsValidHandle( UtlHashHandle_t handle ) const
+{
+ int ndxBucket = GetBucketIndex( handle );
+ int ndxKeyData = GetKeyDataIndex( handle );
+
+ // ndxBucket and ndxKeyData can't possibly be less than zero -- take a
+ // look at the definition of the Get..Index functions for why. However,
+ // if you override those functions, you will need to override this one
+ // as well.
+ if( /*( ndxBucket >= 0 ) && */ ( ndxBucket < m_Buckets.Count() ) )
+ {
+ if( /*( ndxKeyData >= 0 ) && */ ( ndxKeyData < m_Buckets[ndxBucket].Count() ) )
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline int CUtlHash<Data, C, K>::Count( void ) const
+{
+ int count = 0;
+
+ int bucketCount = m_Buckets.Count();
+ for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
+ {
+ count += m_Buckets[ndxBucket].Count();
+ }
+
+ return count;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline int CUtlHash<Data, C, K>::GetBucketIndex( UtlHashHandle_t handle ) const
+{
+ return ( ( ( handle >> 16 ) & 0x0000ffff ) );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline int CUtlHash<Data, C, K>::GetKeyDataIndex( UtlHashHandle_t handle ) const
+{
+ return ( handle & 0x0000ffff );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline UtlHashHandle_t CUtlHash<Data, C, K>::BuildHandle( int ndxBucket, int ndxKeyData ) const
+{
+ assert( ( ndxBucket >= 0 ) && ( ndxBucket < 65536 ) );
+ assert( ( ndxKeyData >= 0 ) && ( ndxKeyData < 65536 ) );
+
+ UtlHashHandle_t handle = ndxKeyData;
+ handle |= ( ndxBucket << 16 );
+
+ return handle;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline void CUtlHash<Data, C, K>::Purge( void )
+{
+ int bucketCount = m_Buckets.Count();
+ for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
+ {
+ m_Buckets[ndxBucket].Purge();
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline bool CUtlHash<Data, C, K>::DoFind( Data const &src, unsigned int *pBucket, int *pIndex ) const
+{
+ // generate the data "key"
+ unsigned int key = m_KeyFunc( src );
+
+ // hash the "key" - get the correct hash table "bucket"
+ unsigned int ndxBucket;
+ if( m_bPowerOfTwo )
+ {
+ *pBucket = ndxBucket = ( key & m_ModMask );
+ }
+ else
+ {
+ int bucketCount = m_Buckets.Count();
+ *pBucket = ndxBucket = key % bucketCount;
+ }
+
+ int ndxKeyData;
+ const CUtlVector<Data> &bucket = m_Buckets[ndxBucket];
+ int keyDataCount = bucket.Count();
+ for( ndxKeyData = 0; ndxKeyData < keyDataCount; ndxKeyData++ )
+ {
+ if( m_CompareFunc( bucket.Element( ndxKeyData ), src ) )
+ break;
+ }
+
+ if( ndxKeyData == keyDataCount )
+ return false;
+
+ *pIndex = ndxKeyData;
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline UtlHashHandle_t CUtlHash<Data, C, K>::Find( Data const &src ) const
+{
+ unsigned int ndxBucket;
+ int ndxKeyData;
+
+ if ( DoFind( src, &ndxBucket, &ndxKeyData ) )
+ {
+ return ( BuildHandle( ndxBucket, ndxKeyData ) );
+ }
+ return ( InvalidHandle() );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline UtlHashHandle_t CUtlHash<Data, C, K>::Insert( Data const &src )
+{
+ unsigned int ndxBucket;
+ int ndxKeyData;
+
+ if ( DoFind( src, &ndxBucket, &ndxKeyData ) )
+ {
+ return ( BuildHandle( ndxBucket, ndxKeyData ) );
+ }
+
+ ndxKeyData = m_Buckets[ndxBucket].AddToTail( src );
+
+ return ( BuildHandle( ndxBucket, ndxKeyData ) );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline UtlHashHandle_t CUtlHash<Data, C, K>::Insert( Data const &src, bool *pDidInsert )
+{
+ unsigned int ndxBucket;
+ int ndxKeyData;
+
+ if ( DoFind( src, &ndxBucket, &ndxKeyData ) )
+ {
+ *pDidInsert = false;
+ return ( BuildHandle( ndxBucket, ndxKeyData ) );
+ }
+
+ *pDidInsert = true;
+ ndxKeyData = m_Buckets[ndxBucket].AddToTail( src );
+
+ return ( BuildHandle( ndxBucket, ndxKeyData ) );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline UtlHashHandle_t CUtlHash<Data, C, K>::AllocEntryFromKey( Data const &src )
+{
+ unsigned int ndxBucket;
+ int ndxKeyData;
+
+ if ( DoFind( src, &ndxBucket, &ndxKeyData ) )
+ {
+ return ( BuildHandle( ndxBucket, ndxKeyData ) );
+ }
+
+ ndxKeyData = m_Buckets[ndxBucket].AddToTail();
+
+ return ( BuildHandle( ndxBucket, ndxKeyData ) );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline void CUtlHash<Data, C, K>::Remove( UtlHashHandle_t handle )
+{
+ assert( IsValidHandle( handle ) );
+
+ // check to see if the bucket exists
+ int ndxBucket = GetBucketIndex( handle );
+ int ndxKeyData = GetKeyDataIndex( handle );
+
+ if( m_Buckets[ndxBucket].IsValidIndex( ndxKeyData ) )
+ {
+ m_Buckets[ndxBucket].FastRemove( ndxKeyData );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline void CUtlHash<Data, C, K>::RemoveAll()
+{
+ int bucketCount = m_Buckets.Count();
+ for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
+ {
+ m_Buckets[ndxBucket].RemoveAll();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline Data &CUtlHash<Data, C, K>::Element( UtlHashHandle_t handle )
+{
+ int ndxBucket = GetBucketIndex( handle );
+ int ndxKeyData = GetKeyDataIndex( handle );
+
+ return ( m_Buckets[ndxBucket].Element( ndxKeyData ) );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline Data const &CUtlHash<Data, C, K>::Element( UtlHashHandle_t handle ) const
+{
+ int ndxBucket = GetBucketIndex( handle );
+ int ndxKeyData = GetKeyDataIndex( handle );
+
+ return ( m_Buckets[ndxBucket].Element( ndxKeyData ) );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline Data &CUtlHash<Data, C, K>::operator[]( UtlHashHandle_t handle )
+{
+ int ndxBucket = GetBucketIndex( handle );
+ int ndxKeyData = GetKeyDataIndex( handle );
+
+ return ( m_Buckets[ndxBucket].Element( ndxKeyData ) );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline Data const &CUtlHash<Data, C, K>::operator[]( UtlHashHandle_t handle ) const
+{
+ int ndxBucket = GetBucketIndex( handle );
+ int ndxKeyData = GetKeyDataIndex( handle );
+
+ return ( m_Buckets[ndxBucket].Element( ndxKeyData ) );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline UtlHashHandle_t CUtlHash<Data, C, K>::GetFirstHandle() const
+{
+ return GetNextHandle( ( UtlHashHandle_t )-1 );
+}
+
+template<class Data, typename C, typename K>
+inline UtlHashHandle_t CUtlHash<Data, C, K>::GetNextHandle( UtlHashHandle_t handle ) const
+{
+ ++handle; // start at the first possible handle after the one given
+
+ int bi = GetBucketIndex( handle );
+ int ki = GetKeyDataIndex( handle );
+
+ int nBuckets = m_Buckets.Count();
+ for ( ; bi < nBuckets; ++bi )
+ {
+ if ( ki < m_Buckets[ bi ].Count() )
+ return BuildHandle( bi, ki );
+
+ ki = 0;
+ }
+
+ return InvalidHandle();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, typename C, typename K>
+inline void CUtlHash<Data, C, K>::Log( const char *filename )
+{
+ FILE *pDebugFp;
+ pDebugFp = fopen( filename, "w" );
+ if( !pDebugFp )
+ return;
+
+ int maxBucketSize = 0;
+ int numBucketsEmpty = 0;
+
+ int bucketCount = m_Buckets.Count();
+ fprintf( pDebugFp, "\n%d Buckets\n", bucketCount );
+
+ for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
+ {
+ int count = m_Buckets[ndxBucket].Count();
+
+ if( count > maxBucketSize ) { maxBucketSize = count; }
+ if( count == 0 )
+ numBucketsEmpty++;
+
+ fprintf( pDebugFp, "Bucket %d: %d\n", ndxBucket, count );
+ }
+
+ fprintf( pDebugFp, "\nBucketHeads Used: %d\n", bucketCount - numBucketsEmpty );
+ fprintf( pDebugFp, "Max Bucket Size: %d\n", maxBucketSize );
+
+ fclose( pDebugFp );
+}
+
+//=============================================================================
+//
+// Fast Hash
+//
+// Number of buckets must be a power of 2.
+// Key must be 32-bits (unsigned int).
+//
+typedef int UtlHashFastHandle_t;
+
+#define UTLHASH_POOL_SCALAR 2
+
+class CUtlHashFastNoHash
+{
+public:
+ static int Hash( int key, int bucketMask )
+ {
+ return ( key & bucketMask );
+ }
+};
+
+class CUtlHashFastGenericHash
+{
+public:
+ static int Hash( int key, int bucketMask )
+ {
+ return ( HashIntConventional( key ) & bucketMask );
+ }
+};
+
+template<class Data, class HashFuncs = CUtlHashFastNoHash >
+class CUtlHashFast
+{
+public:
+
+ // Constructor/Deconstructor.
+ CUtlHashFast();
+ ~CUtlHashFast();
+
+ // Memory.
+ void Purge( void );
+
+ // Invalid handle.
+ static UtlHashFastHandle_t InvalidHandle( void ) { return ( UtlHashFastHandle_t )~0; }
+
+ // Initialize.
+ bool Init( int nBucketCount );
+
+ // Size.
+ int Count( void );
+
+ // Insertion.
+ UtlHashFastHandle_t Insert( unsigned int uiKey, const Data &data );
+ UtlHashFastHandle_t FastInsert( unsigned int uiKey, const Data &data );
+
+ // Removal.
+ void Remove( UtlHashFastHandle_t hHash );
+ void RemoveAll( void );
+
+ // Retrieval.
+ UtlHashFastHandle_t Find( unsigned int uiKey );
+
+ Data &Element( UtlHashFastHandle_t hHash );
+ Data const &Element( UtlHashFastHandle_t hHash ) const;
+ Data &operator[]( UtlHashFastHandle_t hHash );
+ Data const &operator[]( UtlHashFastHandle_t hHash ) const;
+
+//protected:
+
+ // Templatized for memory tracking purposes
+ template <typename HashData>
+ struct HashFastData_t_
+ {
+ unsigned int m_uiKey;
+ HashData m_Data;
+ };
+
+ typedef HashFastData_t_<Data> HashFastData_t;
+
+ unsigned int m_uiBucketMask;
+ CUtlVector<UtlHashFastHandle_t> m_aBuckets;
+ CUtlFixedLinkedList<HashFastData_t> m_aDataPool;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+template<class Data, class HashFuncs> CUtlHashFast<Data,HashFuncs>::CUtlHashFast()
+{
+ Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Deconstructor
+//-----------------------------------------------------------------------------
+template<class Data, class HashFuncs> CUtlHashFast<Data,HashFuncs>::~CUtlHashFast()
+{
+ Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destroy dynamically allocated hash data.
+//-----------------------------------------------------------------------------
+template<class Data, class HashFuncs> inline void CUtlHashFast<Data,HashFuncs>::Purge( void )
+{
+ m_aBuckets.Purge();
+ m_aDataPool.Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Initialize the hash - set bucket count and hash grow amount.
+//-----------------------------------------------------------------------------
+template<class Data, class HashFuncs> bool CUtlHashFast<Data,HashFuncs>::Init( int nBucketCount )
+{
+ // Verify the bucket count is power of 2.
+ if ( !IsPowerOfTwo( nBucketCount ) )
+ return false;
+
+ // Set the bucket size.
+ m_aBuckets.SetSize( nBucketCount );
+ for ( int iBucket = 0; iBucket < nBucketCount; ++iBucket )
+ {
+ m_aBuckets[iBucket] = m_aDataPool.InvalidIndex();
+ }
+
+ // Set the mod mask.
+ m_uiBucketMask = nBucketCount - 1;
+
+ // Calculate the grow size.
+ int nGrowSize = UTLHASH_POOL_SCALAR * nBucketCount;
+ m_aDataPool.SetGrowSize( nGrowSize );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return the number of elements in the hash.
+//-----------------------------------------------------------------------------
+template<class Data, class HashFuncs> inline int CUtlHashFast<Data,HashFuncs>::Count( void )
+{
+ return m_aDataPool.Count();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Insert data into the hash table given its key (unsigned int), with
+// a check to see if the element already exists within the tree.
+//-----------------------------------------------------------------------------
+template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data,HashFuncs>::Insert( unsigned int uiKey, const Data &data )
+{
+ // Check to see if that key already exists in the buckets (should be unique).
+ UtlHashFastHandle_t hHash = Find( uiKey );
+ if( hHash != InvalidHandle() )
+ return hHash;
+
+ return FastInsert( uiKey, data );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Insert data into the hash table given its key (unsigned int),
+// without a check to see if the element already exists within the tree.
+//-----------------------------------------------------------------------------
+template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data,HashFuncs>::FastInsert( unsigned int uiKey, const Data &data )
+{
+ // Get a new element from the pool.
+ int iHashData = m_aDataPool.Alloc( true );
+ HashFastData_t *pHashData = &m_aDataPool[iHashData];
+ if ( !pHashData )
+ return InvalidHandle();
+
+ // Add data to new element.
+ pHashData->m_uiKey = uiKey;
+ pHashData->m_Data = data;
+
+ // Link element.
+ int iBucket = HashFuncs::Hash( uiKey, m_uiBucketMask );
+ m_aDataPool.LinkBefore( m_aBuckets[iBucket], iHashData );
+ m_aBuckets[iBucket] = iHashData;
+
+ return iHashData;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove a given element from the hash.
+//-----------------------------------------------------------------------------
+template<class Data, class HashFuncs> inline void CUtlHashFast<Data,HashFuncs>::Remove( UtlHashFastHandle_t hHash )
+{
+ int iBucket = HashFuncs::Hash( m_aDataPool[hHash].m_uiKey, m_uiBucketMask );
+ if ( m_aBuckets[iBucket] == hHash )
+ {
+ // It is a bucket head.
+ m_aBuckets[iBucket] = m_aDataPool.Next( hHash );
+ }
+ else
+ {
+ // Not a bucket head.
+ m_aDataPool.Unlink( hHash );
+ }
+
+ // Remove the element.
+ m_aDataPool.Remove( hHash );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove all elements from the hash
+//-----------------------------------------------------------------------------
+template<class Data, class HashFuncs> inline void CUtlHashFast<Data,HashFuncs>::RemoveAll( void )
+{
+ m_aBuckets.RemoveAll();
+ m_aDataPool.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data,HashFuncs>::Find( unsigned int uiKey )
+{
+ // hash the "key" - get the correct hash table "bucket"
+ int iBucket = HashFuncs::Hash( uiKey, m_uiBucketMask );
+
+ for ( int iElement = m_aBuckets[iBucket]; iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next( iElement ) )
+ {
+ if ( m_aDataPool[iElement].m_uiKey == uiKey )
+ return iElement;
+ }
+
+ return InvalidHandle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return data given a hash handle.
+//-----------------------------------------------------------------------------
+template<class Data, class HashFuncs> inline Data &CUtlHashFast<Data,HashFuncs>::Element( UtlHashFastHandle_t hHash )
+{
+ return ( m_aDataPool[hHash].m_Data );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return data given a hash handle.
+//-----------------------------------------------------------------------------
+template<class Data, class HashFuncs> inline Data const &CUtlHashFast<Data,HashFuncs>::Element( UtlHashFastHandle_t hHash ) const
+{
+ return ( m_aDataPool[hHash].m_Data );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return data given a hash handle.
+//-----------------------------------------------------------------------------
+template<class Data, class HashFuncs> inline Data &CUtlHashFast<Data,HashFuncs>::operator[]( UtlHashFastHandle_t hHash )
+{
+ return ( m_aDataPool[hHash].m_Data );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return data given a hash handle.
+//-----------------------------------------------------------------------------
+template<class Data, class HashFuncs> inline Data const &CUtlHashFast<Data,HashFuncs>::operator[]( UtlHashFastHandle_t hHash ) const
+{
+ return ( m_aDataPool[hHash].m_Data );
+}
+
+//=============================================================================
+//
+// Fixed Hash
+//
+// Number of buckets must be a power of 2.
+// Key must be 32-bits (unsigned int).
+//
+typedef int UtlHashFixedHandle_t;
+
+template <int NUM_BUCKETS>
+class CUtlHashFixedGenericHash
+{
+public:
+ static int Hash( int key, int bucketMask )
+ {
+ int hash = HashIntConventional( key );
+ if ( NUM_BUCKETS <= USHRT_MAX )
+ {
+ hash ^= ( hash >> 16 );
+ }
+ if ( NUM_BUCKETS <= UCHAR_MAX )
+ {
+ hash ^= ( hash >> 8 );
+ }
+ return ( hash & bucketMask );
+ }
+};
+
+template<class Data, int NUM_BUCKETS, class CHashFuncs = CUtlHashFastNoHash >
+class CUtlHashFixed
+{
+public:
+
+ // Constructor/Deconstructor.
+ CUtlHashFixed();
+ ~CUtlHashFixed();
+
+ // Memory.
+ void Purge( void );
+
+ // Invalid handle.
+ static UtlHashFixedHandle_t InvalidHandle( void ) { return ( UtlHashFixedHandle_t )~0; }
+
+ // Size.
+ int Count( void );
+
+ // Insertion.
+ UtlHashFixedHandle_t Insert( unsigned int uiKey, const Data &data );
+ UtlHashFixedHandle_t FastInsert( unsigned int uiKey, const Data &data );
+
+ // Removal.
+ void Remove( UtlHashFixedHandle_t hHash );
+ void RemoveAll( void );
+
+ // Retrieval.
+ UtlHashFixedHandle_t Find( unsigned int uiKey );
+
+ Data &Element( UtlHashFixedHandle_t hHash );
+ Data const &Element( UtlHashFixedHandle_t hHash ) const;
+ Data &operator[]( UtlHashFixedHandle_t hHash );
+ Data const &operator[]( UtlHashFixedHandle_t hHash ) const;
+
+ //protected:
+
+ // Templatized for memory tracking purposes
+ template <typename Data_t>
+ struct HashFixedData_t_
+ {
+ unsigned int m_uiKey;
+ Data_t m_Data;
+ };
+
+ typedef HashFixedData_t_<Data> HashFixedData_t;
+
+ enum
+ {
+ BUCKET_MASK = NUM_BUCKETS - 1
+ };
+ CUtlPtrLinkedList<HashFixedData_t> m_aBuckets[NUM_BUCKETS];
+ int m_nElements;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+template<class Data, int NUM_BUCKETS, class HashFuncs> CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::CUtlHashFixed()
+{
+ Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Deconstructor
+//-----------------------------------------------------------------------------
+template<class Data, int NUM_BUCKETS, class HashFuncs> CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::~CUtlHashFixed()
+{
+ Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destroy dynamically allocated hash data.
+//-----------------------------------------------------------------------------
+template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Purge( void )
+{
+ RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return the number of elements in the hash.
+//-----------------------------------------------------------------------------
+template<class Data, int NUM_BUCKETS, class HashFuncs> inline int CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Count( void )
+{
+ return m_nElements;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Insert data into the hash table given its key (unsigned int), with
+// a check to see if the element already exists within the tree.
+//-----------------------------------------------------------------------------
+template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Insert( unsigned int uiKey, const Data &data )
+{
+ // Check to see if that key already exists in the buckets (should be unique).
+ UtlHashFixedHandle_t hHash = Find( uiKey );
+ if( hHash != InvalidHandle() )
+ return hHash;
+
+ return FastInsert( uiKey, data );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Insert data into the hash table given its key (unsigned int),
+// without a check to see if the element already exists within the tree.
+//-----------------------------------------------------------------------------
+template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::FastInsert( unsigned int uiKey, const Data &data )
+{
+ int iBucket = HashFuncs::Hash( uiKey, NUM_BUCKETS - 1 );
+ UtlPtrLinkedListIndex_t iElem = m_aBuckets[iBucket].AddToHead();
+
+ HashFixedData_t *pHashData = &m_aBuckets[iBucket][iElem];
+
+ Assert( (UtlPtrLinkedListIndex_t)pHashData == iElem );
+
+ // Add data to new element.
+ pHashData->m_uiKey = uiKey;
+ pHashData->m_Data = data;
+
+ m_nElements++;
+ return (UtlHashFixedHandle_t)pHashData;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove a given element from the hash.
+//-----------------------------------------------------------------------------
+template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Remove( UtlHashFixedHandle_t hHash )
+{
+ HashFixedData_t *pHashData = (HashFixedData_t *)hHash;
+ Assert( Find(pHashData->m_uiKey) != InvalidHandle() );
+ int iBucket = HashFuncs::Hash( pHashData->m_uiKey, NUM_BUCKETS - 1 );
+ m_aBuckets[iBucket].Remove( (UtlPtrLinkedListIndex_t)pHashData );
+ m_nElements--;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove all elements from the hash
+//-----------------------------------------------------------------------------
+template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::RemoveAll( void )
+{
+ for ( int i = 0; i < NUM_BUCKETS; i++ )
+ {
+ m_aBuckets[i].RemoveAll();
+ }
+ m_nElements = 0;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Find( unsigned int uiKey )
+{
+ int iBucket = HashFuncs::Hash( uiKey, NUM_BUCKETS - 1 );
+ CUtlPtrLinkedList<HashFixedData_t> &bucket = m_aBuckets[iBucket];
+
+ for ( UtlPtrLinkedListIndex_t iElement = bucket.Head(); iElement != bucket.InvalidIndex(); iElement = bucket.Next( iElement ) )
+ {
+ if ( bucket[iElement].m_uiKey == uiKey )
+ return (UtlHashFixedHandle_t)iElement;
+ }
+
+ return InvalidHandle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return data given a hash handle.
+//-----------------------------------------------------------------------------
+template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Element( UtlHashFixedHandle_t hHash )
+{
+ return ((HashFixedData_t *)hHash)->m_Data;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return data given a hash handle.
+//-----------------------------------------------------------------------------
+template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data const &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Element( UtlHashFixedHandle_t hHash ) const
+{
+ return ((HashFixedData_t *)hHash)->m_Data;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return data given a hash handle.
+//-----------------------------------------------------------------------------
+template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::operator[]( UtlHashFixedHandle_t hHash )
+{
+ return ((HashFixedData_t *)hHash)->m_Data;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return data given a hash handle.
+//-----------------------------------------------------------------------------
+template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data const &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::operator[]( UtlHashFixedHandle_t hHash ) const
+{
+ return ((HashFixedData_t *)hHash)->m_Data;
+}
+
+#endif // UTLHASH_H
diff --git a/public/tier1/utlhashdict.h b/public/tier1/utlhashdict.h
new file mode 100644
index 0000000..109bb75
--- /dev/null
+++ b/public/tier1/utlhashdict.h
@@ -0,0 +1,342 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef UTLHASHDICT_H
+#define UTLHASHDICT_H
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+
+#include "tier1/utlhash.h"
+#include "tier1/generichash.h"
+#include "mathlib/mathlib.h"
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+template <typename T, bool bCaseInsensitive = true, bool bDupeStrings = true>
+class CUtlHashDict
+{
+public:
+ // constructor, destructor
+ CUtlHashDict( int bucketCount = 16, int growCount = 0, int initCount = 0 );
+ ~CUtlHashDict( );
+
+ // gets particular elements
+ T& Element( unsigned i );
+ const T& Element( unsigned i ) const;
+ T& operator[]( unsigned i );
+ const T& operator[]( unsigned i ) const;
+
+ // gets element names
+ char const *GetElementName( unsigned i ) const;
+
+ // Number of elements
+ int Count() const;
+
+ // Checks if a node is valid and in the tree
+ bool IsValidIndex( unsigned i ) const;
+
+ // Invalid index
+ static unsigned InvalidHandle();
+
+ // Insert method (inserts in order)
+ unsigned Insert( const char *pName, const T &element );
+ unsigned Insert( const char *pName );
+
+ // Find method
+ unsigned Find( const char *pName ) const;
+
+ // Remove methods
+ void RemoveAt( unsigned i );
+ void Remove( const char *pName );
+ void RemoveAll( );
+
+ // Purge memory
+ void Purge();
+ void PurgeAndDeleteElements(); // Call delete on each element.
+
+ // Iteration methods
+ unsigned First() const;
+ unsigned Next( unsigned i ) const;
+
+protected:
+ struct Entry_t
+ {
+ const char *pszSymbol;
+ T value;
+ };
+
+ template <bool bCaseInsensitive>
+ class CCompare
+ {
+ public:
+ CCompare( int ignored ) {}
+
+ bool operator()( const Entry_t &entry1, const Entry_t &entry2 ) const
+ {
+ return !( ( bCaseInsensitive ) ? stricmp( entry1.pszSymbol, entry2.pszSymbol ) : strcmp( entry1.pszSymbol, entry2.pszSymbol ) );
+ }
+ };
+
+ template <bool bCaseInsensitive>
+ class CHash
+ {
+ public:
+ CHash( int ignored ) {}
+
+ unsigned operator()( const Entry_t &entry ) const
+ {
+ return !( ( bCaseInsensitive ) ? HashStringCaseless( entry.pszSymbol ) : HashString( entry.pszSymbol ) );
+ }
+ };
+
+ typedef CUtlHash<Entry_t, CCompare<bCaseInsensitive>, CHash<bCaseInsensitive> > CHashTable;
+ CHashTable m_Elements;
+ int m_nCount;
+};
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::CUtlHashDict( int bucketCount = 16, int growCount = 0, int initCount = 0 ) :
+ m_Elements( SmallestPowerOfTwoGreaterOrEqual(bucketCount), growCount, initCount )
+{
+ Assert( SmallestPowerOfTwoGreaterOrEqual(bucketCount) <= 0xffff );
+}
+
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::~CUtlHashDict()
+{
+ Purge();
+}
+
+//-----------------------------------------------------------------------------
+// gets particular elements
+//-----------------------------------------------------------------------------
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+inline T& CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Element( unsigned i )
+{
+ return m_Elements[i].value;
+}
+
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+inline const T& CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Element( unsigned i ) const
+{
+ return m_Elements[i].value;
+}
+
+//-----------------------------------------------------------------------------
+// gets element names
+//-----------------------------------------------------------------------------
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+inline char const *CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::GetElementName( unsigned i ) const
+{
+ return m_Elements[i].pszSymbol;
+}
+
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+inline T& CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::operator[]( unsigned i )
+{
+ return m_Elements[i].value;
+}
+
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+inline const T & CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::operator[]( unsigned i ) const
+{
+ return m_Elements[i].value;
+}
+
+//-----------------------------------------------------------------------------
+// Num elements
+//-----------------------------------------------------------------------------
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+inline int CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Count() const
+{
+ Assert( m_nCount == m_Elements.Count() );
+ return m_nCount;
+}
+
+
+//-----------------------------------------------------------------------------
+// Checks if a node is valid and in the tree
+//-----------------------------------------------------------------------------
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+inline bool CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::IsValidIndex( unsigned i ) const
+{
+ return m_Elements.IsValidHandle(i);
+}
+
+
+//-----------------------------------------------------------------------------
+// Invalid index
+//-----------------------------------------------------------------------------
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+inline unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::InvalidHandle()
+{
+ return CHashTable::InvalidHandle();
+}
+
+
+//-----------------------------------------------------------------------------
+// Delete a node from the tree
+//-----------------------------------------------------------------------------
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::RemoveAt(unsigned elem)
+{
+ if ( bDupeStrings )
+ {
+ free( (void *)m_Elements[elem].pszSymbol );
+ }
+ m_Elements.Remove(elem);
+ m_nCount--;
+}
+
+
+//-----------------------------------------------------------------------------
+// remove a node in the tree
+//-----------------------------------------------------------------------------
+template <typename T, bool bCaseInsensitive, bool bDupeStrings> void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Remove( const char *search )
+{
+ unsigned node = Find( search );
+ if (node != InvalidHandle())
+ {
+ RemoveAt(node);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Removes all nodes from the tree
+//-----------------------------------------------------------------------------
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::RemoveAll()
+{
+ if ( bDupeStrings )
+ {
+ typename UtlHashHandle_t index = m_Elements.GetFirstHandle();
+ while ( index != m_Elements.InvalidHandle() )
+ {
+ free( (void *)m_Elements[index].pszSymbol );
+ index = m_Elements.GetNextHandle( index );
+ }
+ }
+
+ m_Elements.RemoveAll();
+ m_nCount = 0;
+}
+
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Purge()
+{
+ if ( bDupeStrings )
+ {
+ typename UtlHashHandle_t index = m_Elements.GetFirstHandle();
+ while ( index != m_Elements.InvalidHandle() )
+ {
+ free( (void *)m_Elements[index].pszSymbol );
+ index = m_Elements.GetNextHandle( index );
+ }
+ }
+
+ m_Elements.Purge();
+ m_nCount = 0;
+}
+
+
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::PurgeAndDeleteElements()
+{
+ // Delete all the elements.
+ unsigned index = m_Elements.GetFirstHandle();
+ while ( index != m_Elements.InvalidHandle() )
+ {
+ if ( bDupeStrings )
+ {
+ free( (void *)m_Elements[index].pszSymbol );
+ }
+ delete m_Elements[index].value;
+ index = m_Elements.GetNextHandle( index );
+ }
+
+ m_Elements.RemoveAll();
+ m_nCount = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// inserts a node into the tree
+//-----------------------------------------------------------------------------
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Insert( const char *pName, const T &element )
+{
+ MEM_ALLOC_CREDIT_CLASS();
+ m_nCount++;
+ Entry_t entry =
+ {
+ (bDupeStrings) ? strdup( pName ) : pName,
+ element
+ };
+ bool bInserted;
+ unsigned result = m_Elements.Insert( entry, &bInserted );
+ if ( bDupeStrings && !bInserted )
+ {
+ free( (void *)entry.pszSymbol );
+ }
+ return result;
+}
+
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Insert( const char *pName )
+{
+ MEM_ALLOC_CREDIT_CLASS();
+ m_nCount++;
+ Entry_t entry =
+ {
+ (bDupeStrings) ? strdup( pName ) : pName
+ };
+ bool bInserted;
+ unsigned result = m_Elements.Insert( entry, &bInserted );
+ if ( bDupeStrings && !bInserted )
+ {
+ free( (void *)entry.pszSymbol );
+ }
+ return result;
+}
+
+
+//-----------------------------------------------------------------------------
+// finds a node in the tree
+//-----------------------------------------------------------------------------
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Find( const char *pName ) const
+{
+ MEM_ALLOC_CREDIT_CLASS();
+ if ( pName )
+ return m_Elements.Find( *((Entry_t *)&pName) );
+ else
+ return InvalidHandle();
+}
+
+
+//-----------------------------------------------------------------------------
+// Iteration methods
+//-----------------------------------------------------------------------------
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::First() const
+{
+ return m_Elements.GetFirstHandle();
+}
+
+template <typename T, bool bCaseInsensitive, bool bDupeStrings>
+unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Next( unsigned i ) const
+{
+ return m_Elements.GetNextHandle(i);
+}
+
+#endif // UTLHASHDICT_H
diff --git a/public/tier1/utlhashtable.h b/public/tier1/utlhashtable.h
new file mode 100644
index 0000000..e9ea182
--- /dev/null
+++ b/public/tier1/utlhashtable.h
@@ -0,0 +1,988 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: a fast growable hashtable with stored hashes, L2-friendly behavior.
+// Useful as a string dictionary or a low-overhead set/map for small POD types.
+//
+// Usage notes:
+// - handles are NOT STABLE across element removal! use RemoveAndAdvance()
+// if you are removing elements while iterating through the hashtable.
+// Use CUtlStableHashtable if you need stable handles (less efficient).
+// - handles are also NOT STABLE across element insertion. The handle
+// resulting from the insertion of an element may not retreive the
+// same (or any!) element after further insertions. Again, use
+// CUtlStableHashtable if you need stable handles
+// - Insert() first searches for an existing match and returns it if found
+// - a value type of "empty_t" can be used to eliminate value storage and
+// switch Element() to return const Key references instead of values
+// - an extra user flag bit is accessible via Get/SetUserFlag()
+// - hash function pointer / functor is exposed via GetHashRef()
+// - comparison function pointer / functor is exposed via GetEqualRef()
+// - if your value type cannot be copy-constructed, use key-only Insert()
+// to default-initialize the value and then manipulate it afterwards.
+// - The reason that UtlHashtable permutes itself and invalidates
+// iterators is to make it faster in the case where you are not
+// tracking iterators. If you use it as a set or a map ("is this
+// value a member?") as opposed to a long-term container, then you
+// probably don't need stable iterators. Hashtable tries to place
+// newly inserted data in the primary hash slot, making an
+// assumption that if you inserted it recently, you're more likely
+// to access it than if you inserted something a long time
+// ago. It's effectively trying to minimize cache misses for hot
+// data if you add and remove a lot.
+// If you don't care too much about cache misses, UtlStableHashtable
+// is what you're looking for
+//
+// Implementation notes:
+// - overall hash table load is kept between .25 and .75
+// - items which would map to the same ideal slot are chained together
+// - chained items are stored sequentially in adjacent free spaces
+// - "root" entries are prioritized over chained entries; if a
+// slot is not occupied by an item in its root position, the table
+// is guaranteed to contain no keys which would hash to that slot.
+// - new items go at the head of the chain (ie, in their root slot)
+// and evict / "bump" any chained entries which occupy that slot
+// - chain-following skips over unused holes and continues examining
+// table entries until a chain entry with FLAG_LAST is encountered
+//
+// CUtlHashtable< uint32 > setOfIntegers;
+// CUtlHashtable< const char* > setOfStringPointers;
+// CUtlHashtable< int, CUtlVector<blah_t> > mapFromIntsToArrays;
+//
+// $NoKeywords: $
+//
+// A closed-form (open addressing) hashtable with linear sequential probing.
+//=============================================================================//
+
+#ifndef UTLHASHTABLE_H
+#define UTLHASHTABLE_H
+#pragma once
+
+#include "utlcommon.h"
+#include "utlmemory.h"
+#include "mathlib/mathlib.h"
+#include "utllinkedlist.h"
+
+//-----------------------------------------------------------------------------
+// Henry Goffin (henryg) was here. Questions? Bugs? Go slap him around a bit.
+//-----------------------------------------------------------------------------
+
+typedef unsigned int UtlHashHandle_t;
+
+#define FOR_EACH_HASHTABLE( table, iter ) \
+ for ( UtlHashHandle_t iter = (table).FirstHandle(); iter != (table).InvalidHandle(); iter = (table).NextHandle( iter ) )
+
+// CUtlHashtableEntry selects between 16 and 32 bit storage backing
+// for flags_and_hash depending on the size of the stored types.
+template < typename KeyT, typename ValueT = empty_t >
+class CUtlHashtableEntry
+{
+public:
+ typedef CUtlKeyValuePair< KeyT, ValueT > KVPair;
+
+ enum { INT16_STORAGE = ( sizeof( KVPair ) <= 2 ) };
+ typedef typename CTypeSelect< INT16_STORAGE, int16, int32 >::type storage_t;
+
+ enum
+ {
+ FLAG_FREE = INT16_STORAGE ? 0x8000 : 0x80000000, // must be high bit for IsValid and IdealIndex to work
+ FLAG_LAST = INT16_STORAGE ? 0x4000 : 0x40000000,
+ MASK_HASH = INT16_STORAGE ? 0x3FFF : 0x3FFFFFFF
+ };
+
+ storage_t flags_and_hash;
+ storage_t data[ ( sizeof(KVPair) + sizeof(storage_t) - 1 ) / sizeof(storage_t) ];
+
+ bool IsValid() const { return flags_and_hash >= 0; }
+ void MarkInvalid() { int32 flag = FLAG_FREE; flags_and_hash = (storage_t)flag; }
+ const KVPair *Raw() const { return reinterpret_cast< const KVPair * >( &data[0] ); }
+ const KVPair *operator->() const { Assert( IsValid() ); return reinterpret_cast< const KVPair * >( &data[0] ); }
+ KVPair *Raw() { return reinterpret_cast< KVPair * >( &data[0] ); }
+ KVPair *operator->() { Assert( IsValid() ); return reinterpret_cast< KVPair * >( &data[0] ); }
+
+ // Returns the ideal index of the data in this slot, or all bits set if invalid
+ uint32 FORCEINLINE IdealIndex( uint32 slotmask ) const { return IdealIndex( flags_and_hash, slotmask ) | ( (int32)flags_and_hash >> 31 ); }
+
+ // Use template tricks to fully define only one function that takes either 16 or 32 bits
+ // and performs different logic without using "if ( INT16_STORAGE )", because GCC and MSVC
+ // sometimes have trouble removing the constant branch, which is dumb... but whatever.
+ // 16-bit hashes are simply too narrow for large hashtables; more mask bits than hash bits!
+ // So we duplicate the hash bits. (Note: h *= MASK_HASH+2 is the same as h += h<<HASH_BITS)
+ typedef typename CTypeSelect< INT16_STORAGE, int16, undefined_t >::type uint32_if16BitStorage;
+ typedef typename CTypeSelect< INT16_STORAGE, undefined_t, int32 >::type uint32_if32BitStorage;
+ static FORCEINLINE uint32 IdealIndex( uint32_if16BitStorage h, uint32 m ) { h &= MASK_HASH; h *= MASK_HASH + 2; return h & m; }
+ static FORCEINLINE uint32 IdealIndex( uint32_if32BitStorage h, uint32 m ) { return h & m; }
+
+ // More efficient than memcpy for the small types that are stored in a hashtable
+ void MoveDataFrom( CUtlHashtableEntry &src )
+ {
+ storage_t * RESTRICT srcData = &src.data[0];
+ for ( int i = 0; i < ARRAYSIZE( data ); ++i ) { data[i] = srcData[i]; }
+ }
+};
+
+template <typename KeyT, typename ValueT = empty_t, typename KeyHashT = DefaultHashFunctor<KeyT>, typename KeyIsEqualT = DefaultEqualFunctor<KeyT>, typename AlternateKeyT = typename ArgumentTypeInfo<KeyT>::Alt_t >
+class CUtlHashtable
+{
+public:
+ typedef UtlHashHandle_t handle_t;
+
+protected:
+ typedef CUtlKeyValuePair<KeyT, ValueT> KVPair;
+ typedef typename ArgumentTypeInfo<KeyT>::Arg_t KeyArg_t;
+ typedef typename ArgumentTypeInfo<ValueT>::Arg_t ValueArg_t;
+ typedef typename ArgumentTypeInfo<AlternateKeyT>::Arg_t KeyAlt_t;
+ typedef CUtlHashtableEntry< KeyT, ValueT > entry_t;
+
+ enum { FLAG_FREE = entry_t::FLAG_FREE };
+ enum { FLAG_LAST = entry_t::FLAG_LAST };
+ enum { MASK_HASH = entry_t::MASK_HASH };
+
+ CUtlMemory< entry_t > m_table;
+ int m_nUsed;
+ int m_nMinSize;
+ bool m_bSizeLocked;
+ KeyIsEqualT m_eq;
+ KeyHashT m_hash;
+
+ // Allocate an empty table and then re-insert all existing entries.
+ void DoRealloc( int size );
+
+ // Move an existing entry to a free slot, leaving a hole behind
+ void BumpEntry( unsigned int idx );
+
+ // Insert an unconstructed KVPair at the primary slot
+ int DoInsertUnconstructed( unsigned int h, bool allowGrow );
+
+ // Implementation for Insert functions, constructs a KVPair
+ // with either a default-construted or copy-constructed value
+ template <typename KeyParamT> handle_t DoInsert( KeyParamT k, unsigned int h );
+ template <typename KeyParamT> handle_t DoInsert( KeyParamT k, typename ArgumentTypeInfo<ValueT>::Arg_t v, unsigned int h, bool* pDidInsert );
+ template <typename KeyParamT> handle_t DoInsertNoCheck( KeyParamT k, typename ArgumentTypeInfo<ValueT>::Arg_t v, unsigned int h );
+
+ // Key lookup. Can also return previous-in-chain if result is chained.
+ template <typename KeyParamT> handle_t DoLookup( KeyParamT x, unsigned int h, handle_t *pPreviousInChain ) const;
+
+ // Remove single element by key + hash. Returns the index of the new hole
+ // that was created. Returns InvalidHandle() if element was not found.
+ template <typename KeyParamT> int DoRemove( KeyParamT x, unsigned int h );
+
+ // Friend CUtlStableHashtable so that it can call our Do* functions directly
+ template < typename K, typename V, typename S, typename H, typename E, typename A > friend class CUtlStableHashtable;
+
+public:
+ explicit CUtlHashtable( int minimumSize = 32 )
+ : m_nUsed(0), m_nMinSize(MAX(8, minimumSize)), m_bSizeLocked(false), m_eq(), m_hash() { }
+
+ CUtlHashtable( int minimumSize, const KeyHashT &hash, KeyIsEqualT const &eq = KeyIsEqualT() )
+ : m_nUsed(0), m_nMinSize(MAX(8, minimumSize)), m_bSizeLocked(false), m_eq(eq), m_hash(hash) { }
+
+ CUtlHashtable( entry_t* pMemory, unsigned int nCount, const KeyHashT &hash = KeyHashT(), KeyIsEqualT const &eq = KeyIsEqualT() )
+ : m_nUsed(0), m_nMinSize(8), m_bSizeLocked(false), m_eq(eq), m_hash(hash) { SetExternalBuffer( pMemory, nCount ); }
+
+ ~CUtlHashtable() { RemoveAll(); }
+
+ CUtlHashtable &operator=( CUtlHashtable const &src );
+
+ // Set external memory
+ void SetExternalBuffer( byte* pRawBuffer, unsigned int nBytes, bool bAssumeOwnership = false, bool bGrowable = false );
+ void SetExternalBuffer( entry_t* pBuffer, unsigned int nSize, bool bAssumeOwnership = false, bool bGrowable = false );
+
+ // Functor/function-pointer access
+ KeyHashT& GetHashRef() { return m_hash; }
+ KeyIsEqualT& GetEqualRef() { return m_eq; }
+ KeyHashT const &GetHashRef() const { return m_hash; }
+ KeyIsEqualT const &GetEqualRef() const { return m_eq; }
+
+ // Handle validation
+ bool IsValidHandle( handle_t idx ) const { return (unsigned)idx < (unsigned)m_table.Count() && m_table[idx].IsValid(); }
+ static handle_t InvalidHandle() { return (handle_t) -1; }
+
+ // Iteration functions
+ handle_t FirstHandle() const { return NextHandle( (handle_t) -1 ); }
+ handle_t NextHandle( handle_t start ) const;
+
+ // Returns the number of unique keys in the table
+ int Count() const { return m_nUsed; }
+
+
+ // Key lookup, returns InvalidHandle() if not found
+ handle_t Find( KeyArg_t k ) const { return DoLookup<KeyArg_t>( k, m_hash(k), NULL ); }
+ handle_t Find( KeyArg_t k, unsigned int hash) const { Assert( hash == m_hash(k) ); return DoLookup<KeyArg_t>( k, hash, NULL ); }
+ // Alternate-type key lookup, returns InvalidHandle() if not found
+ handle_t Find( KeyAlt_t k ) const { return DoLookup<KeyAlt_t>( k, m_hash(k), NULL ); }
+ handle_t Find( KeyAlt_t k, unsigned int hash) const { Assert( hash == m_hash(k) ); return DoLookup<KeyAlt_t>( k, hash, NULL ); }
+
+ // True if the key is in the table
+ bool HasElement( KeyArg_t k ) const { return InvalidHandle() != Find( k ); }
+ bool HasElement( KeyAlt_t k ) const { return InvalidHandle() != Find( k ); }
+
+ // Key insertion or lookup, always returns a valid handle
+ handle_t Insert( KeyArg_t k ) { return DoInsert<KeyArg_t>( k, m_hash(k) ); }
+ handle_t Insert( KeyArg_t k, ValueArg_t v, bool *pDidInsert = NULL ) { return DoInsert<KeyArg_t>( k, v, m_hash(k), pDidInsert ); }
+ handle_t Insert( KeyArg_t k, ValueArg_t v, unsigned int hash, bool *pDidInsert = NULL ) { Assert( hash == m_hash(k) ); return DoInsert<KeyArg_t>( k, v, hash, pDidInsert ); }
+ // Alternate-type key insertion or lookup, always returns a valid handle
+ handle_t Insert( KeyAlt_t k ) { return DoInsert<KeyAlt_t>( k, m_hash(k) ); }
+ handle_t Insert( KeyAlt_t k, ValueArg_t v, bool *pDidInsert = NULL ) { return DoInsert<KeyAlt_t>( k, v, m_hash(k), pDidInsert ); }
+ handle_t Insert( KeyAlt_t k, ValueArg_t v, unsigned int hash, bool *pDidInsert = NULL ) { Assert( hash == m_hash(k) ); return DoInsert<KeyAlt_t>( k, v, hash, pDidInsert ); }
+
+ // Key removal, returns false if not found
+ bool Remove( KeyArg_t k ) { return DoRemove<KeyArg_t>( k, m_hash(k) ) >= 0; }
+ bool Remove( KeyArg_t k, unsigned int hash ) { Assert( hash == m_hash(k) ); return DoRemove<KeyArg_t>( k, hash ) >= 0; }
+ // Alternate-type key removal, returns false if not found
+ bool Remove( KeyAlt_t k ) { return DoRemove<KeyAlt_t>( k, m_hash(k) ) >= 0; }
+ bool Remove( KeyAlt_t k, unsigned int hash ) { Assert( hash == m_hash(k) ); return DoRemove<KeyAlt_t>( k, hash ) >= 0; }
+
+ // Remove while iterating, returns the next handle for forward iteration
+ // Note: aside from this, ALL handles are invalid if an element is removed
+ handle_t RemoveAndAdvance( handle_t idx );
+
+ // Remove by handle, convenient when you look up a handle and do something with it before removing the element
+ void RemoveByHandle( handle_t idx );
+
+ // Nuke contents
+ void RemoveAll();
+
+ // Nuke and release memory.
+ void Purge() { RemoveAll(); m_table.Purge(); }
+
+ // Reserve table capacity up front to avoid reallocation during insertions
+ void Reserve( int expected ) { if ( expected > m_nUsed ) DoRealloc( expected * 4 / 3 ); }
+
+ // Shrink to best-fit size, re-insert keys for optimal lookup
+ void Compact( bool bMinimal ) { DoRealloc( bMinimal ? m_nUsed : ( m_nUsed * 4 / 3 ) ); }
+
+ // Access functions. Note: if ValueT is empty_t, all functions return const keys.
+ typedef typename KVPair::ValueReturn_t Element_t;
+ KeyT const &Key( handle_t idx ) const { return m_table[idx]->m_key; }
+ Element_t const &Element( handle_t idx ) const { return m_table[idx]->GetValue(); }
+ Element_t &Element(handle_t idx) { return m_table[idx]->GetValue(); }
+ Element_t const &operator[]( handle_t idx ) const { return m_table[idx]->GetValue(); }
+ Element_t &operator[]( handle_t idx ) { return m_table[idx]->GetValue(); }
+
+ void ReplaceKey( handle_t idx, KeyArg_t k ) { Assert( m_eq( m_table[idx]->m_key, k ) && m_hash( k ) == m_hash( m_table[idx]->m_key ) ); m_table[idx]->m_key = k; }
+ void ReplaceKey( handle_t idx, KeyAlt_t k ) { Assert( m_eq( m_table[idx]->m_key, k ) && m_hash( k ) == m_hash( m_table[idx]->m_key ) ); m_table[idx]->m_key = k; }
+
+ Element_t const &Get( KeyArg_t k, Element_t const &defaultValue ) const { handle_t h = Find( k ); if ( h != InvalidHandle() ) return Element( h ); return defaultValue; }
+ Element_t const &Get( KeyAlt_t k, Element_t const &defaultValue ) const { handle_t h = Find( k ); if ( h != InvalidHandle() ) return Element( h ); return defaultValue; }
+
+ Element_t const *GetPtr( KeyArg_t k ) const { handle_t h = Find(k); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
+ Element_t const *GetPtr( KeyAlt_t k ) const { handle_t h = Find(k); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
+ Element_t *GetPtr( KeyArg_t k ) { handle_t h = Find( k ); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
+ Element_t *GetPtr( KeyAlt_t k ) { handle_t h = Find( k ); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
+
+ // Swap memory and contents with another identical hashtable
+ // (NOTE: if using function pointers or functors with state,
+ // it is up to the caller to ensure that they are compatible!)
+ void Swap( CUtlHashtable &other ) { m_table.Swap(other.m_table); ::V_swap(m_nUsed, other.m_nUsed); }
+
+ // GetMemoryUsage returns all memory held by this class
+ // and its held classes. It does not include sizeof(*this).
+ size_t GetMemoryUsage() const
+ {
+ return m_table.AllocSize();
+ }
+
+ size_t GetReserveCount( )const
+ {
+ return m_table.Count();
+ }
+
+
+#if _DEBUG
+ // Validate the integrity of the hashtable
+ void DbgCheckIntegrity() const;
+#endif
+
+private:
+ CUtlHashtable(const CUtlHashtable& copyConstructorIsNotImplemented);
+};
+
+
+// Set external memory (raw byte buffer, best-fit)
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+void CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::SetExternalBuffer( byte* pRawBuffer, unsigned int nBytes, bool bAssumeOwnership, bool bGrowable )
+{
+ Assert( ((uintptr_t)pRawBuffer % __alignof(int)) == 0 );
+ uint32 bestSize = LargestPowerOfTwoLessThanOrEqual( nBytes / sizeof(entry_t) );
+ Assert( bestSize != 0 && bestSize*sizeof(entry_t) <= nBytes );
+
+ return SetExternalBuffer( (entry_t*) pRawBuffer, bestSize, bAssumeOwnership, bGrowable );
+}
+
+// Set external memory (typechecked, must be power of two)
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+void CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::SetExternalBuffer( entry_t* pBuffer, unsigned int nSize, bool bAssumeOwnership, bool bGrowable )
+{
+ Assert( IsPowerOfTwo(nSize) );
+ Assert( m_nUsed == 0 );
+ for ( uint i = 0; i < nSize; ++i )
+ pBuffer[i].MarkInvalid();
+ if ( bAssumeOwnership )
+ m_table.AssumeMemory( pBuffer, nSize );
+ else
+ m_table.SetExternalBuffer( pBuffer, nSize );
+ m_bSizeLocked = !bGrowable;
+}
+
+// Allocate an empty table and then re-insert all existing entries.
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+void CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DoRealloc( int size )
+{
+ Assert( !m_bSizeLocked );
+
+ size = SmallestPowerOfTwoGreaterOrEqual( MAX( m_nMinSize, size ) );
+ Assert( size > 0 && (uint)size <= entry_t::IdealIndex( ~0, 0x1FFFFFFF ) ); // reasonable power of 2
+ Assert( size > m_nUsed );
+
+ CUtlMemory<entry_t> oldTable;
+ oldTable.Swap( m_table );
+ entry_t * RESTRICT const pOldBase = oldTable.Base();
+
+ m_table.EnsureCapacity( size );
+ entry_t * const pNewBase = m_table.Base();
+ for ( int i = 0; i < size; ++i )
+ pNewBase[i].MarkInvalid();
+
+ int nLeftToMove = m_nUsed;
+ m_nUsed = 0;
+ for ( int i = oldTable.Count() - 1; i >= 0; --i )
+ {
+ if ( pOldBase[i].IsValid() )
+ {
+ int newIdx = DoInsertUnconstructed( pOldBase[i].flags_and_hash, false );
+ pNewBase[newIdx].MoveDataFrom( pOldBase[i] );
+ if ( --nLeftToMove == 0 )
+ break;
+ }
+ }
+ Assert( nLeftToMove == 0 );
+}
+
+
+// Move an existing entry to a free slot, leaving a hole behind
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+void CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::BumpEntry( unsigned int idx )
+{
+ Assert( m_table[idx].IsValid() );
+ Assert( m_nUsed < m_table.Count() );
+
+ entry_t* table = m_table.Base();
+ unsigned int slotmask = m_table.Count()-1;
+ unsigned int new_flags_and_hash = table[idx].flags_and_hash & (FLAG_LAST | MASK_HASH);
+
+ unsigned int chainid = entry_t::IdealIndex( new_flags_and_hash, slotmask );
+
+ // Look for empty slots scanning forward, stripping FLAG_LAST as we go.
+ // Note: this potentially strips FLAG_LAST from table[idx] if we pass it
+ int newIdx = chainid; // start at ideal slot
+ for ( ; ; newIdx = (newIdx + 1) & slotmask )
+ {
+ if ( table[newIdx].IdealIndex( slotmask ) == chainid )
+ {
+ if ( table[newIdx].flags_and_hash & FLAG_LAST )
+ {
+ table[newIdx].flags_and_hash &= ~FLAG_LAST;
+ new_flags_and_hash |= FLAG_LAST;
+ }
+ continue;
+ }
+ if ( table[newIdx].IsValid() )
+ {
+ continue;
+ }
+ break;
+ }
+
+ // Did we pick something closer to the ideal slot, leaving behind a
+ // FLAG_LAST bit on the current slot because we didn't scan past it?
+ if ( table[idx].flags_and_hash & FLAG_LAST )
+ {
+#ifdef _DEBUG
+ Assert( new_flags_and_hash & FLAG_LAST );
+ // Verify logic: we must have moved to an earlier slot, right?
+ uint offset = ((uint)idx - chainid + slotmask + 1) & slotmask;
+ uint newOffset = ((uint)newIdx - chainid + slotmask + 1) & slotmask;
+ Assert( newOffset < offset );
+#endif
+ // Scan backwards from old to new location, depositing FLAG_LAST on
+ // the first match we find. (+slotmask) is the same as (-1) without
+ // having to make anyone think about two's complement shenanigans.
+ int scan = (idx + slotmask) & slotmask;
+ while ( scan != newIdx )
+ {
+ if ( table[scan].IdealIndex( slotmask ) == chainid )
+ {
+ table[scan].flags_and_hash |= FLAG_LAST;
+ new_flags_and_hash &= ~FLAG_LAST;
+ break;
+ }
+ scan = (scan + slotmask) & slotmask;
+ }
+ }
+
+ // Move entry to the free slot we found, leaving a hole at idx
+ table[newIdx].flags_and_hash = new_flags_and_hash;
+ table[newIdx].MoveDataFrom( table[idx] );
+ table[idx].MarkInvalid();
+}
+
+
+// Insert a value at the root position for that value's hash chain.
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+int CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DoInsertUnconstructed( unsigned int h, bool allowGrow )
+{
+ if ( allowGrow && !m_bSizeLocked )
+ {
+ // Keep the load factor between .25 and .75
+ int newSize = m_nUsed + 1;
+ if ( ( newSize*4 < m_table.Count() && m_table.Count() > m_nMinSize*2 ) || newSize*4 > m_table.Count()*3 )
+ {
+ DoRealloc( newSize * 4 / 3 );
+ }
+ }
+ Assert( m_nUsed < m_table.Count() );
+ ++m_nUsed;
+
+ entry_t* table = m_table.Base();
+ unsigned int slotmask = m_table.Count()-1;
+ unsigned int new_flags_and_hash = FLAG_LAST | (h & MASK_HASH);
+ unsigned int idx = entry_t::IdealIndex( h, slotmask );
+ if ( table[idx].IdealIndex( slotmask ) == idx )
+ {
+ // There is already an entry in this chain.
+ new_flags_and_hash &= ~FLAG_LAST;
+ BumpEntry(idx);
+ }
+ else if ( table[idx].IsValid() )
+ {
+ // Somebody else is living in our ideal index but does not belong
+ // to our entry chain; move it out of the way, start a new chain.
+ BumpEntry(idx);
+ }
+ table[idx].flags_and_hash = new_flags_and_hash;
+ return idx;
+}
+
+
+// Key lookup. Can also return previous-in-chain if result is a chained slot.
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+template <typename KeyParamT>
+UtlHashHandle_t CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DoLookup( KeyParamT x, unsigned int h, handle_t *pPreviousInChain ) const
+{
+ if ( m_nUsed == 0 )
+ {
+ // Empty table.
+ return (handle_t) -1;
+ }
+
+ const entry_t* table = m_table.Base();
+ unsigned int slotmask = m_table.Count()-1;
+ Assert( m_table.Count() > 0 && (slotmask & m_table.Count()) == 0 );
+ unsigned int chainid = entry_t::IdealIndex( h, slotmask );
+
+ unsigned int idx = chainid;
+ if ( table[idx].IdealIndex( slotmask ) != chainid )
+ {
+ // Nothing in root position? No match.
+ return (handle_t) -1;
+ }
+
+ // Linear scan until found or end of chain
+ handle_t lastIdx = (handle_t) -1;
+ while (1)
+ {
+ // Only examine this slot if it is valid and belongs to our hash chain
+ if ( table[idx].IdealIndex( slotmask ) == chainid )
+ {
+ // Test the full-width hash to avoid unnecessary calls to m_eq()
+ if ( ((table[idx].flags_and_hash ^ h) & MASK_HASH) == 0 && m_eq( table[idx]->m_key, x ) )
+ {
+ // Found match!
+ if (pPreviousInChain)
+ *pPreviousInChain = lastIdx;
+
+ return (handle_t) idx;
+ }
+
+ if ( table[idx].flags_and_hash & FLAG_LAST )
+ {
+ // End of chain. No match.
+ return (handle_t) -1;
+ }
+
+ lastIdx = (handle_t) idx;
+ }
+ idx = (idx + 1) & slotmask;
+ }
+}
+
+
+// Key insertion, or return index of existing key if found
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+template <typename KeyParamT>
+UtlHashHandle_t CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DoInsert( KeyParamT k, unsigned int h )
+{
+ handle_t idx = DoLookup<KeyParamT>( k, h, NULL );
+ if ( idx == (handle_t) -1 )
+ {
+ idx = (handle_t) DoInsertUnconstructed( h, true );
+ ConstructOneArg( m_table[ idx ].Raw(), k );
+ }
+ return idx;
+}
+
+// Key insertion, or return index of existing key if found
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+template <typename KeyParamT>
+UtlHashHandle_t CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DoInsert( KeyParamT k, typename ArgumentTypeInfo<ValueT>::Arg_t v, unsigned int h, bool *pDidInsert )
+{
+ handle_t idx = DoLookup<KeyParamT>( k, h, NULL );
+ if ( idx == (handle_t) -1 )
+ {
+ idx = (handle_t) DoInsertUnconstructed( h, true );
+ ConstructTwoArg( m_table[ idx ].Raw(), k, v );
+ if ( pDidInsert ) *pDidInsert = true;
+ }
+ else
+ {
+ if ( pDidInsert ) *pDidInsert = false;
+ }
+ return idx;
+}
+
+// Key insertion
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+template <typename KeyParamT>
+UtlHashHandle_t CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DoInsertNoCheck( KeyParamT k, typename ArgumentTypeInfo<ValueT>::Arg_t v, unsigned int h )
+{
+ Assert( DoLookup<KeyParamT>( k, h, NULL ) == (handle_t) -1 );
+ handle_t idx = (handle_t) DoInsertUnconstructed( h, true );
+ ConstructTwoArg( m_table[ idx ].Raw(), k, v );
+ return idx;
+}
+
+
+// Remove single element by key + hash. Returns the location of the new empty hole.
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+template <typename KeyParamT>
+int CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DoRemove( KeyParamT x, unsigned int h )
+{
+ unsigned int slotmask = m_table.Count()-1;
+ handle_t previous = (handle_t) -1;
+ int idx = (int) DoLookup<KeyParamT>( x, h, &previous );
+ if (idx == -1)
+ {
+ return -1;
+ }
+
+ enum { FAKEFLAG_ROOT = 1 };
+ int nLastAndRootFlags = m_table[idx].flags_and_hash & FLAG_LAST;
+ nLastAndRootFlags |= ( (uint)idx == m_table[idx].IdealIndex( slotmask ) );
+
+ // Remove from table
+ m_table[idx].MarkInvalid();
+ Destruct( m_table[idx].Raw() );
+ --m_nUsed;
+
+ if ( nLastAndRootFlags == FLAG_LAST ) // last only, not root
+ {
+ // This was the end of the chain - mark previous as last.
+ // (This isn't the root, so there must be a previous.)
+ Assert( previous != (handle_t) -1 );
+ m_table[previous].flags_and_hash |= FLAG_LAST;
+ }
+
+ if ( nLastAndRootFlags == FAKEFLAG_ROOT ) // root only, not last
+ {
+ // If we are removing the root and there is more to the chain,
+ // scan to find the next chain entry and move it to the root.
+ unsigned int chainid = entry_t::IdealIndex( h, slotmask );
+ unsigned int nextIdx = idx;
+ while (1)
+ {
+ nextIdx = (nextIdx + 1) & slotmask;
+ if ( m_table[nextIdx].IdealIndex( slotmask ) == chainid )
+ {
+ break;
+ }
+ }
+ Assert( !(m_table[nextIdx].flags_and_hash & FLAG_FREE) );
+
+ // Leave a hole where the next entry in the chain was.
+ m_table[idx].flags_and_hash = m_table[nextIdx].flags_and_hash;
+ m_table[idx].MoveDataFrom( m_table[nextIdx] );
+ m_table[nextIdx].MarkInvalid();
+ return nextIdx;
+ }
+
+ // The hole is still where the element used to be.
+ return idx;
+}
+
+
+// Assignment operator. It's up to the user to make sure that the hash and equality functors match.
+template <typename K, typename V, typename H, typename E, typename A>
+CUtlHashtable<K,V,H,E,A> &CUtlHashtable<K,V,H,E,A>::operator=( CUtlHashtable<K,V,H,E,A> const &src )
+{
+ if ( &src != this )
+ {
+ Assert( !m_bSizeLocked || m_table.Count() >= src.m_nUsed );
+ if ( !m_bSizeLocked )
+ {
+ Purge();
+ Reserve(src.m_nUsed);
+ }
+ else
+ {
+ RemoveAll();
+ }
+
+ const entry_t * srcTable = src.m_table.Base();
+ for ( int i = src.m_table.Count() - 1; i >= 0; --i )
+ {
+ if ( srcTable[i].IsValid() )
+ {
+ // If this assert trips, double-check that both hashtables
+ // have the same hash function pointers or hash functor state!
+ Assert( m_hash(srcTable[i]->m_key) == src.m_hash(srcTable[i]->m_key) );
+ int newIdx = DoInsertUnconstructed( srcTable[i].flags_and_hash , false );
+ CopyConstruct( m_table[newIdx].Raw(), *srcTable[i].Raw() ); // copy construct KVPair
+ }
+ }
+ }
+ return *this;
+}
+
+// Remove and return the next valid iterator for a forward iteration.
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+UtlHashHandle_t CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::RemoveAndAdvance( UtlHashHandle_t idx )
+{
+ Assert( IsValidHandle( idx ) );
+
+ // TODO optimize, implement DoRemoveAt that does not need to re-evaluate equality in DoLookup
+ int hole = DoRemove< KeyArg_t >( m_table[idx]->m_key, m_table[idx].flags_and_hash & MASK_HASH );
+ // DoRemove returns the index of the element that it moved to fill the hole, if any.
+ if ( hole <= (int) idx )
+ {
+ // Didn't fill, or filled from a previously seen element.
+ return NextHandle( idx );
+ }
+ else
+ {
+ // Do not advance; slot has a new un-iterated value.
+ Assert( IsValidHandle(idx) );
+ return idx;
+ }
+}
+
+
+// Remove and return the next valid iterator for a forward iteration.
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+void CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::RemoveByHandle( UtlHashHandle_t idx )
+{
+ Assert( IsValidHandle( idx ) );
+
+ // Copied from RemoveAndAdvance(): TODO optimize, implement DoRemoveAt that does not need to re-evaluate equality in DoLookup
+ DoRemove< KeyArg_t >( m_table[idx]->m_key, m_table[idx].flags_and_hash & MASK_HASH );
+}
+
+
+// Burn it with fire.
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+void CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::RemoveAll()
+{
+ int used = m_nUsed;
+ if ( used != 0 )
+ {
+ entry_t* table = m_table.Base();
+ for ( int i = m_table.Count() - 1; i >= 0; --i )
+ {
+ if ( table[i].IsValid() )
+ {
+ table[i].MarkInvalid();
+ Destruct( table[i].Raw() );
+ if ( --used == 0 )
+ break;
+ }
+ }
+ m_nUsed = 0;
+ }
+}
+
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+UtlHashHandle_t CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::NextHandle( handle_t start ) const
+{
+ const entry_t *table = m_table.Base();
+ for ( int i = (int)start + 1; i < m_table.Count(); ++i )
+ {
+ if ( table[i].IsValid() )
+ return (handle_t) i;
+ }
+ return (handle_t) -1;
+}
+
+
+#if _DEBUG
+template <typename KeyT, typename ValueT, typename KeyHashT, typename KeyIsEqualT, typename AltKeyT>
+void CUtlHashtable<KeyT, ValueT, KeyHashT, KeyIsEqualT, AltKeyT>::DbgCheckIntegrity() const
+{
+ // Stress test the hash table as a test of both container functionality
+ // and also the validity of the user's Hash and Equal function objects.
+ // NOTE: will fail if function objects require any sort of state!
+ CUtlHashtable clone;
+ unsigned int bytes = sizeof(entry_t)*max(16,m_table.Count());
+ byte* tempbuf = (byte*) malloc(bytes);
+ clone.SetExternalBuffer( tempbuf, bytes, false, false );
+ clone = *this;
+
+ int count = 0, roots = 0, ends = 0;
+ int slotmask = m_table.Count() - 1;
+ for (int i = 0; i < m_table.Count(); ++i)
+ {
+ if (!(m_table[i].flags_and_hash & FLAG_FREE)) ++count;
+ if (m_table[i].IdealIndex(slotmask) == (uint)i) ++roots;
+ if (m_table[i].flags_and_hash & FLAG_LAST) ++ends;
+ if (m_table[i].IsValid())
+ {
+ Assert( Find(m_table[i]->m_key) == (handle_t)i );
+ Verify( clone.Remove(m_table[i]->m_key) );
+ }
+ else
+ {
+ Assert( m_table[i].flags_and_hash == FLAG_FREE );
+ }
+ }
+ Assert( count == Count() && count >= roots && roots == ends );
+ Assert( clone.Count() == 0 );
+ clone.Purge();
+ free(tempbuf);
+}
+#endif
+
+//-----------------------------------------------------------------------
+// CUtlStableHashtable
+//-----------------------------------------------------------------------
+
+// Stable hashtables are less memory and cache efficient, but can be
+// iterated quickly and their element handles are completely stable.
+// Implemented as a hashtable which only stores indices, and a separate
+// CUtlLinkedList data table which contains key-value pairs; this may
+// change to a more efficient structure in the future if space becomes
+// critical. I have some ideas about that but not the time to implement
+// at the moment. -henryg
+
+// Note: RemoveAndAdvance is slower than in CUtlHashtable because the
+// key needs to be re-hashed under the current implementation.
+
+template <typename KeyT, typename ValueT = empty_t, typename KeyHashT = DefaultHashFunctor<KeyT>, typename KeyIsEqualT = DefaultEqualFunctor<KeyT>, typename IndexStorageT = uint16, typename AlternateKeyT = typename ArgumentTypeInfo<KeyT>::Alt_t >
+class CUtlStableHashtable
+{
+public:
+ typedef typename ArgumentTypeInfo<KeyT>::Arg_t KeyArg_t;
+ typedef typename ArgumentTypeInfo<ValueT>::Arg_t ValueArg_t;
+ typedef typename ArgumentTypeInfo<AlternateKeyT>::Arg_t KeyAlt_t;
+ typedef typename CTypeSelect< sizeof( IndexStorageT ) == 2, uint16, uint32 >::type IndexStorage_t;
+
+protected:
+ COMPILE_TIME_ASSERT( sizeof( IndexStorage_t ) == sizeof( IndexStorageT ) );
+
+ typedef CUtlKeyValuePair< KeyT, ValueT > KVPair;
+ struct HashProxy;
+ struct EqualProxy;
+ struct IndirectIndex;
+
+ typedef CUtlHashtable< IndirectIndex, empty_t, HashProxy, EqualProxy, AlternateKeyT > Hashtable_t;
+ typedef CUtlLinkedList< KVPair, IndexStorage_t > LinkedList_t;
+
+ template <typename KeyArgumentT> bool DoRemove( KeyArgumentT k );
+ template <typename KeyArgumentT> UtlHashHandle_t DoFind( KeyArgumentT k ) const;
+ template <typename KeyArgumentT> UtlHashHandle_t DoInsert( KeyArgumentT k );
+ template <typename KeyArgumentT, typename ValueArgumentT> UtlHashHandle_t DoInsert( KeyArgumentT k, ValueArgumentT v );
+
+public:
+
+ KeyHashT &GetHashRef() { return m_table.GetHashRef().m_hash; }
+ KeyIsEqualT &GetEqualRef() { return m_table.GetEqualRef().m_eq; }
+ KeyHashT const &GetHashRef() const { return m_table.GetHashRef().m_hash; }
+ KeyIsEqualT const &GetEqualRef() const { return m_table.GetEqualRef().m_eq; }
+
+ UtlHashHandle_t Insert( KeyArg_t k ) { return DoInsert<KeyArg_t>( k ); }
+ UtlHashHandle_t Insert( KeyAlt_t k ) { return DoInsert<KeyAlt_t>( k ); }
+ UtlHashHandle_t Insert( KeyArg_t k, ValueArg_t v ) { return DoInsert<KeyArg_t, ValueArg_t>( k, v ); }
+ UtlHashHandle_t Insert( KeyAlt_t k, ValueArg_t v ) { return DoInsert<KeyAlt_t, ValueArg_t>( k, v ); }
+ UtlHashHandle_t Find( KeyArg_t k ) const { return DoFind<KeyArg_t>( k ); }
+ UtlHashHandle_t Find( KeyAlt_t k ) const { return DoFind<KeyAlt_t>( k ); }
+ bool Remove( KeyArg_t k ) { return DoRemove<KeyArg_t>( k ); }
+ bool Remove( KeyAlt_t k ) { return DoRemove<KeyAlt_t>( k ); }
+
+ void RemoveAll() { m_table.RemoveAll(); m_data.RemoveAll(); }
+ void Purge() { m_table.Purge(); m_data.Purge(); }
+ int Count() const { return m_table.Count(); }
+
+ typedef typename KVPair::ValueReturn_t Element_t;
+ KeyT const &Key( UtlHashHandle_t idx ) const { return m_data[idx].m_key; }
+ Element_t const &Element( UtlHashHandle_t idx ) const { return m_data[idx].GetValue(); }
+ Element_t &Element( UtlHashHandle_t idx ) { return m_data[idx].GetValue(); }
+ Element_t const &operator[]( UtlHashHandle_t idx ) const { return m_data[idx].GetValue(); }
+ Element_t &operator[]( UtlHashHandle_t idx ) { return m_data[idx].GetValue(); }
+
+ void ReplaceKey( UtlHashHandle_t idx, KeyArg_t k ) { Assert( GetEqualRef()( m_data[idx].m_key, k ) && GetHashRef()( k ) == GetHashRef()( m_data[idx].m_key ) ); m_data[idx].m_key = k; }
+ void ReplaceKey( UtlHashHandle_t idx, KeyAlt_t k ) { Assert( GetEqualRef()( m_data[idx].m_key, k ) && GetHashRef()( k ) == GetHashRef()( m_data[idx].m_key ) ); m_data[idx].m_key = k; }
+
+ Element_t const &Get( KeyArg_t k, Element_t const &defaultValue ) const { UtlHashHandle_t h = Find( k ); if ( h != InvalidHandle() ) return Element( h ); return defaultValue; }
+ Element_t const &Get( KeyAlt_t k, Element_t const &defaultValue ) const { UtlHashHandle_t h = Find( k ); if ( h != InvalidHandle() ) return Element( h ); return defaultValue; }
+
+ Element_t const *GetPtr( KeyArg_t k ) const { UtlHashHandle_t h = Find(k); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
+ Element_t const *GetPtr( KeyAlt_t k ) const { UtlHashHandle_t h = Find(k); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
+ Element_t *GetPtr( KeyArg_t k ) { UtlHashHandle_t h = Find( k ); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
+ Element_t *GetPtr( KeyAlt_t k ) { UtlHashHandle_t h = Find( k ); if ( h != InvalidHandle() ) return &Element( h ); return NULL; }
+
+ UtlHashHandle_t FirstHandle() const { return ExtendInvalidHandle( m_data.Head() ); }
+ UtlHashHandle_t NextHandle( UtlHashHandle_t h ) const { return ExtendInvalidHandle( m_data.Next( h ) ); }
+ bool IsValidHandle( UtlHashHandle_t h ) const { return m_data.IsValidIndex( h ); }
+ UtlHashHandle_t InvalidHandle() const { return (UtlHashHandle_t)-1; }
+
+ UtlHashHandle_t RemoveAndAdvance( UtlHashHandle_t h )
+ {
+ Assert( m_data.IsValidIndex( h ) );
+ m_table.Remove( IndirectIndex( h ) );
+ IndexStorage_t next = m_data.Next( h );
+ m_data.Remove( h );
+ return ExtendInvalidHandle(next);
+ }
+
+ void Compact( bool bMinimal ) { m_table.Compact( bMinimal ); /*m_data.Compact();*/ }
+
+ void Swap( CUtlStableHashtable &other )
+ {
+ m_table.Swap(other.m_table);
+ // XXX swapping CUtlLinkedList by block memory swap, ugh
+ char buf[ sizeof(m_data) ];
+ memcpy( buf, &m_data, sizeof(m_data) );
+ memcpy( &m_data, &other.m_data, sizeof(m_data) );
+ memcpy( &other.m_data, buf, sizeof(m_data) );
+ }
+
+
+protected:
+ // Perform extension of 0xFFFF to 0xFFFFFFFF if necessary. Note: ( a < CONSTANT ) ? 0 : -1 is usually branchless
+ static UtlHashHandle_t ExtendInvalidHandle( uint32 x ) { return x; }
+ static UtlHashHandle_t ExtendInvalidHandle( uint16 x ) { uint32 a = x; return a | ( ( a < 0xFFFFu ) ? 0 : -1 ); }
+
+ struct IndirectIndex
+ {
+ explicit IndirectIndex(IndexStorage_t i) : m_index(i) { }
+ IndexStorage_t m_index;
+ };
+
+ struct HashProxy
+ {
+ KeyHashT m_hash;
+ unsigned int operator()( IndirectIndex idx ) const
+ {
+ const ptrdiff_t tableoffset = (uintptr_t)(&((Hashtable_t*)1024)->GetHashRef()) - 1024;
+ const ptrdiff_t owneroffset = offsetof(CUtlStableHashtable, m_table) + tableoffset;
+ CUtlStableHashtable* pOwner = (CUtlStableHashtable*)((uintptr_t)this - owneroffset);
+ return m_hash( pOwner->m_data[ idx.m_index ].m_key );
+ }
+ unsigned int operator()( KeyArg_t k ) const { return m_hash( k ); }
+ unsigned int operator()( KeyAlt_t k ) const { return m_hash( k ); }
+ };
+
+ struct EqualProxy
+ {
+ KeyIsEqualT m_eq;
+ unsigned int operator()( IndirectIndex lhs, IndirectIndex rhs ) const
+ {
+ return lhs.m_index == rhs.m_index;
+ }
+ unsigned int operator()( IndirectIndex lhs, KeyArg_t rhs ) const
+ {
+ const ptrdiff_t tableoffset = (uintptr_t)(&((Hashtable_t*)1024)->GetEqualRef()) - 1024;
+ const ptrdiff_t owneroffset = offsetof(CUtlStableHashtable, m_table) + tableoffset;
+ CUtlStableHashtable* pOwner = (CUtlStableHashtable*)((uintptr_t)this - owneroffset);
+ return m_eq( pOwner->m_data[ lhs.m_index ].m_key, rhs );
+ }
+ unsigned int operator()( IndirectIndex lhs, KeyAlt_t rhs ) const
+ {
+ const ptrdiff_t tableoffset = (uintptr_t)(&((Hashtable_t*)1024)->GetEqualRef()) - 1024;
+ const ptrdiff_t owneroffset = offsetof(CUtlStableHashtable, m_table) + tableoffset;
+ CUtlStableHashtable* pOwner = (CUtlStableHashtable*)((uintptr_t)this - owneroffset);
+ return m_eq( pOwner->m_data[ lhs.m_index ].m_key, rhs );
+ }
+ };
+
+ class CCustomLinkedList : public LinkedList_t
+ {
+ public:
+ int AddToTailUnconstructed()
+ {
+ IndexStorage_t newNode = this->AllocInternal();
+ if ( newNode != this->InvalidIndex() )
+ this->LinkToTail( newNode );
+ return newNode;
+ }
+ };
+
+ Hashtable_t m_table;
+ CCustomLinkedList m_data;
+};
+
+template <typename K, typename V, typename H, typename E, typename S, typename A>
+template <typename KeyArgumentT>
+inline bool CUtlStableHashtable<K,V,H,E,S,A>::DoRemove( KeyArgumentT k )
+{
+ unsigned int hash = m_table.GetHashRef()( k );
+ UtlHashHandle_t h = m_table.template DoLookup<KeyArgumentT>( k, hash, NULL );
+ if ( h == m_table.InvalidHandle() )
+ return false;
+
+ int idx = m_table[ h ].m_index;
+ m_table.template DoRemove<IndirectIndex>( IndirectIndex( idx ), hash );
+ m_data.Remove( idx );
+ return true;
+}
+
+template <typename K, typename V, typename H, typename E, typename S, typename A>
+template <typename KeyArgumentT>
+inline UtlHashHandle_t CUtlStableHashtable<K,V,H,E,S,A>::DoFind( KeyArgumentT k ) const
+{
+ unsigned int hash = m_table.GetHashRef()( k );
+ UtlHashHandle_t h = m_table.template DoLookup<KeyArgumentT>( k, hash, NULL );
+ if ( h != m_table.InvalidHandle() )
+ return m_table[ h ].m_index;
+
+ return (UtlHashHandle_t) -1;
+}
+
+template <typename K, typename V, typename H, typename E, typename S, typename A>
+template <typename KeyArgumentT>
+inline UtlHashHandle_t CUtlStableHashtable<K,V,H,E,S,A>::DoInsert( KeyArgumentT k )
+{
+ unsigned int hash = m_table.GetHashRef()( k );
+ UtlHashHandle_t h = m_table.template DoLookup<KeyArgumentT>( k, hash, NULL );
+ if ( h != m_table.InvalidHandle() )
+ return m_table[ h ].m_index;
+
+ int idx = m_data.AddToTailUnconstructed();
+ ConstructOneArg( &m_data[idx], k );
+ m_table.template DoInsertNoCheck<IndirectIndex>( IndirectIndex( idx ), empty_t(), hash );
+ return idx;
+}
+
+template <typename K, typename V, typename H, typename E, typename S, typename A>
+template <typename KeyArgumentT, typename ValueArgumentT>
+inline UtlHashHandle_t CUtlStableHashtable<K,V,H,E,S,A>::DoInsert( KeyArgumentT k, ValueArgumentT v )
+{
+ unsigned int hash = m_table.GetHashRef()( k );
+ UtlHashHandle_t h = m_table.template DoLookup<KeyArgumentT>( k, hash, NULL );
+ if ( h != m_table.InvalidHandle() )
+ return m_table[ h ].m_index;
+
+ int idx = m_data.AddToTailUnconstructed();
+ ConstructTwoArg( &m_data[idx], k, v );
+ m_table.template DoInsertNoCheck<IndirectIndex>( IndirectIndex( idx ), empty_t(), hash );
+ return idx;
+}
+
+#endif // UTLHASHTABLE_H
diff --git a/public/tier1/utlintrusivelist.h b/public/tier1/utlintrusivelist.h
new file mode 100644
index 0000000..04a39bd
--- /dev/null
+++ b/public/tier1/utlintrusivelist.h
@@ -0,0 +1,888 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Intrusive linked list templates, both for singly and doubly linked lists
+//
+// $Revision: $
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef UTILINTRUSIVELIST_H
+#define UTILINTRUSIVELIST_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/basetypes.h"
+#include "utlmemory.h"
+#include "tier0/dbg.h"
+
+
+//
+// These templates are used for intrusive linked list classes. Intrusive linked list templates
+// force the structs and classes contained within them to have their own m_pNext, (optionally),
+// m_pPrev, and other fields contained within. All memory management is up to the caller and their
+// classes. No data will ever be copied. Nodes can only exist on one list at a time, because of
+// only having on m_Next field, and manipulating the list while walking it requires that care on
+// the part of the caller. All accessing and searching functions work by passing and returning
+// pointers.
+//
+//
+//
+// naming and field conventions:
+// functions referring to a DList are for doubly linked lists. nodes must have m_pHead and
+// m_pPrev pointer fields.
+// Functions using Priority require an m_Priority field, which must be comparable.
+//
+// Some functions are mean for use with lists which maintain both a head and tail pointer
+// in order to support fast adding to the end.
+
+
+/// validates that the doubly linked list has the proper structure, pointer-wise
+
+namespace IntrusiveList
+{
+#ifdef SUPERSLOW_DEBUG_VERSION
+ template<class T> inline void ValidateDList(T *head)
+ {
+ if (head)
+ {
+ Assert(head->m_pPrev==0);
+ }
+ while(head)
+ {
+ if (head->m_pNext)
+ {
+ Assert(head->m_pNext->m_pPrev==head);
+ }
+ if (head->m_pPrev)
+ {
+ Assert(head->m_pPrev->m_pNext==head);
+ }
+ head=head->m_pNext;
+ }
+ }
+#else
+ template<class T> inline void ValidateDList(T * /*head*/)
+ {
+ }
+#endif
+
+
+
+// move a node in a doubly linked list backwards one step.
+ template <class T> inline void MoveDNodeBackwards( T *which, T * &head)
+ {
+ if (which->m_pPrev)
+ {
+ T *p=which->m_pPrev;
+ T *pp=p->m_pPrev;
+ T *n=which->m_pNext;
+ Assert(p->m_pNext == which);
+ if (n)
+ {
+ Assert(n->m_pPrev==which);
+ n->m_pPrev=p;
+ }
+ if (pp)
+ {
+ Assert(pp->m_pNext==p);
+ pp->m_pNext=which;
+ }
+ else
+ {
+ head=which; // this node is the new root!
+ }
+ which->m_pNext=p;
+ which->m_pPrev=pp;
+ p->m_pNext=n;
+ p->m_pPrev=which;
+ }
+ ValidateDList(head);
+ }
+
+
+
+ // removes node 'which' from doubly linked list with 'head'
+ template<class T> inline void RemoveFromDList(T * &head, T *which)
+ {
+ if (which->m_pPrev)
+ {
+ Assert(which->m_pPrev->m_pNext==which);
+ which->m_pPrev->m_pNext=which->m_pNext;
+ if (which->m_pNext)
+ {
+ Assert(which->m_pNext->m_pPrev==which);
+ which->m_pNext->m_pPrev=which->m_pPrev;
+ }
+ }
+ else
+ {
+ if (head==which)
+ {
+ head=which->m_pNext;
+ if (head)
+ {
+ Assert(head->m_pPrev==which);
+ head->m_pPrev=0;
+ }
+ }
+ }
+ which->m_pNext=which->m_pPrev=0;
+ ValidateDList(head);
+
+ }
+
+ //checks to see if node is in doubly linked list
+ template<class T> bool OnDList(T const *head, T const *which)
+ {
+ return (head==which) || (which->m_pNext !=0) || (which->m_pPrev !=0);
+ }
+
+ // add a node to the end of a singly linked list
+ template<class T> void AddToDTail(T * & head, T * node)
+ {
+ node->m_pNext=0;
+ if (! head)
+ {
+ head=node;
+ }
+ else
+ {
+ T *ptr=head;
+ while(ptr->m_pNext)
+ {
+ ptr=ptr->m_pNext;
+ }
+ ptr->m_pNext=node;
+ node->m_pPrev=ptr; //
+ }
+ }
+
+ // add a node to end of doubly linked list.
+ template<class T> inline void AddToDHead(T * &head, T *which)
+ {
+ which->m_pNext=head;
+ if (head)
+ {
+ head->m_pPrev=which;
+ }
+ which->m_pPrev=0;
+ head=which;
+ ValidateDList(head);
+ }
+
+ // add a node to front of doubly linked list which maintains a tail ptr
+ template<class T> inline void AddToDHeadWithTailPtr(T * &head, T *which, T * &tailptr)
+ {
+ which->m_pNext=head;
+ if (head)
+ {
+ head->m_pPrev=which;
+ }
+ else
+ {
+ tailptr=which;
+ }
+ which->m_pPrev=0;
+ head=which;
+ ValidateDList(head);
+ }
+
+ // add a node to end of doubly linked list which maintains a tail ptr
+ template<class T> inline void AddToDTailWithTailPtr(T * &head, T *which, T * & tailptr)
+ {
+ if (! tailptr)
+ {
+ Assert(! head);
+ which->m_pPrev=which->m_pNext=0;
+ tailptr=head=which;
+ }
+ else
+ {
+ which->m_pNext=0;
+ which->m_pPrev=tailptr;
+ tailptr->m_pNext=which;
+ tailptr=which;
+ }
+ ValidateDList( head );
+ }
+
+ // Remove a node from a dlist , maintaining the tail ptr. node is not 'delete' d
+ template<class T> inline void RemoveFromDListWithTailPtr(T * &head, T *which, T * & tailptr)
+ {
+ if (which==tailptr)
+ {
+ tailptr=which->m_pPrev;
+ }
+ if (which->m_pPrev)
+ {
+ Assert(which->m_pPrev->m_pNext==which);
+ which->m_pPrev->m_pNext=which->m_pNext;
+ if (which->m_pNext)
+ {
+ Assert(which->m_pNext->m_pPrev==which);
+ which->m_pNext->m_pPrev=which->m_pPrev;
+ }
+ }
+ else
+ {
+ if (head==which)
+ {
+ head=which->m_pNext;
+ if (head)
+ {
+ Assert(head->m_pPrev==which);
+ head->m_pPrev=0;
+ }
+ }
+ }
+ which->m_pNext=which->m_pPrev=0;
+ ValidateDList(head);
+
+ }
+
+ // this function removes a node, and delete's the node
+ template<class T> inline void DeleteFromDListWithTailPtr(T * &head, T *which, T * & tailptr)
+ {
+ T *tmp=which;
+ if (which==tailptr)
+ {
+ tailptr=which->m_pPrev;
+ }
+ if (which->m_pPrev)
+ {
+ Assert(which->m_pPrev->m_pNext==which);
+ which->m_pPrev->m_pNext=which->m_pNext;
+ if (which->m_pNext)
+ {
+ Assert(which->m_pNext->m_pPrev==which);
+ which->m_pNext->m_pPrev=which->m_pPrev;
+ }
+ }
+ else
+ {
+ if (head==which)
+ {
+ head=which->m_pNext;
+ if (head)
+ {
+ Assert(head->m_pPrev==which);
+ head->m_pPrev=0;
+ }
+ }
+ }
+ which->m_pNext=which->m_pPrev=0;
+ delete tmp;
+ ValidateDList(head);
+ }
+
+ // Add a node to a d-list, keeping the highest priority nodes first. This is a simple
+ // linear search to insert, NOT a O(logn) heap.
+ template<class T> inline void AddToDPriority(T * &head, T *which)
+ {
+ T* prevnode=0;
+ for(T *curnode=head;curnode;curnode=curnode->m_pNext)
+ {
+ if (which->m_Priority>=curnode->m_Priority)
+ break;
+ prevnode=curnode;
+ }
+ // now, we have either run out of list, or we have found an
+ // element to add this one before
+ if (! prevnode)
+ {
+ AddToDHead(head,which);
+ }
+ else
+ {
+ which->m_pNext=prevnode->m_pNext;
+ prevnode->m_pNext=which;
+ which->m_pPrev=prevnode;
+ if (which->m_pNext)
+ which->m_pNext->m_pPrev=which;
+ }
+ }
+
+ // same as AddToDPriority, except with reverse order
+ template<class T> inline void AddToDPriorityLowestFirst(T * &head, T *which)
+ {
+ T* prevnode=0;
+ for(T *curnode=head;curnode;curnode=curnode->m_pNext)
+ {
+ if (which->m_Priority<=curnode->m_Priority)
+ break;
+ prevnode=curnode;
+ }
+ // now, we have either run out of list, or we have found an
+ // element to add this one before
+ if (! prevnode)
+ {
+ AddToDHead(head,which);
+ }
+ else
+ {
+ which->m_pNext=prevnode->m_pNext;
+ prevnode->m_pNext=which;
+ which->m_pPrev=prevnode;
+ if (which->m_pNext)
+ which->m_pNext->m_pPrev=which;
+ }
+ }
+
+
+ // return a pointer to the last node in a singly-linked (or doubly) list
+ template<class T> T * LastNode(T * head)
+ {
+ if (head)
+ {
+ while(head->m_pNext)
+ {
+ head=head->m_pNext;
+ }
+ }
+ return head;
+ }
+
+
+ // Remove from a singly linked list. no delete called.
+ template<class T,class V> void RemoveFromList(T * & head, V *which)
+ {
+ if (head==which)
+ {
+ head=which->m_pNext;
+ }
+ else
+ {
+ for(T * i=head; i; i=i->m_pNext)
+ {
+ if (i->m_pNext==which)
+ {
+ i->m_pNext=which->m_pNext;
+ return;
+ }
+ }
+ }
+ }
+
+ // same as RemoveFromList, but 'delete' is called.
+ template<class T,class V> void DeleteFromList(T * & head, V *which)
+ {
+ T *tmp;
+ if (head==which)
+ {
+ tmp=which->m_pNext;
+ delete(head);
+ head=tmp;
+ }
+ else
+ {
+ for(T * i=head; i; i=i->m_pNext)
+ {
+ if (i->m_pNext==which)
+ {
+ tmp=which->m_pNext;
+ delete(which);
+ i->m_pNext=tmp;
+ return;
+ }
+ }
+ }
+ }
+
+ // find the position in a list of a node. -1 if not found. Linear search.
+ // nodes must have comparison functions
+ template<class T,class V> int PositionInList(T *head, V *node)
+ {
+ int pos=0;
+ while(head)
+ {
+ if (head==node) return pos;
+ head=head->m_pNext;
+ pos++;
+ }
+ return -1;
+ }
+
+ // find the Nth node in a list. null if index too high.
+ template<class T> T *NthNode(T * head, int idx)
+ {
+ while(idx && head)
+ {
+ idx--;
+ head=head->m_pNext;
+ }
+ return head;
+ }
+
+ //Add a node to the head of a singly-linked
+ // Note that the head var passed to this will be modified.
+ template<class T,class V> static inline void AddToHead(T * & head, V * node)
+ {
+ node->m_pNext=head;
+ head=node;
+ }
+
+ //Add a node to the tail of a singly-linked. Not fast
+ // Note that the head var passed to this will be modified.
+ template<class T,class V> static inline void AddToTail(T * & head, V * node)
+ {
+ node->m_pNext = NULL;
+ if ( ! head )
+ head = node;
+ else
+ {
+ T *pLastNode = head;
+ while( pLastNode->m_pNext )
+ pLastNode = pLastNode->m_pNext;
+ pLastNode->m_pNext = node;
+ }
+ }
+
+ //Add a node to the head of a singly-linked list, maintaining a tail pointer
+ template<class T,class V> static inline void AddToHead(T * & head, T * &tail,V * node)
+ {
+ if (! head)
+ {
+ tail=node;
+ }
+ node->m_pNext=head;
+ head=node;
+ }
+
+
+
+ // return the node in head before in a singly linked list. returns null if head is empty, n is
+ // null, or if n is the first node. not fast.
+ template<class T> static inline T * PrevNode(T *head, T *node)
+ {
+ T *i;
+ for(i=head;i;i=i->m_pNext)
+ {
+ if (i->m_pNext == node)
+ break;
+ }
+ return i;
+ }
+
+
+ // add a node to the end of a singly linked list. Not fast.
+ template<class T,class V> void AddToEnd(T * & head, V * node)
+ {
+ node->m_pNext=0;
+ if (! head)
+ {
+ head=node;
+ }
+ else
+ {
+ T *ptr=head;
+ while(ptr->m_pNext)
+ {
+ ptr=ptr->m_pNext;
+ }
+ ptr->m_pNext=node;
+ }
+ }
+
+ // add a node to the end of a singly linked list, maintaining a tail pointer.
+ // the head and tail pointer can be modified by this routine.
+ template<class T,class V> void AddToEndWithTail(T * & head, T * & tail,V * node)
+ {
+ Assert((head && tail) || ((!head) && (!tail)));
+ node->m_pNext=0;
+ if (! head)
+ {
+ head=tail=node;
+ }
+ else
+ {
+ tail->m_pNext=node;
+ tail=node;
+ }
+ }
+
+ // Add a node to a singly linked list, sorting by the m_Name field
+ template<class T> void AddSortedByName(T * & head, T * node)
+ {
+ if ( (! head) || // empty list?
+ (stricmp(node->m_Name,head->m_Name)==-1)) // or we should be first?
+ {
+ node->m_pNext=head; // make us head
+ head=node;
+ }
+ else
+ {
+ T *t;
+ for(t=head;t->m_pNext;t=t->m_pNext) // find the node we should be before
+ if (stricmp(t->m_pNext->m_Name,node->m_Name)>=0)
+ break;
+ node->m_pNext=t->m_pNext;
+ t->m_pNext=node;
+ }
+ }
+
+ // count # of elements in list
+ template<class T> int ListLength(T *head)
+ {
+ int len=0;
+ while(head)
+ {
+ len++;
+ head=head->m_pNext;
+ }
+ return len;
+ }
+
+ // this will kill a list if the list is of objects which automatically
+ // remove themselves from the list when delete is called
+ template<class T> void KillList(T * & head)
+ {
+ while(head)
+ {
+ delete head;
+ }
+ }
+
+
+ // this will kill all elements in a list if
+ // the elements are of a type which does NOT remove itself from
+ // the list when the destructor is called.
+ template<class T> void DeleteList(T * & head)
+ {
+ while (head)
+ {
+ T* tmp=head->m_pNext;
+ delete head;
+ head=tmp;
+ }
+ }
+
+ // find a named node in any list which has both a Next field and a Name field.
+ template <class T> static inline T * FindNamedNode(T * head, char const *name)
+ {
+ for(;head && stricmp(head->m_Name,name); head=head->m_pNext)
+ {
+ }
+ return head;
+ }
+
+ template <class T> static inline T * FindNamedNodeCaseSensitive(T * head, char const *name)
+ {
+ for(;head && strcmp(head->m_Name,name); head=head->m_pNext)
+ {
+ }
+ return head;
+ }
+
+ // find data in a singly linked list, using equality match on any field
+ // usage: FindNodeByField(listptr,data,&list::fieldname)
+ template <class T, class U, class V> static inline T * FindNodeByField(T * head, U data, U V::*field)
+ {
+ while(head)
+ {
+ if (data==(*head).*field)
+ return head;
+ head=head->m_pNext;
+ }
+ return 0;
+ }
+
+ // find a node and its predecessor, matching on equality of a given field.
+ // usage: FindNodeByFieldWithPrev(listptr,data,&list::fieldname, prevptr)
+ template <class T, class U, class V> static inline T * FindNodeByFieldWithPrev(T * head, U data, U V::*field, T * & prev)
+ {
+ prev=0;
+ for(T *i=head; i; i=i->m_pNext)
+ {
+ if(data==(*i).*field)
+ return i;
+ prev=i;
+ }
+ prev=0;
+ return 0;
+ }
+
+
+ /// sort a list. comparefn should return 0 if the items are equal, 1 if A goes first, and -1 if A goes last.
+ // NOT fast.
+ template<class T> void SortList(T * &head, int (*comparefn)(T * a, T * b))
+ {
+ int didswap=1;
+ while(didswap)
+ {
+ didswap=0;
+ T *prev=0;
+ for(T *i=head;i && i->m_pNext; i=i->m_pNext)
+ {
+ /// compare i and i+1
+ int rslt=(*comparefn)(i,i->m_pNext);
+ if (rslt==-1)
+ {
+ /// need to swap
+ didswap=1;
+ T *newfirst=i->m_pNext;
+ if (prev)
+ {
+ prev->m_pNext=newfirst;
+ i->m_pNext=newfirst->m_pNext;
+ newfirst->m_pNext=i;
+ }
+ else
+ {
+ head=i->m_pNext;
+ i->m_pNext=newfirst->m_pNext;
+ newfirst->m_pNext=i;
+ }
+ i=newfirst;
+ }
+ prev=i;
+ }
+ }
+ }
+
+ // sort a doubly linked list. NOt fast.
+ template <class T> void SortDList(T * & head, int (*comparefn)(T * a, T * b))
+ {
+ SortList(head,comparefn);
+ /// now, regen prev ptrs
+ T *prev=0;
+ for(T *i=head;i;i=i->m_pNext)
+ {
+ i->m_pPrev=prev;
+ prev=i;
+ }
+ }
+
+ // reverse a singly linked list. not recommended for anything other than valve programming
+ // interview :-)
+ template <class T> T *ReversedList( T * head )
+ {
+ T * pNewHead=NULL;
+ while( head )
+ {
+ T *pNext=head->m_pNext;
+#ifdef INTERVIEW_QUESTION
+ head->m_pNext=pNewHead;
+ pNewHead = head;
+#else
+ AddToHead( pNewHead, head );
+#endif
+ head = pNext;
+ }
+ return pNewHead;
+ }
+};
+
+// singly linked list
+template<class T> class CUtlIntrusiveList
+{
+public:
+ T *m_pHead;
+
+ FORCEINLINE T *Head( void ) const
+ {
+ return m_pHead;
+ }
+
+ FORCEINLINE CUtlIntrusiveList(void)
+ {
+ m_pHead = NULL;
+ }
+
+
+ FORCEINLINE void RemoveAll( void )
+ {
+ // empty list. doesn't touch nodes at all
+ m_pHead = NULL;
+ }
+ FORCEINLINE void AddToHead( T * node )
+ {
+ IntrusiveList::AddToHead( m_pHead, node );
+ }
+
+ FORCEINLINE void AddToTail( T * node )
+ {
+ IntrusiveList::AddToTail( m_pHead, node );
+ }
+
+ void RemoveNode(T *which)
+ {
+ IntrusiveList::RemoveFromList( m_pHead, which );
+ }
+
+ // this will kill a list if the list is of objects which automatically
+ // remove themselves from the list when delete is called
+ void KillList( void )
+ {
+ while(m_pHead)
+ {
+ delete m_pHead;
+ }
+ }
+
+
+ // return the node in head before in a singly linked list. returns null if head is empty, n is
+ // null, or if n is the first node. not fast. Fast for dlists
+ T * PrevNode(T *node)
+ {
+ return IntrusiveList::PrevNode( m_pHead, node );
+ }
+
+ int NthNode( int n )
+ {
+ return NthNode( m_pHead, n );
+ }
+
+ // this will kill all elements in a list if
+ // the elements are of a type which does NOT remove itself from
+ // the list when the destructor is called.
+ void Purge( void )
+ {
+ while (m_pHead)
+ {
+ T* tmp=m_pHead->m_pNext;
+ delete m_pHead;
+ m_pHead=tmp;
+ }
+ }
+
+ int Count( void ) const
+ {
+ return IntrusiveList::ListLength( m_pHead );
+ }
+
+ FORCEINLINE T * FindNamedNodeCaseSensitive( char const *pName ) const
+ {
+ return IntrusiveList::FindNamedNodeCaseSensitive( m_pHead, pName );
+
+ }
+
+ T *RemoveHead( void )
+ {
+ if ( m_pHead )
+ {
+ T *pRet = m_pHead;
+ m_pHead = pRet->m_pNext;
+ return pRet;
+ }
+ else
+ return NULL;
+ }
+};
+
+// doubly linked list
+template<class T> class CUtlIntrusiveDList : public CUtlIntrusiveList<T>
+{
+public:
+
+ FORCEINLINE void AddToHead( T * node )
+ {
+ IntrusiveList::AddToDHead( CUtlIntrusiveList<T>::m_pHead, node );
+ }
+ FORCEINLINE void AddToTail( T * node )
+ {
+ IntrusiveList::AddToDTail( CUtlIntrusiveList<T>::m_pHead, node );
+ }
+
+ void RemoveNode(T *which)
+ {
+ IntrusiveList::RemoveFromDList( CUtlIntrusiveList<T>::m_pHead, which );
+ }
+
+ T *RemoveHead( void )
+ {
+ if ( CUtlIntrusiveList<T>::m_pHead )
+ {
+ T *pRet = CUtlIntrusiveList<T>::m_pHead;
+ CUtlIntrusiveList<T>::m_pHead = CUtlIntrusiveList<T>::m_pHead->m_pNext;
+ if ( CUtlIntrusiveList<T>::m_pHead )
+ CUtlIntrusiveList<T>::m_pHead->m_pPrev = NULL;
+ return pRet;
+ }
+ else
+ return NULL;
+ }
+
+ T * PrevNode(T *node)
+ {
+ return ( node )?node->m_Prev:NULL;
+ }
+
+};
+
+template<class T> class CUtlIntrusiveDListWithTailPtr : public CUtlIntrusiveDList<T>
+{
+public:
+
+ T *m_pTailPtr;
+
+ FORCEINLINE CUtlIntrusiveDListWithTailPtr( void ) : CUtlIntrusiveDList<T>()
+ {
+ m_pTailPtr = NULL;
+ }
+
+ FORCEINLINE void AddToHead( T * node )
+ {
+ IntrusiveList::AddToDHeadWithTailPtr( CUtlIntrusiveList<T>::m_pHead, node, m_pTailPtr );
+ }
+ FORCEINLINE void AddToTail( T * node )
+ {
+ IntrusiveList::AddToDTailWithTailPtr( CUtlIntrusiveList<T>::m_pHead, node, m_pTailPtr );
+ }
+
+ void RemoveNode( T *pWhich )
+ {
+ IntrusiveList::RemoveFromDListWithTailPtr( CUtlIntrusiveList<T>::m_pHead, pWhich, m_pTailPtr );
+ }
+
+ void Purge( void )
+ {
+ CUtlIntrusiveList<T>::Purge();
+ m_pTailPtr = NULL;
+ }
+
+ void Kill( void )
+ {
+ CUtlIntrusiveList<T>::Purge();
+ m_pTailPtr = NULL;
+ }
+
+ T *RemoveHead( void )
+ {
+ if ( CUtlIntrusiveDList<T>::m_pHead )
+ {
+ T *pRet = CUtlIntrusiveDList<T>::m_pHead;
+ CUtlIntrusiveDList<T>::m_pHead = CUtlIntrusiveDList<T>::m_pHead->m_pNext;
+ if ( CUtlIntrusiveDList<T>::m_pHead )
+ CUtlIntrusiveDList<T>::m_pHead->m_pPrev = NULL;
+ if (! CUtlIntrusiveDList<T>::m_pHead )
+ m_pTailPtr = NULL;
+ ValidateDList( CUtlIntrusiveDList<T>::m_pHead );
+ return pRet;
+ }
+ else
+ return NULL;
+ }
+
+ T * PrevNode(T *node)
+ {
+ return ( node )?node->m_Prev:NULL;
+ }
+
+};
+
+template<class T> void PrependDListWithTailToDList( CUtlIntrusiveDListWithTailPtr<T> &src,
+ CUtlIntrusiveDList<T> &dest )
+{
+ if ( src.m_pHead )
+ {
+ src.m_pTailPtr->m_pNext = dest.m_pHead;
+ if ( dest.m_pHead )
+ dest.m_pHead->m_pPrev = src.m_pTailPtr;
+ dest.m_pHead = src.m_pHead;
+ IntrusiveList::ValidateDList( dest.m_pHead );
+ }
+}
+
+#endif
diff --git a/public/tier1/utllinkedlist.h b/public/tier1/utllinkedlist.h
new file mode 100644
index 0000000..37ecef6
--- /dev/null
+++ b/public/tier1/utllinkedlist.h
@@ -0,0 +1,1293 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Linked list container class
+//
+// $Revision: $
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef UTLLINKEDLIST_H
+#define UTLLINKEDLIST_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/basetypes.h"
+#include "utlmemory.h"
+#include "utlfixedmemory.h"
+#include "utlblockmemory.h"
+#include "tier0/dbg.h"
+
+// define to enable asserts griping about things you shouldn't be doing with multilists
+// #define MULTILIST_PEDANTIC_ASSERTS 1
+
+// This is a useful macro to iterate from head to tail in a linked list.
+#define FOR_EACH_LL( listName, iteratorName ) \
+ for( int iteratorName=(listName).Head(); (listName).IsUtlLinkedList && iteratorName != (listName).InvalidIndex(); iteratorName = (listName).Next( iteratorName ) )
+
+//-----------------------------------------------------------------------------
+// class CUtlLinkedList:
+// description:
+// A lovely index-based linked list! T is the class type, I is the index
+// type, which usually should be an unsigned short or smaller. However,
+// you must avoid using 16- or 8-bit arithmetic on PowerPC architectures;
+// therefore you should not use UtlLinkedListElem_t::I as the type of
+// a local variable... ever. PowerPC integer arithmetic must be 32- or
+// 64-bit only; otherwise performance plummets.
+//-----------------------------------------------------------------------------
+
+template <class T, class I>
+struct UtlLinkedListElem_t
+{
+ T m_Element;
+ I m_Previous;
+ I m_Next;
+
+private:
+ // No copy constructor for these...
+ UtlLinkedListElem_t( const UtlLinkedListElem_t& );
+};
+
+
+// Class S is the storage type; the type you can use to save off indices in
+// persistent memory. Class I is the iterator type, which is what should be used
+// in local scopes. I defaults to be S, but be aware that on the 360, 16-bit
+// arithmetic is catastrophically slow. Therefore you should try to save shorts
+// in memory, but always operate on 32's or 64's in local scope.
+// The ideal parameter order would be TSMI (you are more likely to override M than I)
+// but since M depends on I we can't have the defaults in that order, alas.
+template <class T, class S = unsigned short, bool ML = false, class I = S, class M = CUtlMemory< UtlLinkedListElem_t<T, S>, I > >
+class CUtlLinkedList
+{
+public:
+ typedef T ElemType_t;
+ 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
+
+ // constructor, destructor
+ CUtlLinkedList( int growSize = 0, int initSize = 0 );
+ ~CUtlLinkedList();
+
+ // gets particular elements
+ T& Element( I i );
+ T const& Element( I i ) const;
+ T& operator[]( I i );
+ T const& operator[]( I i ) const;
+
+ // Make sure we have a particular amount of memory
+ void EnsureCapacity( int num );
+
+ void SetGrowSize( int growSize );
+
+ // Memory deallocation
+ void Purge();
+
+ // Delete all the elements then call Purge.
+ void PurgeAndDeleteElements();
+
+ // Insertion methods....
+ I InsertBefore( I before );
+ I InsertAfter( I after );
+ I AddToHead( );
+ I AddToTail( );
+
+ I InsertBefore( I before, T const& src );
+ I InsertAfter( I after, T const& src );
+ I AddToHead( T const& src );
+ I AddToTail( T const& src );
+
+ // Find an element and return its index or InvalidIndex() if it couldn't be found.
+ I Find( const T &src ) const;
+
+ // Look for the element. If it exists, remove it and return true. Otherwise, return false.
+ bool FindAndRemove( const T &src );
+
+ // Removal methods
+ void Remove( I elem );
+ void RemoveAll();
+
+ // Allocation/deallocation methods
+ // If multilist == true, then list list may contain many
+ // non-connected lists, and IsInList and Head + Tail are meaningless...
+ I Alloc( bool multilist = false );
+ void Free( I elem );
+
+ // list modification
+ void LinkBefore( I before, I elem );
+ void LinkAfter( I after, I elem );
+ void Unlink( I elem );
+ void LinkToHead( I elem );
+ void LinkToTail( I elem );
+
+ // invalid index (M will never allocate an element at this index)
+ inline static S InvalidIndex() { return ( S )M::InvalidIndex(); }
+
+ // Is a given index valid to use? (representible by S and not the invalid index)
+ static bool IndexInRange( I index );
+
+ inline static size_t ElementSize() { return sizeof( ListElem_t ); }
+
+ // list statistics
+ int Count() const;
+ inline bool IsEmpty( void ) const
+ {
+ return ( Head() == InvalidIndex() );
+ }
+
+ I MaxElementIndex() const;
+ I NumAllocated( void ) const { return m_NumAlloced; }
+
+ // Traversing the list
+ I Head() const;
+ I Tail() const;
+ I Previous( I i ) const;
+ I Next( I i ) const;
+
+ // STL compatible const_iterator class
+ template < typename List_t >
+ class _CUtlLinkedList_constiterator_t
+ {
+ public:
+ typedef typename List_t::ElemType_t ElemType_t;
+ typedef typename List_t::IndexType_t IndexType_t;
+
+ // Default constructor -- gives a currently unusable iterator.
+ _CUtlLinkedList_constiterator_t()
+ : m_list( 0 )
+ , m_index( List_t::InvalidIndex() )
+ {
+ }
+ // Normal constructor.
+ _CUtlLinkedList_constiterator_t( const List_t& list, IndexType_t index )
+ : m_list( &list )
+ , m_index( index )
+ {
+ }
+
+ // Pre-increment operator++. This is the most efficient increment
+ // operator so it should always be used.
+ _CUtlLinkedList_constiterator_t& operator++()
+ {
+ m_index = m_list->Next( m_index );
+ return *this;
+ }
+ // Post-increment operator++. This is less efficient than pre-increment.
+ _CUtlLinkedList_constiterator_t operator++(int)
+ {
+ // Copy ourselves.
+ _CUtlLinkedList_constiterator_t temp = *this;
+ // Increment ourselves.
+ ++*this;
+ // Return the copy.
+ return temp;
+ }
+
+ // Pre-decrement operator--. This is the most efficient decrement
+ // operator so it should always be used.
+ _CUtlLinkedList_constiterator_t& operator--()
+ {
+ Assert( m_index != m_list->Head() );
+ if ( m_index == m_list->InvalidIndex() )
+ {
+ m_index = m_list->Tail();
+ }
+ else
+ {
+ m_index = m_list->Previous( m_index );
+ }
+ return *this;
+ }
+ // Post-decrement operator--. This is less efficient than post-decrement.
+ _CUtlLinkedList_constiterator_t operator--(int)
+ {
+ // Copy ourselves.
+ _CUtlLinkedList_constiterator_t temp = *this;
+ // Decrement ourselves.
+ --*this;
+ // Return the copy.
+ return temp;
+ }
+
+ bool operator==( const _CUtlLinkedList_constiterator_t& other) const
+ {
+ Assert( m_list == other.m_list );
+ return m_index == other.m_index;
+ }
+
+ bool operator!=( const _CUtlLinkedList_constiterator_t& other) const
+ {
+ Assert( m_list == other.m_list );
+ return m_index != other.m_index;
+ }
+
+ const ElemType_t& operator*() const
+ {
+ return m_list->Element( m_index );
+ }
+
+ const ElemType_t* operator->() const
+ {
+ return (&**this);
+ }
+
+ protected:
+ // Use a pointer rather than a reference so that we can support
+ // assignment of iterators.
+ const List_t* m_list;
+ IndexType_t m_index;
+ };
+
+ // STL compatible iterator class, using derivation so that a non-const
+ // list can return a const_iterator.
+ template < typename List_t >
+ class _CUtlLinkedList_iterator_t : public _CUtlLinkedList_constiterator_t< List_t >
+ {
+ public:
+ typedef typename List_t::ElemType_t ElemType_t;
+ typedef typename List_t::IndexType_t IndexType_t;
+ typedef _CUtlLinkedList_constiterator_t< List_t > Base;
+
+ // Default constructor -- gives a currently unusable iterator.
+ _CUtlLinkedList_iterator_t()
+ {
+ }
+ // Normal constructor.
+ _CUtlLinkedList_iterator_t( const List_t& list, IndexType_t index )
+ : _CUtlLinkedList_constiterator_t< List_t >( list, index )
+ {
+ }
+
+ // Pre-increment operator++. This is the most efficient increment
+ // operator so it should always be used.
+ _CUtlLinkedList_iterator_t& operator++()
+ {
+ Base::m_index = Base::m_list->Next( Base::m_index );
+ return *this;
+ }
+ // Post-increment operator++. This is less efficient than pre-increment.
+ _CUtlLinkedList_iterator_t operator++(int)
+ {
+ // Copy ourselves.
+ _CUtlLinkedList_iterator_t temp = *this;
+ // Increment ourselves.
+ ++*this;
+ // Return the copy.
+ return temp;
+ }
+
+ // Pre-decrement operator--. This is the most efficient decrement
+ // operator so it should always be used.
+ _CUtlLinkedList_iterator_t& operator--()
+ {
+ Assert( Base::m_index != Base::m_list->Head() );
+ if ( Base::m_index == Base::m_list->InvalidIndex() )
+ {
+ Base::m_index = Base::m_list->Tail();
+ }
+ else
+ {
+ Base::m_index = Base::m_list->Previous( Base::m_index );
+ }
+ return *this;
+ }
+ // Post-decrement operator--. This is less efficient than post-decrement.
+ _CUtlLinkedList_iterator_t operator--(int)
+ {
+ // Copy ourselves.
+ _CUtlLinkedList_iterator_t temp = *this;
+ // Decrement ourselves.
+ --*this;
+ // Return the copy.
+ return temp;
+ }
+
+ ElemType_t& operator*() const
+ {
+ // Const_cast to allow sharing the implementation with the
+ // base class.
+ List_t* pMutableList = const_cast<List_t*>( Base::m_list );
+ return pMutableList->Element( Base::m_index );
+ }
+
+ ElemType_t* operator->() const
+ {
+ return (&**this);
+ }
+ };
+
+ typedef _CUtlLinkedList_constiterator_t<CUtlLinkedList<T, S, ML, I, M> > const_iterator;
+ typedef _CUtlLinkedList_iterator_t<CUtlLinkedList<T, S, ML, I, M> > iterator;
+ const_iterator begin() const
+ {
+ return const_iterator( *this, Head() );
+ }
+ iterator begin()
+ {
+ return iterator( *this, Head() );
+ }
+
+ const_iterator end() const
+ {
+ return const_iterator( *this, InvalidIndex() );
+ }
+ iterator end()
+ {
+ return iterator( *this, InvalidIndex() );
+ }
+
+ // Are nodes in the list or valid?
+ bool IsValidIndex( I i ) const;
+ bool IsInList( I i ) const;
+
+protected:
+
+ // What the linked list element looks like
+ typedef UtlLinkedListElem_t<T, S> ListElem_t;
+
+ // constructs the class
+ I AllocInternal( bool multilist = false );
+ 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;
+ I m_FirstFree;
+ I m_ElementCount; // The number actually in the list
+ I m_NumAlloced; // The number of allocated elements
+ typename M::Iterator_t m_LastAlloc; // the last index allocated
+
+ // For debugging purposes;
+ // it's in release builds so this can be used in libraries correctly
+ ListElem_t *m_pElements;
+
+ FORCEINLINE M const &Memory( void ) const
+ {
+ return m_Memory;
+ }
+
+ void ResetDbgInfo()
+ {
+ 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
+template < class T >
+class CUtlFixedLinkedList : public CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > >
+{
+public:
+ CUtlFixedLinkedList( int growSize = 0, int initSize = 0 )
+ : CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > >( growSize, initSize ) {}
+
+ typedef CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > > BaseClass;
+ bool IsValidIndex( int i ) const
+ {
+ if ( !BaseClass::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 ) )
+ {
+ 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 );
+ }
+
+private:
+ int MaxElementIndex() const { Assert( 0 ); return BaseClass::InvalidIndex(); } // fixedmemory containers don't support iteration from 0..maxelements-1
+ void ResetDbgInfo() {}
+};
+
+// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice
+template < class T, class I = unsigned short >
+class CUtlBlockLinkedList : public CUtlLinkedList< T, I, true, I, CUtlBlockMemory< UtlLinkedListElem_t< T, I >, I > >
+{
+public:
+ CUtlBlockLinkedList( int growSize = 0, int initSize = 0 )
+ : CUtlLinkedList< T, I, true, I, CUtlBlockMemory< UtlLinkedListElem_t< T, I >, I > >( growSize, initSize ) {}
+protected:
+ void ResetDbgInfo() {}
+};
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+
+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() )
+{
+ // Prevent signed non-int datatypes
+ COMPILE_TIME_ASSERT( sizeof(S) == 4 || ( ( (S)-1 ) > 0 ) );
+ ConstructList();
+ ResetDbgInfo();
+}
+
+template <class T, class S, bool ML, class I, class M>
+CUtlLinkedList<T,S,ML,I,M>::~CUtlLinkedList( )
+{
+ RemoveAll();
+}
+
+template <class T, class S, bool ML, class I, class M>
+void CUtlLinkedList<T,S,ML,I,M>::ConstructList()
+{
+ m_Head = InvalidIndex();
+ m_Tail = InvalidIndex();
+ m_FirstFree = InvalidIndex();
+ m_ElementCount = 0;
+ m_NumAlloced = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// gets particular elements
+//-----------------------------------------------------------------------------
+
+template <class T, class S, bool ML, class I, class M>
+inline T& CUtlLinkedList<T,S,ML,I,M>::Element( I i )
+{
+ return m_Memory[i].m_Element;
+}
+
+template <class T, class S, bool ML, class I, class M>
+inline T const& CUtlLinkedList<T,S,ML,I,M>::Element( I i ) const
+{
+ return m_Memory[i].m_Element;
+}
+
+template <class T, class S, bool ML, class I, class M>
+inline T& CUtlLinkedList<T,S,ML,I,M>::operator[]( I i )
+{
+ return m_Memory[i].m_Element;
+}
+
+template <class T, class S, bool ML, class I, class M>
+inline T const& CUtlLinkedList<T,S,ML,I,M>::operator[]( I i ) const
+{
+ return m_Memory[i].m_Element;
+}
+
+//-----------------------------------------------------------------------------
+// list statistics
+//-----------------------------------------------------------------------------
+
+template <class T, class S, bool ML, class I, class M>
+inline int CUtlLinkedList<T,S,ML,I,M>::Count() const
+{
+#ifdef MULTILIST_PEDANTIC_ASSERTS
+ AssertMsg( !ML, "CUtlLinkedList::Count() is meaningless for linked lists." );
+#endif
+ return m_ElementCount;
+}
+
+template <class T, class S, bool ML, class I, class M>
+inline I CUtlLinkedList<T,S,ML,I,M>::MaxElementIndex() const
+{
+ return m_Memory.NumAllocated();
+}
+
+
+//-----------------------------------------------------------------------------
+// Traversing the list
+//-----------------------------------------------------------------------------
+
+template <class T, class S, bool ML, class I, class M>
+inline I CUtlLinkedList<T,S,ML,I,M>::Head() const
+{
+ return m_Head;
+}
+
+template <class T, class S, bool ML, class I, class M>
+inline I CUtlLinkedList<T,S,ML,I,M>::Tail() const
+{
+ return m_Tail;
+}
+
+template <class T, class S, bool ML, class I, class M>
+inline I CUtlLinkedList<T,S,ML,I,M>::Previous( I i ) const
+{
+ Assert( IsValidIndex(i) );
+ return InternalElement(i).m_Previous;
+}
+
+template <class T, class S, bool ML, class I, class M>
+inline I CUtlLinkedList<T,S,ML,I,M>::Next( I i ) const
+{
+ Assert( IsValidIndex(i) );
+ 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?
+//-----------------------------------------------------------------------------
+
+#pragma warning(push)
+#pragma warning( disable: 4310 ) // Allows "(I)(S)M::INVALID_INDEX" below
+template <class T, class S, bool ML, class I, class M>
+inline bool CUtlLinkedList<T,S,ML,I,M>::IndexInRange( I index ) // Static method
+{
+ // Since S is not necessarily the type returned by M, we need to check that M returns indices
+ // which are representable by S. A common case is 'S === unsigned short', 'I == int', in which
+ // case CUtlMemory will have 'InvalidIndex == (int)-1' (which casts to 65535 in S), and will
+ // happily return elements at index 65535 and above.
+
+ // Do some static checks here:
+ // 'I' needs to be able to store 'S'
+ 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 ) );
+ // 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 ) );
+
+ return ( ( (S)index == index ) && ( (S)index != InvalidIndex() ) );
+}
+#pragma warning(pop)
+
+template <class T, class S, bool ML, class I, class M>
+inline bool CUtlLinkedList<T,S,ML,I,M>::IsValidIndex( I i ) const
+{
+ if ( !m_Memory.IsIdxValid( i ) )
+ return false;
+
+ if ( m_Memory.IsIdxAfter( i, m_LastAlloc ) )
+ return false; // don't read values that have been allocated, but not constructed
+
+ return ( m_Memory[ i ].m_Previous != i ) || ( m_Memory[ i ].m_Next == i );
+}
+
+template <class T, class S, bool ML, class I, class M>
+inline bool CUtlLinkedList<T,S,ML,I,M>::IsInList( I i ) const
+{
+ if ( !m_Memory.IsIdxValid( i ) || m_Memory.IsIdxAfter( i, m_LastAlloc ) )
+ return false; // don't read values that have been allocated, but not constructed
+
+ return Previous( i ) != i;
+}
+
+/*
+template <class T>
+inline bool CUtlFixedLinkedList<T>::IsInList( int i ) const
+{
+ return m_Memory.IsIdxValid( i ) && (Previous( i ) != i);
+}
+*/
+
+//-----------------------------------------------------------------------------
+// Makes sure we have enough memory allocated to store a requested # of elements
+//-----------------------------------------------------------------------------
+
+template< class T, class S, bool ML, class I, class M >
+void CUtlLinkedList<T,S,ML,I,M>::EnsureCapacity( int num )
+{
+ MEM_ALLOC_CREDIT_CLASS();
+ m_Memory.EnsureCapacity(num);
+ ResetDbgInfo();
+}
+
+template< class T, class S, bool ML, class I, class M >
+void CUtlLinkedList<T,S,ML,I,M>::SetGrowSize( int growSize )
+{
+ RemoveAll();
+ m_Memory.Init( growSize );
+ ResetDbgInfo();
+}
+
+
+//-----------------------------------------------------------------------------
+// Deallocate memory
+//-----------------------------------------------------------------------------
+
+template <class T, class S, bool ML, class I, class M>
+void CUtlLinkedList<T,S,ML,I,M>::Purge()
+{
+ RemoveAll();
+
+ m_Memory.Purge();
+ m_FirstFree = InvalidIndex();
+ m_NumAlloced = 0;
+
+ //Routing "m_LastAlloc = m_Memory.InvalidIterator();" through a local const to sidestep an internal compiler error on 360 builds
+ const typename M::Iterator_t scInvalidIterator = m_Memory.InvalidIterator();
+ m_LastAlloc = scInvalidIterator;
+ ResetDbgInfo();
+}
+
+
+template<class T, class S, bool ML, class I, class M>
+void CUtlLinkedList<T,S,ML,I,M>::PurgeAndDeleteElements()
+{
+ I iNext;
+ for( I i=Head(); i != InvalidIndex(); i=iNext )
+ {
+ iNext = Next(i);
+ delete Element(i);
+ }
+
+ Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+// Node allocation/deallocation
+//-----------------------------------------------------------------------------
+template <class T, class S, bool ML, class I, class M>
+I CUtlLinkedList<T,S,ML,I,M>::AllocInternal( bool multilist )
+{
+ Assert( !multilist || ML );
+#ifdef MULTILIST_PEDANTIC_ASSERTS
+ Assert( multilist == ML );
+#endif
+ I elem;
+ if ( m_FirstFree == InvalidIndex() )
+ {
+ Assert( m_Memory.IsValidIterator( m_LastAlloc ) || m_ElementCount == 0 );
+
+ typename M::Iterator_t it = m_Memory.IsValidIterator( m_LastAlloc ) ? m_Memory.Next( m_LastAlloc ) : m_Memory.First();
+
+ if ( !m_Memory.IsValidIterator( it ) )
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ m_Memory.Grow();
+ ResetDbgInfo();
+
+ it = m_Memory.IsValidIterator( m_LastAlloc ) ? m_Memory.Next( m_LastAlloc ) : m_Memory.First();
+
+ Assert( m_Memory.IsValidIterator( it ) );
+ if ( !m_Memory.IsValidIterator( it ) )
+ {
+ // We rarely if ever handle alloc failure. Continuing leads to corruption.
+ Error( "CUtlLinkedList overflow! (exhausted memory allocator)\n" );
+ return InvalidIndex();
+ }
+ }
+
+ // We can overflow before the utlmemory overflows, since S != I
+ if ( !IndexInRange( m_Memory.GetIndex( it ) ) )
+ {
+ // We rarely if ever handle alloc failure. Continuing leads to corruption.
+ Error( "CUtlLinkedList overflow! (exhausted index range)\n" );
+ return InvalidIndex();
+ }
+
+ m_LastAlloc = it;
+ elem = m_Memory.GetIndex( m_LastAlloc );
+ m_NumAlloced++;
+ }
+ else
+ {
+ elem = m_FirstFree;
+ m_FirstFree = InternalElement( m_FirstFree ).m_Next;
+ }
+
+ if ( !multilist )
+ {
+ InternalElement( elem ).m_Next = elem;
+ InternalElement( elem ).m_Previous = elem;
+ }
+ else
+ {
+ InternalElement( elem ).m_Next = InvalidIndex();
+ InternalElement( elem ).m_Previous = InvalidIndex();
+ }
+
+ return elem;
+}
+
+template <class T, class S, bool ML, class I, class M>
+I CUtlLinkedList<T,S,ML,I,M>::Alloc( bool multilist )
+{
+ I elem = AllocInternal( multilist );
+ if ( elem == InvalidIndex() )
+ return elem;
+
+ Construct( &Element(elem) );
+
+ return elem;
+}
+
+template <class T, class S, bool ML, class I, class M>
+void CUtlLinkedList<T,S,ML,I,M>::Free( I elem )
+{
+ Assert( IsValidIndex(elem) && IndexInRange( elem ) );
+ Unlink(elem);
+
+ ListElem_t &internalElem = InternalElement(elem);
+ Destruct( &internalElem.m_Element );
+ internalElem.m_Next = m_FirstFree;
+ m_FirstFree = elem;
+}
+
+//-----------------------------------------------------------------------------
+// Insertion methods; allocates and links (uses default constructor)
+//-----------------------------------------------------------------------------
+
+template <class T, class S, bool ML, class I, class M>
+I CUtlLinkedList<T,S,ML,I,M>::InsertBefore( I before )
+{
+ // Make a new node
+ I newNode = AllocInternal();
+ if ( newNode == InvalidIndex() )
+ return newNode;
+
+ // Link it in
+ LinkBefore( before, newNode );
+
+ // Construct the data
+ Construct( &Element(newNode) );
+
+ return newNode;
+}
+
+template <class T, class S, bool ML, class I, class M>
+I CUtlLinkedList<T,S,ML,I,M>::InsertAfter( I after )
+{
+ // Make a new node
+ I newNode = AllocInternal();
+ if ( newNode == InvalidIndex() )
+ return newNode;
+
+ // Link it in
+ LinkAfter( after, newNode );
+
+ // Construct the data
+ Construct( &Element(newNode) );
+
+ return newNode;
+}
+
+template <class T, class S, bool ML, class I, class M>
+inline I CUtlLinkedList<T,S,ML,I,M>::AddToHead( )
+{
+ return InsertAfter( InvalidIndex() );
+}
+
+template <class T, class S, bool ML, class I, class M>
+inline I CUtlLinkedList<T,S,ML,I,M>::AddToTail( )
+{
+ return InsertBefore( InvalidIndex() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Insertion methods; allocates and links (uses copy constructor)
+//-----------------------------------------------------------------------------
+
+template <class T, class S, bool ML, class I, class M>
+I CUtlLinkedList<T,S,ML,I,M>::InsertBefore( I before, T const& src )
+{
+ // Make a new node
+ I newNode = AllocInternal();
+ if ( newNode == InvalidIndex() )
+ return newNode;
+
+ // Link it in
+ LinkBefore( before, newNode );
+
+ // Construct the data
+ CopyConstruct( &Element(newNode), src );
+
+ return newNode;
+}
+
+template <class T, class S, bool ML, class I, class M>
+I CUtlLinkedList<T,S,ML,I,M>::InsertAfter( I after, T const& src )
+{
+ // Make a new node
+ I newNode = AllocInternal();
+ if ( newNode == InvalidIndex() )
+ return newNode;
+
+ // Link it in
+ LinkAfter( after, newNode );
+
+ // Construct the data
+ CopyConstruct( &Element(newNode), src );
+
+ return newNode;
+}
+
+template <class T, class S, bool ML, class I, class M>
+inline I CUtlLinkedList<T,S,ML,I,M>::AddToHead( T const& src )
+{
+ return InsertAfter( InvalidIndex(), src );
+}
+
+template <class T, class S, bool ML, class I, class M>
+inline I CUtlLinkedList<T,S,ML,I,M>::AddToTail( T const& src )
+{
+ return InsertBefore( InvalidIndex(), src );
+}
+
+
+//-----------------------------------------------------------------------------
+// Removal methods
+//-----------------------------------------------------------------------------
+
+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 ) )
+ {
+ if ( Element( i ) == src )
+ return i;
+ }
+ return InvalidIndex();
+}
+
+
+template<class T, class S, bool ML, class I, class M>
+bool CUtlLinkedList<T,S,ML,I,M>::FindAndRemove( const T &src )
+{
+ I i = Find( src );
+ if ( i == InvalidIndex() )
+ {
+ return false;
+ }
+ else
+ {
+ Remove( i );
+ return true;
+ }
+}
+
+
+template <class T, class S, bool ML, class I, class M>
+void CUtlLinkedList<T,S,ML,I,M>::Remove( I elem )
+{
+ Free( elem );
+}
+
+template <class T, class S, bool ML, class I, class M>
+void CUtlLinkedList<T,S,ML,I,M>::RemoveAll()
+{
+ // Have to do some convoluted stuff to invoke the destructor on all
+ // valid elements for the multilist case (since we don't have all elements
+ // connected to each other in a list).
+
+ if ( m_LastAlloc == m_Memory.InvalidIterator() )
+ {
+ Assert( m_Head == InvalidIndex() );
+ Assert( m_Tail == InvalidIndex() );
+ Assert( m_FirstFree == InvalidIndex() );
+ Assert( m_ElementCount == 0 );
+ return;
+ }
+
+ if ( ML )
+ {
+ for ( typename M::Iterator_t it = m_Memory.First(); it != m_Memory.InvalidIterator(); it = m_Memory.Next( it ) )
+ {
+ I i = m_Memory.GetIndex( it );
+ if ( IsValidIndex( i ) ) // skip elements already in the free list
+ {
+ ListElem_t &internalElem = InternalElement( i );
+ Destruct( &internalElem.m_Element );
+ internalElem.m_Previous = i;
+ internalElem.m_Next = m_FirstFree;
+ m_FirstFree = i;
+ }
+
+ if ( it == m_LastAlloc )
+ break; // don't destruct elements that haven't ever been constructed
+ }
+ }
+ else
+ {
+ I i = Head();
+ I next;
+ while ( i != InvalidIndex() )
+ {
+ next = Next( i );
+ ListElem_t &internalElem = InternalElement( i );
+ Destruct( &internalElem.m_Element );
+ internalElem.m_Previous = i;
+ internalElem.m_Next = next == InvalidIndex() ? m_FirstFree : next;
+ i = next;
+ }
+ if ( Head() != InvalidIndex() )
+ {
+ m_FirstFree = Head();
+ }
+ }
+
+ // Clear everything else out
+ m_Head = InvalidIndex();
+ m_Tail = InvalidIndex();
+ m_ElementCount = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// list modification
+//-----------------------------------------------------------------------------
+
+template <class T, class S, bool ML, class I, class M>
+void CUtlLinkedList<T,S,ML,I,M>::LinkBefore( I before, I elem )
+{
+ Assert( IsValidIndex(elem) );
+
+ // Unlink it if it's in the list at the moment
+ Unlink(elem);
+
+ ListElem_t * RESTRICT pNewElem = &InternalElement(elem);
+
+ // The element *after* our newly linked one is the one we linked before.
+ pNewElem->m_Next = before;
+
+ S newElem_mPrevious; // we need to hang on to this for the compairson against InvalidIndex()
+ // below; otherwise we get a a load-hit-store on pNewElem->m_Previous, even
+ // with RESTRICT
+ if (before == InvalidIndex())
+ {
+ // In this case, we're linking to the end of the list, so reset the tail
+ newElem_mPrevious = m_Tail;
+ pNewElem->m_Previous = m_Tail;
+ m_Tail = elem;
+ }
+ else
+ {
+ // Here, we're not linking to the end. Set the prev pointer to point to
+ // the element we're linking.
+ Assert( IsInList(before) );
+ ListElem_t * RESTRICT beforeElem = &InternalElement(before);
+ pNewElem->m_Previous = newElem_mPrevious = beforeElem->m_Previous;
+ beforeElem->m_Previous = elem;
+ }
+
+ // Reset the head if we linked to the head of the list
+ if (newElem_mPrevious == InvalidIndex())
+ m_Head = elem;
+ else
+ InternalElement(newElem_mPrevious).m_Next = elem;
+
+ // one more element baby
+ ++m_ElementCount;
+}
+
+template <class T, class S, bool ML, class I, class M>
+void CUtlLinkedList<T,S,ML,I,M>::LinkAfter( I after, I elem )
+{
+ Assert( IsValidIndex(elem) );
+
+ // Unlink it if it's in the list at the moment
+ if ( IsInList(elem) )
+ Unlink(elem);
+
+ ListElem_t& newElem = InternalElement(elem);
+
+ // The element *before* our newly linked one is the one we linked after
+ newElem.m_Previous = after;
+ if (after == InvalidIndex())
+ {
+ // In this case, we're linking to the head of the list, reset the head
+ newElem.m_Next = m_Head;
+ m_Head = elem;
+ }
+ else
+ {
+ // Here, we're not linking to the end. Set the next pointer to point to
+ // the element we're linking.
+ Assert( IsInList(after) );
+ ListElem_t& afterElem = InternalElement(after);
+ newElem.m_Next = afterElem.m_Next;
+ afterElem.m_Next = elem;
+ }
+
+ // Reset the tail if we linked to the tail of the list
+ if (newElem.m_Next == InvalidIndex())
+ m_Tail = elem;
+ else
+ InternalElement(newElem.m_Next).m_Previous = elem;
+
+ // one more element baby
+ ++m_ElementCount;
+}
+
+template <class T, class S, bool ML, class I, class M>
+void CUtlLinkedList<T,S,ML,I,M>::Unlink( I elem )
+{
+ Assert( IsValidIndex(elem) );
+ if (IsInList(elem))
+ {
+ ListElem_t * RESTRICT pOldElem = &m_Memory[ elem ];
+
+ // If we're the first guy, reset the head
+ // otherwise, make our previous node's next pointer = our next
+ if ( pOldElem->m_Previous != InvalidIndex() )
+ {
+ m_Memory[ pOldElem->m_Previous ].m_Next = pOldElem->m_Next;
+ }
+ else
+ {
+ m_Head = pOldElem->m_Next;
+ }
+
+ // If we're the last guy, reset the tail
+ // otherwise, make our next node's prev pointer = our prev
+ if ( pOldElem->m_Next != InvalidIndex() )
+ {
+ m_Memory[ pOldElem->m_Next ].m_Previous = pOldElem->m_Previous;
+ }
+ else
+ {
+ m_Tail = pOldElem->m_Previous;
+ }
+
+ // This marks this node as not in the list,
+ // but not in the free list either
+ pOldElem->m_Previous = pOldElem->m_Next = elem;
+
+ // One less puppy
+ --m_ElementCount;
+ }
+}
+
+template <class T, class S, bool ML, class I, class M>
+inline void CUtlLinkedList<T,S,ML,I,M>::LinkToHead( I elem )
+{
+ LinkAfter( InvalidIndex(), elem );
+}
+
+template <class T, class S, bool ML, class I, class M>
+inline void CUtlLinkedList<T,S,ML,I,M>::LinkToTail( I elem )
+{
+ LinkBefore( InvalidIndex(), elem );
+}
+
+
+//-----------------------------------------------------------------------------
+// Class to drop in to replace a CUtlLinkedList that needs to be more memory agressive
+//-----------------------------------------------------------------------------
+
+DECLARE_POINTER_HANDLE( UtlPtrLinkedListIndex_t ); // to enforce correct usage
+
+template < typename T >
+class CUtlPtrLinkedList
+{
+public:
+ CUtlPtrLinkedList()
+ : m_pFirst( NULL ),
+ m_nElems( 0 )
+ {
+ COMPILE_TIME_ASSERT( sizeof(IndexType_t) == sizeof(Node_t *) );
+ }
+
+ ~CUtlPtrLinkedList()
+ {
+ RemoveAll();
+ }
+
+ typedef UtlPtrLinkedListIndex_t IndexType_t;
+
+ T &operator[]( IndexType_t i )
+ {
+ return (( Node_t * )i)->elem;
+ }
+
+ const T &operator[]( IndexType_t i ) const
+ {
+ return (( Node_t * )i)->elem;
+ }
+
+ IndexType_t AddToTail()
+ {
+ return DoInsertBefore( (IndexType_t)m_pFirst, NULL );
+ }
+
+ IndexType_t AddToTail( T const& src )
+ {
+ return DoInsertBefore( (IndexType_t)m_pFirst, &src );
+ }
+
+ IndexType_t AddToHead()
+ {
+ IndexType_t result = DoInsertBefore( (IndexType_t)m_pFirst, NULL );
+ m_pFirst = ((Node_t *)result);
+ return result;
+ }
+
+ IndexType_t AddToHead( T const& src )
+ {
+ IndexType_t result = DoInsertBefore( (IndexType_t)m_pFirst, &src );
+ m_pFirst = ((Node_t *)result);
+ return result;
+ }
+
+ IndexType_t InsertBefore( IndexType_t before )
+ {
+ return DoInsertBefore( before, NULL );
+ }
+
+ IndexType_t InsertAfter( IndexType_t after )
+ {
+ Node_t *pBefore = ((Node_t *)after)->next;
+ return DoInsertBefore( pBefore, NULL );
+ }
+
+ IndexType_t InsertBefore( IndexType_t before, T const& src )
+ {
+ return DoInsertBefore( before, &src );
+ }
+
+ IndexType_t InsertAfter( IndexType_t after, T const& src )
+ {
+ Node_t *pBefore = ((Node_t *)after)->next;
+ return DoInsertBefore( pBefore, &src );
+ }
+
+ void Remove( IndexType_t elem )
+ {
+ Node_t *p = (Node_t *)elem;
+
+ if ( p->pNext == p )
+ {
+ m_pFirst = NULL;
+ }
+ else
+ {
+ if ( m_pFirst == p )
+ {
+ m_pFirst = p->pNext;
+ }
+ p->pNext->pPrev = p->pPrev;
+ p->pPrev->pNext = p->pNext;
+ }
+
+ delete p;
+ m_nElems--;
+ }
+
+ void RemoveAll()
+ {
+ Node_t *p = m_pFirst;
+ if ( p )
+ {
+ do
+ {
+ Node_t *pNext = p->pNext;
+ delete p;
+ p = pNext;
+ } while( p != m_pFirst );
+ }
+
+ m_pFirst = NULL;
+ m_nElems = 0;
+ }
+
+ int Count() const
+ {
+ return m_nElems;
+ }
+
+ IndexType_t Head() const
+ {
+ return (IndexType_t)m_pFirst;
+ }
+
+ IndexType_t Next( IndexType_t i ) const
+ {
+ Node_t *p = ((Node_t *)i)->pNext;
+ if ( p != m_pFirst )
+ {
+ return (IndexType_t)p;
+ }
+ return NULL;
+ }
+
+ bool IsValidIndex( IndexType_t i ) const
+ {
+ Node_t *p = ((Node_t *)i);
+ return ( p && p->pNext && p->pPrev );
+ }
+
+ inline static IndexType_t InvalidIndex()
+ {
+ return NULL;
+ }
+private:
+
+ struct Node_t
+ {
+ Node_t() {}
+ Node_t( const T &_elem ) : elem( _elem ) {}
+
+ T elem;
+ Node_t *pPrev, *pNext;
+ };
+
+ Node_t *AllocNode( const T *pCopyFrom )
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ Node_t *p;
+
+ if ( !pCopyFrom )
+ {
+ p = new Node_t;
+ }
+ else
+ {
+ p = new Node_t( *pCopyFrom );
+ }
+
+ return p;
+ }
+
+ IndexType_t DoInsertBefore( IndexType_t before, const T *pCopyFrom )
+ {
+ Node_t *p = AllocNode( pCopyFrom );
+ Node_t *pBefore = (Node_t *)before;
+ if ( pBefore )
+ {
+ p->pNext = pBefore;
+ p->pPrev = pBefore->pPrev;
+ pBefore->pPrev = p;
+ p->pPrev->pNext = p;
+ }
+ else
+ {
+ Assert( !m_pFirst );
+ m_pFirst = p->pNext = p->pPrev = p;
+ }
+
+ m_nElems++;
+ return (IndexType_t)p;
+ }
+
+ Node_t *m_pFirst;
+ unsigned m_nElems;
+};
+
+//-----------------------------------------------------------------------------
+
+#endif // UTLLINKEDLIST_H
diff --git a/public/tier1/utlmap.h b/public/tier1/utlmap.h
new file mode 100644
index 0000000..9c08bc0
--- /dev/null
+++ b/public/tier1/utlmap.h
@@ -0,0 +1,252 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Header: $
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef UTLMAP_H
+#define UTLMAP_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/dbg.h"
+#include "utlrbtree.h"
+
+//-----------------------------------------------------------------------------
+//
+// Purpose: An associative container. Pretty much identical to std::map.
+//
+//-----------------------------------------------------------------------------
+
+// This is a useful macro to iterate from start to end in order in a map
+#define FOR_EACH_MAP( mapName, iteratorName ) \
+ for ( int iteratorName = (mapName).FirstInorder(); (mapName).IsUtlMap && iteratorName != (mapName).InvalidIndex(); iteratorName = (mapName).NextInorder( iteratorName ) )
+
+// faster iteration, but in an unspecified order
+#define FOR_EACH_MAP_FAST( mapName, iteratorName ) \
+ for ( int iteratorName = 0; (mapName).IsUtlMap && iteratorName < (mapName).MaxElement(); ++iteratorName ) if ( !(mapName).IsValidIndex( iteratorName ) ) continue; else
+
+struct base_utlmap_t
+{
+public:
+ // This enum exists so that FOR_EACH_MAP and FOR_EACH_MAP_FAST cannot accidentally
+ // be used on a type that is not a CUtlMap. If the code compiles then all is well.
+ // The check for IsUtlMap being true should be free.
+ // Using an enum rather than a static const bool ensures that this trick works even
+ // with optimizations disabled on gcc.
+ enum CompileTimeCheck
+ {
+ IsUtlMap = 1
+ };
+};
+
+template <typename K, typename T, typename I = unsigned short>
+class CUtlMap : public base_utlmap_t
+{
+public:
+ typedef K KeyType_t;
+ typedef T ElemType_t;
+ typedef I IndexType_t;
+
+ // Less func typedef
+ // Returns true if the first parameter is "less" than the second
+ typedef bool (*LessFunc_t)( const KeyType_t &, const KeyType_t & );
+
+ // constructor, destructor
+ // Left at growSize = 0, the memory will first allocate 1 element and double in size
+ // at each increment.
+ // LessFunc_t is required, but may be set after the constructor using SetLessFunc() below
+ CUtlMap( int growSize = 0, int initSize = 0, LessFunc_t lessfunc = 0 )
+ : m_Tree( growSize, initSize, CKeyLess( lessfunc ) )
+ {
+ }
+
+ CUtlMap( LessFunc_t lessfunc )
+ : m_Tree( CKeyLess( lessfunc ) )
+ {
+ }
+
+ void EnsureCapacity( int num ) { m_Tree.EnsureCapacity( num ); }
+
+ // gets particular elements
+ ElemType_t & Element( IndexType_t i ) { return m_Tree.Element( i ).elem; }
+ const ElemType_t & Element( IndexType_t i ) const { return m_Tree.Element( i ).elem; }
+ ElemType_t & operator[]( IndexType_t i ) { return m_Tree.Element( i ).elem; }
+ const ElemType_t & operator[]( IndexType_t i ) const { return m_Tree.Element( i ).elem; }
+ KeyType_t & Key( IndexType_t i ) { return m_Tree.Element( i ).key; }
+ const KeyType_t & Key( IndexType_t i ) const { return m_Tree.Element( i ).key; }
+
+
+ // Num elements
+ unsigned int Count() const { return m_Tree.Count(); }
+
+ // Max "size" of the vector
+ IndexType_t MaxElement() const { return m_Tree.MaxElement(); }
+
+ // Checks if a node is valid and in the map
+ bool IsValidIndex( IndexType_t i ) const { return m_Tree.IsValidIndex( i ); }
+
+ // Checks if the map as a whole is valid
+ bool IsValid() const { return m_Tree.IsValid(); }
+
+ // Invalid index
+ static IndexType_t InvalidIndex() { return CTree::InvalidIndex(); }
+
+ // Sets the less func
+ void SetLessFunc( LessFunc_t func )
+ {
+ m_Tree.SetLessFunc( CKeyLess( func ) );
+ }
+
+ // Insert method (inserts in order)
+ IndexType_t Insert( const KeyType_t &key, const ElemType_t &insert )
+ {
+ Node_t node;
+ node.key = key;
+ node.elem = insert;
+ return m_Tree.Insert( node );
+ }
+
+ IndexType_t Insert( const KeyType_t &key )
+ {
+ Node_t node;
+ node.key = key;
+ return m_Tree.Insert( node );
+ }
+
+ // Find method
+ IndexType_t Find( const KeyType_t &key ) const
+ {
+ Node_t dummyNode;
+ dummyNode.key = key;
+ return m_Tree.Find( dummyNode );
+ }
+
+ // Remove methods
+ void RemoveAt( IndexType_t i ) { m_Tree.RemoveAt( i ); }
+ bool Remove( const KeyType_t &key )
+ {
+ Node_t dummyNode;
+ dummyNode.key = key;
+ return m_Tree.Remove( dummyNode );
+ }
+
+ void RemoveAll( ) { m_Tree.RemoveAll(); }
+ void Purge( ) { m_Tree.Purge(); }
+
+ // Purges the list and calls delete on each element in it.
+ void PurgeAndDeleteElements();
+
+ // Iteration
+ IndexType_t FirstInorder() const { return m_Tree.FirstInorder(); }
+ IndexType_t NextInorder( IndexType_t i ) const { return m_Tree.NextInorder( i ); }
+ IndexType_t PrevInorder( IndexType_t i ) const { return m_Tree.PrevInorder( i ); }
+ IndexType_t LastInorder() const { return m_Tree.LastInorder(); }
+
+ // If you change the search key, this can be used to reinsert the
+ // element into the map.
+ void Reinsert( const KeyType_t &key, IndexType_t i )
+ {
+ m_Tree[i].key = key;
+ m_Tree.Reinsert(i);
+ }
+
+ IndexType_t InsertOrReplace( const KeyType_t &key, const ElemType_t &insert )
+ {
+ IndexType_t i = Find( key );
+ if ( i != InvalidIndex() )
+ {
+ Element( i ) = insert;
+ return i;
+ }
+
+ return Insert( key, insert );
+ }
+
+ void Swap( CUtlMap< K, T, I > &that )
+ {
+ m_Tree.Swap( that.m_Tree );
+ }
+
+
+ struct Node_t
+ {
+ Node_t()
+ {
+ }
+
+ Node_t( const Node_t &from )
+ : key( from.key ),
+ elem( from.elem )
+ {
+ }
+
+ KeyType_t key;
+ ElemType_t elem;
+ };
+
+ class CKeyLess
+ {
+ public:
+ CKeyLess( LessFunc_t lessFunc ) : m_LessFunc(lessFunc) {}
+
+ bool operator!() const
+ {
+ return !m_LessFunc;
+ }
+
+ bool operator()( const Node_t &left, const Node_t &right ) const
+ {
+ return m_LessFunc( left.key, right.key );
+ }
+
+ LessFunc_t m_LessFunc;
+ };
+
+ typedef CUtlRBTree<Node_t, I, CKeyLess> CTree;
+
+ CTree *AccessTree() { return &m_Tree; }
+
+protected:
+ CTree m_Tree;
+};
+
+//-----------------------------------------------------------------------------
+
+// Purges the list and calls delete on each element in it.
+template< typename K, typename T, typename I >
+inline void CUtlMap<K, T, I>::PurgeAndDeleteElements()
+{
+ for ( I i = 0; i < MaxElement(); ++i )
+ {
+ if ( !IsValidIndex( i ) )
+ continue;
+
+ delete Element( i );
+ }
+
+ Purge();
+}
+
+//-----------------------------------------------------------------------------
+
+// This is horrible and slow and meant to be used only when you're dealing with really
+// non-time/memory-critical code and desperately want to copy a whole map element-by-element
+// for whatever reason.
+template < typename K, typename T, typename I >
+void DeepCopyMap( const CUtlMap<K,T,I>& pmapIn, CUtlMap<K,T,I> *out_pmapOut )
+{
+ Assert( out_pmapOut );
+
+ out_pmapOut->Purge();
+ FOR_EACH_MAP_FAST( pmapIn, i )
+ {
+ out_pmapOut->Insert( pmapIn.Key( i ), pmapIn.Element( i ) );
+ }
+}
+
+#endif // UTLMAP_H
diff --git a/public/tier1/utlmemory.h b/public/tier1/utlmemory.h
new file mode 100644
index 0000000..9c5a1d1
--- /dev/null
+++ b/public/tier1/utlmemory.h
@@ -0,0 +1,1077 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+// A growable memory class.
+//===========================================================================//
+
+#ifndef UTLMEMORY_H
+#define UTLMEMORY_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/dbg.h"
+#include <string.h>
+#include "tier0/platform.h"
+#include "mathlib/mathlib.h"
+
+#include "tier0/memalloc.h"
+#include "tier0/memdbgon.h"
+
+#pragma warning (disable:4100)
+#pragma warning (disable:4514)
+
+
+//-----------------------------------------------------------------------------
+
+
+#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 )
+#else
+#define UTLMEMORY_TRACK_ALLOC() ((void)0)
+#define UTLMEMORY_TRACK_FREE() ((void)0)
+#endif
+
+
+//-----------------------------------------------------------------------------
+// The CUtlMemory class:
+// A growable memory class which doubles in size by default.
+//-----------------------------------------------------------------------------
+template< class T, class I = int >
+class CUtlMemory
+{
+public:
+ // constructor, destructor
+ CUtlMemory( int nGrowSize = 0, int nInitSize = 0 );
+ CUtlMemory( T* pMemory, int numElements );
+ CUtlMemory( const T* pMemory, int numElements );
+ ~CUtlMemory();
+
+ // Set the size by which the memory grows
+ void Init( int nGrowSize = 0, int nInitSize = 0 );
+
+ class Iterator_t
+ {
+ public:
+ Iterator_t( I i ) : index( i ) {}
+ I index;
+
+ bool operator==( const Iterator_t it ) const { return index == it.index; }
+ bool operator!=( const Iterator_t it ) const { return index != it.index; }
+ };
+ Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); }
+ Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); }
+ I GetIndex( const Iterator_t &it ) const { return it.index; }
+ bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; }
+ bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); }
+ Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); }
+
+ // element access
+ T& operator[]( I i );
+ const T& operator[]( I i ) const;
+ T& Element( I i );
+ const T& Element( I i ) const;
+
+ // Can we use this index?
+ bool IsIdxValid( I i ) const;
+
+ // Specify the invalid ('null') index that we'll only return on failure
+ static const I INVALID_INDEX = ( I )-1; // For use with COMPILE_TIME_ASSERT
+ static I InvalidIndex() { return INVALID_INDEX; }
+
+ // Gets the base address (can change when adding elements!)
+ T* Base();
+ const T* Base() const;
+
+ // 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 );
+
+ // Fast swap
+ void Swap( CUtlMemory< T, I > &mem );
+
+ // Switches the buffer from an external memory buffer to a reallocatable buffer
+ // Will copy the current contents of the external buffer to the reallocatable buffer
+ void ConvertToGrowableMemory( int nGrowSize );
+
+ // Size
+ int NumAllocated() const;
+ int Count() const;
+
+ // Grows the memory, so that at least allocated + num elements are allocated
+ void Grow( int num = 1 );
+
+ // Makes sure we've got at least this much memory
+ void EnsureCapacity( int num );
+
+ // Memory deallocation
+ void Purge();
+
+ // Purge all but the given number of elements
+ void Purge( int numElements );
+
+ // is the memory externally allocated?
+ bool IsExternallyAllocated() const;
+
+ // is the memory read only?
+ bool IsReadOnly() const;
+
+ // Set the size by which the memory grows
+ void SetGrowSize( int size );
+
+protected:
+ void ValidateGrowSize()
+ {
+#ifdef _X360
+ if ( m_nGrowSize && m_nGrowSize != EXTERNAL_BUFFER_MARKER )
+ {
+ // Max grow size at 128 bytes on XBOX
+ const int MAX_GROW = 128;
+ if ( m_nGrowSize * sizeof(T) > MAX_GROW )
+ {
+ m_nGrowSize = max( 1, MAX_GROW / sizeof(T) );
+ }
+ }
+#endif
+ }
+
+ enum
+ {
+ EXTERNAL_BUFFER_MARKER = -1,
+ EXTERNAL_CONST_BUFFER_MARKER = -2,
+ };
+
+ T* m_pMemory;
+ int m_nAllocationCount;
+ int m_nGrowSize;
+};
+
+
+//-----------------------------------------------------------------------------
+// The CUtlMemory class:
+// A growable memory class which doubles in size by default.
+//-----------------------------------------------------------------------------
+template< class T, size_t SIZE, class I = int >
+class CUtlMemoryFixedGrowable : public CUtlMemory< T, I >
+{
+ typedef CUtlMemory< T, I > BaseClass;
+
+public:
+ CUtlMemoryFixedGrowable( int nGrowSize = 0, int nInitSize = SIZE ) : BaseClass( m_pFixedMemory, SIZE )
+ {
+ Assert( nInitSize == 0 || nInitSize == SIZE );
+ m_nMallocGrowSize = nGrowSize;
+ }
+
+ void Grow( int nCount = 1 )
+ {
+ if ( this->IsExternallyAllocated() )
+ {
+ this->ConvertToGrowableMemory( m_nMallocGrowSize );
+ }
+ BaseClass::Grow( nCount );
+ }
+
+ void EnsureCapacity( int num )
+ {
+ if ( CUtlMemory<T>::m_nAllocationCount >= num )
+ return;
+
+ if ( this->IsExternallyAllocated() )
+ {
+ // Can't grow a buffer whose memory was externally allocated
+ this->ConvertToGrowableMemory( m_nMallocGrowSize );
+ }
+
+ BaseClass::EnsureCapacity( num );
+ }
+
+private:
+ int m_nMallocGrowSize;
+ T m_pFixedMemory[ SIZE ];
+};
+
+//-----------------------------------------------------------------------------
+// The CUtlMemoryFixed class:
+// A fixed memory class
+//-----------------------------------------------------------------------------
+template< typename T, size_t SIZE, int nAlignment = 0 >
+class CUtlMemoryFixed
+{
+public:
+ // constructor, destructor
+ CUtlMemoryFixed( int nGrowSize = 0, int nInitSize = 0 ) { Assert( nInitSize == 0 || nInitSize == SIZE ); }
+ 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; }
+
+ // Specify the invalid ('null') index that we'll only return on failure
+ static const int INVALID_INDEX = -1; // For use with COMPILE_TIME_ASSERT
+ static int InvalidIndex() { return INVALID_INDEX; }
+
+ // Gets the base address
+ T* Base() { if ( nAlignment == 0 ) return (T*)(&m_Memory[0]); else return (T*)AlignValue( &m_Memory[0], nAlignment ); }
+ 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]; }
+
+ // Attaches the buffer to external memory....
+ void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); }
+
+ // Size
+ int NumAllocated() const { return SIZE; }
+ int Count() const { return SIZE; }
+
+ // Grows the memory, so that at least allocated + num elements are allocated
+ void Grow( int num = 1 ) { Assert( 0 ); }
+
+ // Makes sure we've got at least this much memory
+ void EnsureCapacity( int num ) { Assert( num <= SIZE ); }
+
+ // Memory deallocation
+ void Purge() {}
+
+ // Purge all but the given number of elements (NOT IMPLEMENTED IN CUtlMemoryFixed)
+ void Purge( int numElements ) { Assert( 0 ); }
+
+ // is the memory externally allocated?
+ bool IsExternallyAllocated() const { return false; }
+
+ // Set the size by which the memory grows
+ void SetGrowSize( int size ) {}
+
+ class Iterator_t
+ {
+ public:
+ Iterator_t( int i ) : index( i ) {}
+ int index;
+ bool operator==( const Iterator_t it ) const { return index == it.index; }
+ bool operator!=( const Iterator_t it ) const { return index != it.index; }
+ };
+ Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); }
+ Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); }
+ int GetIndex( const Iterator_t &it ) const { return it.index; }
+ bool IsIdxAfter( int i, const Iterator_t &it ) const { return i > it.index; }
+ bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); }
+ Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); }
+
+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).
+#define REMEMBER_ALLOC_SIZE_FOR_VALGRIND 1
+#endif
+
+//-----------------------------------------------------------------------------
+// The CUtlMemoryConservative class:
+// A dynamic memory class that tries to minimize overhead (itself small, no custom grow factor)
+//-----------------------------------------------------------------------------
+template< typename T >
+class CUtlMemoryConservative
+{
+
+public:
+ // constructor, destructor
+ CUtlMemoryConservative( int nGrowSize = 0, int nInitSize = 0 ) : m_pMemory( NULL )
+ {
+#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND
+ m_nCurAllocSize = 0;
+#endif
+
+ }
+ CUtlMemoryConservative( T* pMemory, int numElements ) { Assert( 0 ); }
+ ~CUtlMemoryConservative() { if ( m_pMemory ) free( m_pMemory ); }
+
+ // Can we use this index?
+ bool IsIdxValid( int i ) const { return ( IsDebug() ) ? ( i >= 0 && i < NumAllocated() ) : ( i >= 0 ); }
+ static int InvalidIndex() { return -1; }
+
+ // Gets the base address
+ T* Base() { return m_pMemory; }
+ const T* Base() const { return m_pMemory; }
+
+ // element access
+ 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 ); }
+
+ // Size
+ FORCEINLINE void RememberAllocSize( size_t sz )
+ {
+#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND
+ m_nCurAllocSize = sz;
+#endif
+ }
+
+ size_t AllocSize( void ) const
+ {
+#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND
+ return m_nCurAllocSize;
+#else
+ return ( m_pMemory ) ? g_pMemAlloc->GetSize( m_pMemory ) : 0;
+#endif
+ }
+
+ int NumAllocated() const
+ {
+ return AllocSize() / sizeof( T );
+ }
+ int Count() const
+ {
+ return NumAllocated();
+ }
+
+ FORCEINLINE void ReAlloc( size_t sz )
+ {
+ m_pMemory = (T*)realloc( m_pMemory, sz );
+ RememberAllocSize( sz );
+ }
+ // Grows the memory, so that at least allocated + num elements are allocated
+ void Grow( int num = 1 )
+ {
+ int nCurN = NumAllocated();
+ ReAlloc( ( nCurN + num ) * sizeof( T ) );
+ }
+
+ // Makes sure we've got at least this much memory
+ void EnsureCapacity( int num )
+ {
+ size_t nSize = sizeof( T ) * MAX( num, Count() );
+ ReAlloc( nSize );
+ }
+
+ // Memory deallocation
+ void Purge()
+ {
+ free( m_pMemory );
+ RememberAllocSize( 0 );
+ m_pMemory = NULL;
+ }
+
+ // Purge all but the given number of elements
+ void Purge( int numElements ) { ReAlloc( numElements * sizeof(T) ); }
+
+ // is the memory externally allocated?
+ bool IsExternallyAllocated() const { return false; }
+
+ // Set the size by which the memory grows
+ void SetGrowSize( int size ) {}
+
+ class Iterator_t
+ {
+ public:
+ Iterator_t( int i, int _limit ) : index( i ), limit( _limit ) {}
+ int index;
+ int limit;
+ bool operator==( const Iterator_t it ) const { return index == it.index; }
+ bool operator!=( const Iterator_t it ) const { return index != it.index; }
+ };
+ Iterator_t First() const { int limit = NumAllocated(); return Iterator_t( limit ? 0 : InvalidIndex(), limit ); }
+ Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( ( it.index + 1 < it.limit ) ? it.index + 1 : InvalidIndex(), it.limit ); }
+ int GetIndex( const Iterator_t &it ) const { return it.index; }
+ bool IsIdxAfter( int i, const Iterator_t &it ) const { return i > it.index; }
+ bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ) && ( it.index < it.limit ); }
+ Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex(), 0 ); }
+
+private:
+ T *m_pMemory;
+#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND
+ size_t m_nCurAllocSize;
+#endif
+
+};
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+
+template< class T, class I >
+CUtlMemory<T,I>::CUtlMemory( int nGrowSize, int nInitAllocationCount ) : m_pMemory(0),
+ m_nAllocationCount( nInitAllocationCount ), m_nGrowSize( nGrowSize )
+{
+ ValidateGrowSize();
+ Assert( nGrowSize >= 0 );
+ if (m_nAllocationCount)
+ {
+ UTLMEMORY_TRACK_ALLOC();
+ MEM_ALLOC_CREDIT_CLASS();
+ m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) );
+ }
+}
+
+template< class T, class I >
+CUtlMemory<T,I>::CUtlMemory( T* pMemory, int numElements ) : m_pMemory(pMemory),
+ m_nAllocationCount( numElements )
+{
+ // Special marker indicating externally supplied modifyable memory
+ m_nGrowSize = EXTERNAL_BUFFER_MARKER;
+}
+
+template< class T, class I >
+CUtlMemory<T,I>::CUtlMemory( const T* pMemory, int numElements ) : m_pMemory( (T*)pMemory ),
+ m_nAllocationCount( numElements )
+{
+ // Special marker indicating externally supplied modifyable memory
+ m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER;
+}
+
+template< class T, class I >
+CUtlMemory<T,I>::~CUtlMemory()
+{
+ Purge();
+}
+
+template< class T, class I >
+void CUtlMemory<T,I>::Init( int nGrowSize /*= 0*/, int nInitSize /*= 0*/ )
+{
+ Purge();
+
+ m_nGrowSize = nGrowSize;
+ m_nAllocationCount = nInitSize;
+ ValidateGrowSize();
+ Assert( nGrowSize >= 0 );
+ if (m_nAllocationCount)
+ {
+ UTLMEMORY_TRACK_ALLOC();
+ MEM_ALLOC_CREDIT_CLASS();
+ m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Fast swap
+//-----------------------------------------------------------------------------
+template< class T, class I >
+void CUtlMemory<T,I>::Swap( CUtlMemory<T,I> &mem )
+{
+ V_swap( m_nGrowSize, mem.m_nGrowSize );
+ V_swap( m_pMemory, mem.m_pMemory );
+ V_swap( m_nAllocationCount, mem.m_nAllocationCount );
+}
+
+
+//-----------------------------------------------------------------------------
+// Switches the buffer from an external memory buffer to a reallocatable buffer
+//-----------------------------------------------------------------------------
+template< class T, class I >
+void CUtlMemory<T,I>::ConvertToGrowableMemory( int nGrowSize )
+{
+ if ( !IsExternallyAllocated() )
+ return;
+
+ m_nGrowSize = nGrowSize;
+ if (m_nAllocationCount)
+ {
+ UTLMEMORY_TRACK_ALLOC();
+ MEM_ALLOC_CREDIT_CLASS();
+
+ int nNumBytes = m_nAllocationCount * sizeof(T);
+ T *pMemory = (T*)malloc( nNumBytes );
+ memcpy( (void*)pMemory, (void*)m_pMemory, nNumBytes );
+ m_pMemory = pMemory;
+ }
+ else
+ {
+ m_pMemory = NULL;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Attaches the buffer to external memory....
+//-----------------------------------------------------------------------------
+template< class T, class I >
+void CUtlMemory<T,I>::SetExternalBuffer( T* pMemory, int numElements )
+{
+ // Blow away any existing allocated memory
+ Purge();
+
+ m_pMemory = pMemory;
+ m_nAllocationCount = numElements;
+
+ // Indicate that we don't own the memory
+ m_nGrowSize = EXTERNAL_BUFFER_MARKER;
+}
+
+template< class T, class I >
+void CUtlMemory<T,I>::SetExternalBuffer( const T* pMemory, int numElements )
+{
+ // Blow away any existing allocated memory
+ Purge();
+
+ m_pMemory = const_cast<T*>( pMemory );
+ m_nAllocationCount = numElements;
+
+ // Indicate that we don't own the memory
+ m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER;
+}
+
+template< class T, class I >
+void CUtlMemory<T,I>::AssumeMemory( T* pMemory, int numElements )
+{
+ // Blow away any existing allocated memory
+ Purge();
+
+ // Simply take the pointer but don't mark us as external
+ m_pMemory = pMemory;
+ m_nAllocationCount = numElements;
+}
+
+
+//-----------------------------------------------------------------------------
+// element access
+//-----------------------------------------------------------------------------
+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];
+}
+
+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];
+}
+
+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];
+}
+
+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];
+}
+
+
+//-----------------------------------------------------------------------------
+// is the memory externally allocated?
+//-----------------------------------------------------------------------------
+template< class T, class I >
+bool CUtlMemory<T,I>::IsExternallyAllocated() const
+{
+ return (m_nGrowSize < 0);
+}
+
+
+//-----------------------------------------------------------------------------
+// is the memory read only?
+//-----------------------------------------------------------------------------
+template< class T, class I >
+bool CUtlMemory<T,I>::IsReadOnly() const
+{
+ return (m_nGrowSize == EXTERNAL_CONST_BUFFER_MARKER);
+}
+
+
+template< class T, class I >
+void CUtlMemory<T,I>::SetGrowSize( int nSize )
+{
+ Assert( !IsExternallyAllocated() );
+ Assert( nSize >= 0 );
+ m_nGrowSize = nSize;
+ ValidateGrowSize();
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the base address (can change when adding elements!)
+//-----------------------------------------------------------------------------
+template< class T, class I >
+inline T* CUtlMemory<T,I>::Base()
+{
+ Assert( !IsReadOnly() );
+ return m_pMemory;
+}
+
+template< class T, class I >
+inline const T *CUtlMemory<T,I>::Base() const
+{
+ return m_pMemory;
+}
+
+
+//-----------------------------------------------------------------------------
+// Size
+//-----------------------------------------------------------------------------
+template< class T, class I >
+inline int CUtlMemory<T,I>::NumAllocated() const
+{
+ return m_nAllocationCount;
+}
+
+template< class T, class I >
+inline int CUtlMemory<T,I>::Count() const
+{
+ return m_nAllocationCount;
+}
+
+
+//-----------------------------------------------------------------------------
+// Is element index valid?
+//-----------------------------------------------------------------------------
+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;
+}
+
+//-----------------------------------------------------------------------------
+// Grows the memory
+//-----------------------------------------------------------------------------
+inline int UtlMemory_CalcNewAllocationCount( int nAllocationCount, int nGrowSize, int nNewSize, int nBytesItem )
+{
+ if ( nGrowSize )
+ {
+ nAllocationCount = ((1 + ((nNewSize - 1) / nGrowSize)) * nGrowSize);
+ }
+ else
+ {
+ if ( !nAllocationCount )
+ {
+ // Compute an allocation which is at least as big as a cache line...
+ nAllocationCount = (31 + nBytesItem) / nBytesItem;
+ }
+
+ while (nAllocationCount < nNewSize)
+ {
+#ifndef _X360
+ nAllocationCount *= 2;
+#else
+ int nNewAllocationCount = ( nAllocationCount * 9) / 8; // 12.5 %
+ if ( nNewAllocationCount > nAllocationCount )
+ nAllocationCount = nNewAllocationCount;
+ else
+ nAllocationCount *= 2;
+#endif
+ }
+ }
+
+ return nAllocationCount;
+}
+
+template< class T, class I >
+void CUtlMemory<T,I>::Grow( int num )
+{
+ Assert( num > 0 );
+
+ if ( IsExternallyAllocated() )
+ {
+ // Can't grow a buffer whose memory was externally allocated
+ Assert(0);
+ return;
+ }
+
+ // Make sure we have at least numallocated + num allocations.
+ // Use the grow rules specified for this memory (in m_nGrowSize)
+ int nAllocationRequested = m_nAllocationCount + num;
+
+ UTLMEMORY_TRACK_FREE();
+
+ int nNewAllocationCount = UtlMemory_CalcNewAllocationCount( m_nAllocationCount, m_nGrowSize, nAllocationRequested, sizeof(T) );
+
+ // if m_nAllocationRequested wraps index type I, recalculate
+ if ( ( int )( I )nNewAllocationCount < nAllocationRequested )
+ {
+ if ( ( int )( I )nNewAllocationCount == 0 && ( int )( I )( nNewAllocationCount - 1 ) >= nAllocationRequested )
+ {
+ --nNewAllocationCount; // deal w/ the common case of m_nAllocationCount == MAX_USHORT + 1
+ }
+ else
+ {
+ if ( ( int )( I )nAllocationRequested != nAllocationRequested )
+ {
+ // we've been asked to grow memory to a size s.t. the index type can't address the requested amount of memory
+ Assert( 0 );
+ return;
+ }
+ while ( ( int )( I )nNewAllocationCount < nAllocationRequested )
+ {
+ nNewAllocationCount = ( nNewAllocationCount + nAllocationRequested ) / 2;
+ }
+ }
+ }
+
+ m_nAllocationCount = nNewAllocationCount;
+
+ UTLMEMORY_TRACK_ALLOC();
+
+ if (m_pMemory)
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) );
+ Assert( m_pMemory );
+ }
+ else
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) );
+ Assert( m_pMemory );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Makes sure we've got at least this much memory
+//-----------------------------------------------------------------------------
+template< class T, class I >
+inline void CUtlMemory<T,I>::EnsureCapacity( int num )
+{
+ if (m_nAllocationCount >= num)
+ return;
+
+ if ( IsExternallyAllocated() )
+ {
+ // Can't grow a buffer whose memory was externally allocated
+ Assert(0);
+ return;
+ }
+
+ UTLMEMORY_TRACK_FREE();
+
+ m_nAllocationCount = num;
+
+ UTLMEMORY_TRACK_ALLOC();
+
+ if (m_pMemory)
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) );
+ }
+ else
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Memory deallocation
+//-----------------------------------------------------------------------------
+template< class T, class I >
+void CUtlMemory<T,I>::Purge()
+{
+ if ( !IsExternallyAllocated() )
+ {
+ if (m_pMemory)
+ {
+ UTLMEMORY_TRACK_FREE();
+ free( (void*)m_pMemory );
+ m_pMemory = 0;
+ }
+ m_nAllocationCount = 0;
+ }
+}
+
+template< class T, class I >
+void CUtlMemory<T,I>::Purge( int numElements )
+{
+ Assert( numElements >= 0 );
+
+ if( numElements > m_nAllocationCount )
+ {
+ // Ensure this isn't a grow request in disguise.
+ Assert( numElements <= m_nAllocationCount );
+ return;
+ }
+
+ // If we have zero elements, simply do a purge:
+ if( numElements == 0 )
+ {
+ Purge();
+ return;
+ }
+
+ if ( IsExternallyAllocated() )
+ {
+ // Can't shrink a buffer whose memory was externally allocated, fail silently like purge
+ return;
+ }
+
+ // If the number of elements is the same as the allocation count, we are done.
+ if( numElements == m_nAllocationCount )
+ {
+ return;
+ }
+
+
+ if( !m_pMemory )
+ {
+ // Allocation count is non zero, but memory is null.
+ Assert( m_pMemory );
+ return;
+ }
+
+ UTLMEMORY_TRACK_FREE();
+
+ m_nAllocationCount = numElements;
+
+ UTLMEMORY_TRACK_ALLOC();
+
+ // Allocation count > 0, shrink it down.
+ MEM_ALLOC_CREDIT_CLASS();
+ m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) );
+}
+
+//-----------------------------------------------------------------------------
+// The CUtlMemory class:
+// A growable memory class which doubles in size by default.
+//-----------------------------------------------------------------------------
+template< class T, int nAlignment >
+class CUtlMemoryAligned : public CUtlMemory<T>
+{
+public:
+ // constructor, destructor
+ CUtlMemoryAligned( int nGrowSize = 0, int nInitSize = 0 );
+ CUtlMemoryAligned( T* pMemory, int numElements );
+ CUtlMemoryAligned( const T* pMemory, int numElements );
+ ~CUtlMemoryAligned();
+
+ // Attaches the buffer to external memory....
+ void SetExternalBuffer( T* pMemory, int numElements );
+ void SetExternalBuffer( const T* pMemory, int numElements );
+
+ // Grows the memory, so that at least allocated + num elements are allocated
+ void Grow( int num = 1 );
+
+ // Makes sure we've got at least this much memory
+ void EnsureCapacity( int num );
+
+ // Memory deallocation
+ void Purge();
+
+ // Purge all but the given number of elements (NOT IMPLEMENTED IN CUtlMemoryAligned)
+ void Purge( int numElements ) { Assert( 0 ); }
+
+private:
+ void *Align( const void *pAddr );
+};
+
+
+//-----------------------------------------------------------------------------
+// Aligns a pointer
+//-----------------------------------------------------------------------------
+template< class T, int nAlignment >
+void *CUtlMemoryAligned<T, nAlignment>::Align( const void *pAddr )
+{
+ size_t nAlignmentMask = nAlignment - 1;
+ return (void*)( ((size_t)pAddr + nAlignmentMask) & (~nAlignmentMask) );
+}
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+template< class T, int nAlignment >
+CUtlMemoryAligned<T, nAlignment>::CUtlMemoryAligned( int nGrowSize, int nInitAllocationCount )
+{
+ CUtlMemory<T>::m_pMemory = 0;
+ CUtlMemory<T>::m_nAllocationCount = nInitAllocationCount;
+ CUtlMemory<T>::m_nGrowSize = nGrowSize;
+ this->ValidateGrowSize();
+
+ // Alignment must be a power of two
+ COMPILE_TIME_ASSERT( (nAlignment & (nAlignment-1)) == 0 );
+ Assert( (nGrowSize >= 0) && (nGrowSize != CUtlMemory<T>::EXTERNAL_BUFFER_MARKER) );
+ if ( CUtlMemory<T>::m_nAllocationCount )
+ {
+ UTLMEMORY_TRACK_ALLOC();
+ MEM_ALLOC_CREDIT_CLASS();
+ CUtlMemory<T>::m_pMemory = (T*)_aligned_malloc( nInitAllocationCount * sizeof(T), nAlignment );
+ }
+}
+
+template< class T, int nAlignment >
+CUtlMemoryAligned<T, nAlignment>::CUtlMemoryAligned( T* pMemory, int numElements )
+{
+ // Special marker indicating externally supplied memory
+ CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_BUFFER_MARKER;
+
+ CUtlMemory<T>::m_pMemory = (T*)Align( pMemory );
+ CUtlMemory<T>::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory ) / sizeof(T);
+}
+
+template< class T, int nAlignment >
+CUtlMemoryAligned<T, nAlignment>::CUtlMemoryAligned( const T* pMemory, int numElements )
+{
+ // Special marker indicating externally supplied memory
+ CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_CONST_BUFFER_MARKER;
+
+ CUtlMemory<T>::m_pMemory = (T*)Align( pMemory );
+ CUtlMemory<T>::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory ) / sizeof(T);
+}
+
+template< class T, int nAlignment >
+CUtlMemoryAligned<T, nAlignment>::~CUtlMemoryAligned()
+{
+ Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+// Attaches the buffer to external memory....
+//-----------------------------------------------------------------------------
+template< class T, int nAlignment >
+void CUtlMemoryAligned<T, nAlignment>::SetExternalBuffer( T* pMemory, int numElements )
+{
+ // Blow away any existing allocated memory
+ Purge();
+
+ CUtlMemory<T>::m_pMemory = (T*)Align( pMemory );
+ CUtlMemory<T>::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory ) / sizeof(T);
+
+ // Indicate that we don't own the memory
+ CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_BUFFER_MARKER;
+}
+
+template< class T, int nAlignment >
+void CUtlMemoryAligned<T, nAlignment>::SetExternalBuffer( const T* pMemory, int numElements )
+{
+ // Blow away any existing allocated memory
+ Purge();
+
+ CUtlMemory<T>::m_pMemory = (T*)Align( pMemory );
+ CUtlMemory<T>::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory ) / sizeof(T);
+
+ // Indicate that we don't own the memory
+ CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_CONST_BUFFER_MARKER;
+}
+
+
+//-----------------------------------------------------------------------------
+// Grows the memory
+//-----------------------------------------------------------------------------
+template< class T, int nAlignment >
+void CUtlMemoryAligned<T, nAlignment>::Grow( int num )
+{
+ Assert( num > 0 );
+
+ if ( this->IsExternallyAllocated() )
+ {
+ // Can't grow a buffer whose memory was externally allocated
+ Assert(0);
+ return;
+ }
+
+ UTLMEMORY_TRACK_FREE();
+
+ // Make sure we have at least numallocated + num allocations.
+ // Use the grow rules specified for this memory (in m_nGrowSize)
+ int nAllocationRequested = CUtlMemory<T>::m_nAllocationCount + num;
+
+ CUtlMemory<T>::m_nAllocationCount = UtlMemory_CalcNewAllocationCount( CUtlMemory<T>::m_nAllocationCount, CUtlMemory<T>::m_nGrowSize, nAllocationRequested, sizeof(T) );
+
+ UTLMEMORY_TRACK_ALLOC();
+
+ if ( CUtlMemory<T>::m_pMemory )
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ CUtlMemory<T>::m_pMemory = (T*)MemAlloc_ReallocAligned( CUtlMemory<T>::m_pMemory, CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment );
+ Assert( CUtlMemory<T>::m_pMemory );
+ }
+ else
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ CUtlMemory<T>::m_pMemory = (T*)MemAlloc_AllocAligned( CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment );
+ Assert( CUtlMemory<T>::m_pMemory );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Makes sure we've got at least this much memory
+//-----------------------------------------------------------------------------
+template< class T, int nAlignment >
+inline void CUtlMemoryAligned<T, nAlignment>::EnsureCapacity( int num )
+{
+ if ( CUtlMemory<T>::m_nAllocationCount >= num )
+ return;
+
+ if ( this->IsExternallyAllocated() )
+ {
+ // Can't grow a buffer whose memory was externally allocated
+ Assert(0);
+ return;
+ }
+
+ UTLMEMORY_TRACK_FREE();
+
+ CUtlMemory<T>::m_nAllocationCount = num;
+
+ UTLMEMORY_TRACK_ALLOC();
+
+ if ( CUtlMemory<T>::m_pMemory )
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ CUtlMemory<T>::m_pMemory = (T*)MemAlloc_ReallocAligned( CUtlMemory<T>::m_pMemory, CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment );
+ }
+ else
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ CUtlMemory<T>::m_pMemory = (T*)MemAlloc_AllocAligned( CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Memory deallocation
+//-----------------------------------------------------------------------------
+template< class T, int nAlignment >
+void CUtlMemoryAligned<T, nAlignment>::Purge()
+{
+ if ( !this->IsExternallyAllocated() )
+ {
+ if ( CUtlMemory<T>::m_pMemory )
+ {
+ UTLMEMORY_TRACK_FREE();
+ MemAlloc_FreeAligned( CUtlMemory<T>::m_pMemory );
+ CUtlMemory<T>::m_pMemory = 0;
+ }
+ CUtlMemory<T>::m_nAllocationCount = 0;
+ }
+}
+
+#include "tier0/memdbgoff.h"
+
+#endif // UTLMEMORY_H
diff --git a/public/tier1/utlmovingaverage.h b/public/tier1/utlmovingaverage.h
new file mode 100644
index 0000000..b91ccb6
--- /dev/null
+++ b/public/tier1/utlmovingaverage.h
@@ -0,0 +1,103 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Simple moving average class
+//
+// $NoKeywords: $
+//
+//
+//=============================================================================//
+#ifndef MOVING_AVERAGE_H
+#define MOVING_AVERAGE_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/platform.h"
+#include "tier0/basetypes.h"
+
+template<uint32 TBufferSize> class CUtlMovingAverage
+{
+public:
+ CUtlMovingAverage() :
+ m_nValuesPushed( 0 ),
+ m_flTotal( 0.0f )
+ {
+ }
+
+ void Reset()
+ {
+ m_nValuesPushed = 0;
+ m_flTotal = 0.0f;
+ }
+
+ uint32 GetTotalValuesPushed() const
+ {
+ return m_nValuesPushed;
+ }
+
+ float GetAverage( )
+ {
+ uint n = MIN( TBufferSize, m_nValuesPushed );
+ return n ? ( m_flTotal / static_cast<double>( n ) ) : 0.0f;
+ }
+
+ void GetAverageAndAbsRange( float *pflOutAverage, float *pflOutAbsRange, float *pflMinTime, float *pflMaxTime )
+ {
+ if ( m_nValuesPushed == 0 )
+ {
+ *pflOutAverage = 0;
+ *pflOutAbsRange = 0;
+ *pflMinTime = 0;
+ *pflMaxTime = 0;
+ return;
+ }
+
+ *pflOutAverage = GetAverage();
+
+ const int nNumValues = MIN( m_nValuesPushed, TBufferSize );
+
+ float flAbsRange = 0;
+ float flMinTime = 9e+9;
+ float flMaxTime = 0;
+
+ for ( int i = 0; i < nNumValues; ++i )
+ {
+ float flDif = ( m_Buffer[i] - *pflOutAverage );
+ flAbsRange = MAX( flAbsRange, abs( flDif ) );
+ flMinTime = MIN( flMinTime, m_Buffer[i] );
+ flMaxTime = MAX( flMaxTime, m_Buffer[i] );
+ }
+
+ *pflOutAbsRange = flAbsRange;
+ *pflMinTime = flMinTime;
+ *pflMaxTime = flMaxTime;
+ }
+
+ void PushValue( float v )
+ {
+ uint nIndex = m_nValuesPushed % TBufferSize;
+
+ if ( m_nValuesPushed >= TBufferSize )
+ {
+ m_flTotal = MAX( m_flTotal - m_Buffer[nIndex], 0.0f );
+ }
+ m_flTotal += v;
+
+ m_Buffer[nIndex] = v;
+ m_nValuesPushed++;
+
+ if ( UINT_MAX == m_nValuesPushed )
+ {
+ Reset();
+ }
+ }
+
+private:
+ float m_Buffer[TBufferSize];
+ uint32 m_nValuesPushed;
+
+ double m_flTotal;
+};
+
+#endif // MOVING_AVERAGE_H
diff --git a/public/tier1/utlmultilist.h b/public/tier1/utlmultilist.h
new file mode 100644
index 0000000..72a970f
--- /dev/null
+++ b/public/tier1/utlmultilist.h
@@ -0,0 +1,771 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Multiple linked list container class
+//
+// $Revision: $
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef UTLMULTILIST_H
+#define UTLMULTILIST_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "utllinkedlist.h"
+
+// memdbgon must be the last include file in a .h file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// class CUtlMultiList:
+// description:
+// A lovely index-based linked list! T is the class type, I is the index
+// type, which usually should be an unsigned short or smaller.
+// This list can contain multiple lists
+//-----------------------------------------------------------------------------
+template <class T, class I>
+class CUtlMultiList
+{
+protected:
+ // What the linked list element looks like
+ struct ListElem_t
+ {
+ T m_Element;
+ I m_Previous;
+ I m_Next;
+ };
+
+ struct List_t
+ {
+ I m_Head;
+ I m_Tail;
+ I m_Count;
+ };
+
+ typedef CUtlMemory<ListElem_t> M; // Keep naming similar to CUtlLinkedList
+public:
+ typedef I ListHandle_t;
+
+ // constructor, destructor
+ CUtlMultiList( int growSize = 0, int initSize = 0 );
+ CUtlMultiList( void *pMemory, int memsize );
+ ~CUtlMultiList( );
+
+ // gets particular elements
+ T& Element( I i );
+ T const& Element( I i ) const;
+ T& operator[]( I i );
+ T const& operator[]( I i ) const;
+
+ // Make sure we have a particular amount of memory
+ void EnsureCapacity( int num );
+
+ // Memory deallocation
+ void Purge();
+
+ // List Creation/deletion
+ ListHandle_t CreateList();
+ void DestroyList( ListHandle_t list );
+ bool IsValidList( ListHandle_t list ) const;
+
+ // Insertion methods (call default constructor)....
+ I InsertBefore( ListHandle_t list, I before );
+ I InsertAfter( ListHandle_t list, I after );
+ I AddToHead( ListHandle_t list );
+ I AddToTail( ListHandle_t list );
+
+ // Insertion methods (call copy constructor)....
+ I InsertBefore( ListHandle_t list, I before, T const& src );
+ I InsertAfter( ListHandle_t list, I after, T const& src );
+ I AddToHead( ListHandle_t list, T const& src );
+ I AddToTail( ListHandle_t list, T const& src );
+
+ // Removal methods
+ void Remove( ListHandle_t list, I elem );
+
+ // Removes all items in a single list
+ void RemoveAll( ListHandle_t list );
+
+ // Removes all items in all lists
+ void RemoveAll();
+
+ // Allocation/deallocation methods
+ // NOTE: To free, it must *not* be in a list!
+ I Alloc( );
+ void Free( I elem );
+
+ // list modification
+ void LinkBefore( ListHandle_t list, I before, I elem );
+ void LinkAfter( ListHandle_t list, I after, I elem );
+ void Unlink( ListHandle_t list, I elem );
+ void LinkToHead( ListHandle_t list, I elem );
+ void LinkToTail( ListHandle_t list, I elem );
+
+ // invalid index
+ static I InvalidIndex() { return (I)~0; }
+ static bool IndexInRange( int index );
+ static size_t ElementSize() { return sizeof(ListElem_t); }
+
+ // list statistics
+ int Count( ListHandle_t list ) const;
+ int TotalCount( ) const;
+ I MaxElementIndex() const;
+
+ // Traversing the list
+ I Head( ListHandle_t list ) const;
+ I Tail( ListHandle_t list ) const;
+ I Previous( I element ) const;
+ I Next( I element ) const;
+
+ // Are nodes in a list or valid?
+ bool IsValidIndex( I i ) const;
+ bool IsInList( I i ) const;
+
+protected:
+ // constructs the class
+ 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]; }
+
+ // A test for debug mode only...
+ bool IsElementInList( ListHandle_t list, I elem ) const;
+
+ // copy constructors not allowed
+ CUtlMultiList( CUtlMultiList<T, I> const& list ) { Assert(0); }
+
+ M m_Memory;
+ CUtlLinkedList<List_t, I> m_List;
+ I* m_pElementList;
+
+ I m_FirstFree;
+ I m_TotalElements;
+ int m_MaxElementIndex; // The number allocated (use int so we can catch overflow)
+
+ void ResetDbgInfo()
+ {
+ m_pElements = m_Memory.Base();
+
+#ifdef _DEBUG
+ // Allocate space for the element list (which list is each element in)
+ if (m_Memory.NumAllocated() > 0)
+ {
+ if (!m_pElementList)
+ {
+ m_pElementList = (I*)malloc( m_Memory.NumAllocated() * sizeof(I) );
+ }
+ else
+ {
+ m_pElementList = (I*)realloc( m_pElementList, m_Memory.NumAllocated() * sizeof(I) );
+ }
+ }
+#endif
+ }
+
+ // For debugging purposes;
+ // it's in release builds so this can be used in libraries correctly
+ ListElem_t *m_pElements;
+};
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+
+template <class T, class I>
+CUtlMultiList<T,I>::CUtlMultiList( int growSize, int initSize ) :
+ m_Memory(growSize, initSize), m_pElementList(0)
+{
+ ConstructList();
+}
+
+template <class T, class I>
+CUtlMultiList<T,I>::CUtlMultiList( void* pMemory, int memsize ) :
+ m_Memory((ListElem_t *)pMemory, memsize/sizeof(ListElem_t)), m_pElementList(0)
+{
+ ConstructList();
+}
+
+template <class T, class I>
+CUtlMultiList<T,I>::~CUtlMultiList( )
+{
+ RemoveAll();
+ if (m_pElementList)
+ free(m_pElementList);
+}
+
+template <class T, class I>
+void CUtlMultiList<T,I>::ConstructList( )
+{
+ m_FirstFree = InvalidIndex();
+ m_TotalElements = 0;
+ m_MaxElementIndex = 0;
+ ResetDbgInfo();
+}
+
+
+//-----------------------------------------------------------------------------
+// gets particular elements
+//-----------------------------------------------------------------------------
+template <class T, class I>
+inline T& CUtlMultiList<T,I>::Element( I i )
+{
+ return m_Memory[i].m_Element;
+}
+
+template <class T, class I>
+inline T const& CUtlMultiList<T,I>::Element( I i ) const
+{
+ return m_Memory[i].m_Element;
+}
+
+template <class T, class I>
+inline T& CUtlMultiList<T,I>::operator[]( I i )
+{
+ return m_Memory[i].m_Element;
+}
+
+template <class T, class I>
+inline T const& CUtlMultiList<T,I>::operator[]( I i ) const
+{
+ return m_Memory[i].m_Element;
+}
+
+
+//-----------------------------------------------------------------------------
+// list creation/destruction
+//-----------------------------------------------------------------------------
+template <class T, class I>
+typename CUtlMultiList<T,I>::ListHandle_t CUtlMultiList<T,I>::CreateList()
+{
+ ListHandle_t l = m_List.AddToTail();
+ m_List[l].m_Head = m_List[l].m_Tail = InvalidIndex();
+ m_List[l].m_Count = 0;
+ return l;
+}
+
+template <class T, class I>
+void CUtlMultiList<T,I>::DestroyList( ListHandle_t list )
+{
+ Assert( IsValidList(list) );
+ RemoveAll( list );
+ m_List.Remove(list);
+}
+
+template <class T, class I>
+bool CUtlMultiList<T,I>::IsValidList( ListHandle_t list ) const
+{
+ return m_List.IsValidIndex(list);
+}
+
+
+//-----------------------------------------------------------------------------
+// list statistics
+//-----------------------------------------------------------------------------
+template <class T, class I>
+inline int CUtlMultiList<T,I>::TotalCount() const
+{
+ return m_TotalElements;
+}
+
+template <class T, class I>
+inline int CUtlMultiList<T,I>::Count( ListHandle_t list ) const
+{
+ Assert( IsValidList(list) );
+ return m_List[list].m_Count;
+}
+
+template <class T, class I>
+inline I CUtlMultiList<T,I>::MaxElementIndex() const
+{
+ return m_MaxElementIndex;
+}
+
+
+//-----------------------------------------------------------------------------
+// Traversing the list
+//-----------------------------------------------------------------------------
+template <class T, class I>
+inline I CUtlMultiList<T,I>::Head(ListHandle_t list) const
+{
+ Assert( IsValidList(list) );
+ return m_List[list].m_Head;
+}
+
+template <class T, class I>
+inline I CUtlMultiList<T,I>::Tail(ListHandle_t list) const
+{
+ Assert( IsValidList(list) );
+ return m_List[list].m_Tail;
+}
+
+template <class T, class I>
+inline I CUtlMultiList<T,I>::Previous( I i ) const
+{
+ Assert( IsValidIndex(i) );
+ return InternalElement(i).m_Previous;
+}
+
+template <class T, class I>
+inline I CUtlMultiList<T,I>::Next( I i ) const
+{
+ Assert( IsValidIndex(i) );
+ return InternalElement(i).m_Next;
+}
+
+
+//-----------------------------------------------------------------------------
+// Are nodes in the list or valid?
+//-----------------------------------------------------------------------------
+
+template <class T, class I>
+inline bool CUtlMultiList<T,I>::IndexInRange( int index ) // Static method
+{
+ // Since I is not necessarily the type returned by M (int), we need to check that M returns
+ // indices which are representable by I. A common case is 'I === unsigned short', in which case
+ // case CUtlMemory will have 'InvalidIndex == (int)-1' (which casts to 65535 in I), and will
+ // happily return elements at index 65535 and above.
+
+ // Do a couple of static checks here: the invalid index should be (I)~0 given how we use m_MaxElementIndex,
+ // and 'I' should be unsigned (to avoid signed arithmetic errors for plausibly exhaustible ranges).
+ COMPILE_TIME_ASSERT( (I)M::INVALID_INDEX == (I)~0 );
+ COMPILE_TIME_ASSERT( ( sizeof(I) > 2 ) || ( ( (I)-1 ) > 0 ) );
+
+ return ( ( (I)index == index ) && ( (I)index != InvalidIndex() ) );
+}
+
+template <class T, class I>
+inline bool CUtlMultiList<T,I>::IsValidIndex( I i ) const
+{
+ // 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 (i < m_MaxElementIndex) && (x >= 0) &&
+ ((m_Memory[i].m_Previous != i) || (m_Memory[i].m_Next == i));
+}
+
+template <class T, class I>
+inline bool CUtlMultiList<T,I>::IsInList( I i ) const
+{
+ // 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 (i < m_MaxElementIndex) && (x >= 0) && (Previous(i) != i);
+}
+
+
+//-----------------------------------------------------------------------------
+// Makes sure we have enough memory allocated to store a requested # of elements
+//-----------------------------------------------------------------------------
+template< class T, class I >
+void CUtlMultiList<T, I>::EnsureCapacity( int num )
+{
+ m_Memory.EnsureCapacity(num);
+ ResetDbgInfo();
+}
+
+
+//-----------------------------------------------------------------------------
+// Deallocate memory
+//-----------------------------------------------------------------------------
+template <class T, class I>
+void CUtlMultiList<T,I>::Purge()
+{
+ RemoveAll();
+ m_List.Purge();
+ m_Memory.Purge( );
+ m_List.Purge();
+ m_FirstFree = InvalidIndex();
+ m_TotalElements = 0;
+ m_MaxElementIndex = 0;
+ ResetDbgInfo();
+}
+
+
+//-----------------------------------------------------------------------------
+// Node allocation/deallocation
+//-----------------------------------------------------------------------------
+template <class T, class I>
+I CUtlMultiList<T,I>::Alloc( )
+{
+ I elem;
+ if (m_FirstFree == InvalidIndex())
+ {
+ // We can overflow before the utlmemory overflows, since we have have I != int
+ if ( !IndexInRange( m_MaxElementIndex ) )
+ {
+ // We rarely if ever handle alloc failure. Continuing leads to corruption.
+ Error( "CUtlMultiList overflow! (exhausted index range)\n" );
+ return InvalidIndex();
+ }
+
+ // Nothing in the free list; add.
+ // Since nothing is in the free list, m_TotalElements == total # of elements
+ // the list knows about.
+ if (m_MaxElementIndex == m_Memory.NumAllocated())
+ {
+ m_Memory.Grow();
+ ResetDbgInfo();
+
+ if ( m_MaxElementIndex >= m_Memory.NumAllocated() )
+ {
+ // We rarely if ever handle alloc failure. Continuing leads to corruption.
+ Error( "CUtlMultiList overflow! (exhausted memory allocator)\n" );
+ return InvalidIndex();
+ }
+ }
+
+ elem = (I)m_MaxElementIndex;
+ ++m_MaxElementIndex;
+ }
+ else
+ {
+ elem = m_FirstFree;
+ m_FirstFree = InternalElement(m_FirstFree).m_Next;
+ }
+
+ // Mark the element as not being in a list
+ InternalElement(elem).m_Next = InternalElement(elem).m_Previous = elem;
+
+ ++m_TotalElements;
+
+ Construct( &Element(elem) );
+
+ return elem;
+}
+
+template <class T, class I>
+void CUtlMultiList<T,I>::Free( I elem )
+{
+ Assert( IsValidIndex(elem) && !IsInList(elem) );
+ Destruct( &Element(elem) );
+ InternalElement(elem).m_Next = m_FirstFree;
+ m_FirstFree = elem;
+ --m_TotalElements;
+}
+
+
+//-----------------------------------------------------------------------------
+// A test for debug mode only...
+//-----------------------------------------------------------------------------
+template <class T, class I>
+inline bool CUtlMultiList<T,I>::IsElementInList( ListHandle_t list, I elem ) const
+{
+ if (!m_pElementList)
+ return true;
+
+ return m_pElementList[elem] == list;
+}
+
+
+//-----------------------------------------------------------------------------
+// list modification
+//-----------------------------------------------------------------------------
+template <class T, class I>
+void CUtlMultiList<T,I>::LinkBefore( ListHandle_t list, I before, I elem )
+{
+ Assert( IsValidIndex(elem) && IsValidList(list) );
+
+ // Unlink it if it's in the list at the moment
+ Unlink(list, elem);
+
+ ListElem_t& newElem = InternalElement(elem);
+
+ // The element *after* our newly linked one is the one we linked before.
+ newElem.m_Next = before;
+
+ if (before == InvalidIndex())
+ {
+ // In this case, we're linking to the end of the list, so reset the tail
+ newElem.m_Previous = m_List[list].m_Tail;
+ m_List[list].m_Tail = elem;
+ }
+ else
+ {
+ // Here, we're not linking to the end. Set the prev pointer to point to
+ // the element we're linking.
+ Assert( IsInList(before) );
+ ListElem_t& beforeElem = InternalElement(before);
+ newElem.m_Previous = beforeElem.m_Previous;
+ beforeElem.m_Previous = elem;
+ }
+
+ // Reset the head if we linked to the head of the list
+ if (newElem.m_Previous == InvalidIndex())
+ m_List[list].m_Head = elem;
+ else
+ InternalElement(newElem.m_Previous).m_Next = elem;
+
+ // one more element baby
+ ++m_List[list].m_Count;
+
+ // Store the element into the list
+ if (m_pElementList)
+ m_pElementList[elem] = list;
+}
+
+template <class T, class I>
+void CUtlMultiList<T,I>::LinkAfter( ListHandle_t list, I after, I elem )
+{
+ Assert( IsValidIndex(elem) );
+
+ // Unlink it if it's in the list at the moment
+ Unlink(list, elem);
+
+ ListElem_t& newElem = InternalElement(elem);
+
+ // The element *before* our newly linked one is the one we linked after
+ newElem.m_Previous = after;
+ if (after == InvalidIndex())
+ {
+ // In this case, we're linking to the head of the list, reset the head
+ newElem.m_Next = m_List[list].m_Head;
+ m_List[list].m_Head = elem;
+ }
+ else
+ {
+ // Here, we're not linking to the end. Set the next pointer to point to
+ // the element we're linking.
+ Assert( IsInList(after) );
+ ListElem_t& afterElem = InternalElement(after);
+ newElem.m_Next = afterElem.m_Next;
+ afterElem.m_Next = elem;
+ }
+
+ // Reset the tail if we linked to the tail of the list
+ if (newElem.m_Next == InvalidIndex())
+ m_List[list].m_Tail = elem;
+ else
+ InternalElement(newElem.m_Next).m_Previous = elem;
+
+ // one more element baby
+ ++m_List[list].m_Count;
+
+ // Store the element into the list
+ if (m_pElementList)
+ m_pElementList[elem] = list;
+}
+
+template <class T, class I>
+void CUtlMultiList<T,I>::Unlink( ListHandle_t list, I elem )
+{
+ Assert( IsValidIndex(elem) && IsValidList(list) );
+
+ if (IsInList(elem))
+ {
+ // Make sure the element is in the right list
+ Assert( IsElementInList( list, elem ) );
+ ListElem_t& oldElem = InternalElement(elem);
+
+ // If we're the first guy, reset the head
+ // otherwise, make our previous node's next pointer = our next
+ if (oldElem.m_Previous != InvalidIndex())
+ InternalElement(oldElem.m_Previous).m_Next = oldElem.m_Next;
+ else
+ m_List[list].m_Head = oldElem.m_Next;
+
+ // If we're the last guy, reset the tail
+ // otherwise, make our next node's prev pointer = our prev
+ if (oldElem.m_Next != InvalidIndex())
+ InternalElement(oldElem.m_Next).m_Previous = oldElem.m_Previous;
+ else
+ m_List[list].m_Tail = oldElem.m_Previous;
+
+ // This marks this node as not in the list,
+ // but not in the free list either
+ oldElem.m_Previous = oldElem.m_Next = elem;
+
+ // One less puppy
+ --m_List[list].m_Count;
+
+ // Store the element into the list
+ if (m_pElementList)
+ m_pElementList[elem] = m_List.InvalidIndex();
+ }
+}
+
+template <class T, class I>
+inline void CUtlMultiList<T,I>::LinkToHead( ListHandle_t list, I elem )
+{
+ LinkAfter( list, InvalidIndex(), elem );
+}
+
+template <class T, class I>
+inline void CUtlMultiList<T,I>::LinkToTail( ListHandle_t list, I elem )
+{
+ LinkBefore( list, InvalidIndex(), elem );
+}
+
+
+//-----------------------------------------------------------------------------
+// Insertion methods; allocates and links (uses default constructor)
+//-----------------------------------------------------------------------------
+template <class T, class I>
+I CUtlMultiList<T,I>::InsertBefore( ListHandle_t list, I before )
+{
+ // Make a new node
+ I newNode = Alloc();
+ if ( newNode == InvalidIndex() )
+ return newNode;
+
+ // Link it in
+ LinkBefore( list, before, newNode );
+
+ // Construct the data
+ Construct( &Element(newNode) );
+
+ return newNode;
+}
+
+template <class T, class I>
+I CUtlMultiList<T,I>::InsertAfter( ListHandle_t list, I after )
+{
+ // Make a new node
+ I newNode = Alloc();
+ if ( newNode == InvalidIndex() )
+ return newNode;
+
+ // Link it in
+ LinkAfter( list, after, newNode );
+
+ // Construct the data
+ Construct( &Element(newNode) );
+
+ return newNode;
+}
+
+template <class T, class I>
+inline I CUtlMultiList<T,I>::AddToHead( ListHandle_t list )
+{
+ return InsertAfter( list, InvalidIndex() );
+}
+
+template <class T, class I>
+inline I CUtlMultiList<T,I>::AddToTail( ListHandle_t list )
+{
+ return InsertBefore( list, InvalidIndex() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Insertion methods; allocates and links (uses copy constructor)
+//-----------------------------------------------------------------------------
+template <class T, class I>
+I CUtlMultiList<T,I>::InsertBefore( ListHandle_t list, I before, T const& src )
+{
+ // Make a new node
+ I newNode = Alloc();
+ if ( newNode == InvalidIndex() )
+ return newNode;
+
+ // Link it in
+ LinkBefore( list, before, newNode );
+
+ // Construct the data
+ CopyConstruct( &Element(newNode), src );
+
+ return newNode;
+}
+
+template <class T, class I>
+I CUtlMultiList<T,I>::InsertAfter( ListHandle_t list, I after, T const& src )
+{
+ // Make a new node
+ I newNode = Alloc();
+ if ( newNode == InvalidIndex() )
+ return newNode;
+
+ // Link it in
+ LinkAfter( list, after, newNode );
+
+ // Construct the data
+ CopyConstruct( &Element(newNode), src );
+
+ return newNode;
+}
+
+template <class T, class I>
+inline I CUtlMultiList<T,I>::AddToHead( ListHandle_t list, T const& src )
+{
+ return InsertAfter( list, InvalidIndex(), src );
+}
+
+template <class T, class I>
+inline I CUtlMultiList<T,I>::AddToTail( ListHandle_t list, T const& src )
+{
+ return InsertBefore( list, InvalidIndex(), src );
+}
+
+
+//-----------------------------------------------------------------------------
+// Removal methods
+//-----------------------------------------------------------------------------
+template <class T, class I>
+void CUtlMultiList<T,I>::Remove( ListHandle_t list, I elem )
+{
+ if (IsInList(elem))
+ Unlink(list, elem);
+ Free( elem );
+}
+
+// Removes all items in a single list
+template <class T, class I>
+void CUtlMultiList<T,I>::RemoveAll( ListHandle_t list )
+{
+ Assert( IsValidList(list) );
+ I i = Head(list);
+ I next;
+ while( i != InvalidIndex() )
+ {
+ next = Next(i);
+ Remove(list, i);
+ i = next;
+ }
+}
+
+
+template <class T, class I>
+void CUtlMultiList<T,I>::RemoveAll()
+{
+ if (m_MaxElementIndex == 0)
+ return;
+
+ // Put everything into the free list
+ I prev = InvalidIndex();
+ for (int i = (int)m_MaxElementIndex; --i >= 0; )
+ {
+ // Invoke the destructor
+ if (IsValidIndex((I)i))
+ Destruct( &Element((I)i) );
+
+ // next points to the next free list item
+ InternalElement((I)i).m_Next = prev;
+
+ // Indicates it's in the free list
+ InternalElement((I)i).m_Previous = (I)i;
+ prev = (I)i;
+ }
+
+ // First free points to the first element
+ m_FirstFree = 0;
+
+ // Clear everything else out
+ for (I list = m_List.Head(); list != m_List.InvalidIndex(); list = m_List.Next(list) )
+ {
+ m_List[list].m_Head = InvalidIndex();
+ m_List[list].m_Tail = InvalidIndex();
+ m_List[list].m_Count = 0;
+ }
+
+ m_TotalElements = 0;
+}
+
+
+#include "tier0/memdbgoff.h"
+
+#endif // UTLMULTILIST_H
diff --git a/public/tier1/utlntree.h b/public/tier1/utlntree.h
new file mode 100644
index 0000000..463b5e1
--- /dev/null
+++ b/public/tier1/utlntree.h
@@ -0,0 +1,624 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: N-way tree container class
+//
+// $Revision: $
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef UTLNTREE_H
+#define UTLNTREE_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basetypes.h"
+#include "utlmemory.h"
+#include "tier0/dbg.h"
+
+
+#define INVALID_NTREE_IDX ((I)~0)
+
+//-----------------------------------------------------------------------------
+// class CUtlNTree:
+// description:
+// A lovely index-based linked list! T is the class type, I is the index
+// type, which usually should be an unsigned short or smaller.
+//-----------------------------------------------------------------------------
+template <class T, class I = unsigned short>
+class CUtlNTree
+{
+public:
+ typedef T ElemType_t;
+ typedef I IndexType_t;
+
+ // constructor, destructor
+ CUtlNTree( int growSize = 0, int initSize = 0 );
+ CUtlNTree( void *pMemory, int memsize );
+ ~CUtlNTree( );
+
+ // gets particular elements
+ T& Element( I i );
+ const T& Element( I i ) const;
+ T& operator[]( I i );
+ const T& operator[]( I i ) const;
+
+ // Make sure we have a particular amount of memory
+ void EnsureCapacity( int num );
+
+ // Clears the tree, doesn't deallocate memory
+ void RemoveAll();
+
+ // Memory deallocation
+ void Purge();
+
+ // Allocation/deallocation methods
+ I Alloc( );
+ void Free( I elem );
+ void FreeSubTree( I elem );
+
+ // list modification
+ void SetRoot( I root );
+ void LinkChildBefore( I parent, I before, I elem );
+ void LinkChildAfter( I parent, I after, I elem );
+ void Unlink( I elem );
+
+ // Alloc + link combined
+ I InsertChildBefore( I parent, I before );
+ I InsertChildAfter( I parent, I after );
+ I InsertChildBefore( I parent, I before, const T &elem );
+ I InsertChildAfter( I parent, I after, const T &elem );
+
+ // Unlink + free combined
+ void Remove( I elem );
+ void RemoveSubTree( I elem );
+
+ // invalid index
+ inline static I InvalidIndex() { return INVALID_NTREE_IDX; }
+ inline static size_t ElementSize() { return sizeof(Node_t); }
+
+ // list statistics
+ int Count() const;
+ I MaxElementIndex() const;
+
+ // Traversing the list
+ I Root() const;
+ I FirstChild( I i ) const;
+ I PrevSibling( I i ) const;
+ I NextSibling( I i ) const;
+ I Parent( I i ) const;
+
+ // Are nodes in the list or valid?
+ bool IsValidIndex( I i ) const;
+ bool IsInTree( I i ) const;
+
+protected:
+ // What the linked list element looks like
+ struct Node_t
+ {
+ T m_Element;
+ I m_Parent;
+ I m_FirstChild;
+ I m_PrevSibling;
+ I m_NextSibling;
+
+ private:
+ // No copy constructor for these...
+ Node_t( const Node_t& );
+ };
+
+ // constructs the class
+ void ConstructList();
+
+ // Allocates the element, doesn't call the constructor
+ I AllocInternal();
+
+ // Gets at the node element....
+ Node_t& InternalNode( I i ) { return m_Memory[i]; }
+ const Node_t& InternalNode( I i ) const { return m_Memory[i]; }
+
+ void ResetDbgInfo()
+ {
+ m_pElements = m_Memory.Base();
+ }
+
+ // copy constructors not allowed
+ CUtlNTree( CUtlNTree<T, I> const& tree ) { Assert(0); }
+
+ CUtlMemory<Node_t> m_Memory;
+ I m_Root;
+ I m_FirstFree;
+ I m_ElementCount; // The number actually in the tree
+ I m_MaxElementIndex; // The max index we've ever assigned
+
+ // For debugging purposes;
+ // it's in release builds so this can be used in libraries correctly
+ Node_t *m_pElements;
+};
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+
+template <class T, class I>
+CUtlNTree<T,I>::CUtlNTree( int growSize, int initSize ) :
+ m_Memory(growSize, initSize)
+{
+ ConstructList();
+ ResetDbgInfo();
+}
+
+template <class T, class I>
+CUtlNTree<T,I>::CUtlNTree( void* pMemory, int memsize ) :
+ m_Memory(pMemory, memsize/sizeof(T))
+{
+ ConstructList();
+ ResetDbgInfo();
+}
+
+template <class T, class I>
+CUtlNTree<T,I>::~CUtlNTree( )
+{
+ RemoveAll();
+}
+
+template <class T, class I>
+void CUtlNTree<T,I>::ConstructList()
+{
+ m_Root = InvalidIndex();
+ m_FirstFree = InvalidIndex();
+ m_ElementCount = m_MaxElementIndex = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// gets particular elements
+//-----------------------------------------------------------------------------
+template <class T, class I>
+inline T& CUtlNTree<T,I>::Element( I i )
+{
+ return m_Memory[i].m_Element;
+}
+
+template <class T, class I>
+inline const T& CUtlNTree<T,I>::Element( I i ) const
+{
+ return m_Memory[i].m_Element;
+}
+
+template <class T, class I>
+inline T& CUtlNTree<T,I>::operator[]( I i )
+{
+ return m_Memory[i].m_Element;
+}
+
+template <class T, class I>
+inline const T& CUtlNTree<T,I>::operator[]( I i ) const
+{
+ return m_Memory[i].m_Element;
+}
+
+
+//-----------------------------------------------------------------------------
+// list statistics
+//-----------------------------------------------------------------------------
+template <class T, class I>
+inline int CUtlNTree<T,I>::Count() const
+{
+ return m_ElementCount;
+}
+
+template <class T, class I>
+inline I CUtlNTree<T,I>::MaxElementIndex() const
+{
+ return m_MaxElementIndex;
+}
+
+
+//-----------------------------------------------------------------------------
+// Traversing the list
+//-----------------------------------------------------------------------------
+template <class T, class I>
+inline I CUtlNTree<T,I>::Root() const
+{
+ return m_Root;
+}
+
+template <class T, class I>
+inline I CUtlNTree<T,I>::FirstChild( I i ) const
+{
+ Assert( IsInTree(i) );
+ return InternalNode(i).m_FirstChild;
+}
+
+template <class T, class I>
+inline I CUtlNTree<T,I>::PrevSibling( I i ) const
+{
+ Assert( IsInTree(i) );
+ return InternalNode(i).m_PrevSibling;
+}
+
+template <class T, class I>
+inline I CUtlNTree<T,I>::NextSibling( I i ) const
+{
+ Assert( IsInTree(i) );
+ return InternalNode(i).m_NextSibling;
+}
+
+template <class T, class I>
+inline I CUtlNTree<T,I>::Parent( I i ) const
+{
+ Assert( IsInTree(i) );
+ return InternalNode(i).m_Parent;
+}
+
+
+//-----------------------------------------------------------------------------
+// Are nodes in the list or valid?
+//-----------------------------------------------------------------------------
+template <class T, class I>
+inline bool CUtlNTree<T,I>::IsValidIndex( I i ) const
+{
+ return (i < m_MaxElementIndex) && (i >= 0);
+}
+
+template <class T, class I>
+inline bool CUtlNTree<T,I>::IsInTree( I i ) const
+{
+ return (i < m_MaxElementIndex) && (i >= 0) && (InternalNode(i).m_PrevSibling != i);
+}
+
+
+//-----------------------------------------------------------------------------
+// Makes sure we have enough memory allocated to store a requested # of elements
+//-----------------------------------------------------------------------------
+template< class T, class I >
+void CUtlNTree<T, I>::EnsureCapacity( int num )
+{
+ MEM_ALLOC_CREDIT_CLASS();
+ m_Memory.EnsureCapacity(num);
+ ResetDbgInfo();
+}
+
+
+//-----------------------------------------------------------------------------
+// Deallocate memory
+//-----------------------------------------------------------------------------
+template <class T, class I>
+void CUtlNTree<T,I>::Purge()
+{
+ RemoveAll();
+ m_Memory.Purge( );
+ m_FirstFree = InvalidIndex();
+ m_MaxElementIndex = 0;
+ ResetDbgInfo();
+}
+
+
+//-----------------------------------------------------------------------------
+// Node allocation/deallocation
+//-----------------------------------------------------------------------------
+template <class T, class I>
+I CUtlNTree<T,I>::AllocInternal( )
+{
+ I elem;
+ if ( m_FirstFree == INVALID_NTREE_IDX )
+ {
+ // Nothing in the free list; add.
+ // Since nothing is in the free list, m_MaxElementIndex == total # of elements
+ // the list knows about.
+ if ((int)m_MaxElementIndex == m_Memory.NumAllocated())
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ m_Memory.Grow();
+ }
+
+ Assert( m_MaxElementIndex != INVALID_NTREE_IDX );
+
+ elem = (I)m_MaxElementIndex;
+ ++m_MaxElementIndex;
+
+ if ( elem == InvalidIndex() )
+ {
+ Error("CUtlNTree overflow!\n");
+ }
+ }
+ else
+ {
+ elem = m_FirstFree;
+ m_FirstFree = InternalNode( m_FirstFree ).m_NextSibling;
+ }
+
+ Node_t &node = InternalNode( elem );
+ node.m_NextSibling = node.m_PrevSibling = node.m_Parent = node.m_FirstChild = INVALID_NTREE_IDX;
+ ResetDbgInfo();
+
+ // one more element baby
+ ++m_ElementCount;
+
+ return elem;
+}
+
+template <class T, class I>
+I CUtlNTree<T,I>::Alloc( )
+{
+ I elem = AllocInternal();
+ Construct( &Element(elem) );
+ return elem;
+}
+
+template <class T, class I>
+void CUtlNTree<T,I>::Free( I elem )
+{
+ Assert( IsInTree( elem ) );
+ Unlink( elem );
+
+ // If there's children, this will result in leaks. Use FreeSubTree instead.
+ Assert( FirstChild( elem ) == INVALID_NTREE_IDX );
+
+ Node_t &node = InternalNode( elem );
+ Destruct( &node.m_Element );
+ node.m_NextSibling = m_FirstFree;
+ node.m_PrevSibling = elem; // Marks it as being in the free list
+ node.m_Parent = node.m_FirstChild = INVALID_NTREE_IDX;
+ m_FirstFree = elem;
+
+ // one less element baby
+ --m_ElementCount;
+}
+
+template <class T, class I>
+void CUtlNTree<T,I>::FreeSubTree( I elem )
+{
+ Assert( IsValidIndex( elem ) );
+
+ I child = FirstChild( elem );
+ while ( child != INVALID_NTREE_IDX )
+ {
+ I next = NextSibling( child );
+ FreeSubTree( child );
+ child = next;
+ }
+
+ Free( elem );
+}
+
+
+//-----------------------------------------------------------------------------
+// Clears the tree
+//-----------------------------------------------------------------------------
+template <class T, class I>
+void CUtlNTree<T,I>::RemoveAll()
+{
+ if ( m_MaxElementIndex == 0 )
+ return;
+
+ // Put everything into the free list (even unlinked things )
+ I prev = InvalidIndex();
+ for (int i = (int)m_MaxElementIndex; --i >= 0; prev = (I)i )
+ {
+ Node_t &node = InternalNode( i );
+ if ( IsInTree( i ) )
+ {
+ Destruct( &node.m_Element );
+ }
+
+ node.m_NextSibling = prev;
+ node.m_PrevSibling = (I)i; // Marks it as being in the free list
+ node.m_Parent = node.m_FirstChild = INVALID_NTREE_IDX;
+ }
+
+ // First free points to the first element
+ m_FirstFree = 0;
+
+ // Clear everything else out
+ m_Root = INVALID_NTREE_IDX;
+ m_ElementCount = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// list modification
+//-----------------------------------------------------------------------------
+template <class T, class I>
+void CUtlNTree<T,I>::SetRoot( I root )
+{
+ // Resetting the root while it's got stuff in it is bad...
+ Assert( m_Root == InvalidIndex() );
+ m_Root = root;
+}
+
+
+//-----------------------------------------------------------------------------
+// Links a node after a particular node
+//-----------------------------------------------------------------------------
+template <class T, class I>
+void CUtlNTree<T,I>::LinkChildAfter( I parent, I after, I elem )
+{
+ Assert( IsInTree(elem) );
+
+ // Unlink it if it's in the list at the moment
+ Unlink(elem);
+
+ Node_t& newElem = InternalNode(elem);
+ newElem.m_Parent = parent;
+ newElem.m_PrevSibling = after;
+ if ( after != INVALID_NTREE_IDX )
+ {
+ Node_t& prevSiblingNode = InternalNode( after );
+ newElem.m_NextSibling = prevSiblingNode.m_NextSibling;
+ prevSiblingNode.m_NextSibling = elem;
+ }
+ else
+ {
+ if ( parent != INVALID_NTREE_IDX )
+ {
+ Node_t& parentNode = InternalNode( parent );
+ newElem.m_NextSibling = parentNode.m_FirstChild;
+ parentNode.m_FirstChild = elem;
+ }
+ else
+ {
+ newElem.m_NextSibling = m_Root;
+ if ( m_Root != INVALID_NTREE_IDX )
+ {
+ Node_t& rootNode = InternalNode( m_Root );
+ rootNode.m_PrevSibling = elem;
+ }
+ m_Root = elem;
+ }
+ }
+
+ if ( newElem.m_NextSibling != INVALID_NTREE_IDX )
+ {
+ Node_t& nextSiblingNode = InternalNode( newElem.m_NextSibling );
+ nextSiblingNode.m_PrevSibling = elem;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Links a node before a particular node
+//-----------------------------------------------------------------------------
+template <class T, class I>
+void CUtlNTree<T,I>::LinkChildBefore( I parent, I before, I elem )
+{
+ Assert( IsValidIndex(elem) );
+
+ if ( before != INVALID_NTREE_IDX )
+ {
+ LinkChildAfter( parent, InternalNode( before ).m_PrevSibling, elem );
+ return;
+ }
+
+ // NOTE: I made the choice to do an O(n) operation here
+ // instead of store more data per node (LastChild).
+ // This might not be the right choice. Revisit if we get perf problems.
+ I after;
+ if ( parent != INVALID_NTREE_IDX )
+ {
+ after = InternalNode( parent ).m_FirstChild;
+ }
+ else
+ {
+ after = m_Root;
+ }
+
+ if ( after == INVALID_NTREE_IDX )
+ {
+ LinkChildAfter( parent, after, elem );
+ return;
+ }
+
+ I next = InternalNode( after ).m_NextSibling;
+ while ( next != InvalidIndex() )
+ {
+ after = next;
+ next = InternalNode( next ).m_NextSibling;
+ }
+
+ LinkChildAfter( parent, after, elem );
+}
+
+
+//-----------------------------------------------------------------------------
+// Unlinks a node from the tree
+//-----------------------------------------------------------------------------
+template <class T, class I>
+void CUtlNTree<T,I>::Unlink( I elem )
+{
+ Assert( IsInTree(elem) );
+
+ Node_t *pOldNode = &InternalNode( elem );
+
+ // If we're the first guy, reset the head
+ // otherwise, make our previous node's next pointer = our next
+ if ( pOldNode->m_PrevSibling != INVALID_NTREE_IDX )
+ {
+ InternalNode( pOldNode->m_PrevSibling ).m_NextSibling = pOldNode->m_NextSibling;
+ }
+ else
+ {
+ if ( pOldNode->m_Parent != INVALID_NTREE_IDX )
+ {
+ InternalNode( pOldNode->m_Parent ).m_FirstChild = pOldNode->m_NextSibling;
+ }
+ else if ( m_Root == elem )
+ {
+ m_Root = pOldNode->m_NextSibling;
+ }
+ }
+
+ // If we're the last guy, reset the tail
+ // otherwise, make our next node's prev pointer = our prev
+ if ( pOldNode->m_NextSibling != INVALID_NTREE_IDX )
+ {
+ InternalNode( pOldNode->m_NextSibling ).m_PrevSibling = pOldNode->m_PrevSibling;
+ }
+
+ // Unlink everything except children
+ pOldNode->m_Parent = pOldNode->m_PrevSibling = pOldNode->m_NextSibling = INVALID_NTREE_IDX;
+}
+
+
+//-----------------------------------------------------------------------------
+// Alloc + link combined
+//-----------------------------------------------------------------------------
+template <class T, class I>
+I CUtlNTree<T,I>::InsertChildBefore( I parent, I before )
+{
+ I elem = AllocInternal();
+ Construct( &Element( elem ) );
+ LinkChildBefore( parent, before, elem );
+ return elem;
+}
+
+template <class T, class I>
+I CUtlNTree<T,I>::InsertChildAfter( I parent, I after )
+{
+ I elem = AllocInternal();
+ Construct( &Element( elem ) );
+ LinkChildAfter( parent, after, elem );
+ return elem;
+}
+
+template <class T, class I>
+I CUtlNTree<T,I>::InsertChildBefore( I parent, I before, const T &data )
+{
+ I elem = AllocInternal();
+ CopyConstruct( &Element( elem ), data );
+ LinkChildBefore( parent, before, elem );
+ return elem;
+}
+
+template <class T, class I>
+I CUtlNTree<T,I>::InsertChildAfter( I parent, I after, const T &data )
+{
+ I elem = AllocInternal();
+ CopyConstruct( &Element( elem ), data );
+ LinkChildAfter( parent, after, elem );
+ return elem;
+}
+
+
+//-----------------------------------------------------------------------------
+// Unlink + free combined
+//-----------------------------------------------------------------------------
+template <class T, class I>
+void CUtlNTree<T,I>::Remove( I elem )
+{
+ Unlink( elem );
+ Free( elem );
+}
+
+template <class T, class I>
+void CUtlNTree<T,I>::RemoveSubTree( I elem )
+{
+ UnlinkSubTree( elem );
+ Free( elem );
+}
+
+
+#endif // UTLNTREE_H
diff --git a/public/tier1/utlobjectreference.h b/public/tier1/utlobjectreference.h
new file mode 100644
index 0000000..da9d303
--- /dev/null
+++ b/public/tier1/utlobjectreference.h
@@ -0,0 +1,165 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// $Revision: $
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef UTLOBJECTREFERENCE_H
+#define UTLOBJECTREFERENCE_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier1/utlintrusivelist.h"
+#include "mathlib/mathlib.h"
+
+
+// Purpose: class for keeping track of all the references that exist to an object. When the object
+// being referenced is freed, all of the references pointing at it will become null.
+//
+// To Use:
+// Add a DECLARE_REFERENCED_CLASS to the class that you want to use CutlReferences with.
+// Replace pointers to that class with CUtlReferences.
+// Check these references for null in appropriate places.
+//
+// NOTE : You can still happily use pointers instead of references where you want to - these
+// pointers will not magically become null like references would, but if you know no one is going
+// to delete the underlying object during a partcular section of code, it doesn't
+// matter. Basically, CUtlReferences don't rely on every use of an object using one.
+
+
+
+
+template<class T> class CUtlReference
+{
+public:
+ FORCEINLINE CUtlReference(void)
+ {
+ m_pNext = m_pPrev = NULL;
+ m_pObject = NULL;
+ }
+
+ FORCEINLINE CUtlReference(T *pObj)
+ {
+ m_pNext = m_pPrev = NULL;
+ AddRef( pObj );
+ }
+
+ FORCEINLINE ~CUtlReference(void)
+ {
+ KillRef();
+ }
+
+ FORCEINLINE void Set(T *pObj)
+ {
+ if ( m_pObject != pObj )
+ {
+ KillRef();
+ AddRef( pObj );
+ }
+ }
+
+ FORCEINLINE T * operator()(void) const
+ {
+ return m_pObject;
+ }
+
+ FORCEINLINE operator T*()
+ {
+ return m_pObject;
+ }
+
+ FORCEINLINE operator const T*() const
+ {
+ return m_pObject;
+ }
+
+ FORCEINLINE T* operator->()
+ {
+ return m_pObject;
+ }
+
+ FORCEINLINE const T* operator->() const
+ {
+ return m_pObject;
+ }
+
+ FORCEINLINE CUtlReference &operator=( const CUtlReference& otherRef )
+ {
+ Set( otherRef.m_pObject );
+ return *this;
+ }
+
+ FORCEINLINE CUtlReference &operator=( T *pObj )
+ {
+ Set( pObj );
+ return *this;
+ }
+
+
+ FORCEINLINE bool operator==( const CUtlReference& o ) const
+ {
+ return ( o.m_pObject == m_pObject );
+ }
+
+public:
+ CUtlReference *m_pNext;
+ CUtlReference *m_pPrev;
+
+ T *m_pObject;
+
+ FORCEINLINE void AddRef( T *pObj )
+ {
+ m_pObject = pObj;
+ if ( pObj )
+ {
+ pObj->m_References.AddToHead( this );
+ }
+ }
+
+ FORCEINLINE void KillRef(void)
+ {
+ if ( m_pObject )
+ {
+ m_pObject->m_References.RemoveNode( this );
+ m_pObject = NULL;
+ }
+ }
+
+};
+
+template<class T> class CUtlReferenceList : public CUtlIntrusiveDList< CUtlReference<T> >
+{
+public:
+ ~CUtlReferenceList( void )
+ {
+ CUtlReference<T> *i = CUtlIntrusiveDList<CUtlReference<T> >::m_pHead;
+ while( i )
+ {
+ CUtlReference<T> *n = i->m_pNext;
+ i->m_pNext = NULL;
+ i->m_pPrev = NULL;
+ i->m_pObject = NULL;
+ i = n;
+ }
+ CUtlIntrusiveDList<CUtlReference<T> >::m_pHead = NULL;
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// Put this macro in classes that are referenced by CUtlReference
+//-----------------------------------------------------------------------------
+#define DECLARE_REFERENCED_CLASS( _className ) \
+ private: \
+ CUtlReferenceList< _className > m_References; \
+ template<class T> friend class CUtlReference;
+
+
+#endif
+
+
+
+
+
diff --git a/public/tier1/utlpair.h b/public/tier1/utlpair.h
new file mode 100644
index 0000000..d306f32
--- /dev/null
+++ b/public/tier1/utlpair.h
@@ -0,0 +1,52 @@
+//========= Copyright, Valve Corporation, All rights reserved. ================//
+//
+// std::pair style container; exists to work easily in our CUtlMap/CUtlHashMap classes
+//
+//=============================================================================//
+
+#ifndef UTLPAIR_H
+#define UTLPAIR_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+// std::pair style container; exists to work easily in our CUtlMap/CUtlHashMap classes
+template<typename T1, typename T2>
+class CUtlPair
+{
+public:
+ CUtlPair() {}
+ CUtlPair( T1 t1, T2 t2 ) : first( t1 ), second( t2 ) {}
+
+ bool operator<( const CUtlPair<T1,T2> &rhs ) const {
+ if ( first != rhs.first )
+ return first < rhs.first;
+ return second < rhs.second;
+ }
+
+ bool operator==( const CUtlPair<T1,T2> &rhs ) const {
+ return first == rhs.first && second == rhs.second;
+ }
+
+ T1 first;
+ T2 second;
+};
+
+// utility to make a CUtlPair without having to specify template parameters
+template<typename T1, typename T2>
+inline CUtlPair<T1,T2> MakeUtlPair( T1 t1, T2 t2 )
+{
+ return CUtlPair<T1,T2>(t1, t2);
+}
+
+//// HashItem() overload that works automatically with our hash containers
+//template<typename T1, typename T2>
+//inline uint32 HashItem( const CUtlPair<T1,T2> &item )
+//{
+// return HashItem( (uint64)HashItem( item.first ) + ((uint64)HashItem( item.second ) << 32) );
+//}
+
+
+#endif // UTLPAIR_H
diff --git a/public/tier1/utlpriorityqueue.h b/public/tier1/utlpriorityqueue.h
new file mode 100644
index 0000000..8d3f457
--- /dev/null
+++ b/public/tier1/utlpriorityqueue.h
@@ -0,0 +1,198 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef UTLPRIORITYQUEUE_H
+#define UTLPRIORITYQUEUE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "utlvector.h"
+
+// T is the type stored in the queue, it must include the priority
+// The head of the list contains the element with GREATEST priority
+// configure the LessFunc_t to get the desired queue order
+template< class T >
+class CUtlPriorityQueue
+{
+public:
+ // Less func typedef
+ // Returns true if the first parameter is "less priority" than the second
+ // Items that are "less priority" sort toward the tail of the queue
+ typedef bool (*LessFunc_t)( T const&, T const& );
+
+ typedef T ElemType_t;
+
+ // constructor: lessfunc is required, but may be set after the constructor with
+ // SetLessFunc
+ CUtlPriorityQueue( int growSize = 0, int initSize = 0, LessFunc_t lessfunc = 0 );
+ CUtlPriorityQueue( T *pMemory, int numElements, LessFunc_t lessfunc = 0 );
+
+ // gets particular elements
+ inline T const& ElementAtHead() const { return m_heap.Element(0); }
+
+ inline bool IsValidIndex(int index) { return m_heap.IsValidIndex(index); }
+
+ // O(lgn) to rebalance the heap
+ void RemoveAtHead();
+ void RemoveAt( int index );
+
+ // O(lgn) to rebalance heap
+ void Insert( T const &element );
+ // Sets the less func
+ void SetLessFunc( LessFunc_t func );
+
+ // Returns the count of elements in the queue
+ inline int Count() const { return m_heap.Count(); }
+
+ // doesn't deallocate memory
+ void RemoveAll() { m_heap.RemoveAll(); }
+
+ // Memory deallocation
+ void Purge() { m_heap.Purge(); }
+
+ inline const T & Element( int index ) const { return m_heap.Element(index); }
+
+protected:
+ CUtlVector<T> m_heap;
+
+ void Swap( int index1, int index2 );
+
+ // Used for sorting.
+ LessFunc_t m_LessFunc;
+};
+
+template< class T >
+inline CUtlPriorityQueue<T>::CUtlPriorityQueue( int growSize, int initSize, LessFunc_t lessfunc ) :
+ m_heap(growSize, initSize), m_LessFunc(lessfunc)
+{
+}
+
+template< class T >
+inline CUtlPriorityQueue<T>::CUtlPriorityQueue( T *pMemory, int numElements, LessFunc_t lessfunc ) :
+ m_heap(pMemory, numElements), m_LessFunc(lessfunc)
+{
+}
+
+template <class T>
+void CUtlPriorityQueue<T>::RemoveAtHead()
+{
+ m_heap.FastRemove( 0 );
+ int index = 0;
+
+ int count = Count();
+ if ( !count )
+ return;
+
+ int half = count/2;
+ int larger = index;
+ while ( index < half )
+ {
+ int child = ((index+1) * 2) - 1; // if we wasted an element, this math would be more compact (1 based array)
+ if ( child < count )
+ {
+ // Item has been filtered down to its proper place, terminate.
+ if ( m_LessFunc( m_heap[index], m_heap[child] ) )
+ {
+ // mark the potential swap and check the other child
+ larger = child;
+ }
+ }
+ // go to sibling
+ child++;
+ if ( child < count )
+ {
+ // If this child is larger, swap it instead
+ if ( m_LessFunc( m_heap[larger], m_heap[child] ) )
+ larger = child;
+ }
+
+ if ( larger == index )
+ break;
+
+ // swap with the larger child
+ Swap( index, larger );
+ index = larger;
+ }
+}
+
+
+template <class T>
+void CUtlPriorityQueue<T>::RemoveAt( int index )
+{
+ Assert(m_heap.IsValidIndex(index));
+ m_heap.FastRemove( index );
+
+ int count = Count();
+ if ( !count )
+ return;
+
+ int half = count/2;
+ int larger = index;
+ while ( index < half )
+ {
+ int child = ((index+1) * 2) - 1; // if we wasted an element, this math would be more compact (1 based array)
+ if ( child < count )
+ {
+ // Item has been filtered down to its proper place, terminate.
+ if ( m_LessFunc( m_heap[index], m_heap[child] ) )
+ {
+ // mark the potential swap and check the other child
+ larger = child;
+ }
+ }
+ // go to sibling
+ child++;
+ if ( child < count )
+ {
+ // If this child is larger, swap it instead
+ if ( m_LessFunc( m_heap[larger], m_heap[child] ) )
+ larger = child;
+ }
+
+ if ( larger == index )
+ break;
+
+ // swap with the larger child
+ Swap( index, larger );
+ index = larger;
+ }
+}
+
+template <class T>
+void CUtlPriorityQueue<T>::Insert( T const &element )
+{
+ int index = m_heap.AddToTail();
+ m_heap[index] = element;
+
+ while ( index != 0 )
+ {
+ int parent = ((index+1) / 2) - 1;
+ if ( m_LessFunc( m_heap[index], m_heap[parent] ) )
+ break;
+
+ // swap with parent and repeat
+ Swap( parent, index );
+ index = parent;
+ }
+}
+
+template <class T>
+void CUtlPriorityQueue<T>::Swap( int index1, int index2 )
+{
+ T tmp = m_heap[index1];
+ m_heap[index1] = m_heap[index2];
+ m_heap[index2] = tmp;
+}
+
+template <class T>
+void CUtlPriorityQueue<T>::SetLessFunc( LessFunc_t lessfunc )
+{
+ m_LessFunc = lessfunc;
+}
+
+#endif // UTLPRIORITYQUEUE_H
diff --git a/public/tier1/utlqueue.h b/public/tier1/utlqueue.h
new file mode 100644
index 0000000..05c89ee
--- /dev/null
+++ b/public/tier1/utlqueue.h
@@ -0,0 +1,551 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef UTLQUEUE_H
+#define UTLQUEUE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "utlmemory.h"
+
+//#define TEST_UTLQUEUE
+
+enum QueueIter_t { QUEUE_ITERATOR_INVALID = 0xffffffff };
+
+// T is the type stored in the queue
+template< class T, class M = CUtlMemory< T > >
+class CUtlQueue
+{
+public:
+
+ CUtlQueue( int growSize = 0, int initSize = 0 );
+ CUtlQueue( T *pMemory, int numElements );
+
+ // return the item from the front of the queue and delete it
+ T RemoveAtHead();
+ bool RemoveAtHead( T &removedElement );
+
+ // return the item from the end of the queue and delete it
+ T RemoveAtTail();
+ bool RemoveAtTail( T &removedElement );
+
+ // return item at the front of the queue
+ T const& Head() const;
+ // return item at the end of the queue
+ T const& Tail() const;
+
+ // Add a new item to the end of the queue
+ void Insert( T const &element );
+
+ // checks if an element of this value already exists on the stack, returns true if it does
+ bool Check( T const element ) const;
+
+ // iterators may be invalidated by Insert()
+ QueueIter_t First() const;
+ QueueIter_t Next( QueueIter_t it ) const;
+ QueueIter_t Last() const;
+ QueueIter_t Previous( QueueIter_t it ) const;
+ bool IsValid( QueueIter_t it ) const;
+ T const& Element( QueueIter_t it ) const;
+
+ // Returns the count of elements in the queue
+ int Count() const;
+
+ // Return whether the queue is empty or not, faster than Count().
+ bool IsEmpty() const;
+
+ // doesn't deallocate memory
+ void RemoveAll();
+
+ // Memory deallocation
+ void Purge();
+
+protected:
+ QueueIter_t Next_Unchecked( QueueIter_t it ) const;
+ QueueIter_t Previous_Unchecked( QueueIter_t it ) const;
+
+ M m_memory;
+
+ // if m_head == m_tail == QUEUE_ITERATOR_INVALID, then the queue is empty
+ QueueIter_t m_head;
+ QueueIter_t m_tail;
+
+#ifdef TEST_UTLQUEUE
+ friend void CUtlQueue_Test();
+#endif
+};
+
+//-----------------------------------------------------------------------------
+// The CUtlQueueFixed class:
+// A queue class with a fixed allocation scheme
+//-----------------------------------------------------------------------------
+template< class T, size_t MAX_SIZE >
+class CUtlQueueFixed : public CUtlQueue< T, CUtlMemoryFixed<T, MAX_SIZE > >
+{
+ typedef CUtlQueue< T, CUtlMemoryFixed<T, MAX_SIZE > > BaseClass;
+public:
+
+ // constructor, destructor
+ CUtlQueueFixed( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {}
+ CUtlQueueFixed( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {}
+};
+
+template< class T, class M >
+inline CUtlQueue<T, M>::CUtlQueue( int growSize, int initSize ) :
+ m_memory( growSize, initSize ), m_head( QUEUE_ITERATOR_INVALID ), m_tail( QUEUE_ITERATOR_INVALID )
+{
+}
+
+template< class T, class M >
+inline CUtlQueue<T, M>::CUtlQueue( T *pMemory, int numElements ) :
+ m_memory( pMemory, numElements ), m_head( QUEUE_ITERATOR_INVALID ), m_tail( QUEUE_ITERATOR_INVALID )
+{
+}
+
+template <class T, class M>
+inline T CUtlQueue<T, M>::RemoveAtHead()
+{
+ T temp;
+ RemoveAtHead( temp );
+ return temp;
+}
+
+template <class T, class M>
+inline bool CUtlQueue<T, M>::RemoveAtHead( T &removedElement )
+{
+ Assert( m_head != QUEUE_ITERATOR_INVALID );
+ if ( m_head == QUEUE_ITERATOR_INVALID )
+ {
+ Construct( &removedElement );
+ return false;
+ }
+
+ QueueIter_t it = m_head;
+ removedElement = m_memory[ it ];
+ Destruct( &m_memory[ it ] );
+ if ( m_head == m_tail )
+ {
+ m_head = m_tail = QUEUE_ITERATOR_INVALID;
+ }
+ else
+ {
+ m_head = Next_Unchecked( m_head );
+ }
+ return true;
+}
+
+template <class T, class M>
+inline T CUtlQueue<T, M>::RemoveAtTail()
+{
+ T temp;
+ RemoveAtTail( temp );
+ return temp;
+}
+
+template <class T, class M>
+inline bool CUtlQueue<T, M>::RemoveAtTail( T &removedElement )
+{
+ Assert( m_tail != QUEUE_ITERATOR_INVALID );
+ if ( m_tail == QUEUE_ITERATOR_INVALID )
+ {
+ Construct( &removedElement );
+ return false;
+ }
+
+ removedElement = m_memory[ m_tail ];
+ Destruct( &m_memory[ m_tail ] );
+ if ( m_head == m_tail )
+ {
+ m_head = m_tail = QUEUE_ITERATOR_INVALID;
+ }
+ else
+ {
+ m_tail = Previous_Unchecked( m_tail );
+ }
+ return true;
+}
+
+template <class T, class M>
+inline T const& CUtlQueue<T, M>::Head() const
+{
+ Assert( m_head != QUEUE_ITERATOR_INVALID );
+ if ( m_head == QUEUE_ITERATOR_INVALID )
+ {
+ static T dummy;
+ return dummy;
+ }
+
+ return m_memory[ m_head ];
+}
+
+template <class T, class M>
+inline T const& CUtlQueue<T, M>::Tail() const
+{
+ Assert( m_tail != QUEUE_ITERATOR_INVALID );
+ if ( m_tail == QUEUE_ITERATOR_INVALID )
+ {
+ static T dummy;
+ return dummy;
+ }
+
+ return m_memory[ m_tail ];
+}
+
+template <class T, class M>
+void CUtlQueue<T, M>::Insert( T const &element )
+{
+ if ( m_tail == QUEUE_ITERATOR_INVALID )
+ {
+ // empty
+ m_memory.EnsureCapacity( 1 );
+ m_head = m_tail = QueueIter_t( 0 );
+ }
+ else
+ {
+ // non-empty
+ QueueIter_t nextTail = Next_Unchecked( m_tail );
+ if ( nextTail == m_head ) // if non-empty, and growing by 1 appears to make the queue of length 1, then we were already full before the Insert
+ {
+ int nOldAllocCount = m_memory.NumAllocated();
+ m_memory.Grow();
+ int nNewAllocCount = m_memory.NumAllocated();
+ int nGrowAmount = nNewAllocCount - nOldAllocCount;
+
+ nextTail = Next_Unchecked( m_tail ); // if nextTail was 0, then it now should be nOldAllocCount
+
+ if ( m_head != QueueIter_t( 0 ) )
+ {
+ // if the queue wraps around the end of m_memory, move the part at the end of memory to the new end of memory
+ Q_memmove( &m_memory[ m_head + nGrowAmount ], &m_memory[ m_head ], ( nOldAllocCount - m_head ) * sizeof( T ) );
+#ifdef _DEBUG
+ Q_memset( &m_memory[ m_head ], 0xdd, nGrowAmount * sizeof( T ) );
+#endif
+ m_head = QueueIter_t( m_head + nGrowAmount );
+ }
+ }
+ m_tail = nextTail;
+ }
+
+ CopyConstruct( &m_memory[ m_tail ], element );
+}
+
+template <class T, class M>
+bool CUtlQueue<T, M>::Check( T const element ) const
+{
+ for ( QueueIter_t it = First(); it != QUEUE_ITERATOR_INVALID; it = Next( it ) )
+ {
+ if ( m_memory[ it ] == element )
+ return true;
+ }
+ return false;
+}
+
+template <class T, class M>
+QueueIter_t CUtlQueue<T, M>::First() const
+{
+ return m_head;
+}
+
+template <class T, class M>
+QueueIter_t CUtlQueue<T, M>::Next( QueueIter_t it ) const
+{
+ if ( it == QUEUE_ITERATOR_INVALID )
+ return QUEUE_ITERATOR_INVALID;
+
+ if ( it == m_tail )
+ return QUEUE_ITERATOR_INVALID;
+
+ Assert( IsValid( it ) );
+ if ( !IsValid( it ) )
+ return QUEUE_ITERATOR_INVALID;
+
+ return Next_Unchecked( it );
+}
+
+template <class T, class M>
+QueueIter_t CUtlQueue<T, M>::Last() const
+{
+ return m_tail;
+}
+
+template <class T, class M>
+QueueIter_t CUtlQueue<T, M>::Previous( QueueIter_t it ) const
+{
+ if ( it == QUEUE_ITERATOR_INVALID )
+ return QUEUE_ITERATOR_INVALID;
+
+ if ( it == m_head )
+ return QUEUE_ITERATOR_INVALID;
+
+ Assert( IsValid( it ) );
+ if ( !IsValid( it ) )
+ return QUEUE_ITERATOR_INVALID;
+
+ return Previous_Unchecked( it );
+}
+
+template <class T, class M>
+QueueIter_t CUtlQueue<T, M>::Next_Unchecked( QueueIter_t it ) const
+{
+ return it == m_memory.Count() - 1 ? QueueIter_t( 0 ) : QueueIter_t( it + 1 );
+}
+
+template <class T, class M>
+QueueIter_t CUtlQueue<T, M>::Previous_Unchecked( QueueIter_t it ) const
+{
+ return it == 0 ? QueueIter_t( m_memory.Count() - 1 ) : QueueIter_t( it - 1 );
+}
+
+template <class T, class M>
+bool CUtlQueue<T, M>::IsValid( QueueIter_t it ) const
+{
+ if ( it == QUEUE_ITERATOR_INVALID )
+ return false;
+
+ if ( m_head == QUEUE_ITERATOR_INVALID )
+ return false;
+
+ if ( m_head <= m_tail )
+ return it >= m_head && it <= m_tail;
+
+ return ( it >= m_head && it < m_memory.Count() ) || ( it >= 0 && it <= m_tail );
+}
+
+template <class T, class M>
+T const& CUtlQueue<T, M>::Element( QueueIter_t it ) const
+{
+ Assert( it != QUEUE_ITERATOR_INVALID );
+ if ( it == QUEUE_ITERATOR_INVALID )
+ {
+ static T dummy;
+ return dummy;
+ }
+
+ Assert( IsValid( it ) );
+ return m_memory[ it ];
+}
+
+template <class T, class M>
+int CUtlQueue<T, M>::Count() const
+{
+ if ( m_head == QUEUE_ITERATOR_INVALID )
+ {
+ Assert( m_tail == QUEUE_ITERATOR_INVALID );
+ return 0;
+ }
+ Assert( m_tail != QUEUE_ITERATOR_INVALID );
+
+ if ( m_head <= m_tail )
+ return m_tail + 1 - m_head;
+
+ return m_tail + 1 - m_head + m_memory.Count();
+}
+
+template <class T, class M>
+bool CUtlQueue<T, M>::IsEmpty() const
+{
+ Assert( ( m_head == QUEUE_ITERATOR_INVALID ) == ( m_tail == QUEUE_ITERATOR_INVALID ) );
+ return ( m_head == QUEUE_ITERATOR_INVALID );
+}
+
+template <class T, class M>
+void CUtlQueue<T, M>::RemoveAll()
+{
+ m_head = m_tail = QUEUE_ITERATOR_INVALID;
+}
+
+template <class T, class M>
+void CUtlQueue<T, M>::Purge()
+{
+ m_head = m_tail = QUEUE_ITERATOR_INVALID;
+ m_memory.Purge();
+}
+
+
+#ifdef TEST_UTLQUEUE
+
+#include <stdlib.h>
+
+struct Data_t
+{
+ Data_t( int i = 0xffffffff ) : m_id( i ) {}
+ Data_t( const Data_t &that ) : m_id( that.m_id ) {}
+ ~Data_t() { m_id = 0xdddddddd; }
+ Data_t &operator=( const Data_t &that ) { m_id = that.m_id; return *this; }
+
+ int m_id;
+};
+
+inline void CUtlQueue_Test()
+{
+ CUtlQueue< Data_t > queue;
+
+ for ( int n = 1; n < 100; ++n )
+ {
+ Assert( queue.Count() == 0 );
+ Assert( queue.m_head == QUEUE_ITERATOR_INVALID );
+ Assert( queue.m_tail == QUEUE_ITERATOR_INVALID );
+
+ int w = rand() % n;
+ for ( int i = 0; i < w; ++i )
+ {
+ queue.Insert( Data_t( i ) );
+ }
+
+ if ( w > 0 )
+ {
+ Assert( queue.Head().m_id == queue.First() );
+ Assert( queue.Tail().m_id == queue.Last() );
+ Assert( queue.Head().m_id == 0 );
+ Assert( queue.Tail().m_id == w - 1 );
+ }
+ Assert( queue.Count() == w );
+
+ for ( int j = 0; j < n; ++j )
+ {
+ queue.Insert( Data_t( w + j ) );
+
+ if ( j == 0 )
+ {
+ Assert( queue.Count() == w + j + 1 );
+
+ for ( int i = 0; i < w; ++i )
+ {
+ queue.RemoveAtHead();
+ }
+ }
+
+ Assert( queue.Count() == j + 1 );
+
+ Assert( queue.m_head != QUEUE_ITERATOR_INVALID );
+ Assert( queue.m_tail != QUEUE_ITERATOR_INVALID );
+
+ int id = queue.Head().m_id % queue.m_memory.Count();
+ for ( QueueIter_t it = queue.First(); it != QUEUE_ITERATOR_INVALID; it = queue.Next( it ) )
+ {
+ Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id );
+ id = ( id + 1 ) % queue.m_memory.Count();
+ }
+
+ id = queue.Tail().m_id % queue.m_memory.Count();
+ for ( QueueIter_t it = queue.Last(); it != QUEUE_ITERATOR_INVALID; it = queue.Previous( it ) )
+ {
+ Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id );
+ id = ( id + queue.m_memory.Count() - 1 ) % queue.m_memory.Count();
+ }
+
+ for ( int i = 0; i < j; ++i )
+ {
+ int id = queue.m_memory[ i ].m_id;
+ if ( queue.IsValid( QueueIter_t( i ) ) )
+ {
+ Assert( ( id & 0xff000000 ) == 0 );
+ }
+ else
+ {
+ Assert( id == 0xdddddddd );
+ }
+ }
+ }
+
+ Assert( queue.Count() == n );
+#if 0
+ for ( int j = 0; j < n; ++j )
+ {
+ Assert( queue.m_head != QUEUE_ITERATOR_INVALID );
+ Assert( queue.m_tail != QUEUE_ITERATOR_INVALID );
+
+ Assert( queue.Count() == n - j );
+
+ Data_t data = queue.RemoveAtHead();
+
+ Assert( queue.Count() == n - j - 1 );
+
+ if ( queue.Count() > 0 )
+ {
+ int id = queue.Head().m_id % queue.m_memory.Count();
+ for ( QueueIter_t it = queue.First(); it != QUEUE_ITERATOR_INVALID; it = queue.Next( it ) )
+ {
+ Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id );
+ id = ( id + 1 ) % queue.m_memory.Count();
+ }
+
+ id = queue.Tail().m_id % queue.m_memory.Count();
+ for ( QueueIter_t it = queue.Last(); it != QUEUE_ITERATOR_INVALID; it = queue.Previous( it ) )
+ {
+ Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id );
+ id = ( id + queue.m_memory.Count() - 1 ) % queue.m_memory.Count();
+ }
+ }
+
+ for ( int i = 0; i < j; ++i )
+ {
+ int id = queue.m_memory[ i ].m_id;
+ if ( queue.IsValid( QueueIter_t( i ) ) )
+ {
+ Assert( ( id & 0xff000000 ) == 0 );
+ }
+ else
+ {
+ Assert( id == 0xdddddddd );
+ }
+ }
+ }
+#else
+ for ( int j = n - 1; j >= 0; --j )
+ {
+ Assert( queue.m_head != QUEUE_ITERATOR_INVALID );
+ Assert( queue.m_tail != QUEUE_ITERATOR_INVALID );
+
+ Assert( queue.Count() == j + 1 );
+
+ Data_t data = queue.RemoveAtTail();
+
+ Assert( queue.Count() == j );
+
+ if ( queue.Count() > 0 )
+ {
+ int id = queue.Head().m_id % queue.m_memory.Count();
+ for ( QueueIter_t it = queue.First(); it != QUEUE_ITERATOR_INVALID; it = queue.Next( it ) )
+ {
+ Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id );
+ id = ( id + 1 ) % queue.m_memory.Count();
+ }
+
+ id = queue.Tail().m_id % queue.m_memory.Count();
+ for ( QueueIter_t it = queue.Last(); it != QUEUE_ITERATOR_INVALID; it = queue.Previous( it ) )
+ {
+ Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id );
+ id = ( id + queue.m_memory.Count() - 1 ) % queue.m_memory.Count();
+ }
+ }
+
+ for ( int i = 0; i < j; ++i )
+ {
+ int id = queue.m_memory[ i ].m_id;
+ if ( queue.IsValid( QueueIter_t( i ) ) )
+ {
+ Assert( ( id & 0xff000000 ) == 0 );
+ }
+ else
+ {
+ Assert( id == 0xdddddddd );
+ }
+ }
+ }
+#endif
+
+ Assert( queue.Count() == 0 );
+ Assert( queue.m_head == QUEUE_ITERATOR_INVALID );
+ Assert( queue.m_tail == QUEUE_ITERATOR_INVALID );
+ }
+}
+
+#endif // TEST_UTLQUEUE
+
+#endif // UTLQUEUE_H
diff --git a/public/tier1/utlrbtree.h b/public/tier1/utlrbtree.h
new file mode 100644
index 0000000..745c162
--- /dev/null
+++ b/public/tier1/utlrbtree.h
@@ -0,0 +1,1593 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Header: $
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef UTLRBTREE_H
+#define UTLRBTREE_H
+
+#include "tier1/utlmemory.h"
+#include "tier1/utlfixedmemory.h"
+#include "tier1/utlblockmemory.h"
+#include "tier1/strtools.h"
+
+//-----------------------------------------------------------------------------
+// Tool to generate a default compare function for any type that implements
+// operator<, including all simple types
+//-----------------------------------------------------------------------------
+
+template <typename T >
+class CDefOps
+{
+public:
+ static bool LessFunc( const T &lhs, const T &rhs ) { return ( lhs < rhs ); }
+};
+
+#define DefLessFunc( type ) CDefOps< type >::LessFunc
+
+template <typename T>
+class CDefLess
+{
+public:
+ CDefLess() {}
+ CDefLess( int i ) {}
+ inline bool operator()( const T &lhs, const T &rhs ) const { return ( lhs < rhs ); }
+ inline bool operator!() const { return false; }
+};
+
+//-------------------------------------
+
+inline bool StringLessThan( const char * const &lhs, const char * const &rhs) {
+ if ( !lhs ) return false;
+ if ( !rhs ) return true;
+ return ( V_strcmp( lhs, rhs) < 0 );
+}
+
+inline bool CaselessStringLessThan( const char * const &lhs, const char * const &rhs ) {
+ if ( !lhs ) return false;
+ if ( !rhs ) return true;
+ return ( V_stricmp( lhs, rhs) < 0 );
+}
+
+
+// Same as CaselessStringLessThan, but it ignores differences in / and \.
+inline bool CaselessStringLessThanIgnoreSlashes( const char * const &lhs, const char * const &rhs )
+{
+ const char *pa = lhs;
+ const char *pb = rhs;
+ while ( *pa && *pb )
+ {
+ char a = *pa;
+ char b = *pb;
+
+ // Check for dir slashes.
+ if ( a == '/' || a == '\\' )
+ {
+ if ( b != '/' && b != '\\' )
+ return ('/' < b);
+ }
+ else
+ {
+ if ( a >= 'a' && a <= 'z' )
+ a = 'A' + (a - 'a');
+
+ if ( b >= 'a' && b <= 'z' )
+ b = 'A' + (b - 'a');
+
+ if ( a > b )
+ return false;
+ else if ( a < b )
+ return true;
+ }
+ ++pa;
+ ++pb;
+ }
+
+ // Filenames also must be the same length.
+ if ( *pa != *pb )
+ {
+ // If pa shorter than pb then it's "less"
+ return ( !*pa );
+ }
+
+ return false;
+}
+
+//-------------------------------------
+// inline these two templates to stop multiple definitions of the same code
+template <> inline bool CDefOps<const char *>::LessFunc( const char * const &lhs, const char * const &rhs ) { return StringLessThan( lhs, rhs ); }
+template <> inline bool CDefOps<char *>::LessFunc( char * const &lhs, char * const &rhs ) { return StringLessThan( lhs, rhs ); }
+
+//-------------------------------------
+
+template <typename RBTREE_T>
+void SetDefLessFunc( RBTREE_T &RBTree )
+{
+ RBTree.SetLessFunc( DefLessFunc( typename RBTREE_T::KeyType_t ) );
+}
+
+//-----------------------------------------------------------------------------
+// A red-black binary search tree
+//-----------------------------------------------------------------------------
+
+template < class I >
+struct UtlRBTreeLinks_t
+{
+ I m_Left;
+ I m_Right;
+ I m_Parent;
+ I m_Tag;
+};
+
+template < class T, class I >
+struct UtlRBTreeNode_t : public UtlRBTreeLinks_t< I >
+{
+ T m_Data;
+};
+
+template < class T, class I = unsigned short, typename L = bool (*)( const T &, const T & ), class M = CUtlMemory< UtlRBTreeNode_t< T, I >, I > >
+class CUtlRBTree
+{
+public:
+
+ typedef T KeyType_t;
+ typedef T ElemType_t;
+ typedef I IndexType_t;
+
+ // Less func typedef
+ // Returns true if the first parameter is "less" than the second
+ typedef L LessFunc_t;
+
+ // constructor, destructor
+ // Left at growSize = 0, the memory will first allocate 1 element and double in size
+ // at each increment.
+ // LessFunc_t is required, but may be set after the constructor using SetLessFunc() below
+ CUtlRBTree( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 );
+ CUtlRBTree( const LessFunc_t &lessfunc );
+ ~CUtlRBTree( );
+
+ void EnsureCapacity( int num );
+
+ void CopyFrom( const CUtlRBTree<T, I, L, M> &other );
+
+ // gets particular elements
+ T& Element( I i );
+ T const &Element( I i ) const;
+ T& operator[]( I i );
+ T const &operator[]( I i ) const;
+
+ // Gets the root
+ I Root() const;
+
+ // Num elements
+ unsigned int Count() const;
+
+ // Max "size" of the vector
+ // it's not generally safe to iterate from index 0 to MaxElement()-1
+ // it IS safe to do so when using CUtlMemory as the allocator,
+ // but we should really remove patterns using this anyways, for safety and generality
+ I MaxElement() const;
+
+ // Gets the children
+ I Parent( I i ) const;
+ I LeftChild( I i ) const;
+ I RightChild( I i ) const;
+
+ // Tests if a node is a left or right child
+ bool IsLeftChild( I i ) const;
+ bool IsRightChild( I i ) const;
+
+ // Tests if root or leaf
+ bool IsRoot( I i ) const;
+ bool IsLeaf( I i ) const;
+
+ // Checks if a node is valid and in the tree
+ bool IsValidIndex( I i ) const;
+
+ // Checks if the tree as a whole is valid
+ bool IsValid() const;
+
+ // Invalid index
+ static I InvalidIndex();
+
+ // returns the tree depth (not a very fast operation)
+ int Depth( I node ) const;
+ int Depth() const;
+
+ // Sets the less func
+ void SetLessFunc( const LessFunc_t &func );
+
+ // Allocation method
+ I NewNode();
+
+ // Insert method (inserts in order)
+ I Insert( T const &insert );
+ void Insert( const T *pArray, int nItems );
+ I InsertIfNotFound( T const &insert );
+
+ // Find method
+ I Find( T const &search ) const;
+
+ // Remove methods
+ void RemoveAt( I i );
+ bool Remove( T const &remove );
+ void RemoveAll( );
+ void Purge();
+
+ bool HasElement( T const &search ) const { return Find( search ) != InvalidIndex(); }
+
+ // Allocation, deletion
+ void FreeNode( I i );
+
+ // Iteration
+ I FirstInorder() const;
+ I NextInorder( I i ) const;
+ I PrevInorder( I i ) const;
+ I LastInorder() const;
+
+ I FirstPreorder() const;
+ I NextPreorder( I i ) const;
+ I PrevPreorder( I i ) const;
+ I LastPreorder( ) const;
+
+ I FirstPostorder() const;
+ I NextPostorder( I i ) const;
+
+ // If you change the search key, this can be used to reinsert the
+ // element into the tree.
+ void Reinsert( I elem );
+
+ // swap in place
+ void Swap( CUtlRBTree< T, I, L > &that );
+
+private:
+ // Can't copy the tree this way!
+ CUtlRBTree<T, I, L, M>& operator=( const CUtlRBTree<T, I, L, M> &other );
+
+protected:
+ enum NodeColor_t
+ {
+ RED = 0,
+ BLACK
+ };
+
+ typedef UtlRBTreeNode_t< T, I > Node_t;
+ typedef UtlRBTreeLinks_t< I > Links_t;
+
+ // Sets the children
+ void SetParent( I i, I parent );
+ void SetLeftChild( I i, I child );
+ void SetRightChild( I i, I child );
+ void LinkToParent( I i, I parent, bool isLeft );
+
+ // Gets at the links
+ Links_t const &Links( I i ) const;
+ Links_t &Links( I i );
+
+ // Checks if a link is red or black
+ bool IsRed( I i ) const;
+ bool IsBlack( I i ) const;
+
+ // Sets/gets node color
+ NodeColor_t Color( I i ) const;
+ void SetColor( I i, NodeColor_t c );
+
+ // operations required to preserve tree balance
+ void RotateLeft(I i);
+ void RotateRight(I i);
+ void InsertRebalance(I i);
+ void RemoveRebalance(I i);
+
+ // Insertion, removal
+ I InsertAt( I parent, bool leftchild );
+
+ // copy constructors not allowed
+ CUtlRBTree( CUtlRBTree<T, I, L, M> const &tree );
+
+ // Inserts a node into the tree, doesn't copy the data in.
+ void FindInsertionPosition( T const &insert, I &parent, bool &leftchild );
+
+ // Remove and add back an element in the tree.
+ void Unlink( I elem );
+ void Link( I elem );
+
+ // Used for sorting.
+ LessFunc_t m_LessFunc;
+
+ M m_Elements;
+ I m_Root;
+ I m_NumElements;
+ I m_FirstFree;
+ typename M::Iterator_t m_LastAlloc; // the last index allocated
+
+ Node_t* m_pElements;
+
+ FORCEINLINE M const &Elements( void ) const
+ {
+ return m_Elements;
+ }
+
+
+ void ResetDbgInfo()
+ {
+ m_pElements = (Node_t*)m_Elements.Base();
+ }
+};
+
+// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice
+template < class T, class I = int, typename L = bool (*)( const T &, const T & ) >
+class CUtlFixedRBTree : public CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > >
+{
+public:
+
+ typedef L LessFunc_t;
+
+ CUtlFixedRBTree( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 )
+ : CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > >( growSize, initSize, lessfunc ) {}
+ CUtlFixedRBTree( const LessFunc_t &lessfunc )
+ : CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > >( lessfunc ) {}
+
+ typedef CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > > BaseClass;
+ bool IsValidIndex( I i ) const
+ {
+ if ( !BaseClass::Elements().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 MaxElement()
+ if ( BaseClass::Elements().IsIdxAfter( i, this->m_LastAlloc ) )
+ {
+ Assert( 0 );
+ return false; // don't read values that have been allocated, but not constructed
+ }
+#endif
+
+ return LeftChild(i) != i;
+ }
+
+protected:
+ void ResetDbgInfo() {}
+
+private:
+ // this doesn't make sense for fixed rbtrees, since there's no useful max pointer, and the index space isn't contiguous anyways
+ I MaxElement() const;
+};
+
+// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice
+template < class T, class I = unsigned short, typename L = bool (*)( const T &, const T & ) >
+class CUtlBlockRBTree : public CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > >
+{
+public:
+ typedef L LessFunc_t;
+ CUtlBlockRBTree( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 )
+ : CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > >( growSize, initSize, lessfunc ) {}
+ CUtlBlockRBTree( const LessFunc_t &lessfunc )
+ : CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > >( lessfunc ) {}
+protected:
+ void ResetDbgInfo() {}
+};
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline CUtlRBTree<T, I, L, M>::CUtlRBTree( int growSize, int initSize, const LessFunc_t &lessfunc ) :
+m_Elements( growSize, initSize ),
+m_LessFunc( lessfunc ),
+m_Root( InvalidIndex() ),
+m_NumElements( 0 ),
+m_FirstFree( InvalidIndex() ),
+m_LastAlloc( m_Elements.InvalidIterator() )
+{
+ ResetDbgInfo();
+}
+
+template < class T, class I, typename L, class M >
+inline CUtlRBTree<T, I, L, M>::CUtlRBTree( const LessFunc_t &lessfunc ) :
+m_Elements( 0, 0 ),
+m_LessFunc( lessfunc ),
+m_Root( InvalidIndex() ),
+m_NumElements( 0 ),
+m_FirstFree( InvalidIndex() ),
+m_LastAlloc( m_Elements.InvalidIterator() )
+{
+ ResetDbgInfo();
+}
+
+template < class T, class I, typename L, class M >
+inline CUtlRBTree<T, I, L, M>::~CUtlRBTree()
+{
+ Purge();
+}
+
+template < class T, class I, typename L, class M >
+inline void CUtlRBTree<T, I, L, M>::EnsureCapacity( int num )
+{
+ m_Elements.EnsureCapacity( num );
+}
+
+template < class T, class I, typename L, class M >
+inline void CUtlRBTree<T, I, L, M>::CopyFrom( const CUtlRBTree<T, I, L, M> &other )
+{
+ Purge();
+ m_Elements.EnsureCapacity( other.m_Elements.Count() );
+ memcpy( m_Elements.Base(), other.m_Elements.Base(), other.m_Elements.Count() * sizeof( T ) );
+ m_LessFunc = other.m_LessFunc;
+ m_Root = other.m_Root;
+ m_NumElements = other.m_NumElements;
+ m_FirstFree = other.m_FirstFree;
+ m_LastAlloc = other.m_LastAlloc;
+ ResetDbgInfo();
+}
+
+//-----------------------------------------------------------------------------
+// gets particular elements
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline T &CUtlRBTree<T, I, L, M>::Element( I i )
+{
+ return m_Elements[i].m_Data;
+}
+
+template < class T, class I, typename L, class M >
+inline T const &CUtlRBTree<T, I, L, M>::Element( I i ) const
+{
+ return m_Elements[i].m_Data;
+}
+
+template < class T, class I, typename L, class M >
+inline T &CUtlRBTree<T, I, L, M>::operator[]( I i )
+{
+ return Element(i);
+}
+
+template < class T, class I, typename L, class M >
+inline T const &CUtlRBTree<T, I, L, M>::operator[]( I i ) const
+{
+ return Element(i);
+}
+
+//-----------------------------------------------------------------------------
+//
+// various accessors
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Gets the root
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline I CUtlRBTree<T, I, L, M>::Root() const
+{
+ return m_Root;
+}
+
+//-----------------------------------------------------------------------------
+// Num elements
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline unsigned int CUtlRBTree<T, I, L, M>::Count() const
+{
+ return (unsigned int)m_NumElements;
+}
+
+//-----------------------------------------------------------------------------
+// Max "size" of the vector
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline I CUtlRBTree<T, I, L, M>::MaxElement() const
+{
+ return ( I )m_Elements.NumAllocated();
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the children
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline I CUtlRBTree<T, I, L, M>::Parent( I i ) const
+{
+ return Links(i).m_Parent;
+}
+
+template < class T, class I, typename L, class M >
+inline I CUtlRBTree<T, I, L, M>::LeftChild( I i ) const
+{
+ return Links(i).m_Left;
+}
+
+template < class T, class I, typename L, class M >
+inline I CUtlRBTree<T, I, L, M>::RightChild( I i ) const
+{
+ return Links(i).m_Right;
+}
+
+//-----------------------------------------------------------------------------
+// Tests if a node is a left or right child
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline bool CUtlRBTree<T, I, L, M>::IsLeftChild( I i ) const
+{
+ return LeftChild(Parent(i)) == i;
+}
+
+template < class T, class I, typename L, class M >
+inline bool CUtlRBTree<T, I, L, M>::IsRightChild( I i ) const
+{
+ return RightChild(Parent(i)) == i;
+}
+
+
+//-----------------------------------------------------------------------------
+// Tests if root or leaf
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline bool CUtlRBTree<T, I, L, M>::IsRoot( I i ) const
+{
+ return i == m_Root;
+}
+
+template < class T, class I, typename L, class M >
+inline bool CUtlRBTree<T, I, L, M>::IsLeaf( I i ) const
+{
+ return (LeftChild(i) == InvalidIndex()) && (RightChild(i) == InvalidIndex());
+}
+
+
+//-----------------------------------------------------------------------------
+// Checks if a node is valid and in the tree
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline bool CUtlRBTree<T, I, L, M>::IsValidIndex( I i ) const
+{
+ if ( !m_Elements.IsIdxValid( i ) )
+ return false;
+
+ if ( m_LastAlloc == m_Elements.InvalidIndex() || m_Elements.IsIdxAfter( i, m_LastAlloc ) )
+ return false; // don't read values that have been allocated, but not constructed
+
+ return LeftChild(i) != i;
+}
+
+
+//-----------------------------------------------------------------------------
+// Invalid index
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline I CUtlRBTree<T, I, L, M>::InvalidIndex()
+{
+ return ( I )M::InvalidIndex();
+}
+
+
+//-----------------------------------------------------------------------------
+// returns the tree depth (not a very fast operation)
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline int CUtlRBTree<T, I, L, M>::Depth() const
+{
+ return Depth(Root());
+}
+
+//-----------------------------------------------------------------------------
+// Sets the children
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline void CUtlRBTree<T, I, L, M>::SetParent( I i, I parent )
+{
+ Links(i).m_Parent = parent;
+}
+
+template < class T, class I, typename L, class M >
+inline void CUtlRBTree<T, I, L, M>::SetLeftChild( I i, I child )
+{
+ Links(i).m_Left = child;
+}
+
+template < class T, class I, typename L, class M >
+inline void CUtlRBTree<T, I, L, M>::SetRightChild( I i, I child )
+{
+ Links(i).m_Right = child;
+}
+
+//-----------------------------------------------------------------------------
+// Gets at the links
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline typename CUtlRBTree<T, I, L, M>::Links_t const &CUtlRBTree<T, I, L, M>::Links( I i ) const
+{
+ // Sentinel node, makes life easier
+ static Links_t s_Sentinel =
+ {
+ InvalidIndex(), InvalidIndex(), InvalidIndex(), CUtlRBTree<T, I, L, M>::BLACK
+ };
+
+ return (i != InvalidIndex()) ? *(Links_t*)&m_Elements[i] : *(Links_t*)&s_Sentinel;
+}
+
+template < class T, class I, typename L, class M >
+inline typename CUtlRBTree<T, I, L, M>::Links_t &CUtlRBTree<T, I, L, M>::Links( I i )
+{
+ Assert(i != InvalidIndex());
+ return *(Links_t *)&m_Elements[i];
+}
+
+//-----------------------------------------------------------------------------
+// Checks if a link is red or black
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline bool CUtlRBTree<T, I, L, M>::IsRed( I i ) const
+{
+ return (Links(i).m_Tag == RED);
+}
+
+template < class T, class I, typename L, class M >
+inline bool CUtlRBTree<T, I, L, M>::IsBlack( I i ) const
+{
+ return (Links(i).m_Tag == BLACK);
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets/gets node color
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+inline typename CUtlRBTree<T, I, L, M>::NodeColor_t CUtlRBTree<T, I, L, M>::Color( I i ) const
+{
+ return (NodeColor_t)Links(i).m_Tag;
+}
+
+template < class T, class I, typename L, class M >
+inline void CUtlRBTree<T, I, L, M>::SetColor( I i, typename CUtlRBTree<T, I, L, M>::NodeColor_t c )
+{
+ Links(i).m_Tag = (I)c;
+}
+
+//-----------------------------------------------------------------------------
+// Allocates/ deallocates nodes
+//-----------------------------------------------------------------------------
+#pragma warning(push)
+#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::NewNode()
+{
+ I elem;
+
+ // Nothing in the free list; add.
+ if ( m_FirstFree == InvalidIndex() )
+ {
+ Assert( m_Elements.IsValidIterator( m_LastAlloc ) || m_NumElements == 0 );
+ typename M::Iterator_t it = m_Elements.IsValidIterator( m_LastAlloc ) ? m_Elements.Next( m_LastAlloc ) : m_Elements.First();
+ if ( !m_Elements.IsValidIterator( it ) )
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ m_Elements.Grow();
+
+ it = m_Elements.IsValidIterator( m_LastAlloc ) ? m_Elements.Next( m_LastAlloc ) : m_Elements.First();
+
+ Assert( m_Elements.IsValidIterator( it ) );
+ if ( !m_Elements.IsValidIterator( it ) )
+ {
+ Error( "CUtlRBTree overflow!\n" );
+ }
+ }
+ m_LastAlloc = it;
+ elem = m_Elements.GetIndex( m_LastAlloc );
+ Assert( m_Elements.IsValidIterator( m_LastAlloc ) );
+ }
+ else
+ {
+ elem = m_FirstFree;
+ m_FirstFree = Links( m_FirstFree ).m_Right;
+ }
+
+#ifdef _DEBUG
+ // reset links to invalid....
+ Links_t &node = Links( elem );
+ node.m_Left = node.m_Right = node.m_Parent = InvalidIndex();
+#endif
+
+ Construct( &Element( elem ) );
+ ResetDbgInfo();
+
+ return elem;
+}
+#pragma warning(pop)
+
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::FreeNode( I i )
+{
+ Assert( IsValidIndex(i) && (i != InvalidIndex()) );
+ Destruct( &Element(i) );
+ SetLeftChild( i, i ); // indicates it's in not in the tree
+ SetRightChild( i, m_FirstFree );
+ m_FirstFree = i;
+}
+
+
+//-----------------------------------------------------------------------------
+// Rotates node i to the left
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::RotateLeft(I elem)
+{
+ I rightchild = RightChild(elem);
+ SetRightChild( elem, LeftChild(rightchild) );
+ if (LeftChild(rightchild) != InvalidIndex())
+ SetParent( LeftChild(rightchild), elem );
+
+ if (rightchild != InvalidIndex())
+ SetParent( rightchild, Parent(elem) );
+ if (!IsRoot(elem))
+ {
+ if (IsLeftChild(elem))
+ SetLeftChild( Parent(elem), rightchild );
+ else
+ SetRightChild( Parent(elem), rightchild );
+ }
+ else
+ m_Root = rightchild;
+
+ SetLeftChild( rightchild, elem );
+ if (elem != InvalidIndex())
+ SetParent( elem, rightchild );
+}
+
+
+//-----------------------------------------------------------------------------
+// Rotates node i to the right
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::RotateRight(I elem)
+{
+ I leftchild = LeftChild(elem);
+ SetLeftChild( elem, RightChild(leftchild) );
+ if (RightChild(leftchild) != InvalidIndex())
+ SetParent( RightChild(leftchild), elem );
+
+ if (leftchild != InvalidIndex())
+ SetParent( leftchild, Parent(elem) );
+ if (!IsRoot(elem))
+ {
+ if (IsRightChild(elem))
+ SetRightChild( Parent(elem), leftchild );
+ else
+ SetLeftChild( Parent(elem), leftchild );
+ }
+ else
+ m_Root = leftchild;
+
+ SetRightChild( leftchild, elem );
+ if (elem != InvalidIndex())
+ SetParent( elem, leftchild );
+}
+
+
+//-----------------------------------------------------------------------------
+// Rebalances the tree after an insertion
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::InsertRebalance(I elem)
+{
+ while ( !IsRoot(elem) && (Color(Parent(elem)) == RED) )
+ {
+ I parent = Parent(elem);
+ I grandparent = Parent(parent);
+
+ /* we have a violation */
+ if (IsLeftChild(parent))
+ {
+ I uncle = RightChild(grandparent);
+ if (IsRed(uncle))
+ {
+ /* uncle is RED */
+ SetColor(parent, BLACK);
+ SetColor(uncle, BLACK);
+ SetColor(grandparent, RED);
+ elem = grandparent;
+ }
+ else
+ {
+ /* uncle is BLACK */
+ if (IsRightChild(elem))
+ {
+ /* make x a left child, will change parent and grandparent */
+ elem = parent;
+ RotateLeft(elem);
+ parent = Parent(elem);
+ grandparent = Parent(parent);
+ }
+ /* recolor and rotate */
+ SetColor(parent, BLACK);
+ SetColor(grandparent, RED);
+ RotateRight(grandparent);
+ }
+ }
+ else
+ {
+ /* mirror image of above code */
+ I uncle = LeftChild(grandparent);
+ if (IsRed(uncle))
+ {
+ /* uncle is RED */
+ SetColor(parent, BLACK);
+ SetColor(uncle, BLACK);
+ SetColor(grandparent, RED);
+ elem = grandparent;
+ }
+ else
+ {
+ /* uncle is BLACK */
+ if (IsLeftChild(elem))
+ {
+ /* make x a right child, will change parent and grandparent */
+ elem = parent;
+ RotateRight(parent);
+ parent = Parent(elem);
+ grandparent = Parent(parent);
+ }
+ /* recolor and rotate */
+ SetColor(parent, BLACK);
+ SetColor(grandparent, RED);
+ RotateLeft(grandparent);
+ }
+ }
+ }
+ SetColor( m_Root, BLACK );
+}
+
+
+//-----------------------------------------------------------------------------
+// Insert a node into the tree
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::InsertAt( I parent, bool leftchild )
+{
+ I i = NewNode();
+ LinkToParent( i, parent, leftchild );
+ ++m_NumElements;
+
+ Assert(IsValid());
+
+ return i;
+}
+
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::LinkToParent( I i, I parent, bool isLeft )
+{
+ Links_t &elem = Links(i);
+ elem.m_Parent = parent;
+ elem.m_Left = elem.m_Right = InvalidIndex();
+ elem.m_Tag = RED;
+
+ /* insert node in tree */
+ if (parent != InvalidIndex())
+ {
+ if (isLeft)
+ Links(parent).m_Left = i;
+ else
+ Links(parent).m_Right = i;
+ }
+ else
+ {
+ m_Root = i;
+ }
+
+ InsertRebalance(i);
+}
+
+//-----------------------------------------------------------------------------
+// Rebalance the tree after a deletion
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::RemoveRebalance(I elem)
+{
+ while (elem != m_Root && IsBlack(elem))
+ {
+ I parent = Parent(elem);
+
+ // If elem is the left child of the parent
+ if (elem == LeftChild(parent))
+ {
+ // Get our sibling
+ I sibling = RightChild(parent);
+ if (IsRed(sibling))
+ {
+ SetColor(sibling, BLACK);
+ SetColor(parent, RED);
+ RotateLeft(parent);
+
+ // We may have a new parent now
+ parent = Parent(elem);
+ sibling = RightChild(parent);
+ }
+ if ( (IsBlack(LeftChild(sibling))) && (IsBlack(RightChild(sibling))) )
+ {
+ if (sibling != InvalidIndex())
+ SetColor(sibling, RED);
+ elem = parent;
+ }
+ else
+ {
+ if (IsBlack(RightChild(sibling)))
+ {
+ SetColor(LeftChild(sibling), BLACK);
+ SetColor(sibling, RED);
+ RotateRight(sibling);
+
+ // rotation may have changed this
+ parent = Parent(elem);
+ sibling = RightChild(parent);
+ }
+ SetColor( sibling, Color(parent) );
+ SetColor( parent, BLACK );
+ SetColor( RightChild(sibling), BLACK );
+ RotateLeft( parent );
+ elem = m_Root;
+ }
+ }
+ else
+ {
+ // Elem is the right child of the parent
+ I sibling = LeftChild(parent);
+ if (IsRed(sibling))
+ {
+ SetColor(sibling, BLACK);
+ SetColor(parent, RED);
+ RotateRight(parent);
+
+ // We may have a new parent now
+ parent = Parent(elem);
+ sibling = LeftChild(parent);
+ }
+ if ( (IsBlack(RightChild(sibling))) && (IsBlack(LeftChild(sibling))) )
+ {
+ if (sibling != InvalidIndex())
+ SetColor( sibling, RED );
+ elem = parent;
+ }
+ else
+ {
+ if (IsBlack(LeftChild(sibling)))
+ {
+ SetColor( RightChild(sibling), BLACK );
+ SetColor( sibling, RED );
+ RotateLeft( sibling );
+
+ // rotation may have changed this
+ parent = Parent(elem);
+ sibling = LeftChild(parent);
+ }
+ SetColor( sibling, Color(parent) );
+ SetColor( parent, BLACK );
+ SetColor( LeftChild(sibling), BLACK );
+ RotateRight( parent );
+ elem = m_Root;
+ }
+ }
+ }
+ SetColor( elem, BLACK );
+}
+
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::Unlink( I elem )
+{
+ if ( elem != InvalidIndex() )
+ {
+ I x, y;
+
+ if ((LeftChild(elem) == InvalidIndex()) ||
+ (RightChild(elem) == InvalidIndex()))
+ {
+ /* y has a NIL node as a child */
+ y = elem;
+ }
+ else
+ {
+ /* find tree successor with a NIL node as a child */
+ y = RightChild(elem);
+ while (LeftChild(y) != InvalidIndex())
+ y = LeftChild(y);
+ }
+
+ /* x is y's only child */
+ if (LeftChild(y) != InvalidIndex())
+ x = LeftChild(y);
+ else
+ x = RightChild(y);
+
+ /* remove y from the parent chain */
+ if (x != InvalidIndex())
+ SetParent( x, Parent(y) );
+ if (!IsRoot(y))
+ {
+ if (IsLeftChild(y))
+ SetLeftChild( Parent(y), x );
+ else
+ SetRightChild( Parent(y), x );
+ }
+ else
+ m_Root = x;
+
+ // need to store this off now, we'll be resetting y's color
+ NodeColor_t ycolor = Color(y);
+ if (y != elem)
+ {
+ // Standard implementations copy the data around, we cannot here.
+ // Hook in y to link to the same stuff elem used to.
+ SetParent( y, Parent(elem) );
+ SetRightChild( y, RightChild(elem) );
+ SetLeftChild( y, LeftChild(elem) );
+
+ if (!IsRoot(elem))
+ if (IsLeftChild(elem))
+ SetLeftChild( Parent(elem), y );
+ else
+ SetRightChild( Parent(elem), y );
+ else
+ m_Root = y;
+
+ if (LeftChild(y) != InvalidIndex())
+ SetParent( LeftChild(y), y );
+ if (RightChild(y) != InvalidIndex())
+ SetParent( RightChild(y), y );
+
+ SetColor( y, Color(elem) );
+ }
+
+ if ((x != InvalidIndex()) && (ycolor == BLACK))
+ RemoveRebalance(x);
+ }
+}
+
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::Link( I elem )
+{
+ if ( elem != InvalidIndex() )
+ {
+ I parent;
+ bool leftchild;
+
+ FindInsertionPosition( Element( elem ), parent, leftchild );
+
+ LinkToParent( elem, parent, leftchild );
+
+ Assert(IsValid());
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Delete a node from the tree
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::RemoveAt(I elem)
+{
+ if ( elem != InvalidIndex() )
+ {
+ Unlink( elem );
+
+ FreeNode(elem);
+ --m_NumElements;
+
+ Assert(IsValid());
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// remove a node in the tree
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M > bool CUtlRBTree<T, I, L, M>::Remove( T const &search )
+{
+ I node = Find( search );
+ if (node != InvalidIndex())
+ {
+ RemoveAt(node);
+ return true;
+ }
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Removes all nodes from the tree
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::RemoveAll()
+{
+ // Have to do some convoluted stuff to invoke the destructor on all
+ // valid elements for the multilist case (since we don't have all elements
+ // connected to each other in a list).
+
+ if ( m_LastAlloc == m_Elements.InvalidIterator() )
+ {
+ Assert( m_Root == InvalidIndex() );
+ Assert( m_FirstFree == InvalidIndex() );
+ Assert( m_NumElements == 0 );
+ return;
+ }
+
+ for ( typename M::Iterator_t it = m_Elements.First(); it != m_Elements.InvalidIterator(); it = m_Elements.Next( it ) )
+ {
+ I i = m_Elements.GetIndex( it );
+ if ( IsValidIndex( i ) ) // skip elements in the free list
+ {
+ Destruct( &Element( i ) );
+ SetRightChild( i, m_FirstFree );
+ SetLeftChild( i, i );
+ m_FirstFree = i;
+ }
+
+ if ( it == m_LastAlloc )
+ break; // don't destruct elements that haven't ever been constucted
+ }
+
+ // Clear everything else out
+ m_Root = InvalidIndex();
+ // Technically, this iterator could become invalid. It will not, because it's
+ // always the same iterator. If we don't clear this here, the state of this
+ // container will be invalid after we start inserting elements again.
+ m_LastAlloc = m_Elements.InvalidIterator();
+ m_FirstFree = InvalidIndex();
+ m_NumElements = 0;
+
+ Assert( IsValid() );
+}
+
+//-----------------------------------------------------------------------------
+// Removes all nodes from the tree and purges memory
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::Purge()
+{
+ RemoveAll();
+ m_Elements.Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+// iteration
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::FirstInorder() const
+{
+ I i = m_Root;
+ while (LeftChild(i) != InvalidIndex())
+ i = LeftChild(i);
+ return i;
+}
+
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::NextInorder( I i ) const
+{
+ // Don't go into an infinite loop if it's a bad index
+ Assert(IsValidIndex(i));
+ if ( !IsValidIndex(i) )
+ return InvalidIndex();
+
+ if (RightChild(i) != InvalidIndex())
+ {
+ i = RightChild(i);
+ while (LeftChild(i) != InvalidIndex())
+ i = LeftChild(i);
+ return i;
+ }
+
+ I parent = Parent(i);
+ while (IsRightChild(i))
+ {
+ i = parent;
+ if (i == InvalidIndex()) break;
+ parent = Parent(i);
+ }
+ return parent;
+}
+
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::PrevInorder( I i ) const
+{
+ // Don't go into an infinite loop if it's a bad index
+ Assert(IsValidIndex(i));
+ if ( !IsValidIndex(i) )
+ return InvalidIndex();
+
+ if (LeftChild(i) != InvalidIndex())
+ {
+ i = LeftChild(i);
+ while (RightChild(i) != InvalidIndex())
+ i = RightChild(i);
+ return i;
+ }
+
+ I parent = Parent(i);
+ while (IsLeftChild(i))
+ {
+ i = parent;
+ if (i == InvalidIndex()) break;
+ parent = Parent(i);
+ }
+ return parent;
+}
+
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::LastInorder() const
+{
+ I i = m_Root;
+ while (RightChild(i) != InvalidIndex())
+ i = RightChild(i);
+ return i;
+}
+
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::FirstPreorder() const
+{
+ return m_Root;
+}
+
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::NextPreorder( I i ) const
+{
+ if (LeftChild(i) != InvalidIndex())
+ return LeftChild(i);
+
+ if (RightChild(i) != InvalidIndex())
+ return RightChild(i);
+
+ I parent = Parent(i);
+ while( parent != InvalidIndex())
+ {
+ if (IsLeftChild(i) && (RightChild(parent) != InvalidIndex()))
+ return RightChild(parent);
+ i = parent;
+ parent = Parent(parent);
+ }
+ return InvalidIndex();
+}
+
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::PrevPreorder( I i ) const
+{
+ Assert(0); // not implemented yet
+ return InvalidIndex();
+}
+
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::LastPreorder() const
+{
+ I i = m_Root;
+ while (1)
+ {
+ while (RightChild(i) != InvalidIndex())
+ i = RightChild(i);
+
+ if (LeftChild(i) != InvalidIndex())
+ i = LeftChild(i);
+ else
+ break;
+ }
+ return i;
+}
+
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::FirstPostorder() const
+{
+ I i = m_Root;
+ while (!IsLeaf(i))
+ {
+ if (LeftChild(i))
+ i = LeftChild(i);
+ else
+ i = RightChild(i);
+ }
+ return i;
+}
+
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::NextPostorder( I i ) const
+{
+ I parent = Parent(i);
+ if (parent == InvalidIndex())
+ return InvalidIndex();
+
+ if (IsRightChild(i))
+ return parent;
+
+ if (RightChild(parent) == InvalidIndex())
+ return parent;
+
+ i = RightChild(parent);
+ while (!IsLeaf(i))
+ {
+ if (LeftChild(i))
+ i = LeftChild(i);
+ else
+ i = RightChild(i);
+ }
+ return i;
+}
+
+
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::Reinsert( I elem )
+{
+ Unlink( elem );
+ Link( elem );
+}
+
+
+//-----------------------------------------------------------------------------
+// returns the tree depth (not a very fast operation)
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+int CUtlRBTree<T, I, L, M>::Depth( I node ) const
+{
+ if (node == InvalidIndex())
+ return 0;
+
+ int depthright = Depth( RightChild(node) );
+ int depthleft = Depth( LeftChild(node) );
+ return Max(depthright, depthleft) + 1;
+}
+
+
+//#define UTLTREE_PARANOID
+
+//-----------------------------------------------------------------------------
+// Makes sure the tree is valid after every operation
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+bool CUtlRBTree<T, I, L, M>::IsValid() const
+{
+ if ( !Count() )
+ return true;
+
+ if ( m_LastAlloc == m_Elements.InvalidIterator() )
+ return false;
+
+ if ( !m_Elements.IsIdxValid( Root() ) )
+ return false;
+
+ if ( Parent( Root() ) != InvalidIndex() )
+ return false;
+
+#ifdef UTLTREE_PARANOID
+
+ // First check to see that mNumEntries matches reality.
+ // count items on the free list
+ int numFree = 0;
+ for ( int i = m_FirstFree; i != InvalidIndex(); i = RightChild( i ) )
+ {
+ ++numFree;
+ if ( !m_Elements.IsIdxValid( i ) )
+ return false;
+ }
+
+ // iterate over all elements, looking for validity
+ // based on the self pointers
+ int nElements = 0;
+ int numFree2 = 0;
+ for ( M::Iterator_t it = m_Elements.First(); it != m_Elements.InvalidIterator(); it = m_Elements.Next( it ) )
+ {
+ I i = m_Elements.GetIndex( it );
+ if ( !IsValidIndex( i ) )
+ {
+ ++numFree2;
+ }
+ else
+ {
+ ++nElements;
+
+ int right = RightChild( i );
+ int left = LeftChild( i );
+ if ( ( right == left ) && ( right != InvalidIndex() ) )
+ return false;
+
+ if ( right != InvalidIndex() )
+ {
+ if ( !IsValidIndex( right ) )
+ return false;
+ if ( Parent( right ) != i )
+ return false;
+ if ( IsRed( i ) && IsRed( right ) )
+ return false;
+ }
+
+ if ( left != InvalidIndex() )
+ {
+ if ( !IsValidIndex( left ) )
+ return false;
+ if ( Parent( left ) != i )
+ return false;
+ if ( IsRed( i ) && IsRed( left ) )
+ return false;
+ }
+ }
+
+ if ( it == m_LastAlloc )
+ break;
+ }
+ if ( numFree2 != numFree )
+ return false;
+
+ if ( nElements != m_NumElements )
+ return false;
+
+#endif // UTLTREE_PARANOID
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the less func
+//-----------------------------------------------------------------------------
+
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::SetLessFunc( const typename CUtlRBTree<T, I, L, M>::LessFunc_t &func )
+{
+ if (!m_LessFunc)
+ {
+ m_LessFunc = func;
+ }
+ else if ( Count() > 0 )
+ {
+ // need to re-sort the tree here....
+ Assert(0);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// inserts a node into the tree
+//-----------------------------------------------------------------------------
+
+// Inserts a node into the tree, doesn't copy the data in.
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::FindInsertionPosition( T const &insert, I &parent, bool &leftchild )
+{
+ Assert( m_LessFunc );
+
+ /* find where node belongs */
+ I current = m_Root;
+ parent = InvalidIndex();
+ leftchild = false;
+ while (current != InvalidIndex())
+ {
+ parent = current;
+ if (m_LessFunc( insert, Element(current) ))
+ {
+ leftchild = true; current = LeftChild(current);
+ }
+ else
+ {
+ leftchild = false; current = RightChild(current);
+ }
+ }
+}
+
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::Insert( T const &insert )
+{
+ // use copy constructor to copy it in
+ I parent;
+ bool leftchild;
+ FindInsertionPosition( insert, parent, leftchild );
+ I newNode = InsertAt( parent, leftchild );
+ CopyConstruct( &Element( newNode ), insert );
+ return newNode;
+}
+
+
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::Insert( const T *pArray, int nItems )
+{
+ while ( nItems-- )
+ {
+ Insert( *pArray++ );
+ }
+}
+
+
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::InsertIfNotFound( T const &insert )
+{
+ // use copy constructor to copy it in
+ I parent;
+ bool leftchild;
+
+ I current = m_Root;
+ parent = InvalidIndex();
+ leftchild = false;
+ while (current != InvalidIndex())
+ {
+ parent = current;
+ if (m_LessFunc( insert, Element(current) ))
+ {
+ leftchild = true; current = LeftChild(current);
+ }
+ else if (m_LessFunc( Element(current), insert ))
+ {
+ leftchild = false; current = RightChild(current);
+ }
+ else
+ // Match found, no insertion
+ return InvalidIndex();
+ }
+
+ I newNode = InsertAt( parent, leftchild );
+ CopyConstruct( &Element( newNode ), insert );
+ return newNode;
+}
+
+
+//-----------------------------------------------------------------------------
+// finds a node in the tree
+//-----------------------------------------------------------------------------
+template < class T, class I, typename L, class M >
+I CUtlRBTree<T, I, L, M>::Find( T const &search ) const
+{
+ Assert( m_LessFunc );
+
+ I current = m_Root;
+ while (current != InvalidIndex())
+ {
+ if (m_LessFunc( search, Element(current) ))
+ current = LeftChild(current);
+ else if (m_LessFunc( Element(current), search ))
+ current = RightChild(current);
+ else
+ break;
+ }
+ return current;
+}
+
+
+//-----------------------------------------------------------------------------
+// swap in place
+//-----------------------------------------------------------------------------
+template < class T, class I, typename L, class M >
+void CUtlRBTree<T, I, L, M>::Swap( CUtlRBTree< T, I, L > &that )
+{
+ m_Elements.Swap( that.m_Elements );
+ V_swap( m_LessFunc, that.m_LessFunc );
+ V_swap( m_Root, that.m_Root );
+ V_swap( m_NumElements, that.m_NumElements );
+ V_swap( m_FirstFree, that.m_FirstFree );
+ V_swap( m_pElements, that.m_pElements );
+ V_swap( m_LastAlloc, that.m_LastAlloc );
+ Assert( IsValid() );
+ Assert( m_Elements.IsValidIterator( m_LastAlloc ) || ( m_NumElements == 0 && m_FirstFree == InvalidIndex() ) );
+}
+
+
+#endif // UTLRBTREE_H
diff --git a/public/tier1/utlsoacontainer.h b/public/tier1/utlsoacontainer.h
new file mode 100644
index 0000000..b9440c5
--- /dev/null
+++ b/public/tier1/utlsoacontainer.h
@@ -0,0 +1,334 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+// A Fixed-allocation class for maintaining a 1d or 2d or 3d array of data in a structure-of-arrays
+// (SOA) sse-friendly manner.
+// =============================================================================//
+
+#ifndef UTLSOACONTAINER_H
+#define UTLSOACONTAINER_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "tier0/platform.h"
+#include "tier0/dbg.h"
+#include "tier0/threadtools.h"
+#include "tier1/utlmemory.h"
+#include "tier1/utlblockmemory.h"
+#include "mathlib/ssemath.h"
+
+
+// strided pointers. gives you a class that acts like a pointer, but the ++ and += operators do the
+// right thing
+template<class T> class CStridedPtr
+{
+protected:
+ T *m_pData;
+ size_t m_nStride;
+
+public:
+ FORCEINLINE CStridedPtr<T>( void *pData, size_t nByteStride )
+ {
+ m_pData = reinterpret_cast<T *>( pData );
+ m_nStride = nByteStride / sizeof( T );
+ }
+
+ FORCEINLINE CStridedPtr<T>( void ) {}
+ T *operator->(void) const
+ {
+ return m_pData;
+ }
+
+ T & operator*(void) const
+ {
+ return *m_pData;
+ }
+
+ FORCEINLINE operator T *(void)
+ {
+ return m_pData;
+ }
+
+ FORCEINLINE CStridedPtr<T> & operator++(void)
+ {
+ m_pData += m_nStride;
+ return *this;
+ }
+
+ FORCEINLINE void operator+=( size_t nNumElements )
+ {
+ m_pData += nNumElements * m_nStride;
+ }
+
+};
+
+template<class T> class CStridedConstPtr
+{
+protected:
+ const T *m_pData;
+ size_t m_nStride;
+
+public:
+ FORCEINLINE CStridedConstPtr<T>( void const *pData, size_t nByteStride )
+ {
+ m_pData = reinterpret_cast<T const *>( pData );
+ m_nStride = nByteStride / sizeof( T );
+ }
+
+ FORCEINLINE CStridedConstPtr<T>( void ) {}
+
+ const T *operator->(void) const
+ {
+ return m_pData;
+ }
+
+ const T & operator*(void) const
+ {
+ return *m_pData;
+ }
+
+ FORCEINLINE operator const T *(void) const
+ {
+ return m_pData;
+ }
+
+ FORCEINLINE CStridedConstPtr<T> &operator++(void)
+ {
+ m_pData += m_nStride;
+ return *this;
+ }
+ FORCEINLINE void operator+=( size_t nNumElements )
+ {
+ m_pData += nNumElements*m_nStride;
+ }
+};
+
+// allowed field data types. if you change these values, you need to change the tables in the .cpp file
+enum EAttributeDataType
+{
+ ATTRDATATYPE_FLOAT = 0, // a float attribute
+ ATTRDATATYPE_4V = 1, // vector data type, stored as class FourVectors
+ ATTRDATATYPE_INT = 2, // integer. not especially sse-able on
+ // all architectures.
+ ATTRDATATYPE_POINTER = 3, // a pointer.
+ ATTRDATATYPE_NONE = -1, // pad and varargs ender
+};
+
+#define MAX_SOA_FIELDS 32
+
+class CSOAContainer
+{
+
+protected:
+ int m_nColumns; // # of rows and columns created with
+ int m_nRows;
+ int m_nSlices;
+
+ int m_nPaddedColumns; // # of columns rounded up for sse
+ int m_nNumQuadsPerRow; // # of groups of 4 elements per row
+
+ uint8 *m_pDataMemory; // the actual data memory
+ uint8 *m_pAttributePtrs[MAX_SOA_FIELDS];
+
+ EAttributeDataType m_nDataType[MAX_SOA_FIELDS];
+
+ size_t m_nStrideInBytes[MAX_SOA_FIELDS]; // stride from one field datum to another
+ size_t m_nRowStrideInBytes[MAX_SOA_FIELDS]; // stride from one row datum to another per field
+ size_t m_nSliceStrideInBytes[MAX_SOA_FIELDS]; // stride from one slice datum to another per field
+
+
+
+ uint32 m_nFieldPresentMask;
+
+ FORCEINLINE void Init( void )
+ {
+ memset( m_nDataType, 0xff, sizeof( m_nDataType ) );
+ m_pDataMemory = 0;
+ m_nColumns = m_nPaddedColumns = m_nRows = m_nSlices = 0;
+ m_nFieldPresentMask = 0;
+ }
+public:
+
+
+ CSOAContainer( void ) // an empoty one with no attributes
+ {
+ Init();
+ }
+
+ void Purge( void ); // set back to un-initted state, freeing memory
+
+ ~CSOAContainer( void );
+
+ // easy constructor for 2d using varargs. call like
+ // #define ATTR_RED 0
+ // #define ATTR_GREEN 1
+ // #define ATTR_BLUE 2
+ // CSOAContainer myimage( 256, 256, ATTR_RED, ATTRDATATYPE_FLOAT, ATTR_GREEN, ATTRDATATYPE_FLOAT,
+ // ATTR_BLUE, ATTRDATATYPE_FLOAT, -1 );
+
+ CSOAContainer( int nCols, int nRows, ... );
+
+ size_t ElementSize( void ) const; // total bytes per element. not super fast.
+
+ // set the data type for an attribute. If you set the data type, but tell it not to allocate,
+ // the data type will be set but writes will assert, and reads will give you back zeros.
+ FORCEINLINE void SetAttributeType( int nAttrIdx, EAttributeDataType nDataType, bool bAllocateMemory = true )
+ {
+ Assert( !m_pDataMemory ); // can't change after memory allocated
+ Assert( nAttrIdx < MAX_SOA_FIELDS );
+ m_nDataType[nAttrIdx] = nDataType;
+ if ( ( m_nDataType[nAttrIdx] != ATTRDATATYPE_NONE ) && bAllocateMemory )
+ m_nFieldPresentMask |= ( 1 << nAttrIdx );
+ else
+ m_nFieldPresentMask &= ~( 1 << nAttrIdx );
+ }
+
+ FORCEINLINE int NumRows( void ) const
+ {
+ return m_nRows;
+ }
+
+ FORCEINLINE int NumCols( void ) const
+ {
+ return m_nColumns;
+ }
+ FORCEINLINE int NumSlices( void ) const
+ {
+ return m_nSlices;
+ }
+
+
+ FORCEINLINE void AssertDataType( int nAttrIdx, EAttributeDataType nDataType ) const
+ {
+ Assert( nAttrIdx >= 0 );
+ Assert( nAttrIdx < MAX_SOA_FIELDS );
+ Assert( m_nStrideInBytes[nAttrIdx] );
+ }
+
+
+ // # of groups of 4 elements per row
+ FORCEINLINE int NumQuadsPerRow( void ) const
+ {
+ return m_nNumQuadsPerRow;
+ }
+
+ FORCEINLINE int Count( void ) const // for 1d data
+ {
+ return NumCols();
+ }
+
+ FORCEINLINE int NumElements( void ) const
+ {
+ return NumCols() * NumRows() * NumSlices();
+ }
+
+
+ // how much to step to go from the end of one row to the start of the next one. Basically, how
+ // many bytes to add at the end of a row when iterating over the whole 2d array with ++
+ FORCEINLINE size_t RowToRowStep( int nAttrIdx ) const
+ {
+ return 0;
+ }
+
+ FORCEINLINE void *RowPtr( int nAttributeIdx, int nRowNumber, int nSliceNumber = 0 ) const
+ {
+ Assert( nRowNumber < m_nRows );
+ Assert( nAttributeIdx < MAX_SOA_FIELDS );
+ Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE );
+ Assert( m_nFieldPresentMask & ( 1 << nAttributeIdx ) );
+ return m_pAttributePtrs[nAttributeIdx] +
+ + nRowNumber * m_nRowStrideInBytes[nAttributeIdx]
+ + nSliceNumber * m_nSliceStrideInBytes[nAttributeIdx];
+ }
+
+ FORCEINLINE void const *ConstRowPtr( int nAttributeIdx, int nRowNumber, int nSliceNumber = 0 ) const
+ {
+ Assert( nRowNumber < m_nRows );
+ Assert( nAttributeIdx < MAX_SOA_FIELDS );
+ Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE );
+ return m_pAttributePtrs[nAttributeIdx]
+ + nRowNumber * m_nRowStrideInBytes[nAttributeIdx]
+ + nSliceNumber * m_nSliceStrideInBytes[nAttributeIdx];
+ }
+
+
+ template<class T> FORCEINLINE T *ElementPointer( int nAttributeIdx,
+ int nX = 0, int nY = 0, int nZ = 0 ) const
+ {
+ Assert( nAttributeIdx < MAX_SOA_FIELDS );
+ Assert( nX < m_nColumns );
+ Assert( nY < m_nRows );
+ Assert( nZ < m_nSlices );
+ Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE );
+ Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_4V );
+ return reinterpret_cast<T *>( m_pAttributePtrs[nAttributeIdx]
+ + nX * sizeof( float )
+ + nY * m_nRowStrideInBytes[nAttributeIdx]
+ + nZ * m_nSliceStrideInBytes[nAttributeIdx]
+ );
+ }
+
+ FORCEINLINE size_t ItemByteStride( int nAttributeIdx ) const
+ {
+ Assert( nAttributeIdx < MAX_SOA_FIELDS );
+ Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE );
+ return m_nStrideInBytes[ nAttributeIdx ];
+ }
+
+ // copy the attribute data from another soacontainer. must be compatible geometry
+ void CopyAttrFrom( CSOAContainer const &other, int nAttributeIdx );
+
+ // copy the attribute data from another attribute. must be compatible data format
+ void CopyAttrToAttr( int nSrcAttributeIndex, int nDestAttributeIndex);
+
+ // move all the data from one csoacontainer to another, leaving the source empty.
+ // this is just a pointer copy.
+ FORCEINLINE void MoveDataFrom( CSOAContainer other )
+ {
+ (*this) = other;
+ other.Init();
+ }
+
+
+
+ void AllocateData( int nNCols, int nNRows, int nSlices = 1 ); // actually allocate the memory and set the pointers up
+
+ // arithmetic and data filling functions. All SIMD and hopefully fast
+
+ // set all elements of a float attribute to random #s
+ void RandomizeAttribute( int nAttr, float flMin, float flMax ) const ;
+
+ // fill 2d a rectangle with values interpolated from 4 corner values.
+ void FillAttrWithInterpolatedValues( int nAttr, float flValue00, float flValue10, float flValue01, float flValue11 ) const;
+ void FillAttrWithInterpolatedValues( int nAttr, Vector flValue00, Vector flValue10,
+ Vector const &flValue01, Vector const &flValue11 ) const;
+
+};
+
+class CFltX4AttributeIterator : public CStridedConstPtr<fltx4>
+{
+ FORCEINLINE CFltX4AttributeIterator( CSOAContainer const *pContainer, int nAttribute, int nRowNumber = 0 )
+ : CStridedConstPtr<fltx4>( pContainer->ConstRowPtr( nAttribute, nRowNumber),
+ pContainer->ItemByteStride( nAttribute ) )
+ {
+ }
+};
+
+class CFltX4AttributeWriteIterator : public CStridedPtr<fltx4>
+{
+ FORCEINLINE CFltX4AttributeWriteIterator( CSOAContainer const *pContainer, int nAttribute, int nRowNumber = 0 )
+ : CStridedPtr<fltx4>( pContainer->RowPtr( nAttribute, nRowNumber),
+ pContainer->ItemByteStride( nAttribute ) )
+ {
+ }
+
+};
+
+
+#endif
diff --git a/public/tier1/utlstack.h b/public/tier1/utlstack.h
new file mode 100644
index 0000000..a46beb2
--- /dev/null
+++ b/public/tier1/utlstack.h
@@ -0,0 +1,331 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+// A stack based on a growable array
+//=============================================================================//
+
+#ifndef UTLSTACK_H
+#define UTLSTACK_H
+
+#include <assert.h>
+#include <string.h>
+#include "utlmemory.h"
+
+
+//-----------------------------------------------------------------------------
+// The CUtlStack class:
+// A growable stack class which doubles in size by default.
+// It will always keep all elements consecutive in memory, and may move the
+// elements around in memory (via a realloc) when elements are pushed or
+// popped. Clients should therefore refer to the elements of the stack
+// by index (they should *never* maintain pointers to elements in the stack).
+//-----------------------------------------------------------------------------
+
+template< class T, class M = CUtlMemory< T > >
+class CUtlStack
+{
+public:
+ // constructor, destructor
+ CUtlStack( int growSize = 0, int initSize = 0 );
+ ~CUtlStack();
+
+ void CopyFrom( const CUtlStack<T, M> &from );
+
+ // element access
+ T& operator[]( int i );
+ T const& operator[]( int i ) const;
+ T& Element( int i );
+ T const& Element( int i ) const;
+
+ // Gets the base address (can change when adding elements!)
+ T* Base();
+ T const* Base() const;
+
+ // Looks at the stack top
+ T& Top();
+ T const& Top() const;
+
+ // Size
+ int Count() const;
+
+ // Is element index valid?
+ bool IsIdxValid( int i ) const;
+
+ // Adds an element, uses default constructor
+ int Push();
+
+ // Adds an element, uses copy constructor
+ int Push( T const& src );
+
+ // Pops the stack
+ void Pop();
+ void Pop( T& oldTop );
+ void PopMultiple( int num );
+
+ // Makes sure we have enough memory allocated to store a requested # of elements
+ void EnsureCapacity( int num );
+
+ // Clears the stack, no deallocation
+ void Clear();
+
+ // Memory deallocation
+ void Purge();
+
+private:
+ // Grows the stack allocation
+ void GrowStack();
+
+ // For easier access to the elements through the debugger
+ void ResetDbgInfo();
+
+ M m_Memory;
+ int m_Size;
+
+ // For easier access to the elements through the debugger
+ T* m_pElements;
+};
+
+
+//-----------------------------------------------------------------------------
+// For easier access to the elements through the debugger
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+inline void CUtlStack<T,M>::ResetDbgInfo()
+{
+ m_pElements = m_Memory.Base();
+}
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+CUtlStack<T,M>::CUtlStack( int growSize, int initSize ) :
+ m_Memory(growSize, initSize), m_Size(0)
+{
+ ResetDbgInfo();
+}
+
+template< class T, class M >
+CUtlStack<T,M>::~CUtlStack()
+{
+ Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+// copy into
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+void CUtlStack<T,M>::CopyFrom( const CUtlStack<T, M> &from )
+{
+ Purge();
+ EnsureCapacity( from.Count() );
+ for ( int i = 0; i < from.Count(); i++ )
+ {
+ Push( from[i] );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// element access
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+inline T& CUtlStack<T,M>::operator[]( int i )
+{
+ assert( IsIdxValid(i) );
+ return m_Memory[i];
+}
+
+template< class T, class M >
+inline T const& CUtlStack<T,M>::operator[]( int i ) const
+{
+ assert( IsIdxValid(i) );
+ return m_Memory[i];
+}
+
+template< class T, class M >
+inline T& CUtlStack<T,M>::Element( int i )
+{
+ assert( IsIdxValid(i) );
+ return m_Memory[i];
+}
+
+template< class T, class M >
+inline T const& CUtlStack<T,M>::Element( int i ) const
+{
+ assert( IsIdxValid(i) );
+ return m_Memory[i];
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the base address (can change when adding elements!)
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+inline T* CUtlStack<T,M>::Base()
+{
+ return m_Memory.Base();
+}
+
+template< class T, class M >
+inline T const* CUtlStack<T,M>::Base() const
+{
+ return m_Memory.Base();
+}
+
+//-----------------------------------------------------------------------------
+// Returns the top of the stack
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+inline T& CUtlStack<T,M>::Top()
+{
+ assert( m_Size > 0 );
+ return Element(m_Size-1);
+}
+
+template< class T, class M >
+inline T const& CUtlStack<T,M>::Top() const
+{
+ assert( m_Size > 0 );
+ return Element(m_Size-1);
+}
+
+//-----------------------------------------------------------------------------
+// Size
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+inline int CUtlStack<T,M>::Count() const
+{
+ return m_Size;
+}
+
+
+//-----------------------------------------------------------------------------
+// Is element index valid?
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+inline bool CUtlStack<T,M>::IsIdxValid( int i ) const
+{
+ return (i >= 0) && (i < m_Size);
+}
+
+//-----------------------------------------------------------------------------
+// Grows the stack
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+void CUtlStack<T,M>::GrowStack()
+{
+ if (m_Size >= m_Memory.NumAllocated())
+ m_Memory.Grow();
+
+ ++m_Size;
+
+ ResetDbgInfo();
+}
+
+//-----------------------------------------------------------------------------
+// Makes sure we have enough memory allocated to store a requested # of elements
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+void CUtlStack<T,M>::EnsureCapacity( int num )
+{
+ m_Memory.EnsureCapacity(num);
+ ResetDbgInfo();
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds an element, uses default constructor
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+int CUtlStack<T,M>::Push()
+{
+ GrowStack();
+ Construct( &Element(m_Size-1) );
+ return m_Size - 1;
+}
+
+//-----------------------------------------------------------------------------
+// Adds an element, uses copy constructor
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+int CUtlStack<T,M>::Push( T const& src )
+{
+ GrowStack();
+ CopyConstruct( &Element(m_Size-1), src );
+ return m_Size - 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Pops the stack
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+void CUtlStack<T,M>::Pop()
+{
+ assert( m_Size > 0 );
+ Destruct( &Element(m_Size-1) );
+ --m_Size;
+}
+
+template< class T, class M >
+void CUtlStack<T,M>::Pop( T& oldTop )
+{
+ assert( m_Size > 0 );
+ oldTop = Top();
+ Pop();
+}
+
+template< class T, class M >
+void CUtlStack<T,M>::PopMultiple( int num )
+{
+ assert( m_Size >= num );
+ for ( int i = 0; i < num; ++i )
+ Destruct( &Element( m_Size - i - 1 ) );
+ m_Size -= num;
+}
+
+
+//-----------------------------------------------------------------------------
+// Element removal
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+void CUtlStack<T,M>::Clear()
+{
+ for (int i = m_Size; --i >= 0; )
+ Destruct(&Element(i));
+
+ m_Size = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Memory deallocation
+//-----------------------------------------------------------------------------
+
+template< class T, class M >
+void CUtlStack<T,M>::Purge()
+{
+ Clear();
+ m_Memory.Purge( );
+ ResetDbgInfo();
+}
+
+#endif // UTLSTACK_H \ No newline at end of file
diff --git a/public/tier1/utlstring.h b/public/tier1/utlstring.h
new file mode 100644
index 0000000..f2cd469
--- /dev/null
+++ b/public/tier1/utlstring.h
@@ -0,0 +1,469 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef UTLSTRING_H
+#define UTLSTRING_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "tier1/utlmemory.h"
+#include "tier1/strtools.h"
+#include "limits.h"
+
+// Matched with the memdbgoff at end of header
+#include "memdbgon.h"
+
+#if defined( OSX )
+#ifndef wcsdup
+// The mem override tools may provide a copy of this if active, otherwise it is not available in OS X's libc due to
+// being introduced in POSIX-20008
+inline wchar_t *wcsdup(const wchar_t *pString)
+{
+ wchar_t *pMemory;
+
+ if (!pString)
+ return NULL;
+
+ size_t len = (wcslen(pString) + 1);
+ if ((pMemory = (wchar_t *)malloc(len * sizeof(wchar_t))) != NULL)
+ {
+ return wcscpy( pMemory, pString );
+ }
+
+ return NULL;
+}
+#endif
+
+inline size_t strnlen(const char *s, size_t n)
+{
+ const char *p = (const char *)memchr(s, 0, n);
+ return (p ? p - s : n);
+}
+
+#endif
+
+//-----------------------------------------------------------------------------
+// Simple string class.
+// NOTE: This is *not* optimal! Use in tools, but not runtime code
+//-----------------------------------------------------------------------------
+class CUtlString
+{
+public:
+ typedef enum
+ {
+ PATTERN_NONE = 0x00000000,
+ PATTERN_DIRECTORY = 0x00000001
+ } TUtlStringPattern;
+
+public:
+ CUtlString();
+ CUtlString( const char *pString );
+ CUtlString( const char *pString, int length );
+ CUtlString( const CUtlString& string );
+
+#ifdef MOVE_CONSTRUCTOR_SUPPORT
+ // Support moving of CUtlString objects. Long live C++11
+ // This move constructor will get called when appropriate, such as when
+ // returning objects from functions, or otherwise copying from temporaries
+ // which are about to be destroyed. It can also be explicitly invoked with
+ // std::move().
+ // Move constructor:
+ CUtlString( CUtlString&& rhs )
+ {
+ // Move the string pointer from the source to this -- be sure to
+ // zero out the source to avoid double frees.
+ m_pString = rhs.m_pString;
+ rhs.m_pString = 0;
+ }
+ // Move assignment operator:
+ CUtlString& operator=( CUtlString&& rhs )
+ {
+ // Move the string pointer from the source to this -- be sure to
+ // zero out the source to avoid double frees.
+ m_pString = rhs.m_pString;
+ rhs.m_pString = 0;
+ return *this;
+ }
+#endif
+
+ ~CUtlString();
+
+ const char *Get( ) const;
+ void Set( const char *pValue );
+ operator const char*() const;
+
+ // Set directly and don't look for a null terminator in pValue.
+ // nChars does not include the nul and this will only copy
+ // at most nChars (even if pValue is longer). If nChars
+ // is >strlen(pValue) it will copy past the end, don't do it
+ // Does nothing if pValue == String()
+ void SetDirect( const char *pValue, int nChars );
+
+ // for compatibility switching items from UtlSymbol
+ const char *String() const { return Get(); }
+
+ // Returns strlen
+ int Length() const;
+ // IsEmpty() is more efficient than Length() == 0
+ bool IsEmpty() const;
+
+ // Sets the length (used to serialize into the buffer )
+ // Note: If nLen != 0, then this adds an extra byte for a null-terminator.
+ void SetLength( int nLen );
+ char *GetForModify();
+ void Clear();
+ void Purge();
+
+ // Case Change
+ void ToLower();
+ void ToUpper();
+ void Append( const char *pAddition, int nChars );
+
+ void Append( const char *pchAddition );
+ void Append( const char chAddition ) { char temp[2] = { chAddition, 0 }; Append( temp ); }
+ // Strips the trailing slash
+ void StripTrailingSlash();
+ void FixSlashes( char cSeparator = CORRECT_PATH_SEPARATOR );
+
+ // Trim whitespace
+ void TrimLeft( char cTarget );
+ void TrimLeft( const char *szTargets = "\t\r\n " );
+ void TrimRight( char cTarget );
+ void TrimRight( const char *szTargets = "\t\r\n " );
+ void Trim( char cTarget );
+ void Trim( const char *szTargets = "\t\r\n " );
+
+ bool IsEqual_CaseSensitive( const char *src ) const;
+ bool IsEqual_CaseInsensitive( const char *src ) const;
+
+ CUtlString &operator=( const CUtlString &src );
+ CUtlString &operator=( const char *src );
+
+ // Test for equality
+ bool operator==( const CUtlString &src ) const;
+ bool operator!=( const CUtlString &src ) const { return !operator==( src ); }
+
+ CUtlString &operator+=( const CUtlString &rhs );
+ CUtlString &operator+=( const char *rhs );
+ CUtlString &operator+=( char c );
+ CUtlString &operator+=( int rhs );
+ CUtlString &operator+=( double rhs );
+
+ CUtlString operator+( const char *pOther ) const;
+ CUtlString operator+( const CUtlString &other ) const;
+ CUtlString operator+( int rhs ) const;
+
+ bool MatchesPattern( const CUtlString &Pattern, int nFlags = 0 ) const; // case SENSITIVE, use * for wildcard in pattern string
+
+ char operator[]( int i ) const;
+
+#if ! defined(SWIG)
+ // Don't let SWIG see the PRINTF_FORMAT_STRING attribute or it will complain.
+ int Format( PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 2, 3 );
+ int FormatV( PRINTF_FORMAT_STRING const char *pFormat, va_list marker );
+#else
+ int Format( const char *pFormat, ... );
+ int FormatV( const char *pFormat, va_list marker );
+#endif
+
+ // Defining AltArgumentType_t hints that associative container classes should
+ // also implement Find/Insert/Remove functions that take const char* params.
+ typedef const char *AltArgumentType_t;
+
+ // Get a copy of part of the string.
+ // If you only specify nStart, it'll go from nStart to the end.
+ // You can use negative numbers and it'll wrap around to the start.
+ CUtlString Slice( int32 nStart=0, int32 nEnd=INT_MAX ) const;
+
+ // Get a substring starting from the left or the right side.
+ CUtlString Left( int32 nChars ) const;
+ CUtlString Right( int32 nChars ) const;
+
+ // Get a string with all instances of one character replaced with another.
+ CUtlString Replace( char cFrom, char cTo ) const;
+
+ // Replace all instances of specified string with another.
+ CUtlString Replace( const char *pszFrom, const char *pszTo ) const;
+
+ // Get this string as an absolute path (calls right through to V_MakeAbsolutePath).
+ CUtlString AbsPath( const char *pStartingDir=NULL ) const;
+
+ // Gets the filename (everything except the path.. c:\a\b\c\somefile.txt -> somefile.txt).
+ CUtlString UnqualifiedFilename() const;
+
+ // Gets a string with one directory removed. Uses V_StripLastDir but strips the last slash also!
+ CUtlString DirName() const;
+
+ // Get a string with the extension removed (with V_StripExtension).
+ CUtlString StripExtension() const;
+
+ // Get a string with the filename removed (uses V_UnqualifiedFileName and also strips the last slash)
+ CUtlString StripFilename() const;
+
+ // Get a string with the base filename (with V_FileBase).
+ CUtlString GetBaseFilename() const;
+
+ // Get a string with the file extension (with V_FileBase).
+ CUtlString GetExtension() const;
+
+ // Works like V_ComposeFileName.
+ static CUtlString PathJoin( const char *pStr1, const char *pStr2 );
+
+ // These can be used for utlvector sorts.
+ static int __cdecl SortCaseInsensitive( const CUtlString *pString1, const CUtlString *pString2 );
+ static int __cdecl SortCaseSensitive( const CUtlString *pString1, const CUtlString *pString2 );
+
+ // Empty string for those times when you need to return an empty string and
+ // either don't want to pay the construction cost, or are returning a
+ // const CUtlString& and cannot just return "".
+ static const CUtlString &GetEmptyString();
+
+private:
+ // INTERNALS
+ // AllocMemory allocates enough space for length characters plus a terminating zero.
+ // Previous characters are preserved, the buffer is null-terminated, but new characters
+ // are not touched.
+ void *AllocMemory( uint32 length );
+
+ // If m_pString is not NULL, it points to the start of the string, and the memory allocation.
+ char *m_pString;
+};
+
+// // If these are not defined, CUtlConstString as rhs will auto-convert
+// // to const char* and do logical operations on the raw pointers. Ugh.
+// inline friend bool operator<( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) > 0; }
+// inline friend bool operator==( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) == 0; }
+// inline friend bool operator!=( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) != 0; }
+
+inline bool operator==( const char *pString, const CUtlString &utlString )
+{
+ return utlString.IsEqual_CaseSensitive( pString );
+}
+
+inline bool operator!=( const char *pString, const CUtlString &utlString )
+{
+ return !utlString.IsEqual_CaseSensitive( pString );
+}
+
+inline bool operator==( const CUtlString &utlString, const char *pString )
+{
+ return utlString.IsEqual_CaseSensitive( pString );
+}
+
+inline bool operator!=( const CUtlString &utlString, const char *pString )
+{
+ return !utlString.IsEqual_CaseSensitive( pString );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Inline methods
+//-----------------------------------------------------------------------------
+inline CUtlString::CUtlString()
+: m_pString( NULL )
+{
+}
+
+inline CUtlString::CUtlString( const char *pString )
+: m_pString( NULL )
+{
+ Set( pString );
+}
+
+inline CUtlString::CUtlString( const char *pString, int length )
+: m_pString( NULL )
+{
+ SetDirect( pString, length );
+}
+
+inline CUtlString::CUtlString( const CUtlString& string )
+: m_pString( NULL )
+{
+ Set( string.Get() );
+}
+
+inline CUtlString::~CUtlString()
+{
+ Purge();
+}
+
+inline int CUtlString::Length() const
+{
+ if (m_pString)
+ {
+ return V_strlen( m_pString );
+ }
+ return 0;
+}
+
+inline bool CUtlString::IsEmpty() const
+{
+ return !m_pString || m_pString[0] == 0;
+}
+
+inline int __cdecl CUtlString::SortCaseInsensitive( const CUtlString *pString1, const CUtlString *pString2 )
+{
+ return V_stricmp( pString1->String(), pString2->String() );
+}
+
+inline int __cdecl CUtlString::SortCaseSensitive( const CUtlString *pString1, const CUtlString *pString2 )
+{
+ return V_strcmp( pString1->String(), pString2->String() );
+}
+
+// Converts to c-strings
+inline CUtlString::operator const char*() const
+{
+ return Get();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Implementation of low-level string functionality for character types.
+//-----------------------------------------------------------------------------
+
+template < typename T >
+class StringFuncs
+{
+public:
+ static T *Duplicate( const T *pValue );
+ // Note that this function takes a character count, and does not guarantee null-termination.
+ static void Copy( T *out_pOut, const T *pIn, int iLengthInChars );
+ static int Compare( const T *pLhs, const T *pRhs );
+ static int CaselessCompare( const T *pLhs, const T *pRhs );
+ static int Length( const T *pValue );
+ static const T *FindChar( const T *pStr, const T cSearch );
+ static const T *EmptyString();
+ static const T *NullDebugString();
+};
+
+template < >
+class StringFuncs<char>
+{
+public:
+ static char *Duplicate( const char *pValue ) { return strdup( pValue ); }
+ // Note that this function takes a character count, and does not guarantee null-termination.
+ static void Copy( OUT_CAP(iLengthInChars) char *out_pOut, const char *pIn, int iLengthInChars ) { strncpy( out_pOut, pIn, iLengthInChars ); }
+ static int Compare( const char *pLhs, const char *pRhs ) { return strcmp( pLhs, pRhs ); }
+ static int CaselessCompare( const char *pLhs, const char *pRhs ) { return Q_strcasecmp( pLhs, pRhs ); }
+ static int Length( const char *pValue ) { return (int)strlen( pValue ); }
+ static const char *FindChar( const char *pStr, const char cSearch ) { return strchr( pStr, cSearch ); }
+ static const char *EmptyString() { return ""; }
+ static const char *NullDebugString() { return "(null)"; }
+};
+
+template < >
+class StringFuncs<wchar_t>
+{
+public:
+ static wchar_t *Duplicate( const wchar_t *pValue ) { return wcsdup( pValue ); }
+ // Note that this function takes a character count, and does not guarantee null-termination.
+ static void Copy( OUT_CAP(iLengthInChars) wchar_t *out_pOut, const wchar_t *pIn, int iLengthInChars ) { wcsncpy( out_pOut, pIn, iLengthInChars ); }
+ static int Compare( const wchar_t *pLhs, const wchar_t *pRhs ) { return wcscmp( pLhs, pRhs ); }
+ static int CaselessCompare( const wchar_t *pLhs, const wchar_t *pRhs ); // no implementation?
+ static int Length( const wchar_t *pValue ) { return (int)wcslen( pValue ); }
+ static const wchar_t *FindChar( const wchar_t *pStr, const wchar_t cSearch ) { return wcschr( pStr, cSearch ); }
+ static const wchar_t *EmptyString() { return L""; }
+ static const wchar_t *NullDebugString() { return L"(null)"; }
+};
+
+//-----------------------------------------------------------------------------
+// Dirt-basic auto-release string class. Not intended for manipulation,
+// can be stored in a container or forwarded as a functor parameter.
+// Note the benefit over CUtlString: sizeof(CUtlConstString) == sizeof(char*).
+// Also note: null char* pointers are treated identically to empty strings.
+//-----------------------------------------------------------------------------
+
+template < typename T = char >
+class CUtlConstStringBase
+{
+public:
+ CUtlConstStringBase() : m_pString( NULL ) {}
+ explicit CUtlConstStringBase( const T *pString ) : m_pString( NULL ) { Set( pString ); }
+ CUtlConstStringBase( const CUtlConstStringBase& src ) : m_pString( NULL ) { Set( src.m_pString ); }
+ ~CUtlConstStringBase() { Set( NULL ); }
+
+ void Set( const T *pValue );
+ void Clear() { Set( NULL ); }
+
+ const T *Get() const { return m_pString ? m_pString : StringFuncs<T>::EmptyString(); }
+ operator const T*() const { return m_pString ? m_pString : StringFuncs<T>::EmptyString(); }
+
+ bool IsEmpty() const { return m_pString == NULL; } // Note: empty strings are never stored by Set
+
+ int Compare( const T *rhs ) const;
+
+ // Logical ops
+ bool operator<( const T *rhs ) const { return Compare( rhs ) < 0; }
+ bool operator==( const T *rhs ) const { return Compare( rhs ) == 0; }
+ bool operator!=( const T *rhs ) const { return Compare( rhs ) != 0; }
+ bool operator<( const CUtlConstStringBase &rhs ) const { return Compare( rhs.m_pString ) < 0; }
+ bool operator==( const CUtlConstStringBase &rhs ) const { return Compare( rhs.m_pString ) == 0; }
+ bool operator!=( const CUtlConstStringBase &rhs ) const { return Compare( rhs.m_pString ) != 0; }
+
+ // If these are not defined, CUtlConstString as rhs will auto-convert
+ // to const char* and do logical operations on the raw pointers. Ugh.
+ inline friend bool operator<( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) > 0; }
+ inline friend bool operator==( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) == 0; }
+ inline friend bool operator!=( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) != 0; }
+
+ CUtlConstStringBase &operator=( const T *src ) { Set( src ); return *this; }
+ CUtlConstStringBase &operator=( const CUtlConstStringBase &src ) { Set( src.m_pString ); return *this; }
+
+ // Defining AltArgumentType_t is a hint to containers that they should
+ // implement Find/Insert/Remove functions that take const char* params.
+ typedef const T *AltArgumentType_t;
+
+protected:
+ const T *m_pString;
+};
+
+template < typename T >
+void CUtlConstStringBase<T>::Set( const T *pValue )
+{
+ if ( pValue != m_pString )
+ {
+ free( ( void* ) m_pString );
+ m_pString = pValue && pValue[0] ? StringFuncs<T>::Duplicate( pValue ) : NULL;
+ }
+}
+
+template < typename T >
+int CUtlConstStringBase<T>::Compare( const T *rhs ) const
+{
+ // Empty or null RHS?
+ if ( !rhs || !rhs[0] )
+ return m_pString ? 1 : 0;
+
+ // Empty *this, non-empty RHS?
+ if ( !m_pString )
+ return -1;
+
+ // Neither empty
+ return StringFuncs<T>::Compare( m_pString, rhs );
+}
+
+typedef CUtlConstStringBase<char> CUtlConstString;
+typedef CUtlConstStringBase<wchar_t> CUtlConstWideString;
+
+//-----------------------------------------------------------------------------
+// Helper functor objects.
+//-----------------------------------------------------------------------------
+
+template < typename T > struct UTLConstStringCaselessStringLessFunctor { bool operator()( const CUtlConstStringBase<T>& a, const char *b ) const { return StringFuncs<T>::CaselessCompare( a.Get(), b ) < 0; } };
+template < typename T > struct UTLConstStringCaselessStringEqualFunctor { bool operator()( const CUtlConstStringBase<T>& a, const char *b ) const { return StringFuncs<T>::CaselessCompare( a.Get(), b ) == 0; } };
+
+// Helper function for CUtlMaps with a CUtlString key
+inline bool UtlStringLessFunc( const CUtlString &lhs, const CUtlString &rhs ) { return V_strcmp( lhs.Get(), rhs.Get() ) < 0; }
+inline bool UtlStringCaseInsensitiveLessFunc( const CUtlString &lhs, const CUtlString &rhs ) { return V_stricmp( lhs.Get(), rhs.Get() ) < 0; }
+
+#include "memdbgoff.h"
+
+#endif // UTLSTRING_H
diff --git a/public/tier1/utlsymbol.h b/public/tier1/utlsymbol.h
new file mode 100644
index 0000000..e90be46
--- /dev/null
+++ b/public/tier1/utlsymbol.h
@@ -0,0 +1,269 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Defines a symbol table
+//
+// $Header: $
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef UTLSYMBOL_H
+#define UTLSYMBOL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/threadtools.h"
+#include "tier1/utlrbtree.h"
+#include "tier1/utlvector.h"
+
+
+//-----------------------------------------------------------------------------
+// forward declarations
+//-----------------------------------------------------------------------------
+class CUtlSymbolTable;
+class CUtlSymbolTableMT;
+
+
+//-----------------------------------------------------------------------------
+// This is a symbol, which is a easier way of dealing with strings.
+//-----------------------------------------------------------------------------
+typedef unsigned short UtlSymId_t;
+
+#define UTL_INVAL_SYMBOL ((UtlSymId_t)~0)
+
+class CUtlSymbol
+{
+public:
+ // constructor, destructor
+ CUtlSymbol() : m_Id(UTL_INVAL_SYMBOL) {}
+ CUtlSymbol( UtlSymId_t id ) : m_Id(id) {}
+ CUtlSymbol( const char* pStr );
+ CUtlSymbol( CUtlSymbol const& sym ) : m_Id(sym.m_Id) {}
+
+ // operator=
+ CUtlSymbol& operator=( CUtlSymbol const& src ) { m_Id = src.m_Id; return *this; }
+
+ // operator==
+ bool operator==( CUtlSymbol const& src ) const { return m_Id == src.m_Id; }
+ bool operator==( const char* pStr ) const;
+
+ // Is valid?
+ bool IsValid() const { return m_Id != UTL_INVAL_SYMBOL; }
+
+ // Gets at the symbol
+ operator UtlSymId_t const() 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();
+
+protected:
+ UtlSymId_t m_Id;
+
+ // Initializes the symbol table
+ static void Initialize();
+
+ // returns the current symbol table
+ static CUtlSymbolTableMT* CurrTable();
+
+ // The standard global symbol table
+ static CUtlSymbolTableMT* s_pSymbolTable;
+
+ static bool s_bAllowStaticSymbolTable;
+
+ friend class CCleanupUtlSymbolTable;
+};
+
+
+//-----------------------------------------------------------------------------
+// CUtlSymbolTable:
+// description:
+// This class defines a symbol table, which allows us to perform mappings
+// of strings to symbols and back. The symbol class itself contains
+// a static version of this class for creating global strings, but this
+// class can also be instanced to create local symbol tables.
+//-----------------------------------------------------------------------------
+
+class CUtlSymbolTable
+{
+public:
+ // constructor, destructor
+ CUtlSymbolTable( int growSize = 0, int initSize = 32, bool caseInsensitive = false );
+ ~CUtlSymbolTable();
+
+ // Finds and/or creates a symbol based on the string
+ CUtlSymbol AddString( const char* pString );
+
+ // Finds the symbol for pString
+ CUtlSymbol Find( const char* pString ) const;
+
+ // Look up the string associated with a particular symbol
+ const char* String( CUtlSymbol id ) const;
+
+ // Remove all symbols in the table.
+ void RemoveAll();
+
+ int GetNumStrings( void ) const
+ {
+ return m_Lookup.Count();
+ }
+
+protected:
+ class CStringPoolIndex
+ {
+ public:
+ inline CStringPoolIndex()
+ {
+ }
+
+ inline CStringPoolIndex( unsigned short iPool, unsigned short iOffset )
+ {
+ m_iPool = iPool;
+ m_iOffset = iOffset;
+ }
+
+ inline bool operator==( const CStringPoolIndex &other ) const
+ {
+ return m_iPool == other.m_iPool && m_iOffset == other.m_iOffset;
+ }
+
+ unsigned short m_iPool; // Index into m_StringPools.
+ unsigned short m_iOffset; // Index into the string pool.
+ };
+
+ class CLess
+ {
+ public:
+ CLess( int ignored = 0 ) {} // permits default initialization to NULL in CUtlRBTree
+ bool operator!() const { return false; }
+ bool operator()( const CStringPoolIndex &left, const CStringPoolIndex &right ) const;
+ };
+
+ // Stores the symbol lookup
+ class CTree : public CUtlRBTree<CStringPoolIndex, unsigned short, CLess>
+ {
+ public:
+ CTree( int growSize, int initSize ) : CUtlRBTree<CStringPoolIndex, unsigned short, CLess>( growSize, initSize ) {}
+ friend class CUtlSymbolTable::CLess; // Needed to allow CLess to calculate pointer to symbol table
+ };
+
+ struct StringPool_t
+ {
+ int m_TotalLen; // How large is
+ int m_SpaceUsed;
+ char m_Data[1];
+ };
+
+ CTree m_Lookup;
+ bool m_bInsensitive;
+ mutable const char* m_pUserSearchString;
+
+ // stores the string data
+ CUtlVector<StringPool_t*> m_StringPools;
+
+private:
+ int FindPoolWithSpace( int len ) const;
+ const char* StringFromIndex( const CStringPoolIndex &index ) const;
+
+ friend class CLess;
+};
+
+class CUtlSymbolTableMT : private CUtlSymbolTable
+{
+public:
+ CUtlSymbolTableMT( int growSize = 0, int initSize = 32, bool caseInsensitive = false )
+ : CUtlSymbolTable( growSize, initSize, caseInsensitive )
+ {
+ }
+
+ CUtlSymbol AddString( const char* pString )
+ {
+ m_lock.LockForWrite();
+ CUtlSymbol result = CUtlSymbolTable::AddString( pString );
+ m_lock.UnlockWrite();
+ return result;
+ }
+
+ CUtlSymbol Find( const char* pString ) const
+ {
+ m_lock.LockForRead();
+ CUtlSymbol result = CUtlSymbolTable::Find( pString );
+ m_lock.UnlockRead();
+ return result;
+ }
+
+ const char* String( CUtlSymbol id ) const
+ {
+ m_lock.LockForRead();
+ const char *pszResult = CUtlSymbolTable::String( id );
+ m_lock.UnlockRead();
+ return pszResult;
+ }
+
+private:
+#if defined(WIN32) || defined(_WIN32)
+ mutable CThreadSpinRWLock m_lock;
+#else
+ mutable CThreadRWLock m_lock;
+#endif
+};
+
+
+
+//-----------------------------------------------------------------------------
+// CUtlFilenameSymbolTable:
+// description:
+// This class defines a symbol table of individual filenames, stored more
+// efficiently than a standard symbol table. Internally filenames are broken
+// up into file and path entries, and a file handle class allows convenient
+// access to these.
+//-----------------------------------------------------------------------------
+
+// The handle is a CUtlSymbol for the dirname and the same for the filename, the accessor
+// copies them into a static char buffer for return.
+typedef void* FileNameHandle_t;
+#define FILENAMEHANDLE_INVALID 0
+
+// Symbol table for more efficiently storing filenames by breaking paths and filenames apart.
+// Refactored from BaseFileSystem.h
+class CUtlFilenameSymbolTable
+{
+ // Internal representation of a FileHandle_t
+ // If we get more than 64K filenames, we'll have to revisit...
+ // Right now CUtlSymbol is a short, so this packs into an int/void * pointer size...
+ struct FileNameHandleInternal_t
+ {
+ FileNameHandleInternal_t()
+ {
+ path = 0;
+ file = 0;
+ }
+
+ // Part before the final '/' character
+ unsigned short path;
+ // Part after the final '/', including extension
+ unsigned short file;
+ };
+
+ 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; }
+ bool String( const FileNameHandle_t& handle, char *buf, int buflen );
+ void RemoveAll();
+
+private:
+ //CCountedStringPool m_StringPool;
+ HashTable* m_Strings;
+ mutable CThreadSpinRWLock m_lock;
+};
+
+
+#endif // UTLSYMBOL_H
diff --git a/public/tier1/utlsymbollarge.h b/public/tier1/utlsymbollarge.h
new file mode 100644
index 0000000..4384540
--- /dev/null
+++ b/public/tier1/utlsymbollarge.h
@@ -0,0 +1,499 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Defines a large symbol table (intp sized handles, can store more than 64k strings)
+//
+// $Header: $
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef UTLSYMBOLLARGE_H
+#define UTLSYMBOLLARGE_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/threadtools.h"
+#include "tier1/utltshash.h"
+#include "tier1/stringpool.h"
+#include "tier0/vprof.h"
+#include "tier1/utltshash.h"
+
+//-----------------------------------------------------------------------------
+// CUtlSymbolTableLarge:
+// description:
+// This class defines a symbol table, which allows us to perform mappings
+// of strings to symbols and back.
+//
+// This class stores the strings in a series of string pools. The returned CUtlSymbolLarge is just a pointer
+// to the string data, the hash precedes it in memory and is used to speed up searching, etc.
+//-----------------------------------------------------------------------------
+
+typedef intp UtlSymLargeId_t;
+
+#define UTL_INVAL_SYMBOL_LARGE ((UtlSymLargeId_t)~0)
+
+class CUtlSymbolLarge
+{
+public:
+ // constructor, destructor
+ CUtlSymbolLarge()
+ {
+ u.m_Id = UTL_INVAL_SYMBOL_LARGE;
+ }
+
+ CUtlSymbolLarge( UtlSymLargeId_t id )
+ {
+ u.m_Id = id;
+ }
+ CUtlSymbolLarge( CUtlSymbolLarge const& sym )
+ {
+ u.m_Id = sym.u.m_Id;
+ }
+
+ // operator=
+ CUtlSymbolLarge& operator=( CUtlSymbolLarge const& src )
+ {
+ u.m_Id = src.u.m_Id;
+ return *this;
+ }
+
+ // operator==
+ bool operator==( CUtlSymbolLarge const& src ) const
+ {
+ return u.m_Id == src.u.m_Id;
+ }
+
+ // operator==
+ bool operator==( UtlSymLargeId_t const& src ) const
+ {
+ return u.m_Id == src;
+ }
+
+ // operator==
+ bool operator!=( CUtlSymbolLarge const& src ) const
+ {
+ return u.m_Id != src.u.m_Id;
+ }
+
+ // operator==
+ bool operator!=( UtlSymLargeId_t const& src ) const
+ {
+ return u.m_Id != src;
+ }
+
+ // Gets at the symbol
+ operator UtlSymLargeId_t const() const
+ {
+ return u.m_Id;
+ }
+
+ // Gets the string associated with the symbol
+ inline const char* String( ) const
+ {
+ if ( u.m_Id == UTL_INVAL_SYMBOL_LARGE )
+ return "";
+ return u.m_pAsString;
+ }
+
+ inline bool IsValid() const
+ {
+ return u.m_Id != UTL_INVAL_SYMBOL_LARGE ? true : false;
+ }
+
+private:
+ // Disallowed
+ CUtlSymbolLarge( const char* pStr ); // they need to go through the table to assign the ptr
+ bool operator==( const char* pStr ) const; // disallow since we don't know if the table this is from was case sensitive or not... maybe we don't care
+
+ union
+ {
+ UtlSymLargeId_t m_Id;
+ char const *m_pAsString;
+ } u;
+};
+
+#define MIN_STRING_POOL_SIZE 2048
+
+inline uint32 CUtlSymbolLarge_Hash( bool CASEINSENSITIVE, const char *pString, int len )
+{
+ return ( CASEINSENSITIVE ? HashStringCaseless( pString ) : HashString( pString ) );
+}
+
+typedef uint32 LargeSymbolTableHashDecoration_t;
+
+// The structure consists of the hash immediately followed by the string data
+struct CUtlSymbolTableLargeBaseTreeEntry_t
+{
+ LargeSymbolTableHashDecoration_t m_Hash;
+ // Variable length string data
+ char m_String[1];
+
+ bool IsEmpty() const
+ {
+ return ( ( m_Hash == 0 ) && ( 0 == m_String[0] ) );
+ }
+
+ char const *String() const
+ {
+ return (const char *)&m_String[ 0 ];
+ }
+
+ CUtlSymbolLarge ToSymbol() const
+ {
+ return reinterpret_cast< UtlSymLargeId_t >( String() );
+ }
+
+ LargeSymbolTableHashDecoration_t HashValue() const
+ {
+ return m_Hash;
+ }
+};
+
+template< class TreeType, bool CASEINSENSITIVE >
+class CTreeEntryLess
+{
+public:
+ CTreeEntryLess( int ignored = 0 ) {} // permits default initialization to NULL in CUtlRBTree
+ bool operator!() const { return false; }
+ bool operator()( CUtlSymbolTableLargeBaseTreeEntry_t * const &left, CUtlSymbolTableLargeBaseTreeEntry_t * const &right ) const
+ {
+ // compare the hashes
+ if ( left->m_Hash == right->m_Hash )
+ {
+ // if the hashes match compare the strings
+ if ( !CASEINSENSITIVE )
+ return strcmp( left->String(), right->String() ) < 0;
+ else
+ return V_stricmp( left->String(), right->String() ) < 0;
+ }
+ else
+ {
+ return left->m_Hash < right->m_Hash;
+ }
+ }
+};
+
+// For non-threaded versions, simply index into CUtlRBTree
+template< bool CASEINSENSITIVE >
+class CNonThreadsafeTree : public CUtlRBTree<CUtlSymbolTableLargeBaseTreeEntry_t *, intp, CTreeEntryLess< CNonThreadsafeTree< CASEINSENSITIVE >, CASEINSENSITIVE > >
+{
+public:
+ typedef CUtlRBTree<CUtlSymbolTableLargeBaseTreeEntry_t *, intp, CTreeEntryLess< CNonThreadsafeTree, CASEINSENSITIVE > > CNonThreadsafeTreeType;
+
+ CNonThreadsafeTree() :
+ CNonThreadsafeTreeType( 0, 16 )
+ {
+ }
+ inline void Commit()
+ {
+ // Nothing, only matters for thread-safe tables
+ }
+ inline int Insert( CUtlSymbolTableLargeBaseTreeEntry_t *entry )
+ {
+ return CNonThreadsafeTreeType::Insert( entry );
+ }
+ inline int Find( CUtlSymbolTableLargeBaseTreeEntry_t *entry ) const
+ {
+ return CNonThreadsafeTreeType::Find( entry );
+ }
+ inline int InvalidIndex() const
+ {
+ return CNonThreadsafeTreeType::InvalidIndex();
+ }
+ inline int GetElements( int nFirstElement, int nCount, CUtlSymbolLarge *pElements ) const
+ {
+ CUtlVector< CUtlSymbolTableLargeBaseTreeEntry_t * > list;
+ list.EnsureCount( nCount );
+ for ( int i = 0; i < nCount; ++i )
+ {
+ pElements[ i ] = CNonThreadsafeTreeType::Element( i )->ToSymbol();
+ }
+
+ return nCount;
+ }
+};
+
+// Since CUtlSymbolTableLargeBaseTreeEntry_t already has the hash
+// contained inside of it, don't need to recompute a hash here
+template < int BUCKET_COUNT, class KEYTYPE, bool CASEINSENSITIVE >
+class CCThreadsafeTreeHashMethod
+{
+public:
+ static int Hash( const KEYTYPE &key, int nBucketMask )
+ {
+ uint32 nHash = key->HashValue();
+ return ( nHash & nBucketMask );
+ }
+
+ static bool Compare( CUtlSymbolTableLargeBaseTreeEntry_t * const &lhs, CUtlSymbolTableLargeBaseTreeEntry_t * const &rhs )
+ {
+ if ( lhs->m_Hash != rhs->m_Hash )
+ return false;
+ if ( !CASEINSENSITIVE )
+ {
+ return ( !Q_strcmp( lhs->String(), rhs->String() ) ? true : false );
+ }
+
+ return ( !Q_stricmp( lhs->String(), rhs->String() ) ? true : false );
+ }
+};
+
+/*
+ NOTE: So the only crappy thing about using a CUtlTSHash here is that the KEYTYPE is a CUtlSymbolTableLargeBaseTreeEntry_t ptr which has both the
+ hash and the string since with strings there is a good chance of hash collision after you have a fair number of strings so we have to implement
+ a Compare method (above) which falls back to strcmp/stricmp if the hashes are equal. This means that all of the data is in the KEYTYPE of the hash and the
+ payload doesn't matter. So I made the payload also be a pointer to a CUtlSymbolTableLargeBaseTreeEntry_t since that makes using the API more convenient
+
+ TODO: If we have a CUtlTSHash that was all about the existence of the KEYTYPE and didn't require a payload (or template on 'void') then we could eliminate
+ 50% of the pointer overhead used for this data structure.
+*/
+
+// Thread safe version is based on the
+template < bool CASEINSENSITIVE >
+class CThreadsafeTree : public CUtlTSHash< CUtlSymbolTableLargeBaseTreeEntry_t *, 2048, CUtlSymbolTableLargeBaseTreeEntry_t *, CCThreadsafeTreeHashMethod< 2048, CUtlSymbolTableLargeBaseTreeEntry_t *, CASEINSENSITIVE > >
+{
+public:
+ typedef CUtlTSHash< CUtlSymbolTableLargeBaseTreeEntry_t *, 2048, CUtlSymbolTableLargeBaseTreeEntry_t *, CCThreadsafeTreeHashMethod< 2048, CUtlSymbolTableLargeBaseTreeEntry_t *, CASEINSENSITIVE > > CThreadsafeTreeType;
+
+ CThreadsafeTree() :
+ CThreadsafeTreeType( 32 )
+ {
+ }
+ inline void Commit()
+ {
+ CThreadsafeTreeType::Commit();
+ }
+ inline int Insert( CUtlSymbolTableLargeBaseTreeEntry_t *entry )
+ {
+ return CThreadsafeTreeType::Insert( entry, entry );
+ }
+ inline int Find( CUtlSymbolTableLargeBaseTreeEntry_t *entry )
+ {
+ return CThreadsafeTreeType::Find( entry );
+ }
+ inline int InvalidIndex() const
+ {
+ return CThreadsafeTreeType::InvalidHandle();
+ }
+ inline int GetElements( int nFirstElement, int nCount, CUtlSymbolLarge *pElements ) const
+ {
+ CUtlVector< UtlTSHashHandle_t > list;
+ list.EnsureCount( nCount );
+ int c = CThreadsafeTreeType::GetElements( nFirstElement, nCount, list.Base() );
+ for ( int i = 0; i < c; ++i )
+ {
+ pElements[ i ] = CThreadsafeTreeType::Element( list[ i ] )->ToSymbol();
+ }
+
+ return c;
+ }
+};
+
+// Base Class for threaded and non-threaded types
+template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE = MIN_STRING_POOL_SIZE >
+class CUtlSymbolTableLargeBase
+{
+public:
+ // constructor, destructor
+ CUtlSymbolTableLargeBase();
+ ~CUtlSymbolTableLargeBase();
+
+ // Finds and/or creates a symbol based on the string
+ CUtlSymbolLarge AddString( const char* pString );
+
+ // Finds the symbol for pString
+ CUtlSymbolLarge Find( const char* pString ) const;
+
+ // Remove all symbols in the table.
+ void RemoveAll();
+
+ int GetNumStrings( void ) const
+ {
+ return m_Lookup.Count();
+ }
+
+ void Commit()
+ {
+ m_Lookup.Commit();
+ }
+
+ // Returns elements in the table
+ int GetElements( int nFirstElement, int nCount, CUtlSymbolLarge *pElements ) const
+ {
+ return m_Lookup.GetElements( nFirstElement, nCount, pElements );
+ }
+
+ uint64 GetMemoryUsage() const
+ {
+ uint64 unBytesUsed = 0u;
+
+ for ( int i=0; i < m_StringPools.Count(); i++ )
+ {
+ StringPool_t *pPool = m_StringPools[i];
+
+ unBytesUsed += (uint64)pPool->m_TotalLen;
+ }
+ return unBytesUsed;
+ }
+
+
+protected:
+
+ struct StringPool_t
+ {
+ int m_TotalLen; // How large is
+ int m_SpaceUsed;
+ char m_Data[1];
+ };
+
+ TreeType m_Lookup;
+
+ // stores the string data
+ CUtlVector< StringPool_t * > m_StringPools;
+
+private:
+ int FindPoolWithSpace( int len ) const;
+};
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE >
+inline CUtlSymbolTableLargeBase<TreeType, CASEINSENSITIVE, POOL_SIZE >::CUtlSymbolTableLargeBase() :
+ m_StringPools( 8 )
+{
+}
+
+template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE >
+inline CUtlSymbolTableLargeBase<TreeType, CASEINSENSITIVE, POOL_SIZE>::~CUtlSymbolTableLargeBase()
+{
+ // Release the stringpool string data
+ RemoveAll();
+}
+
+template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE >
+inline CUtlSymbolLarge CUtlSymbolTableLargeBase<TreeType, CASEINSENSITIVE, POOL_SIZE>::Find( const char* pString ) const
+{
+ VPROF( "CUtlSymbolLarge::Find" );
+ if (!pString)
+ return CUtlSymbolLarge();
+
+ // Passing this special invalid symbol makes the comparison function
+ // use the string passed in the context
+ int len = Q_strlen( pString ) + 1;
+
+ CUtlSymbolTableLargeBaseTreeEntry_t *search = (CUtlSymbolTableLargeBaseTreeEntry_t *)_alloca( len + sizeof( LargeSymbolTableHashDecoration_t ) );
+ search->m_Hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, len );
+ Q_memcpy( (char *)&search->m_String[ 0 ], pString, len );
+
+ int idx = const_cast< TreeType & >(m_Lookup).Find( search );
+
+ if ( idx == m_Lookup.InvalidIndex() )
+ return UTL_INVAL_SYMBOL_LARGE;
+
+ const CUtlSymbolTableLargeBaseTreeEntry_t *entry = m_Lookup[ idx ];
+ return entry->ToSymbol();
+}
+
+template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE >
+inline int CUtlSymbolTableLargeBase<TreeType, CASEINSENSITIVE, POOL_SIZE>::FindPoolWithSpace( int len ) const
+{
+ for ( int i=0; i < m_StringPools.Count(); i++ )
+ {
+ StringPool_t *pPool = m_StringPools[i];
+
+ if ( (pPool->m_TotalLen - pPool->m_SpaceUsed) >= len )
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+// Finds and/or creates a symbol based on the string
+//-----------------------------------------------------------------------------
+template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE >
+inline CUtlSymbolLarge CUtlSymbolTableLargeBase<TreeType, CASEINSENSITIVE, POOL_SIZE>::AddString( const char* pString )
+{
+ VPROF("CUtlSymbolLarge::AddString");
+ if (!pString)
+ return UTL_INVAL_SYMBOL_LARGE;
+
+ CUtlSymbolLarge id = Find( pString );
+ if ( id != UTL_INVAL_SYMBOL_LARGE )
+ return id;
+
+ int lenString = Q_strlen(pString) + 1; // length of just the string
+ int lenDecorated = lenString + sizeof(LargeSymbolTableHashDecoration_t); // and with its hash decoration
+ // make sure that all strings are aligned on 2-byte boundaries so the hashes will read correctly
+ // This assert seems to be invalid because LargeSymbolTableHashDecoration_t is always
+ // a uint32, by design.
+ //COMPILE_TIME_ASSERT(sizeof(LargeSymbolTableHashDecoration_t) == sizeof(intp));
+ lenDecorated = ALIGN_VALUE(lenDecorated, sizeof( intp ) );
+
+ // Find a pool with space for this string, or allocate a new one.
+ int iPool = FindPoolWithSpace( lenDecorated );
+ if ( iPool == -1 )
+ {
+ // Add a new pool.
+ int newPoolSize = MAX( lenDecorated + sizeof( StringPool_t ), POOL_SIZE );
+ StringPool_t *pPool = (StringPool_t*)malloc( newPoolSize );
+
+ pPool->m_TotalLen = newPoolSize - sizeof( StringPool_t );
+ pPool->m_SpaceUsed = 0;
+ iPool = m_StringPools.AddToTail( pPool );
+ }
+
+ // Compute a hash
+ LargeSymbolTableHashDecoration_t hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, lenString );
+
+ // Copy the string in.
+ StringPool_t *pPool = m_StringPools[iPool];
+ // Assert( pPool->m_SpaceUsed < 0xFFFF ); // Pool could be bigger than 2k
+ // This should never happen, because if we had a string > 64k, it
+ // would have been given its entire own pool.
+
+ CUtlSymbolTableLargeBaseTreeEntry_t *entry = ( CUtlSymbolTableLargeBaseTreeEntry_t * )&pPool->m_Data[ pPool->m_SpaceUsed ];
+
+ pPool->m_SpaceUsed += lenDecorated;
+
+ entry->m_Hash = hash;
+ char *pText = (char *)&entry->m_String [ 0 ];
+ Q_memcpy( pText, pString, lenString );
+
+ // insert the string into the database
+ MEM_ALLOC_CREDIT();
+ int idx = m_Lookup.Insert( entry );
+ return m_Lookup.Element( idx )->ToSymbol();
+}
+
+//-----------------------------------------------------------------------------
+// Remove all symbols in the table.
+//-----------------------------------------------------------------------------
+template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE >
+inline void CUtlSymbolTableLargeBase<TreeType, CASEINSENSITIVE, POOL_SIZE>::RemoveAll()
+{
+ m_Lookup.Purge();
+
+ for ( int i=0; i < m_StringPools.Count(); i++ )
+ {
+ StringPool_t * pString = m_StringPools[i];
+ free( pString );
+ }
+
+ m_StringPools.RemoveAll();
+}
+
+// Case-sensitive
+typedef CUtlSymbolTableLargeBase< CNonThreadsafeTree< false >, false > CUtlSymbolTableLarge;
+// Case-insensitive
+typedef CUtlSymbolTableLargeBase< CNonThreadsafeTree< true >, true > CUtlSymbolTableLarge_CI;
+// Multi-threaded case-sensitive
+typedef CUtlSymbolTableLargeBase< CThreadsafeTree< false >, false > CUtlSymbolTableLargeMT;
+// Multi-threaded case-insensitive
+typedef CUtlSymbolTableLargeBase< CThreadsafeTree< true >, true > CUtlSymbolTableLargeMT_CI;
+
+#endif // UTLSYMBOLLARGE_H
diff --git a/public/tier1/utltshash.h b/public/tier1/utltshash.h
new file mode 100644
index 0000000..9ff4e83
--- /dev/null
+++ b/public/tier1/utltshash.h
@@ -0,0 +1,625 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+// Thread-safe hash class
+//===========================================================================//
+
+#ifndef UTLTSHASH_H
+#define UTLTSHASH_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <limits.h>
+#include "tier0/threadtools.h"
+#include "tier1/mempool.h"
+#include "generichash.h"
+
+
+//=============================================================================
+//
+// Threadsafe Hash
+//
+// Number of buckets must be a power of 2.
+// Key must be intp sized (32-bits on x32, 64-bits on x64)
+// Designed for a usage pattern where the data is semi-static, and there
+// is a well-defined point where we are guaranteed no queries are occurring.
+//
+// Insertions are added into a thread-safe list, and when Commit() is called,
+// the insertions are moved into a lock-free list
+//
+// Elements are never individually removed; clears must occur at a time
+// where we and guaranteed no queries are occurring
+//
+typedef intp UtlTSHashHandle_t;
+
+template < class T >
+abstract_class ITSHashConstructor
+{
+public:
+ virtual void Construct( T* pElement ) = 0;
+};
+
+template < class T >
+class CDefaultTSHashConstructor : public ITSHashConstructor< T >
+{
+public:
+ virtual void Construct( T* pElement )
+ {
+ ::Construct( pElement );
+ }
+};
+
+template < int BUCKET_COUNT, class KEYTYPE = intp >
+class CUtlTSHashGenericHash
+{
+public:
+ static int Hash( const KEYTYPE &key, int nBucketMask )
+ {
+ int nHash = HashIntConventional( (intp)key );
+ if ( BUCKET_COUNT <= USHRT_MAX )
+ {
+ nHash ^= ( nHash >> 16 );
+ }
+ if ( BUCKET_COUNT <= UCHAR_MAX )
+ {
+ nHash ^= ( nHash >> 8 );
+ }
+ return ( nHash & nBucketMask );
+ }
+
+ static bool Compare( const KEYTYPE &lhs, const KEYTYPE &rhs )
+ {
+ return lhs == rhs;
+ }
+};
+
+template < int BUCKET_COUNT, class KEYTYPE >
+class CUtlTSHashUseKeyHashMethod
+{
+public:
+ static int Hash( const KEYTYPE &key, int nBucketMask )
+ {
+ uint32 nHash = key.HashValue();
+ return ( nHash & nBucketMask );
+ }
+
+ static bool Compare( const KEYTYPE &lhs, const KEYTYPE &rhs )
+ {
+ return lhs == rhs;
+ }
+};
+
+template< class T, int BUCKET_COUNT, class KEYTYPE = intp, class HashFuncs = CUtlTSHashGenericHash< BUCKET_COUNT, KEYTYPE >, int nAlignment = 0 >
+class CUtlTSHash
+{
+public:
+ // Constructor/Deconstructor.
+ CUtlTSHash( int nAllocationCount );
+ ~CUtlTSHash();
+
+ // Invalid handle.
+ static UtlTSHashHandle_t InvalidHandle( void ) { return ( UtlTSHashHandle_t )0; }
+
+ // Retrieval. Super fast, is thread-safe
+ UtlTSHashHandle_t Find( KEYTYPE uiKey );
+
+ // Insertion ( find or add ).
+ UtlTSHashHandle_t Insert( KEYTYPE uiKey, const T &data, bool *pDidInsert = NULL );
+ UtlTSHashHandle_t Insert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor, bool *pDidInsert = NULL );
+
+ // This insertion method assumes the element is not in the hash table, skips
+ UtlTSHashHandle_t FastInsert( KEYTYPE uiKey, const T &data );
+ UtlTSHashHandle_t FastInsert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor );
+
+ // Commit recent insertions, making finding them faster.
+ // Only call when you're certain no threads are accessing the hash table
+ void Commit( );
+
+ // Removal. Only call when you're certain no threads are accessing the hash table
+ void FindAndRemove( KEYTYPE uiKey );
+ void Remove( UtlTSHashHandle_t hHash ) { FindAndRemove( GetID( hHash ) ); }
+ void RemoveAll( void );
+ void Purge( void );
+
+ // Returns the number of elements in the hash table
+ int Count() const;
+
+ // Returns elements in the table
+ int GetElements( int nFirstElement, int nCount, UtlTSHashHandle_t *pHandles ) const;
+
+ // Element access
+ T &Element( UtlTSHashHandle_t hHash );
+ T const &Element( UtlTSHashHandle_t hHash ) const;
+ T &operator[]( UtlTSHashHandle_t hHash );
+ T const &operator[]( UtlTSHashHandle_t hHash ) const;
+ KEYTYPE GetID( UtlTSHashHandle_t hHash ) const;
+
+ // Convert element * to hashHandle
+ UtlTSHashHandle_t ElementPtrToHandle( T* pElement ) const;
+
+private:
+ // Templatized for memory tracking purposes
+ template < typename Data_t >
+ struct HashFixedDataInternal_t
+ {
+ KEYTYPE m_uiKey;
+ HashFixedDataInternal_t< Data_t >* m_pNext;
+ Data_t m_Data;
+ };
+
+ typedef HashFixedDataInternal_t<T> HashFixedData_t;
+
+ enum
+ {
+ BUCKET_MASK = BUCKET_COUNT - 1
+ };
+
+ struct HashBucket_t
+ {
+ HashFixedData_t *m_pFirst;
+ HashFixedData_t *m_pFirstUncommitted;
+ CThreadSpinRWLock m_AddLock;
+ };
+
+ UtlTSHashHandle_t Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement );
+ UtlTSHashHandle_t InsertUncommitted( KEYTYPE uiKey, HashBucket_t &bucket );
+ CMemoryPoolMT m_EntryMemory;
+ HashBucket_t m_aBuckets[BUCKET_COUNT];
+ bool m_bNeedsCommit;
+
+#ifdef _DEBUG
+ CInterlockedInt m_ContentionCheck;
+#endif
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::CUtlTSHash( int nAllocationCount ) :
+ m_EntryMemory( sizeof( HashFixedData_t ), nAllocationCount, CUtlMemoryPool::GROW_SLOW, MEM_ALLOC_CLASSNAME( HashFixedData_t ), nAlignment )
+{
+#ifdef _DEBUG
+ m_ContentionCheck = 0;
+#endif
+ m_bNeedsCommit = false;
+ for ( int i = 0; i < BUCKET_COUNT; i++ )
+ {
+ HashBucket_t &bucket = m_aBuckets[ i ];
+ bucket.m_pFirst = NULL;
+ bucket.m_pFirstUncommitted = NULL;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Deconstructor
+//-----------------------------------------------------------------------------
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::~CUtlTSHash()
+{
+#ifdef _DEBUG
+ if ( m_ContentionCheck != 0 )
+ {
+ DebuggerBreak();
+ }
+#endif
+ Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destroy dynamically allocated hash data.
+//-----------------------------------------------------------------------------
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Purge( void )
+{
+ RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the number of elements in the hash table
+//-----------------------------------------------------------------------------
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Count() const
+{
+ return m_EntryMemory.Count();
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns elements in the table
+//-----------------------------------------------------------------------------
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::GetElements( int nFirstElement, int nCount, UtlTSHashHandle_t *pHandles ) const
+{
+ int nIndex = 0;
+ for ( int i = 0; i < BUCKET_COUNT; i++ )
+ {
+ const HashBucket_t &bucket = m_aBuckets[ i ];
+ bucket.m_AddLock.LockForRead( );
+ for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pElement = pElement->m_pNext )
+ {
+ if ( --nFirstElement >= 0 )
+ continue;
+
+ pHandles[ nIndex++ ] = (UtlTSHashHandle_t)pElement;
+ if ( nIndex >= nCount )
+ {
+ bucket.m_AddLock.UnlockRead( );
+ return nIndex;
+ }
+ }
+ bucket.m_AddLock.UnlockRead( );
+ }
+ return nIndex;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Insert data into the hash table given its key (KEYTYPE),
+// without a check to see if the element already exists within the tree.
+//-----------------------------------------------------------------------------
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::InsertUncommitted( KEYTYPE uiKey, HashBucket_t &bucket )
+{
+ m_bNeedsCommit = true;
+ HashFixedData_t *pNewElement = static_cast< HashFixedData_t * >( m_EntryMemory.Alloc() );
+ pNewElement->m_pNext = bucket.m_pFirstUncommitted;
+ bucket.m_pFirstUncommitted = pNewElement;
+ pNewElement->m_uiKey = uiKey;
+ return (UtlTSHashHandle_t)pNewElement;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Insert data into the hash table given its key, with
+// a check to see if the element already exists within the tree.
+//-----------------------------------------------------------------------------
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Insert( KEYTYPE uiKey, const T &data, bool *pDidInsert )
+{
+#ifdef _DEBUG
+ if ( m_ContentionCheck != 0 )
+ {
+ DebuggerBreak();
+ }
+#endif
+
+ if ( pDidInsert )
+ {
+ *pDidInsert = false;
+ }
+
+ int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
+ HashBucket_t &bucket = m_aBuckets[ iBucket ];
+
+ // First try lock-free
+ UtlTSHashHandle_t h = Find( uiKey );
+ if ( h != InvalidHandle() )
+ return h;
+
+ // Now, try again, but only look in uncommitted elements
+ bucket.m_AddLock.LockForWrite( );
+
+ h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst );
+ if ( h == InvalidHandle() )
+ {
+ h = InsertUncommitted( uiKey, bucket );
+ CopyConstruct( &Element(h), data );
+ if ( pDidInsert )
+ {
+ *pDidInsert = true;
+ }
+ }
+
+ bucket.m_AddLock.UnlockWrite( );
+ return h;
+}
+
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Insert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor, bool *pDidInsert )
+{
+#ifdef _DEBUG
+ if ( m_ContentionCheck != 0 )
+ {
+ DebuggerBreak();
+ }
+#endif
+
+ if ( pDidInsert )
+ {
+ *pDidInsert = false;
+ }
+
+ // First try lock-free
+ UtlTSHashHandle_t h = Find( uiKey );
+ if ( h != InvalidHandle() )
+ return h;
+
+ // Now, try again, but only look in uncommitted elements
+ int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
+ HashBucket_t &bucket = m_aBuckets[ iBucket ];
+ bucket.m_AddLock.LockForWrite( );
+
+ h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst );
+ if ( h == InvalidHandle() )
+ {
+ // Useful if non-trivial work needs to happen to make data; don't want to
+ // do it and then have to undo it if it turns out we don't need to add it
+ h = InsertUncommitted( uiKey, bucket );
+ pConstructor->Construct( &Element(h) );
+ if ( pDidInsert )
+ {
+ *pDidInsert = true;
+ }
+ }
+
+ bucket.m_AddLock.UnlockWrite( );
+ return h;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Insert data into the hash table given its key
+// without a check to see if the element already exists within the tree.
+//-----------------------------------------------------------------------------
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FastInsert( KEYTYPE uiKey, const T &data )
+{
+#ifdef _DEBUG
+ if ( m_ContentionCheck != 0 )
+ {
+ DebuggerBreak();
+ }
+#endif
+ int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
+ HashBucket_t &bucket = m_aBuckets[ iBucket ];
+ bucket.m_AddLock.LockForWrite( );
+ UtlTSHashHandle_t h = InsertUncommitted( uiKey, bucket );
+ CopyConstruct( &Element(h), data );
+ bucket.m_AddLock.UnlockWrite( );
+ return h;
+}
+
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FastInsert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor )
+{
+#ifdef _DEBUG
+ if ( m_ContentionCheck != 0 )
+ {
+ DebuggerBreak();
+ }
+#endif
+ int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
+ HashBucket_t &bucket = m_aBuckets[ iBucket ];
+ bucket.m_AddLock.LockForWrite( );
+ UtlTSHashHandle_t h = InsertUncommitted( uiKey, bucket );
+ pConstructor->Construct( &Element(h) );
+ bucket.m_AddLock.UnlockWrite( );
+ return h;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Commits all uncommitted insertions
+//-----------------------------------------------------------------------------
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Commit( )
+{
+ // FIXME: Is this legal? Want this to be lock-free
+ if ( !m_bNeedsCommit )
+ return;
+
+ // This must occur when no queries are occurring
+#ifdef _DEBUG
+ m_ContentionCheck++;
+#endif
+
+ for ( int i = 0; i < BUCKET_COUNT; i++ )
+ {
+ HashBucket_t &bucket = m_aBuckets[ i ];
+ bucket.m_AddLock.LockForRead( );
+ bucket.m_pFirst = bucket.m_pFirstUncommitted;
+ bucket.m_AddLock.UnlockRead( );
+ }
+
+ m_bNeedsCommit = false;
+
+#ifdef _DEBUG
+ m_ContentionCheck--;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove a single element from the hash
+//-----------------------------------------------------------------------------
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FindAndRemove( KEYTYPE uiKey )
+{
+ if ( m_EntryMemory.Count() == 0 )
+ return;
+
+ // This must occur when no queries are occurring
+#ifdef _DEBUG
+ m_ContentionCheck++;
+#endif
+
+ int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
+ HashBucket_t &bucket = m_aBuckets[ iBucket ];
+ bucket.m_AddLock.LockForWrite( );
+
+ HashFixedData_t *pPrev = NULL;
+ for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pPrev = pElement, pElement = pElement->m_pNext )
+ {
+ if ( !HashFuncs::Compare( pElement->m_uiKey, uiKey ) )
+ continue;
+
+ if ( pPrev )
+ {
+ pPrev->m_pNext = pElement->m_pNext;
+ }
+ else
+ {
+ bucket.m_pFirstUncommitted = pElement->m_pNext;
+ }
+
+ if ( bucket.m_pFirst == pElement )
+ {
+ bucket.m_pFirst = bucket.m_pFirst->m_pNext;
+ }
+
+ Destruct( &pElement->m_Data );
+
+#ifdef _DEBUG
+ memset( pElement, 0xDD, sizeof(HashFixedData_t) );
+#endif
+
+ m_EntryMemory.Free( pElement );
+
+ break;
+ }
+
+ bucket.m_AddLock.UnlockWrite( );
+
+#ifdef _DEBUG
+ m_ContentionCheck--;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove all elements from the hash
+//-----------------------------------------------------------------------------
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::RemoveAll( void )
+{
+ m_bNeedsCommit = false;
+ if ( m_EntryMemory.Count() == 0 )
+ return;
+
+ // This must occur when no queries are occurring
+#ifdef _DEBUG
+ m_ContentionCheck++;
+#endif
+
+ for ( int i = 0; i < BUCKET_COUNT; i++ )
+ {
+ HashBucket_t &bucket = m_aBuckets[ i ];
+
+ bucket.m_AddLock.LockForWrite( );
+
+ for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pElement = pElement->m_pNext )
+ {
+ Destruct( &pElement->m_Data );
+ }
+
+ bucket.m_pFirst = NULL;
+ bucket.m_pFirstUncommitted = NULL;
+ bucket.m_AddLock.UnlockWrite( );
+ }
+
+ m_EntryMemory.Clear();
+
+#ifdef _DEBUG
+ m_ContentionCheck--;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Finds an element, but only in the committed elements
+//-----------------------------------------------------------------------------
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement )
+{
+#ifdef _DEBUG
+ if ( m_ContentionCheck != 0 )
+ {
+ DebuggerBreak();
+ }
+#endif
+
+ for ( HashFixedData_t *pElement = pFirstElement; pElement != pLastElement; pElement = pElement->m_pNext )
+ {
+ if ( HashFuncs::Compare( pElement->m_uiKey, uiKey ) )
+ return (UtlTSHashHandle_t)pElement;
+ }
+ return InvalidHandle();
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds an element, but only in the committed elements
+//-----------------------------------------------------------------------------
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Find( KEYTYPE uiKey )
+{
+ int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
+ const HashBucket_t &bucket = m_aBuckets[iBucket];
+ UtlTSHashHandle_t h = Find( uiKey, bucket.m_pFirst, NULL );
+ if ( h != InvalidHandle() )
+ return h;
+
+ // Didn't find it in the fast ( committed ) list. Let's try the slow ( uncommitted ) one
+ bucket.m_AddLock.LockForRead( );
+ h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst );
+ bucket.m_AddLock.UnlockRead( );
+
+ return h;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Return data given a hash handle.
+//-----------------------------------------------------------------------------
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline T &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Element( UtlTSHashHandle_t hHash )
+{
+ return ((HashFixedData_t *)hHash)->m_Data;
+}
+
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline T const &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Element( UtlTSHashHandle_t hHash ) const
+{
+ return ((HashFixedData_t *)hHash)->m_Data;
+}
+
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline T &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::operator[]( UtlTSHashHandle_t hHash )
+{
+ return ((HashFixedData_t *)hHash)->m_Data;
+}
+
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline T const &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::operator[]( UtlTSHashHandle_t hHash ) const
+{
+ return ((HashFixedData_t *)hHash)->m_Data;
+}
+
+
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline KEYTYPE CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::GetID( UtlTSHashHandle_t hHash ) const
+{
+ return ((HashFixedData_t *)hHash)->m_uiKey;
+}
+
+
+// Convert element * to hashHandle
+template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
+inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::ElementPtrToHandle( T* pElement ) const
+{
+ Assert( pElement );
+ HashFixedData_t *pFixedData = (HashFixedData_t*)( (uint8*)pElement - offsetof( HashFixedData_t, m_Data ) );
+ Assert( m_EntryMemory.IsAllocationWithinPool( pFixedData ) );
+ return (UtlTSHashHandle_t)pFixedData;
+}
+
+
+#endif // UTLTSHASH_H
diff --git a/public/tier1/utlvector.h b/public/tier1/utlvector.h
new file mode 100644
index 0000000..15b1e26
--- /dev/null
+++ b/public/tier1/utlvector.h
@@ -0,0 +1,1513 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+// A growable array class that maintains a free list and keeps elements
+// in the same location
+//=============================================================================//
+
+#ifndef UTLVECTOR_H
+#define UTLVECTOR_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <algorithm>
+
+#include <string.h>
+#include "tier0/platform.h"
+#include "tier0/dbg.h"
+#include "tier0/threadtools.h"
+#include "tier1/utlmemory.h"
+#include "tier1/utlblockmemory.h"
+#include "tier1/strtools.h"
+#include "vstdlib/random.h"
+
+#define FOR_EACH_VEC( vecName, iteratorName ) \
+ for ( int iteratorName = 0; (vecName).IsUtlVector && iteratorName < (vecName).Count(); iteratorName++ )
+#define FOR_EACH_VEC_BACK( vecName, iteratorName ) \
+ for ( int iteratorName = (vecName).Count()-1; (vecName).IsUtlVector && iteratorName >= 0; iteratorName-- )
+
+// UtlVector derives from this so we can do the type check above
+struct base_vector_t
+{
+public:
+ enum { IsUtlVector = true }; // Used to match this at compiletime
+};
+
+//-----------------------------------------------------------------------------
+// The CUtlVector class:
+// A growable array class which doubles in size by default.
+// It will always keep all elements consecutive in memory, and may move the
+// elements around in memory (via a PvRealloc) when elements are inserted or
+// removed. Clients should therefore refer to the elements of the vector
+// by index (they should *never* maintain pointers to elements in the vector).
+//-----------------------------------------------------------------------------
+template< class T, class A = CUtlMemory<T> >
+class CUtlVector : public base_vector_t
+{
+ typedef A CAllocator;
+public:
+ typedef T ElemType_t;
+ typedef T* iterator;
+ typedef const T* const_iterator;
+
+ // Set the growth policy and initial capacity. Count will always be zero. This is different from std::vector
+ // where the constructor sets count as well as capacity.
+ // growSize of zero implies the default growth pattern which is exponential.
+ explicit CUtlVector( int growSize = 0, int initialCapacity = 0 );
+
+ // Initialize with separately allocated buffer, setting the capacity and count.
+ // The container will not be growable.
+ CUtlVector( T* pMemory, int initialCapacity, int initialCount = 0 );
+ ~CUtlVector();
+
+ // Copy the array.
+ CUtlVector<T, A>& operator=( const CUtlVector<T, A> &other );
+
+ // element access
+ T& operator[]( int i );
+ const T& operator[]( int i ) const;
+ T& Element( int i );
+ const T& Element( int i ) const;
+ T& Head();
+ const T& Head() const;
+ T& Tail();
+ const T& Tail() const;
+ T& Random();
+ const T& Random() const;
+
+ // STL compatible member functions. These allow easier use of std::sort
+ // and they are forward compatible with the C++ 11 range-based for loops.
+ iterator begin() { return Base(); }
+ const_iterator begin() const { return Base(); }
+ iterator end() { return Base() + Count(); }
+ const_iterator end() const { return Base() + Count(); }
+
+ // Gets the base address (can change when adding elements!)
+ T* Base() { return m_Memory.Base(); }
+ const T* Base() const { return m_Memory.Base(); }
+
+ // Returns the number of elements in the vector
+ // SIZE IS DEPRECATED!
+ int Count() const;
+ int Size() const; // don't use me!
+
+ /// are there no elements? For compatibility with lists.
+ inline bool IsEmpty( void ) const
+ {
+ return ( Count() == 0 );
+ }
+
+ // Is element index valid?
+ bool IsValidIndex( int i ) const;
+ static int InvalidIndex();
+
+ // Adds an element, uses default constructor
+ int AddToHead();
+ int AddToTail();
+ T *AddToTailGetPtr();
+ int InsertBefore( int elem );
+ int InsertAfter( int elem );
+
+ // Adds an element, uses copy constructor
+ int AddToHead( const T& src );
+ int AddToTail( const T& src );
+ int InsertBefore( int elem, const T& src );
+ int InsertAfter( int elem, const T& src );
+
+ // Adds multiple elements, uses default constructor
+ int AddMultipleToHead( int num );
+ int AddMultipleToTail( int num );
+ int AddMultipleToTail( int num, const T *pToCopy );
+ int InsertMultipleBefore( int elem, int num );
+ int InsertMultipleBefore( int elem, int num, const T *pToCopy );
+ int InsertMultipleAfter( int elem, int num );
+
+ // Calls RemoveAll() then AddMultipleToTail.
+ // SetSize is a synonym for SetCount
+ void SetSize( int size );
+ // SetCount deletes the previous contents of the container and sets the
+ // container to have this many elements.
+ // Use GetCount to retrieve the current count.
+ void SetCount( int count );
+ void SetCountNonDestructively( int count ); //sets count by adding or removing elements to tail TODO: This should probably be the default behavior for SetCount
+
+ // Calls SetSize and copies each element.
+ void CopyArray( const T *pArray, int size );
+
+ // Fast swap
+ void Swap( CUtlVector< T, A > &vec );
+
+ // Add the specified array to the tail.
+ int AddVectorToTail( CUtlVector<T, A> const &src );
+
+ // Finds an element (element needs operator== defined)
+ int Find( const T& src ) const;
+
+ // Helper to find using std::find_if with a predicate
+ // e.g. [] -> bool ( T &a ) { return a.IsTheThingIWant(); }
+ //
+ // Useful if your object doesn't define a ==
+ template < typename F >
+ int FindPredicate( F&& predicate ) const;
+
+ void FillWithValue( const T& src );
+
+ bool HasElement( const T& src ) const;
+
+ // Makes sure we have enough memory allocated to store a requested # of elements
+ // Use NumAllocated() to retrieve the current capacity.
+ void EnsureCapacity( int num );
+
+ // Makes sure we have at least this many elements
+ // Use GetCount to retrieve the current count.
+ void EnsureCount( int num );
+
+ // Element removal
+ void FastRemove( int elem ); // doesn't preserve order
+ void Remove( int elem ); // preserves order, shifts elements
+ bool FindAndRemove( const T& src ); // removes first occurrence of src, preserves order, shifts elements
+ bool FindAndFastRemove( const T& src ); // removes first occurrence of src, doesn't preserve order
+ void RemoveMultiple( int elem, int num ); // preserves order, shifts elements
+ void RemoveMultipleFromHead(int num); // removes num elements from tail
+ void RemoveMultipleFromTail(int num); // removes num elements from tail
+ void RemoveAll(); // doesn't deallocate memory
+
+ // Memory deallocation
+ void Purge();
+
+ // Purges the list and calls delete on each element in it.
+ void PurgeAndDeleteElements();
+
+ // Compacts the vector to the number of elements actually in use
+ void Compact();
+
+ // Set the size by which it grows when it needs to allocate more memory.
+ void SetGrowSize( int size ) { m_Memory.SetGrowSize( size ); }
+
+ int NumAllocated() const; // Only use this if you really know what you're doing!
+
+ void Sort( int (__cdecl *pfnCompare)(const T *, const T *) );
+
+ void Shuffle( IUniformRandomStream* pSteam = NULL );
+
+ // Call this to quickly sort non-contiguously allocated vectors
+ void InPlaceQuickSort( int (__cdecl *pfnCompare)(const T *, const T *) );
+ // reverse the order of elements
+ void Reverse( );
+
+#ifdef DBGFLAG_VALIDATE
+ void Validate( CValidator &validator, char *pchName ); // Validate our internal structures
+#endif // DBGFLAG_VALIDATE
+
+ /// sort using std:: and expecting a "<" function to be defined for the type
+ void Sort( void );
+
+ /// sort using std:: with a predicate. e.g. [] -> bool ( T &a, T &b ) { return a < b; }
+ template <class F> void SortPredicate( F &&predicate );
+
+protected:
+ // Can't copy this unless we explicitly do it!
+ CUtlVector( CUtlVector const& vec ) { Assert(0); }
+
+ // Grows the vector
+ void GrowVector( int num = 1 );
+
+ // Shifts elements....
+ void ShiftElementsRight( int elem, int num = 1 );
+ void ShiftElementsLeft( int elem, int num = 1 );
+
+ CAllocator m_Memory;
+ int m_Size;
+
+#ifndef _X360
+ // For easier access to the elements through the debugger
+ // it's in release builds so this can be used in libraries correctly
+ T *m_pElements;
+
+ inline void ResetDbgInfo()
+ {
+ m_pElements = Base();
+ }
+#else
+ inline void ResetDbgInfo() {}
+#endif
+
+private:
+ void InPlaceQuickSort_r( int (__cdecl *pfnCompare)(const T *, const T *), int nLeft, int nRight );
+};
+
+
+// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice
+template < class T >
+class CUtlBlockVector : public CUtlVector< T, CUtlBlockMemory< T, int > >
+{
+public:
+ explicit CUtlBlockVector( int growSize = 0, int initSize = 0 )
+ : CUtlVector< T, CUtlBlockMemory< T, int > >( growSize, initSize ) {}
+};
+
+//-----------------------------------------------------------------------------
+// The CUtlVectorMT class:
+// An array class with spurious mutex protection. Nothing is actually protected
+// unless you call Lock and Unlock. Also, the Mutex_t is actually not a type
+// but a member which probably isn't used.
+//-----------------------------------------------------------------------------
+
+template< class BASE_UTLVECTOR, class MUTEX_TYPE = CThreadFastMutex >
+class CUtlVectorMT : public BASE_UTLVECTOR, public MUTEX_TYPE
+{
+ typedef BASE_UTLVECTOR BaseClass;
+public:
+ // MUTEX_TYPE Mutex_t;
+
+ // constructor, destructor
+ explicit CUtlVectorMT( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {}
+ CUtlVectorMT( typename BaseClass::ElemType_t* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {}
+};
+
+
+//-----------------------------------------------------------------------------
+// The CUtlVectorFixed class:
+// A array class with a fixed allocation scheme
+//-----------------------------------------------------------------------------
+template< class T, size_t MAX_SIZE >
+class CUtlVectorFixed : public CUtlVector< T, CUtlMemoryFixed<T, MAX_SIZE > >
+{
+ typedef CUtlVector< T, CUtlMemoryFixed<T, MAX_SIZE > > BaseClass;
+public:
+
+ // constructor, destructor
+ explicit CUtlVectorFixed( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {}
+ CUtlVectorFixed( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {}
+};
+
+
+//-----------------------------------------------------------------------------
+// The CUtlVectorFixedGrowable class:
+// A array class with a fixed allocation scheme backed by a dynamic one
+//-----------------------------------------------------------------------------
+template< class T, size_t MAX_SIZE >
+class CUtlVectorFixedGrowable : public CUtlVector< T, CUtlMemoryFixedGrowable<T, MAX_SIZE > >
+{
+ typedef CUtlVector< T, CUtlMemoryFixedGrowable<T, MAX_SIZE > > BaseClass;
+
+public:
+ // constructor, destructor
+ explicit CUtlVectorFixedGrowable( int growSize = 0 ) : BaseClass( growSize, MAX_SIZE ) {}
+};
+
+
+//-----------------------------------------------------------------------------
+// The CUtlVectorConservative class:
+// A array class with a conservative allocation scheme
+//-----------------------------------------------------------------------------
+template< class T >
+class CUtlVectorConservative : public CUtlVector< T, CUtlMemoryConservative<T> >
+{
+ typedef CUtlVector< T, CUtlMemoryConservative<T> > BaseClass;
+public:
+
+ // constructor, destructor
+ explicit CUtlVectorConservative( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {}
+ CUtlVectorConservative( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {}
+};
+
+
+//-----------------------------------------------------------------------------
+// The CUtlVectorUltra Conservative class:
+// A array class with a very conservative allocation scheme, with customizable allocator
+// Especialy useful if you have a lot of vectors that are sparse, or if you're
+// carefully packing holders of vectors
+//-----------------------------------------------------------------------------
+#pragma warning(push)
+#pragma warning(disable : 4200) // warning C4200: nonstandard extension used : zero-sized array in struct/union
+#pragma warning(disable : 4815 ) // warning C4815: 'staticData' : zero-sized array in stack object will have no elements
+
+class CUtlVectorUltraConservativeAllocator
+{
+public:
+ static void *Alloc( size_t nSize )
+ {
+ return malloc( nSize );
+ }
+
+ static void *Realloc( void *pMem, size_t nSize )
+ {
+ return realloc( pMem, nSize );
+ }
+
+ static void Free( void *pMem )
+ {
+ free( pMem );
+ }
+
+ static size_t GetSize( void *pMem )
+ {
+ return mallocsize( pMem );
+ }
+
+};
+
+template <typename T, typename A = CUtlVectorUltraConservativeAllocator >
+class CUtlVectorUltraConservative : private A
+{
+public:
+ // Don't inherit from base_vector_t because multiple-inheritance increases
+ // class size!
+ enum { IsUtlVector = true }; // Used to match this at compiletime
+
+ CUtlVectorUltraConservative()
+ {
+ m_pData = StaticData();
+ }
+
+ ~CUtlVectorUltraConservative()
+ {
+ RemoveAll();
+ }
+
+ int Count() const
+ {
+ return m_pData->m_Size;
+ }
+
+ static int InvalidIndex()
+ {
+ return -1;
+ }
+
+ inline bool IsValidIndex( int i ) const
+ {
+ return (i >= 0) && (i < Count());
+ }
+
+ T& operator[]( int i )
+ {
+ Assert( IsValidIndex( i ) );
+ return m_pData->m_Elements[i];
+ }
+
+ const T& operator[]( int i ) const
+ {
+ Assert( IsValidIndex( i ) );
+ return m_pData->m_Elements[i];
+ }
+
+ T& Element( int i )
+ {
+ Assert( IsValidIndex( i ) );
+ return m_pData->m_Elements[i];
+ }
+
+ const T& Element( int i ) const
+ {
+ Assert( IsValidIndex( i ) );
+ return m_pData->m_Elements[i];
+ }
+
+ void EnsureCapacity( int num )
+ {
+ int nCurCount = Count();
+ if ( num <= nCurCount )
+ {
+ return;
+ }
+ if ( m_pData == StaticData() )
+ {
+ m_pData = (Data_t *)A::Alloc( sizeof(Data_t) + ( num * sizeof(T) ) );
+ m_pData->m_Size = 0;
+ }
+ else
+ {
+ int nNeeded = sizeof(Data_t) + ( num * sizeof(T) );
+ int nHave = A::GetSize( m_pData );
+ if ( nNeeded > nHave )
+ {
+ m_pData = (Data_t *)A::Realloc( m_pData, nNeeded );
+ }
+ }
+ }
+
+ int AddToTail( const T& src )
+ {
+ int iNew = Count();
+ EnsureCapacity( Count() + 1 );
+ m_pData->m_Elements[iNew] = src;
+ m_pData->m_Size++;
+ return iNew;
+ }
+
+ void RemoveAll()
+ {
+ if ( Count() )
+ {
+ for (int i = m_pData->m_Size; --i >= 0; )
+ {
+ // Global scope to resolve conflict with Scaleform 4.0
+ ::Destruct(&m_pData->m_Elements[i]);
+ }
+ }
+ if ( m_pData != StaticData() )
+ {
+ A::Free( m_pData );
+ m_pData = StaticData();
+
+ }
+ }
+
+ void PurgeAndDeleteElements()
+ {
+ if ( m_pData != StaticData() )
+ {
+ for( int i=0; i < m_pData->m_Size; i++ )
+ {
+ delete Element(i);
+ }
+ RemoveAll();
+ }
+ }
+
+ void FastRemove( int elem )
+ {
+ Assert( IsValidIndex(elem) );
+
+ // Global scope to resolve conflict with Scaleform 4.0
+ ::Destruct( &Element(elem) );
+ if (Count() > 0)
+ {
+ if ( elem != m_pData->m_Size -1 )
+ memcpy( &Element(elem), &Element(m_pData->m_Size-1), sizeof(T) );
+ --m_pData->m_Size;
+ }
+ if ( !m_pData->m_Size )
+ {
+ A::Free( m_pData );
+ m_pData = StaticData();
+ }
+ }
+
+ void Remove( int elem )
+ {
+ // Global scope to resolve conflict with Scaleform 4.0
+ ::Destruct( &Element(elem) );
+ ShiftElementsLeft(elem);
+ --m_pData->m_Size;
+ if ( !m_pData->m_Size )
+ {
+ A::Free( m_pData );
+ m_pData = StaticData();
+ }
+ }
+
+ int Find( const T& src ) const
+ {
+ int nCount = Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ if (Element(i) == src)
+ return i;
+ }
+ return -1;
+ }
+
+ bool FindAndRemove( const T& src )
+ {
+ int elem = Find( src );
+ if ( elem != -1 )
+ {
+ Remove( elem );
+ return true;
+ }
+ return false;
+ }
+
+
+ bool FindAndFastRemove( const T& src )
+ {
+ int elem = Find( src );
+ if ( elem != -1 )
+ {
+ FastRemove( elem );
+ return true;
+ }
+ return false;
+ }
+
+ bool DebugCompileError_ANonVectorIsUsedInThe_FOR_EACH_VEC_Macro( void ) const { return true; }
+
+ struct Data_t
+ {
+ int m_Size;
+ T m_Elements[0];
+ };
+
+ Data_t *m_pData;
+private:
+ void ShiftElementsLeft( int elem, int num = 1 )
+ {
+ int Size = Count();
+ Assert( IsValidIndex(elem) || ( Size == 0 ) || ( num == 0 ));
+ int numToMove = Size - elem - num;
+ if ((numToMove > 0) && (num > 0))
+ {
+ Q_memmove( &Element(elem), &Element(elem+num), numToMove * sizeof(T) );
+
+#ifdef _DEBUG
+ Q_memset( &Element(Size-num), 0xDD, num * sizeof(T) );
+#endif
+ }
+ }
+
+
+
+ static Data_t *StaticData()
+ {
+ static Data_t staticData;
+ Assert( staticData.m_Size == 0 );
+ return &staticData;
+ }
+};
+
+#pragma warning(pop)
+
+// Make sure nobody adds multiple inheritance and makes this class bigger.
+COMPILE_TIME_ASSERT( sizeof(CUtlVectorUltraConservative<int>) == sizeof(void*) );
+
+
+//-----------------------------------------------------------------------------
+// The CCopyableUtlVector class:
+// A array class that allows copy construction (so you can nest a CUtlVector inside of another one of our containers)
+// WARNING - this class lets you copy construct which can be an expensive operation if you don't carefully control when it happens
+// Only use this when nesting a CUtlVector() inside of another one of our container classes (i.e a CUtlMap)
+//-----------------------------------------------------------------------------
+template< class T >
+class CCopyableUtlVector : public CUtlVector< T, CUtlMemory<T> >
+{
+ typedef CUtlVector< T, CUtlMemory<T> > BaseClass;
+public:
+ explicit CCopyableUtlVector( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {}
+ CCopyableUtlVector( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {}
+ virtual ~CCopyableUtlVector() {}
+ CCopyableUtlVector( CCopyableUtlVector const& vec ) { this->CopyArray( vec.Base(), vec.Count() ); }
+};
+
+//-----------------------------------------------------------------------------
+// The CCopyableUtlVector class:
+// A array class that allows copy construction (so you can nest a CUtlVector inside of another one of our containers)
+// WARNING - this class lets you copy construct which can be an expensive operation if you don't carefully control when it happens
+// Only use this when nesting a CUtlVector() inside of another one of our container classes (i.e a CUtlMap)
+//-----------------------------------------------------------------------------
+template< class T, size_t MAX_SIZE >
+class CCopyableUtlVectorFixed : public CUtlVectorFixed< T, MAX_SIZE >
+{
+ typedef CUtlVectorFixed< T, MAX_SIZE > BaseClass;
+public:
+ explicit CCopyableUtlVectorFixed( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {}
+ CCopyableUtlVectorFixed( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {}
+ virtual ~CCopyableUtlVectorFixed() {}
+ CCopyableUtlVectorFixed( CCopyableUtlVectorFixed const& vec ) { this->CopyArray( vec.Base(), vec.Count() ); }
+};
+
+// TODO (Ilya): It seems like all the functions in CUtlVector are simple enough that they should be inlined.
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+inline CUtlVector<T, A>::CUtlVector( int growSize, int initSize ) :
+ m_Memory(growSize, initSize), m_Size(0)
+{
+ ResetDbgInfo();
+}
+
+template< typename T, class A >
+inline CUtlVector<T, A>::CUtlVector( T* pMemory, int allocationCount, int numElements ) :
+ m_Memory(pMemory, allocationCount), m_Size(numElements)
+{
+ ResetDbgInfo();
+}
+
+template< typename T, class A >
+inline CUtlVector<T, A>::~CUtlVector()
+{
+ Purge();
+}
+
+template< typename T, class A >
+inline CUtlVector<T, A>& CUtlVector<T, A>::operator=( const CUtlVector<T, A> &other )
+{
+ int nCount = other.Count();
+ SetSize( nCount );
+ for ( int i = 0; i < nCount; i++ )
+ {
+ (*this)[ i ] = other[ i ];
+ }
+ return *this;
+}
+
+#ifdef STAGING_ONLY
+inline void StagingUtlVectorBoundsCheck( int i, int size )
+{
+ if ( (unsigned)i >= (unsigned)size )
+ {
+ Msg( "Array access error: %d / %d\n", i, size );
+ DebuggerBreak();
+ }
+}
+
+#else
+#define StagingUtlVectorBoundsCheck( _i, _size )
+#endif
+
+//-----------------------------------------------------------------------------
+// element access
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+inline T& CUtlVector<T, A>::operator[]( int i )
+{
+ // Do an inline unsigned check for maximum debug-build performance.
+ Assert( (unsigned)i < (unsigned)m_Size );
+ StagingUtlVectorBoundsCheck( i, m_Size );
+ return m_Memory[ i ];
+}
+
+template< typename T, class A >
+inline const T& CUtlVector<T, A>::operator[]( int i ) const
+{
+ // Do an inline unsigned check for maximum debug-build performance.
+ Assert( (unsigned)i < (unsigned)m_Size );
+ StagingUtlVectorBoundsCheck( i, m_Size );
+ return m_Memory[ i ];
+}
+
+template< typename T, class A >
+inline T& CUtlVector<T, A>::Element( int i )
+{
+ // Do an inline unsigned check for maximum debug-build performance.
+ Assert( (unsigned)i < (unsigned)m_Size );
+ StagingUtlVectorBoundsCheck( i, m_Size );
+ return m_Memory[ i ];
+}
+
+template< typename T, class A >
+inline const T& CUtlVector<T, A>::Element( int i ) const
+{
+ // Do an inline unsigned check for maximum debug-build performance.
+ Assert( (unsigned)i < (unsigned)m_Size );
+ StagingUtlVectorBoundsCheck( i, m_Size );
+ return m_Memory[ i ];
+}
+
+template< typename T, class A >
+inline T& CUtlVector<T, A>::Head()
+{
+ Assert( m_Size > 0 );
+ StagingUtlVectorBoundsCheck( 0, m_Size );
+ return m_Memory[ 0 ];
+}
+
+template< typename T, class A >
+inline const T& CUtlVector<T, A>::Head() const
+{
+ Assert( m_Size > 0 );
+ StagingUtlVectorBoundsCheck( 0, m_Size );
+ return m_Memory[ 0 ];
+}
+
+template< typename T, class A >
+inline T& CUtlVector<T, A>::Tail()
+{
+ Assert( m_Size > 0 );
+ StagingUtlVectorBoundsCheck( 0, m_Size );
+ return m_Memory[ m_Size - 1 ];
+}
+
+template< typename T, class A >
+inline const T& CUtlVector<T, A>::Tail() const
+{
+ Assert( m_Size > 0 );
+ StagingUtlVectorBoundsCheck( 0, m_Size );
+ return m_Memory[ m_Size - 1 ];
+}
+
+
+//-----------------------------------------------------------------------------
+// Count
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+inline int CUtlVector<T, A>::Size() const
+{
+ return m_Size;
+}
+
+template< typename T, class A >
+inline T& CUtlVector<T, A>::Random()
+{
+ Assert( m_Size > 0 );
+ return m_Memory[ RandomInt( 0, m_Size - 1 ) ];
+}
+
+template< typename T, class A >
+inline const T& CUtlVector<T, A>::Random() const
+{
+ Assert( m_Size > 0 );
+ return m_Memory[ RandomInt( 0, m_Size - 1 ) ];
+}
+
+
+//-----------------------------------------------------------------------------
+// Shuffle - Knuth/Fisher-Yates
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+void CUtlVector<T, A>::Shuffle( IUniformRandomStream* pSteam )
+{
+ for ( int i = 0; i < m_Size; i++ )
+ {
+ int j = pSteam ? pSteam->RandomInt( i, m_Size - 1 ) : RandomInt( i, m_Size - 1 );
+ if ( i != j )
+ {
+ V_swap( m_Memory[ i ], m_Memory[ j ] );
+ }
+ }
+}
+
+template< typename T, class A >
+inline int CUtlVector<T, A>::Count() const
+{
+ return m_Size;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// Reverse - reverse the order of elements, akin to std::vector<>::reverse()
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+void CUtlVector<T, A>::Reverse( )
+{
+ for ( int i = 0; i < m_Size / 2; i++ )
+ {
+ V_swap( m_Memory[ i ], m_Memory[ m_Size - 1 - i ] );
+#if defined( UTLVECTOR_TRACK_STACKS )
+ if ( bTrackingEnabled )
+ {
+ V_swap( m_pElementStackStatsIndices[ i ], m_pElementStackStatsIndices[ m_Size - 1 - i ] );
+ }
+#endif
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Is element index valid?
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+inline bool CUtlVector<T, A>::IsValidIndex( int i ) const
+{
+ return (i >= 0) && (i < m_Size);
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns in invalid index
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+inline int CUtlVector<T, A>::InvalidIndex()
+{
+ return -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Grows the vector
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+void CUtlVector<T, A>::GrowVector( int num )
+{
+ if (m_Size + num > m_Memory.NumAllocated())
+ {
+ MEM_ALLOC_CREDIT_CLASS();
+ m_Memory.Grow( m_Size + num - m_Memory.NumAllocated() );
+ }
+
+ m_Size += num;
+ ResetDbgInfo();
+}
+
+
+//-----------------------------------------------------------------------------
+// Sorts the vector
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+void CUtlVector<T, A>::Sort( int (__cdecl *pfnCompare)(const T *, const T *) )
+{
+ typedef int (__cdecl *QSortCompareFunc_t)(const void *, const void *);
+ if ( Count() <= 1 )
+ return;
+
+ if ( Base() )
+ {
+ qsort( Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare) );
+ }
+ else
+ {
+ Assert( 0 );
+ // this path is untested
+ // if you want to sort vectors that use a non-sequential memory allocator,
+ // you'll probably want to patch in a quicksort algorithm here
+ // I just threw in this bubble sort to have something just in case...
+
+ for ( int i = m_Size - 1; i >= 0; --i )
+ {
+ for ( int j = 1; j <= i; ++j )
+ {
+ if ( pfnCompare( &Element( j - 1 ), &Element( j ) ) < 0 )
+ {
+ V_swap( Element( j - 1 ), Element( j ) );
+ }
+ }
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------------------------------
+// Private function that does the in-place quicksort for non-contiguously allocated vectors.
+//----------------------------------------------------------------------------------------------
+template< typename T, class A >
+void CUtlVector<T, A>::InPlaceQuickSort_r( int (__cdecl *pfnCompare)(const T *, const T *), int nLeft, int nRight )
+{
+ int nPivot;
+ int nLeftIdx = nLeft;
+ int nRightIdx = nRight;
+
+ if ( nRight - nLeft > 0 )
+ {
+ nPivot = ( nLeft + nRight ) / 2;
+
+ while ( ( nLeftIdx <= nPivot ) && ( nRightIdx >= nPivot ) )
+ {
+ while ( ( pfnCompare( &Element( nLeftIdx ), &Element( nPivot ) ) < 0 ) && ( nLeftIdx <= nPivot ) )
+ {
+ nLeftIdx++;
+ }
+
+ while ( ( pfnCompare( &Element( nRightIdx ), &Element( nPivot ) ) > 0 ) && ( nRightIdx >= nPivot ) )
+ {
+ nRightIdx--;
+ }
+
+ V_swap( Element( nLeftIdx ), Element( nRightIdx ) );
+
+ nLeftIdx++;
+ nRightIdx--;
+
+ if ( ( nLeftIdx - 1 ) == nPivot )
+ {
+ nPivot = nRightIdx = nRightIdx + 1;
+ }
+ else if ( nRightIdx + 1 == nPivot )
+ {
+ nPivot = nLeftIdx = nLeftIdx - 1;
+ }
+ }
+
+ InPlaceQuickSort_r( pfnCompare, nLeft, nPivot - 1 );
+ InPlaceQuickSort_r( pfnCompare, nPivot + 1, nRight );
+ }
+}
+
+
+//----------------------------------------------------------------------------------------------
+// Call this to quickly sort non-contiguously allocated vectors. Sort uses a slower bubble sort.
+//----------------------------------------------------------------------------------------------
+template< typename T, class A >
+void CUtlVector<T, A>::InPlaceQuickSort( int (__cdecl *pfnCompare)(const T *, const T *) )
+{
+ InPlaceQuickSort_r( pfnCompare, 0, Count() - 1 );
+}
+
+template< typename T, class A >
+void CUtlVector<T, A>::Sort( void )
+{
+ //STACK STATS TODO: Do we care about allocation tracking precision enough to match element origins across a sort?
+ std::sort( Base(), Base() + Count() );
+}
+
+template< typename T, class A >
+template <class F>
+void CUtlVector<T, A>::SortPredicate( F &&predicate )
+{
+ std::sort( Base(), Base() + Count(), predicate );
+}
+
+//-----------------------------------------------------------------------------
+// Makes sure we have enough memory allocated to store a requested # of elements
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+void CUtlVector<T, A>::EnsureCapacity( int num )
+{
+ MEM_ALLOC_CREDIT_CLASS();
+ m_Memory.EnsureCapacity(num);
+ ResetDbgInfo();
+}
+
+
+//-----------------------------------------------------------------------------
+// Makes sure we have at least this many elements
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+void CUtlVector<T, A>::EnsureCount( int num )
+{
+ if (Count() < num)
+ {
+ AddMultipleToTail( num - Count() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Shifts elements
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+void CUtlVector<T, A>::ShiftElementsRight( int elem, int num )
+{
+ Assert( IsValidIndex(elem) || ( m_Size == 0 ) || ( num == 0 ));
+ int numToMove = m_Size - elem - num;
+ if ((numToMove > 0) && (num > 0))
+ Q_memmove( &Element(elem+num), &Element(elem), numToMove * sizeof(T) );
+}
+
+template< typename T, class A >
+void CUtlVector<T, A>::ShiftElementsLeft( int elem, int num )
+{
+ Assert( IsValidIndex(elem) || ( m_Size == 0 ) || ( num == 0 ));
+ int numToMove = m_Size - elem - num;
+ if ((numToMove > 0) && (num > 0))
+ {
+ Q_memmove( &Element(elem), &Element(elem+num), numToMove * sizeof(T) );
+
+#ifdef _DEBUG
+ Q_memset( &Element(m_Size-num), 0xDD, num * sizeof(T) );
+#endif
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds an element, uses default constructor
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+inline int CUtlVector<T, A>::AddToHead()
+{
+ return InsertBefore(0);
+}
+
+template< typename T, class A >
+inline int CUtlVector<T, A>::AddToTail()
+{
+ return InsertBefore( m_Size );
+}
+
+template< typename T, class A >
+inline T *CUtlVector<T, A>::AddToTailGetPtr()
+{
+ return &Element( AddToTail() );
+}
+
+template< typename T, class A >
+inline int CUtlVector<T, A>::InsertAfter( int elem )
+{
+ return InsertBefore( elem + 1 );
+}
+
+template< typename T, class A >
+int CUtlVector<T, A>::InsertBefore( int elem )
+{
+ // Can insert at the end
+ Assert( (elem == Count()) || IsValidIndex(elem) );
+
+ GrowVector();
+ ShiftElementsRight(elem);
+ Construct( &Element(elem) );
+ return elem;
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds an element, uses copy constructor
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+inline int CUtlVector<T, A>::AddToHead( const T& src )
+{
+ // Can't insert something that's in the list... reallocation may hose us
+ Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) );
+ return InsertBefore( 0, src );
+}
+
+template< typename T, class A >
+inline int CUtlVector<T, A>::AddToTail( const T& src )
+{
+ // Can't insert something that's in the list... reallocation may hose us
+ Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) );
+ return InsertBefore( m_Size, src );
+}
+
+template< typename T, class A >
+inline int CUtlVector<T, A>::InsertAfter( int elem, const T& src )
+{
+ // Can't insert something that's in the list... reallocation may hose us
+ Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) );
+ return InsertBefore( elem + 1, src );
+}
+
+template< typename T, class A >
+int CUtlVector<T, A>::InsertBefore( int elem, const T& src )
+{
+ // Can't insert something that's in the list... reallocation may hose us
+ Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) );
+
+ // Can insert at the end
+ Assert( (elem == Count()) || IsValidIndex(elem) );
+
+ GrowVector();
+ ShiftElementsRight(elem);
+ CopyConstruct( &Element(elem), src );
+ return elem;
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds multiple elements, uses default constructor
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+inline int CUtlVector<T, A>::AddMultipleToHead( int num )
+{
+ return InsertMultipleBefore( 0, num );
+}
+
+template< typename T, class A >
+inline int CUtlVector<T, A>::AddMultipleToTail( int num )
+{
+ return InsertMultipleBefore( m_Size, num );
+}
+
+template< typename T, class A >
+inline int CUtlVector<T, A>::AddMultipleToTail( int num, const T *pToCopy )
+{
+ // Can't insert something that's in the list... reallocation may hose us
+ Assert( (Base() == NULL) || !pToCopy || (pToCopy + num <= Base()) || (pToCopy >= (Base() + Count()) ) );
+
+ return InsertMultipleBefore( m_Size, num, pToCopy );
+}
+
+template< typename T, class A >
+int CUtlVector<T, A>::InsertMultipleAfter( int elem, int num )
+{
+ return InsertMultipleBefore( elem + 1, num );
+}
+
+
+template< typename T, class A >
+void CUtlVector<T, A>::SetCount( int count )
+{
+ RemoveAll();
+ AddMultipleToTail( count );
+}
+
+template< typename T, class A >
+inline void CUtlVector<T, A>::SetSize( int size )
+{
+ SetCount( size );
+}
+
+template< typename T, class A >
+void CUtlVector<T, A>::SetCountNonDestructively( int count )
+{
+ int delta = count - m_Size;
+ if(delta > 0) AddMultipleToTail( delta );
+ else if(delta < 0) RemoveMultipleFromTail( -delta );
+}
+
+template< typename T, class A >
+void CUtlVector<T, A>::CopyArray( const T *pArray, int size )
+{
+ // Can't insert something that's in the list... reallocation may hose us
+ Assert( (Base() == NULL) || !pArray || (Base() >= (pArray + size)) || (pArray >= (Base() + Count()) ) );
+
+ SetSize( size );
+ for( int i=0; i < size; i++ )
+ {
+ (*this)[i] = pArray[i];
+ }
+}
+
+template< typename T, class A >
+void CUtlVector<T, A>::Swap( CUtlVector< T, A > &vec )
+{
+ m_Memory.Swap( vec.m_Memory );
+ V_swap( m_Size, vec.m_Size );
+
+#ifndef _X360
+ V_swap( m_pElements, vec.m_pElements );
+#endif
+}
+
+template< typename T, class A >
+int CUtlVector<T, A>::AddVectorToTail( CUtlVector const &src )
+{
+ Assert( &src != this );
+
+ int base = Count();
+
+ // Make space.
+ int nSrcCount = src.Count();
+ EnsureCapacity( base + nSrcCount );
+
+ // Copy the elements.
+ m_Size += nSrcCount;
+ for ( int i=0; i < nSrcCount; i++ )
+ {
+ CopyConstruct( &Element(base+i), src[i] );
+ }
+ return base;
+}
+
+template< typename T, class A >
+inline int CUtlVector<T, A>::InsertMultipleBefore( int elem, int num )
+{
+ if( num == 0 )
+ return elem;
+
+ // Can insert at the end
+ Assert( (elem == Count()) || IsValidIndex(elem) );
+
+ GrowVector(num);
+ ShiftElementsRight( elem, num );
+
+ // Invoke default constructors
+ for (int i = 0; i < num; ++i )
+ {
+ Construct( &Element( elem+i ) );
+ }
+
+ return elem;
+}
+
+template< typename T, class A >
+inline int CUtlVector<T, A>::InsertMultipleBefore( int elem, int num, const T *pToInsert )
+{
+ if( num == 0 )
+ return elem;
+
+ // Can insert at the end
+ Assert( (elem == Count()) || IsValidIndex(elem) );
+
+ GrowVector(num);
+ ShiftElementsRight( elem, num );
+
+ // Invoke default constructors
+ if ( !pToInsert )
+ {
+ for (int i = 0; i < num; ++i )
+ {
+ Construct( &Element( elem+i ) );
+ }
+ }
+ else
+ {
+ for ( int i=0; i < num; i++ )
+ {
+ CopyConstruct( &Element( elem+i ), pToInsert[i] );
+ }
+ }
+
+ return elem;
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds an element (element needs operator== defined)
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+int CUtlVector<T, A>::Find( const T& src ) const
+{
+ for ( int i = 0; i < Count(); ++i )
+ {
+ if (Element(i) == src)
+ return i;
+ }
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+// Finds an element using a predicate, using std::find_if
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+template< class F >
+int CUtlVector<T, A>::FindPredicate( F &&predicate ) const
+{
+ const T * begin = Base();
+ const T * end = begin + Count();
+ const T * const &elem = std::find_if( begin, end, predicate );
+
+ if ( elem != end )
+ {
+ int idx = (int)std::distance( begin, elem );
+ StagingUtlVectorBoundsCheck( idx, m_Size );
+ return idx;
+ }
+
+ return InvalidIndex();
+}
+
+template< typename T, class A >
+void CUtlVector<T, A>::FillWithValue( const T& src )
+{
+ for ( int i = 0; i < Count(); i++ )
+ {
+ Element(i) = src;
+ }
+}
+
+template< typename T, class A >
+bool CUtlVector<T, A>::HasElement( const T& src ) const
+{
+ return ( Find(src) >= 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Element removal
+//-----------------------------------------------------------------------------
+template< typename T, class A >
+void CUtlVector<T, A>::FastRemove( int elem )
+{
+ Assert( IsValidIndex(elem) );
+
+ // Global scope to resolve conflict with Scaleform 4.0
+ ::Destruct( &Element(elem) );
+ if (m_Size > 0)
+ {
+ if ( elem != m_Size -1 )
+ memcpy( &Element(elem), &Element(m_Size-1), sizeof(T) );
+ --m_Size;
+ }
+}
+
+template< typename T, class A >
+void CUtlVector<T, A>::Remove( int elem )
+{
+ // Global scope to resolve conflict with Scaleform 4.0
+ ::Destruct( &Element(elem) );
+ ShiftElementsLeft(elem);
+ --m_Size;
+}
+
+template< typename T, class A >
+bool CUtlVector<T, A>::FindAndRemove( const T& src )
+{
+ int elem = Find( src );
+ if ( elem != -1 )
+ {
+ Remove( elem );
+ return true;
+ }
+ return false;
+}
+
+template< typename T, class A >
+bool CUtlVector<T, A>::FindAndFastRemove( const T& src )
+{
+ int elem = Find( src );
+ if ( elem != -1 )
+ {
+ FastRemove( elem );
+ return true;
+ }
+ return false;
+}
+
+template< typename T, class A >
+void CUtlVector<T, A>::RemoveMultiple( int elem, int num )
+{
+ Assert( elem >= 0 );
+ Assert( elem + num <= Count() );
+
+ // Global scope to resolve conflict with Scaleform 4.0
+ for (int i = elem + num; --i >= elem; )
+ ::Destruct(&Element(i));
+
+ ShiftElementsLeft(elem, num);
+ m_Size -= num;
+}
+
+template< typename T, class A >
+void CUtlVector<T, A>::RemoveMultipleFromHead( int num )
+{
+ Assert( num <= Count() );
+
+ // Global scope to resolve conflict with Scaleform 4.0
+ for (int i = num; --i >= 0; )
+ ::Destruct(&Element(i));
+
+ ShiftElementsLeft(0, num);
+ m_Size -= num;
+}
+
+template< typename T, class A >
+void CUtlVector<T, A>::RemoveMultipleFromTail( int num )
+{
+ Assert( num <= Count() );
+
+ // Global scope to resolve conflict with Scaleform 4.0
+ for (int i = m_Size-num; i < m_Size; i++)
+ ::Destruct(&Element(i));
+
+ m_Size -= num;
+}
+
+template< typename T, class A >
+void CUtlVector<T, A>::RemoveAll()
+{
+ for (int i = m_Size; --i >= 0; )
+ {
+ // Global scope to resolve conflict with Scaleform 4.0
+ ::Destruct(&Element(i));
+ }
+
+ m_Size = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Memory deallocation
+//-----------------------------------------------------------------------------
+
+template< typename T, class A >
+inline void CUtlVector<T, A>::Purge()
+{
+ RemoveAll();
+ m_Memory.Purge();
+ ResetDbgInfo();
+}
+
+
+template< typename T, class A >
+inline void CUtlVector<T, A>::PurgeAndDeleteElements()
+{
+ for( int i=0; i < m_Size; i++ )
+ {
+ delete Element(i);
+ }
+ Purge();
+}
+
+template< typename T, class A >
+inline void CUtlVector<T, A>::Compact()
+{
+ m_Memory.Purge(m_Size);
+}
+
+template< typename T, class A >
+inline int CUtlVector<T, A>::NumAllocated() const
+{
+ return m_Memory.NumAllocated();
+}
+
+
+//-----------------------------------------------------------------------------
+// Data and memory validation
+//-----------------------------------------------------------------------------
+#ifdef DBGFLAG_VALIDATE
+template< typename T, class A >
+void CUtlVector<T, A>::Validate( CValidator &validator, char *pchName )
+{
+ validator.Push( typeid(*this).name(), this, pchName );
+
+ m_Memory.Validate( validator, "m_Memory" );
+
+ validator.Pop();
+}
+#endif // DBGFLAG_VALIDATE
+
+// A vector class for storing pointers, so that the elements pointed to by the pointers are deleted
+// on exit.
+template<class T> class CUtlVectorAutoPurge : public CUtlVector< T, CUtlMemory< T, int> >
+{
+public:
+ ~CUtlVectorAutoPurge( void )
+ {
+ this->PurgeAndDeleteElements();
+ }
+
+};
+
+// easy string list class with dynamically allocated strings. For use with V_SplitString, etc.
+// Frees the dynamic strings in destructor.
+class CUtlStringList : public CUtlVectorAutoPurge< char *>
+{
+public:
+ void CopyAndAddToTail( char const *pString ) // clone the string and add to the end
+ {
+ char *pNewStr = new char[1 + strlen( pString )];
+ V_strcpy( pNewStr, pString );
+ AddToTail( pNewStr );
+ }
+
+ static int __cdecl SortFunc( char * const * sz1, char * const * sz2 )
+ {
+ return strcmp( *sz1, *sz2 );
+ }
+
+ CUtlStringList(){}
+
+ CUtlStringList( char const *pString, char const *pSeparator )
+ {
+ SplitString( pString, pSeparator );
+ }
+
+ CUtlStringList( char const *pString, const char **pSeparators, int nSeparators )
+ {
+ SplitString2( pString, pSeparators, nSeparators );
+ }
+
+ void SplitString( char const *pString, char const *pSeparator )
+ {
+ V_SplitString( pString, pSeparator, *this );
+ }
+
+ void SplitString2( char const *pString, const char **pSeparators, int nSeparators )
+ {
+ V_SplitString2( pString, pSeparators, nSeparators, *this );
+ }
+private:
+ CUtlStringList( const CUtlStringList &other ); // copying directly will cause double-release of the same strings; maybe we need to do a deep copy, but unless and until such need arises, this will guard against double-release
+};
+
+
+
+// <Sergiy> placing it here a few days before Cert to minimize disruption to the rest of codebase
+class CSplitString: public CUtlVector<char*, CUtlMemory<char*, int> >
+{
+public:
+ CSplitString(const char *pString, const char *pSeparator);
+ CSplitString(const char *pString, const char **pSeparators, int nSeparators);
+ ~CSplitString();
+ //
+ // NOTE: If you want to make Construct() public and implement Purge() here, you'll have to free m_szBuffer there
+ //
+private:
+ void Construct(const char *pString, const char **pSeparators, int nSeparators);
+ void PurgeAndDeleteElements();
+private:
+ char *m_szBuffer; // a copy of original string, with '\0' instead of separators
+};
+
+
+#endif // CCVECTOR_H