From 80aff5ec260d2492ffa78fd71f3cdb22a631c772 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sun, 23 Feb 2025 22:44:35 +0300 Subject: [PATCH 01/30] Add `CUtlStringMap::FindAndRemove` method --- public/tier1/UtlStringMap.h | 106 ++++++++++++++++++++++++++++++++---- 1 file changed, 96 insertions(+), 10 deletions(-) diff --git a/public/tier1/UtlStringMap.h b/public/tier1/UtlStringMap.h index c14334865..e21f23147 100644 --- a/public/tier1/UtlStringMap.h +++ b/public/tier1/UtlStringMap.h @@ -6,6 +6,7 @@ #ifndef UTLSTRINGMAP_H #define UTLSTRINGMAP_H + #ifdef _WIN32 #pragma once #endif @@ -17,8 +18,8 @@ class CUtlStringMap { public: CUtlStringMap( bool caseInsensitive = true, int initsize = 32 ) : - m_SymbolTable( 0, 32, caseInsensitive ), - m_Vector( initsize ) + m_Vector( initsize ), + m_SymbolTable( 0, 32, caseInsensitive ) { } @@ -26,7 +27,7 @@ class CUtlStringMap T& operator[]( const char *pString ) { CUtlSymbol symbol = m_SymbolTable.AddString( pString ); - int index = ( int )( UtlSymId_t )symbol; + int index = ( int )symbol; if( m_Vector.Count() <= index ) { m_Vector.EnsureCount( index + 1 ); @@ -35,32 +36,38 @@ class CUtlStringMap } // 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 ) + T& operator[]( CUtlSymbol n ) { Assert( n <= m_Vector.Count() ); return m_Vector[n]; } - const T& operator[]( UtlSymId_t n ) const + const T& operator[]( CUtlSymbol n ) const { Assert( n <= m_Vector.Count() ); return m_Vector[n]; } + unsigned int Count() const + { + // Assert( m_Vector.Count() == m_SymbolTable.GetNumStrings() ); + return m_Vector.Count(); + } + bool Defined( const char *pString ) const { return m_SymbolTable.Find( pString ).IsValid(); } - UtlSymId_t Find( const char *pString ) const + CUtlSymbol Find( const char *pString ) const { return m_SymbolTable.Find( pString ); } - UtlSymId_t AddString( const char *pString, bool* created = NULL ) + CUtlSymbol AddString( const char *pString, bool* created = NULL ) { CUtlSymbol symbol = m_SymbolTable.AddString( pString, created ); - int index = ( int )( UtlSymId_t )symbol; + int index = ( int )symbol; if( m_Vector.Count() <= index ) { m_Vector.EnsureCount( index + 1 ); @@ -68,11 +75,78 @@ class CUtlStringMap return symbol; } - static UtlSymId_t InvalidIndex() + /// Add a string to the map and also insert an item at + /// its location in the same operation. Returns the + /// newly created index (or the one that was just + /// overwritten, if pString already existed.) + CUtlSymbol Insert( const char *pString, const T &item ) { - return UTL_INVAL_SYMBOL; + CUtlSymbol symbol = m_SymbolTable.AddString( pString ); // implicit coercion + if ( m_Vector.Count() > symbol ) + { + // this string is already in the dictionary. + + } + else if ( m_Vector.Count() == symbol ) + { + // this is the expected case when we've added one more to the tail. + m_Vector.AddToTail( item ); + } + else // ( m_Vector.Count() < symbol ) + { + // this is a strange shouldn't-happen case. + AssertMsg( false, "CUtlStringMap insert unexpected entries." ); + m_Vector.EnsureCount( symbol + 1 ); + m_Vector[symbol] = item; + } + return symbol; } + bool FindAndRemove( const char *pString ) + { + CUtlSymbol symbol = m_SymbolTable.Find( pString ); + + if ( !symbol.IsValid() ) + { + return false; + } + + m_Vector.Remove( symbol ); + + return true; + } + + /// iterate, not in any particular order. + CUtlSymbol First() const + { + if ( Count() > 0 ) + { + return 0; + } + else + { + return InvalidIndex(); + } + } + + static CUtlSymbol InvalidIndex() + { + return {}; + } + + // iterators (for uniformity with other map types) + inline CUtlSymbol Head() const + { + return m_SymbolTable.GetNumStrings() > 0 ? CUtlSymbol( 0 ) : InvalidIndex(); + } + + inline CUtlSymbol Next( const CUtlSymbol &i ) const + { + CUtlSymbol n = i+1; + return n < m_SymbolTable.GetNumStrings() ? n : InvalidIndex(); + } + + int GetNumStrings( void ) const { return m_SymbolTable.GetNumStrings(); @@ -109,4 +183,16 @@ class CUtlStringMap CUtlSymbolTable m_SymbolTable; }; + +template< class T > +class CUtlStringMapAutoPurge : public CUtlStringMap < T > +{ +public: + ~CUtlStringMapAutoPurge( void ) + { + this->PurgeAndDeleteElements(); + } + +}; + #endif // UTLSTRINGMAP_H From 292e03c7f0a7bcc9b0ea91ce440a044bd830bd14 Mon Sep 17 00:00:00 2001 From: Boeing666 Date: Sun, 2 Mar 2025 17:06:40 +0500 Subject: [PATCH 02/30] Removed Plat_FatalErrorFunc from deadlock --- public/tier0/dbg.h | 22 +++------------------- public/tier0/platform.h | 13 +++++++++++-- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/public/tier0/dbg.h b/public/tier0/dbg.h index 37cc3655a..d11c008f0 100644 --- a/public/tier0/dbg.h +++ b/public/tier0/dbg.h @@ -243,6 +243,9 @@ PLATFORM_INTERFACE void Msg( const tchar* pMsg, ... ); PLATFORM_INTERFACE void Warning( const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); PLATFORM_INTERFACE void Warning_SpewCallStack( int iMaxCallStackLength, const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); +#define Plat_FatalError( ... ) do { Log_Error( LOG_GENERAL, ##__VA_ARGS__ ); Plat_ExitProcess( EXIT_FAILURE ); } while( 0 ) +#define Plat_FatalErrorFunc + // This is gone in Source2. Provide helper to roughly mimic Source1 behavior void Error( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); inline void Error( const tchar* pMsg, ... ) @@ -312,25 +315,6 @@ PLATFORM_INTERFACE void COM_TimestampedLog( char const *fmt, ... ) FMTFUNCTION( #endif /* _DEBUG */ -//----------------------------------------------------------------------------- -// Macro to assist in asserting constant invariants during compilation - -#define COMPILE_TIME_ASSERT( pred ) static_assert( pred, "Compile time assert constraint is not true: " #pred ) -// ASSERT_INVARIANT used to be needed in order to allow COMPILE_TIME_ASSERTs at global -// scope. However the new COMPILE_TIME_ASSERT macro supports that by default. -#define ASSERT_INVARIANT( pred ) COMPILE_TIME_ASSERT( pred ) - -#ifdef _DEBUG -template -inline DEST_POINTER_TYPE assert_cast(SOURCE_POINTER_TYPE* pSource) -{ - Assert( static_cast(pSource) == dynamic_cast(pSource) ); - return static_cast(pSource); -} -#else -#define assert_cast static_cast -#endif - //----------------------------------------------------------------------------- // Templates to assist in validating pointers: diff --git a/public/tier0/platform.h b/public/tier0/platform.h index 1450957b4..ecdb17a28 100644 --- a/public/tier0/platform.h +++ b/public/tier0/platform.h @@ -81,6 +81,17 @@ class CBufferString; // scope. However the new COMPILE_TIME_ASSERT macro supports that by default. #define ASSERT_INVARIANT( pred ) COMPILE_TIME_ASSERT( pred ) +#ifdef _DEBUG +template +inline DEST_POINTER_TYPE assert_cast(SOURCE_POINTER_TYPE* pSource) +{ + Assert( static_cast(pSource) == dynamic_cast(pSource) ); + return static_cast(pSource); +} +#else +#define assert_cast static_cast +#endif + // feature enables #define NEW_SOFTWARE_LIGHTING #if !defined( _X360 ) @@ -1117,8 +1128,6 @@ PLATFORM_INTERFACE void Plat_ExitProcess( int nCode ); PLATFORM_INTERFACE bool Plat_ShouldCollectMiniDumpsForFatalErrors(); -PLATFORM_INTERFACE void Plat_FatalErrorFunc( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); - // b/w compatibility #define Sys_FloatTime Plat_FloatTime From d8c5f5431d2efcada93f0ead1c6ecf81cdeee53b Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Tue, 4 Mar 2025 15:42:36 +0300 Subject: [PATCH 03/30] `CUtlStringMap`: remove hash element of symbol table --- public/tier1/UtlStringMap.h | 1 + public/tier1/utlsymbol.h | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/public/tier1/UtlStringMap.h b/public/tier1/UtlStringMap.h index e21f23147..e4cb8f6ea 100644 --- a/public/tier1/UtlStringMap.h +++ b/public/tier1/UtlStringMap.h @@ -112,6 +112,7 @@ class CUtlStringMap } m_Vector.Remove( symbol ); + m_SymbolTable.Remove( symbol ); return true; } diff --git a/public/tier1/utlsymbol.h b/public/tier1/utlsymbol.h index 08e9c441f..265e4dcb7 100644 --- a/public/tier1/utlsymbol.h +++ b/public/tier1/utlsymbol.h @@ -95,7 +95,12 @@ class CUtlSymbolTable // Look up the string associated with a particular symbol DLL_CLASS_IMPORT const char* String( CUtlSymbol id ) const; - + + void Remove( CUtlSymbol id ) + { + m_HashTable.Remove( id ); + } + // Remove all symbols in the table. DLL_CLASS_IMPORT void RemoveAll(); DLL_CLASS_IMPORT void Purge(); From caa592891e20603d7aa6f92bb6e0761e3fe7df9c Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Thu, 6 Mar 2025 21:58:24 +0300 Subject: [PATCH 04/30] Update `CUtlSymbolTable` & hash staff --- interfaces/interfaces.cpp | 2 +- public/entity2/entitykeyvalues.h | 2 +- public/tier1/UtlStringMap.h | 6 +- public/tier1/bufferstring.h | 24 ++-- public/tier1/keyvalues3.h | 72 ++++++++---- public/tier1/utlhashtable.h | 15 ++- public/tier1/utlstringtoken.h | 166 +++++++++++++++++++++++--- public/tier1/utlsymbol.h | 153 +++++++++++++++++++----- public/tier1/utlsymbollarge.h | 54 +++++---- tier1/keyvalues3.cpp | 194 +++++++++++++++++++------------ 10 files changed, 503 insertions(+), 185 deletions(-) diff --git a/interfaces/interfaces.cpp b/interfaces/interfaces.cpp index 864af2049..e3a389d61 100644 --- a/interfaces/interfaces.cpp +++ b/interfaces/interfaces.cpp @@ -6,8 +6,8 @@ /* This is totally reverse-engineered code and may be wrong */ -#include "interfaces/interfaces.h" #include "tier0/dbg.h" +#include "interfaces/interfaces.h" IApplication *g_pApplication; ICvar *cvar, *g_pCVar; diff --git a/public/entity2/entitykeyvalues.h b/public/entity2/entitykeyvalues.h index 255f1d23c..447f6ff81 100644 --- a/public/entity2/entitykeyvalues.h +++ b/public/entity2/entitykeyvalues.h @@ -248,7 +248,7 @@ inline EntityKeyId_t CEntityKeyValues::GetEntityKeyId( const CEntityKeyValues::I if ( it.index >= it.keys->GetMemberCount() ) return EntityKeyId_t(); - return it.keys->GetMemberNameEx( it.index ); + return it.keys->GetKV3MemberName( it.index ); } inline const char* CEntityKeyValues::GetAttributeName( const CEntityKeyValues::Iterator_t &it ) const diff --git a/public/tier1/UtlStringMap.h b/public/tier1/UtlStringMap.h index e4cb8f6ea..3d7fb96e0 100644 --- a/public/tier1/UtlStringMap.h +++ b/public/tier1/UtlStringMap.h @@ -13,6 +13,9 @@ #include "utlsymbol.h" +#define FOR_EACH_STRING_MAP( mapName, iter ) \ + for ( auto iter = (mapName).First(); iter < (mapName).GetNumStrings() && iter != (mapName).InvalidIndex(); iter = (mapName).Next( iter ) ) + template class CUtlStringMap { @@ -111,7 +114,8 @@ class CUtlStringMap return false; } - m_Vector.Remove( symbol ); + Destruct( &m_Vector[ symbol ] ); + m_Vector[ symbol ] = {}; m_SymbolTable.Remove( symbol ); return true; diff --git a/public/tier1/bufferstring.h b/public/tier1/bufferstring.h index 356aa092a..5bd89de07 100644 --- a/public/tier1/bufferstring.h +++ b/public/tier1/bufferstring.h @@ -83,7 +83,6 @@ class CBufferString m_nAllocatedSize( (bAllowHeapAllocation * ALLOW_HEAP_ALLOCATION) | STACK_ALLOCATED_MARKER | (nAllocatedSize + sizeof( m_szString )) ), m_pString( nullptr ) { - Assert( nAllocatedSize > 8 ); } public: @@ -122,11 +121,11 @@ class CBufferString bool IsAllocationEmpty() const { return AllocatedNum() == 0; } protected: - char *Base() { return IsStackAllocated() ? m_szString : (!IsAllocationEmpty() ? m_pString : nullptr); } + char *Base() { return IsStackAllocated() ? m_szString : m_pString; } const char *Base() const { return const_cast( this )->Base(); } public: - const char *Get() const { auto base = Base(); return base ? base : StringFuncs::EmptyString(); } + const char *Get() const { return IsStackAllocated() ? m_szString : (IsAllocationEmpty() ? StringFuncs::EmptyString() : m_pString); } void Clear() { @@ -269,8 +268,8 @@ class CBufferString DLL_CLASS_IMPORT const char *StripExtension(); DLL_CLASS_IMPORT const char *StripTrailingSlash(); - DLL_CLASS_IMPORT void ToLowerFast(int nStart); - DLL_CLASS_IMPORT void ToUpperFast(int nStart); + DLL_CLASS_IMPORT void ToLowerFast(int nStart = 0); + DLL_CLASS_IMPORT void ToUpperFast(int nStart = 0); DLL_CLASS_IMPORT const char *Trim(const char *pTrimChars = "\t\r\n "); DLL_CLASS_IMPORT const char *TrimHead(const char *pTrimChars = "\t\r\n "); @@ -292,19 +291,14 @@ class CBufferString }; }; -template +template< uintp SIZE = 128 > // Most commonly used. class CBufferStringN : public CBufferString { public: - static const size_t DATA_SIZE = ALIGN_VALUE( SIZE - sizeof( char[8] ), 8 ); + static const uintp DATA_SIZE = ALIGN_VALUE( SIZE - sizeof( char[8] ), 8 ); - CBufferStringN( bool bAllowHeapAllocation = true ) : CBufferString( DATA_SIZE, bAllowHeapAllocation ), m_FixedData{} {} - CBufferStringN( const char *pString, bool bAllowHeapAllocation = true ) : CBufferStringN( bAllowHeapAllocation ) - { - Insert( 0, pString ); - } - - ~CBufferStringN() { PurgeN(); } + CBufferStringN( bool bAllowHeapAllocation = true ) : CBufferString( DATA_SIZE, bAllowHeapAllocation ) {} + CBufferStringN( const char *pString, int nLen = -1, bool bAllowHeapAllocation = true ) : CBufferStringN( bAllowHeapAllocation ) { Insert( 0, pString, nLen ); } // Should be preferred over CBufferString::Purge as it preserves stack space correctly void PurgeN() { Purge( DATA_SIZE ); } @@ -314,7 +308,7 @@ class CBufferStringN : public CBufferString }; // AMNOTE: CBufferStringN name is preferred to be used, altho CBufferStringGrowable is left as a small bcompat -template +template< uintp SIZE > using CBufferStringGrowable = CBufferStringN; #endif /* BUFFERSTRING_H */ \ No newline at end of file diff --git a/public/tier1/keyvalues3.h b/public/tier1/keyvalues3.h index 443a98274..698c66a61 100644 --- a/public/tier1/keyvalues3.h +++ b/public/tier1/keyvalues3.h @@ -364,26 +364,43 @@ struct KV3BinaryBlob_t class CKV3MemberName { public: - inline CKV3MemberName(const char* pszString): m_nHashCode(), m_pszString("") - { - if (!pszString || !pszString[0]) - return; + template< uintp N > constexpr CKV3MemberName( const char (&szInit)[N] ) : CUtlStringToken( szInit ), m_pszString( (const char *)szInit ) {} + CKV3MemberName( const char* pszString, int nLen ) : CUtlStringToken( MakeStringToken2( pszString, nLen ) ), m_pszString( pszString ) {} + CKV3MemberName( uint32 nHash = 0, const char* pszString = StringFuncs::EmptyString() ) : CUtlStringToken( nHash ), m_pszString( pszString ) {} - m_nHashCode = MakeStringToken( pszString ); - m_pszString = pszString; - } + static CKV3MemberName Make( const char *pszInit, int nLen = -1 ) + { + Assert( pszInit && pszInit[0] ); - inline CKV3MemberName(): m_nHashCode(), m_pszString("") {} - inline CKV3MemberName( CUtlStringToken nHashCode, const char* pszString = ""): m_nHashCode(nHashCode), m_pszString(pszString) {} + return CKV3MemberName( pszInit, nLen ); + } - inline unsigned int GetHashCode() const { return m_nHashCode.GetHashCode(); } - inline const char* GetString() const { return m_pszString; } + const char* GetString() const { return m_pszString; } private: - CUtlStringToken m_nHashCode; const char* m_pszString; }; +using KeyValues3LowercaseHash_t = CUtlStringToken; +using CKeyValues3StringAndHash = CKV3MemberName; + +// Pulse thing +class CKV3MemberNameWithStorage : public CKV3MemberName +{ +public: + template< uintp N > constexpr CKV3MemberNameWithStorage( const char (&szInit)[N] ) : CKV3MemberName( szInit ), m_Storage( (const char*)szInit, N - 1 ) {} + CKV3MemberNameWithStorage( const char* pszString, int nLen ): CKV3MemberName( pszString, nLen ), m_Storage( pszString, nLen ) {} + CKV3MemberNameWithStorage( uint32 nHash = 0, const char* pszString = StringFuncs::EmptyString(), int nLen = -1 ) : CKV3MemberName( nHash, pszString ), m_Storage( pszString, nLen ) {} + + const CBufferString &GetStorage() const { return m_Storage; } + +private: + CBufferStringN< 32 > m_Storage; +}; + +// Pulse thing +using CKV3MemberNameSet = KeyValues3; // Allocates with KV_TYPE_ARRAY. + template class CKeyValues3ClusterImpl; @@ -509,18 +526,23 @@ class KeyValues3 void SetToEmptyTable(); int GetMemberCount() const; - CKeyValues3Table *GetTableRaw(); - CKeyValues3Table *GetTableRaw() const { return const_cast(this)->GetTableRaw(); }; + CKeyValues3Array *GetArray(); + const CKeyValues3Array *GetArray() const { return const_cast(this)->GetArray(); }; + + CKeyValues3Table *GetTable(); + const CKeyValues3Table *GetTable() const { return const_cast(this)->GetTable(); }; KeyValues3* GetMember( KV3MemberId_t id ); const KeyValues3* GetMember( KV3MemberId_t id ) const { return const_cast(this)->GetMember( id ); } - const char* GetMemberName( KV3MemberId_t id ) const; - CKV3MemberName GetMemberNameEx( KV3MemberId_t id ) const; - CUtlStringToken GetMemberHash( KV3MemberId_t id ) const; + CKV3MemberName GetKV3MemberName( KV3MemberId_t id ) const; - KeyValues3* FindMember( const CKV3MemberName &name, KeyValues3* defaultValue = nullptr ); +protected: + KeyValues3* Internal_FindMember( const CKV3MemberName &name, KV3MemberId_t &next, KeyValues3* defaultValue = nullptr ); + +public: + KeyValues3* FindMember( const CKV3MemberName &name, KeyValues3* defaultValue = nullptr ) { KV3MemberId_t next = KV3_INVALID_MEMBER; return Internal_FindMember( name, next, defaultValue ); } const KeyValues3 *FindMember( const CKV3MemberName &name, KeyValues3 *defaultValue = nullptr ) const { return const_cast(this)->FindMember( name, defaultValue ); }; KeyValues3* FindOrCreateMember( const CKV3MemberName &name, bool *pCreated = nullptr ); @@ -797,10 +819,10 @@ class CKeyValues3Table MEMBER_FLAG_EXTERNAL_NAME = (1 << 0) }; - typedef CUtlStringToken Hash_t; - typedef KeyValues3* Member_t; - typedef const char* Name_t; - typedef uint8 Flags_t; + typedef KeyValues3LowercaseHash_t Hash_t; + typedef KeyValues3* Member_t; + typedef const char* Name_t; + typedef uint8 Flags_t; static const size_t DATA_SIZE = KV3_TABLE_MAX_FIXED_MEMBERS; static const size_t DATA_ALIGNMENT = KV3Helpers::PackAlignOf(); @@ -824,8 +846,9 @@ class CKeyValues3Table void EnableFastSearch(); void EnsureMemberCapacity( int num, bool force = false, bool dont_move = false ); + KV3MemberId_t Internal_FindMember( const CKV3MemberName &name, KV3MemberId_t &next ); + KV3MemberId_t FindMember( const CKV3MemberName &name ) { KV3MemberId_t next = KV3_INVALID_MEMBER; return Internal_FindMember( name, next ); } KV3MemberId_t FindMember( const KeyValues3* kv ) const; - KV3MemberId_t FindMember( const CKV3MemberName &name ); KV3MemberId_t CreateMember( KeyValues3 *parent, const CKV3MemberName &name, bool name_external = false ); void CopyFrom( KeyValues3 *parent, const CKeyValues3Table* src ); @@ -868,7 +891,8 @@ class CKeyValues3Table int m_nClusterElement; int m_nAllocatedChunks; - struct kv3tablefastsearch_t { + struct kv3tablefastsearch_t + { kv3tablefastsearch_t() : m_ignore( false ), m_ignores_counter( 0 ) {} ~kv3tablefastsearch_t() { Clear(); } diff --git a/public/tier1/utlhashtable.h b/public/tier1/utlhashtable.h index c2d686df3..8e78ec91b 100644 --- a/public/tier1/utlhashtable.h +++ b/public/tier1/utlhashtable.h @@ -265,6 +265,19 @@ class CUtlHashtable // 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); ::V_swap(m_nTableSize, other.m_nTableSize); } + // GetMemoryUsage returns all memory held by this class + // and its held classes. It does not include sizeof(*this). + size_t GetMemoryUsage() const + { + return m_table.AllocSize(); + } + + size_t GetReserveCount() const + { + return m_nTableSize; + } + + #if _DEBUG // Validate the integrity of the hashtable void DbgCheckIntegrity() const; @@ -495,7 +508,6 @@ int CUtlHashtable::DoInser return idx; } - // Key lookup. Can also return previous-in-chain if result is a chained slot. template template @@ -602,6 +614,7 @@ int CUtlHashtable::DoRemov unsigned int slotmask = m_nTableSize-1; handle_t previous = (handle_t) -1; int idx = (int) DoLookup( x, h, &previous ); + if (idx == -1) { return -1; diff --git a/public/tier1/utlstringtoken.h b/public/tier1/utlstringtoken.h index b06240b11..2eea2cbfc 100644 --- a/public/tier1/utlstringtoken.h +++ b/public/tier1/utlstringtoken.h @@ -14,42 +14,116 @@ #endif #include +#include +#include "bufferstring.h" #include "tier1/generichash.h" +#define DEBUG_STRINGTOKENS 0 #define STRINGTOKEN_MURMURHASH_SEED 0x31415926 -class CUtlString; +// Macros are intended to be used between CUtlStringToken (always lowercase) +#define MAKE_STRINGTOKEN(pstr) CUtlStringToken::Hash( (pstr), strlen(pstr), STRINGTOKEN_MURMURHASH_SEED ) +#define MAKE_STRINGTOKEN_UTL(containerName) CUtlStringToken::Hash( (containerName).Get(), (containerName).Length(), STRINGTOKEN_MURMURHASH_SEED ) + class IFormatOutputStream; class CFormatStringElement; -// AMNOTE: See VStringTokenSystem001 + +// See VStringTokenSystem001 // Interact with stringtokendatabase.txt PLATFORM_INTERFACE bool g_bUpdateStringTokenDatabase; PLATFORM_INTERFACE void RegisterStringToken( uint32 nHashCode, const char *pStart, const char *pEnd = NULL, bool bExtraAddToDatabase = true ); +#define TOLOWERU( c ) ( ( uint32 ) ( ( ( c >= 'A' ) && ( c <= 'Z' ) ) ? ( c | ( 1 << 5 ) ) : c ) ) class CUtlStringToken { public: - FORCEINLINE CUtlStringToken( uint32 nHashCode = 0 ) : m_nHashCode( nHashCode ) {} - FORCEINLINE CUtlStringToken( const char *str ) : m_nHashCode( 0 ) + static constexpr uint32 sm_nMagic = 0x5bd1e995; + static constexpr uint32 sm_nRotation = 24; + + template< bool CASEINSENSITIVE = true > + FORCEINLINE static uint32 Hash( const char *pString, int n, uint32 nSeed = STRINGTOKEN_MURMURHASH_SEED ) { - if(str && *str) + // They're not really 'magic', they just happen to work well. + + constexpr uint32 m = sm_nMagic; + constexpr uint32 r = sm_nRotation; + + // Initialize the hash to a 'random' value + + uint32 nLength = static_cast< uint32 >( n ); + + uint32 h = nSeed ^ nLength; + + // Mix 4 bytes at a time into the hash + + while ( nLength >= 4 ) { - m_nHashCode = MurmurHash2LowerCase( str, STRINGTOKEN_MURMURHASH_SEED ); - if(g_bUpdateStringTokenDatabase) - { - RegisterStringToken( m_nHashCode, str, 0, true ); - } + uint32 k = CASEINSENSITIVE ? ( TOLOWERU( pString[ 0 ] ) | ( TOLOWERU( pString[ 1 ] ) << 8 ) | ( TOLOWERU( pString[ 2 ] ) << 16 ) | ( TOLOWERU( pString[ 3 ] ) << 24 ) ) : LittleDWord( *(uint32 *)pString ); + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + pString += 4; + nLength -= 4; } + + // Handle the last few bytes of the input array + + switch ( nLength ) + { + case 3: h ^= ( CASEINSENSITIVE ? TOLOWERU( pString[ 2 ] ) : pString[ 2 ] ) << 16; [[fallthrough]]; + case 2: h ^= ( CASEINSENSITIVE ? TOLOWERU( pString[ 1 ] ) : pString[ 1 ] ) << 8; [[fallthrough]]; + case 1: h ^= ( CASEINSENSITIVE ? TOLOWERU( pString[ 0 ] ) : pString[ 0 ] ); + h *= m; + }; + + // Do a few final mixes of the hash to ensure the last few + // bytes are well-incorporated. + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; } - FORCEINLINE bool operator==( CUtlStringToken const &other ) const { return ( other.m_nHashCode == m_nHashCode ); } - FORCEINLINE bool operator!=( CUtlStringToken const &other ) const { return !operator==( other ); } - FORCEINLINE bool operator<( CUtlStringToken const &other ) const { return ( m_nHashCode < other.m_nHashCode ); } + CUtlStringToken( uint32 nHashCode = 0 ) : m_nHashCode( nHashCode ) {} + template < uintp N > constexpr CUtlStringToken( const char (&str)[N] ) : m_nHashCode( Make( str, N - 1 ) ) {} + CUtlStringToken( const char *pString, int nLen ) : m_nHashCode( Hash( pString, nLen ) ) {} + CUtlStringToken( const char *pString ) : CUtlStringToken( pString, strlen(pString) ) {} + CUtlStringToken( const CUtlString &str ) : CUtlStringToken( str.Get(), str.Length() ) {} + CUtlStringToken( const CBufferString &buffer ) : CUtlStringToken( buffer.Get(), buffer.Length() ) {} - FORCEINLINE bool IsValid() const { return m_nHashCode != 0; } - FORCEINLINE uint32 GetHashCode() const { return m_nHashCode; } - FORCEINLINE void SetHashCode( uint32 hash ) { m_nHashCode = hash; } + // operator== + // aka CUtlStringTokenHashMethod. + bool operator==( const uint32 nHash ) const { return m_nHashCode == nHash; } + bool operator==( const CUtlStringToken &other ) const { return operator==( other.GetHashCode() ); } + bool operator==( const char *pString ) const { return operator==( MAKE_STRINGTOKEN( pString ) ); } + bool operator==( const CUtlString &str ) const { return operator==( MAKE_STRINGTOKEN_UTL( str ) ); } + bool operator==( const CBufferString &buffer ) const { return operator==( MAKE_STRINGTOKEN_UTL( buffer ) ); } + + // operator!= + bool operator!=( const uint32 nHash ) const { return !operator==( nHash ); } + bool operator!=( const CUtlStringToken &other ) const { return !operator==( other ); } + bool operator!=( const char *pString ) const { return !operator==( pString ); } + bool operator!=( const CUtlString &str ) const { return !operator==( str ); } + bool operator!=( const CBufferString &buffer ) const { return !operator==( buffer ); } + + // opertator< + bool operator<( const uint32 nHash ) const { return ( m_nHashCode < nHash ); } + bool operator<( CUtlStringToken const &other ) const { return operator<( other.GetHashCode() ); } + bool operator<( const char *pString ) const { return operator<( MAKE_STRINGTOKEN( pString ) ); } + bool operator<( const CUtlString &str ) const { return !operator<( MAKE_STRINGTOKEN_UTL( str ) ); } + bool operator<( const CBufferString &buffer ) const { return !operator<( MAKE_STRINGTOKEN_UTL( buffer ) ); } + + /// access to the hash code for people who need to store thse as 32-bits, regardless of the + operator uint32() const { return m_nHashCode; } + uint32 GetHashCode() const { return m_nHashCode; } DLL_CLASS_IMPORT void FormatTo( IFormatOutputStream* pOutputStream, CFormatStringElement pElement ) const; DLL_CLASS_IMPORT static bool TrackTokenCreation( const char *s1, const char *s2 ); @@ -58,9 +132,65 @@ class CUtlStringToken uint32 m_nHashCode; }; -FORCEINLINE CUtlStringToken MakeStringToken( const char *str ) +// To compare into CUtlHash< Data, C, K > +class CUtlStringTokenHashMethod +{ +public: + CUtlStringTokenHashMethod( int ) {} + + bool operator()( const CUtlStringToken &nLHS, const CUtlStringToken &nRHS ) const { return nLHS == nRHS; } + static bool Compare( const CUtlStringToken &nLHS, const CUtlStringToken &nRHS ) { return nLHS == nRHS; } +}; + +FORCEINLINE bool TrackStringToken( uint32 nHash, const char *pString ) +{ + if ( g_bUpdateStringTokenDatabase ) + { + RegisterStringToken( nHash, pString ); + + return true; + } + + return false; +} + +template< bool CASEINSENSITIVE = true, bool TRACKCREATION = true > +FORCEINLINE uint32 MakeStringToken( const char *pString, int nLen ) +{ + uint32 nHash = CASEINSENSITIVE ? MurmurHash2LowerCase( pString, nLen, STRINGTOKEN_MURMURHASH_SEED ) : MurmurHash2( pString, nLen, STRINGTOKEN_MURMURHASH_SEED ); + + if constexpr ( TRACKCREATION ) + TrackStringToken( nHash, pString ); + + return nHash; +} + +template< bool CASEINSENSITIVE = true, bool TRACKCREATION = true > +FORCEINLINE uint32 MakeStringToken( const char *pString ) +{ + return MakeStringToken< CASEINSENSITIVE, TRACKCREATION >( pString, strlen(pString) ); +} + +template< bool CASEINSENSITIVE = true, uintp SIZE = 128 > +FORCEINLINE uint32 HashStringWithBuffer( const char *pString, int nLen = -1 ) +{ + CBufferStringN< SIZE > buffer( pString, nLen ); + + if constexpr ( CASEINSENSITIVE ) + buffer.ToLowerFast(); + + return CUtlStringToken::Hash< CASEINSENSITIVE >( buffer.Get(), buffer.Length() ); +} + +template< bool CASEINSENSITIVE = true, bool TRACKCREATION = true > +FORCEINLINE CUtlStringToken MakeStringToken2( const char *pString, int nLen = -1 ) { - return CUtlStringToken( str ); + CUtlStringToken nHashToken = HashStringWithBuffer< CASEINSENSITIVE >( pString, nLen ); + + if constexpr ( TRACKCREATION ) + TrackStringToken( nHashToken, pString ); + + return nHashToken; } #endif // UTLSTRINGTOKEN_H diff --git a/public/tier1/utlsymbol.h b/public/tier1/utlsymbol.h index 265e4dcb7..845fb39b4 100644 --- a/public/tier1/utlsymbol.h +++ b/public/tier1/utlsymbol.h @@ -21,7 +21,6 @@ #include "tier1/utlhashtable.h" #include "tier1/memblockallocator.h" - //----------------------------------------------------------------------------- // forward declarations //----------------------------------------------------------------------------- @@ -33,9 +32,15 @@ class CUtlSymbolTableMT; // This is a symbol, which is a easier way of dealing with strings. //----------------------------------------------------------------------------- typedef unsigned short UtlSymId_t; +typedef unsigned int UtlSymElm_t; #define UTL_INVAL_SYMBOL ((UtlSymId_t)~0) +#define FOR_EACH_SYMBOL( tableName, iter ) \ + for ( CUtlSymbol iter = 0; iter < (tableName).GetNumStrings(); iter++ ) +#define FOR_EACH_SYMBOL_BACK( tableName, iter ) \ + for ( CUtlSymbol iter = (tableName).GetNumStrings()-1; iter >= 0; iter-- ) + class CUtlSymbol { public: @@ -46,15 +51,32 @@ class CUtlSymbol // operator= CUtlSymbol& operator=( CUtlSymbol const& src ) { m_Id = src.m_Id; return *this; } - + + // operator++ + CUtlSymbol& operator++() { ++m_Id; return *this; } + CUtlSymbol operator++(int) { CUtlSymbol oldId = *this; ++m_Id; return oldId; } + + // operator-- + CUtlSymbol& operator--() { --m_Id; return *this; } + CUtlSymbol operator--(int) { CUtlSymbol oldId = *this; --m_Id; return oldId; } + // operator== bool operator==( CUtlSymbol const& src ) const { return m_Id == src.m_Id; } + static uint32 Hash( bool bInsensitive, const char *pString, int nLength ) + { + return bInsensitive ? MakeStringToken2< true >( pString, nLength ) + : MakeStringToken2< false >( pString, nLength ); + } + + UtlSymId_t GetId() const { return m_Id; } + // Is valid? - bool IsValid() const { return m_Id != UTL_INVAL_SYMBOL; } - + static UtlSymId_t Invalid() { return UTL_INVAL_SYMBOL; } + bool IsValid() const { return GetId() != Invalid(); } + // Gets at the symbol - operator UtlSymId_t () const { return m_Id; } + operator UtlSymId_t () const { return GetId(); } protected: CUtlSymbol( const char* pStr ); @@ -64,6 +86,7 @@ class CUtlSymbol UtlSymId_t m_Id; }; +CUtlSymbol CUtlSymbol_Make( const CUtlSymbolTable *pTable, const char *pString, int nLength, uint32 hash ); //----------------------------------------------------------------------------- // CUtlSymbolTable: @@ -77,7 +100,6 @@ class CUtlSymbol // two bytes of each string are decorated with a hash to speed up // comparisons. //----------------------------------------------------------------------------- - class CUtlSymbolTable { public: @@ -92,14 +114,17 @@ class CUtlSymbolTable // Finds the symbol for pString DLL_CLASS_IMPORT CUtlSymbol Find( const char* pString ) const; DLL_CLASS_IMPORT CUtlSymbol Find( const char* pString, int nLength ) const; - + // Look up the string associated with a particular symbol DLL_CLASS_IMPORT const char* String( CUtlSymbol id ) const; - void Remove( CUtlSymbol id ) - { - m_HashTable.Remove( id ); - } + uint32 Hash( const char *pString, int nLength ) const { return CUtlSymbol::Hash( IsInsensitive(), pString, nLength ); } + uint32 Hash( const char *pString ) const { return Hash( pString, strlen( pString ) ); } + uint32 Hash( CUtlSymbol id ) const { return Hash( (const char *)m_MemBlockAllocator.GetBlock( m_MemBlocks[ id ] ) ); } + + // Remove once symbol element. + // @Wend4r: The table is not designed for that. + void Remove( CUtlSymbol id ) { m_HashTable.Remove( id ); m_MemBlocks[ id ] = MEMBLOCKHANDLE_INVALID; } // Remove all symbols in the table. DLL_CLASS_IMPORT void RemoveAll(); @@ -115,12 +140,6 @@ class CUtlSymbolTable DLL_CLASS_IMPORT bool SaveToBuffer( CUtlBuffer& buff ) const; DLL_CLASS_IMPORT bool RestoreFromBuffer( CUtlBuffer& buff ); - int GetNumStrings( void ) const - { - return m_MemBlocks.Count(); - } - -protected: struct UtlSymTableAltKey { const CUtlSymbolTable* m_pTable; @@ -132,31 +151,113 @@ class CUtlSymbolTable { ptrdiff_t m_ownerOffset; - UtlSymTableHashFunctor(); - unsigned int operator()( UtlSymTableAltKey k ) const; - unsigned int operator()( int k ) const; + UtlSymTableHashFunctor() + { + const ptrdiff_t tableoffset = (uintp)(&((Hashtable_t*)1024)->GetHashRef()) - 1024; + const ptrdiff_t owneroffset = offsetof(CUtlSymbolTable, m_HashTable) + tableoffset; + m_ownerOffset = -owneroffset; + } + + unsigned int operator()( UtlSymTableAltKey k ) const + { + const CUtlSymbolTable* pTable = (const CUtlSymbolTable*)((uintp)this + m_ownerOffset); + + return pTable->Hash( k.m_pString ); + } + + unsigned int operator()( UtlSymElm_t k ) const + { + const CUtlSymbolTable* pTable = (const CUtlSymbolTable*)((uintp)this + m_ownerOffset); + + return pTable->Hash( k ); + } }; struct UtlSymTableEqualFunctor { ptrdiff_t m_ownerOffset; - UtlSymTableEqualFunctor(); - bool operator()( int a, int b ) const; - bool operator()( UtlSymTableAltKey a, int b ) const; - bool operator()( int a, UtlSymTableAltKey b ) const; + UtlSymTableEqualFunctor() + { + const ptrdiff_t tableoffset = (uintp)(&((Hashtable_t*)1024)->GetEqualRef()) - 1024; + const ptrdiff_t owneroffset = offsetof(CUtlSymbolTable, m_HashTable) + tableoffset; + m_ownerOffset = -owneroffset; + } + + bool operator()( UtlSymElm_t a, UtlSymElm_t b ) const + { + const CUtlSymbolTable* pTable = (const CUtlSymbolTable*)((uintp)this + m_ownerOffset); + + if ( pTable->IsInsensitive() ) + return V_stricmp( pTable->String( a ), pTable->String( b ) ) == 0; + else + return V_strcmp( pTable->String( a ), pTable->String( b ) ) == 0; + } + + bool operator()( UtlSymTableAltKey a, UtlSymElm_t b ) const + { + const char* pString = a.m_pTable->String( b ); + int nLength = ( int )strlen( pString ); + + if ( a.m_nLength != nLength ) + return false; + + if ( a.m_pTable->IsInsensitive() ) + return V_strnicmp( a.m_pString, pString, a.m_nLength ) == 0; + else + return V_strncmp( a.m_pString, pString, a.m_nLength ) == 0; + } + + bool operator()( UtlSymElm_t a, UtlSymTableAltKey b ) const + { + return operator()( b, a ); + } }; - typedef CUtlHashtable Hashtable_t; - typedef CUtlVector MemBlocksVec_t; + typedef CUtlHashtable Hashtable_t; + typedef CUtlVector MemBlocksVec_t; + + const Hashtable_t &GetHashtable() const + { + return m_HashTable; + } + + UtlSymElm_t GetNumStrings( void ) const + { + return m_MemBlocks.Count(); + } + + bool IsInsensitive() const + { + return m_bInsensitive; + } +protected: + // By "UtlSymId_t" elements. Hashtable_t m_HashTable; + + // By "const char *" elements. MemBlocksVec_t m_MemBlocks; CUtlMemoryBlockAllocator m_MemBlockAllocator; bool m_bInsensitive; }; +inline CUtlSymbol CUtlSymbol_Make( const CUtlSymbolTable *pTable, const char *pString, int nLength, unsigned int hash ) +{ + auto &hashtable = pTable->GetHashtable(); + + CUtlSymbolTable::UtlSymTableAltKey key; + + key.m_pTable = pTable; + key.m_pString = pString; + key.m_nLength = nLength; + + UtlHashHandle_t h = hashtable.Find( key, hash ); + + return h == hashtable.InvalidHandle() ? UTL_INVAL_SYMBOL : hashtable[ h ]; +} + class CUtlSymbolTableMT : public CUtlSymbolTable { public: diff --git a/public/tier1/utlsymbollarge.h b/public/tier1/utlsymbollarge.h index 0e839bb4e..01f5e9053 100644 --- a/public/tier1/utlsymbollarge.h +++ b/public/tier1/utlsymbollarge.h @@ -33,6 +33,11 @@ typedef unsigned int UtlSymLargeId_t; #define UTL_INVAL_SYMBOL_LARGE ((UtlSymLargeId_t)~0) +#define FOR_EACH_SYMBOL_LARGE( table, iter ) \ + for ( UtlSymLargeId_t iter = 0; iter < (table).GetNumStrings(); iter++ ) +#define FOR_EACH_SYMBOL_LARGE_BACK( table, iter ) \ + for ( UtlSymLargeId_t iter = (table).GetNumStrings()-1; iter >= 0; iter-- ) + class CUtlSymbolLarge { public: @@ -65,6 +70,12 @@ class CUtlSymbolLarge return ( intp )m_pString < ( intp )src.m_pString; } + template< bool CASEINSENSITIVE = true > + static uint32 Hash( const char *pString, int nLength = -1 ) + { + return MakeStringToken2< CASEINSENSITIVE >( pString, nLength ); + } + inline const char* String() const { if ( !m_pString ) @@ -84,15 +95,10 @@ class CUtlSymbolLarge const char* m_pString; }; -inline uint32 CUtlSymbolLarge_Hash( bool CASEINSENSITIVE, const char *pString, int len ) -{ - return ( CASEINSENSITIVE ? MurmurHash2LowerCase( pString, len, 0x31415926 ) : MurmurHash2( pString, len, 0x31415926 ) ); -} - typedef uint32 LargeSymbolTableHashDecoration_t; // The structure consists of the hash immediately followed by the string data -struct CUtlSymbolTableLargeBaseTreeEntry_t +struct alignas(8) CUtlSymbolTableLargeBaseTreeEntry_t { LargeSymbolTableHashDecoration_t m_Hash; // Variable length string data @@ -112,8 +118,8 @@ struct CUtlSymbolTableLargeBaseTreeEntry_t { return CUtlSymbolLarge( String() ); } - - LargeSymbolTableHashDecoration_t HashValue() const + + LargeSymbolTableHashDecoration_t Hash() const { return m_Hash; } @@ -143,6 +149,11 @@ class CUtlSymbolTableLargeBase CUtlSymbolLarge Find( const char* pString ) const; CUtlSymbolLarge Find( const char* pString, int nLength ) const; + const char* String( UtlSymLargeId_t id ) const; + unsigned int Hash( UtlSymLargeId_t id ) const; + + int GetNumStrings() const { return m_MemBlocks.Count(); }; + // Remove all symbols in the table. void RemoveAll(); void Purge(); @@ -151,9 +162,6 @@ class CUtlSymbolTableLargeBase CUtlSymbolLarge AddString( unsigned int hash, const char* pString, int nLength, bool* created ); CUtlSymbolLarge Find( unsigned int hash, const char* pString, int nLength ) const; - const char* String( UtlSymLargeId_t id ) const; - unsigned int HashValue( UtlSymLargeId_t id ) const; - struct UtlSymTableLargeAltKey { const CUtlSymbolTableLargeBase* m_pTable; @@ -174,14 +182,14 @@ class CUtlSymbolTableLargeBase unsigned int operator()( UtlSymTableLargeAltKey k ) const { - return CUtlSymbolLarge_Hash( CASEINSENSITIVE, k.m_pString, k.m_nLength ); + return CUtlSymbolLarge::Hash< CASEINSENSITIVE >( k.m_pString, k.m_nLength ); } unsigned int operator()( UtlSymLargeId_t k ) const { const CUtlSymbolTableLargeBase* pTable = (const CUtlSymbolTableLargeBase*)((uintp)this + m_ownerOffset); - return pTable->HashValue( k ); + return pTable->Hash( k ); } }; @@ -200,10 +208,10 @@ class CUtlSymbolTableLargeBase { const CUtlSymbolTableLargeBase* pTable = (const CUtlSymbolTableLargeBase*)((uintp)this + m_ownerOffset); - if ( !CASEINSENSITIVE ) - return strcmp( pTable->String( a ), pTable->String( b ) ) == 0; + if ( CASEINSENSITIVE ) + return V_stricmp( pTable->String( a ), pTable->String( b ) ) == 0; else - return V_stricmp_fast( pTable->String( a ), pTable->String( b ) ) == 0; + return V_strcmp( pTable->String( a ), pTable->String( b ) ) == 0; } bool operator()( UtlSymTableLargeAltKey a, UtlSymLargeId_t b ) const @@ -214,10 +222,10 @@ class CUtlSymbolTableLargeBase if ( a.m_nLength != nLength ) return false; - if ( !CASEINSENSITIVE ) - return strncmp( a.m_pString, pString, a.m_nLength ) == 0; + if ( CASEINSENSITIVE ) + return V_strnicmp( a.m_pString, pString, a.m_nLength ) == 0; else - return _V_strnicmp_fast( a.m_pString, pString, a.m_nLength ) == 0; + return V_strncmp( a.m_pString, pString, a.m_nLength ) == 0; } bool operator()( UtlSymLargeId_t a, UtlSymTableLargeAltKey b ) const @@ -297,11 +305,11 @@ inline const char* CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_T } template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE > -inline unsigned int CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::HashValue( UtlSymLargeId_t id ) const +inline unsigned int CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::Hash( UtlSymLargeId_t id ) const { CUtlSymbolTableLargeBaseTreeEntry_t *entry = (CUtlSymbolTableLargeBaseTreeEntry_t *)m_MemBlockAllocator.GetBlock( m_MemBlocks[ id ] - sizeof( LargeSymbolTableHashDecoration_t ) ); - return entry->HashValue(); + return entry->Hash(); } template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE > @@ -311,7 +319,7 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT if ( pString && nLength > 0 && *pString ) { - unsigned int hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, nLength ); + unsigned int hash = CUtlSymbolLarge::Hash< CASEINSENSITIVE >( pString, nLength ); AUTO_LOCK( m_Mutex ); @@ -337,7 +345,7 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT if ( pString && nLength > 0 && *pString ) { - unsigned int hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, nLength ); + unsigned int hash = CUtlSymbolLarge::Hash< CASEINSENSITIVE >( pString, nLength ); AUTO_LOCK( m_Mutex ); diff --git a/tier1/keyvalues3.cpp b/tier1/keyvalues3.cpp index 49788cf21..c86d67224 100644 --- a/tier1/keyvalues3.cpp +++ b/tier1/keyvalues3.cpp @@ -533,32 +533,32 @@ void KeyValues3::SetColor( const Color &color ) int KeyValues3::GetArrayElementCount() const { - if ( GetType() != KV3_TYPE_ARRAY ) + const CKeyValues3Array *pArray = GetArray(); + + if ( !pArray ) return 0; - if ( GetTypeEx() == KV3_TYPEEX_ARRAY ) - return m_Data.m_pArray->Count(); - else - return m_nNumArrayElements; + return GetTypeEx() == KV3_TYPEEX_ARRAY ? pArray->Count() : m_nNumArrayElements; } KeyValues3** KeyValues3::GetArrayBase() { - if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) + CKeyValues3Array *pArray = GetArray(); + + if ( !pArray ) return nullptr; - return m_Data.m_pArray->Base(); + return pArray->Base(); } KeyValues3* KeyValues3::GetArrayElement( int elem ) { - if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) - return nullptr; + CKeyValues3Array *pArray = GetArray(); - if ( elem < 0 || elem >= m_Data.m_pArray->Count() ) + if ( !pArray || elem < 0 || elem >= pArray->Count() ) return nullptr; - return m_Data.m_pArray->Element( elem ); + return pArray->Element( elem ); } KeyValues3* KeyValues3::ArrayInsertElementBefore( int elem ) @@ -566,7 +566,11 @@ KeyValues3* KeyValues3::ArrayInsertElementBefore( int elem ) if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY ); - return *m_Data.m_pArray->InsertMultipleBefore( this, elem, 1 ); + CKeyValues3Array *pArray = GetArray(); + + Assert( pArray ); + + return *pArray->InsertMultipleBefore( this, elem, 1 ); } KeyValues3* KeyValues3::ArrayAddElementToTail() @@ -574,21 +578,27 @@ KeyValues3* KeyValues3::ArrayAddElementToTail() if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY ); - return *m_Data.m_pArray->InsertMultipleBefore( this, m_Data.m_pArray->Count(), 1 ); + CKeyValues3Array *pArray = GetArray(); + + Assert( pArray ); + + return *pArray->InsertMultipleBefore( this, pArray->Count(), 1 ); } void KeyValues3::ArraySwapItems( int idx1, int idx2 ) { - if(GetTypeEx() != KV3_TYPEEX_ARRAY) + CKeyValues3Array *pArray = GetArray(); + + if ( !pArray ) return; - if(idx1 < 0 || idx1 >= m_Data.m_pArray->Count()) + if(idx1 < 0 || idx1 >= pArray->Count()) return; - if(idx2 < 0 || idx2 >= m_Data.m_pArray->Count()) + if(idx2 < 0 || idx2 >= pArray->Count()) return; - auto base = GetArrayBase(); + auto base = pArray->Base(); auto temp = base[idx1]; base[idx1] = base[idx2]; @@ -600,15 +610,20 @@ void KeyValues3::SetArrayElementCount( int count, KV3TypeEx_t type, KV3SubType_t if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY ); - m_Data.m_pArray->SetCount( this, count, type, subtype ); + CKeyValues3Array *pArray = GetArray(); + + Assert( pArray ); + pArray->SetCount( this, count, type, subtype ); } void KeyValues3::ArrayRemoveElements( int elem, int num ) { - if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) + CKeyValues3Array *pArray = GetArray(); + + if ( !pArray ) return; - m_Data.m_pArray->RemoveMultiple( this, elem, num ); + pArray->RemoveMultiple( this, elem, num ); } void KeyValues3::NormalizeArray() @@ -774,13 +789,20 @@ bool KeyValues3::ReadArrayFloat32( int dest_size, float32* data ) const int KeyValues3::GetMemberCount() const { - if ( GetType() != KV3_TYPE_TABLE ) - return 0; - - return m_Data.m_pTable->GetMemberCount(); + const CKeyValues3Table *pTable = GetTable(); + + return pTable ? pTable->GetMemberCount() : 0; } -CKeyValues3Table *KeyValues3::GetTableRaw() +CKeyValues3Array *KeyValues3::GetArray() +{ + if(GetType() != KV3_TYPE_ARRAY) + return nullptr; + + return m_Data.m_pArray; +} + +CKeyValues3Table *KeyValues3::GetTable() { if(GetType() != KV3_TYPE_TABLE) return nullptr; @@ -790,47 +812,57 @@ CKeyValues3Table *KeyValues3::GetTableRaw() KeyValues3* KeyValues3::GetMember( KV3MemberId_t id ) { - if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_Data.m_pTable->GetMemberCount() ) + CKeyValues3Table *pTable = GetTable(); + + if ( !pTable || id < 0 || id >= pTable->GetMemberCount() ) return nullptr; - return m_Data.m_pTable->GetMember( id ); + return pTable->GetMember( id ); } const char* KeyValues3::GetMemberName( KV3MemberId_t id ) const { - if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_Data.m_pTable->GetMemberCount() ) + const CKeyValues3Table *pTable = GetTable(); + + if ( !pTable || id < 0 || id >= pTable->GetMemberCount() ) return nullptr; - return m_Data.m_pTable->GetMemberName( id ); + return pTable->GetMemberName( id ); } -CKV3MemberName KeyValues3::GetMemberNameEx( KV3MemberId_t id ) const +CKV3MemberName KeyValues3::GetKV3MemberName( KV3MemberId_t id ) const { - if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_Data.m_pTable->GetMemberCount() ) + const CKeyValues3Table *pTable = GetTable(); + + if ( !pTable || id < 0 || id >= pTable->GetMemberCount() ) return CKV3MemberName(); - return CKV3MemberName( m_Data.m_pTable->GetMemberHash( id ), m_Data.m_pTable->GetMemberName( id ) ); + return CKV3MemberName( pTable->GetMemberHash( id ), pTable->GetMemberName( id ) ); } CUtlStringToken KeyValues3::GetMemberHash( KV3MemberId_t id ) const { - if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_Data.m_pTable->GetMemberCount() ) + const CKeyValues3Table *pTable = GetTable(); + + if ( !pTable || id < 0 || id >= pTable->GetMemberCount() ) return CUtlStringToken(); - return m_Data.m_pTable->GetMemberHash( id ); + return pTable->GetMemberHash( id ); } -KeyValues3* KeyValues3::FindMember( const CKV3MemberName &name, KeyValues3* defaultValue ) +KeyValues3* KeyValues3::Internal_FindMember( const CKV3MemberName &name, KV3MemberId_t &next, KeyValues3* defaultValue ) { - if ( GetType() != KV3_TYPE_TABLE ) + CKeyValues3Table *pTable = GetTable(); + + if ( !pTable ) return defaultValue; - KV3MemberId_t id = m_Data.m_pTable->FindMember( name ); + KV3MemberId_t id = pTable->Internal_FindMember( name, next ); if ( id == KV3_INVALID_MEMBER ) return defaultValue; - return m_Data.m_pTable->GetMember( id ); + return pTable->GetMember( id ); } KeyValues3* KeyValues3::FindOrCreateMember( const CKV3MemberName &name, bool *pCreated ) @@ -838,14 +870,18 @@ KeyValues3* KeyValues3::FindOrCreateMember( const CKV3MemberName &name, bool *pC if ( GetType() != KV3_TYPE_TABLE ) PrepareForType( KV3_TYPEEX_TABLE, KV3_SUBTYPE_TABLE ); - KV3MemberId_t id = m_Data.m_pTable->FindMember( name ); + CKeyValues3Table *pTable = GetTable(); + + Assert( pTable ); + + KV3MemberId_t id = pTable->FindMember( name ); if ( id == KV3_INVALID_MEMBER ) { if ( pCreated ) *pCreated = true; - id = m_Data.m_pTable->CreateMember( this, name ); + id = pTable->CreateMember( this, name ); } else { @@ -853,51 +889,55 @@ KeyValues3* KeyValues3::FindOrCreateMember( const CKV3MemberName &name, bool *pC *pCreated = false; } - return m_Data.m_pTable->GetMember( id ); + return pTable->GetMember( id ); } void KeyValues3::SetToEmptyTable() { PrepareForType( KV3_TYPEEX_TABLE, KV3_SUBTYPE_TABLE ); - m_Data.m_pTable->RemoveAll( this ); + GetTable()->RemoveAll( this ); } bool KeyValues3::RemoveMember( KV3MemberId_t id ) { - if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_Data.m_pTable->GetMemberCount() ) + if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= GetTable()->GetMemberCount() ) return false; - m_Data.m_pTable->RemoveMember( this, id ); + GetTable()->RemoveMember( this, id ); return true; } bool KeyValues3::RemoveMember( const KeyValues3* kv ) { - if ( GetType() != KV3_TYPE_TABLE ) + CKeyValues3Table *pTable = GetTable(); + + if ( !pTable ) return false; - KV3MemberId_t id = m_Data.m_pTable->FindMember( kv ); + KV3MemberId_t id = GetTable()->FindMember( kv ); if ( id == KV3_INVALID_MEMBER ) return false; - m_Data.m_pTable->RemoveMember( this, id ); + pTable->RemoveMember( this, id ); return true; } bool KeyValues3::RemoveMember( const CKV3MemberName &name ) { - if ( GetType() != KV3_TYPE_TABLE ) + CKeyValues3Table *pTable = GetTable(); + + if ( !pTable ) return false; - KV3MemberId_t id = m_Data.m_pTable->FindMember( name ); + KV3MemberId_t id = pTable->FindMember( name ); if ( id == KV3_INVALID_MEMBER ) return false; - m_Data.m_pTable->RemoveMember( this, id ); + pTable->RemoveMember( this, id ); return true; } @@ -1267,7 +1307,7 @@ void KeyValues3::CopyFrom( const KeyValues3* pSrc ) case KV3_TYPE_TABLE: { SetToEmptyTable(); - m_Data.m_pTable->CopyFrom( this, pSrc->m_Data.m_pTable ); + GetTable()->CopyFrom( this, pSrc->GetTable() ); break; } default: @@ -1573,7 +1613,7 @@ void CKeyValues3Table::EnableFastSearch() for ( int i = 0; i < m_nCount; ++i ) { - m_pFastSearch->m_member_ids.Insert( pHashes[i].GetHashCode(), i ); + m_pFastSearch->m_member_ids.Insert( pHashes[i], i ); } m_pFastSearch->m_ignore = false; @@ -1622,20 +1662,7 @@ void CKeyValues3Table::EnsureMemberCapacity( int count, bool force, bool dont_mo m_bIsDynamicallySized = true; } -KV3MemberId_t CKeyValues3Table::FindMember( const KeyValues3* kv ) const -{ - const Member_t* pMembers = MembersBase(); - - for ( int i = 0; i < m_nCount; ++i ) - { - if ( pMembers[i] == kv ) - return i; - } - - return KV3_INVALID_MEMBER; -} - -KV3MemberId_t CKeyValues3Table::FindMember( const CKV3MemberName &name ) +KV3MemberId_t CKeyValues3Table::Internal_FindMember( const CKV3MemberName &name, KV3MemberId_t &next ) { bool bFastSearch = false; @@ -1650,32 +1677,49 @@ KV3MemberId_t CKeyValues3Table::FindMember( const CKV3MemberName &name ) } } else - { bFastSearch = true; - } } if ( bFastSearch ) { - UtlHashHandle_t h = m_pFastSearch->m_member_ids.Find( name.GetHashCode() ); + UtlHashHandle_t h = m_pFastSearch->m_member_ids.Find( name ); if ( h != m_pFastSearch->m_member_ids.InvalidHandle() ) - return m_pFastSearch->m_member_ids[ h ]; + { + KV3MemberId_t res = m_pFastSearch->m_member_ids[ h ]; + + next = res + 1; + + return res; + } } else { const Hash_t* pHashes = HashesBase(); - for ( int i = 0; i < m_nCount; ++i ) - { - if ( pHashes[i] == name.GetHashCode() ) + for ( KV3MemberId_t i = 0; i < m_nCount; ++i ) + if ( pHashes[i] == name ) + { + next = i + 1; + return i; - } + } } return KV3_INVALID_MEMBER; } +KV3MemberId_t CKeyValues3Table::FindMember( const KeyValues3* kv ) const +{ + const Member_t* pMembers = MembersBase(); + + for ( int i = 0; i < m_nCount; ++i ) + if ( pMembers[i] == kv ) + return i; + + return KV3_INVALID_MEMBER; +} + KV3MemberId_t CKeyValues3Table::CreateMember( KeyValues3 *parent, const CKV3MemberName &name, bool name_external ) { if ( GetMemberCount() >= 128 && !m_pFastSearch ) @@ -2014,4 +2058,4 @@ void CKeyValues3Context::FreeKV( KeyValues3* kv ) // Free( kv, &m_KV3BaseCluster, m_pKV3FreeCluster ); } -#include "tier0/memdbgoff.h" \ No newline at end of file +#include "tier0/memdbgoff.h" From bcb806983ad5b47d2f8dc58894b7cc02b70a9a4e Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sun, 9 Mar 2025 07:48:52 +0300 Subject: [PATCH 05/30] Add `CCommandBuffer::SplitCommands` method --- public/tier1/CommandBuffer.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/tier1/CommandBuffer.h b/public/tier1/CommandBuffer.h index 0a3c4433d..5285f4058 100644 --- a/public/tier1/CommandBuffer.h +++ b/public/tier1/CommandBuffer.h @@ -69,6 +69,10 @@ class CCommandBuffer // Indicates how long to delay when encoutering a 'wait' command void SetWaitDelayTime( int nTickDelay ); + // Splits cfg-like commands into compartmentalizes. + // nLength can be -1 + DLL_CLASS_IMPORT void SplitCommands( const char *pText, int nLength, CUtlVector< CUtlString > &outString ); + // 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, From c4e277d73a96068f4fd774d64104f248ae84a0ff Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sun, 9 Mar 2025 10:00:45 +0300 Subject: [PATCH 06/30] Locate `CKeyValues3Table::m_bHasInvalidMemberNames` field --- public/tier1/CommandBuffer.h | 2 +- public/tier1/keyvalues3.h | 8 +++++++- tier1/keyvalues3.cpp | 30 ++++++++++++++++++++++++++---- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/public/tier1/CommandBuffer.h b/public/tier1/CommandBuffer.h index 5285f4058..529a4799b 100644 --- a/public/tier1/CommandBuffer.h +++ b/public/tier1/CommandBuffer.h @@ -69,7 +69,7 @@ class CCommandBuffer // Indicates how long to delay when encoutering a 'wait' command void SetWaitDelayTime( int nTickDelay ); - // Splits cfg-like commands into compartmentalizes. + // Compartmentalizes cfg-like commands. // nLength can be -1 DLL_CLASS_IMPORT void SplitCommands( const char *pText, int nLength, CUtlVector< CUtlString > &outString ); diff --git a/public/tier1/keyvalues3.h b/public/tier1/keyvalues3.h index 698c66a61..13c4776c8 100644 --- a/public/tier1/keyvalues3.h +++ b/public/tier1/keyvalues3.h @@ -434,6 +434,9 @@ class KeyValues3 KV3TypeEx_t GetTypeEx() const { return ( KV3TypeEx_t )m_TypeEx; } KV3SubType_t GetSubType() const { return ( KV3SubType_t )m_SubType; } + bool HasInvalidMemberNames() const; + void SetHasInvalidMemberNames( bool bValue = true ); + const char* GetTypeAsString() const; const char* GetSubTypeAsString() const; @@ -851,6 +854,9 @@ class CKeyValues3Table KV3MemberId_t FindMember( const KeyValues3* kv ) const; KV3MemberId_t CreateMember( KeyValues3 *parent, const CKV3MemberName &name, bool name_external = false ); + bool HasInvalidMemberNames() const { return m_bHasInvalidMemberNames; } + void SetHasInvalidMemberNames( bool bValue = true ) { m_bHasInvalidMemberNames = bValue; } + void CopyFrom( KeyValues3 *parent, const CKeyValues3Table* src ); void RemoveMember( KeyValues3 *parent, KV3MemberId_t id ); void RemoveAll( KeyValues3 *parent, int new_size = 0 ); @@ -916,7 +922,7 @@ class CKeyValues3Table uint8 m_nInitialSize; bool m_bIsDynamicallySized; - bool m_unk001; + bool m_bHasInvalidMemberNames; bool m_unk002; union diff --git a/tier1/keyvalues3.cpp b/tier1/keyvalues3.cpp index c86d67224..b2efd38e2 100644 --- a/tier1/keyvalues3.cpp +++ b/tier1/keyvalues3.cpp @@ -900,10 +900,12 @@ void KeyValues3::SetToEmptyTable() bool KeyValues3::RemoveMember( KV3MemberId_t id ) { - if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= GetTable()->GetMemberCount() ) + CKeyValues3Table *pTable = GetTable(); + + if ( !pTable || id < 0 || id >= pTable->GetMemberCount() ) return false; - GetTable()->RemoveMember( this, id ); + pTable->RemoveMember( this, id ); return true; } @@ -915,7 +917,7 @@ bool KeyValues3::RemoveMember( const KeyValues3* kv ) if ( !pTable ) return false; - KV3MemberId_t id = GetTable()->FindMember( kv ); + KV3MemberId_t id = pTable->FindMember( kv ); if ( id == KV3_INVALID_MEMBER ) return false; @@ -942,6 +944,26 @@ bool KeyValues3::RemoveMember( const CKV3MemberName &name ) return true; } +bool KeyValues3::HasInvalidMemberNames() const +{ + const CKeyValues3Table *pTable = GetTable(); + + if ( !pTable ) + return false; + + return pTable->HasInvalidMemberNames(); +} + +void KeyValues3::SetHasInvalidMemberNames( bool bValue ) +{ + CKeyValues3Table *pTable = GetTable(); + + if ( !pTable ) + return; + + pTable->SetHasInvalidMemberNames( bValue ); +} + const char* KeyValues3::GetTypeAsString() const { static const char* s_Types[] = @@ -1557,7 +1579,7 @@ CKeyValues3Table::CKeyValues3Table( int cluster_elem, int alloc_size ) : m_nCount( 0 ), m_nInitialSize( MIN( alloc_size, 255 ) ), m_bIsDynamicallySized( false ), - m_unk001( false ), + m_bHasInvalidMemberNames( false ), m_unk002( false ), m_pDynamicBuffer( nullptr ) { From a4982c5804d8e1ef26be9fa5f7fedfd81b6cac40 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sun, 9 Mar 2025 11:38:09 +0300 Subject: [PATCH 07/30] Add `KeyValues3::RenameMember` method Update `CUtlSymbolLarge` container --- public/tier1/keyvalues3.h | 13 +++-- public/tier1/utlsymbollarge.h | 58 +++++++--------------- tier1/keyvalues3.cpp | 91 ++++++++++++++++++++++++----------- 3 files changed, 90 insertions(+), 72 deletions(-) diff --git a/public/tier1/keyvalues3.h b/public/tier1/keyvalues3.h index 13c4776c8..e8ddfde76 100644 --- a/public/tier1/keyvalues3.h +++ b/public/tier1/keyvalues3.h @@ -375,6 +375,7 @@ class CKV3MemberName return CKV3MemberName( pszInit, nLen ); } + bool IsEmpty() const { return !m_pszString || !m_pszString[0]; } const char* GetString() const { return m_pszString; } private: @@ -538,7 +539,7 @@ class KeyValues3 KeyValues3* GetMember( KV3MemberId_t id ); const KeyValues3* GetMember( KV3MemberId_t id ) const { return const_cast(this)->GetMember( id ); } const char* GetMemberName( KV3MemberId_t id ) const; - CUtlStringToken GetMemberHash( KV3MemberId_t id ) const; + KeyValues3LowercaseHash_t GetMemberHash( KV3MemberId_t id ) const; CKV3MemberName GetKV3MemberName( KV3MemberId_t id ) const; protected: @@ -548,7 +549,7 @@ class KeyValues3 KeyValues3* FindMember( const CKV3MemberName &name, KeyValues3* defaultValue = nullptr ) { KV3MemberId_t next = KV3_INVALID_MEMBER; return Internal_FindMember( name, next, defaultValue ); } const KeyValues3 *FindMember( const CKV3MemberName &name, KeyValues3 *defaultValue = nullptr ) const { return const_cast(this)->FindMember( name, defaultValue ); }; KeyValues3* FindOrCreateMember( const CKV3MemberName &name, bool *pCreated = nullptr ); - + KeyValues3* RenameMember( const CKV3MemberName &name, const CKV3MemberName &newName ); bool RemoveMember( KV3MemberId_t id ); bool RemoveMember( const KeyValues3* kv ); bool RemoveMember( const CKV3MemberName &name ); @@ -836,6 +837,9 @@ class CKeyValues3Table int GetClusterElement() const { return m_nClusterElement; } void SetClusterElement( int element ) { m_nClusterElement = element; } + bool HasInvalidMemberNames() const { return m_bHasInvalidMemberNames; } + void SetHasInvalidMemberNames( bool bValue = true ) { m_bHasInvalidMemberNames = bValue; } + CKeyValues3TableCluster* GetCluster() const; CKeyValues3Context* GetContext() const; @@ -854,10 +858,9 @@ class CKeyValues3Table KV3MemberId_t FindMember( const KeyValues3* kv ) const; KV3MemberId_t CreateMember( KeyValues3 *parent, const CKV3MemberName &name, bool name_external = false ); - bool HasInvalidMemberNames() const { return m_bHasInvalidMemberNames; } - void SetHasInvalidMemberNames( bool bValue = true ) { m_bHasInvalidMemberNames = bValue; } - void CopyFrom( KeyValues3 *parent, const CKeyValues3Table* src ); + + void RenameMember( KeyValues3 *parent, KV3MemberId_t id, const CKV3MemberName &newName ); void RemoveMember( KeyValues3 *parent, KV3MemberId_t id ); void RemoveAll( KeyValues3 *parent, int new_size = 0 ); diff --git a/public/tier1/utlsymbollarge.h b/public/tier1/utlsymbollarge.h index 01f5e9053..eb2091de8 100644 --- a/public/tier1/utlsymbollarge.h +++ b/public/tier1/utlsymbollarge.h @@ -31,7 +31,7 @@ typedef unsigned int UtlSymLargeId_t; -#define UTL_INVAL_SYMBOL_LARGE ((UtlSymLargeId_t)~0) +#define UTL_INVAL_SYMBOL_LARGE ((UtlSymLargeId_t)~0) #define FOR_EACH_SYMBOL_LARGE( table, iter ) \ for ( UtlSymLargeId_t iter = 0; iter < (table).GetNumStrings(); iter++ ) @@ -42,57 +42,35 @@ class CUtlSymbolLarge { public: // constructor, destructor - CUtlSymbolLarge() - { - m_pString = NULL; - } - - CUtlSymbolLarge( const char* pString ) - { - m_pString = pString; - } + CUtlSymbolLarge( UtlSymLargeId_t id = UTL_INVAL_SYMBOL_LARGE ) : u( id ) {} + CUtlSymbolLarge( const char* pString ) : u( pString ) {}; // operator== - bool operator==( CUtlSymbolLarge const& src ) const - { - return m_pString == src.m_pString; - } + bool operator==( CUtlSymbolLarge const& src ) const { return u.m_Id == src.u.m_Id; } + bool operator==( const char* pString ) const = delete; // disallow since we don't know if the table this is from was case sensitive or not... maybe we don't care // operator!= - bool operator!=( CUtlSymbolLarge const& src ) const - { - return m_pString != src.m_pString; - } + bool operator!=( CUtlSymbolLarge const& src ) const { return u.m_Id != src.u.m_Id; } // operator< - bool operator<( CUtlSymbolLarge const& src ) const - { - return ( intp )m_pString < ( intp )src.m_pString; - } + bool operator<( CUtlSymbolLarge const& src ) const { return u.m_Id < src.u.m_Id; } template< bool CASEINSENSITIVE = true > - static uint32 Hash( const char *pString, int nLength = -1 ) - { - return MakeStringToken2< CASEINSENSITIVE >( pString, nLength ); - } + static uint32 Hash( const char *pString, int nLength = -1 ) { return MakeStringToken2< CASEINSENSITIVE >( pString, nLength ); } - inline const char* String() const - { - if ( !m_pString ) - return ""; - return m_pString; - } - - inline bool IsValid() const - { - return m_pString != NULL; - } + bool IsValid() const { return u.m_Id != UTL_INVAL_SYMBOL_LARGE; } + UtlSymLargeId_t GetId() { return u.m_Id; }; + const char* String() const { return IsValid() ? u.m_pAsString : ""; } private: - // Disallowed - bool operator==( const char* pString ) const; // disallow since we don't know if the table this is from was case sensitive or not... maybe we don't care + union Data_t + { + Data_t( UtlSymLargeId_t id ) : m_Id( id ) {} + Data_t( const char *pString ) : m_pAsString( pString ) {} - const char* m_pString; + UtlSymLargeId_t m_Id; + const char *m_pAsString; + } u; }; typedef uint32 LargeSymbolTableHashDecoration_t; diff --git a/tier1/keyvalues3.cpp b/tier1/keyvalues3.cpp index b2efd38e2..cc45bbe88 100644 --- a/tier1/keyvalues3.cpp +++ b/tier1/keyvalues3.cpp @@ -208,10 +208,7 @@ KeyValues3 *KeyValues3::AllocMember( KV3TypeEx_t type, KV3SubType_t subtype ) { auto context = GetContext(); - if(context) - return context->AllocKV( type, subtype ); - else - return new KeyValues3( type, subtype ); + return context ? context->AllocKV( type, subtype ) : new KeyValues3( type, subtype ); } void KeyValues3::FreeMember( KeyValues3 *member ) @@ -371,20 +368,14 @@ void KeyValues3::PrepareForType( KV3TypeEx_t type, KV3SubType_t subtype ) CKeyValues3Cluster* KeyValues3::GetCluster() const { - if ( m_bContextIndependent ) - return nullptr; - - return GET_OUTER( CKeyValues3Cluster, m_Values[ m_nClusterElement ] ); + return m_bContextIndependent ? nullptr : GET_OUTER( CKeyValues3Cluster, m_Values[ m_nClusterElement ] ); } CKeyValues3Context* KeyValues3::GetContext() const { CKeyValues3Cluster* cluster = GetCluster(); - if ( cluster ) - return cluster->GetContext(); - else - return nullptr; + return cluster ? cluster->GetContext() : nullptr; } KV3MetaData_t* KeyValues3::GetMetaData( CKeyValues3Context** ppCtx ) const @@ -787,6 +778,12 @@ bool KeyValues3::ReadArrayFloat32( int dest_size, float32* data ) const return ( src_size == dest_size ); } +void KeyValues3::SetToEmptyTable() +{ + PrepareForType( KV3_TYPEEX_TABLE, KV3_SUBTYPE_TABLE ); + GetTable()->RemoveAll( this ); +} + int KeyValues3::GetMemberCount() const { const CKeyValues3Table *pTable = GetTable(); @@ -840,12 +837,12 @@ CKV3MemberName KeyValues3::GetKV3MemberName( KV3MemberId_t id ) const return CKV3MemberName( pTable->GetMemberHash( id ), pTable->GetMemberName( id ) ); } -CUtlStringToken KeyValues3::GetMemberHash( KV3MemberId_t id ) const +KeyValues3LowercaseHash_t KeyValues3::GetMemberHash( KV3MemberId_t id ) const { const CKeyValues3Table *pTable = GetTable(); if ( !pTable || id < 0 || id >= pTable->GetMemberCount() ) - return CUtlStringToken(); + return KeyValues3LowercaseHash_t(); return pTable->GetMemberHash( id ); } @@ -892,10 +889,24 @@ KeyValues3* KeyValues3::FindOrCreateMember( const CKV3MemberName &name, bool *pC return pTable->GetMember( id ); } -void KeyValues3::SetToEmptyTable() +KeyValues3* KeyValues3::RenameMember( const CKV3MemberName &name, const CKV3MemberName &newName ) { - PrepareForType( KV3_TYPEEX_TABLE, KV3_SUBTYPE_TABLE ); - GetTable()->RemoveAll( this ); + if ( newName.IsEmpty() ) + return nullptr; + + CKeyValues3Table *pTable = GetTable(); + + if ( !pTable ) + return nullptr; + + KV3MemberId_t id = pTable->FindMember( name ); + + if ( id == KV3_INVALID_MEMBER ) + return nullptr; + + pTable->RenameMember( this, id, newName ); + + return pTable->GetMember( id ); } bool KeyValues3::RemoveMember( KV3MemberId_t id ) @@ -1770,10 +1781,7 @@ KV3MemberId_t CKeyValues3Table::CreateMember( KeyValues3 *parent, const CKV3Memb { auto context = parent->GetContext(); - if(context) - names_base[curr] = context->AllocString( name.GetString() ); - else - names_base[curr] = strdup( name.GetString() ); + names_base[curr] = context ? context->AllocString( name.GetString() ) : strdup( name.GetString() ); } flags_base[curr] = flags; @@ -1810,12 +1818,7 @@ void CKeyValues3Table::CopyFrom( KeyValues3 *parent, const CKeyValues3Table* src for(int i = 0; i < new_size; i++) { flags_base[i] = src_flags_base[i] & ~MEMBER_FLAG_EXTERNAL_NAME; - - if(context) - names_base[i] = context->AllocString( src_names_base[i] ); - else - names_base[i] = strdup( src_names_base[i] ); - + names_base[i] = context ? context->AllocString( src_names_base[i] ) : strdup( src_names_base[i] ); members_base[i] = parent->AllocMember(); members_base[i]->CopyFrom( src_members_base[i] ); } @@ -1824,6 +1827,40 @@ void CKeyValues3Table::CopyFrom( KeyValues3 *parent, const CKeyValues3Table* src EnableFastSearch(); } +void CKeyValues3Table::RenameMember( KeyValues3 *parent, KV3MemberId_t id, const CKV3MemberName &newName ) +{ + Hash_t* hashes_base = HashesBase(); + Name_t* names_base = NamesBase(); + Flags_t* flags_base = FlagsBase(); + + auto &name = names_base[id]; + auto &flags = flags_base[id]; + + hashes_base[id] = newName; + + auto context = parent->GetContext(); + + if ( context ) + { + name = context->AllocString( newName.GetString() ); + } + else + { + if ( flags & MEMBER_FLAG_EXTERNAL_NAME ) + flags &= ~MEMBER_FLAG_EXTERNAL_NAME; + else if ( name ) + free( (void *)name ); + + name = strdup( newName.GetString() ); + } + + if ( m_pFastSearch ) + { + m_pFastSearch->m_ignore = true; + m_pFastSearch->m_ignores_counter = 1; + } +} + void CKeyValues3Table::RemoveMember( KeyValues3 *parent, KV3MemberId_t id ) { m_nCount--; From 8441bc8537306791382693f2977803e5ad8c7f25 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sun, 9 Mar 2025 13:26:44 +0300 Subject: [PATCH 08/30] Add `KeyValues3::OverlayKeysFrom` method --- public/tier1/keyvalues3.h | 56 +++++++++++++++--------- public/tier1/utlsymbollarge.h | 4 +- tier1/keyvalues3.cpp | 80 ++++++++++++++++++++--------------- 3 files changed, 82 insertions(+), 58 deletions(-) diff --git a/public/tier1/keyvalues3.h b/public/tier1/keyvalues3.h index e8ddfde76..90c0e8320 100644 --- a/public/tier1/keyvalues3.h +++ b/public/tier1/keyvalues3.h @@ -114,6 +114,16 @@ PLATFORM_OVERLOAD bool SaveKV3ToFile( const KV3ID_t& encoding, const KV3ID_t& fo typedef int32 KV3MemberId_t; #define KV3_INVALID_MEMBER ((KV3MemberId_t)-1) +#define FOR_EACH_KV3_ARRAY( arrayName, iter ) \ + for ( int iter = 0; (arrayName).Count(); iter++ ) +#define FOR_EACH_KV3_ARRAY_BACK( arrayName, iter ) \ + for ( int iter = (arrayName).Count()-1; iter >= 0; iter-- ) + +#define FOR_EACH_KV3_TABLE( tableName, iter ) \ + for ( KV3MemberId_t iter = 0; (tableName).GetMemberCount(); iter++ ) +#define FOR_EACH_KV3_TABLE_BACK( tableName, iter ) \ + for ( KV3MemberId_t iter = (tableName).GetMemberCount()-1; iter >= 0; iter-- ) + // AMNOTE: These constants aren't actual constants, but rather calculated at compile time // but the way they are calculated is unknown, previously it was using CUtlLeanVector min/max calculations // but in here they seem to not match that behaviour. @@ -443,8 +453,8 @@ class KeyValues3 const char* ToString( CBufferString& buff, uint flags = KV3_TO_STRING_NONE ) const; - void SetToNull() { PrepareForType( KV3_TYPEEX_NULL, KV3_SUBTYPE_NULL ); } bool IsNull() const { return GetType() == KV3_TYPE_NULL; } + void SetToNull() { PrepareForType( KV3_TYPEEX_NULL, KV3_SUBTYPE_NULL ); } bool GetBool( bool defaultValue = false ) const { return GetValue( defaultValue ); } char8 GetChar( char8 defaultValue = 0 ) const { return GetValue( defaultValue ); } @@ -509,6 +519,10 @@ class KeyValues3 void SetQAngle( const QAngle &ang ) { SetVecBasedObj( ang, 3, KV3_SUBTYPE_QANGLE ); } void SetMatrix3x4( const matrix3x4_t &matrix ) { SetVecBasedObj( matrix, 3*4, KV3_SUBTYPE_MATRIX3X4 ); } + bool IsArray() const { return GetType() == KV3_TYPE_ARRAY; } + CKeyValues3Array *GetArray() { return IsArray() ? m_Data.m_pArray : nullptr; } + const CKeyValues3Array *GetArray() const { return const_cast(this)->GetArray(); }; + int GetArrayElementCount() const; void SetArrayElementCount( int count, KV3TypeEx_t type = KV3_TYPEEX_NULL, KV3SubType_t subtype = KV3_SUBTYPE_UNSPECIFIED ); @@ -527,15 +541,13 @@ class KeyValues3 void ArrayRemoveElements( int elem, int num ); void ArrayRemoveElement( int elem ) { ArrayRemoveElements( elem, 1 ); } + bool IsTable() const { return GetType() == KV3_TYPE_TABLE; } + CKeyValues3Table *GetTable() { return IsTable() ? m_Data.m_pTable : nullptr; } + const CKeyValues3Table *GetTable() const { return const_cast(this)->GetTable(); } + void SetToEmptyTable(); int GetMemberCount() const; - CKeyValues3Array *GetArray(); - const CKeyValues3Array *GetArray() const { return const_cast(this)->GetArray(); }; - - CKeyValues3Table *GetTable(); - const CKeyValues3Table *GetTable() const { return const_cast(this)->GetTable(); }; - KeyValues3* GetMember( KV3MemberId_t id ); const KeyValues3* GetMember( KV3MemberId_t id ) const { return const_cast(this)->GetMember( id ); } const char* GetMemberName( KV3MemberId_t id ) const; @@ -678,8 +690,10 @@ class KeyValues3 void Free( bool bClearingContext = false ); void ResolveUnspecified(); - void PrepareForType( KV3TypeEx_t type, KV3SubType_t subtype ); + void PrepareForType( KV3TypeEx_t type, KV3SubType_t subtype, int initial_size = 0, Data_t data = {}, int bytes_available = 0, bool should_free = false ); + void CopyFrom( const KeyValues3* pSrc ); + void OverlayKeysFrom( KeyValues3 *parent, bool depth = false ); int GetClusterElement() const { return m_nClusterElement; } void SetClusterElement( int element ) { m_bContextIndependent = (element == -1); m_nClusterElement = element; } @@ -843,6 +857,19 @@ class CKeyValues3Table CKeyValues3TableCluster* GetCluster() const; CKeyValues3Context* GetContext() const; + // Gets the base address (can change when adding elements!) + void *Base() { return IsBaseStatic() ? &m_StaticBuffer : m_pDynamicBuffer; }; + Hash_t *HashesBase() { return reinterpret_cast((uint8 *)Base() + OffsetToHashesBase( GetAllocatedChunks() )); } + Member_t *MembersBase() { return reinterpret_cast((uint8 *)Base() + OffsetToMembersBase( GetAllocatedChunks() )); } + Name_t *NamesBase() { return reinterpret_cast((uint8 *)Base() + OffsetToNamesBase( GetAllocatedChunks() )); } + Flags_t *FlagsBase() { return reinterpret_cast((uint8 *)Base() + OffsetToFlagsBase( GetAllocatedChunks() )); } + + const void *Base() const { return const_cast(this)->Base(); } + const Hash_t *HashesBase() const { return const_cast(this)->HashesBase(); } + const Member_t *MembersBase() const { return const_cast(this)->MembersBase(); } + const Name_t *NamesBase() const { return const_cast(this)->NamesBase(); } + const Flags_t *FlagsBase() const { return const_cast(this)->FlagsBase(); } + int GetMemberCount() const { return m_nCount; } Member_t GetMember( KV3MemberId_t id ); const Member_t GetMember( KV3MemberId_t id ) const { return const_cast(this)->GetMember( id ); } @@ -883,19 +910,6 @@ class CKeyValues3Table constexpr size_t OffsetToNamesBase( int size ) const { return KV3Helpers::PackSizeOf( size ); } constexpr size_t OffsetToFlagsBase( int size ) const { return KV3Helpers::PackSizeOf( size ); } - // Gets the base address (can change when adding elements!) - void *Base() { return IsBaseStatic() ? &m_StaticBuffer : m_pDynamicBuffer; }; - Hash_t *HashesBase() { return reinterpret_cast((uint8 *)Base() + OffsetToHashesBase( GetAllocatedChunks() )); } - Member_t *MembersBase() { return reinterpret_cast((uint8 *)Base() + OffsetToMembersBase( GetAllocatedChunks() )); } - Name_t *NamesBase() { return reinterpret_cast((uint8 *)Base() + OffsetToNamesBase( GetAllocatedChunks() )); } - Flags_t *FlagsBase() { return reinterpret_cast((uint8 *)Base() + OffsetToFlagsBase( GetAllocatedChunks() )); } - - const void *Base() const { return const_cast(this)->Base(); } - const Hash_t *HashesBase() const { return const_cast(this)->HashesBase(); } - const Member_t *MembersBase() const { return const_cast(this)->MembersBase(); } - const Name_t *NamesBase() const { return const_cast(this)->NamesBase(); } - const Flags_t *FlagsBase() const { return const_cast(this)->FlagsBase(); } - private: int m_nClusterElement; int m_nAllocatedChunks; diff --git a/public/tier1/utlsymbollarge.h b/public/tier1/utlsymbollarge.h index eb2091de8..67a6c4723 100644 --- a/public/tier1/utlsymbollarge.h +++ b/public/tier1/utlsymbollarge.h @@ -29,9 +29,9 @@ // to the string data, the hash precedes it in memory and is used to speed up searching, etc. //----------------------------------------------------------------------------- -typedef unsigned int UtlSymLargeId_t; +typedef intp UtlSymLargeId_t; -#define UTL_INVAL_SYMBOL_LARGE ((UtlSymLargeId_t)~0) +#define UTL_INVAL_SYMBOL_LARGE ((UtlSymLargeId_t)0) #define FOR_EACH_SYMBOL_LARGE( table, iter ) \ for ( UtlSymLargeId_t iter = 0; iter < (table).GetNumStrings(); iter++ ) diff --git a/tier1/keyvalues3.cpp b/tier1/keyvalues3.cpp index cc45bbe88..0fa805419 100644 --- a/tier1/keyvalues3.cpp +++ b/tier1/keyvalues3.cpp @@ -333,7 +333,7 @@ void KeyValues3::ResolveUnspecified() } } -void KeyValues3::PrepareForType( KV3TypeEx_t type, KV3SubType_t subtype ) +void KeyValues3::PrepareForType( KV3TypeEx_t type, KV3SubType_t subtype, int initial_size, Data_t data, int bytes_available, bool should_free ) { if ( GetTypeEx() == type ) { @@ -360,7 +360,7 @@ void KeyValues3::PrepareForType( KV3TypeEx_t type, KV3SubType_t subtype ) { Free(); m_TypeEx = type; - Alloc(); + Alloc( initial_size, data, bytes_available, should_free ); } m_SubType = subtype; @@ -529,7 +529,7 @@ int KeyValues3::GetArrayElementCount() const if ( !pArray ) return 0; - return GetTypeEx() == KV3_TYPEEX_ARRAY ? pArray->Count() : m_nNumArrayElements; + return IsArray() ? pArray->Count() : m_nNumArrayElements; } KeyValues3** KeyValues3::GetArrayBase() @@ -554,8 +554,8 @@ KeyValues3* KeyValues3::GetArrayElement( int elem ) KeyValues3* KeyValues3::ArrayInsertElementBefore( int elem ) { - if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) - PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY ); + if ( !IsArray() ) + SetToEmptyArray(); CKeyValues3Array *pArray = GetArray(); @@ -566,8 +566,8 @@ KeyValues3* KeyValues3::ArrayInsertElementBefore( int elem ) KeyValues3* KeyValues3::ArrayAddElementToTail() { - if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) - PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY ); + if ( !IsArray() ) + SetToEmptyArray(); CKeyValues3Array *pArray = GetArray(); @@ -598,8 +598,8 @@ void KeyValues3::ArraySwapItems( int idx1, int idx2 ) void KeyValues3::SetArrayElementCount( int count, KV3TypeEx_t type, KV3SubType_t subtype ) { - if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) - PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY ); + if ( !IsArray() ) + SetToEmptyArray(); CKeyValues3Array *pArray = GetArray(); @@ -791,22 +791,6 @@ int KeyValues3::GetMemberCount() const return pTable ? pTable->GetMemberCount() : 0; } -CKeyValues3Array *KeyValues3::GetArray() -{ - if(GetType() != KV3_TYPE_ARRAY) - return nullptr; - - return m_Data.m_pArray; -} - -CKeyValues3Table *KeyValues3::GetTable() -{ - if(GetType() != KV3_TYPE_TABLE) - return nullptr; - - return m_Data.m_pTable; -} - KeyValues3* KeyValues3::GetMember( KV3MemberId_t id ) { CKeyValues3Table *pTable = GetTable(); @@ -865,7 +849,7 @@ KeyValues3* KeyValues3::Internal_FindMember( const CKV3MemberName &name, KV3Memb KeyValues3* KeyValues3::FindOrCreateMember( const CKV3MemberName &name, bool *pCreated ) { if ( GetType() != KV3_TYPE_TABLE ) - PrepareForType( KV3_TYPEEX_TABLE, KV3_SUBTYPE_TABLE ); + SetToEmptyTable(); CKeyValues3Table *pTable = GetTable(); @@ -1310,7 +1294,7 @@ void KeyValues3::CopyFrom( const KeyValues3* pSrc ) { case KV3_TYPEEX_ARRAY: { - PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY ); + SetToEmptyArray(); m_Data.m_pArray->CopyFrom( this, pSrc->m_Data.m_pArray ); break; } @@ -1351,6 +1335,38 @@ void KeyValues3::CopyFrom( const KeyValues3* pSrc ) m_nFlags = pSrc->m_nFlags; } +void KeyValues3::OverlayKeysFrom( KeyValues3 *parent, bool depth ) +{ + CKeyValues3Table *pTable = GetTable(); + + if( !pTable ) + SetToNull(); + + CKeyValues3Table *pParentTable = parent->GetTable(); + + if ( !pParentTable ) + return; + + auto parent_hashes = pParentTable->HashesBase(); + auto parent_members = pParentTable->MembersBase(); + auto parent_names = pParentTable->NamesBase(); + + FOR_EACH_KV3_TABLE( *pParentTable, id ) + { + KeyValues3 *kv = FindOrCreateMember( CKV3MemberName( parent_hashes[id], parent_names[id] ) ); + KeyValues3 *parent_kv = parent_members[id]; + + if ( depth && kv->IsTable() && parent_kv->IsTable() ) + { + OverlayKeysFrom( parent_kv, true ); + } + else + { + CopyFrom( parent_kv ); + } + } +} + KeyValues3& KeyValues3::operator=( const KeyValues3& src ) { if ( this == &src ) @@ -1423,20 +1439,14 @@ CKeyValues3Array::CKeyValues3Array( int cluster_elem, int alloc_size ) : CKeyValues3ArrayCluster* CKeyValues3Array::GetCluster() const { - if ( m_nClusterElement == -1 ) - return nullptr; - - return GET_OUTER( CKeyValues3ArrayCluster, m_Values[ m_nClusterElement ] ); + return m_nClusterElement == -1 ? nullptr : GET_OUTER( CKeyValues3ArrayCluster, m_Values[ m_nClusterElement ] ); } CKeyValues3Context* CKeyValues3Array::GetContext() const { CKeyValues3ArrayCluster* cluster = GetCluster(); - if ( cluster ) - return cluster->GetContext(); - else - return nullptr; + return cluster ? cluster->GetContext() : nullptr; } KeyValues3* CKeyValues3Array::Element( int i ) From c8064850cd8238ff038964cf8de7fd4e060cc972 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Tue, 11 Mar 2025 07:15:38 +0300 Subject: [PATCH 09/30] Resolve `UtlSymLargeId_t` differences --- public/tier1/utlsymbollarge.h | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/public/tier1/utlsymbollarge.h b/public/tier1/utlsymbollarge.h index 67a6c4723..21faad965 100644 --- a/public/tier1/utlsymbollarge.h +++ b/public/tier1/utlsymbollarge.h @@ -13,6 +13,7 @@ #pragma once #endif +#include "tier0/platform.h" #include "tier0/threadtools.h" #include "tier1/generichash.h" #include "tier1/utlvector.h" @@ -30,13 +31,14 @@ //----------------------------------------------------------------------------- typedef intp UtlSymLargeId_t; +typedef uint UtlSymLargeElm_t; #define UTL_INVAL_SYMBOL_LARGE ((UtlSymLargeId_t)0) #define FOR_EACH_SYMBOL_LARGE( table, iter ) \ - for ( UtlSymLargeId_t iter = 0; iter < (table).GetNumStrings(); iter++ ) + for ( UtlSymLargeElm_t iter = 0; iter < (table).GetNumStrings(); iter++ ) #define FOR_EACH_SYMBOL_LARGE_BACK( table, iter ) \ - for ( UtlSymLargeId_t iter = (table).GetNumStrings()-1; iter >= 0; iter-- ) + for ( UtlSymLargeElm_t iter = (table).GetNumStrings()-1; iter >= 0; iter-- ) class CUtlSymbolLarge { @@ -127,8 +129,8 @@ class CUtlSymbolTableLargeBase CUtlSymbolLarge Find( const char* pString ) const; CUtlSymbolLarge Find( const char* pString, int nLength ) const; - const char* String( UtlSymLargeId_t id ) const; - unsigned int Hash( UtlSymLargeId_t id ) const; + const char* String( UtlSymLargeElm_t elem ) const; + unsigned int Hash( UtlSymLargeElm_t elem ) const; int GetNumStrings() const { return m_MemBlocks.Count(); }; @@ -163,7 +165,7 @@ class CUtlSymbolTableLargeBase return CUtlSymbolLarge::Hash< CASEINSENSITIVE >( k.m_pString, k.m_nLength ); } - unsigned int operator()( UtlSymLargeId_t k ) const + unsigned int operator()( UtlSymLargeElm_t k ) const { const CUtlSymbolTableLargeBase* pTable = (const CUtlSymbolTableLargeBase*)((uintp)this + m_ownerOffset); @@ -182,7 +184,7 @@ class CUtlSymbolTableLargeBase m_ownerOffset = -owneroffset; } - bool operator()( UtlSymLargeId_t a, UtlSymLargeId_t b ) const + bool operator()( UtlSymLargeElm_t a, UtlSymLargeElm_t b ) const { const CUtlSymbolTableLargeBase* pTable = (const CUtlSymbolTableLargeBase*)((uintp)this + m_ownerOffset); @@ -192,7 +194,7 @@ class CUtlSymbolTableLargeBase return V_strcmp( pTable->String( a ), pTable->String( b ) ) == 0; } - bool operator()( UtlSymTableLargeAltKey a, UtlSymLargeId_t b ) const + bool operator()( UtlSymTableLargeAltKey a, UtlSymLargeElm_t b ) const { const char* pString = a.m_pTable->String( b ); int nLength = strlen( pString ); @@ -206,14 +208,14 @@ class CUtlSymbolTableLargeBase return V_strncmp( a.m_pString, pString, a.m_nLength ) == 0; } - bool operator()( UtlSymLargeId_t a, UtlSymTableLargeAltKey b ) const + bool operator()( UtlSymLargeElm_t a, UtlSymTableLargeAltKey b ) const { return operator()( b, a ); } }; - typedef CUtlHashtable>> Hashtable_t; - typedef CUtlVector< MemBlockHandle_t, CUtlMemory_RawAllocator > MemBlocksVec_t; + typedef CUtlHashtable< UtlSymLargeElm_t, empty_t, UtlSymTableLargeHashFunctor, UtlSymTableLargeEqualFunctor, UtlSymTableLargeAltKey, CUtlMemory_RawAllocator< CUtlHashtableEntry< UtlSymLargeElm_t, empty_t > > > Hashtable_t; + typedef CUtlVector< MemBlockHandle_t, CUtlMemory_RawAllocator< MemBlockHandle_t > > MemBlocksVec_t; Hashtable_t m_HashTable; MemBlocksVec_t m_MemBlocks; @@ -277,13 +279,13 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT } template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE > -inline const char* CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::String( UtlSymLargeId_t id ) const +inline const char* CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::String( UtlSymLargeElm_t elem ) const { return ( const char* )m_MemBlockAllocator.GetBlock( m_MemBlocks[ id ] ); } template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE > -inline unsigned int CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::Hash( UtlSymLargeId_t id ) const +inline unsigned int CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::Hash( UtlSymLargeElm_t elem ) const { CUtlSymbolTableLargeBaseTreeEntry_t *entry = (CUtlSymbolTableLargeBaseTreeEntry_t *)m_MemBlockAllocator.GetBlock( m_MemBlocks[ id ] - sizeof( LargeSymbolTableHashDecoration_t ) ); From c6ac50664931cc69c122e382ea2e37b9aa22a907 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Tue, 11 Mar 2025 10:07:46 +0300 Subject: [PATCH 10/30] Resolve `UtlSymLargeId_t` differences (2) --- public/tier1/utlsymbollarge.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/tier1/utlsymbollarge.h b/public/tier1/utlsymbollarge.h index 21faad965..58075374d 100644 --- a/public/tier1/utlsymbollarge.h +++ b/public/tier1/utlsymbollarge.h @@ -281,13 +281,13 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE > inline const char* CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::String( UtlSymLargeElm_t elem ) const { - return ( const char* )m_MemBlockAllocator.GetBlock( m_MemBlocks[ id ] ); + return ( const char* )m_MemBlockAllocator.GetBlock( m_MemBlocks[ elem ] ); } template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE > inline unsigned int CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::Hash( UtlSymLargeElm_t elem ) const { - CUtlSymbolTableLargeBaseTreeEntry_t *entry = (CUtlSymbolTableLargeBaseTreeEntry_t *)m_MemBlockAllocator.GetBlock( m_MemBlocks[ id ] - sizeof( LargeSymbolTableHashDecoration_t ) ); + CUtlSymbolTableLargeBaseTreeEntry_t *entry = (CUtlSymbolTableLargeBaseTreeEntry_t *)m_MemBlockAllocator.GetBlock( m_MemBlocks[ elem ] - sizeof( LargeSymbolTableHashDecoration_t ) ); return entry->Hash(); } From 998f037c40d82ef5a613cbd01e966140fcf9d997 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 03:17:39 +0300 Subject: [PATCH 11/30] Update `CUtlStringMap` constructor Co-authored-by: GAMMACASE <31375974+GAMMACASE@users.noreply.github.com> --- public/tier1/UtlStringMap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/tier1/UtlStringMap.h b/public/tier1/UtlStringMap.h index 3d7fb96e0..6577cca86 100644 --- a/public/tier1/UtlStringMap.h +++ b/public/tier1/UtlStringMap.h @@ -22,7 +22,7 @@ class CUtlStringMap public: CUtlStringMap( bool caseInsensitive = true, int initsize = 32 ) : m_Vector( initsize ), - m_SymbolTable( 0, 32, caseInsensitive ) + m_SymbolTable( 0, initsize, caseInsensitive ) { } From 49b63395d85ec58d4fbd3828097de2c7c44be40c Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 03:20:47 +0300 Subject: [PATCH 12/30] Update `CUtlStringMap` access operators Co-authored-by: Co-authored-by: GAMMACASE <31375974+GAMMACASE@users.noreply.github.com> --- public/tier1/UtlStringMap.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/tier1/UtlStringMap.h b/public/tier1/UtlStringMap.h index 6577cca86..5ee97686f 100644 --- a/public/tier1/UtlStringMap.h +++ b/public/tier1/UtlStringMap.h @@ -39,13 +39,13 @@ class CUtlStringMap } // Get data by the string's symbol table ID - only used to retrieve a pre-existing symbol, not create a new one! - T& operator[]( CUtlSymbol n ) + T& operator[]( UtlSymId_t n ) { Assert( n <= m_Vector.Count() ); return m_Vector[n]; } - const T& operator[]( CUtlSymbol n ) const + const T& operator[]( UtlSymId_t n ) const { Assert( n <= m_Vector.Count() ); return m_Vector[n]; From dfc32eb575855409d31d539d009143df3cd0d5e2 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 03:21:45 +0300 Subject: [PATCH 13/30] Uncomment `CUtlStringMap::Count`'s assert Co-authored-by: GAMMACASE <31375974+GAMMACASE@users.noreply.github.com> --- public/tier1/UtlStringMap.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/tier1/UtlStringMap.h b/public/tier1/UtlStringMap.h index 5ee97686f..6bf07d172 100644 --- a/public/tier1/UtlStringMap.h +++ b/public/tier1/UtlStringMap.h @@ -53,7 +53,8 @@ class CUtlStringMap unsigned int Count() const { - // Assert( m_Vector.Count() == m_SymbolTable.GetNumStrings() ); + Assert( m_Vector.Count() == m_SymbolTable.GetNumStrings() ); + return m_Vector.Count(); } From ae85a4ea915637c7f6e3b19a26d884df11267619 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 03:35:25 +0300 Subject: [PATCH 14/30] Remove `CUtlStringMap::First`'s method Co-authored-by: GAMMACASE <31375974+GAMMACASE@users.noreply.github.com> --- public/tier1/UtlStringMap.h | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/public/tier1/UtlStringMap.h b/public/tier1/UtlStringMap.h index 6bf07d172..f346a6b17 100644 --- a/public/tier1/UtlStringMap.h +++ b/public/tier1/UtlStringMap.h @@ -14,7 +14,7 @@ #include "utlsymbol.h" #define FOR_EACH_STRING_MAP( mapName, iter ) \ - for ( auto iter = (mapName).First(); iter < (mapName).GetNumStrings() && iter != (mapName).InvalidIndex(); iter = (mapName).Next( iter ) ) + for ( auto iter = (mapName).Head(); iter < (mapName).GetNumStrings() && iter != (mapName).InvalidIndex(); iter = (mapName).Next( iter ) ) template class CUtlStringMap @@ -122,19 +122,6 @@ class CUtlStringMap return true; } - /// iterate, not in any particular order. - CUtlSymbol First() const - { - if ( Count() > 0 ) - { - return 0; - } - else - { - return InvalidIndex(); - } - } - static CUtlSymbol InvalidIndex() { return {}; From 6c9762278bc98d9270bfc0ad22eba0721be68a31 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 03:39:50 +0300 Subject: [PATCH 15/30] `CBufferStringN`: replace `uintp` with `size_t` Co-authored-by: GAMMACASE <31375974+GAMMACASE@users.noreply.github.com> --- public/tier1/bufferstring.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/public/tier1/bufferstring.h b/public/tier1/bufferstring.h index 5bd89de07..377e33089 100644 --- a/public/tier1/bufferstring.h +++ b/public/tier1/bufferstring.h @@ -5,6 +5,10 @@ #pragma once #endif +#define __need_size_t +#include +#undef __need_size_t + #include "tier0/platform.h" #include "strtools.h" #include "utlstring.h" @@ -291,11 +295,11 @@ class CBufferString }; }; -template< uintp SIZE = 128 > // Most commonly used. +template< size_t SIZE > class CBufferStringN : public CBufferString { public: - static const uintp DATA_SIZE = ALIGN_VALUE( SIZE - sizeof( char[8] ), 8 ); + static const size_t DATA_SIZE = ALIGN_VALUE( SIZE - sizeof( char[8] ), 8 ); CBufferStringN( bool bAllowHeapAllocation = true ) : CBufferString( DATA_SIZE, bAllowHeapAllocation ) {} CBufferStringN( const char *pString, int nLen = -1, bool bAllowHeapAllocation = true ) : CBufferStringN( bAllowHeapAllocation ) { Insert( 0, pString, nLen ); } @@ -308,7 +312,7 @@ class CBufferStringN : public CBufferString }; // AMNOTE: CBufferStringN name is preferred to be used, altho CBufferStringGrowable is left as a small bcompat -template< uintp SIZE > +template< size_t SIZE > using CBufferStringGrowable = CBufferStringN; #endif /* BUFFERSTRING_H */ \ No newline at end of file From 2b2c44789f3f704d45b0d968e8ff8b8f32a61e47 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 03:43:40 +0300 Subject: [PATCH 16/30] Update `FOR_EACH_KV3_ARRAY`(`_BACK`) & `FOR_EACH_KV3_TABLE` macros Co-authored-by: GAMMACASE <31375974+GAMMACASE@users.noreply.github.com> --- public/tier1/keyvalues3.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/tier1/keyvalues3.h b/public/tier1/keyvalues3.h index 90c0e8320..c8d265966 100644 --- a/public/tier1/keyvalues3.h +++ b/public/tier1/keyvalues3.h @@ -115,12 +115,12 @@ typedef int32 KV3MemberId_t; #define KV3_INVALID_MEMBER ((KV3MemberId_t)-1) #define FOR_EACH_KV3_ARRAY( arrayName, iter ) \ - for ( int iter = 0; (arrayName).Count(); iter++ ) + for ( int iter = 0; iter < (arrayName).Count(); iter++ ) #define FOR_EACH_KV3_ARRAY_BACK( arrayName, iter ) \ - for ( int iter = (arrayName).Count()-1; iter >= 0; iter-- ) + for ( int iter = iter < (arrayName).Count()-1; iter >= 0; iter-- ) #define FOR_EACH_KV3_TABLE( tableName, iter ) \ - for ( KV3MemberId_t iter = 0; (tableName).GetMemberCount(); iter++ ) + for ( KV3MemberId_t iter = 0; iter < (tableName).GetMemberCount(); iter++ ) #define FOR_EACH_KV3_TABLE_BACK( tableName, iter ) \ for ( KV3MemberId_t iter = (tableName).GetMemberCount()-1; iter >= 0; iter-- ) From 1c5f01527056ca2c9e16771fca6a1fbe09468c78 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 03:56:45 +0300 Subject: [PATCH 17/30] Add `CKV3MemberHash` definition Co-authored-by: GAMMACASE <31375974+GAMMACASE@users.noreply.github.com> --- public/tier1/keyvalues3.h | 8 +++++--- tier1/keyvalues3.cpp | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/public/tier1/keyvalues3.h b/public/tier1/keyvalues3.h index c8d265966..14884fbc6 100644 --- a/public/tier1/keyvalues3.h +++ b/public/tier1/keyvalues3.h @@ -371,7 +371,10 @@ struct KV3BinaryBlob_t bool m_bFreeMemory; }; -class CKV3MemberName +using KeyValues3LowercaseHash_t = CUtlStringToken; +using CKV3MemberHash = KeyValues3LowercaseHash_t; + +class CKV3MemberName : public CKV3MemberHash { public: template< uintp N > constexpr CKV3MemberName( const char (&szInit)[N] ) : CUtlStringToken( szInit ), m_pszString( (const char *)szInit ) {} @@ -392,7 +395,6 @@ class CKV3MemberName const char* m_pszString; }; -using KeyValues3LowercaseHash_t = CUtlStringToken; using CKeyValues3StringAndHash = CKV3MemberName; // Pulse thing @@ -551,7 +553,7 @@ class KeyValues3 KeyValues3* GetMember( KV3MemberId_t id ); const KeyValues3* GetMember( KV3MemberId_t id ) const { return const_cast(this)->GetMember( id ); } const char* GetMemberName( KV3MemberId_t id ) const; - KeyValues3LowercaseHash_t GetMemberHash( KV3MemberId_t id ) const; + CKV3MemberHash GetMemberHash( KV3MemberId_t id ) const; CKV3MemberName GetKV3MemberName( KV3MemberId_t id ) const; protected: diff --git a/tier1/keyvalues3.cpp b/tier1/keyvalues3.cpp index 0fa805419..e2fb71d68 100644 --- a/tier1/keyvalues3.cpp +++ b/tier1/keyvalues3.cpp @@ -821,12 +821,12 @@ CKV3MemberName KeyValues3::GetKV3MemberName( KV3MemberId_t id ) const return CKV3MemberName( pTable->GetMemberHash( id ), pTable->GetMemberName( id ) ); } -KeyValues3LowercaseHash_t KeyValues3::GetMemberHash( KV3MemberId_t id ) const +CKV3MemberHash KeyValues3::GetMemberHash( KV3MemberId_t id ) const { const CKeyValues3Table *pTable = GetTable(); if ( !pTable || id < 0 || id >= pTable->GetMemberCount() ) - return KeyValues3LowercaseHash_t(); + return CKV3MemberHash(); return pTable->GetMemberHash( id ); } From 3a6ff85bc8ff1b3b04c423f772dc2d9036c494fd Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 04:19:45 +0300 Subject: [PATCH 18/30] Remove `CUtlStringTokenHashMethod` class Use `DefaultHashFunctor< CUtlStringToken >` instead Co-authored-by: GAMMACASE <31375974+GAMMACASE@users.noreply.github.com> --- public/tier1/utlstringtoken.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/public/tier1/utlstringtoken.h b/public/tier1/utlstringtoken.h index 2eea2cbfc..190954dd7 100644 --- a/public/tier1/utlstringtoken.h +++ b/public/tier1/utlstringtoken.h @@ -100,7 +100,6 @@ class CUtlStringToken CUtlStringToken( const CBufferString &buffer ) : CUtlStringToken( buffer.Get(), buffer.Length() ) {} // operator== - // aka CUtlStringTokenHashMethod. bool operator==( const uint32 nHash ) const { return m_nHashCode == nHash; } bool operator==( const CUtlStringToken &other ) const { return operator==( other.GetHashCode() ); } bool operator==( const char *pString ) const { return operator==( MAKE_STRINGTOKEN( pString ) ); } @@ -132,16 +131,6 @@ class CUtlStringToken uint32 m_nHashCode; }; -// To compare into CUtlHash< Data, C, K > -class CUtlStringTokenHashMethod -{ -public: - CUtlStringTokenHashMethod( int ) {} - - bool operator()( const CUtlStringToken &nLHS, const CUtlStringToken &nRHS ) const { return nLHS == nRHS; } - static bool Compare( const CUtlStringToken &nLHS, const CUtlStringToken &nRHS ) { return nLHS == nRHS; } -}; - FORCEINLINE bool TrackStringToken( uint32 nHash, const char *pString ) { if ( g_bUpdateStringTokenDatabase ) From bd0c6b30c8928c78abab0fe4980ead533abae920 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 04:35:57 +0300 Subject: [PATCH 19/30] Update `CUtlStringToken`'s constructors Co-authored-by: GAMMACASE <31375974+GAMMACASE@users.noreply.github.com> --- public/tier1/utlstringtoken.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/public/tier1/utlstringtoken.h b/public/tier1/utlstringtoken.h index 190954dd7..771137f0f 100644 --- a/public/tier1/utlstringtoken.h +++ b/public/tier1/utlstringtoken.h @@ -42,7 +42,7 @@ class CUtlStringToken static constexpr uint32 sm_nRotation = 24; template< bool CASEINSENSITIVE = true > - FORCEINLINE static uint32 Hash( const char *pString, int n, uint32 nSeed = STRINGTOKEN_MURMURHASH_SEED ) + FORCEINLINE static constexpr uint32 Hash( const char *pString, int n, uint32 nSeed = STRINGTOKEN_MURMURHASH_SEED ) { // They're not really 'magic', they just happen to work well. @@ -93,9 +93,8 @@ class CUtlStringToken } CUtlStringToken( uint32 nHashCode = 0 ) : m_nHashCode( nHashCode ) {} - template < uintp N > constexpr CUtlStringToken( const char (&str)[N] ) : m_nHashCode( Make( str, N - 1 ) ) {} + template < uintp N > FORCEINLINE constexpr CUtlStringToken( const char (&str)[N] ) : m_nHashCode( Hash( str, N - 1 ) ) {} CUtlStringToken( const char *pString, int nLen ) : m_nHashCode( Hash( pString, nLen ) ) {} - CUtlStringToken( const char *pString ) : CUtlStringToken( pString, strlen(pString) ) {} CUtlStringToken( const CUtlString &str ) : CUtlStringToken( str.Get(), str.Length() ) {} CUtlStringToken( const CBufferString &buffer ) : CUtlStringToken( buffer.Get(), buffer.Length() ) {} From 892434b3526a6fb7f55f8ca8d7eda5a8d48c7c8c Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 04:38:10 +0300 Subject: [PATCH 20/30] Remove `CUtlSymbol` interate opertators Co-authored-by: GAMMACASE <31375974+GAMMACASE@users.noreply.github.com> --- public/tier1/utlsymbol.h | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/public/tier1/utlsymbol.h b/public/tier1/utlsymbol.h index 845fb39b4..b4b993ff8 100644 --- a/public/tier1/utlsymbol.h +++ b/public/tier1/utlsymbol.h @@ -37,9 +37,9 @@ typedef unsigned int UtlSymElm_t; #define UTL_INVAL_SYMBOL ((UtlSymId_t)~0) #define FOR_EACH_SYMBOL( tableName, iter ) \ - for ( CUtlSymbol iter = 0; iter < (tableName).GetNumStrings(); iter++ ) + for ( UtlSymElm_t iter = 0; iter < (tableName).GetNumStrings(); iter++ ) #define FOR_EACH_SYMBOL_BACK( tableName, iter ) \ - for ( CUtlSymbol iter = (tableName).GetNumStrings()-1; iter >= 0; iter-- ) + for ( UtlSymElm_t iter = (tableName).GetNumStrings()-1; iter >= 0; iter-- ) class CUtlSymbol { @@ -52,14 +52,6 @@ class CUtlSymbol // operator= CUtlSymbol& operator=( CUtlSymbol const& src ) { m_Id = src.m_Id; return *this; } - // operator++ - CUtlSymbol& operator++() { ++m_Id; return *this; } - CUtlSymbol operator++(int) { CUtlSymbol oldId = *this; ++m_Id; return oldId; } - - // operator-- - CUtlSymbol& operator--() { --m_Id; return *this; } - CUtlSymbol operator--(int) { CUtlSymbol oldId = *this; --m_Id; return oldId; } - // operator== bool operator==( CUtlSymbol const& src ) const { return m_Id == src.m_Id; } From 44e3ddfc229e99f441f4b6fdcf96c66811804c0b Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 05:16:24 +0300 Subject: [PATCH 21/30] Update `UtlSymId_t` operator method Co-authored-by: GAMMACASE <31375974+GAMMACASE@users.noreply.github.com> --- public/tier1/utlsymbol.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/tier1/utlsymbol.h b/public/tier1/utlsymbol.h index b4b993ff8..270ef6853 100644 --- a/public/tier1/utlsymbol.h +++ b/public/tier1/utlsymbol.h @@ -68,7 +68,7 @@ class CUtlSymbol bool IsValid() const { return GetId() != Invalid(); } // Gets at the symbol - operator UtlSymId_t () const { return GetId(); } + operator UtlSymId_t () const { return m_Id; } protected: CUtlSymbol( const char* pStr ); From eaf586edfa8ff3a61b133d6304fceeafad4d4115 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 05:48:55 +0300 Subject: [PATCH 22/30] Update `CUtlSymbolTableLargeBaseTreeEntry_t` structure --- public/tier1/utlsymbollarge.h | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/public/tier1/utlsymbollarge.h b/public/tier1/utlsymbollarge.h index 58075374d..3df54dd93 100644 --- a/public/tier1/utlsymbollarge.h +++ b/public/tier1/utlsymbollarge.h @@ -75,23 +75,30 @@ class CUtlSymbolLarge } u; }; -typedef uint32 LargeSymbolTableHashDecoration_t; +typedef uint32 LargeSymbolTableHashDecoration_t; // The structure consists of the hash immediately followed by the string data -struct alignas(8) CUtlSymbolTableLargeBaseTreeEntry_t +struct ALIGN8_POST CUtlSymbolTableLargeBaseTreeEntry_t { LargeSymbolTableHashDecoration_t m_Hash; // Variable length string data - char m_String[1]; + char m_szString[1]; bool IsEmpty() const { - return ( ( m_Hash == 0 ) && ( 0 == m_String[0] ) ); + return ( !m_Hash && !m_szString[0] ); } - char const *String() const + const char *String() const { - return (const char *)&m_String[ 0 ]; + return (const char *)m_szString; + } + + void Replace( LargeSymbolTableHashDecoration_t nNewHash, const char *pNewString, int nLength ) + { + m_Hash = nNewHash; + Q_memcpy( (char *)m_szString, pNewString, nLength ); + m_szString[nLength] = '\0'; } CUtlSymbolLarge ToSymbol() const @@ -265,15 +272,11 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT CUtlSymbolTableLargeBaseTreeEntry_t *entry = (CUtlSymbolTableLargeBaseTreeEntry_t *)m_MemBlockAllocator.GetBlock( block ); - entry->m_Hash = hash; - char *pText = (char *)&entry->m_String[ 0 ]; - memcpy( pText, pString, nLength ); - pText[ nLength ] = '\0'; + entry->Replace( hash, pString, nLength ); UtlSymLargeId_t id = m_MemBlocks.AddToTail( block + sizeof( LargeSymbolTableHashDecoration_t ) ); - empty_t empty; - m_HashTable.Insert( id, empty, hash ); + m_HashTable.Insert( elem, empty_t(), hash ); return entry->ToSymbol(); } From f6ca035ecc84be952286a53a4c6c7e68ea76769a Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 05:53:02 +0300 Subject: [PATCH 23/30] `CUtlSymbolTableLargeBaseTreeEntry_t`: Rename `Hash` method to `HashValue` back Update hash value type Co-authored-by: GAMMACASE <31375974+GAMMACASE@users.noreply.github.com> --- public/tier1/utlsymbollarge.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/public/tier1/utlsymbollarge.h b/public/tier1/utlsymbollarge.h index 3df54dd93..87c50823c 100644 --- a/public/tier1/utlsymbollarge.h +++ b/public/tier1/utlsymbollarge.h @@ -106,7 +106,7 @@ struct ALIGN8_POST CUtlSymbolTableLargeBaseTreeEntry_t return CUtlSymbolLarge( String() ); } - LargeSymbolTableHashDecoration_t Hash() const + LargeSymbolTableHashDecoration_t HashValue() const { return m_Hash; } @@ -136,8 +136,8 @@ class CUtlSymbolTableLargeBase CUtlSymbolLarge Find( const char* pString ) const; CUtlSymbolLarge Find( const char* pString, int nLength ) const; - const char* String( UtlSymLargeElm_t elem ) const; - unsigned int Hash( UtlSymLargeElm_t elem ) const; + const char* String( UtlSymLargeElm_t id ) const; + uint32 Hash( UtlSymLargeElm_t id ) const; int GetNumStrings() const { return m_MemBlocks.Count(); }; @@ -146,8 +146,8 @@ class CUtlSymbolTableLargeBase void Purge(); private: - CUtlSymbolLarge AddString( unsigned int hash, const char* pString, int nLength, bool* created ); - CUtlSymbolLarge Find( unsigned int hash, const char* pString, int nLength ) const; + CUtlSymbolLarge AddString( uint32 hash, const char* pString, int nLength, bool* created ); + CUtlSymbolLarge Find( uint32 hash, const char* pString, int nLength ) const; struct UtlSymTableLargeAltKey { @@ -167,12 +167,12 @@ class CUtlSymbolTableLargeBase m_ownerOffset = -owneroffset; } - unsigned int operator()( UtlSymTableLargeAltKey k ) const + uint32 operator()( UtlSymTableLargeAltKey k ) const { return CUtlSymbolLarge::Hash< CASEINSENSITIVE >( k.m_pString, k.m_nLength ); } - unsigned int operator()( UtlSymLargeElm_t k ) const + uint32 operator()( UtlSymLargeElm_t k ) const { const CUtlSymbolTableLargeBase* pTable = (const CUtlSymbolTableLargeBase*)((uintp)this + m_ownerOffset); @@ -233,7 +233,7 @@ class CUtlSymbolTableLargeBase }; template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE > -inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::Find( unsigned int hash, const char* pString, int nLength ) const +inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::Find( uint32 hash, const char* pString, int nLength ) const { UtlSymTableLargeAltKey key; @@ -250,7 +250,7 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT } template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE > -inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::AddString( unsigned int hash, const char* pString, int nLength, bool* created ) +inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::AddString( uint32 hash, const char* pString, int nLength, bool* created ) { if ( m_MemBlocks.Count() >= m_nElementLimit ) { @@ -288,11 +288,11 @@ inline const char* CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_T } template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE > -inline unsigned int CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::Hash( UtlSymLargeElm_t elem ) const +inline uint32 CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::Hash( UtlSymLargeElm_t elem ) const { CUtlSymbolTableLargeBaseTreeEntry_t *entry = (CUtlSymbolTableLargeBaseTreeEntry_t *)m_MemBlockAllocator.GetBlock( m_MemBlocks[ elem ] - sizeof( LargeSymbolTableHashDecoration_t ) ); - return entry->Hash(); + return entry->HashValue(); } template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE > @@ -302,7 +302,7 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT if ( pString && nLength > 0 && *pString ) { - unsigned int hash = CUtlSymbolLarge::Hash< CASEINSENSITIVE >( pString, nLength ); + uint32 hash = CUtlSymbolLarge::Hash< CASEINSENSITIVE >( pString, nLength ); AUTO_LOCK( m_Mutex ); @@ -328,7 +328,7 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT if ( pString && nLength > 0 && *pString ) { - unsigned int hash = CUtlSymbolLarge::Hash< CASEINSENSITIVE >( pString, nLength ); + uint32 hash = CUtlSymbolLarge::Hash< CASEINSENSITIVE >( pString, nLength ); AUTO_LOCK( m_Mutex ); From 37a2d4be858b242fca448a236fe1b17844642825 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 06:30:39 +0300 Subject: [PATCH 24/30] Rename `CUtlSymbol::Hash` to `CUtlSymbol::MakeHash` Co-authored-by: GAMMACASE <31375974+GAMMACASE@users.noreply.github.com> --- public/tier1/utlsymbol.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/tier1/utlsymbol.h b/public/tier1/utlsymbol.h index 270ef6853..18584e11e 100644 --- a/public/tier1/utlsymbol.h +++ b/public/tier1/utlsymbol.h @@ -55,7 +55,7 @@ class CUtlSymbol // operator== bool operator==( CUtlSymbol const& src ) const { return m_Id == src.m_Id; } - static uint32 Hash( bool bInsensitive, const char *pString, int nLength ) + static uint32 MakeHash( bool bInsensitive, const char *pString, int nLength ) { return bInsensitive ? MakeStringToken2< true >( pString, nLength ) : MakeStringToken2< false >( pString, nLength ); @@ -110,7 +110,7 @@ class CUtlSymbolTable // Look up the string associated with a particular symbol DLL_CLASS_IMPORT const char* String( CUtlSymbol id ) const; - uint32 Hash( const char *pString, int nLength ) const { return CUtlSymbol::Hash( IsInsensitive(), pString, nLength ); } + uint32 Hash( const char *pString, int nLength ) const { return CUtlSymbol::MakeHash( IsInsensitive(), pString, nLength ); } uint32 Hash( const char *pString ) const { return Hash( pString, strlen( pString ) ); } uint32 Hash( CUtlSymbol id ) const { return Hash( (const char *)m_MemBlockAllocator.GetBlock( m_MemBlocks[ id ] ) ); } From 5f9f05b321e0b8f4b29bb1d2e4fc6bd15acd2cec Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 07:46:02 +0300 Subject: [PATCH 25/30] Format kv3 source & make more readable cluster things --- public/tier1/keyvalues3.h | 17 ++-- tier1/keyvalues3.cpp | 168 ++++++++++++++++++++------------------ 2 files changed, 99 insertions(+), 86 deletions(-) diff --git a/public/tier1/keyvalues3.h b/public/tier1/keyvalues3.h index 14884fbc6..441b86834 100644 --- a/public/tier1/keyvalues3.h +++ b/public/tier1/keyvalues3.h @@ -111,9 +111,11 @@ PLATFORM_OVERLOAD bool SaveKV3Text_ToString( const KV3ID_t& format, const KeyVal PLATFORM_OVERLOAD bool SaveKV3Text_ToString( const KV3ID_t& format, const KeyValues3* kv, CUtlString* error, CUtlString* output, uint flags = KV3_SAVE_TEXT_NONE ); PLATFORM_OVERLOAD bool SaveKV3ToFile( const KV3ID_t& encoding, const KV3ID_t& format, const KeyValues3* kv, CUtlString* error, const char* filename, const char* path, uint flags = KV3_SAVE_TEXT_NONE ); -typedef int32 KV3MemberId_t; +using KV3MemberId_t = int32; #define KV3_INVALID_MEMBER ((KV3MemberId_t)-1) +#define KV3_INVALID_CLUSTER_ELEMENT (~0) + #define FOR_EACH_KV3_ARRAY( arrayName, iter ) \ for ( int iter = 0; iter < (arrayName).Count(); iter++ ) #define FOR_EACH_KV3_ARRAY_BACK( arrayName, iter ) \ @@ -697,8 +699,9 @@ class KeyValues3 void CopyFrom( const KeyValues3* pSrc ); void OverlayKeysFrom( KeyValues3 *parent, bool depth = false ); + bool HasCluster() const { return m_nClusterElement != KV3_INVALID_CLUSTER_ELEMENT; } int GetClusterElement() const { return m_nClusterElement; } - void SetClusterElement( int element ) { m_bContextIndependent = (element == -1); m_nClusterElement = element; } + void SetClusterElement( int element ) { m_bContextIndependent = ( element == KV3_INVALID_CLUSTER_ELEMENT ); m_nClusterElement = element; } CKeyValues3Cluster* GetCluster() const; template < typename T > T FromString( T defaultValue ) const; @@ -775,9 +778,10 @@ class CKeyValues3Array static const size_t DATA_SIZE = KV3_ARRAY_MAX_FIXED_MEMBERS; static const size_t DATA_ALIGNMENT = KV3Helpers::PackAlignOf(); - CKeyValues3Array( int cluster_elem = -1, int alloc_size = DATA_SIZE ); + CKeyValues3Array( int cluster_elem = KV3_INVALID_CLUSTER_ELEMENT, int alloc_size = DATA_SIZE ); ~CKeyValues3Array() { Free(); } + bool HasCluster() const { return m_nClusterElement != KV3_INVALID_CLUSTER_ELEMENT; } int GetClusterElement() const { return m_nClusterElement; } void SetClusterElement( int element ) { m_nClusterElement = element; } @@ -847,9 +851,10 @@ class CKeyValues3Table static const size_t DATA_SIZE = KV3_TABLE_MAX_FIXED_MEMBERS; static const size_t DATA_ALIGNMENT = KV3Helpers::PackAlignOf(); - CKeyValues3Table( int cluster_elem = -1, int alloc_size = DATA_SIZE ); + CKeyValues3Table( int cluster_elem = KV3_INVALID_CLUSTER_ELEMENT, int alloc_size = DATA_SIZE ); ~CKeyValues3Table() { Free(); } + bool HasCluster() const { return m_nClusterElement != KV3_INVALID_CLUSTER_ELEMENT; } int GetClusterElement() const { return m_nClusterElement; } void SetClusterElement( int element ) { m_nClusterElement = element; } @@ -1315,7 +1320,7 @@ inline T *KeyValues3::AllocateOnHeap( int initial_size ) initial_size = T::DATA_SIZE; auto element = (T *)g_pMemAlloc->RegionAlloc( MEMALLOC_REGION_ALLOC_4, T::TotalSizeOf( initial_size ) ); - Construct( element, -1, initial_size ); + Construct( element, KV3_INVALID_CLUSTER_ELEMENT, initial_size ); return element; } @@ -1633,7 +1638,7 @@ inline NODE *CKeyValues3ContextBase::NodeList::Alloc( int initial_size ) auto entry = Tail(); m_nUsedBytes = byte_size_needed; - Construct( &entry->m_Value, -1, initial_size ); + Construct( &entry->m_Value, KV3_INVALID_CLUSTER_ELEMENT, initial_size ); entry->m_pNext = Tail(); return &entry->m_Value; diff --git a/tier1/keyvalues3.cpp b/tier1/keyvalues3.cpp index e2fb71d68..da249bb00 100644 --- a/tier1/keyvalues3.cpp +++ b/tier1/keyvalues3.cpp @@ -10,7 +10,7 @@ #endif KeyValues3::KeyValues3( KV3TypeEx_t type, KV3SubType_t subtype ) : - KeyValues3( -1, type, subtype ) + KeyValues3( KV3_INVALID_CLUSTER_ELEMENT, type, subtype ) { } @@ -19,7 +19,7 @@ KeyValues3::KeyValues3( int cluster_elem, KV3TypeEx_t type, KV3SubType_t subtype m_TypeEx( type ), m_SubType( subtype ), m_nFlags( 0 ), - m_nClusterElement( (uint16)-1 ), + m_nClusterElement( (uint16)KV3_INVALID_CLUSTER_ELEMENT ), m_nNumArrayElements( 0 ), m_nReserved( 0 ) { @@ -39,7 +39,7 @@ void KeyValues3::Alloc( int initial_size, Data_t data, int preallocated_size, bo { case KV3_TYPEEX_ARRAY: { - if(preallocated_size <= 0) + if ( preallocated_size <= 0 ) { m_Data.m_pArray = AllocArray(); m_bFreeArrayMemory = true; @@ -53,7 +53,7 @@ void KeyValues3::Alloc( int initial_size, Data_t data, int preallocated_size, bo } case KV3_TYPEEX_TABLE: { - if(preallocated_size <= 0) + if ( preallocated_size <= 0 ) { m_Data.m_pTable = AllocTable(); m_bFreeArrayMemory = true; @@ -86,13 +86,13 @@ void KeyValues3::AllocArrayInPlace( int initial_size, Data_t data, int prealloca { int bytes_needed = MAX( CKeyValues3Array::TotalSizeOf( 0 ), CKeyValues3Array::TotalSizeOf( initial_size ) ); - if(bytes_needed > preallocated_size) + if ( bytes_needed > preallocated_size ) { Plat_FatalErrorFunc( "KeyValues3: pre-allocated array memory is too small for %u elements (%u bytes available, %u bytes needed)\n", initial_size, preallocated_size, bytes_needed ); DebuggerBreak(); } - Construct( data.m_pArray, -1, initial_size ); + Construct( data.m_pArray, KV3_INVALID_CLUSTER_ELEMENT, initial_size ); m_Data.m_pArray = data.m_pArray; m_bFreeArrayMemory = should_free; @@ -102,13 +102,13 @@ void KeyValues3::AllocTableInPlace( int initial_size, Data_t data, int prealloca { int bytes_needed = MAX( CKeyValues3Array::TotalSizeOf( 0 ), CKeyValues3Array::TotalSizeOf( initial_size ) ); - if(bytes_needed > preallocated_size) + if ( bytes_needed > preallocated_size ) { Plat_FatalErrorFunc( "KeyValues3: pre-allocated table memory is too small for %u members (%u bytes available, %u bytes needed)\n", initial_size, preallocated_size, bytes_needed ); DebuggerBreak(); } - Construct( data.m_pTable, -1, initial_size ); + Construct( data.m_pTable, KV3_INVALID_CLUSTER_ELEMENT, initial_size ); m_Data.m_pTable = data.m_pTable; m_bFreeArrayMemory = should_free; @@ -118,11 +118,11 @@ CKeyValues3Array *KeyValues3::AllocArray( int initial_size ) { auto context = GetContext(); - if(context) + if ( context ) { auto arr = context->AllocArray( initial_size ); - if(arr) + if ( arr ) return arr; } @@ -133,11 +133,11 @@ CKeyValues3Table* KeyValues3::AllocTable( int initial_size ) { auto context = GetContext(); - if(context) + if ( context ) { auto table = context->AllocTable( initial_size ); - if(table) + if ( table ) return table; } @@ -146,12 +146,12 @@ CKeyValues3Table* KeyValues3::AllocTable( int initial_size ) void KeyValues3::FreeArray( CKeyValues3Array *element, bool clearing_context ) { - if(!element) + if ( !element ) return; element->PurgeContent( this, clearing_context ); - if(!m_bFreeArrayMemory) + if ( !m_bFreeArrayMemory ) { Destruct( element ); } @@ -160,13 +160,13 @@ void KeyValues3::FreeArray( CKeyValues3Array *element, bool clearing_context ) auto context = GetContext(); bool raw_allocated = context && context->IsArrayRawAllocated( element ); - if(!raw_allocated && element->GetClusterElement() < 0) + if ( !raw_allocated && element->GetClusterElement() < 0 ) { FreeOnHeap( element ); } - else if(!clearing_context) + else if ( !clearing_context ) { - if(!raw_allocated) + if ( !raw_allocated ) context->FreeArray( element ); else Destruct( element ); @@ -176,12 +176,12 @@ void KeyValues3::FreeArray( CKeyValues3Array *element, bool clearing_context ) void KeyValues3::FreeTable( CKeyValues3Table *element, bool clearing_context ) { - if(!element) + if ( !element ) return; element->PurgeContent( this, clearing_context ); - if(!m_bFreeArrayMemory) + if ( !m_bFreeArrayMemory ) { Destruct( element ); } @@ -190,16 +190,16 @@ void KeyValues3::FreeTable( CKeyValues3Table *element, bool clearing_context ) auto context = GetContext(); bool raw_allocated = context && context->IsTableRawAllocated( element ); - if(!raw_allocated && element->GetClusterElement() < 0) + if ( !raw_allocated && element->GetClusterElement() < 0 ) { FreeOnHeap( element ); } - else if(!clearing_context) + else if ( !clearing_context ) { - if(!raw_allocated) - context->FreeTable( element ); - else + if ( raw_allocated ) Destruct( element ); + else + context->FreeTable( element ); } } } @@ -215,7 +215,7 @@ void KeyValues3::FreeMember( KeyValues3 *member ) { auto context = GetContext(); - if(context) + if ( context ) { auto cluster = member->GetCluster(); @@ -526,10 +526,10 @@ int KeyValues3::GetArrayElementCount() const { const CKeyValues3Array *pArray = GetArray(); - if ( !pArray ) - return 0; + if ( pArray ) + return pArray->Count(); - return IsArray() ? pArray->Count() : m_nNumArrayElements; + return m_nNumArrayElements; } KeyValues3** KeyValues3::GetArrayBase() @@ -554,11 +554,11 @@ KeyValues3* KeyValues3::GetArrayElement( int elem ) KeyValues3* KeyValues3::ArrayInsertElementBefore( int elem ) { - if ( !IsArray() ) - SetToEmptyArray(); - CKeyValues3Array *pArray = GetArray(); + if ( !pArray ) + SetToEmptyArray(); + Assert( pArray ); return *pArray->InsertMultipleBefore( this, elem, 1 ); @@ -566,11 +566,11 @@ KeyValues3* KeyValues3::ArrayInsertElementBefore( int elem ) KeyValues3* KeyValues3::ArrayAddElementToTail() { - if ( !IsArray() ) - SetToEmptyArray(); - CKeyValues3Array *pArray = GetArray(); + if ( !pArray ) + SetToEmptyArray(); + Assert( pArray ); return *pArray->InsertMultipleBefore( this, pArray->Count(), 1 ); @@ -583,10 +583,10 @@ void KeyValues3::ArraySwapItems( int idx1, int idx2 ) if ( !pArray ) return; - if(idx1 < 0 || idx1 >= pArray->Count()) + if ( idx1 < 0 || idx1 >= pArray->Count() ) return; - if(idx2 < 0 || idx2 >= pArray->Count()) + if ( idx2 < 0 || idx2 >= pArray->Count() ) return; auto base = pArray->Base(); @@ -598,12 +598,11 @@ void KeyValues3::ArraySwapItems( int idx1, int idx2 ) void KeyValues3::SetArrayElementCount( int count, KV3TypeEx_t type, KV3SubType_t subtype ) { - if ( !IsArray() ) - SetToEmptyArray(); - CKeyValues3Array *pArray = GetArray(); - Assert( pArray ); + if ( !pArray ) + SetToEmptyArray(); + pArray->SetCount( this, count, type, subtype ); } @@ -1248,7 +1247,7 @@ const char* KeyValues3::ToString( CBufferString& buff, uint flags ) const void KeyValues3::CopyFrom( const KeyValues3* pSrc ) { - if(this == pSrc) + if ( this == pSrc ) return; SetToNull(); @@ -1339,7 +1338,7 @@ void KeyValues3::OverlayKeysFrom( KeyValues3 *parent, bool depth ) { CKeyValues3Table *pTable = GetTable(); - if( !pTable ) + if ( !pTable ) SetToNull(); CKeyValues3Table *pParentTable = parent->GetTable(); @@ -1381,7 +1380,7 @@ void CKeyValues3Iterator::Init( KeyValues3 *kv ) { m_Stack.Purge(); - if(kv) + if ( kv ) { auto entry = m_Stack.AddToTailGetPtr(); entry->m_nIndex = -1; @@ -1391,16 +1390,16 @@ void CKeyValues3Iterator::Init( KeyValues3 *kv ) void CKeyValues3Iterator::Advance() { - while(m_Stack.Count() > 0) + while ( m_Stack.Count() > 0 ) { auto &entry = m_Stack[m_Stack.Count() - 1]; auto kv = entry.m_pKV; - if(kv->GetType() == KV3_TYPE_ARRAY) + if ( kv->GetType() == KV3_TYPE_ARRAY ) { entry.m_nIndex++; - if(entry.m_nIndex < kv->GetArrayElementCount()) + if ( entry.m_nIndex < kv->GetArrayElementCount() ) { auto new_entry = m_Stack.AddToTailGetPtr(); new_entry->m_nIndex = -1; @@ -1408,11 +1407,11 @@ void CKeyValues3Iterator::Advance() return; } } - else if(kv->GetType() == KV3_TYPE_TABLE) + else if ( kv->GetType() == KV3_TYPE_TABLE ) { entry.m_nIndex++; - if(entry.m_nIndex < kv->GetMemberCount()) + if ( entry.m_nIndex < kv->GetMemberCount() ) { auto new_entry = m_Stack.AddToTailGetPtr(); new_entry->m_nIndex = -1; @@ -1439,7 +1438,10 @@ CKeyValues3Array::CKeyValues3Array( int cluster_elem, int alloc_size ) : CKeyValues3ArrayCluster* CKeyValues3Array::GetCluster() const { - return m_nClusterElement == -1 ? nullptr : GET_OUTER( CKeyValues3ArrayCluster, m_Values[ m_nClusterElement ] ); + if ( !HasCluster() ) + return nullptr; + + return GET_OUTER( CKeyValues3ArrayCluster, m_Values[ m_nClusterElement ] ); } CKeyValues3Context* CKeyValues3Array::GetContext() const @@ -1458,10 +1460,10 @@ KeyValues3* CKeyValues3Array::Element( int i ) void CKeyValues3Array::EnsureElementCapacity( int count, bool force, bool dont_move ) { - if(count <= m_nAllocatedChunks) + if ( count <= m_nAllocatedChunks ) return; - if(count > ALLOC_KV3ARRAY_MAX) + if ( count > ALLOC_KV3ARRAY_MAX ) { Plat_FatalErrorFunc( "%s: element count overflow (%u)\n", __FUNCTION__, count ); DebuggerBreak(); @@ -1472,7 +1474,7 @@ void CKeyValues3Array::EnsureElementCapacity( int count, bool force, bool dont_m Element_t *new_base = nullptr; - if(m_bIsDynamicallySized) + if ( m_bIsDynamicallySized ) { new_base = (Element_t *)realloc( m_pDynamicElements, new_byte_size ); } @@ -1480,7 +1482,7 @@ void CKeyValues3Array::EnsureElementCapacity( int count, bool force, bool dont_m { new_base = (Element_t *)malloc( new_byte_size ); - if(m_nCount > 0 && !dont_move) + if ( m_nCount > 0 && !dont_move ) { memmove( new_base, Base(), sizeof( Element_t ) * m_nCount ); } @@ -1494,7 +1496,8 @@ void CKeyValues3Array::EnsureElementCapacity( int count, bool force, bool dont_m void CKeyValues3Array::SetCount( KeyValues3 *parent, int count, KV3TypeEx_t type, KV3SubType_t subtype ) { Element_t *elements_base = Base(); - for(int i = count; i < m_nCount; i++) + + for ( int i = count; i < m_nCount; i++ ) { parent->FreeMember( elements_base[i] ); } @@ -1502,7 +1505,7 @@ void CKeyValues3Array::SetCount( KeyValues3 *parent, int count, KV3TypeEx_t type EnsureElementCapacity( count ); elements_base = Base(); - for(int i = m_nCount; i < count; i++) + for ( int i = m_nCount; i < count; i++ ) { elements_base[i] = parent->AllocMember( type, subtype ); } @@ -1512,23 +1515,25 @@ void CKeyValues3Array::SetCount( KeyValues3 *parent, int count, KV3TypeEx_t type CKeyValues3Array::Element_t* CKeyValues3Array::InsertMultipleBefore( KeyValues3 *parent, int from, int num ) { - if(from < 0 || from > m_nCount) + if ( from < 0 || from > m_nCount ) { Plat_FatalErrorFunc( "%s: invalid insert point %u (current count %u)\n", __FUNCTION__, from, m_nCount ); DebuggerBreak(); } - if(num > ALLOC_KV3ARRAY_MAX - m_nCount) + if ( num > ALLOC_KV3ARRAY_MAX - m_nCount ) { Plat_FatalErrorFunc( "%s: max element overflow, cur count %u + %u\n", __FUNCTION__, m_nCount, num ); DebuggerBreak(); } int new_size = m_nCount + num; + EnsureElementCapacity( new_size ); Element_t *base = Base(); - if(from < m_nCount) + + if ( from < m_nCount ) { memmove( (void *)base[from + num], (void *)base[from], sizeof(Element_t) * (m_nCount - from) ); } @@ -1570,7 +1575,7 @@ void CKeyValues3Array::RemoveMultiple( KeyValues3 *parent, int from, int num ) void CKeyValues3Array::PurgeBuffers() { - if(m_bIsDynamicallySized) + if ( m_bIsDynamicallySized ) { free( m_pDynamicElements ); m_nAllocatedChunks = m_nInitialSize; @@ -1582,7 +1587,7 @@ void CKeyValues3Array::PurgeBuffers() void CKeyValues3Array::PurgeContent( KeyValues3 *parent, bool clearing_context ) { - if(!clearing_context && parent) + if ( !clearing_context && parent ) { auto elements_base = Base(); @@ -1608,7 +1613,7 @@ CKeyValues3Table::CKeyValues3Table( int cluster_elem, int alloc_size ) : CKeyValues3TableCluster* CKeyValues3Table::GetCluster() const { - if ( m_nClusterElement == -1 ) + if ( !HasCluster() ) return nullptr; return GET_OUTER( CKeyValues3TableCluster, m_Values[ m_nClusterElement ] ); @@ -1620,8 +1625,8 @@ CKeyValues3Context* CKeyValues3Table::GetContext() const if ( cluster ) return cluster->GetContext(); - else - return nullptr; + + return nullptr; } KeyValues3* CKeyValues3Table::GetMember( KV3MemberId_t id ) @@ -1665,10 +1670,10 @@ void CKeyValues3Table::EnableFastSearch() void CKeyValues3Table::EnsureMemberCapacity( int count, bool force, bool dont_move ) { - if(count <= m_nAllocatedChunks) + if ( count <= m_nAllocatedChunks ) return; - if(count > ALLOC_KV3TABLE_MAX) + if ( count > ALLOC_KV3TABLE_MAX ) { Plat_FatalErrorFunc( "%s member count overflow (%u)\n", __FUNCTION__, count ); DebuggerBreak(); @@ -1679,7 +1684,7 @@ void CKeyValues3Table::EnsureMemberCapacity( int count, bool force, bool dont_mo void *new_base = nullptr; - if(m_bIsDynamicallySized) + if ( m_bIsDynamicallySized ) { new_base = realloc( m_pDynamicBuffer, new_byte_size ); @@ -1691,7 +1696,7 @@ void CKeyValues3Table::EnsureMemberCapacity( int count, bool force, bool dont_mo { new_base = malloc( new_byte_size ); - if(m_nCount > 0 && !dont_move) + if ( m_nCount > 0 && !dont_move ) { memmove( (uint8 *)new_base + OffsetToHashesBase( new_count ), HashesBase(), m_nCount * sizeof( Hash_t ) ); memmove( (uint8 *)new_base + OffsetToMembersBase( new_count ), MembersBase(), m_nCount * sizeof( Member_t ) ); @@ -1780,22 +1785,25 @@ KV3MemberId_t CKeyValues3Table::CreateMember( KeyValues3 *parent, const CKV3Memb members_base[curr] = parent->AllocMember(); hashes_base[curr] = name.GetHashCode(); - Flags_t flags = 0; - if(name_external) + auto &curr_name = names_base[curr]; + auto &flags = flags_base[curr]; + + if ( name_external ) { - names_base[curr] = name.GetString(); + curr_name = name.GetString(); flags |= MEMBER_FLAG_EXTERNAL_NAME; } else { auto context = parent->GetContext(); - names_base[curr] = context ? context->AllocString( name.GetString() ) : strdup( name.GetString() ); + if ( context ) + curr_name = context->AllocString( name.GetString() ); + else + curr_name = strdup( name.GetString() ); } - flags_base[curr] = flags; - if ( m_pFastSearch && !m_pFastSearch->m_ignore ) m_pFastSearch->m_member_ids.Insert( name.GetHashCode(), curr ); @@ -1825,7 +1833,7 @@ void CKeyValues3Table::CopyFrom( KeyValues3 *parent, const CKeyValues3Table* src memmove( hashes_base, src_hashes_base, sizeof(Hash_t) * new_size ); - for(int i = 0; i < new_size; i++) + for ( int i = 0; i < new_size; i++ ) { flags_base[i] = src_flags_base[i] & ~MEMBER_FLAG_EXTERNAL_NAME; names_base[i] = context ? context->AllocString( src_names_base[i] ) : strdup( src_names_base[i] ); @@ -1882,7 +1890,7 @@ void CKeyValues3Table::RemoveMember( KeyValues3 *parent, KV3MemberId_t id ) parent->FreeMember( members_base[id] ); - if((flags_base[id] & MEMBER_FLAG_EXTERNAL_NAME) == 0 && !parent->GetContext() && names_base[id]) + if ( ( flags_base[id] & MEMBER_FLAG_EXTERNAL_NAME ) == 0 && !parent->GetContext() && names_base[id] ) { free( (void *)names_base[id] ); } @@ -1915,19 +1923,19 @@ void CKeyValues3Table::RemoveAll( KeyValues3 *parent, int new_size ) { parent->FreeMember( members_base[i] ); - if((flags_base[i] & MEMBER_FLAG_EXTERNAL_NAME) == 0 && !parent->GetContext() && names_base[i]) + if ( ( flags_base[i] & MEMBER_FLAG_EXTERNAL_NAME ) == 0 && !parent->GetContext() && names_base[i] ) { free( (void *)names_base[i] ); } } m_nCount = 0; - if(new_size > 0) + if ( new_size > 0 ) { EnsureMemberCapacity( new_size, true, true ); } - if(new_size < 128) + if ( new_size < 128 ) { PurgeFastSearch(); } @@ -1954,12 +1962,12 @@ void CKeyValues3Table::PurgeContent( KeyValues3 *parent, bool bClearingContext ) for ( int i = 0; i < m_nCount; ++i ) { - if(!bClearingContext && parent) + if ( !bClearingContext && parent ) { parent->FreeMember( members_base[i] ); } - if((flags_base[i] & MEMBER_FLAG_EXTERNAL_NAME) == 0 && parent && !parent->GetContext() && names_base[i]) + if ( ( flags_base[i] & MEMBER_FLAG_EXTERNAL_NAME ) == 0 && parent && !parent->GetContext() && names_base[i] ) { free( (void *)names_base[i] ); } From cfcd8355c16cd0a3ca7db7b756bf526df52f507f Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 08:02:19 +0300 Subject: [PATCH 26/30] Correct kv3(array/table) getting ones --- tier1/keyvalues3.cpp | 48 +++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/tier1/keyvalues3.cpp b/tier1/keyvalues3.cpp index da249bb00..a8732b6a9 100644 --- a/tier1/keyvalues3.cpp +++ b/tier1/keyvalues3.cpp @@ -536,10 +536,10 @@ KeyValues3** KeyValues3::GetArrayBase() { CKeyValues3Array *pArray = GetArray(); - if ( !pArray ) - return nullptr; + if ( pArray ) + return pArray->Base(); - return pArray->Base(); + return nullptr; } KeyValues3* KeyValues3::GetArrayElement( int elem ) @@ -554,24 +554,18 @@ KeyValues3* KeyValues3::GetArrayElement( int elem ) KeyValues3* KeyValues3::ArrayInsertElementBefore( int elem ) { - CKeyValues3Array *pArray = GetArray(); - - if ( !pArray ) + if ( !IsArray() ) SetToEmptyArray(); - Assert( pArray ); - - return *pArray->InsertMultipleBefore( this, elem, 1 ); + return *GetArray()->InsertMultipleBefore( this, elem, 1 ); } KeyValues3* KeyValues3::ArrayAddElementToTail() { - CKeyValues3Array *pArray = GetArray(); - - if ( !pArray ) + if ( !IsArray() ) SetToEmptyArray(); - Assert( pArray ); + CKeyValues3Array *pArray = GetArray(); return *pArray->InsertMultipleBefore( this, pArray->Count(), 1 ); } @@ -598,12 +592,10 @@ void KeyValues3::ArraySwapItems( int idx1, int idx2 ) void KeyValues3::SetArrayElementCount( int count, KV3TypeEx_t type, KV3SubType_t subtype ) { - CKeyValues3Array *pArray = GetArray(); - - if ( !pArray ) + if ( !IsArray() ) SetToEmptyArray(); - pArray->SetCount( this, count, type, subtype ); + GetArray()->SetCount( this, count, type, subtype ); } void KeyValues3::ArrayRemoveElements( int elem, int num ) @@ -787,7 +779,10 @@ int KeyValues3::GetMemberCount() const { const CKeyValues3Table *pTable = GetTable(); - return pTable ? pTable->GetMemberCount() : 0; + if ( pTable ) + return pTable->GetMemberCount(); + + return KV3_INVALID_MEMBER; } KeyValues3* KeyValues3::GetMember( KV3MemberId_t id ) @@ -847,13 +842,11 @@ KeyValues3* KeyValues3::Internal_FindMember( const CKV3MemberName &name, KV3Memb KeyValues3* KeyValues3::FindOrCreateMember( const CKV3MemberName &name, bool *pCreated ) { - if ( GetType() != KV3_TYPE_TABLE ) + if ( !IsTable() ) SetToEmptyTable(); CKeyValues3Table *pTable = GetTable(); - Assert( pTable ); - KV3MemberId_t id = pTable->FindMember( name ); if ( id == KV3_INVALID_MEMBER ) @@ -1336,9 +1329,7 @@ void KeyValues3::CopyFrom( const KeyValues3* pSrc ) void KeyValues3::OverlayKeysFrom( KeyValues3 *parent, bool depth ) { - CKeyValues3Table *pTable = GetTable(); - - if ( !pTable ) + if ( !IsTable() ) SetToNull(); CKeyValues3Table *pParentTable = parent->GetTable(); @@ -1439,16 +1430,19 @@ CKeyValues3Array::CKeyValues3Array( int cluster_elem, int alloc_size ) : CKeyValues3ArrayCluster* CKeyValues3Array::GetCluster() const { if ( !HasCluster() ) - return nullptr; + return GET_OUTER( CKeyValues3ArrayCluster, m_Values[ m_nClusterElement ] ); - return GET_OUTER( CKeyValues3ArrayCluster, m_Values[ m_nClusterElement ] ); + return nullptr; } CKeyValues3Context* CKeyValues3Array::GetContext() const { CKeyValues3ArrayCluster* cluster = GetCluster(); - return cluster ? cluster->GetContext() : nullptr; + if ( cluster ) + return cluster->GetContext(); + + return nullptr; } KeyValues3* CKeyValues3Array::Element( int i ) From c1ee0837e1e609c87dd92288693aa17f60dfd63d Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 10:24:15 +0300 Subject: [PATCH 27/30] HL2SDK: resolve include conflicts & fix errors --- public/tier0/fasttimer.h | 8 ++--- public/tier1/bufferstring.h | 4 +-- public/tier1/utlcommon.h | 52 +++++++++++++++++++++++++++- public/tier1/utlstring.h | 65 +++++------------------------------ public/tier1/utlstringtoken.h | 16 ++++----- public/tier1/utlsymbol.h | 2 +- public/tier1/utlsymbollarge.h | 2 +- 7 files changed, 72 insertions(+), 77 deletions(-) diff --git a/public/tier0/fasttimer.h b/public/tier0/fasttimer.h index 9778cc765..11bdc119d 100644 --- a/public/tier0/fasttimer.h +++ b/public/tier0/fasttimer.h @@ -1,4 +1,4 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -84,16 +84,14 @@ class CClockSpeedInit static void Init() { - const CPUInformation& pi = GetCPUInformation(); - if ( !IsX360() ) { - g_ClockSpeed = pi.m_Speed; + g_ClockSpeed = Plat_CPUTickFrequency(); } else { // cycle counter runs as doc'd at 1/64 Xbox 3.2GHz clock speed, thus 50 Mhz - g_ClockSpeed = pi.m_Speed / 64L; + g_ClockSpeed = Plat_CPUTickFrequency() / 64L; } g_dwClockSpeed = (unsigned long)g_ClockSpeed; diff --git a/public/tier1/bufferstring.h b/public/tier1/bufferstring.h index 377e33089..b4df7f75e 100644 --- a/public/tier1/bufferstring.h +++ b/public/tier1/bufferstring.h @@ -9,9 +9,9 @@ #include #undef __need_size_t -#include "tier0/platform.h" #include "strtools.h" -#include "utlstring.h" +#include "tier0/platform.h" +#include "tier1/utlcommon.h" class CFormatStringElement; class IFormatOutputStream; diff --git a/public/tier1/utlcommon.h b/public/tier1/utlcommon.h index e75f7e168..d08efa029 100644 --- a/public/tier1/utlcommon.h +++ b/public/tier1/utlcommon.h @@ -10,7 +10,6 @@ #define UTLCOMMON_H #pragma once -#include "utlstring.h" #include "type_traits" //----------------------------------------------------------------------------- @@ -135,6 +134,55 @@ struct PointerLessFunctor { bool operator()( const void *a, const void *b ) cons 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)); } }; +//----------------------------------------------------------------------------- +// 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 +{ +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( 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 +{ +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( 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)"; } +}; + // Generic implementation of Less and Equal functors template < typename T > @@ -153,6 +201,8 @@ struct DefaultEqualFunctor bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Alt_t b ) const { return a == b; } }; +class CUtlStringToken; + // Hashes for basic types template <> struct DefaultHashFunctor : Mix32HashFunctor { }; template <> struct DefaultHashFunctor : Mix32HashFunctor { }; diff --git a/public/tier1/utlstring.h b/public/tier1/utlstring.h index 87cc8521a..4d4182243 100644 --- a/public/tier1/utlstring.h +++ b/public/tier1/utlstring.h @@ -10,10 +10,10 @@ #pragma once #endif -#include "tier1/utlstringtoken.h" +#include +#include "strtools.h" +#include "tier1/utlcommon.h" #include "tier1/utlmemory.h" -#include "tier1/strtools.h" -#include "limits.h" #if defined( OSX ) inline wchar_t *wcsdup(const wchar_t *pString) @@ -148,8 +148,8 @@ class CUtlString DLL_CLASS_IMPORT 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); + static int SortCaseInsensitive(const CUtlString *pString1, const CUtlString *pString2); + static int SortCaseSensitive(const CUtlString *pString1, const CUtlString *pString2); DLL_CLASS_IMPORT void Purge(); void Clear() { Purge(); } @@ -303,7 +303,7 @@ inline const char *CUtlString::Get() const { if(!m_pString) { - return ""; + return StringFuncs::EmptyString(); } return m_pString; } @@ -322,67 +322,18 @@ inline bool CUtlString::IsEmpty() const return !m_pString || m_pString[0] == 0; } -inline int __cdecl CUtlString::SortCaseInsensitive( const CUtlString *pString1, const CUtlString *pString2 ) +inline int 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 ) +inline int 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 -{ -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( 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 -{ -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( 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. diff --git a/public/tier1/utlstringtoken.h b/public/tier1/utlstringtoken.h index 771137f0f..5769e097d 100644 --- a/public/tier1/utlstringtoken.h +++ b/public/tier1/utlstringtoken.h @@ -22,8 +22,8 @@ #define STRINGTOKEN_MURMURHASH_SEED 0x31415926 // Macros are intended to be used between CUtlStringToken (always lowercase) -#define MAKE_STRINGTOKEN(pstr) CUtlStringToken::Hash( (pstr), strlen(pstr), STRINGTOKEN_MURMURHASH_SEED ) -#define MAKE_STRINGTOKEN_UTL(containerName) CUtlStringToken::Hash( (containerName).Get(), (containerName).Length(), STRINGTOKEN_MURMURHASH_SEED ) +#define MAKE_STRINGTOKEN_HASH(pstr) CUtlStringToken::Hash( (pstr), strlen(pstr), STRINGTOKEN_MURMURHASH_SEED ) +#define MAKE_STRINGTOKEN_HASH_UTL(containerName) CUtlStringToken::Hash( (containerName).Get(), (containerName).Length(), STRINGTOKEN_MURMURHASH_SEED ) class IFormatOutputStream; class CFormatStringElement; @@ -95,29 +95,25 @@ class CUtlStringToken CUtlStringToken( uint32 nHashCode = 0 ) : m_nHashCode( nHashCode ) {} template < uintp N > FORCEINLINE constexpr CUtlStringToken( const char (&str)[N] ) : m_nHashCode( Hash( str, N - 1 ) ) {} CUtlStringToken( const char *pString, int nLen ) : m_nHashCode( Hash( pString, nLen ) ) {} - CUtlStringToken( const CUtlString &str ) : CUtlStringToken( str.Get(), str.Length() ) {} CUtlStringToken( const CBufferString &buffer ) : CUtlStringToken( buffer.Get(), buffer.Length() ) {} // operator== bool operator==( const uint32 nHash ) const { return m_nHashCode == nHash; } bool operator==( const CUtlStringToken &other ) const { return operator==( other.GetHashCode() ); } - bool operator==( const char *pString ) const { return operator==( MAKE_STRINGTOKEN( pString ) ); } - bool operator==( const CUtlString &str ) const { return operator==( MAKE_STRINGTOKEN_UTL( str ) ); } - bool operator==( const CBufferString &buffer ) const { return operator==( MAKE_STRINGTOKEN_UTL( buffer ) ); } + bool operator==( const char *pString ) const { return operator==( MAKE_STRINGTOKEN_HASH( pString ) ); } + bool operator==( const CBufferString &buffer ) const { return operator==( MAKE_STRINGTOKEN_HASH_UTL( buffer ) ); } // operator!= bool operator!=( const uint32 nHash ) const { return !operator==( nHash ); } bool operator!=( const CUtlStringToken &other ) const { return !operator==( other ); } bool operator!=( const char *pString ) const { return !operator==( pString ); } - bool operator!=( const CUtlString &str ) const { return !operator==( str ); } bool operator!=( const CBufferString &buffer ) const { return !operator==( buffer ); } // opertator< bool operator<( const uint32 nHash ) const { return ( m_nHashCode < nHash ); } bool operator<( CUtlStringToken const &other ) const { return operator<( other.GetHashCode() ); } - bool operator<( const char *pString ) const { return operator<( MAKE_STRINGTOKEN( pString ) ); } - bool operator<( const CUtlString &str ) const { return !operator<( MAKE_STRINGTOKEN_UTL( str ) ); } - bool operator<( const CBufferString &buffer ) const { return !operator<( MAKE_STRINGTOKEN_UTL( buffer ) ); } + bool operator<( const char *pString ) const { return operator<( MAKE_STRINGTOKEN_HASH( pString ) ); } + bool operator<( const CBufferString &buffer ) const { return !operator<( MAKE_STRINGTOKEN_HASH_UTL( buffer ) ); } /// access to the hash code for people who need to store thse as 32-bits, regardless of the operator uint32() const { return m_nHashCode; } diff --git a/public/tier1/utlsymbol.h b/public/tier1/utlsymbol.h index 18584e11e..a19da4d02 100644 --- a/public/tier1/utlsymbol.h +++ b/public/tier1/utlsymbol.h @@ -207,7 +207,7 @@ class CUtlSymbolTable }; typedef CUtlHashtable Hashtable_t; - typedef CUtlVector MemBlocksVec_t; + typedef CUtlVector MemBlocksVec_t; const Hashtable_t &GetHashtable() const { diff --git a/public/tier1/utlsymbollarge.h b/public/tier1/utlsymbollarge.h index 87c50823c..858e21628 100644 --- a/public/tier1/utlsymbollarge.h +++ b/public/tier1/utlsymbollarge.h @@ -274,7 +274,7 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT entry->Replace( hash, pString, nLength ); - UtlSymLargeId_t id = m_MemBlocks.AddToTail( block + sizeof( LargeSymbolTableHashDecoration_t ) ); + UtlSymLargeElm_t elem = m_MemBlocks.AddToTail( block + sizeof( LargeSymbolTableHashDecoration_t ) ); m_HashTable.Insert( elem, empty_t(), hash ); From 145f2f91496fef62ee015f35c6e36dad78a70675 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 09:35:32 +0300 Subject: [PATCH 28/30] HL2SDK: fix `FOR_EACH_KV3` macro To prevent non-kv3(array/table) values into a loop body --- tier1/keyvalues3.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tier1/keyvalues3.cpp b/tier1/keyvalues3.cpp index a8732b6a9..de81f3655 100644 --- a/tier1/keyvalues3.cpp +++ b/tier1/keyvalues3.cpp @@ -1376,6 +1376,8 @@ void CKeyValues3Iterator::Init( KeyValues3 *kv ) auto entry = m_Stack.AddToTailGetPtr(); entry->m_nIndex = -1; entry->m_pKV = kv; + + Advance(); } } From 111a6bf5380bfe77ad9ab4f60d3daabdb393e0f6 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 12:26:20 +0300 Subject: [PATCH 29/30] Fix kv3table & cluster issues --- public/tier1/keyvalues3.h | 73 ++++++++++++++----------- tier1/keyvalues3.cpp | 112 ++++++++++++++++++++++---------------- 2 files changed, 108 insertions(+), 77 deletions(-) diff --git a/public/tier1/keyvalues3.h b/public/tier1/keyvalues3.h index 441b86834..e6493aca1 100644 --- a/public/tier1/keyvalues3.h +++ b/public/tier1/keyvalues3.h @@ -295,6 +295,24 @@ enum KeyValues3Flag_t : uint8 KEYVALUES3_FLAG_LAST_VALUE = (1 << 2) }; +union KeyValues3Array_t +{ + float32* m_f32; + Vector *m_vec; + Vector2D *m_vec2; + Vector4D *m_vec4; + Quaternion *m_quat; + QAngle *m_ang; + matrix3x4_t *m_mat; + float64* m_f64; + int16* m_i16; + int32* m_i32; + uint8 m_u8Short[8]; + int16 m_i16Short[4]; + + CKeyValues3Array* m_pRoot; +}; + namespace KV3Helpers { template @@ -460,6 +478,11 @@ class KeyValues3 bool IsNull() const { return GetType() == KV3_TYPE_NULL; } void SetToNull() { PrepareForType( KV3_TYPEEX_NULL, KV3_SUBTYPE_NULL ); } + bool IsArray() const { return GetType() == KV3_TYPE_ARRAY; } + bool IsKV3Array() const { return GetTypeEx() == KV3_TYPEEX_ARRAY; } + bool IsTable() const { return GetType() == KV3_TYPE_TABLE; } + bool IsString() const { return GetType() == KV3_TYPE_STRING; } + bool GetBool( bool defaultValue = false ) const { return GetValue( defaultValue ); } char8 GetChar( char8 defaultValue = 0 ) const { return GetValue( defaultValue ); } uchar32 GetUChar32( uchar32 defaultValue = 0 ) const { return GetValue( defaultValue ); } @@ -523,14 +546,15 @@ class KeyValues3 void SetQAngle( const QAngle &ang ) { SetVecBasedObj( ang, 3, KV3_SUBTYPE_QANGLE ); } void SetMatrix3x4( const matrix3x4_t &matrix ) { SetVecBasedObj( matrix, 3*4, KV3_SUBTYPE_MATRIX3X4 ); } - bool IsArray() const { return GetType() == KV3_TYPE_ARRAY; } - CKeyValues3Array *GetArray() { return IsArray() ? m_Data.m_pArray : nullptr; } - const CKeyValues3Array *GetArray() const { return const_cast(this)->GetArray(); }; + KeyValues3Array_t *GetArray() { return IsArray() ? &m_Data.m_Array : nullptr; } + const KeyValues3Array_t *GetArray() const { return const_cast(this)->GetArray(); }; + CKeyValues3Array *GetKV3Array() { return IsKV3Array() ? m_Data.m_Array.m_pRoot : nullptr; } + const CKeyValues3Array *GetKV3Array() const { return const_cast(this)->GetKV3Array(); }; int GetArrayElementCount() const; void SetArrayElementCount( int count, KV3TypeEx_t type = KV3_TYPEEX_NULL, KV3SubType_t subtype = KV3_SUBTYPE_UNSPECIFIED ); - void SetToEmptyArray() { PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY ); } + void SetToEmptyKV3Array() { PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY ); } KeyValues3** GetArrayBase(); KeyValues3* GetArrayElement( int elem ); @@ -545,7 +569,6 @@ class KeyValues3 void ArrayRemoveElements( int elem, int num ); void ArrayRemoveElement( int elem ) { ArrayRemoveElements( elem, 1 ); } - bool IsTable() const { return GetType() == KV3_TYPE_TABLE; } CKeyValues3Table *GetTable() { return IsTable() ? m_Data.m_pTable : nullptr; } const CKeyValues3Table *GetTable() const { return const_cast(this)->GetTable(); } @@ -596,7 +619,7 @@ class KeyValues3 matrix3x4_t GetMemberMatrix3x4( const CKV3MemberName &name, const matrix3x4_t &defaultValue = matrix3x4_t( Vector( 0.0f, 0.0f, 0.0f ), Vector( 0.0f, 0.0f, 0.0f ), Vector( 0.0f, 0.0f, 0.0f ), Vector( 0.0f, 0.0f, 0.0f ) ) ) const { auto kv = FindMember( name ); return kv ? kv->GetMatrix3x4( defaultValue ) : defaultValue; } void SetMemberToNull( const CKV3MemberName &name ) { FindOrCreateMember( name )->SetToNull(); } - void SetMemberToEmptyArray( const CKV3MemberName &name ) { FindOrCreateMember( name )->SetToEmptyArray(); } + void SetMemberToEmptyArray( const CKV3MemberName &name ) { FindOrCreateMember( name )->SetToEmptyKV3Array(); } void SetMemberToEmptyTable( const CKV3MemberName &name ) { FindOrCreateMember( name )->SetToEmptyTable(); } void SetMemberToBinaryBlob( const CKV3MemberName &name, const byte *blob, int size ) { FindOrCreateMember( name )->SetToBinaryBlob( blob, size ); } void SetMemberToBinaryBlobExternal( const CKV3MemberName &name, const byte *blob, int size, bool free_mem ) { FindOrCreateMember( name )->SetToBinaryBlobExternal( blob, size, free_mem ); } @@ -648,25 +671,9 @@ class KeyValues3 KV3BinaryBlob_t* m_pBinaryBlob; - CKeyValues3Array* m_pArray; + KeyValues3Array_t m_Array; CKeyValues3Table* m_pTable; - union Array_t - { - float32* m_f32; - Vector *m_vec; - Vector2D *m_vec2; - Vector4D *m_vec4; - Quaternion *m_quat; - QAngle *m_ang; - matrix3x4_t *m_mat; - float64* m_f64; - int16* m_i16; - int32* m_i32; - uint8 m_u8Short[8]; - int16 m_i16Short[4]; - } m_Array; - uint64 m_nMemory; void* m_pMemory; char m_Memory[1]; @@ -1198,8 +1205,8 @@ class CKeyValues3Context : public CKeyValues3ContextBase template void PurgeClusterNodeChain( ClusterNodeChain &cluster_node ); - bool IsArrayRawAllocated( CKeyValues3Array *element ) { return m_RawArrayEntries.IsWithinRange( element ); } - bool IsTableRawAllocated( CKeyValues3Table *element ) { return m_RawTableEntries.IsWithinRange( element ); } + bool IsArrayAllocated( CKeyValues3Array *element ) { return m_RawArrayEntries.IsWithinRange( element ); } + bool IsTableAllocated( CKeyValues3Table *element ) { return m_RawTableEntries.IsWithinRange( element ); } private: template @@ -1303,10 +1310,12 @@ void KeyValues3::NormalizeArray( KV3TypeEx_t type, KV3SubType_t subtype, int siz m_TypeEx = KV3_TYPEEX_ARRAY; Alloc( size ); - m_Data.m_pArray->SetCount( this, size, type, subtype ); + CKeyValues3Array *pNewArray = m_Data.m_Array.m_pRoot; + + pNewArray->SetCount( this, size, type, subtype ); - CKeyValues3Array::Element_t* arr = m_Data.m_pArray->Base(); - for ( int i = 0; i < m_Data.m_pArray->Count(); ++i ) + CKeyValues3Array::Element_t* arr = pNewArray->Base(); + for ( int i = 0; i < pNewArray->Count(); ++i ) arr[ i ]->SetDirect( data[ i ] ); if ( bFree ) @@ -1388,10 +1397,12 @@ void KeyValues3::AllocArray( int size, const T* data, KV3ArrayAllocType_t alloc_ { PrepareForType( KV3_TYPEEX_ARRAY, subtype ); - m_Data.m_pArray->SetCount( this, size, type_elem, subtype_elem ); + CKeyValues3Array *pNewArray = m_Data.m_Array.m_pRoot; + + pNewArray->SetCount( this, size, type_elem, subtype_elem ); - CKeyValues3Array::Element_t* arr = m_Data.m_pArray->Base(); - for ( int i = 0; i < m_Data.m_pArray->Count(); ++i ) + CKeyValues3Array::Element_t* arr = pNewArray->Base(); + for ( int i = 0; i < pNewArray->Count(); ++i ) arr[ i ]->SetValue( data[ i ], type_elem, subtype_elem ); if ( alloc_type == KV3_ARRAY_ALLOC_EXTERN_FREE ) diff --git a/tier1/keyvalues3.cpp b/tier1/keyvalues3.cpp index de81f3655..1e6454726 100644 --- a/tier1/keyvalues3.cpp +++ b/tier1/keyvalues3.cpp @@ -41,7 +41,7 @@ void KeyValues3::Alloc( int initial_size, Data_t data, int preallocated_size, bo { if ( preallocated_size <= 0 ) { - m_Data.m_pArray = AllocArray(); + m_Data.m_Array.m_pRoot = AllocArray(); m_bFreeArrayMemory = true; } else @@ -92,9 +92,9 @@ void KeyValues3::AllocArrayInPlace( int initial_size, Data_t data, int prealloca DebuggerBreak(); } - Construct( data.m_pArray, KV3_INVALID_CLUSTER_ELEMENT, initial_size ); + Construct( m_Data.m_Array.m_pRoot, KV3_INVALID_CLUSTER_ELEMENT, initial_size ); - m_Data.m_pArray = data.m_pArray; + m_Data.m_Array.m_pRoot = data.m_Array.m_pRoot; m_bFreeArrayMemory = should_free; } @@ -158,7 +158,7 @@ void KeyValues3::FreeArray( CKeyValues3Array *element, bool clearing_context ) else { auto context = GetContext(); - bool raw_allocated = context && context->IsArrayRawAllocated( element ); + bool raw_allocated = context && context->IsArrayAllocated( element ); if ( !raw_allocated && element->GetClusterElement() < 0 ) { @@ -188,7 +188,7 @@ void KeyValues3::FreeTable( CKeyValues3Table *element, bool clearing_context ) else { auto context = GetContext(); - bool raw_allocated = context && context->IsTableRawAllocated( element ); + bool raw_allocated = context && context->IsTableAllocated( element ); if ( !raw_allocated && element->GetClusterElement() < 0 ) { @@ -258,10 +258,10 @@ void KeyValues3::Free( bool bClearingContext ) } case KV3_TYPEEX_ARRAY: { - FreeArray( m_Data.m_pArray, bClearingContext ); + FreeArray( m_Data.m_Array.m_pRoot, bClearingContext ); m_bFreeArrayMemory = false; - m_Data.m_pArray = nullptr; + m_Data.m_Array.m_pRoot = nullptr; break; } @@ -368,14 +368,20 @@ void KeyValues3::PrepareForType( KV3TypeEx_t type, KV3SubType_t subtype, int ini CKeyValues3Cluster* KeyValues3::GetCluster() const { - return m_bContextIndependent ? nullptr : GET_OUTER( CKeyValues3Cluster, m_Values[ m_nClusterElement ] ); + if ( !m_bContextIndependent ) + return nullptr; + + return GET_OUTER( CKeyValues3Cluster, m_Values[ m_nClusterElement ] ); } CKeyValues3Context* KeyValues3::GetContext() const { CKeyValues3Cluster* cluster = GetCluster(); - return cluster ? cluster->GetContext() : nullptr; + if ( !cluster ) + return nullptr; + + return cluster->GetContext(); } KV3MetaData_t* KeyValues3::GetMetaData( CKeyValues3Context** ppCtx ) const @@ -524,27 +530,32 @@ void KeyValues3::SetColor( const Color &color ) int KeyValues3::GetArrayElementCount() const { - const CKeyValues3Array *pArray = GetArray(); + if ( IsArray() ) + { + const CKeyValues3Array *pArray = GetKV3Array(); + + if ( !pArray ) + return m_nNumArrayElements; - if ( pArray ) return pArray->Count(); + } - return m_nNumArrayElements; + return -1; } KeyValues3** KeyValues3::GetArrayBase() { - CKeyValues3Array *pArray = GetArray(); + CKeyValues3Array *pArray = GetKV3Array(); - if ( pArray ) - return pArray->Base(); + if ( !pArray ) + return nullptr; - return nullptr; + return pArray->Base(); } KeyValues3* KeyValues3::GetArrayElement( int elem ) { - CKeyValues3Array *pArray = GetArray(); + CKeyValues3Array *pArray = GetKV3Array(); if ( !pArray || elem < 0 || elem >= pArray->Count() ) return nullptr; @@ -554,25 +565,25 @@ KeyValues3* KeyValues3::GetArrayElement( int elem ) KeyValues3* KeyValues3::ArrayInsertElementBefore( int elem ) { - if ( !IsArray() ) - SetToEmptyArray(); + if ( !IsKV3Array() ) + SetToEmptyKV3Array(); - return *GetArray()->InsertMultipleBefore( this, elem, 1 ); + return *GetKV3Array()->InsertMultipleBefore( this, elem, 1 ); } KeyValues3* KeyValues3::ArrayAddElementToTail() { if ( !IsArray() ) - SetToEmptyArray(); + SetToEmptyKV3Array(); - CKeyValues3Array *pArray = GetArray(); + CKeyValues3Array *pArray = GetKV3Array(); return *pArray->InsertMultipleBefore( this, pArray->Count(), 1 ); } void KeyValues3::ArraySwapItems( int idx1, int idx2 ) { - CKeyValues3Array *pArray = GetArray(); + CKeyValues3Array *pArray = GetKV3Array(); if ( !pArray ) return; @@ -592,15 +603,15 @@ void KeyValues3::ArraySwapItems( int idx1, int idx2 ) void KeyValues3::SetArrayElementCount( int count, KV3TypeEx_t type, KV3SubType_t subtype ) { - if ( !IsArray() ) - SetToEmptyArray(); + if ( !IsKV3Array() ) + SetToEmptyKV3Array(); - GetArray()->SetCount( this, count, type, subtype ); + GetKV3Array()->SetCount( this, count, type, subtype ); } void KeyValues3::ArrayRemoveElements( int elem, int num ) { - CKeyValues3Array *pArray = GetArray(); + CKeyValues3Array *pArray = GetKV3Array(); if ( !pArray ) return; @@ -655,7 +666,7 @@ bool KeyValues3::ReadArrayInt32( int dest_size, int32* data ) const { int src_size = 0; - if ( GetType() == KV3_TYPE_STRING ) + if ( IsString() ) { CSplitString values( GetString(), " " ); src_size = values.Count(); @@ -669,9 +680,11 @@ bool KeyValues3::ReadArrayInt32( int dest_size, int32* data ) const { case KV3_TYPEEX_ARRAY: { - src_size = m_Data.m_pArray->Count(); + CKeyValues3Array *pArray = m_Data.m_Array.m_pRoot; + + src_size = pArray->Count(); int count = MIN( src_size, dest_size ); - KeyValues3** arr = m_Data.m_pArray->Base(); + KeyValues3** arr = pArray->Base(); for ( int i = 0; i < count; ++i ) data[ i ] = arr[ i ]->GetInt(); break; @@ -722,7 +735,7 @@ bool KeyValues3::ReadArrayFloat32( int dest_size, float32* data ) const { int src_size = 0; - if ( GetType() == KV3_TYPE_STRING ) + if ( IsString() ) { CSplitString values( GetString(), " " ); src_size = values.Count(); @@ -736,9 +749,11 @@ bool KeyValues3::ReadArrayFloat32( int dest_size, float32* data ) const { case KV3_TYPEEX_ARRAY: { - src_size = m_Data.m_pArray->Count(); + CKeyValues3Array *pArray = m_Data.m_Array.m_pRoot; + + src_size = pArray->Count(); int count = MIN( src_size, dest_size ); - KeyValues3** arr = m_Data.m_pArray->Base(); + KeyValues3** arr = pArray->Base(); for ( int i = 0; i < count; ++i ) data[ i ] = arr[ i ]->GetFloat(); break; @@ -758,7 +773,7 @@ bool KeyValues3::ReadArrayFloat32( int dest_size, float32* data ) const data[ i ] = ( float32 )m_Data.m_Array.m_f64[ i ]; break; } - default: + default: break; } } @@ -1114,7 +1129,7 @@ const char* KeyValues3::ToString( CBufferString& buff, uint flags ) const bool unprintable = false; CBufferStringN<128> temp; - CKeyValues3Array::Element_t* arr = m_Data.m_pArray->Base(); + CKeyValues3Array::Element_t* arr = m_Data.m_Array.m_pRoot->Base(); for ( int i = 0; i < elements; ++i ) { switch ( arr[i]->GetType() ) @@ -1286,8 +1301,8 @@ void KeyValues3::CopyFrom( const KeyValues3* pSrc ) { case KV3_TYPEEX_ARRAY: { - SetToEmptyArray(); - m_Data.m_pArray->CopyFrom( this, pSrc->m_Data.m_pArray ); + SetToEmptyKV3Array(); + m_Data.m_Array.m_pRoot->CopyFrom( this, pSrc->m_Data.m_Array.m_pRoot ); break; } case KV3_TYPEEX_ARRAY_FLOAT32: @@ -1432,19 +1447,19 @@ CKeyValues3Array::CKeyValues3Array( int cluster_elem, int alloc_size ) : CKeyValues3ArrayCluster* CKeyValues3Array::GetCluster() const { if ( !HasCluster() ) - return GET_OUTER( CKeyValues3ArrayCluster, m_Values[ m_nClusterElement ] ); + return nullptr; - return nullptr; + return GET_OUTER( CKeyValues3ArrayCluster, m_Values[ m_nClusterElement ] ); } CKeyValues3Context* CKeyValues3Array::GetContext() const { CKeyValues3ArrayCluster* cluster = GetCluster(); - if ( cluster ) - return cluster->GetContext(); + if ( !cluster ) + return nullptr; - return nullptr; + return cluster->GetContext(); } KeyValues3* CKeyValues3Array::Element( int i ) @@ -1619,10 +1634,10 @@ CKeyValues3Context* CKeyValues3Table::GetContext() const { CKeyValues3TableCluster* cluster = GetCluster(); - if ( cluster ) - return cluster->GetContext(); + if ( !cluster ) + return nullptr; - return nullptr; + return cluster->GetContext(); } KeyValues3* CKeyValues3Table::GetMember( KV3MemberId_t id ) @@ -1832,7 +1847,12 @@ void CKeyValues3Table::CopyFrom( KeyValues3 *parent, const CKeyValues3Table* src for ( int i = 0; i < new_size; i++ ) { flags_base[i] = src_flags_base[i] & ~MEMBER_FLAG_EXTERNAL_NAME; - names_base[i] = context ? context->AllocString( src_names_base[i] ) : strdup( src_names_base[i] ); + + if ( context ) + names_base[i] = context->AllocString( src_names_base[i] ); + else + names_base[i] = strdup( src_names_base[i] ); + members_base[i] = parent->AllocMember(); members_base[i]->CopyFrom( src_members_base[i] ); } From 936f277ea4ed535887742f60240bdc313ae40fb7 Mon Sep 17 00:00:00 2001 From: Wend4r <47463683+Wend4r@users.noreply.github.com> Date: Sat, 15 Mar 2025 12:36:53 +0300 Subject: [PATCH 30/30] Fix `KeyValues3::GetCluster` method --- tier1/keyvalues3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tier1/keyvalues3.cpp b/tier1/keyvalues3.cpp index 1e6454726..3445c93d7 100644 --- a/tier1/keyvalues3.cpp +++ b/tier1/keyvalues3.cpp @@ -368,7 +368,7 @@ void KeyValues3::PrepareForType( KV3TypeEx_t type, KV3SubType_t subtype, int ini CKeyValues3Cluster* KeyValues3::GetCluster() const { - if ( !m_bContextIndependent ) + if ( m_bContextIndependent ) return nullptr; return GET_OUTER( CKeyValues3Cluster, m_Values[ m_nClusterElement ] );