diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/public/tier1 | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/public/tier1')
79 files changed, 30144 insertions, 30144 deletions
diff --git a/mp/src/public/tier1/CommandBuffer.h b/mp/src/public/tier1/CommandBuffer.h index 95971c12..d9bfd7de 100644 --- a/mp/src/public/tier1/CommandBuffer.h +++ b/mp/src/public/tier1/CommandBuffer.h @@ -1,167 +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
+//========= 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/mp/src/public/tier1/KeyValues.h b/mp/src/public/tier1/KeyValues.h index 2d46e377..67b2f012 100644 --- a/mp/src/public/tier1/KeyValues.h +++ b/mp/src/public/tier1/KeyValues.h @@ -1,477 +1,477 @@ -//========= 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 SaveToFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, bool sortKeys = false, bool bAllowEmptyString = 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
- 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 );
- 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=( 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;
-
- // 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 );
-
- // Merge in another KeyValues, keeping "our" settings
- void RecursiveMergeKeyValues( KeyValues *baseKV );
-
-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 AddSubkeyUsingKnownLastChild( KeyValues *pSubKey, KeyValues *pLastChild );
-
- void RecursiveCopyKeyValues( KeyValues& src );
- 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
+//========= 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 SaveToFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, bool sortKeys = false, bool bAllowEmptyString = 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 + 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 ); + 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=( 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; + + // 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 ); + + // Merge in another KeyValues, keeping "our" settings + void RecursiveMergeKeyValues( KeyValues *baseKV ); + +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 AddSubkeyUsingKnownLastChild( KeyValues *pSubKey, KeyValues *pLastChild ); + + void RecursiveCopyKeyValues( KeyValues& src ); + 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/mp/src/public/tier1/UtlSortVector.h b/mp/src/public/tier1/UtlSortVector.h index ec7d972d..76026925 100644 --- a/mp/src/public/tier1/UtlSortVector.h +++ b/mp/src/public/tier1/UtlSortVector.h @@ -1,321 +1,321 @@ -//========= Copyright 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
-{
-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 );
-
- // Finds an element within the list using a binary search
- int Find( const T& search ) const;
- int FindLessOrEqual( const T& search ) const;
- int FindLess( const T& 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 );
-
- // Note that you can only use this index until sorting is redone!!!
- int InsertNoSort( const T& src );
- void RedoSort( bool bForceSort = false );
-
-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 AddToHead( const T& src );
- int AddToTail( const T& src );
- int InsertBefore( int elem, const T& src );
- int InsertAfter( int elem, 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:
- 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;
-}
-
-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>
-int CUtlSortVector<T, LessFunc, BaseVector>::Find( const T& 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
-//-----------------------------------------------------------------------------
-template <class T, class LessFunc, class BaseVector>
-int CUtlSortVector<T, LessFunc, BaseVector>::FindLessOrEqual( const T& 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 end;
-}
-
-template <class T, class LessFunc, class BaseVector>
-int CUtlSortVector<T, LessFunc, BaseVector>::FindLess( const T& 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
+//========= Copyright 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 +{ +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 ); + + // Finds an element within the list using a binary search + int Find( const T& search ) const; + int FindLessOrEqual( const T& search ) const; + int FindLess( const T& 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 ); + + // Note that you can only use this index until sorting is redone!!! + int InsertNoSort( const T& src ); + void RedoSort( bool bForceSort = false ); + +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 AddToHead( const T& src ); + int AddToTail( const T& src ); + int InsertBefore( int elem, const T& src ); + int InsertAfter( int elem, 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: + 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; +} + +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> +int CUtlSortVector<T, LessFunc, BaseVector>::Find( const T& 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 +//----------------------------------------------------------------------------- +template <class T, class LessFunc, class BaseVector> +int CUtlSortVector<T, LessFunc, BaseVector>::FindLessOrEqual( const T& 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 end; +} + +template <class T, class LessFunc, class BaseVector> +int CUtlSortVector<T, LessFunc, BaseVector>::FindLess( const T& 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/mp/src/public/tier1/UtlStringMap.h b/mp/src/public/tier1/UtlStringMap.h index e4b64229..59d5c23f 100644 --- a/mp/src/public/tier1/UtlStringMap.h +++ b/mp/src/public/tier1/UtlStringMap.h @@ -1,99 +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
+//========= 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/mp/src/public/tier1/bitbuf.h b/mp/src/public/tier1/bitbuf.h index b47d80d5..b92e010c 100644 --- a/mp/src/public/tier1/bitbuf.h +++ b/mp/src/public/tier1/bitbuf.h @@ -1,809 +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
-
-
-
+//========= 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/mp/src/public/tier1/byteswap.h b/mp/src/public/tier1/byteswap.h index c7bc3c87..9b082541 100644 --- a/mp/src/public/tier1/byteswap.h +++ b/mp/src/public/tier1/byteswap.h @@ -1,249 +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( int 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 */
+//========= 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( int 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/mp/src/public/tier1/callqueue.h b/mp/src/public/tier1/callqueue.h index c576efec..5e0e9940 100644 --- a/mp/src/public/tier1/callqueue.h +++ b/mp/src/public/tier1/callqueue.h @@ -1,203 +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
+//========= 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/mp/src/public/tier1/characterset.h b/mp/src/public/tier1/characterset.h index 8bd35352..0c639e1a 100644 --- a/mp/src/public/tier1/characterset.h +++ b/mp/src/public/tier1/characterset.h @@ -1,43 +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
+//========= 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/mp/src/public/tier1/checksum_crc.h b/mp/src/public/tier1/checksum_crc.h index 130577ee..dbbc50a4 100644 --- a/mp/src/public/tier1/checksum_crc.h +++ b/mp/src/public/tier1/checksum_crc.h @@ -1,31 +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
+//========= 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/mp/src/public/tier1/checksum_md5.h b/mp/src/public/tier1/checksum_md5.h index 34f82823..e7cf7ec9 100644 --- a/mp/src/public/tier1/checksum_md5.h +++ b/mp/src/public/tier1/checksum_md5.h @@ -1,62 +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
+//========= 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/mp/src/public/tier1/checksum_sha1.h b/mp/src/public/tier1/checksum_sha1.h index 9a503c0d..7c87aa5c 100644 --- a/mp/src/public/tier1/checksum_sha1.h +++ b/mp/src/public/tier1/checksum_sha1.h @@ -1,174 +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
+//========= 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/mp/src/public/tier1/convar.h b/mp/src/public/tier1/convar.h index 7cf21f53..2174e1f9 100644 --- a/mp/src/public/tier1/convar.h +++ b/mp/src/public/tier1/convar.h @@ -1,672 +1,672 @@ -//========= 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 ( *FnCommandCallbackV1_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 Create( 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, FnCommandCallbackV1_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
- {
- FnCommandCallbackV1_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 );
-
- 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 );
-
-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 );
- virtual void InternalSetIntValue( int nValue );
-
- virtual bool ClampValue( float& value );
- virtual void ChangeStringValue( const char *tempVal, float flOldValue );
-
- virtual 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 = false, 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;
-
- // 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 : "";
-}
-
-
-//-----------------------------------------------------------------------------
-// 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;
-
- 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 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
+//========= 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 ( *FnCommandCallbackV1_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 Create( 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, FnCommandCallbackV1_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 + { + FnCommandCallbackV1_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 ); + + 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 ); + +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 ); + virtual void InternalSetIntValue( int nValue ); + + virtual bool ClampValue( float& value ); + virtual void ChangeStringValue( const char *tempVal, float flOldValue ); + + virtual 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 = false, 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; + + // 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 : ""; +} + + +//----------------------------------------------------------------------------- +// 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; + + 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 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/mp/src/public/tier1/convar_serverbounded.h b/mp/src/public/tier1/convar_serverbounded.h index 59287ec6..3bdd1ab3 100644 --- a/mp/src/public/tier1/convar_serverbounded.h +++ b/mp/src/public/tier1/convar_serverbounded.h @@ -1,53 +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
+//========= 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/mp/src/public/tier1/datamanager.h b/mp/src/public/tier1/datamanager.h index 6c72bf9e..88030547 100644 --- a/mp/src/public/tier1/datamanager.h +++ b/mp/src/public/tier1/datamanager.h @@ -1,277 +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
+//========= 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/mp/src/public/tier1/delegates.h b/mp/src/public/tier1/delegates.h index a81d70ec..35a50cf7 100644 --- a/mp/src/public/tier1/delegates.h +++ b/mp/src/public/tier1/delegates.h @@ -1,99 +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
+//========= 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/mp/src/public/tier1/diff.h b/mp/src/public/tier1/diff.h index a17c5087..fc2fb752 100644 --- a/mp/src/public/tier1/diff.h +++ b/mp/src/public/tier1/diff.h @@ -1,29 +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
-
+//========= 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/mp/src/public/tier1/fileio.h b/mp/src/public/tier1/fileio.h index f2f76e8d..d85ca182 100644 --- a/mp/src/public/tier1/fileio.h +++ b/mp/src/public/tier1/fileio.h @@ -1,101 +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
+//========= 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/mp/src/public/tier1/fmtstr.h b/mp/src/public/tier1/fmtstr.h index 64d44add..8c9ccf47 100644 --- a/mp/src/public/tier1/fmtstr.h +++ b/mp/src/public/tier1/fmtstr.h @@ -1,202 +1,202 @@ -//========= 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 unsigned int scAsserted = 0; \
- \
- va_start(arg_ptr, lastArg); \
- result = Q_vsnprintfRet( (szBuf), nBufSize, (*(ppszFormat)), arg_ptr, &bTruncated ); \
- va_end(arg_ptr); \
- \
- if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \
- { \
- Assert( !bTruncated ); \
- scAsserted++; \
- } \
- m_nLength = nPrevLen + result; \
- } \
- while (0)
-
-
-//-----------------------------------------------------------------------------
-//
-// Purpose: String formatter with specified size
-//
-
-template <int SIZE_BUF>
-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 )
- {
- FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
- return m_szBuf;
- }
-
- // Use this for pass-through formatting
- void VSprintf(const char **ppszFormat, ...)
- {
- 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; }
-
- CFmtStrN<SIZE_BUF> & operator=( const char *pchValue )
- {
- V_strncpy( m_szBuf, pchValue, SIZE_BUF );
- m_nLength = V_strlen( m_szBuf );
- return *this;
- }
-
- CFmtStrN<SIZE_BUF> & operator+=( const char *pchValue )
- {
- Append( pchValue );
- return *this;
- }
-
- int Length() const { return m_nLength; }
-
- 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 ) { AppendFormat( "%s", pchValue ); }
- void AppendIndent( uint32 unCount, char chIndent = '\t' );
-
-protected:
- virtual void InitQuietTruncation()
- {
-#ifdef _DEBUG
- m_bQuietTruncation = false;
-#else
- m_bQuietTruncation = true; // Force quiet for release builds
-#endif
- }
-
- 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>
-{
-protected:
- virtual void InitQuietTruncation() { this->m_bQuietTruncation = true; }
-};
-
-
-template< int SIZE_BUF >
-void CFmtStrN<SIZE_BUF>::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 >
-void CFmtStrN<SIZE_BUF>::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;
-
-//=============================================================================
-
-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
+//========= 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 unsigned int scAsserted = 0; \ + \ + va_start(arg_ptr, lastArg); \ + result = Q_vsnprintfRet( (szBuf), nBufSize, (*(ppszFormat)), arg_ptr, &bTruncated ); \ + va_end(arg_ptr); \ + \ + if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \ + { \ + Assert( !bTruncated ); \ + scAsserted++; \ + } \ + m_nLength = nPrevLen + result; \ + } \ + while (0) + + +//----------------------------------------------------------------------------- +// +// Purpose: String formatter with specified size +// + +template <int SIZE_BUF> +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 ) + { + FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat ); + return m_szBuf; + } + + // Use this for pass-through formatting + void VSprintf(const char **ppszFormat, ...) + { + 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; } + + CFmtStrN<SIZE_BUF> & operator=( const char *pchValue ) + { + V_strncpy( m_szBuf, pchValue, SIZE_BUF ); + m_nLength = V_strlen( m_szBuf ); + return *this; + } + + CFmtStrN<SIZE_BUF> & operator+=( const char *pchValue ) + { + Append( pchValue ); + return *this; + } + + int Length() const { return m_nLength; } + + 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 ) { AppendFormat( "%s", pchValue ); } + void AppendIndent( uint32 unCount, char chIndent = '\t' ); + +protected: + virtual void InitQuietTruncation() + { +#ifdef _DEBUG + m_bQuietTruncation = false; +#else + m_bQuietTruncation = true; // Force quiet for release builds +#endif + } + + 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> +{ +protected: + virtual void InitQuietTruncation() { this->m_bQuietTruncation = true; } +}; + + +template< int SIZE_BUF > +void CFmtStrN<SIZE_BUF>::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 > +void CFmtStrN<SIZE_BUF>::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; + +//============================================================================= + +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/mp/src/public/tier1/functors.h b/mp/src/public/tier1/functors.h index f6094ada..afc45d3a 100644 --- a/mp/src/public/tier1/functors.h +++ b/mp/src/public/tier1/functors.h @@ -1,637 +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
+//========= 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/mp/src/public/tier1/generichash.h b/mp/src/public/tier1/generichash.h index 70226b45..59b8b610 100644 --- a/mp/src/public/tier1/generichash.h +++ b/mp/src/public/tier1/generichash.h @@ -1,116 +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 */
+//========= 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/mp/src/public/tier1/iconvar.h b/mp/src/public/tier1/iconvar.h index b33154ce..1ea5f7af 100644 --- a/mp/src/public/tier1/iconvar.h +++ b/mp/src/public/tier1/iconvar.h @@ -1,118 +1,118 @@ -//========= 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_AVAILABLE (1<<15)
-// #define FCVAR_AVAILABLE (1<<18)
-// #define FCVAR_AVAILABLE (1<<19)
-// #define FCVAR_AVAILABLE (1<<20)
-// #define FCVAR_AVAILABLE (1<<21)
-// #define FCVAR_AVAILABLE (1<<23)
-// #define FCVAR_AVAILABLE (1<<26)
-// #define FCVAR_AVAILABLE (1<<27)
-// #define FCVAR_AVAILABLE (1<<31)
-
-#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
+//========= 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_AVAILABLE (1<<15) +// #define FCVAR_AVAILABLE (1<<18) +// #define FCVAR_AVAILABLE (1<<19) +// #define FCVAR_AVAILABLE (1<<20) +// #define FCVAR_AVAILABLE (1<<21) +// #define FCVAR_AVAILABLE (1<<23) +// #define FCVAR_AVAILABLE (1<<26) +// #define FCVAR_AVAILABLE (1<<27) +// #define FCVAR_AVAILABLE (1<<31) + +#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/mp/src/public/tier1/ilocalize.h b/mp/src/public/tier1/ilocalize.h index a3dd6bb8..fed7af6d 100644 --- a/mp/src/public/tier1/ilocalize.h +++ b/mp/src/public/tier1/ilocalize.h @@ -1,424 +1,424 @@ -
-//========= 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 );
- }
-
-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, 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() );
- }
- }
-
- 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
+ +//========= 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 ); + } + +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, 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() ); + } + } + + 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/mp/src/public/tier1/interface.h b/mp/src/public/tier1/interface.h index 22ce5a5c..5453f67d 100644 --- a/mp/src/public/tier1/interface.h +++ b/mp/src/public/tier1/interface.h @@ -1,230 +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
-
-
-
+//========= 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/mp/src/public/tier1/kvpacker.h b/mp/src/public/tier1/kvpacker.h index 8812ee4e..7e47fa1a 100644 --- a/mp/src/public/tier1/kvpacker.h +++ b/mp/src/public/tier1/kvpacker.h @@ -1,49 +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
+//========= 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/mp/src/public/tier1/lzmaDecoder.h b/mp/src/public/tier1/lzmaDecoder.h index 8aa1f2ca..51ecfd1a 100644 --- a/mp/src/public/tier1/lzmaDecoder.h +++ b/mp/src/public/tier1/lzmaDecoder.h @@ -1,41 +1,41 @@ -//
-// LZMA Decoder. Designed for run time decoding.
-//
-// LZMA SDK 4.43 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
-// http://www.7-zip.org/
-//
-//=====================================================================================//
-
-#ifndef _LZMADECODER_H
-#define _LZMADECODER_H
-#pragma once
-
-#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 CLZMA
-{
-public:
- unsigned int Uncompress( unsigned char *pInput, unsigned char *pOutput );
- bool IsCompressed( unsigned char *pInput );
- unsigned int GetActualSize( unsigned char *pInput );
-
-private:
-};
-
-#endif
-
+// +// LZMA Decoder. Designed for run time decoding. +// +// LZMA SDK 4.43 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01) +// http://www.7-zip.org/ +// +//=====================================================================================// + +#ifndef _LZMADECODER_H +#define _LZMADECODER_H +#pragma once + +#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 CLZMA +{ +public: + unsigned int Uncompress( unsigned char *pInput, unsigned char *pOutput ); + bool IsCompressed( unsigned char *pInput ); + unsigned int GetActualSize( unsigned char *pInput ); + +private: +}; + +#endif + diff --git a/mp/src/public/tier1/lzss.h b/mp/src/public/tier1/lzss.h index 0afdfef0..8b3409a9 100644 --- a/mp/src/public/tier1/lzss.h +++ b/mp/src/public/tier1/lzss.h @@ -1,69 +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
-
+//========= 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/mp/src/public/tier1/mempool.h b/mp/src/public/tier1/mempool.h index 65eeb7c9..88406fbf 100644 --- a/mp/src/public/tier1/mempool.h +++ b/mp/src/public/tier1/mempool.h @@ -1,551 +1,551 @@ -//========= 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, ... );
-
-class CUtlMemoryPool
-{
-public:
- // Ways the memory pool can grow when it needs to make a new blob.
- enum MemoryPoolGrowType_t
- {
- GROW_NONE=0, // Don't allow new blobs.
- GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates
- // get larger and larger each time it allocates one).
- GROW_SLOW=2 // New blob size is numElements.
- };
-
- CUtlMemoryPool( int blockSize, int numElements, int growMode = 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 = 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
+//========= 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, ... ); + +class CUtlMemoryPool +{ +public: + // Ways the memory pool can grow when it needs to make a new blob. + enum MemoryPoolGrowType_t + { + GROW_NONE=0, // Don't allow new blobs. + GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates + // get larger and larger each time it allocates one). + GROW_SLOW=2 // New blob size is numElements. + }; + + CUtlMemoryPool( int blockSize, int numElements, int growMode = 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 = 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/mp/src/public/tier1/memstack.h b/mp/src/public/tier1/memstack.h index dff0f240..e5f08855 100644 --- a/mp/src/public/tier1/memstack.h +++ b/mp/src/public/tier1/memstack.h @@ -1,207 +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
+//========= 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/mp/src/public/tier1/netadr.h b/mp/src/public/tier1/netadr.h index fdc28504..9249613e 100644 --- a/mp/src/public/tier1/netadr.h +++ b/mp/src/public/tier1/netadr.h @@ -1,68 +1,68 @@ -//========= 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
-
-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 ); }
- void 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;
- const char* ToString( bool onlyBase = false ) const; // returns xxx.xxx.xxx.xxx:ppppp
- void ToSockadr(struct sockaddr *s) const;
- unsigned int GetIPHostByteOrder() const;
- 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
- void SetFromSocket( int hSocket );
- 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;
-
-#endif // NETADR_H
+//========= 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 + +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 ); } + void 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; + const char* ToString( bool onlyBase = false ) const; // returns xxx.xxx.xxx.xxx:ppppp + void ToSockadr(struct sockaddr *s) const; + unsigned int GetIPHostByteOrder() const; + 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 + void SetFromSocket( int hSocket ); + 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; + +#endif // NETADR_H diff --git a/mp/src/public/tier1/passwordhash.h b/mp/src/public/tier1/passwordhash.h index b2480590..f557c7f7 100644 --- a/mp/src/public/tier1/passwordhash.h +++ b/mp/src/public/tier1/passwordhash.h @@ -1,94 +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
+//========= 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/mp/src/public/tier1/processor_detect.h b/mp/src/public/tier1/processor_detect.h index cd0239bb..cb4cc37e 100644 --- a/mp/src/public/tier1/processor_detect.h +++ b/mp/src/public/tier1/processor_detect.h @@ -1,12 +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);
-
+//========= 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/mp/src/public/tier1/rangecheckedvar.h b/mp/src/public/tier1/rangecheckedvar.h index 8d9eba70..52313f82 100644 --- a/mp/src/public/tier1/rangecheckedvar.h +++ b/mp/src/public/tier1/rangecheckedvar.h @@ -1,118 +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
+//========= 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/mp/src/public/tier1/refcount.h b/mp/src/public/tier1/refcount.h index 5dd50011..264da100 100644 --- a/mp/src/public/tier1/refcount.h +++ b/mp/src/public/tier1/refcount.h @@ -1,385 +1,385 @@ -//========= 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
-
-//-----------------------------------------------------------------------------
-// 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
+//========= 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 + +//----------------------------------------------------------------------------- +// 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/mp/src/public/tier1/reliabletimer.h b/mp/src/public/tier1/reliabletimer.h index f20f3bdf..c830fbe3 100644 --- a/mp/src/public/tier1/reliabletimer.h +++ b/mp/src/public/tier1/reliabletimer.h @@ -1,183 +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
+//========= 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/mp/src/public/tier1/smartptr.h b/mp/src/public/tier1/smartptr.h index a0065e5a..466ca0bc 100644 --- a/mp/src/public/tier1/smartptr.h +++ b/mp/src/public/tier1/smartptr.h @@ -1,279 +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
+//========= 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/mp/src/public/tier1/snappy-sinksource.h b/mp/src/public/tier1/snappy-sinksource.h index c7c3df9d..430baeab 100644 --- a/mp/src/public/tier1/snappy-sinksource.h +++ b/mp/src/public/tier1/snappy-sinksource.h @@ -1,136 +1,136 @@ -// 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_
+// 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/mp/src/public/tier1/snappy.h b/mp/src/public/tier1/snappy.h index 1c9ad6bf..c5eeea01 100644 --- a/mp/src/public/tier1/snappy.h +++ b/mp/src/public/tier1/snappy.h @@ -1,172 +1,172 @@ -// 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 "tier0/platform.h"
-
-#define SNAPPY_MAJOR 1
-#define SNAPPY_MINOR 0
-#define SNAPPY_PATCHLEVEL 3
-#define SNAPPY_VERSION \
- ((SNAPPY_MAJOR << 16) | (SNAPPY_MINOR << 8) | SNAPPY_PATCHLEVEL)
-
-#define SNAPPY_DISALLOW_COPY_AND_ASSIGN(TypeName) \
- TypeName(const TypeName&); \
- void operator=(const TypeName&)
-
-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);
-
- 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);
-
- // 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);
-
- // *** DO NOT CHANGE THE VALUE OF kBlockSize ***
- //
- // New Compression code chops up the input into blocks of at most
- // the following size. This ensures that back-references in the
- // output never cross kBlockSize block boundaries. This can be
- // helpful in implementing blocked decompression. However the
- // decompression code should not rely on this guarantee since older
- // compression code may not obey it.
- static const int kBlockLog = 15;
- static const int kBlockSize = 1 << kBlockLog;
-
- static const int kMaxHashTableBits = 14;
- static const int kMaxHashTableSize = 1 << kMaxHashTableBits;
-
-} // end namespace snappy
-
-
-#endif // UTIL_SNAPPY_SNAPPY_H__
+// 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 "tier0/platform.h" + +#define SNAPPY_MAJOR 1 +#define SNAPPY_MINOR 0 +#define SNAPPY_PATCHLEVEL 3 +#define SNAPPY_VERSION \ + ((SNAPPY_MAJOR << 16) | (SNAPPY_MINOR << 8) | SNAPPY_PATCHLEVEL) + +#define SNAPPY_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +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); + + 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); + + // 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); + + // *** DO NOT CHANGE THE VALUE OF kBlockSize *** + // + // New Compression code chops up the input into blocks of at most + // the following size. This ensures that back-references in the + // output never cross kBlockSize block boundaries. This can be + // helpful in implementing blocked decompression. However the + // decompression code should not rely on this guarantee since older + // compression code may not obey it. + static const int kBlockLog = 15; + static const int kBlockSize = 1 << kBlockLog; + + static const int kMaxHashTableBits = 14; + static const int kMaxHashTableSize = 1 << kMaxHashTableBits; + +} // end namespace snappy + + +#endif // UTIL_SNAPPY_SNAPPY_H__ diff --git a/mp/src/public/tier1/sparsematrix.h b/mp/src/public/tier1/sparsematrix.h index e1f4b770..d882e5f9 100644 --- a/mp/src/public/tier1/sparsematrix.h +++ b/mp/src/public/tier1/sparsematrix.h @@ -1,123 +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
+//========= 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/mp/src/public/tier1/stringpool.h b/mp/src/public/tier1/stringpool.h index bfb0872d..6b1dfaef 100644 --- a/mp/src/public/tier1/stringpool.h +++ b/mp/src/public/tier1/stringpool.h @@ -1,91 +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
+//========= 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/mp/src/public/tier1/strtools.h b/mp/src/public/tier1/strtools.h index 6089a8f4..93d0af6d 100644 --- a/mp/src/public/tier1/strtools.h +++ b/mp/src/public/tier1/strtools.h @@ -1,847 +1,847 @@ -//========= 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>
-
-#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 );
-
-#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);
-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; }
-
-
-// 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';
-}
-
-// 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
-
-
-// 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 );
-}
-
-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 );
-}
-
-
-// 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;
-}
-
-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 );
-
-// conversion functions wchar_t <-> char, returning the number of characters converted
-int V_UTF8ToUnicode( const char *pUTF8, OUT_Z_BYTECAP(cubDestSizeInBytes) wchar_t *pwchDest, int cubDestSizeInBytes );
-int V_UnicodeToUTF8( const wchar_t *pUnicode, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes );
-int V_UCS2ToUnicode( const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) wchar_t *pUnicode, int cubDestSizeInBytes );
-int V_UCS2ToUTF8( const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes );
-int V_UnicodeToUCS2( const wchar_t *pUnicode, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUCS2, int cubDestSizeInBytes );
-int V_UTF8ToUCS2( const char *pUTF8, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) ucs2 *pUCS2, 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 );
-
-// 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 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 );
-
-// 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 );
-
-// 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 );
-}
-
-//-----------------------------------------------------------------------------
-// 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;
-#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;
-#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_bCreatedUTF16 = true;
- }
-#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;
- }
- }
-
-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_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;
-#endif
- // "created as UTF-16", means our owned string is the UTF-8 string not the UTF-16 one.
- bool m_bCreatedUTF16;
-
-};
-
-
-
-// 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 )
-
-
-#endif // TIER1_STRTOOLS_H
+//========= 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> + +#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 ); + +#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); +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; } + + +// 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'; +} + +// 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 + + +// 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 ); +} + +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 ); +} + + +// 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; +} + +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 ); + +// conversion functions wchar_t <-> char, returning the number of characters converted +int V_UTF8ToUnicode( const char *pUTF8, OUT_Z_BYTECAP(cubDestSizeInBytes) wchar_t *pwchDest, int cubDestSizeInBytes ); +int V_UnicodeToUTF8( const wchar_t *pUnicode, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes ); +int V_UCS2ToUnicode( const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) wchar_t *pUnicode, int cubDestSizeInBytes ); +int V_UCS2ToUTF8( const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes ); +int V_UnicodeToUCS2( const wchar_t *pUnicode, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUCS2, int cubDestSizeInBytes ); +int V_UTF8ToUCS2( const char *pUTF8, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) ucs2 *pUCS2, 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 ); + +// 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 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 ); + +// 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 ); + +// 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 ); +} + +//----------------------------------------------------------------------------- +// 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; +#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; +#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_bCreatedUTF16 = true; + } +#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; + } + } + +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_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; +#endif + // "created as UTF-16", means our owned string is the UTF-8 string not the UTF-16 one. + bool m_bCreatedUTF16; + +}; + + + +// 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 ) + + +#endif // TIER1_STRTOOLS_H diff --git a/mp/src/public/tier1/thash.h b/mp/src/public/tier1/thash.h index 453aebf0..51020749 100644 --- a/mp/src/public/tier1/thash.h +++ b/mp/src/public/tier1/thash.h @@ -1,698 +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
+//========= 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/mp/src/public/tier1/tier1.h b/mp/src/public/tier1/tier1.h index 7e48c3c3..ac790673 100644 --- a/mp/src/public/tier1/tier1.h +++ b/mp/src/public/tier1/tier1.h @@ -1,106 +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
-
+//========= 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/mp/src/public/tier1/tokenreader.h b/mp/src/public/tier1/tokenreader.h index 14061e76..b174869c 100644 --- a/mp/src/public/tier1/tokenreader.h +++ b/mp/src/public/tier1/tokenreader.h @@ -1,99 +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
+//========= 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/mp/src/public/tier1/uniqueid.h b/mp/src/public/tier1/uniqueid.h index e7df1600..fd3fe262 100644 --- a/mp/src/public/tier1/uniqueid.h +++ b/mp/src/public/tier1/uniqueid.h @@ -1,56 +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
-
+//========= 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/mp/src/public/tier1/utlallocation.h b/mp/src/public/tier1/utlallocation.h index c0116b08..65416bcf 100644 --- a/mp/src/public/tier1/utlallocation.h +++ b/mp/src/public/tier1/utlallocation.h @@ -1,134 +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
+//========= 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/mp/src/public/tier1/utlarray.h b/mp/src/public/tier1/utlarray.h index bc50b068..36850860 100644 --- a/mp/src/public/tier1/utlarray.h +++ b/mp/src/public/tier1/utlarray.h @@ -1,299 +1,299 @@ -//========= 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;
-
- 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;
-
- 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 >
-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
+//========= 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; + + 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; + + 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 > +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/mp/src/public/tier1/utlbidirectionalset.h b/mp/src/public/tier1/utlbidirectionalset.h index a2e6d746..36aea62b 100644 --- a/mp/src/public/tier1/utlbidirectionalset.h +++ b/mp/src/public/tier1/utlbidirectionalset.h @@ -1,394 +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
+//========= 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/mp/src/public/tier1/utlblockmemory.h b/mp/src/public/tier1/utlblockmemory.h index 8ceb0a2b..69885060 100644 --- a/mp/src/public/tier1/utlblockmemory.h +++ b/mp/src/public/tier1/utlblockmemory.h @@ -1,349 +1,349 @@ -//========= 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
-
- // free old blocks if shrinking
- for ( int i = m_nBlocks; i < nBlocksOld; ++i )
- {
- UTLBLOCKMEMORY_TRACK_FREE();
- free( (void*)m_pMemory[ i ] );
- }
-
- if ( m_pMemory )
- {
- 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
+//========= 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 + + // free old blocks if shrinking + for ( int i = m_nBlocks; i < nBlocksOld; ++i ) + { + UTLBLOCKMEMORY_TRACK_FREE(); + free( (void*)m_pMemory[ i ] ); + } + + if ( m_pMemory ) + { + 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/mp/src/public/tier1/utlbuffer.h b/mp/src/public/tier1/utlbuffer.h index 82c42f9b..4213dd6a 100644 --- a/mp/src/public/tier1/utlbuffer.h +++ b/mp/src/public/tier1/utlbuffer.h @@ -1,1084 +1,1084 @@ -//========= 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( );
- void GetString( char* pString, int nMaxChars = 0 );
- 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 );
-
- 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
-
+//========= 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( ); + void GetString( char* pString, int nMaxChars = 0 ); + 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 ); + + 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/mp/src/public/tier1/utlbufferutil.h b/mp/src/public/tier1/utlbufferutil.h index a5b1c9f2..a52a528a 100644 --- a/mp/src/public/tier1/utlbufferutil.h +++ b/mp/src/public/tier1/utlbufferutil.h @@ -1,192 +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
-
+//========= 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/mp/src/public/tier1/utlcommon.h b/mp/src/public/tier1/utlcommon.h index 85f91017..d44dc2d5 100644 --- a/mp/src/public/tier1/utlcommon.h +++ b/mp/src/public/tier1/utlcommon.h @@ -1,345 +1,345 @@ -//========= 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 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; } };
-struct PointerHashFunctor { unsigned int operator()( const void* s ) const { return Mix32HashFunctor()((uint32)POINTER_TO_INT(s)); } };
-
-
-// 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 { };
-template <> struct DefaultHashFunctor<signed long> : Mix32HashFunctor { };
-template <> struct DefaultHashFunctor<unsigned long> : Mix32HashFunctor { };
-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;
-}
-
-// 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
+//========= 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 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; } }; +struct PointerHashFunctor { unsigned int operator()( const void* s ) const { return Mix32HashFunctor()((uint32)POINTER_TO_INT(s)); } }; + + +// 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 { }; +template <> struct DefaultHashFunctor<signed long> : Mix32HashFunctor { }; +template <> struct DefaultHashFunctor<unsigned long> : Mix32HashFunctor { }; +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; +} + +// 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/mp/src/public/tier1/utldelegate.h b/mp/src/public/tier1/utldelegate.h index f1d58ff0..04c5dad2 100644 --- a/mp/src/public/tier1/utldelegate.h +++ b/mp/src/public/tier1/utldelegate.h @@ -1,97 +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
+//========= 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/mp/src/public/tier1/utldelegateimpl.h b/mp/src/public/tier1/utldelegateimpl.h index 12f8a3c2..cf9809d8 100644 --- a/mp/src/public/tier1/utldelegateimpl.h +++ b/mp/src/public/tier1/utldelegateimpl.h @@ -1,2656 +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)
-
+//========= 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/mp/src/public/tier1/utldict.h b/mp/src/public/tier1/utldict.h index b4268e90..cb0455a5 100644 --- a/mp/src/public/tier1/utldict.h +++ b/mp/src/public/tier1/utldict.h @@ -1,358 +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
+//========= 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/mp/src/public/tier1/utlenvelope.h b/mp/src/public/tier1/utlenvelope.h index 8c8c4f79..3de254a3 100644 --- a/mp/src/public/tier1/utlenvelope.h +++ b/mp/src/public/tier1/utlenvelope.h @@ -1,241 +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
+//========= 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/mp/src/public/tier1/utlfixedmemory.h b/mp/src/public/tier1/utlfixedmemory.h index 3d92d679..6ff8c19b 100644 --- a/mp/src/public/tier1/utlfixedmemory.h +++ b/mp/src/public/tier1/utlfixedmemory.h @@ -1,354 +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
+//========= 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/mp/src/public/tier1/utlflags.h b/mp/src/public/tier1/utlflags.h index f18f1e15..e225b438 100644 --- a/mp/src/public/tier1/utlflags.h +++ b/mp/src/public/tier1/utlflags.h @@ -1,124 +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
+//========= 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/mp/src/public/tier1/utlhandletable.h b/mp/src/public/tier1/utlhandletable.h index 5d9c46fc..22f54357 100644 --- a/mp/src/public/tier1/utlhandletable.h +++ b/mp/src/public/tier1/utlhandletable.h @@ -1,586 +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
-
+//========= 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/mp/src/public/tier1/utlhash.h b/mp/src/public/tier1/utlhash.h index 72751ffc..7207b597 100644 --- a/mp/src/public/tier1/utlhash.h +++ b/mp/src/public/tier1/utlhash.h @@ -1,936 +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
+//========= 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/mp/src/public/tier1/utlhashdict.h b/mp/src/public/tier1/utlhashdict.h index b1ba7ecd..109bb759 100644 --- a/mp/src/public/tier1/utlhashdict.h +++ b/mp/src/public/tier1/utlhashdict.h @@ -1,342 +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
+//========= 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/mp/src/public/tier1/utlhashtable.h b/mp/src/public/tier1/utlhashtable.h index 051690fc..2517111f 100644 --- a/mp/src/public/tier1/utlhashtable.h +++ b/mp/src/public/tier1/utlhashtable.h @@ -1,944 +1,944 @@ -//========= 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).
-// - 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.
-//
-// 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 );
-
- // 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); }
-
-#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;
- }
-}
-
-// 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
+//========= 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). +// - 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. +// +// 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 ); + + // 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); } + +#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; + } +} + +// 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/mp/src/public/tier1/utlintrusivelist.h b/mp/src/public/tier1/utlintrusivelist.h index 98426f7a..04a39bd9 100644 --- a/mp/src/public/tier1/utlintrusivelist.h +++ b/mp/src/public/tier1/utlintrusivelist.h @@ -1,888 +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
+//========= 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/mp/src/public/tier1/utllinkedlist.h b/mp/src/public/tier1/utllinkedlist.h index ff251268..822f0b36 100644 --- a/mp/src/public/tier1/utllinkedlist.h +++ b/mp/src/public/tier1/utllinkedlist.h @@ -1,1286 +1,1286 @@ -//========= 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;
- 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 ) )
- {
- ExecuteNTimes( 10, Warning( "CUtlLinkedList overflow! (exhausted memory allocator)\n" ) );
- return InvalidIndex();
- }
- }
-
- // We can overflow before the utlmemory overflows, since S != I
- if ( !IndexInRange( m_Memory.GetIndex( it ) ) )
- {
- ExecuteNTimes( 10, Warning( "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
+//========= 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; + 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 ) ) + { + ExecuteNTimes( 10, Warning( "CUtlLinkedList overflow! (exhausted memory allocator)\n" ) ); + return InvalidIndex(); + } + } + + // We can overflow before the utlmemory overflows, since S != I + if ( !IndexInRange( m_Memory.GetIndex( it ) ) ) + { + ExecuteNTimes( 10, Warning( "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/mp/src/public/tier1/utlmap.h b/mp/src/public/tier1/utlmap.h index e79c7b85..9c08bc04 100644 --- a/mp/src/public/tier1/utlmap.h +++ b/mp/src/public/tier1/utlmap.h @@ -1,252 +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
+//========= 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/mp/src/public/tier1/utlmemory.h b/mp/src/public/tier1/utlmemory.h index 0d20a6ad..2b817bb2 100644 --- a/mp/src/public/tier1/utlmemory.h +++ b/mp/src/public/tier1/utlmemory.h @@ -1,1077 +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[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[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[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[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
+//========= 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[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[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[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[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/mp/src/public/tier1/utlmovingaverage.h b/mp/src/public/tier1/utlmovingaverage.h index 997b07c9..b91ccb60 100644 --- a/mp/src/public/tier1/utlmovingaverage.h +++ b/mp/src/public/tier1/utlmovingaverage.h @@ -1,103 +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
+//========= 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/mp/src/public/tier1/utlmultilist.h b/mp/src/public/tier1/utlmultilist.h index 95df4523..c677746c 100644 --- a/mp/src/public/tier1/utlmultilist.h +++ b/mp/src/public/tier1/utlmultilist.h @@ -1,769 +1,769 @@ -//========= 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 ) )
- {
- ExecuteNTimes( 10, Warning( "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() )
- {
- ExecuteNTimes( 10, Warning( "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
+//========= 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 ) ) + { + ExecuteNTimes( 10, Warning( "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() ) + { + ExecuteNTimes( 10, Warning( "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/mp/src/public/tier1/utlntree.h b/mp/src/public/tier1/utlntree.h index 7092b605..463b5e16 100644 --- a/mp/src/public/tier1/utlntree.h +++ b/mp/src/public/tier1/utlntree.h @@ -1,624 +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
+//========= 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/mp/src/public/tier1/utlobjectreference.h b/mp/src/public/tier1/utlobjectreference.h index 6ff30213..da9d3033 100644 --- a/mp/src/public/tier1/utlobjectreference.h +++ b/mp/src/public/tier1/utlobjectreference.h @@ -1,165 +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
-
-
-
-
-
+//========= 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/mp/src/public/tier1/utlpriorityqueue.h b/mp/src/public/tier1/utlpriorityqueue.h index cc6935cd..8d3f4573 100644 --- a/mp/src/public/tier1/utlpriorityqueue.h +++ b/mp/src/public/tier1/utlpriorityqueue.h @@ -1,198 +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
+//========= 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/mp/src/public/tier1/utlqueue.h b/mp/src/public/tier1/utlqueue.h index 30a4fdd4..8624a3db 100644 --- a/mp/src/public/tier1/utlqueue.h +++ b/mp/src/public/tier1/utlqueue.h @@ -1,114 +1,114 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef UTLQUEUE_H
-#define UTLQUEUE_H
-#ifdef _WIN32
-#pragma once
-#endif
-
-#include "utlvector.h"
-
-// T is the type stored in the stack
-template< class T >
-class CUtlQueue
-{
-public:
-
- // constructor: lessfunc is required, but may be set after the constructor with
- // SetLessFunc
- 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 const& RemoveAtHead();
- // return the item from the end of the queue and delete it
- T const& RemoveAtTail();
-
- // return item at the front of the queue
- T const& Head();
- // return item at the end of the queue
- T const& Tail();
-
- // 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 );
-
- // Returns the count of elements in the stack
- int Count() const { return m_heap.Count(); }
-
- // doesn't deallocate memory
- void RemoveAll() { m_heap.RemoveAll(); }
-
- // Memory deallocation
- void Purge() { m_heap.Purge(); }
-
-protected:
- CUtlVector<T> m_heap;
- T m_current;
-};
-
-template< class T >
-inline CUtlQueue<T>::CUtlQueue( int growSize, int initSize ) :
- m_heap(growSize, initSize)
-{
-}
-
-template< class T >
-inline CUtlQueue<T>::CUtlQueue( T *pMemory, int numElements ) :
- m_heap(pMemory, numElements)
-{
-}
-
-template <class T>
-inline T const& CUtlQueue<T>::RemoveAtHead()
-{
- m_current = m_heap[0];
- m_heap.Remove((int)0);
- return m_current;
-}
-
-template <class T>
-inline T const& CUtlQueue<T>::RemoveAtTail()
-{
- m_current = m_heap[ m_heap.Count() - 1 ];
- m_heap.Remove((int)(m_heap.Count() - 1));
- return m_current;
-}
-
-template <class T>
-inline T const& CUtlQueue<T>::Head()
-{
- m_current = m_heap[0];
- return m_current;
-}
-
-template <class T>
-inline T const& CUtlQueue<T>::Tail()
-{
- m_current = m_heap[ m_heap.Count() - 1 ];
- return m_current;
-}
-
-template <class T>
-void CUtlQueue<T>::Insert( T const &element )
-{
- int index = m_heap.AddToTail();
- m_heap[index] = element;
-}
-
-template <class T>
-bool CUtlQueue<T>::Check( T const element )
-{
- int index = m_heap.Find(element);
- return ( index != -1 );
-}
-
-
-#endif // UTLQUEUE_H
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLQUEUE_H +#define UTLQUEUE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + +// T is the type stored in the stack +template< class T > +class CUtlQueue +{ +public: + + // constructor: lessfunc is required, but may be set after the constructor with + // SetLessFunc + 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 const& RemoveAtHead(); + // return the item from the end of the queue and delete it + T const& RemoveAtTail(); + + // return item at the front of the queue + T const& Head(); + // return item at the end of the queue + T const& Tail(); + + // 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 ); + + // Returns the count of elements in the stack + int Count() const { return m_heap.Count(); } + + // doesn't deallocate memory + void RemoveAll() { m_heap.RemoveAll(); } + + // Memory deallocation + void Purge() { m_heap.Purge(); } + +protected: + CUtlVector<T> m_heap; + T m_current; +}; + +template< class T > +inline CUtlQueue<T>::CUtlQueue( int growSize, int initSize ) : + m_heap(growSize, initSize) +{ +} + +template< class T > +inline CUtlQueue<T>::CUtlQueue( T *pMemory, int numElements ) : + m_heap(pMemory, numElements) +{ +} + +template <class T> +inline T const& CUtlQueue<T>::RemoveAtHead() +{ + m_current = m_heap[0]; + m_heap.Remove((int)0); + return m_current; +} + +template <class T> +inline T const& CUtlQueue<T>::RemoveAtTail() +{ + m_current = m_heap[ m_heap.Count() - 1 ]; + m_heap.Remove((int)(m_heap.Count() - 1)); + return m_current; +} + +template <class T> +inline T const& CUtlQueue<T>::Head() +{ + m_current = m_heap[0]; + return m_current; +} + +template <class T> +inline T const& CUtlQueue<T>::Tail() +{ + m_current = m_heap[ m_heap.Count() - 1 ]; + return m_current; +} + +template <class T> +void CUtlQueue<T>::Insert( T const &element ) +{ + int index = m_heap.AddToTail(); + m_heap[index] = element; +} + +template <class T> +bool CUtlQueue<T>::Check( T const element ) +{ + int index = m_heap.Find(element); + return ( index != -1 ); +} + + +#endif // UTLQUEUE_H diff --git a/mp/src/public/tier1/utlrbtree.h b/mp/src/public/tier1/utlrbtree.h index 6ea22614..70b0d72c 100644 --- a/mp/src/public/tier1/utlrbtree.h +++ b/mp/src/public/tier1/utlrbtree.h @@ -1,1588 +1,1588 @@ -//========= 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();
-
- // 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_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();
- 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_FirstFree = InvalidIndex();
- m_Elements.Purge();
- m_LastAlloc = m_Elements.InvalidIterator();
-}
-
-
-//-----------------------------------------------------------------------------
-// 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
+//========= 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(); + + // 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_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(); + 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_FirstFree = InvalidIndex(); + m_Elements.Purge(); + m_LastAlloc = m_Elements.InvalidIterator(); +} + + +//----------------------------------------------------------------------------- +// 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/mp/src/public/tier1/utlsoacontainer.h b/mp/src/public/tier1/utlsoacontainer.h index 55073259..b9440c5f 100644 --- a/mp/src/public/tier1/utlsoacontainer.h +++ b/mp/src/public/tier1/utlsoacontainer.h @@ -1,334 +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
+//========= 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/mp/src/public/tier1/utlstack.h b/mp/src/public/tier1/utlstack.h index 9740effe..a46beb26 100644 --- a/mp/src/public/tier1/utlstack.h +++ b/mp/src/public/tier1/utlstack.h @@ -1,331 +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();
-}
-
+//========= 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/mp/src/public/tier1/utlstring.h b/mp/src/public/tier1/utlstring.h index 26d98338..f425b271 100644 --- a/mp/src/public/tier1/utlstring.h +++ b/mp/src/public/tier1/utlstring.h @@ -1,401 +1,401 @@ -//========= 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"
-
-#if defined( OSX )
-#define wcsdup wcsdup_osx
-inline wchar_t *wcsdup_osx(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
-
-//-----------------------------------------------------------------------------
-// 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();
-}
-
-
-//-----------------------------------------------------------------------------
-// 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 CUtlString& string );
-
- // Attaches the string to external memory. Useful for avoiding a copy
- CUtlString( void* pMemory, int nSizeInBytes, int nInitialLength );
- CUtlString( const void* pMemory, int nSizeInBytes );
-
- const char *Get( ) const;
- void Set( const char *pValue );
-
- void Clear() { Set( NULL ); }
-
- // Converts to c-strings
- operator const char*() const;
-
- // for compatibility switching items from UtlSymbol
- const char *String() const { return Get(); }
-
- // Returns strlen
- int Length() const;
- 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 *Get();
- void Purge();
-
- // Case Change
- void ToLower();
- void ToUpper();
-
- void Append( const char *pchAddition );
-
- // Strips the trailing slash
- void StripTrailingSlash();
-
- CUtlString &operator=( const CUtlString &src );
- CUtlString &operator=( const char *src );
-
- // Test for equality
- bool operator==( const CUtlString &src ) const;
- bool operator==( const char *src ) const;
- bool operator!=( const CUtlString &src ) const { return !operator==( src ); }
- bool operator!=( const char *src ) const { return !operator==( src ); }
-
- // If these are not defined, CUtlString as rhs will auto-convert
- // to const char* and do logical operations on the raw pointers. Ugh.
- inline friend bool operator==( const char *lhs, const CUtlString &rhs ) { return rhs.operator==( lhs ); }
- inline friend bool operator!=( const char *lhs, const CUtlString &rhs ) { return rhs.operator!=( lhs ); }
-
- CUtlString &operator+=( const CUtlString &rhs );
- CUtlString &operator+=( const char *rhs );
- CUtlString &operator+=( char c );
- CUtlString &operator+=( int rhs );
- CUtlString &operator+=( double rhs );
-
- // is valid?
- bool IsValid() const;
-
- bool MatchesPattern( const CUtlString &Pattern, int nFlags = 0 ); // case SENSITIVE, use * for wildcard in pattern string
-
- int Format( PRINTF_FORMAT_STRING const char *pFormat, ... );
- void SetDirect( const char *pValue, int nChars );
-
- // 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;
-
- // Take a piece out 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 );
-
- // Grab a substring starting from the left or the right side.
- CUtlString Left( int32 nChars );
- CUtlString Right( int32 nChars );
-
- // Replace all instances of one character with another.
- CUtlString Replace( char cFrom, char cTo );
-
- // Calls right through to V_MakeAbsolutePath.
- CUtlString AbsPath( const char *pStartingDir=NULL );
-
- // Gets the filename (everything except the path.. c:\a\b\c\somefile.txt -> somefile.txt).
- CUtlString UnqualifiedFilename();
-
- // Strips off one directory. Uses V_StripLastDir but strips the last slash also!
- CUtlString DirName();
-
- // 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 );
-
-private:
- CUtlBinaryBlock m_Storage;
-};
-
-//-----------------------------------------------------------------------------
-// Inline methods
-//-----------------------------------------------------------------------------
-inline bool CUtlString::IsEmpty() const
-{
- return Length() == 0;
-}
-
-inline bool CUtlString::IsValid() const
-{
- return ( String() != NULL );
-}
-
-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() );
-}
-
-//-----------------------------------------------------------------------------
-// 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(); }
-
- 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; } };
-
-
-#endif // UTLSTRING_H
+//========= 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" + +#if defined( OSX ) +#define wcsdup wcsdup_osx +inline wchar_t *wcsdup_osx(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 + +//----------------------------------------------------------------------------- +// 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(); +} + + +//----------------------------------------------------------------------------- +// 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 CUtlString& string ); + + // Attaches the string to external memory. Useful for avoiding a copy + CUtlString( void* pMemory, int nSizeInBytes, int nInitialLength ); + CUtlString( const void* pMemory, int nSizeInBytes ); + + const char *Get( ) const; + void Set( const char *pValue ); + + void Clear() { Set( NULL ); } + + // Converts to c-strings + operator const char*() const; + + // for compatibility switching items from UtlSymbol + const char *String() const { return Get(); } + + // Returns strlen + int Length() const; + 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 *Get(); + void Purge(); + + // Case Change + void ToLower(); + void ToUpper(); + + void Append( const char *pchAddition ); + + // Strips the trailing slash + void StripTrailingSlash(); + + CUtlString &operator=( const CUtlString &src ); + CUtlString &operator=( const char *src ); + + // Test for equality + bool operator==( const CUtlString &src ) const; + bool operator==( const char *src ) const; + bool operator!=( const CUtlString &src ) const { return !operator==( src ); } + bool operator!=( const char *src ) const { return !operator==( src ); } + + // If these are not defined, CUtlString as rhs will auto-convert + // to const char* and do logical operations on the raw pointers. Ugh. + inline friend bool operator==( const char *lhs, const CUtlString &rhs ) { return rhs.operator==( lhs ); } + inline friend bool operator!=( const char *lhs, const CUtlString &rhs ) { return rhs.operator!=( lhs ); } + + CUtlString &operator+=( const CUtlString &rhs ); + CUtlString &operator+=( const char *rhs ); + CUtlString &operator+=( char c ); + CUtlString &operator+=( int rhs ); + CUtlString &operator+=( double rhs ); + + // is valid? + bool IsValid() const; + + bool MatchesPattern( const CUtlString &Pattern, int nFlags = 0 ); // case SENSITIVE, use * for wildcard in pattern string + + int Format( PRINTF_FORMAT_STRING const char *pFormat, ... ); + void SetDirect( const char *pValue, int nChars ); + + // 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; + + // Take a piece out 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 ); + + // Grab a substring starting from the left or the right side. + CUtlString Left( int32 nChars ); + CUtlString Right( int32 nChars ); + + // Replace all instances of one character with another. + CUtlString Replace( char cFrom, char cTo ); + + // Calls right through to V_MakeAbsolutePath. + CUtlString AbsPath( const char *pStartingDir=NULL ); + + // Gets the filename (everything except the path.. c:\a\b\c\somefile.txt -> somefile.txt). + CUtlString UnqualifiedFilename(); + + // Strips off one directory. Uses V_StripLastDir but strips the last slash also! + CUtlString DirName(); + + // 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 ); + +private: + CUtlBinaryBlock m_Storage; +}; + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline bool CUtlString::IsEmpty() const +{ + return Length() == 0; +} + +inline bool CUtlString::IsValid() const +{ + return ( String() != NULL ); +} + +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() ); +} + +//----------------------------------------------------------------------------- +// 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(); } + + 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; } }; + + +#endif // UTLSTRING_H diff --git a/mp/src/public/tier1/utlsymbol.h b/mp/src/public/tier1/utlsymbol.h index b169b9ce..e90be466 100644 --- a/mp/src/public/tier1/utlsymbol.h +++ b/mp/src/public/tier1/utlsymbol.h @@ -1,269 +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
+//========= 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/mp/src/public/tier1/utlsymbollarge.h b/mp/src/public/tier1/utlsymbollarge.h index 735e32e6..43845404 100644 --- a/mp/src/public/tier1/utlsymbollarge.h +++ b/mp/src/public/tier1/utlsymbollarge.h @@ -1,499 +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
+//========= 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/mp/src/public/tier1/utltshash.h b/mp/src/public/tier1/utltshash.h index eb19ae99..9ff4e83f 100644 --- a/mp/src/public/tier1/utltshash.h +++ b/mp/src/public/tier1/utltshash.h @@ -1,625 +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
+//========= 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/mp/src/public/tier1/utlvector.h b/mp/src/public/tier1/utlvector.h index 3b8dd0ee..1f2fe6e1 100644 --- a/mp/src/public/tier1/utlvector.h +++ b/mp/src/public/tier1/utlvector.h @@ -1,1210 +1,1210 @@ -//========= 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 <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"
-
-#define FOR_EACH_VEC( vecName, iteratorName ) \
- for ( int iteratorName = 0; iteratorName < (vecName).Count(); iteratorName++ )
-#define FOR_EACH_VEC_BACK( vecName, iteratorName ) \
- for ( int iteratorName = (vecName).Count()-1; iteratorName >= 0; iteratorName-- )
-
-//-----------------------------------------------------------------------------
-// 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
-{
- typedef A CAllocator;
-public:
- typedef T ElemType_t;
- typedef T* iterator;
- typedef const T* const_iterator;
-
- // constructor, destructor
- explicit CUtlVector( int growSize = 0, int initSize = 0 );
- explicit CUtlVector( T* pMemory, int allocationCount, int numElements = 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;
-
- // 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!
-
- // Is element index valid?
- bool IsValidIndex( int i ) const;
- static int InvalidIndex();
-
- // Adds an element, uses default constructor
- int AddToHead();
- int AddToTail();
- 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, const T *pToCopy=NULL );
- int InsertMultipleBefore( int elem, int num, const T *pToCopy=NULL ); // If pToCopy is set, then it's an array of length 'num' and
- int InsertMultipleAfter( int elem, int num );
-
- // Calls RemoveAll() then AddMultipleToTail.
- void SetSize( int size );
- 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;
-
- bool HasElement( const T& src ) const;
-
- // Makes sure we have enough memory allocated to store a requested # of elements
- void EnsureCapacity( int num );
-
- // Makes sure we have at least this many elements
- 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 *) );
-
-#ifdef DBGFLAG_VALIDATE
- void Validate( CValidator &validator, char *pchName ); // Validate our internal structures
-#endif // DBGFLAG_VALIDATE
-
-protected:
- // 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:
- // Can't copy this unless we explicitly do it!
- // Use CCopyableUtlVector<T> to get this functionality
- CUtlVector( CUtlVector const& vec );
-};
-
-
-// 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 ) {}
-
-private:
- // Private and unimplemented because iterator semantics are not currently supported
- // on CUtlBlockVector, due to its non-contiguous allocations.
- // typename is require to disambiguate iterator as a type versus other possibilities.
- typedef CUtlVector< T, CUtlBlockMemory< T, int > > Base;
- typename Base::iterator begin();
- typename Base::const_iterator begin() const;
- typename Base::iterator end();
- typename Base::const_iterator end() const;
-};
-
-//-----------------------------------------------------------------------------
-// The CUtlVectorFixed class:
-// A array class with a fixed allocation scheme
-//-----------------------------------------------------------------------------
-
-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 ) {}
- explicit 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 ) {}
- explicit 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 ) {}
- explicit 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:
- 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(int) + ( num * sizeof(T) ) );
- m_pData->m_Size = 0;
- }
- else
- {
- int nNeeded = sizeof(int) + ( 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; )
- {
- 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) );
-
- 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 )
- {
- 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;
- }
-
- 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)
-
-
-//-----------------------------------------------------------------------------
-// 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< typename T, typename A = CUtlMemory<T> >
-class CCopyableUtlVector : public CUtlVector< T, A >
-{
- typedef CUtlVector< T, A > BaseClass;
-public:
- explicit CCopyableUtlVector( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {}
- explicit CCopyableUtlVector( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {}
- virtual ~CCopyableUtlVector() {}
- CCopyableUtlVector( CCopyableUtlVector 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;
-}
-
-
-//-----------------------------------------------------------------------------
-// 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 );
- 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 );
- 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 );
- 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 );
- return m_Memory[ i ];
-}
-
-template< typename T, class A >
-inline T& CUtlVector<T, A>::Head()
-{
- Assert( m_Size > 0 );
- return m_Memory[ 0 ];
-}
-
-template< typename T, class A >
-inline const T& CUtlVector<T, A>::Head() const
-{
- Assert( m_Size > 0 );
- return m_Memory[ 0 ];
-}
-
-template< typename T, class A >
-inline T& CUtlVector<T, A>::Tail()
-{
- Assert( m_Size > 0 );
- return m_Memory[ m_Size - 1 ];
-}
-
-template< typename T, class A >
-inline const T& CUtlVector<T, A>::Tail() const
-{
- Assert( m_Size > 0 );
- 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 int CUtlVector<T, A>::Count() const
-{
- return m_Size;
-}
-
-
-//-----------------------------------------------------------------------------
-// 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 ) );
- }
- }
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// 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 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, 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.
- AddMultipleToTail( src.Count() );
-
- // Copy the elements.
- for ( int i=0; i < src.Count(); i++ )
- {
- (*this)[base + i] = src[i];
- }
-
- return base;
-}
-
-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
- for (int i = 0; i < num; ++i )
- Construct( &Element( elem+i ) );
-
- // Copy stuff in?
- if ( pToInsert )
- {
- for ( int i=0; i < num; i++ )
- {
- 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;
-}
-
-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) );
-
- Destruct( &Element(elem) );
- if (m_Size > 0)
- {
- if ( elem != m_Size -1 )
- memcpy( reinterpret_cast<void*>( &Element(elem) ), reinterpret_cast<void*>( &Element(m_Size-1) ), sizeof(T) );
- --m_Size;
- }
-}
-
-template< typename T, class A >
-void CUtlVector<T, A>::Remove( int elem )
-{
- 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() );
-
- 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() );
-
- 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() );
-
- 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; )
- {
- 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 );
- }
-
- inline void PurgeAndDeleteElements()
- {
- for( int i=0; i < m_Size; i++ )
- {
- delete [] Element(i);
- }
- Purge();
- }
-
- ~CUtlStringList( void )
- {
- this->PurgeAndDeleteElements();
- }
-};
-
-
-
-// <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
+//========= 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 <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" + +#define FOR_EACH_VEC( vecName, iteratorName ) \ + for ( int iteratorName = 0; iteratorName < (vecName).Count(); iteratorName++ ) +#define FOR_EACH_VEC_BACK( vecName, iteratorName ) \ + for ( int iteratorName = (vecName).Count()-1; iteratorName >= 0; iteratorName-- ) + +//----------------------------------------------------------------------------- +// 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 +{ + typedef A CAllocator; +public: + typedef T ElemType_t; + typedef T* iterator; + typedef const T* const_iterator; + + // constructor, destructor + explicit CUtlVector( int growSize = 0, int initSize = 0 ); + explicit CUtlVector( T* pMemory, int allocationCount, int numElements = 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; + + // 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! + + // Is element index valid? + bool IsValidIndex( int i ) const; + static int InvalidIndex(); + + // Adds an element, uses default constructor + int AddToHead(); + int AddToTail(); + 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, const T *pToCopy=NULL ); + int InsertMultipleBefore( int elem, int num, const T *pToCopy=NULL ); // If pToCopy is set, then it's an array of length 'num' and + int InsertMultipleAfter( int elem, int num ); + + // Calls RemoveAll() then AddMultipleToTail. + void SetSize( int size ); + 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; + + bool HasElement( const T& src ) const; + + // Makes sure we have enough memory allocated to store a requested # of elements + void EnsureCapacity( int num ); + + // Makes sure we have at least this many elements + 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 *) ); + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, char *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + +protected: + // 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: + // Can't copy this unless we explicitly do it! + // Use CCopyableUtlVector<T> to get this functionality + CUtlVector( CUtlVector const& vec ); +}; + + +// 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 ) {} + +private: + // Private and unimplemented because iterator semantics are not currently supported + // on CUtlBlockVector, due to its non-contiguous allocations. + // typename is require to disambiguate iterator as a type versus other possibilities. + typedef CUtlVector< T, CUtlBlockMemory< T, int > > Base; + typename Base::iterator begin(); + typename Base::const_iterator begin() const; + typename Base::iterator end(); + typename Base::const_iterator end() const; +}; + +//----------------------------------------------------------------------------- +// The CUtlVectorFixed class: +// A array class with a fixed allocation scheme +//----------------------------------------------------------------------------- + +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 ) {} + explicit 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 ) {} + explicit 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 ) {} + explicit 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: + 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(int) + ( num * sizeof(T) ) ); + m_pData->m_Size = 0; + } + else + { + int nNeeded = sizeof(int) + ( 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; ) + { + 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) ); + + 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 ) + { + 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; + } + + 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) + + +//----------------------------------------------------------------------------- +// 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< typename T, typename A = CUtlMemory<T> > +class CCopyableUtlVector : public CUtlVector< T, A > +{ + typedef CUtlVector< T, A > BaseClass; +public: + explicit CCopyableUtlVector( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + explicit CCopyableUtlVector( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} + virtual ~CCopyableUtlVector() {} + CCopyableUtlVector( CCopyableUtlVector 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; +} + + +//----------------------------------------------------------------------------- +// 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 ); + 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 ); + 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 ); + 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 ); + return m_Memory[ i ]; +} + +template< typename T, class A > +inline T& CUtlVector<T, A>::Head() +{ + Assert( m_Size > 0 ); + return m_Memory[ 0 ]; +} + +template< typename T, class A > +inline const T& CUtlVector<T, A>::Head() const +{ + Assert( m_Size > 0 ); + return m_Memory[ 0 ]; +} + +template< typename T, class A > +inline T& CUtlVector<T, A>::Tail() +{ + Assert( m_Size > 0 ); + return m_Memory[ m_Size - 1 ]; +} + +template< typename T, class A > +inline const T& CUtlVector<T, A>::Tail() const +{ + Assert( m_Size > 0 ); + 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 int CUtlVector<T, A>::Count() const +{ + return m_Size; +} + + +//----------------------------------------------------------------------------- +// 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 ) ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// 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 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, 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. + AddMultipleToTail( src.Count() ); + + // Copy the elements. + for ( int i=0; i < src.Count(); i++ ) + { + (*this)[base + i] = src[i]; + } + + return base; +} + +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 + for (int i = 0; i < num; ++i ) + Construct( &Element( elem+i ) ); + + // Copy stuff in? + if ( pToInsert ) + { + for ( int i=0; i < num; i++ ) + { + 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; +} + +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) ); + + Destruct( &Element(elem) ); + if (m_Size > 0) + { + if ( elem != m_Size -1 ) + memcpy( reinterpret_cast<void*>( &Element(elem) ), reinterpret_cast<void*>( &Element(m_Size-1) ), sizeof(T) ); + --m_Size; + } +} + +template< typename T, class A > +void CUtlVector<T, A>::Remove( int elem ) +{ + 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() ); + + 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() ); + + 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() ); + + 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; ) + { + 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 ); + } + + inline void PurgeAndDeleteElements() + { + for( int i=0; i < m_Size; i++ ) + { + delete [] Element(i); + } + Purge(); + } + + ~CUtlStringList( void ) + { + this->PurgeAndDeleteElements(); + } +}; + + + +// <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 |