diff --git a/entity2/entitykeyvalues.cpp b/entity2/entitykeyvalues.cpp index e21fac3c..02776282 100644 --- a/entity2/entitykeyvalues.cpp +++ b/entity2/entitykeyvalues.cpp @@ -285,22 +285,6 @@ bool CEntityKeyValues::IsEmpty() const return false; } -bool CEntityKeyValues::ValuesHasBadNames() const -{ - if ( !m_pAllocator ) - return false; - - return m_pValues->TableHasBadNames(); -} - -bool CEntityKeyValues::AttributesHasBadNames() const -{ - if ( !m_pAllocator ) - return false; - - return m_pAttributes->TableHasBadNames(); -} - void CEntityKeyValues::ReleaseAllComplexKeys() { EntityComplexKeyListElem_t* pListElem = m_pComplexKeys; diff --git a/public/entity2/entitykeyvalues.h b/public/entity2/entitykeyvalues.h index f54af6bb..255f1d23 100644 --- a/public/entity2/entitykeyvalues.h +++ b/public/entity2/entitykeyvalues.h @@ -115,9 +115,6 @@ public: void RemoveAllKeys(); bool IsEmpty() const; - - bool ValuesHasBadNames() const; - bool AttributesHasBadNames() const; bool HasValue( const EntityKeyId_t &id ) const { bool bIsAttribute; return ( GetKeyValue( id, &bIsAttribute ) && !bIsAttribute ); } bool HasAttribute( const EntityKeyId_t &id ) const { bool bIsAttribute; return ( GetKeyValue( id, &bIsAttribute ) && bIsAttribute ); } diff --git a/public/tier1/keyvalues3.h b/public/tier1/keyvalues3.h index 1eb5c38a..8b102c7b 100644 --- a/public/tier1/keyvalues3.h +++ b/public/tier1/keyvalues3.h @@ -12,29 +12,26 @@ #include "tier1/strtools.h" #include "tier1/utlbuffer.h" #include "tier1/utlhashtable.h" -#include "tier1/utlleanvector.h" #include "tier1/utlmap.h" #include "tier1/utlstring.h" #include "tier1/utlstringtoken.h" #include "tier1/utlsymbollarge.h" #include "mathlib/vector4d.h" #include "Color.h" +#include "bitvec.h" #include "entityhandle.h" +#include + #include "tier0/memdbgon.h" class KeyValues3; class CKeyValues3Array; class CKeyValues3Table; -class CKeyValues3Cluster; class CKeyValues3Context; struct KV1ToKV3Translation_t; struct KV3ToKV1Translation_t; -template < class T > class CKeyValues3ClusterT; -typedef CKeyValues3ClusterT< CKeyValues3Array > CKeyValues3ArrayCluster; -typedef CKeyValues3ClusterT< CKeyValues3Table > CKeyValues3TableCluster; - /* KeyValues3 is a data storage format. See https://developer.valvesoftware.com/wiki/KeyValues3 Supports various specific data types targeted at the Source2. @@ -112,14 +109,32 @@ PLATFORM_OVERLOAD bool SaveKV3ToFile( const KV3ID_t& encoding, const KV3ID_t& fo typedef int32 KV3MemberId_t; #define KV3_INVALID_MEMBER ((KV3MemberId_t)-1) +// 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. enum { - KV3_CONTEXT_SIZE = 4608 + ALLOC_KV3TABLE_MIN = 4, + ALLOC_KV3TABLE_MAX = 0x6186154, + + ALLOC_KV3ARRAY_MIN = 4, + ALLOC_KV3ARRAY_MAX = 0xFFFFF7F, + + ALLOC_CONTEXT_NODELIST_MIN = 32, + ALLOC_CONTEXT_NODELIST_MAX = INT_MAX }; enum { - KV3_CLUSTER_MAX_ELEMENTS = 63 + KV3_ARRAY_MAX_FIXED_MEMBERS = 6, + KV3_TABLE_MAX_FIXED_MEMBERS = 8, + + KV3_CONTEXT_SIZE = 4608, + + KV3_ARRAY_INIT_SIZE = 32, + KV3_TABLE_INIT_SIZE = 64, + + KV3_CLUSTER_MAX_ELEMENTS = 253 }; enum KV3Type_t : uint8 @@ -191,9 +206,10 @@ enum KV3SubType_t : uint8 KV3_SUBTYPE_RESOURCE_NAME, KV3_SUBTYPE_PANORAMA, KV3_SUBTYPE_SOUNDEVENT, - KV3_SUBTYPE_SUBCLASS, // table type KV3_SUBTYPE_ENTITY_NAME, // string type + KV3_SUBTYPE_LOCALIZE, + KV3_SUBTYPE_UNSPECIFIED, KV3_SUBTYPE_NULL, KV3_SUBTYPE_BINARY_BLOB, @@ -256,36 +272,38 @@ enum KV3MetaDataFlags_t namespace KV3Helpers { + template + constexpr size_t PackAlignOf() + { + if constexpr (sizeof...(Ts) == 0) + return alignof(T); + else + return (alignof(T) > PackAlignOf()) ? alignof(T) : PackAlignOf(); + } -// https://www.chessprogramming.org/BitScan -inline int BitScanFwd( uint64 bb ) -{ - static const int index64[64] = { - 0, 47, 1, 56, 48, 27, 2, 60, - 57, 49, 41, 37, 28, 16, 3, 61, - 54, 58, 35, 52, 50, 42, 21, 44, - 38, 32, 29, 23, 17, 11, 4, 62, - 46, 55, 26, 59, 40, 36, 15, 53, - 34, 51, 20, 43, 31, 22, 10, 45, - 25, 39, 14, 33, 19, 30, 9, 24, - 13, 18, 8, 12, 7, 6, 5, 63 - }; + template + constexpr size_t PackSizeOf( int size ) + { + return ((ALIGN_VALUE( size * sizeof( Ts ), ALIGN )) + ... + 0); + } - const uint64 debruijn64 = 0x03f79d71b4cb0a89ull; - Assert( bb != 0 ); - return index64[ ( ( bb ^ ( bb - 1 ) ) * debruijn64 ) >> 58 ]; -} + inline int CalcNewBufferSize( int old_size, int requested_size, int min_size, int max_size ) + { + int new_size = MAX( old_size, min_size ); -// https://www.chessprogramming.org/Population_Count -inline int PopCount( uint64 x ) -{ - x = x - ( ( x >> 1 ) & 0x5555555555555555ull ); - x = ( x & 0x3333333333333333ull ) + ( ( x >> 2 ) & 0x3333333333333333ull ); - x = ( x + ( x >> 4 ) ) & 0x0f0f0f0f0f0f0f0full; - x = ( x * 0x0101010101010101ull ) >> 56; - return ( int )x; -} + while(new_size < requested_size) + { + if(new_size < max_size / 2) + new_size *= 2; + else + { + new_size = max_size; + break; + } + } + return new_size; + } } struct KV3MetaData_t @@ -311,7 +329,7 @@ struct KV3MetaData_t } typedef CUtlMap, int, CDefLess> CommentsMap_t; - + int m_nLine; int m_nColumn; uint m_nFlags; @@ -353,14 +371,22 @@ private: const char* m_pszString; }; +template +class CKeyValues3ClusterImpl; + +using CKeyValues3Cluster = CKeyValues3ClusterImpl; +using CKeyValues3TableCluster = CKeyValues3ClusterImpl; +using CKeyValues3ArrayCluster = CKeyValues3ClusterImpl; + class KeyValues3 { public: KeyValues3( KV3TypeEx_t type = KV3_TYPEEX_NULL, KV3SubType_t subtype = KV3_SUBTYPE_UNSPECIFIED ); + KeyValues3( int cluster_elem, KV3TypeEx_t type, KV3SubType_t subtype ); ~KeyValues3(); CKeyValues3Context* GetContext() const; - KV3MetaData_t* GetMetaData( CKeyValues3Context** ppCtx = NULL ) const; + KV3MetaData_t* GetMetaData( CKeyValues3Context** ppCtx = nullptr ) const; KV3Type_t GetType() const { return ( KV3Type_t )( m_TypeEx & 0xF ); } KV3TypeEx_t GetTypeEx() const { return ( KV3TypeEx_t )m_TypeEx; } @@ -401,13 +427,13 @@ public: void SetFloat( float32 value ) { SetValue( value, KV3_TYPEEX_DOUBLE, KV3_SUBTYPE_FLOAT32 ); } void SetDouble( float64 value ) { SetValue( value, KV3_TYPEEX_DOUBLE, KV3_SUBTYPE_FLOAT64 ); } - void* GetPointer( void *defaultValue = ( void* )0 ) const { return ( GetSubType() == KV3_SUBTYPE_POINTER ) ? ( void* )m_UInt : defaultValue; } + void* GetPointer( void *defaultValue = ( void* )0 ) const { return ( GetSubType() == KV3_SUBTYPE_POINTER ) ? ( void* )m_Data.m_UInt : defaultValue; } void SetPointer( void* ptr ) { SetValue( ( uint64 )ptr, KV3_TYPEEX_UINT, KV3_SUBTYPE_POINTER ); } - CUtlStringToken GetStringToken( CUtlStringToken defaultValue = CUtlStringToken() ) const { return ( GetSubType() == KV3_SUBTYPE_STRING_TOKEN ) ? CUtlStringToken( ( uint32 )m_UInt ) : defaultValue; } + CUtlStringToken GetStringToken( CUtlStringToken defaultValue = CUtlStringToken() ) const { return ( GetSubType() == KV3_SUBTYPE_STRING_TOKEN ) ? CUtlStringToken( ( uint32 )m_Data.m_UInt ) : defaultValue; } void SetStringToken( CUtlStringToken token ) { SetValue( token.GetHashCode(), KV3_TYPEEX_UINT, KV3_SUBTYPE_STRING_TOKEN ); } - CEntityHandle GetEHandle( CEntityHandle defaultValue = CEntityHandle() ) const { return ( GetSubType() == KV3_SUBTYPE_EHANDLE ) ? CEntityHandle( ( uint32 )m_UInt ) : defaultValue; } + CEntityHandle GetEHandle( CEntityHandle defaultValue = CEntityHandle() ) const { return ( GetSubType() == KV3_SUBTYPE_EHANDLE ) ? CEntityHandle( ( uint32 )m_Data.m_UInt ) : defaultValue; } void SetEHandle( CEntityHandle ehandle ) { SetValue( ehandle.ToInt(), KV3_TYPEEX_UINT, KV3_SUBTYPE_EHANDLE ); } const char* GetString( const char *defaultValue = "" ) const; @@ -455,8 +481,6 @@ public: unsigned int GetMemberHash( KV3MemberId_t id ) const; KeyValues3* FindMember( const CKV3MemberName &name, KeyValues3* defaultValue = NULL ); KeyValues3* FindOrCreateMember( const CKV3MemberName &name, bool *pCreated = NULL ); - bool TableHasBadNames() const; - void SetTableHasBadNames( bool bHasBadNames ); void SetToEmptyTable(); bool RemoveMember( KV3MemberId_t id ); bool RemoveMember( const KeyValues3* kv ); @@ -465,10 +489,68 @@ public: KeyValues3& operator=( const KeyValues3& src ); private: - KeyValues3( int cluster_elem, KV3TypeEx_t type, KV3SubType_t subtype ); KeyValues3( const KeyValues3& other ); - void Alloc(); + union Data_t + { + Data_t() : m_nMemory(0) + { + } + + bool m_Bool; + int64 m_Int; + uint64 m_UInt; + float64 m_Double; + + const char* m_pString; + char m_szStringShort[8]; + + KV3BinaryBlob_t* m_pBinaryBlob; + + CKeyValues3Array* m_pArray; + 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]; + }; + + void Alloc( int initial_size = 0, Data_t data = {}, int bytes_available = 0, bool should_free = false ); + + CKeyValues3Array *AllocArray( int initial_size = 0 ); + CKeyValues3Table *AllocTable( int initial_size = 0 ); + + void AllocArrayInPlace( int initial_size, Data_t data, int preallocated_size, bool should_free ); + void AllocTableInPlace( int initial_size, Data_t data, int preallocated_size, bool should_free ); + + template + T *AllocateOnHeap( int initial_size = 0 ); + + template + void FreeOnHeap( T *element ); + + void FreeArray( CKeyValues3Array *element, bool clearing_context = false ); + void FreeTable( CKeyValues3Table *element, bool clearing_context = false ); + + KeyValues3 *AllocMember( KV3TypeEx_t type = KV3_TYPEEX_NULL, KV3SubType_t subtype = KV3_SUBTYPE_UNSPECIFIED ); + void FreeMember( KeyValues3 *member ); + void Free( bool bClearingContext = false ); void ResolveUnspecified(); void PrepareForType( KV3TypeEx_t type, KV3SubType_t subtype ); @@ -476,6 +558,7 @@ private: void CopyFrom( const KeyValues3* pSrc ); int GetClusterElement() const { return m_nClusterElement; } + void SetClusterElement( int element ) { m_bExternalStorage = (element == -1); m_nClusterElement = element; } CKeyValues3Cluster* GetCluster() const; template < typename T > T FromString( T defaultValue ) const; @@ -497,112 +580,177 @@ private: bool ReadArrayInt32( int size, int32* data ) const; bool ReadArrayFloat32( int size, float32* data ) const; + static constexpr size_t TotalSizeOf( int initial_size ) { return sizeof(KeyValues3); } + static constexpr size_t TotalSizeOfData( int size ) { return sizeof(Data_t); } + static constexpr size_t TotalSizeWithoutStaticData() { return sizeof(KeyValues3) - TotalSizeOfData( 0 ); } + private: uint64 m_bExternalStorage : 1; uint64 m_bFreeArrayMemory : 1; uint64 m_TypeEx : 8; uint64 m_SubType : 8; uint64 m_nFlags : 8; - uint64 m_nClusterElement : 6; + uint64 m_nClusterElement : 16; uint64 m_nNumArrayElements : 5; - uint64 m_nReserved : 27; - - union - { - bool m_Bool; - int64 m_Int; - uint64 m_UInt; - float64 m_Double; - - const char* m_pString; - char m_szStringShort[8]; - - KV3BinaryBlob_t* m_pBinaryBlob; + uint64 m_nReserved : 17; + Data_t m_Data; - CKeyValues3Array* m_pArray; - float32* m_f32Array; - float64* m_f64Array; - int16* m_i16Array; - int32* m_i32Array; - uint8 m_u8ArrayShort[8]; - int16 m_i16ArrayShort[4]; - - CKeyValues3Table* m_pTable; - - uint64 m_nData; - void* m_pData; - char m_Data[1]; - }; - - friend class CKeyValues3Cluster; + friend CKeyValues3Cluster; + friend CKeyValues3ArrayCluster; + friend CKeyValues3TableCluster; friend class CKeyValues3Context; + friend class CKeyValues3Table; + friend class CKeyValues3Array; }; COMPILE_TIME_ASSERT(sizeof(KeyValues3) == 16); class CKeyValues3Array { public: - CKeyValues3Array( int cluster_elem = -1 ); + typedef KeyValues3 *Element_t; + + 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() { PurgeBuffers(); } int GetClusterElement() const { return m_nClusterElement; } + void SetClusterElement( int element ) { m_nClusterElement = element; } + CKeyValues3ArrayCluster* GetCluster() const; CKeyValues3Context* GetContext() const; - - KeyValues3** Base() { return m_Elements.Base(); } - KeyValues3* const * Base() const { return m_Elements.Base(); } - KeyValues3* Element( int i ) { return m_Elements[ i ]; } - const KeyValues3* Element( int i ) const { return m_Elements[ i ]; } + Element_t *Base() { return IsBaseStatic() ? &m_StaticElements[0] : m_pDynamicElements; }; + Element_t const *Base() const { return const_cast(this)->Base(); } - int Count() const { return m_Elements.Count(); } - void SetCount( int count, KV3TypeEx_t type = KV3_TYPEEX_NULL, KV3SubType_t subtype = KV3_SUBTYPE_UNSPECIFIED ); - KeyValues3** InsertBeforeGetPtr( int elem, int num ); - void CopyFrom( const CKeyValues3Array* pSrc ); - void RemoveMultiple( int elem, int num ); - void Purge( bool bClearingContext ); + Element_t Element( int i ); + const Element_t Element( int i ) const { return const_cast(this)->Element( i ); } + int Count() const { return m_nCount; } + + void EnsureElementCapacity( int count, bool force = false, bool dont_move = false ); + + void SetCount( KeyValues3 *parent, int count, KV3TypeEx_t type = KV3_TYPEEX_NULL, KV3SubType_t subtype = KV3_SUBTYPE_UNSPECIFIED ); + Element_t* InsertMultipleBefore( KeyValues3 *parent, int from, int num ); + void CopyFrom( KeyValues3 *parent, const CKeyValues3Array* pSrc ); + void RemoveMultiple( KeyValues3 *parent, int from, int num ); + + void OnClearContext() { PurgeContent( nullptr, true ); } + void PurgeContent( KeyValues3 *parent = nullptr, bool clearing_context = false ); + void PurgeBuffers(); + + static constexpr size_t TotalSizeOf( int initial_size ) { return ALIGN_VALUE( TotalSizeWithoutStaticData() + TotalSizeOfData( MAX( initial_size, 0 ) ), 8 ); } + static constexpr size_t TotalSizeOfData( int size ) { return MAX( (KV3Helpers::PackSizeOf( size )), sizeof( m_pDynamicElements ) ); } + static constexpr size_t TotalSizeWithoutStaticData() { return sizeof( CKeyValues3Array ) - sizeof( m_StaticElements ); } private: - typedef CUtlLeanVectorFixedGrowable ElementsVec_t; - - int m_nClusterElement; - ElementsVec_t m_Elements; + int GetAllocatedChunks() const { return m_nAllocatedChunks; } + bool IsBaseStatic() { return !m_bIsDynamicallySized; } + + size_t GetAllocatedBytesSize() const { return TotalSizeOfData( GetAllocatedChunks() ); } + +private: + int m_nClusterElement; + int m_nAllocatedChunks; + + int m_nCount; + uint8 m_nInitialSize; + bool m_bIsDynamicallySized; + + bool m_unk001; + bool m_unk002; + + union + { + Element_t m_StaticElements[DATA_SIZE]; + Element_t *m_pDynamicElements; + }; }; +COMPILE_TIME_ASSERT(sizeof(CKeyValues3Array) == 64); class CKeyValues3Table { public: - CKeyValues3Table( int cluster_elem = -1 ); + enum : uint8 + { + TABLEFL_NONE = 0, + TABLEFL_NAME_EXTERNAL = (1 << 0) + }; + + typedef uint32 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(); + + CKeyValues3Table( int cluster_elem = -1, int alloc_size = DATA_SIZE ); + ~CKeyValues3Table() { PurgeBuffers(); } int GetClusterElement() const { return m_nClusterElement; } + void SetClusterElement( int element ) { m_nClusterElement = element; } + CKeyValues3TableCluster* GetCluster() const; CKeyValues3Context* GetContext() const; - int GetMemberCount() const { return m_Hashes.Count(); } - KeyValues3* GetMember( KV3MemberId_t id ) { return m_Members[ id ]; } - const KeyValues3* GetMember( KV3MemberId_t id ) const { return m_Members[ id ]; } - const char* GetMemberName( KV3MemberId_t id ) const { return m_Names[ id ]; } - unsigned int GetMemberHash( KV3MemberId_t id ) const { return m_Hashes[ id ]; } + 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 ); } + const Name_t GetMemberName( KV3MemberId_t id ) const; + const Hash_t GetMemberHash( KV3MemberId_t id ) const; + + void PurgeFastSearch(); void EnableFastSearch(); + void EnsureMemberCapacity( int num, bool force = false, bool dont_move = false ); + KV3MemberId_t FindMember( const KeyValues3* kv ) const; KV3MemberId_t FindMember( const CKV3MemberName &name ); - KV3MemberId_t CreateMember( const CKV3MemberName &name ); - bool HasBadNames() const { return m_bHasBadNames; } - void SetHasBadNames( bool bHasBadNames ) { m_bHasBadNames = bHasBadNames; } - void CopyFrom( const CKeyValues3Table* pSrc ); - void RemoveMember( KV3MemberId_t id ); - void RemoveAll( int nAllocSize = 0 ); - void Purge( bool bClearingContext ); + KV3MemberId_t CreateMember( KeyValues3 *parent, const CKV3MemberName &name, bool name_external = false ); + + void CopyFrom( KeyValues3 *parent, const CKeyValues3Table* src ); + void RemoveMember( KeyValues3 *parent, KV3MemberId_t id ); + void RemoveAll( KeyValues3 *parent, int new_size = 0 ); + + void OnClearContext() { PurgeContent( nullptr, true ); } + void PurgeContent( KeyValues3 *parent = nullptr, bool bClearingContext = false ); + void PurgeBuffers(); + + static constexpr size_t TotalSizeOf( int initial_size ) { return ALIGN_VALUE( TotalSizeWithoutStaticData() + TotalSizeOfData( MAX( initial_size, 0 ) ), 8 ); } + static constexpr size_t TotalSizeOfData( int size ) { return MAX( (KV3Helpers::PackSizeOf( size )), sizeof(m_pDynamicBuffer) ); } + static constexpr size_t TotalSizeWithoutStaticData() { return sizeof(CKeyValues3Table) - sizeof(m_StaticBuffer); } + +private: + int GetAllocatedChunks() const { return m_nAllocatedChunks; } + bool IsBaseStatic() { return !m_bIsDynamicallySized; } + + size_t GetAllocatedBytesSize() const { return TotalSizeOfData( GetAllocatedChunks() ); } + + constexpr size_t OffsetToHashesBase( int size ) const { return 0; } + constexpr size_t OffsetToMembersBase( int size ) const { return KV3Helpers::PackSizeOf( size ); } + 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: - typedef CUtlLeanVectorFixedGrowable HashesVec_t; - typedef CUtlLeanVectorFixedGrowable MembersVec_t; - typedef CUtlLeanVectorFixedGrowable NamesVec_t; - typedef CUtlLeanVectorFixedGrowable IsExternalNameVec_t; - int m_nClusterElement; + int m_nAllocatedChunks; struct kv3tablefastsearch_t { kv3tablefastsearch_t() : m_ignore( false ), m_ignores_counter( 0 ) {} + ~kv3tablefastsearch_t() { Clear(); } void Clear() { @@ -619,113 +767,221 @@ private: Hashtable_t m_member_ids; } *m_pFastSearch; - HashesVec_t m_Hashes; - MembersVec_t m_Members; - NamesVec_t m_Names; - IsExternalNameVec_t m_IsExternalName; // didn't find this used when deleting a table - bool m_bHasBadNames; -}; + int m_nCount; -class CKeyValues3Cluster + uint8 m_nInitialSize; + bool m_bIsDynamicallySized; + + bool m_unk001; + bool m_unk002; + + union + { + struct + { + Hash_t m_Hashes[DATA_SIZE]; + Member_t m_Members[DATA_SIZE]; + Name_t m_Names[DATA_SIZE]; + Flags_t m_Flags[DATA_SIZE]; + } m_StaticBuffer; + + void* m_pDynamicBuffer; + }; +}; +COMPILE_TIME_ASSERT(sizeof(CKeyValues3Table) == 192); + +template +class CKeyValues3ClusterImpl { public: - CKeyValues3Cluster( CKeyValues3Context* context ); - ~CKeyValues3Cluster(); + typedef T NodeType; + static const size_t CLUSTER_SIZE = SIZE; + + union Node + { + Node() : m_pNextFree( nullptr ) {} + ~Node() {} + + NodeType m_Value; + Node *m_pNextFree; + }; + + enum + { + HEAP_MARKER = (1 << 31), + + FLAGS_MASK = ~(HEAP_MARKER) + }; + + CKeyValues3ClusterImpl( CKeyValues3Context *context, bool allocated_on_heap = false, int initial_size = SIZE ); + ~CKeyValues3ClusterImpl() { Purge(); } + + CKeyValues3Context *GetContext() const { return m_pContext; } + + bool IsFull() const { return NumCount() >= NumAllocated(); } + bool IsAllocatedOnHeap() const { return (m_nAllocatedElements & HEAP_MARKER) != 0; } + int NumAllocated() const { return m_nAllocatedElements & FLAGS_MASK; } + int NumCount() const { return m_nElementCount; } + + template , int>> + NodeType *Alloc( Args&&... args ); + + void Free( int element, bool clearing_context = false ); + void Free( NodeType *node, bool clearing_context = false ); - KeyValues3* Alloc( KV3TypeEx_t type = KV3_TYPEEX_NULL, KV3SubType_t subtype = KV3_SUBTYPE_UNSPECIFIED ); - void Free( int element ); - void Clear(); - void PurgeElements(); void Purge(); + void Clear(); + + Node *GetNextFree() const { return m_pFirstFreeNode; } + void SetNextFree( Node *free ) { m_pFirstFreeNode = free; } + + CKeyValues3ClusterImpl *GetNext() const { return m_pNext; } + void SetNext( CKeyValues3ClusterImpl *cluster ) { m_pNext = cluster; } + + CKeyValues3ClusterImpl *GetPrev() const { return m_pPrev; } + void SetPrev( CKeyValues3ClusterImpl *cluster ) { m_pPrev = cluster; } + + Node *Head() { return &m_Values[0]; } + Node *Tail() { return &m_Values[NumAllocated()]; } + + const Node *Head() const { return const_cast(this)->Head(); } + const Node *Tail() const { return const_cast(this)->Tail(); } void EnableMetaData( bool bEnable ); - void FreeMetaData(); - KV3MetaData_t* GetMetaData( int element ) const; + void ClearMetaData(); + void PurgeMetaData(); + void PurgeMetaData( int element ); + KV3MetaData_t *GetMetaData( int element ) const; - CKeyValues3Context* GetContext() const { return m_pContext; } - int NumAllocated() const { return KV3Helpers::PopCount( m_nAllocatedElements ); } - bool IsFree() const { return ( m_nAllocatedElements != 0x7fffffffffffffffull ); } - CKeyValues3Cluster* GetNextFree() const { return m_pNextFree; } - void SetNextFree( CKeyValues3Cluster* free ) { m_pNextFree = free; } + int GetNodeIndex( NodeType *node ) const; - KeyValues3* Head() { return &m_KeyValues[ 0 ]; } - const KeyValues3* Head() const { return &m_KeyValues[ 0 ]; } + static constexpr size_t TotalSizeOf( int initial_size ) { return ALIGN_VALUE( TotalSizeWithoutStaticData() + TotalSizeOfData( MAX( initial_size, 0 ) ), 8 ); } + static constexpr size_t TotalSizeOfData( int size ) { return sizeof( Node ) * size; } + static constexpr size_t TotalSizeWithoutStaticData() { return sizeof( CKeyValues3ClusterImpl ) - TotalSizeOfData( SIZE ); } + + friend CKeyValues3Cluster *KeyValues3::GetCluster() const; + friend CKeyValues3ArrayCluster *CKeyValues3Array::GetCluster() const; + friend CKeyValues3TableCluster *CKeyValues3Table::GetCluster() const; private: - CKeyValues3Context* m_pContext; - uint64 m_nAllocatedElements; - KeyValues3 m_KeyValues[KV3_CLUSTER_MAX_ELEMENTS]; - - struct kv3metadata_t { - KV3MetaData_t m_elements[KV3_CLUSTER_MAX_ELEMENTS]; - } *m_pMetaData; - - CKeyValues3Cluster* m_pNextFree; - - friend CKeyValues3Cluster* KeyValues3::GetCluster() const; -}; - -template < class T > -class CKeyValues3ClusterT -{ -public: - CKeyValues3ClusterT( CKeyValues3Context* context ); - - T* Alloc(); - void Free( int element ); - void Clear() { Purge(); } - void Purge(); - - CKeyValues3Context* GetContext() const { return m_pContext; } - int NumAllocated() const { return KV3Helpers::PopCount( m_nAllocatedElements ); } - bool IsFree() const { return ( m_nAllocatedElements != 0x7fffffffffffffffull ); } - CKeyValues3ClusterT* GetNextFree() const { return m_pNextFree; } - void SetNextFree( CKeyValues3ClusterT* free ) { m_pNextFree = free; } + void InitNodes(); + void PurgeNodes( bool clearing_context = false ); private: - CKeyValues3Context* m_pContext; - uint64 m_nAllocatedElements; - T m_Elements[KV3_CLUSTER_MAX_ELEMENTS]; - CKeyValues3ClusterT* m_pNextFree; + struct kv3metadata_t + { + int m_AllocatedElements; + KV3MetaData_t m_elements[SIZE]; + }; - friend CKeyValues3ArrayCluster* CKeyValues3Array::GetCluster() const; - friend CKeyValues3TableCluster* CKeyValues3Table::GetCluster() const; + CKeyValues3Context *m_pContext; + Node *m_pFirstFreeNode; + + int m_nAllocatedElements; + int m_nElementCount; + + CKeyValues3ClusterImpl *m_pPrev; + CKeyValues3ClusterImpl *m_pNext; + + kv3metadata_t *m_pMetaData; + + Node m_Values[SIZE]; }; class CKeyValues3ContextBase { public: CKeyValues3ContextBase( CKeyValues3Context* context ); - ~CKeyValues3ContextBase(); + ~CKeyValues3ContextBase() { Purge(); } void Clear(); void Purge(); protected: - typedef CUtlLeanVectorFixedGrowable KV3ClustersVec_t; - typedef CUtlLeanVectorFixedGrowable ArrayClustersVec_t; - typedef CUtlLeanVectorFixedGrowable TableClustersVec_t; + template + struct ClusterNodeChain + { + ClusterNodeChain() : m_pTail( nullptr ), m_pHead( nullptr ) + {} - CKeyValues3Context* m_pContext; - CUtlBuffer m_BinaryData; - - CKeyValues3Cluster m_KV3BaseCluster; - KV3ClustersVec_t m_KV3Clusters; - CKeyValues3Cluster* m_pKV3FreeCluster; - - ArrayClustersVec_t m_ArrayClusters; - CKeyValues3ArrayCluster* m_pArrayFreeCluster; - - TableClustersVec_t m_TableClusters; - CKeyValues3TableCluster* m_pTableFreeCluster; + void Reset() + { + m_pTail = nullptr; + m_pHead = nullptr; + } - CUtlSymbolTableLarge m_Symbols; + void AddToChain( CLUSTER *cluster ); + void RemoveFromChain( CLUSTER *cluster ); - bool m_bMetaDataEnabled : 1; - bool m_bFormatConverted : 1; - bool m_bRootAvailabe : 1; + CLUSTER *m_pTail; + CLUSTER *m_pHead; + }; - IParsingErrorListener* m_pParsingErrorListener; + template + class NodeList + { + public: + struct ListEntry + { + ListEntry *m_pNext; + NODE m_Value; + }; + + NodeList() : m_nUsedBytes( 0 ), m_nAllocatedBytes( 0 ), m_pData( nullptr ) + {} + + ~NodeList() { Free(); } + + NODE *Alloc( int initial_size ); + void Free() { Purge(); } + void Purge(); + void Clear(); + + int UsedBytes() const { return m_nUsedBytes; } + int AllocatedBytes() const { return m_nAllocatedBytes; } + int FreeBytes() const { return m_nAllocatedBytes - m_nUsedBytes; } + + bool IsFull() const { return m_nUsedBytes >= m_nAllocatedBytes; } + + ListEntry *Head() { return &m_pData[0]; } + ListEntry *Tail() { return reinterpret_cast((uint8 *)Head() + m_nUsedBytes); } + + bool IsWithinRange( NODE *element ) { return AllocatedBytes() > 0 && element >= (void *)Head() && element < (void *)Tail(); } + + private: + void EnsureByteSize( int bytes_needed ); + + private: + int m_nUsedBytes; + int m_nAllocatedBytes; + ListEntry *m_pData; + }; + + CKeyValues3Context* m_pContext; + CUtlBuffer m_BinaryData; + + CKeyValues3Cluster m_KV3BaseCluster; + + ClusterNodeChain m_KV3PartialClusters; + ClusterNodeChain m_KV3FullClusters; + + ClusterNodeChain m_PartialArrayClusters; + ClusterNodeChain m_FullArrayClusters; + NodeList m_RawArrayEntries; + + ClusterNodeChain m_PartialTableClusters; + ClusterNodeChain m_FullTableClusters; + NodeList m_RawTableEntries; + + CUtlSymbolTableLarge m_Symbols; + + bool m_bMetaDataEnabled: 1; + bool m_bFormatConverted: 1; + bool m_bRootAvailabe: 1; + + IParsingErrorListener* m_pParsingErrorListener; + + friend class KeyValues3; }; class CKeyValues3Context : public CKeyValues3ContextBase @@ -734,7 +990,7 @@ class CKeyValues3Context : public CKeyValues3ContextBase public: CKeyValues3Context( bool bNoRoot = false ); - ~CKeyValues3Context(); + ~CKeyValues3Context() { Purge(); } KeyValues3* AllocKV( KV3TypeEx_t type = KV3_TYPEEX_NULL, KV3SubType_t subtype = KV3_SUBTYPE_UNSPECIFIED ); // WARNING: kv must belong to this context!!! @@ -763,18 +1019,32 @@ public: void Clear(); void Purge(); + template + void ClearClusterNodeChain( ClusterNodeChain &cluster_node ); + template + void PurgeClusterNodeChain( ClusterNodeChain &cluster_node ); + + bool IsArrayRawAllocated( CKeyValues3Array *element ) { return m_RawArrayEntries.IsWithinRange( element ); } + bool IsTableRawAllocated( CKeyValues3Table *element ) { return m_RawTableEntries.IsWithinRange( element ); } + private: - template< class ELEMENT_TYPE, class CLUSTER_TYPE, class VECTOR_TYPE > - ELEMENT_TYPE* Alloc( CLUSTER_TYPE *&head, VECTOR_TYPE &vec ); + template + void MoveToPartial( ClusterNodeChain &full_cluster, ClusterNodeChain &partial_cluster ); - template< class ELEMENT_TYPE, class CLUSTER_TYPE, class VECTOR_TYPE > - void Free( ELEMENT_TYPE *element, CLUSTER_TYPE *base, CLUSTER_TYPE *&head, VECTOR_TYPE &vec ); + template , int>> + auto Alloc( ClusterNodeChain &partial_clusters, ClusterNodeChain &full_clusters, int initial_size, Args&&... args ); - CKeyValues3Array* AllocArray() { return Alloc( m_pArrayFreeCluster, m_ArrayClusters ); } - CKeyValues3Table* AllocTable() { return Alloc( m_pTableFreeCluster, m_TableClusters ); } + template , int>> + NODE *RawAlloc( NodeList &raw_array, ClusterNodeChain &partial_clusters, ClusterNodeChain &full_clusters, int initial_size, Args&&... args ); - void FreeArray( CKeyValues3Array* arr ) { Free( arr, NULL, m_pArrayFreeCluster, m_ArrayClusters ); } - void FreeTable( CKeyValues3Table* table ) { Free( table, NULL, m_pTableFreeCluster, m_TableClusters ); } + CKeyValues3Array *AllocArray( int initial_size = 0 ) { return RawAlloc( m_RawArrayEntries, m_PartialArrayClusters, m_FullArrayClusters, initial_size ); } + CKeyValues3Table *AllocTable( int initial_size = 0 ) { return RawAlloc( m_RawTableEntries, m_PartialTableClusters, m_FullTableClusters, initial_size ); } + + template + void Free( NODE *element, ClusterNodeChain &partial_clusters, ClusterNodeChain &full_clusters ); + + inline void FreeArray( CKeyValues3Array *element ) { Free( element, m_PartialArrayClusters, m_FullArrayClusters ); } + inline void FreeTable( CKeyValues3Table *element ) { Free( element, m_PartialTableClusters, m_FullTableClusters ); } private: uint8 pad[ KV3_CONTEXT_SIZE - ( sizeof( BaseClass ) % KV3_CONTEXT_SIZE ) ]; @@ -798,18 +1068,18 @@ template <> inline float32 KeyValues3::FromString( float32 defaultValue ) const template <> inline float64 KeyValues3::FromString( float64 defaultValue ) const { return V_StringToFloat64( GetString(), defaultValue ); } template < typename T > inline void KeyValues3::SetDirect( T value ) { Assert( 0 ); } -template <> inline void KeyValues3::SetDirect( bool value ) { m_Bool = value; } -template <> inline void KeyValues3::SetDirect( char8 value ) { m_Int = ( int64 )value; } -template <> inline void KeyValues3::SetDirect( int8 value ) { m_Int = ( int64 )value; } -template <> inline void KeyValues3::SetDirect( uint8 value ) { m_UInt = ( uint64 )value; } -template <> inline void KeyValues3::SetDirect( int16 value ) { m_Int = ( int64 )value; } -template <> inline void KeyValues3::SetDirect( uint16 value ) { m_UInt = ( uint64 )value; } -template <> inline void KeyValues3::SetDirect( int32 value ) { m_Int = ( int64 )value; } -template <> inline void KeyValues3::SetDirect( uint32 value ) { m_UInt = ( uint64 )value; } -template <> inline void KeyValues3::SetDirect( int64 value ) { m_Int = value; } -template <> inline void KeyValues3::SetDirect( uint64 value ) { m_UInt = value; } -template <> inline void KeyValues3::SetDirect( float32 value ) { m_Double = ( float64 )value; } -template <> inline void KeyValues3::SetDirect( float64 value ) { m_Double = value; } +template <> inline void KeyValues3::SetDirect( bool value ) { m_Data.m_Bool = value; } +template <> inline void KeyValues3::SetDirect( char8 value ) { m_Data.m_Int = ( int64 )value; } +template <> inline void KeyValues3::SetDirect( int8 value ) { m_Data.m_Int = ( int64 )value; } +template <> inline void KeyValues3::SetDirect( uint8 value ) { m_Data.m_UInt = ( uint64 )value; } +template <> inline void KeyValues3::SetDirect( int16 value ) { m_Data.m_Int = ( int64 )value; } +template <> inline void KeyValues3::SetDirect( uint16 value ) { m_Data.m_UInt = ( uint64 )value; } +template <> inline void KeyValues3::SetDirect( int32 value ) { m_Data.m_Int = ( int64 )value; } +template <> inline void KeyValues3::SetDirect( uint32 value ) { m_Data.m_UInt = ( uint64 )value; } +template <> inline void KeyValues3::SetDirect( int64 value ) { m_Data.m_Int = value; } +template <> inline void KeyValues3::SetDirect( uint64 value ) { m_Data.m_UInt = value; } +template <> inline void KeyValues3::SetDirect( float32 value ) { m_Data.m_Double = ( float64 )value; } +template <> inline void KeyValues3::SetDirect( float64 value ) { m_Data.m_Double = value; } template < typename T > T KeyValues3::GetVecBasedObj( int size, const T &defaultValue ) const @@ -832,13 +1102,13 @@ T KeyValues3::GetValue( T defaultValue ) const switch ( GetType() ) { case KV3_TYPE_BOOL: - return ( T )m_Bool; + return ( T )m_Data.m_Bool; case KV3_TYPE_INT: - return ( T )m_Int; + return ( T )m_Data.m_Int; case KV3_TYPE_UINT: - return ( GetSubType() != KV3_SUBTYPE_POINTER ) ? ( T )m_UInt : defaultValue; + return ( GetSubType() != KV3_SUBTYPE_POINTER ) ? ( T )m_Data.m_UInt : defaultValue; case KV3_TYPE_DOUBLE: - return ( T )m_Double; + return ( T )m_Data.m_Double; case KV3_TYPE_STRING: return FromString( defaultValue ); default: @@ -857,19 +1127,38 @@ template < typename T > void KeyValues3::NormalizeArray( KV3TypeEx_t type, KV3SubType_t subtype, int size, const T* data, bool bFree ) { m_TypeEx = KV3_TYPEEX_ARRAY; - m_nData = 0; - Alloc(); + Alloc( size ); - m_pArray->SetCount( size, type, subtype ); + m_Data.m_pArray->SetCount( this, size, type, subtype ); - KeyValues3** arr = m_pArray->Base(); - for ( int i = 0; i < m_pArray->Count(); ++i ) + CKeyValues3Array::Element_t* arr = m_Data.m_pArray->Base(); + for ( int i = 0; i < m_Data.m_pArray->Count(); ++i ) arr[ i ]->SetDirect( data[ i ] ); if ( bFree ) free( (void*)data ); } +template +inline T *KeyValues3::AllocateOnHeap( int initial_size ) +{ + if(initial_size <= 0) + initial_size = T::DATA_SIZE; + + auto element = (T *)g_pMemAlloc->RegionAlloc( MEMALLOC_REGION_ALLOC_4, T::TotalSizeOf( initial_size ) ); + Construct( element, -1, initial_size ); + + return element; +} + +template +inline void KeyValues3::FreeOnHeap( T *element ) +{ + Destruct( element ); + + g_pMemAlloc->RegionFree( MEMALLOC_REGION_FREE_4, element ); +} + template < typename T > void KeyValues3::AllocArray( int size, const T* data, KV3ArrayAllocType_t alloc_type, KV3TypeEx_t type_short, KV3TypeEx_t type_ptr, KV3SubType_t subtype, KV3TypeEx_t type_elem, KV3SubType_t subtype_elem ) { @@ -883,7 +1172,7 @@ void KeyValues3::AllocArray( int size, const T* data, KV3ArrayAllocType_t alloc_ m_bFreeArrayMemory = false; m_nNumArrayElements = size; - m_pData = (void*)data; + m_Data.m_pMemory = (void*)data; } else { @@ -891,8 +1180,8 @@ void KeyValues3::AllocArray( int size, const T* data, KV3ArrayAllocType_t alloc_ m_bFreeArrayMemory = false; m_nNumArrayElements = size; - m_nData = 0; - memcpy( m_Data, data, size * sizeof( T ) ); + m_Data.m_pMemory = NULL; + memcpy( &m_Data.m_pMemory, data, size * sizeof( T ) ); if ( alloc_type == KV3_ARRAY_ALLOC_EXTERN_FREE ) free( (void*)data ); @@ -907,28 +1196,28 @@ void KeyValues3::AllocArray( int size, const T* data, KV3ArrayAllocType_t alloc_ if ( alloc_type == KV3_ARRAY_ALLOC_EXTERN ) { m_bFreeArrayMemory = false; - m_pData = (void*)data; + m_Data.m_pMemory = (void*)data; } else if ( alloc_type == KV3_ARRAY_ALLOC_EXTERN_FREE ) { m_bFreeArrayMemory = true; - m_pData = (void*)data; + m_Data.m_pMemory = (void*)data; } else { m_bFreeArrayMemory = true; - m_pData = malloc( size * sizeof( T ) ); - memcpy( m_pData, data, size * sizeof( T ) ); + m_Data.m_pMemory = malloc( size * sizeof( T ) ); + memcpy( m_Data.m_pMemory, data, size * sizeof( T ) ); } } else { PrepareForType( KV3_TYPEEX_ARRAY, subtype ); - m_pArray->SetCount( size, type_elem, subtype_elem ); + m_Data.m_pArray->SetCount( this, size, type_elem, subtype_elem ); - KeyValues3** arr = m_pArray->Base(); - for ( int i = 0; i < m_pArray->Count(); ++i ) + CKeyValues3Array::Element_t* arr = m_Data.m_pArray->Base(); + for ( int i = 0; i < m_Data.m_pArray->Count(); ++i ) arr[ i ]->SetValue( data[ i ], type_elem, subtype_elem ); if ( alloc_type == KV3_ARRAY_ALLOC_EXTERN_FREE ) @@ -936,121 +1225,389 @@ void KeyValues3::AllocArray( int size, const T* data, KV3ArrayAllocType_t alloc_ } } -template < class T > -CKeyValues3ClusterT< T >::CKeyValues3ClusterT( CKeyValues3Context* context ) : - m_pContext( context ), - m_nAllocatedElements( 0 ), - m_pNextFree( NULL ) +template +inline CKeyValues3ClusterImpl::CKeyValues3ClusterImpl( CKeyValues3Context *context, bool allocated_on_heap, int initial_size ) : + m_pContext( context ), + m_pFirstFreeNode( nullptr ), + m_nAllocatedElements( initial_size | (allocated_on_heap ? HEAP_MARKER : 0) ), + m_nElementCount( 0 ), + m_pPrev( nullptr ), + m_pNext( nullptr ), + m_pMetaData( nullptr ) { - memset( &m_Elements, 0, sizeof( m_Elements ) ); + InitNodes(); } -template < class T > -T* CKeyValues3ClusterT< T >::Alloc() +template +template +inline T *CKeyValues3ClusterImpl::Alloc( Args&&... args ) { - Assert( IsFree() ); - int element = KV3Helpers::BitScanFwd( ~m_nAllocatedElements ); - m_nAllocatedElements |= ( 1ull << element ); - T* pElement = &m_Elements[ element ]; - Construct( pElement, element ); - return pElement; + Assert( !IsFull() ); + + Node *node = GetNextFree(); + Assert( node != nullptr ); + + SetNextFree( node->m_pNextFree ); + + Construct( &node->m_Value, std::forward( args )... ); + node->m_Value.SetClusterElement( GetNodeIndex( &node->m_Value ) ); + + m_nElementCount++; + + return &node->m_Value; } -template < class T > -void CKeyValues3ClusterT< T >::Free( int element ) +template +inline void CKeyValues3ClusterImpl::Free( NodeType* node, bool clearing_context ) { - Assert( element >= 0 && element < KV3_CLUSTER_MAX_ELEMENTS ); - T* pElement = &m_Elements[ element ]; - Destruct( pElement ); - memset( (void *)pElement, 0, sizeof( T ) ); - m_nAllocatedElements &= ~( 1ull << element ); + Assert( node >= (void *)Head() && node < (void *)Tail() ); + Free( GetNodeIndex( node ), clearing_context ); } -template < class T > -void CKeyValues3ClusterT< T >::Purge() +template +inline void CKeyValues3ClusterImpl::Free( int element, bool clearing_context ) { - uint64 mask = 1; - for ( int i = 0; i < KV3_CLUSTER_MAX_ELEMENTS; ++i ) + Assert( element >= 0 && element < NumAllocated() ); + + Node *node = &m_Values[element]; + + if(clearing_context) + node->m_Value.OnClearContext(); + else + Destruct( &node->m_Value ); + + m_nElementCount--; + + node->m_pNextFree = GetNextFree(); + SetNextFree( node ); +} + +template +inline void CKeyValues3ClusterImpl::InitNodes() +{ + Node *iter = Tail() - 1; + Node *prev = nullptr; + + for(int i = 0; i < NumAllocated(); i++, iter--) { - if ( ( m_nAllocatedElements & mask ) != 0 ) - m_Elements[ i ].Purge( true ); - mask <<= 1; + iter->m_pNextFree = prev; + prev = iter; } - m_nAllocatedElements = 0; + m_nElementCount = 0; + SetNextFree( prev ); } -template< class ELEMENT_TYPE, class CLUSTER_TYPE, class VECTOR_TYPE > -ELEMENT_TYPE* CKeyValues3Context::Alloc( CLUSTER_TYPE *&head, VECTOR_TYPE &vec ) +template +inline void CKeyValues3ClusterImpl::PurgeNodes( bool clearing_context ) { - ELEMENT_TYPE* element; + CVarBitVec free_nodes( NumAllocated() * BITS_PER_INT ); - if ( head ) + for(auto iter = GetNextFree(); iter; iter = iter->m_pNextFree) { - element = head->Alloc(); + free_nodes.Set( GetNodeIndex( &iter->m_Value ) ); + } - if ( !head->IsFree() ) + if(!free_nodes.IsAllSet()) + { + for(int i = 0; i < NumAllocated(); i++) { - CLUSTER_TYPE* cluster = head->GetNextFree(); - head->SetNextFree( NULL ); - head = cluster; + if(!free_nodes.IsBitSet( i )) + { + Free( i, clearing_context ); + } + } + + InitNodes(); + } +} + +template +inline int CKeyValues3ClusterImpl::GetNodeIndex( NodeType *element ) const +{ + Node *node = reinterpret_cast(element); + + auto head = Head(); + if(node < head || node >= Tail()) + return -1; + + return node - head; +} + +template +inline void CKeyValues3ClusterImpl::Purge() +{ + PurgeNodes( false ); + PurgeMetaData(); +} + +template +inline void CKeyValues3ClusterImpl::Clear() +{ + PurgeNodes( true ); + ClearMetaData(); +} + +template +void CKeyValues3ClusterImpl::EnableMetaData( bool bEnable ) +{ + if(bEnable) + { + if(!m_pMetaData) + { + m_pMetaData = (kv3metadata_t *)g_pMemAlloc->RegionAlloc( MEMALLOC_REGION_ALLOC_4, (NumAllocated() * sizeof(KV3MetaData_t)) + 8 ); + m_pMetaData->m_AllocatedElements = NumAllocated(); } } else { - CLUSTER_TYPE* cluster = new CLUSTER_TYPE( m_pContext ); - *vec.AddToTailGetPtr() = cluster; - head = cluster; - element = cluster->Alloc(); + PurgeMetaData(); } - - return element; } -template< class ELEMENT_TYPE, class CLUSTER_TYPE, class VECTOR_TYPE > -void CKeyValues3Context::Free( ELEMENT_TYPE *element, CLUSTER_TYPE *base, CLUSTER_TYPE *&head, VECTOR_TYPE &vec ) +template +void CKeyValues3ClusterImpl::ClearMetaData() { - CLUSTER_TYPE* cluster = element->GetCluster(); - - Assert( cluster != NULL && cluster->GetContext() == m_pContext ); - - cluster->Free( element->GetClusterElement() ); - - int num_allocated = cluster->NumAllocated(); - - if ( !num_allocated ) + if(m_pMetaData) { - if ( cluster == base ) - return; - - vec.FindAndFastRemove( cluster ); - - if ( head != cluster ) + for(int i = 0; i < m_pMetaData->m_AllocatedElements; i++) { - CLUSTER_TYPE* cur = head; + m_pMetaData->m_elements[i].Clear(); + } + } +} - while ( cur ) - { - CLUSTER_TYPE* next = cur->GetNextFree(); - if ( next == cluster ) - break; - cur = next; - } +template +void CKeyValues3ClusterImpl::PurgeMetaData() +{ + if(m_pMetaData) + { + for(int i = 0; i < m_pMetaData->m_AllocatedElements; i++) + { + m_pMetaData->m_elements[i].Purge(); + } - if ( cur ) - cur->SetNextFree( cluster->GetNextFree() ); + g_pMemAlloc->RegionFree( MEMALLOC_REGION_FREE_4, m_pMetaData ); + } + + m_pMetaData = nullptr; +} + +template +void CKeyValues3ClusterImpl::PurgeMetaData( int element ) +{ + if(!m_pMetaData) + return; + + Assert( element >= 0 && element < m_pMetaData->m_AllocatedElements ); + GetMetaData( element )->Clear(); +} + +template +KV3MetaData_t *CKeyValues3ClusterImpl::GetMetaData( int element ) const +{ + if(!m_pMetaData) + return nullptr; + + Assert( element >= 0 && element < m_pMetaData->m_AllocatedElements ); + return &m_pMetaData->m_elements[element]; +} + +template +inline void CKeyValues3ContextBase::ClusterNodeChain::AddToChain( CLUSTER *cluster ) +{ + if(m_pTail) + m_pTail->SetNext( cluster ); + else + m_pHead = cluster; + + cluster->SetNext( nullptr ); + cluster->SetPrev( m_pTail ); + + m_pTail = cluster; +} + +template +inline void CKeyValues3ContextBase::ClusterNodeChain::RemoveFromChain( CLUSTER *cluster ) +{ + auto prev = cluster->GetPrev(); + auto next = cluster->GetNext(); + + if(prev) + prev->SetNext( next ); + else + m_pHead = next; + + if(next) + next->SetPrev( prev ); + else + m_pTail = prev; + + cluster->SetPrev( nullptr ); + cluster->SetNext( nullptr ); +} + +template +inline void CKeyValues3ContextBase::NodeList::EnsureByteSize( int bytes_needed ) +{ + if(bytes_needed < m_nAllocatedBytes) + return; + + int new_alloc_size = KV3Helpers::CalcNewBufferSize( m_nAllocatedBytes, bytes_needed, ALLOC_CONTEXT_NODELIST_MIN, ALLOC_CONTEXT_NODELIST_MAX ); + + m_pData = (ListEntry *)realloc( m_pData, new_alloc_size ); + m_nAllocatedBytes = new_alloc_size; +} + +template +inline NODE *CKeyValues3ContextBase::NodeList::Alloc( int initial_size ) +{ + int byte_size_needed = m_nUsedBytes + NODE::TotalSizeOf( initial_size ) + 8; + EnsureByteSize( byte_size_needed ); + + auto entry = Tail(); + m_nUsedBytes = byte_size_needed; + + Construct( &entry->m_Value, -1, initial_size ); + entry->m_pNext = Tail(); + + return &entry->m_Value; +} + +template +inline void CKeyValues3ContextBase::NodeList::Clear() +{ + if(m_nAllocatedBytes > 0) + { + for(auto iter = Head(); iter; iter = iter->m_pNext) + { + Destruct( iter ); + } + } + + m_nUsedBytes = 0; +} + +template +inline void CKeyValues3ContextBase::NodeList::Purge() +{ + Clear(); + + free( m_pData ); + m_pData = nullptr; +} + +template +inline void CKeyValues3Context::PurgeClusterNodeChain( ClusterNodeChain &cluster_node ) +{ + for(auto node = cluster_node.m_pTail; node; node = node->GetPrev()) + { + if(node->IsAllocatedOnHeap()) + { + node->Purge(); + g_pMemAlloc->RegionFree( MEMALLOC_REGION_FREE_4, node ); } else { - head = cluster->GetNextFree(); + node->Clear(); } - - delete cluster; } - else if ( num_allocated == ( KV3_CLUSTER_MAX_ELEMENTS - 1 ) ) + + cluster_node.Reset(); +} + +template +inline void CKeyValues3Context::ClearClusterNodeChain( ClusterNodeChain &cluster_node ) +{ + for(auto node = cluster_node.m_pTail; node; node = node->GetPrev()) { - cluster->SetNextFree( head ); - head = cluster; + node->Clear(); + } +} + +template +inline void CKeyValues3Context::MoveToPartial( ClusterNodeChain &full_cluster, ClusterNodeChain &partial_cluster ) +{ + for(auto node = full_cluster.m_pTail; node; node = node->GetPrev()) + { + partial_cluster.AddToChain( node ); + } + + full_cluster.Reset(); +} + +template +auto CKeyValues3Context::Alloc( ClusterNodeChain &partial_clusters, + ClusterNodeChain &full_clusters, + int initial_size, Args&&... args ) +{ + auto cluster = partial_clusters.m_pTail; + typename CLUSTER::NodeType *elem = nullptr; + + if(cluster) + { + elem = cluster->Alloc( std::forward( args )... ); + + if(cluster->IsFull()) + { + partial_clusters.RemoveFromChain( cluster ); + full_clusters.AddToChain( cluster ); + } + } + else + { + cluster = (CLUSTER *)g_pMemAlloc->RegionAlloc( MEMALLOC_REGION_ALLOC_4, CLUSTER::TotalSizeOf( initial_size ) ); + + Construct( cluster, this, true, initial_size ); + partial_clusters.AddToChain( cluster ); + + elem = cluster->Alloc( std::forward( args )... ); + } + + return elem; +} + +template +inline NODE *CKeyValues3Context::RawAlloc( NodeList &raw_array, ClusterNodeChain &partial_clusters, ClusterNodeChain &full_clusters, int initial_size, Args && ...args ) +{ + int needed_byte_size = MAX( NODE::TotalSizeOf( initial_size ), 32 ); + + if(raw_array.IsFull() || needed_byte_size > raw_array.FreeBytes()) + { + if(initial_size <= NODE::DATA_SIZE) + return Alloc( partial_clusters, full_clusters, CLUSTER::CLUSTER_SIZE ); + else + return nullptr; + } + + return raw_array.Alloc( initial_size ); +} + +template +void CKeyValues3Context::Free( NODE *element, ClusterNodeChain &partial_clusters, ClusterNodeChain &full_clusters ) +{ + auto cluster = element->GetCluster(); + + Assert( cluster != nullptr && cluster->GetContext() == m_pContext ); + + cluster->Free( element ); + + int num_allocated = cluster->NumAllocated(); + + if(cluster->NumCount() > 0) + { + if(cluster->NumCount() == cluster->NumAllocated() - 1) + { + full_clusters.RemoveFromChain( cluster ); + partial_clusters.AddToChain( cluster ); + } + } + else if(cluster->IsAllocatedOnHeap()) + { + partial_clusters.RemoveFromChain( cluster ); + + Destruct( cluster ); + g_pMemAlloc->RegionFree( MEMALLOC_REGION_FREE_4, cluster ); } } diff --git a/tier1/keyvalues3.cpp b/tier1/keyvalues3.cpp index 5a0ca0ae..680772b7 100644 --- a/tier1/keyvalues3.cpp +++ b/tier1/keyvalues3.cpp @@ -10,26 +10,20 @@ #endif KeyValues3::KeyValues3( KV3TypeEx_t type, KV3SubType_t subtype ) : + KeyValues3( -1, type, subtype ) +{ +} + +KeyValues3::KeyValues3( int cluster_elem, KV3TypeEx_t type, KV3SubType_t subtype ) : m_bExternalStorage( true ), m_TypeEx( type ), m_SubType( subtype ), m_nFlags( 0 ), - m_nReserved( 0 ), - m_nData( 0 ) -{ - ResolveUnspecified(); - Alloc(); -} - -KeyValues3::KeyValues3( int cluster_elem, KV3TypeEx_t type, KV3SubType_t subtype ) : - m_bExternalStorage( false ), - m_TypeEx( type ), - m_SubType( subtype ), - m_nFlags( 0 ), - m_nClusterElement( cluster_elem ), - m_nReserved( 0 ), - m_nData( 0 ) + m_nClusterElement( (uint16)-1 ), + m_nNumArrayElements( 0 ), + m_nReserved( 0 ) { + SetClusterElement( cluster_elem ); ResolveUnspecified(); Alloc(); } @@ -39,26 +33,36 @@ KeyValues3::~KeyValues3() Free(); }; -void KeyValues3::Alloc() +void KeyValues3::Alloc( int initial_size, Data_t data, int preallocated_size, bool should_free ) { switch ( GetTypeEx() ) { case KV3_TYPEEX_ARRAY: { - CKeyValues3Context* context = GetContext(); - if ( context ) - m_pArray = context->AllocArray(); + if(preallocated_size <= 0) + { + m_Data.m_pArray = AllocArray(); + m_bFreeArrayMemory = true; + } else - m_pArray = new CKeyValues3Array; + { + AllocArrayInPlace( initial_size, data, preallocated_size, should_free ); + } + break; } case KV3_TYPEEX_TABLE: { - CKeyValues3Context* context = GetContext(); - if ( context ) - m_pTable = context->AllocTable(); + if(preallocated_size <= 0) + { + m_Data.m_pTable = AllocTable(); + m_bFreeArrayMemory = true; + } else - m_pTable = new CKeyValues3Table; + { + AllocTableInPlace( initial_size, data, preallocated_size, should_free ); + } + break; } case KV3_TYPEEX_ARRAY_FLOAT32: @@ -70,7 +74,7 @@ void KeyValues3::Alloc() { m_bFreeArrayMemory = false; m_nNumArrayElements = 0; - m_nData = 0; + m_Data.m_pMemory = NULL; break; } default: @@ -78,70 +82,199 @@ void KeyValues3::Alloc() } } +void KeyValues3::AllocArrayInPlace( int initial_size, Data_t data, int preallocated_size, bool should_free ) +{ + int bytes_needed = MAX( CKeyValues3Array::TotalSizeOf( 0 ), CKeyValues3Array::TotalSizeOf( initial_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 ); + + m_Data.m_pArray = data.m_pArray; + m_bFreeArrayMemory = should_free; +} + +void KeyValues3::AllocTableInPlace( int initial_size, Data_t data, int preallocated_size, bool should_free ) +{ + int bytes_needed = MAX( CKeyValues3Array::TotalSizeOf( 0 ), CKeyValues3Array::TotalSizeOf( initial_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 ); + + m_Data.m_pTable = data.m_pTable; + m_bFreeArrayMemory = should_free; +} + +CKeyValues3Array *KeyValues3::AllocArray( int initial_size ) +{ + auto context = GetContext(); + + if(context) + { + auto arr = context->AllocArray( initial_size ); + + if(arr) + return arr; + } + + return AllocateOnHeap( initial_size ); +} + +CKeyValues3Table* KeyValues3::AllocTable( int initial_size ) +{ + auto context = GetContext(); + + if(context) + { + auto table = context->AllocTable( initial_size ); + + if(table) + return table; + } + + return AllocateOnHeap( initial_size ); +} + +void KeyValues3::FreeArray( CKeyValues3Array *element, bool clearing_context ) +{ + if(!element) + return; + + element->PurgeContent( this, clearing_context ); + + if(!m_bFreeArrayMemory) + { + Destruct( element ); + } + else + { + auto context = GetContext(); + bool raw_allocated = context && context->IsArrayRawAllocated( element ); + + if(!raw_allocated && element->GetClusterElement() < 0) + { + FreeOnHeap( element ); + } + else if(!clearing_context) + { + if(!raw_allocated) + context->FreeArray( element ); + else + Destruct( element ); + } + } +} + +void KeyValues3::FreeTable( CKeyValues3Table *element, bool clearing_context ) +{ + if(!element) + return; + + element->PurgeContent( this, clearing_context ); + + if(!m_bFreeArrayMemory) + { + Destruct( element ); + } + else + { + auto context = GetContext(); + bool raw_allocated = context && context->IsTableRawAllocated( element ); + + if(!raw_allocated && element->GetClusterElement() < 0) + { + FreeOnHeap( element ); + } + else if(!clearing_context) + { + if(!raw_allocated) + context->FreeTable( element ); + else + Destruct( element ); + } + } +} + +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 ); +} + +void KeyValues3::FreeMember( KeyValues3 *member ) +{ + auto context = GetContext(); + + if(context) + { + auto cluster = member->GetCluster(); + + cluster->PurgeMetaData( cluster->GetNodeIndex( member ) ); + context->FreeKV( member ); + } + else + { + delete member; + } +} + void KeyValues3::Free( bool bClearingContext ) { switch ( GetTypeEx() ) { case KV3_TYPEEX_STRING: { - free( (void*)m_pString ); - m_pString = NULL; + free( (void*)m_Data.m_pString ); + m_Data.m_pString = nullptr; break; } case KV3_TYPEEX_BINARY_BLOB: { - if ( m_pBinaryBlob ) - free( m_pBinaryBlob ); - m_pBinaryBlob = NULL; + if ( m_Data.m_pBinaryBlob ) + free( m_Data.m_pBinaryBlob ); + m_Data.m_pBinaryBlob = nullptr; break; } case KV3_TYPEEX_BINARY_BLOB_EXTERN: { - if ( m_pBinaryBlob ) + if ( m_Data.m_pBinaryBlob ) { - if ( m_pBinaryBlob->m_bFreeMemory ) - free( (void*)m_pBinaryBlob->m_pubData ); - free( m_pBinaryBlob ); + if ( m_Data.m_pBinaryBlob->m_bFreeMemory ) + free( (void*)m_Data.m_pBinaryBlob->m_pubData ); + free( m_Data.m_pBinaryBlob ); } - m_pBinaryBlob = NULL; + m_Data.m_pBinaryBlob = nullptr; break; } case KV3_TYPEEX_ARRAY: { - m_pArray->Purge( bClearingContext ); + FreeArray( m_Data.m_pArray ); - CKeyValues3Context* context = GetContext(); + m_bFreeArrayMemory = false; + m_Data.m_pArray = nullptr; - if ( context ) - { - if ( !bClearingContext ) - context->FreeArray( m_pArray ); - } - else - { - delete m_pArray; - } - - m_pArray = NULL; break; } case KV3_TYPEEX_TABLE: { - m_pTable->Purge( bClearingContext ); + FreeTable( m_Data.m_pTable ); - CKeyValues3Context* context = GetContext(); + m_bFreeArrayMemory = false; + m_Data.m_pTable = nullptr; - if ( context ) - { - if ( !bClearingContext ) - context->FreeTable( m_pTable ); - } - else - { - delete m_pTable; - } - - m_pTable = NULL; break; } case KV3_TYPEEX_ARRAY_FLOAT32: @@ -152,10 +285,10 @@ void KeyValues3::Free( bool bClearingContext ) case KV3_TYPEEX_ARRAY_INT16_SHORT: { if ( m_bFreeArrayMemory ) - free( m_pData ); + free( m_Data.m_pMemory ); m_bFreeArrayMemory = false; m_nNumArrayElements = 0; - m_nData = 0; + m_Data.m_nMemory = 0; break; } default: @@ -230,7 +363,6 @@ void KeyValues3::PrepareForType( KV3TypeEx_t type, KV3SubType_t subtype ) { Free(); m_TypeEx = type; - m_nData = 0; Alloc(); } @@ -241,7 +373,7 @@ void KeyValues3::OnClearContext() { Free( true ); m_TypeEx = KV3_TYPEEX_NULL; - m_nData = 0; + m_Data.m_nMemory = 0; } CKeyValues3Cluster* KeyValues3::GetCluster() const @@ -249,7 +381,7 @@ CKeyValues3Cluster* KeyValues3::GetCluster() const if ( m_bExternalStorage ) return NULL; - return GET_OUTER( CKeyValues3Cluster, m_KeyValues[ m_nClusterElement ] ); + return GET_OUTER( CKeyValues3Cluster, m_Values[ m_nClusterElement ] ); } CKeyValues3Context* KeyValues3::GetContext() const @@ -288,9 +420,9 @@ const char* KeyValues3::GetString( const char* defaultValue ) const { case KV3_TYPEEX_STRING: case KV3_TYPEEX_STRING_EXTERN: - return m_pString; + return m_Data.m_pString; case KV3_TYPEEX_STRING_SHORT: - return m_szStringShort; + return m_Data.m_szStringShort; default: return defaultValue; } @@ -301,29 +433,29 @@ void KeyValues3::SetString( const char* pString, KV3SubType_t subtype ) if ( !pString ) pString = ""; - if ( strlen( pString ) < sizeof( m_szStringShort ) ) + if ( strlen( pString ) < sizeof( m_Data.m_szStringShort ) ) { PrepareForType( KV3_TYPEEX_STRING_SHORT, subtype ); - V_strncpy( m_szStringShort, pString, sizeof( m_szStringShort ) ); + V_strncpy( m_Data.m_szStringShort, pString, sizeof( m_Data.m_szStringShort ) ); } else { PrepareForType( KV3_TYPEEX_STRING, subtype ); - m_pString = strdup( pString ); + m_Data.m_pString = strdup( pString ); } } void KeyValues3::SetStringExternal( const char* pString, KV3SubType_t subtype ) { - if ( strlen( pString ) < sizeof( m_szStringShort ) ) + if ( strlen( pString ) < sizeof( m_Data.m_szStringShort ) ) { PrepareForType( KV3_TYPEEX_STRING_SHORT, subtype ); - V_strncpy( m_szStringShort, pString, sizeof( m_szStringShort ) ); + V_strncpy( m_Data.m_szStringShort, pString, sizeof( m_Data.m_szStringShort ) ); } else { PrepareForType( KV3_TYPEEX_STRING_EXTERN, subtype ); - m_pString = pString; + m_Data.m_pString = pString; } } @@ -332,9 +464,9 @@ const byte* KeyValues3::GetBinaryBlob() const switch ( GetTypeEx() ) { case KV3_TYPEEX_BINARY_BLOB: - return m_pBinaryBlob ? m_pBinaryBlob->m_ubData : NULL; + return m_Data.m_pBinaryBlob ? m_Data.m_pBinaryBlob->m_ubData : NULL; case KV3_TYPEEX_BINARY_BLOB_EXTERN: - return m_pBinaryBlob ? m_pBinaryBlob->m_pubData : NULL; + return m_Data.m_pBinaryBlob ? m_Data.m_pBinaryBlob->m_pubData : NULL; default: return NULL; } @@ -342,10 +474,10 @@ const byte* KeyValues3::GetBinaryBlob() const int KeyValues3::GetBinaryBlobSize() const { - if ( GetType() != KV3_TYPE_BINARY_BLOB || !m_pBinaryBlob ) + if ( GetType() != KV3_TYPE_BINARY_BLOB || !m_Data.m_pBinaryBlob ) return 0; - return ( int )m_pBinaryBlob->m_nSize; + return ( int )m_Data.m_pBinaryBlob->m_nSize; } void KeyValues3::SetToBinaryBlob( const byte* blob, int size ) @@ -354,13 +486,13 @@ void KeyValues3::SetToBinaryBlob( const byte* blob, int size ) if ( size > 0 ) { - m_pBinaryBlob = (KV3BinaryBlob_t*)malloc( sizeof( size_t ) + size ); - m_pBinaryBlob->m_nSize = size; - memcpy( m_pBinaryBlob->m_ubData, blob, size ); + m_Data.m_pBinaryBlob = (KV3BinaryBlob_t*)malloc( sizeof( size_t ) + size ); + m_Data.m_pBinaryBlob->m_nSize = size; + memcpy( m_Data.m_pBinaryBlob->m_ubData, blob, size ); } else { - m_pBinaryBlob = NULL; + m_Data.m_pBinaryBlob = NULL; } } @@ -370,14 +502,14 @@ void KeyValues3::SetToBinaryBlobExternal( const byte* blob, int size, bool free_ if ( size > 0 ) { - m_pBinaryBlob = (KV3BinaryBlob_t*)malloc( sizeof( KV3BinaryBlob_t ) ); - m_pBinaryBlob->m_nSize = size; - m_pBinaryBlob->m_pubData = blob; - m_pBinaryBlob->m_bFreeMemory = free_mem; + m_Data.m_pBinaryBlob = (KV3BinaryBlob_t*)malloc( sizeof( KV3BinaryBlob_t ) ); + m_Data.m_pBinaryBlob->m_nSize = size; + m_Data.m_pBinaryBlob->m_pubData = blob; + m_Data.m_pBinaryBlob->m_bFreeMemory = free_mem; } else { - m_pBinaryBlob = NULL; + m_Data.m_pBinaryBlob = NULL; } } @@ -412,72 +544,60 @@ int KeyValues3::GetArrayElementCount() const return 0; if ( GetTypeEx() == KV3_TYPEEX_ARRAY ) - return m_pArray->Count(); + return m_Data.m_pArray->Count(); else return m_nNumArrayElements; } KeyValues3** KeyValues3::GetArrayBase() { - if ( GetType() != KV3_TYPE_ARRAY ) + if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) return NULL; - NormalizeArray(); - - return m_pArray->Base(); + return m_Data.m_pArray->Base(); } KeyValues3* KeyValues3::GetArrayElement( int elem ) { - if ( GetType() != KV3_TYPE_ARRAY ) + if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) return NULL; - NormalizeArray(); - - if ( elem < 0 || elem >= m_pArray->Count() ) + if ( elem < 0 || elem >= m_Data.m_pArray->Count() ) return NULL; - return m_pArray->Element( elem ); + return m_Data.m_pArray->Element( elem ); } KeyValues3* KeyValues3::InsertArrayElementBefore( int elem ) { - if ( GetType() != KV3_TYPE_ARRAY ) + if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) return NULL; - NormalizeArray(); - - return *m_pArray->InsertBeforeGetPtr( elem, 1 ); + return *m_Data.m_pArray->InsertMultipleBefore( this, elem, 1 ); } KeyValues3* KeyValues3::AddArrayElementToTail() { - if ( GetType() != KV3_TYPE_ARRAY ) - PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY ); - else - NormalizeArray(); + if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) + return NULL; - return *m_pArray->InsertBeforeGetPtr( m_pArray->Count(), 1 ); + return *m_Data.m_pArray->InsertMultipleBefore( this, m_Data.m_pArray->Count(), 1 ); } void KeyValues3::SetArrayElementCount( int count, KV3TypeEx_t type, KV3SubType_t subtype ) { - if ( GetType() != KV3_TYPE_ARRAY ) - PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY ); - else - NormalizeArray(); + if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) + return; - m_pArray->SetCount( count, type, subtype ); + m_Data.m_pArray->SetCount( this, count, type, subtype ); } void KeyValues3::RemoveArrayElements( int elem, int num ) { - if ( GetType() != KV3_TYPE_ARRAY ) + if ( GetTypeEx() != KV3_TYPEEX_ARRAY ) return; - NormalizeArray(); - - m_pArray->RemoveMultiple( elem, num ); + m_Data.m_pArray->RemoveMultiple( this, elem, num ); } void KeyValues3::NormalizeArray() @@ -486,35 +606,35 @@ void KeyValues3::NormalizeArray() { case KV3_TYPEEX_ARRAY_FLOAT32: { - NormalizeArray( KV3_TYPEEX_DOUBLE, KV3_SUBTYPE_FLOAT32, m_nNumArrayElements, m_f32Array, m_bFreeArrayMemory ); + NormalizeArray( KV3_TYPEEX_DOUBLE, KV3_SUBTYPE_FLOAT32, m_nNumArrayElements, m_Data.m_Array.m_f32, m_bFreeArrayMemory ); break; } case KV3_TYPEEX_ARRAY_FLOAT64: { - NormalizeArray( KV3_TYPEEX_DOUBLE, KV3_SUBTYPE_FLOAT64, m_nNumArrayElements, m_f64Array, m_bFreeArrayMemory ); + NormalizeArray( KV3_TYPEEX_DOUBLE, KV3_SUBTYPE_FLOAT64, m_nNumArrayElements, m_Data.m_Array.m_f64, m_bFreeArrayMemory ); break; } case KV3_TYPEEX_ARRAY_INT16: { - NormalizeArray( KV3_TYPEEX_INT, KV3_SUBTYPE_INT16, m_nNumArrayElements, m_i16Array, m_bFreeArrayMemory ); + NormalizeArray( KV3_TYPEEX_INT, KV3_SUBTYPE_INT16, m_nNumArrayElements, m_Data.m_Array.m_i16, m_bFreeArrayMemory ); break; } case KV3_TYPEEX_ARRAY_INT32: { - NormalizeArray( KV3_TYPEEX_INT, KV3_SUBTYPE_INT32, m_nNumArrayElements, m_i32Array, m_bFreeArrayMemory ); + NormalizeArray( KV3_TYPEEX_INT, KV3_SUBTYPE_INT32, m_nNumArrayElements, m_Data.m_Array.m_i32, m_bFreeArrayMemory ); break; } case KV3_TYPEEX_ARRAY_UINT8_SHORT: { uint8 u8ArrayShort[8]; - memcpy( u8ArrayShort, m_u8ArrayShort, sizeof( u8ArrayShort ) ); + memcpy( u8ArrayShort, m_Data.m_Array.m_u8Short, sizeof( u8ArrayShort ) ); NormalizeArray( KV3_TYPEEX_UINT, KV3_SUBTYPE_UINT8, m_nNumArrayElements, u8ArrayShort, false ); break; } case KV3_TYPEEX_ARRAY_INT16_SHORT: { int16 i16ArrayShort[4]; - memcpy( i16ArrayShort, m_i16ArrayShort, sizeof( i16ArrayShort ) ); + memcpy( i16ArrayShort, m_Data.m_Array.m_u8Short, sizeof( i16ArrayShort ) ); NormalizeArray( KV3_TYPEEX_INT, KV3_SUBTYPE_INT16, m_nNumArrayElements, i16ArrayShort, false ); break; } @@ -541,9 +661,9 @@ bool KeyValues3::ReadArrayInt32( int dest_size, int32* data ) const { case KV3_TYPEEX_ARRAY: { - src_size = m_pArray->Count(); + src_size = m_Data.m_pArray->Count(); int count = MIN( src_size, dest_size ); - KeyValues3** arr = m_pArray->Base(); + KeyValues3** arr = m_Data.m_pArray->Base(); for ( int i = 0; i < count; ++i ) data[ i ] = arr[ i ]->GetInt(); break; @@ -553,14 +673,14 @@ bool KeyValues3::ReadArrayInt32( int dest_size, int32* data ) const src_size = m_nNumArrayElements; int count = MIN( src_size, dest_size ); for ( int i = 0; i < count; ++i ) - data[ i ] = ( int32 )m_i16Array[ i ]; + data[ i ] = ( int32 )m_Data.m_Array.m_u8Short[ i ]; break; } case KV3_TYPEEX_ARRAY_INT32: { src_size = m_nNumArrayElements; int count = MIN( src_size, dest_size ); - memcpy( data, m_i32Array, count * sizeof( int32 ) ); + memcpy( data, m_Data.m_Array.m_i32, count * sizeof( int32 ) ); break; } case KV3_TYPEEX_ARRAY_UINT8_SHORT: @@ -568,7 +688,7 @@ bool KeyValues3::ReadArrayInt32( int dest_size, int32* data ) const src_size = m_nNumArrayElements; int count = MIN( src_size, dest_size ); for ( int i = 0; i < count; ++i ) - data[ i ] = ( int32 )m_u8ArrayShort[ i ]; + data[ i ] = ( int32 )m_Data.m_Array.m_u8Short[ i ]; break; } case KV3_TYPEEX_ARRAY_INT16_SHORT: @@ -576,7 +696,7 @@ bool KeyValues3::ReadArrayInt32( int dest_size, int32* data ) const src_size = m_nNumArrayElements; int count = MIN( src_size, dest_size ); for ( int i = 0; i < count; ++i ) - data[ i ] = ( int32 )m_i16ArrayShort[ i ]; + data[ i ] = ( int32 )m_Data.m_Array.m_u8Short[ i ]; break; } default: @@ -608,9 +728,9 @@ bool KeyValues3::ReadArrayFloat32( int dest_size, float32* data ) const { case KV3_TYPEEX_ARRAY: { - src_size = m_pArray->Count(); + src_size = m_Data.m_pArray->Count(); int count = MIN( src_size, dest_size ); - KeyValues3** arr = m_pArray->Base(); + KeyValues3** arr = m_Data.m_pArray->Base(); for ( int i = 0; i < count; ++i ) data[ i ] = arr[ i ]->GetFloat(); break; @@ -619,7 +739,7 @@ bool KeyValues3::ReadArrayFloat32( int dest_size, float32* data ) const { src_size = m_nNumArrayElements; int count = MIN( src_size, dest_size ); - memcpy( data, m_f32Array, count * sizeof( float32 ) ); + memcpy( data, m_Data.m_Array.m_f32, count * sizeof( float32 ) ); break; } case KV3_TYPEEX_ARRAY_FLOAT64: @@ -627,7 +747,7 @@ bool KeyValues3::ReadArrayFloat32( int dest_size, float32* data ) const src_size = m_nNumArrayElements; int count = MIN( src_size, dest_size ); for ( int i = 0; i < count; ++i ) - data[ i ] = ( float32 )m_f64Array[ i ]; + data[ i ] = ( float32 )m_Data.m_Array.m_f64[ i ]; break; } default: @@ -646,39 +766,39 @@ int KeyValues3::GetMemberCount() const if ( GetType() != KV3_TYPE_TABLE ) return 0; - return m_pTable->GetMemberCount(); + return m_Data.m_pTable->GetMemberCount(); } KeyValues3* KeyValues3::GetMember( KV3MemberId_t id ) { - if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_pTable->GetMemberCount() ) + if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_Data.m_pTable->GetMemberCount() ) return NULL; - return m_pTable->GetMember( id ); + return m_Data.m_pTable->GetMember( id ); } const char* KeyValues3::GetMemberName( KV3MemberId_t id ) const { - if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_pTable->GetMemberCount() ) + if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_Data.m_pTable->GetMemberCount() ) return NULL; - return m_pTable->GetMemberName( id ); + return m_Data.m_pTable->GetMemberName( id ); } CKV3MemberName KeyValues3::GetMemberNameEx( KV3MemberId_t id ) const { - if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_pTable->GetMemberCount() ) + if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_Data.m_pTable->GetMemberCount() ) return CKV3MemberName(); - return CKV3MemberName( m_pTable->GetMemberHash( id ), m_pTable->GetMemberName( id ) ); + return CKV3MemberName( m_Data.m_pTable->GetMemberHash( id ), m_Data.m_pTable->GetMemberName( id ) ); } unsigned int KeyValues3::GetMemberHash( KV3MemberId_t id ) const { - if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_pTable->GetMemberCount() ) + if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_Data.m_pTable->GetMemberCount() ) return 0; - return m_pTable->GetMemberHash( id ); + return m_Data.m_pTable->GetMemberHash( id ); } KeyValues3* KeyValues3::FindMember( const CKV3MemberName &name, KeyValues3* defaultValue ) @@ -686,12 +806,12 @@ KeyValues3* KeyValues3::FindMember( const CKV3MemberName &name, KeyValues3* defa if ( GetType() != KV3_TYPE_TABLE ) return defaultValue; - KV3MemberId_t id = m_pTable->FindMember( name ); + KV3MemberId_t id = m_Data.m_pTable->FindMember( name ); if ( id == KV3_INVALID_MEMBER ) return defaultValue; - return m_pTable->GetMember( id ); + return m_Data.m_pTable->GetMember( id ); } KeyValues3* KeyValues3::FindOrCreateMember( const CKV3MemberName &name, bool *pCreated ) @@ -699,14 +819,14 @@ KeyValues3* KeyValues3::FindOrCreateMember( const CKV3MemberName &name, bool *pC if ( GetType() != KV3_TYPE_TABLE ) PrepareForType( KV3_TYPEEX_TABLE, KV3_SUBTYPE_TABLE ); - KV3MemberId_t id = m_pTable->FindMember( name ); + KV3MemberId_t id = m_Data.m_pTable->FindMember( name ); if ( id == KV3_INVALID_MEMBER ) { if ( pCreated ) *pCreated = true; - id = m_pTable->CreateMember( name ); + id = m_Data.m_pTable->CreateMember( this, name ); } else { @@ -714,37 +834,21 @@ KeyValues3* KeyValues3::FindOrCreateMember( const CKV3MemberName &name, bool *pC *pCreated = false; } - return m_pTable->GetMember( id ); -} - -bool KeyValues3::TableHasBadNames() const -{ - if ( GetType() != KV3_TYPE_TABLE ) - return false; - - return m_pTable->HasBadNames(); -} - -void KeyValues3::SetTableHasBadNames( bool bHasBadNames ) -{ - if ( GetType() != KV3_TYPE_TABLE ) - return; - - m_pTable->SetHasBadNames( bHasBadNames ); + return m_Data.m_pTable->GetMember( id ); } void KeyValues3::SetToEmptyTable() { PrepareForType( KV3_TYPEEX_TABLE, KV3_SUBTYPE_TABLE ); - m_pTable->RemoveAll(); + m_Data.m_pTable->RemoveAll( this ); } bool KeyValues3::RemoveMember( KV3MemberId_t id ) { - if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_pTable->GetMemberCount() ) + if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_Data.m_pTable->GetMemberCount() ) return false; - m_pTable->RemoveMember( id ); + m_Data.m_pTable->RemoveMember( this, id ); return true; } @@ -754,12 +858,12 @@ bool KeyValues3::RemoveMember( const KeyValues3* kv ) if ( GetType() != KV3_TYPE_TABLE ) return false; - KV3MemberId_t id = m_pTable->FindMember( kv ); + KV3MemberId_t id = m_Data.m_pTable->FindMember( kv ); if ( id == KV3_INVALID_MEMBER ) return false; - m_pTable->RemoveMember( id ); + m_Data.m_pTable->RemoveMember( this, id ); return true; } @@ -769,12 +873,12 @@ bool KeyValues3::RemoveMember( const CKV3MemberName &name ) if ( GetType() != KV3_TYPE_TABLE ) return false; - KV3MemberId_t id = m_pTable->FindMember( name ); + KV3MemberId_t id = m_Data.m_pTable->FindMember( name ); if ( id == KV3_INVALID_MEMBER ) return false; - m_pTable->RemoveMember( id ); + m_Data.m_pTable->RemoveMember( this, id ); return true; } @@ -815,6 +919,7 @@ const char* KeyValues3::GetSubTypeAsString() const "soundevent", "subclass", "entity_name", + "localize", "unspecified", "null", "binary_blob", @@ -874,7 +979,7 @@ const char* KeyValues3::ToString( CBufferString& buff, uint flags ) const } case KV3_TYPE_BOOL: { - const char* str = m_Bool ? "true" : "false"; + const char* str = m_Data.m_Bool ? "true" : "false"; if ( ( flags & KV3_TO_STRING_DONT_APPEND_STRINGS ) != 0 ) return str; @@ -884,7 +989,7 @@ const char* KeyValues3::ToString( CBufferString& buff, uint flags ) const } case KV3_TYPE_INT: { - buff.AppendFormat( "%lld", m_Int ); + buff.AppendFormat( "%lld", m_Data.m_Int ); return buff.ToGrowable()->Get(); } case KV3_TYPE_UINT: @@ -900,12 +1005,12 @@ const char* KeyValues3::ToString( CBufferString& buff, uint flags ) const return buff.ToGrowable()->Get(); } - buff.AppendFormat( "%llu", m_UInt ); + buff.AppendFormat( "%llu", m_Data.m_UInt ); return buff.ToGrowable()->Get(); } case KV3_TYPE_DOUBLE: { - buff.AppendFormat( "%g", m_Double ); + buff.AppendFormat( "%g", m_Data.m_Double ); return buff.ToGrowable()->Get(); } case KV3_TYPE_STRING: @@ -941,22 +1046,22 @@ const char* KeyValues3::ToString( CBufferString& buff, uint flags ) const bool unprintable = false; CBufferStringGrowable<128> temp; - KeyValues3** arr = m_pArray->Base(); + CKeyValues3Array::Element_t* arr = m_Data.m_pArray->Base(); for ( int i = 0; i < elements; ++i ) { switch ( arr[i]->GetType() ) { case KV3_TYPE_INT: - temp.AppendFormat( "%lld", arr[i]->m_Int ); + temp.AppendFormat( "%lld", arr[i]->m_Data.m_Int ); break; case KV3_TYPE_UINT: if ( arr[i]->GetSubType() == KV3_SUBTYPE_POINTER ) unprintable = true; else - temp.AppendFormat( "%llu", arr[i]->m_UInt ); + temp.AppendFormat( "%llu", arr[i]->m_Data.m_UInt ); break; case KV3_TYPE_DOUBLE: - temp.AppendFormat( "%g", arr[i]->m_Double ); + temp.AppendFormat( "%g", arr[i]->m_Data.m_Double ); break; default: unprintable = true; @@ -979,7 +1084,7 @@ const char* KeyValues3::ToString( CBufferString& buff, uint flags ) const { for ( int i = 0; i < elements; ++i ) { - buff.AppendFormat( "%g", m_f32Array[i] ); + buff.AppendFormat( "%g", m_Data.m_Array.m_f32[i] ); if ( i != elements - 1 ) buff.Insert( buff.ToGrowable()->GetTotalNumber(), " " ); } return buff.ToGrowable()->Get(); @@ -988,7 +1093,7 @@ const char* KeyValues3::ToString( CBufferString& buff, uint flags ) const { for ( int i = 0; i < elements; ++i ) { - buff.AppendFormat( "%g", m_f64Array[i] ); + buff.AppendFormat( "%g", m_Data.m_Array.m_f64[i] ); if ( i != elements - 1 ) buff.Insert( buff.ToGrowable()->GetTotalNumber(), " " ); } return buff.ToGrowable()->Get(); @@ -997,7 +1102,7 @@ const char* KeyValues3::ToString( CBufferString& buff, uint flags ) const { for ( int i = 0; i < elements; ++i ) { - buff.AppendFormat( "%d", m_i16Array[i] ); + buff.AppendFormat( "%d", m_Data.m_Array.m_i16Short[i] ); if ( i != elements - 1 ) buff.Insert( buff.ToGrowable()->GetTotalNumber(), " " ); } return buff.ToGrowable()->Get(); @@ -1006,7 +1111,7 @@ const char* KeyValues3::ToString( CBufferString& buff, uint flags ) const { for ( int i = 0; i < elements; ++i ) { - buff.AppendFormat( "%d", m_i32Array[i] ); + buff.AppendFormat( "%d", m_Data.m_Array.m_i32[i] ); if ( i != elements - 1 ) buff.Insert( buff.ToGrowable()->GetTotalNumber(), " " ); } return buff.ToGrowable()->Get(); @@ -1015,7 +1120,7 @@ const char* KeyValues3::ToString( CBufferString& buff, uint flags ) const { for ( int i = 0; i < elements; ++i ) { - buff.AppendFormat( "%u", m_u8ArrayShort[i] ); + buff.AppendFormat( "%u", m_Data.m_Array.m_u8Short[i] ); if ( i != elements - 1 ) buff.Insert( buff.ToGrowable()->GetTotalNumber(), " " ); } return buff.ToGrowable()->Get(); @@ -1024,7 +1129,7 @@ const char* KeyValues3::ToString( CBufferString& buff, uint flags ) const { for ( int i = 0; i < elements; ++i ) { - buff.AppendFormat( "%d", m_i16ArrayShort[i] ); + buff.AppendFormat( "%d", m_Data.m_Array.m_i16Short[i] ); if ( i != elements - 1 ) buff.Insert( buff.ToGrowable()->GetTotalNumber(), " " ); } return buff.ToGrowable()->Get(); @@ -1067,6 +1172,9 @@ const char* KeyValues3::ToString( CBufferString& buff, uint flags ) const void KeyValues3::CopyFrom( const KeyValues3* pSrc ) { + if(this == pSrc) + return; + SetToNull(); CKeyValues3Context* context; @@ -1087,16 +1195,16 @@ void KeyValues3::CopyFrom( const KeyValues3* pSrc ) switch ( pSrc->GetType() ) { case KV3_TYPE_BOOL: - SetBool( pSrc->m_Bool ); + SetBool( pSrc->m_Data.m_Bool ); break; case KV3_TYPE_INT: - SetValue( pSrc->m_Int, KV3_TYPEEX_INT, eSrcSubType ); + SetValue( pSrc->m_Data.m_Int, KV3_TYPEEX_INT, eSrcSubType ); break; case KV3_TYPE_UINT: - SetValue( pSrc->m_UInt, KV3_TYPEEX_UINT, eSrcSubType ); + SetValue( pSrc->m_Data.m_UInt, KV3_TYPEEX_UINT, eSrcSubType ); break; case KV3_TYPE_DOUBLE: - SetValue( pSrc->m_Double, KV3_TYPEEX_DOUBLE, eSrcSubType ); + SetValue( pSrc->m_Data.m_Double, KV3_TYPEEX_DOUBLE, eSrcSubType ); break; case KV3_TYPE_STRING: SetString( pSrc->GetString(), eSrcSubType ); @@ -1111,26 +1219,26 @@ void KeyValues3::CopyFrom( const KeyValues3* pSrc ) case KV3_TYPEEX_ARRAY: { PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY ); - m_pArray->CopyFrom( pSrc->m_pArray ); + m_Data.m_pArray->CopyFrom( this, pSrc->m_Data.m_pArray ); break; } case KV3_TYPEEX_ARRAY_FLOAT32: - AllocArray( pSrc->m_nNumArrayElements, pSrc->m_f32Array, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_INVALID, KV3_TYPEEX_ARRAY_FLOAT32, eSrcSubType, KV3_TYPEEX_DOUBLE, KV3_SUBTYPE_FLOAT32 ); + AllocArray( pSrc->m_nNumArrayElements, pSrc->m_Data.m_Array.m_f32, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_INVALID, KV3_TYPEEX_ARRAY_FLOAT32, eSrcSubType, KV3_TYPEEX_DOUBLE, KV3_SUBTYPE_FLOAT32 ); break; case KV3_TYPEEX_ARRAY_FLOAT64: - AllocArray( pSrc->m_nNumArrayElements, pSrc->m_f64Array, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_INVALID, KV3_TYPEEX_ARRAY_FLOAT64, eSrcSubType, KV3_TYPEEX_DOUBLE, KV3_SUBTYPE_FLOAT64 ); + AllocArray( pSrc->m_nNumArrayElements, pSrc->m_Data.m_Array.m_f64, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_INVALID, KV3_TYPEEX_ARRAY_FLOAT64, eSrcSubType, KV3_TYPEEX_DOUBLE, KV3_SUBTYPE_FLOAT64 ); break; case KV3_TYPEEX_ARRAY_INT16: - AllocArray( pSrc->m_nNumArrayElements, pSrc->m_i16Array, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_ARRAY_INT16_SHORT, KV3_TYPEEX_ARRAY_INT16, eSrcSubType, KV3_TYPEEX_INT, KV3_SUBTYPE_INT16 ); + AllocArray( pSrc->m_nNumArrayElements, pSrc->m_Data.m_Array.m_i16, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_ARRAY_INT16_SHORT, KV3_TYPEEX_ARRAY_INT16, eSrcSubType, KV3_TYPEEX_INT, KV3_SUBTYPE_INT16 ); break; case KV3_TYPEEX_ARRAY_INT32: - AllocArray( pSrc->m_nNumArrayElements, pSrc->m_i32Array, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_INVALID, KV3_TYPEEX_ARRAY_INT32, eSrcSubType, KV3_TYPEEX_INT, KV3_SUBTYPE_INT32 ); + AllocArray( pSrc->m_nNumArrayElements, pSrc->m_Data.m_Array.m_i32, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_INVALID, KV3_TYPEEX_ARRAY_INT32, eSrcSubType, KV3_TYPEEX_INT, KV3_SUBTYPE_INT32 ); break; case KV3_TYPEEX_ARRAY_UINT8_SHORT: - AllocArray( pSrc->m_nNumArrayElements, pSrc->m_u8ArrayShort, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_ARRAY_UINT8_SHORT, KV3_TYPEEX_INVALID, eSrcSubType, KV3_TYPEEX_UINT, KV3_SUBTYPE_UINT8 ); + AllocArray( pSrc->m_nNumArrayElements, pSrc->m_Data.m_Array.m_u8Short, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_ARRAY_UINT8_SHORT, KV3_TYPEEX_INVALID, eSrcSubType, KV3_TYPEEX_UINT, KV3_SUBTYPE_UINT8 ); break; case KV3_TYPEEX_ARRAY_INT16_SHORT: - AllocArray( pSrc->m_nNumArrayElements, pSrc->m_i16ArrayShort, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_ARRAY_INT16_SHORT, KV3_TYPEEX_ARRAY_INT16, eSrcSubType, KV3_TYPEEX_INT, KV3_SUBTYPE_INT16 ); + AllocArray( pSrc->m_nNumArrayElements, pSrc->m_Data.m_Array.m_i16Short, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_ARRAY_INT16_SHORT, KV3_TYPEEX_ARRAY_INT16, eSrcSubType, KV3_TYPEEX_INT, KV3_SUBTYPE_INT16 ); break; default: break; @@ -1139,8 +1247,8 @@ void KeyValues3::CopyFrom( const KeyValues3* pSrc ) } case KV3_TYPE_TABLE: { - PrepareForType( KV3_TYPEEX_TABLE, KV3_SUBTYPE_TABLE ); - m_pTable->CopyFrom( pSrc->m_pTable ); + SetToEmptyTable(); + m_Data.m_pTable->CopyFrom( this, pSrc->m_Data.m_pTable ); break; } default: @@ -1161,8 +1269,15 @@ KeyValues3& KeyValues3::operator=( const KeyValues3& src ) return *this; } -CKeyValues3Array::CKeyValues3Array( int cluster_elem ) : - m_nClusterElement( cluster_elem ) +CKeyValues3Array::CKeyValues3Array( int cluster_elem, int alloc_size ) : + m_nClusterElement( cluster_elem ), + m_nAllocatedChunks( alloc_size ), + m_nCount( 0 ), + m_nInitialSize( MIN( alloc_size, 255 ) ), + m_bIsDynamicallySized( false ), + m_unk001( false ), + m_unk002( false ), + m_pDynamicElements( nullptr ) { } @@ -1171,7 +1286,7 @@ CKeyValues3ArrayCluster* CKeyValues3Array::GetCluster() const if ( m_nClusterElement == -1 ) return NULL; - return GET_OUTER( CKeyValues3ArrayCluster, m_Elements[ m_nClusterElement ] ); + return GET_OUTER( CKeyValues3ArrayCluster, m_Values[ m_nClusterElement ] ); } CKeyValues3Context* CKeyValues3Array::GetContext() const @@ -1184,97 +1299,160 @@ CKeyValues3Context* CKeyValues3Array::GetContext() const return NULL; } -void CKeyValues3Array::SetCount( int count, KV3TypeEx_t type, KV3SubType_t subtype ) +KeyValues3* CKeyValues3Array::Element( int i ) { - int nOldSize = m_Elements.Count(); + Assert( 0 <= i && i < m_nCount ); - CKeyValues3Context* context = GetContext(); - - for ( int i = count; i < nOldSize; ++i ) - { - if ( context ) - context->FreeKV( m_Elements[ i ] ); - else - delete m_Elements[ i ]; - } - - m_Elements.SetCount( count ); - - for ( int i = nOldSize; i < count; ++i ) - { - if ( context ) - m_Elements[ i ] = context->AllocKV( type, subtype ); - else - m_Elements[ i ] = new KeyValues3( type, subtype ); - } + return Base()[i]; } -KeyValues3** CKeyValues3Array::InsertBeforeGetPtr( int elem, int num ) +void CKeyValues3Array::EnsureElementCapacity( int count, bool force, bool dont_move ) { - KeyValues3** kv = m_Elements.InsertBeforeGetPtr( elem, num ); + if(count <= m_nAllocatedChunks) + return; - CKeyValues3Context* context = GetContext(); + if(count > ALLOC_KV3ARRAY_MAX) + { + Plat_FatalErrorFunc( "%s: element count overflow (%u)\n", __FUNCTION__, count ); + DebuggerBreak(); + } + + const int new_count = force ? count : KV3Helpers::CalcNewBufferSize( m_nAllocatedChunks, count, ALLOC_KV3ARRAY_MIN, ALLOC_KV3ARRAY_MAX ); + const int new_byte_size = TotalSizeOfData( new_count ); + + Element_t *new_base = nullptr; + + if(m_bIsDynamicallySized) + { + new_base = (Element_t *)realloc( m_pDynamicElements, new_byte_size ); + } + else + { + new_base = (Element_t *)malloc( new_byte_size ); + + if(m_nCount > 0 && !dont_move) + { + memmove( new_base, Base(), sizeof( Element_t ) * m_nCount ); + } + } + + m_pDynamicElements = new_base; + m_nAllocatedChunks = new_count; + m_bIsDynamicallySized = true; +} + +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++) + { + parent->FreeMember( elements_base[i] ); + } + + EnsureElementCapacity( count ); + + elements_base = Base(); + for(int i = m_nCount; i < count; i++) + { + elements_base[i] = parent->AllocMember( type, subtype ); + } + + m_nCount = count; +} + +CKeyValues3Array::Element_t* CKeyValues3Array::InsertMultipleBefore( KeyValues3 *parent, int from, int num ) +{ + 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) + { + 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) + { + memmove( (void *)base[from + num], (void *)base[from], sizeof(Element_t) * (m_nCount - from) ); + } for ( int i = 0; i < num; ++i ) { - if ( context ) - m_Elements[ elem + i ] = context->AllocKV(); - else - m_Elements[ elem + i ] = new KeyValues3; + base[from + i] = parent->AllocMember(); } - return kv; + m_nCount = new_size; + + return base; } -void CKeyValues3Array::CopyFrom( const CKeyValues3Array* pSrc ) +void CKeyValues3Array::CopyFrom( KeyValues3 *parent, const CKeyValues3Array* pSrc ) { - int nNewSize = pSrc->m_Elements.Count(); + int nNewSize = pSrc->Count(); - SetCount( nNewSize ); + SetCount( parent, nNewSize ); + + Element_t *base = Base(); + Element_t const *pSrcKV = pSrc->Base(); for ( int i = 0; i < nNewSize; ++i ) - *m_Elements[i] = *pSrc->m_Elements[i]; + *base[i] = *pSrcKV[i]; } -void CKeyValues3Array::RemoveMultiple( int elem, int num ) +void CKeyValues3Array::RemoveMultiple( KeyValues3 *parent, int from, int num ) { - CKeyValues3Context* context = GetContext(); + Element_t *base = Base(); - for ( int i = 0; i < num; ++i ) + for ( int i = 0; i <= num; ++i ) { - if ( context ) - context->FreeKV( m_Elements[ elem + i ] ); - else - delete m_Elements[ elem + i ]; + parent->FreeMember( base[from + i] ); } - m_Elements.RemoveMultiple( elem, num ); + m_nCount -= num; } -void CKeyValues3Array::Purge( bool bClearingContext ) -{ - CKeyValues3Context* context = GetContext(); - - FOR_EACH_LEANVEC( m_Elements, iter ) +void CKeyValues3Array::PurgeBuffers() +{ + if(m_bIsDynamicallySized) { - if ( context ) - { - if ( !bClearingContext ) - context->FreeKV( m_Elements[ iter ] ); - } - else - { - delete m_Elements[ iter ]; - } + free( m_pDynamicElements ); + m_nAllocatedChunks = m_nInitialSize; + m_bIsDynamicallySized = false; } - m_Elements.Purge(); + m_nCount = 0; } -CKeyValues3Table::CKeyValues3Table( int cluster_elem ) : +void CKeyValues3Array::PurgeContent( KeyValues3 *parent, bool clearing_context ) +{ + if(!clearing_context && parent) + { + auto elements_base = Base(); + + for(int i = 0; i < m_nCount; i++) + { + parent->FreeMember( elements_base[i] ); + } + } +} + +CKeyValues3Table::CKeyValues3Table( int cluster_elem, int alloc_size ) : m_nClusterElement( cluster_elem ), - m_pFastSearch( NULL ), - m_bHasBadNames( false ) + m_nAllocatedChunks( alloc_size ), + m_pFastSearch( nullptr ), + m_nCount( 0 ), + m_nInitialSize( MIN( alloc_size, 255 ) ), + m_bIsDynamicallySized( false ), + m_unk001( false ), + m_unk002( false ), + m_pDynamicBuffer( nullptr ) { } @@ -1283,7 +1461,7 @@ CKeyValues3TableCluster* CKeyValues3Table::GetCluster() const if ( m_nClusterElement == -1 ) return NULL; - return GET_OUTER( CKeyValues3TableCluster, m_Elements[ m_nClusterElement ] ); + return GET_OUTER( CKeyValues3TableCluster, m_Values[ m_nClusterElement ] ); } CKeyValues3Context* CKeyValues3Table::GetContext() const @@ -1296,6 +1474,27 @@ CKeyValues3Context* CKeyValues3Table::GetContext() const return NULL; } +KeyValues3* CKeyValues3Table::GetMember( KV3MemberId_t id ) +{ + Assert( 0 <= id && id < m_nCount ); + + return MembersBase()[id]; +} + +const CKeyValues3Table::Name_t CKeyValues3Table::GetMemberName( KV3MemberId_t id ) const +{ + Assert( 0 <= id && id < m_nCount ); + + return NamesBase()[id]; +} + +const CKeyValues3Table::Hash_t CKeyValues3Table::GetMemberHash( KV3MemberId_t id ) const +{ + Assert( 0 <= id && id < m_nCount ); + + return HashesBase()[id]; +} + void CKeyValues3Table::EnableFastSearch() { if ( m_pFastSearch ) @@ -1303,18 +1502,66 @@ void CKeyValues3Table::EnableFastSearch() else m_pFastSearch = new kv3tablefastsearch_t; - for ( int i = 0; i < m_Hashes.Count(); ++i ) - m_pFastSearch->m_member_ids.Insert( m_Hashes[i], i ); + const Hash_t* pHashes = HashesBase(); + + for ( int i = 0; i < m_nCount; ++i ) + { + m_pFastSearch->m_member_ids.Insert( pHashes[i], i ); + } m_pFastSearch->m_ignore = false; m_pFastSearch->m_ignores_counter = 0; } +void CKeyValues3Table::EnsureMemberCapacity( int count, bool force, bool dont_move ) +{ + if(count <= m_nAllocatedChunks) + return; + + if(count > ALLOC_KV3TABLE_MAX) + { + Plat_FatalErrorFunc( "%s member count overflow (%u)\n", __FUNCTION__, count ); + DebuggerBreak(); + } + + const int new_count = force ? count : KV3Helpers::CalcNewBufferSize( m_nAllocatedChunks, count, ALLOC_KV3TABLE_MIN, ALLOC_KV3TABLE_MAX ); + const int new_byte_size = TotalSizeOfData( new_count ); + + void *new_base = nullptr; + + if(m_bIsDynamicallySized) + { + new_base = realloc( m_pDynamicBuffer, new_byte_size ); + + memmove( (uint8 *)new_base + OffsetToFlagsBase( new_count ), FlagsBase(), m_nCount * sizeof( Flags_t ) ); + memmove( (uint8 *)new_base + OffsetToNamesBase( new_count ), NamesBase(), m_nCount * sizeof( Name_t ) ); + memmove( (uint8 *)new_base + OffsetToMembersBase( new_count ), MembersBase(), m_nCount * sizeof( Member_t ) ); + } + else + { + new_base = malloc( new_byte_size ); + + 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 ) ); + memmove( (uint8 *)new_base + OffsetToNamesBase( new_count ), NamesBase(), m_nCount * sizeof( Name_t ) ); + memmove( (uint8 *)new_base + OffsetToFlagsBase( new_count ), FlagsBase(), m_nCount * sizeof( Flags_t ) ); + } + } + + m_pDynamicBuffer = new_base; + m_nAllocatedChunks = new_count; + m_bIsDynamicallySized = true; +} + KV3MemberId_t CKeyValues3Table::FindMember( const KeyValues3* kv ) const { - for ( int i = 0; i < m_Hashes.Count(); ++i ) + const Member_t* pMembers = MembersBase(); + + for ( int i = 0; i < m_nCount; ++i ) { - if ( m_Members[i] == kv ) + if ( pMembers[i] == kv ) return i; } @@ -1350,9 +1597,11 @@ KV3MemberId_t CKeyValues3Table::FindMember( const CKV3MemberName &name ) } else { - for ( int i = 0; i < m_Hashes.Count(); ++i ) + const Hash_t* pHashes = HashesBase(); + + for ( int i = 0; i < m_nCount; ++i ) { - if ( m_Hashes[i] == name.GetHashCode() ) + if ( pHashes[i] == name.GetHashCode() ) return i; } } @@ -1360,91 +1609,114 @@ KV3MemberId_t CKeyValues3Table::FindMember( const CKV3MemberName &name ) return KV3_INVALID_MEMBER; } -KV3MemberId_t CKeyValues3Table::CreateMember( const CKV3MemberName &name ) +KV3MemberId_t CKeyValues3Table::CreateMember( KeyValues3 *parent, const CKV3MemberName &name, bool name_external ) { - if ( m_Hashes.Count() >= 128 && !m_pFastSearch ) + if ( GetMemberCount() >= 128 && !m_pFastSearch ) EnableFastSearch(); - *m_Hashes.AddToTailGetPtr() = name.GetHashCode(); + KV3MemberId_t curr = m_nCount; - KV3MemberId_t memberId = m_Hashes.Count() - 1; + int new_size = m_nCount + 1; + EnsureMemberCapacity( new_size ); - CKeyValues3Context* context = GetContext(); + Hash_t *hashes_base = HashesBase(); + Member_t *members_base = MembersBase(); + Name_t *names_base = NamesBase(); + Flags_t *flags_base = FlagsBase(); - if ( context ) + members_base[curr] = parent->AllocMember(); + hashes_base[curr] = name.GetHashCode(); + Flags_t flags = TABLEFL_NONE; + + if(name_external) { - *m_Members.AddToTailGetPtr() = context->AllocKV(); - *m_Names.AddToTailGetPtr() = context->AllocString( name.GetString() ); + names_base[curr] = name.GetString(); + flags |= TABLEFL_NAME_EXTERNAL; } else { - *m_Members.AddToTailGetPtr() = new KeyValues3; - *m_Names.AddToTailGetPtr() = strdup( name.GetString() ); + auto context = parent->GetContext(); + + if(context) + names_base[curr] = context->AllocString( name.GetString() ); + else + names_base[curr] = strdup( name.GetString() ); } - m_IsExternalName.AddToTail( false ); + flags_base[curr] = flags; if ( m_pFastSearch && !m_pFastSearch->m_ignore ) - m_pFastSearch->m_member_ids.Insert( name.GetHashCode(), memberId ); + m_pFastSearch->m_member_ids.Insert( name.GetHashCode(), curr ); - return memberId; + m_nCount = new_size; + + return curr; } -void CKeyValues3Table::CopyFrom( const CKeyValues3Table* pSrc ) +void CKeyValues3Table::CopyFrom( KeyValues3 *parent, const CKeyValues3Table* src ) { - int nNewSize = pSrc->m_Hashes.Count(); + int new_size = src->GetMemberCount(); - RemoveAll( nNewSize ); + RemoveAll( parent, new_size ); + EnsureMemberCapacity( new_size, true, true ); - m_Hashes.SetCount( nNewSize ); - m_Members.SetCount( nNewSize ); - m_Names.SetCount( nNewSize ); - m_IsExternalName.SetCount( nNewSize ); + auto context = parent->GetContext(); - CKeyValues3Context* context = GetContext(); + Hash_t *hashes_base = HashesBase(); + Member_t *members_base = MembersBase(); + Name_t *names_base = NamesBase(); + Flags_t *flags_base = FlagsBase(); - for ( int i = 0; i < nNewSize; ++i ) + const Hash_t *src_hashes_base = src->HashesBase(); + const Member_t *src_members_base = src->MembersBase(); + const Name_t *src_names_base = src->NamesBase(); + const Flags_t *src_flags_base = src->FlagsBase(); + + memmove( hashes_base, src_hashes_base, sizeof(Hash_t) * new_size ); + + for(int i = 0; i < new_size; i++) { - m_Hashes[i] = pSrc->m_Hashes[i]; + flags_base[i] = src_flags_base[i] & ~TABLEFL_NAME_EXTERNAL; - if ( context ) - { - m_Members[i] = context->AllocKV(); - m_Names[i] = context->AllocString( pSrc->m_Names[i] ); - } + if(context) + names_base[i] = context->AllocString( src_names_base[i] ); else - { - m_Members[i] = new KeyValues3; - m_Names[i] = strdup( pSrc->m_Names[i] ); - } + names_base[i] = strdup( src_names_base[i] ); - m_IsExternalName[i] = false; - - *m_Members[i] = *pSrc->m_Members[i]; + members_base[i] = parent->AllocMember(); + members_base[i]->CopyFrom( src_members_base[i] ); } - if ( nNewSize >= 128 ) + if ( new_size >= 128 ) EnableFastSearch(); } -void CKeyValues3Table::RemoveMember( KV3MemberId_t id ) +void CKeyValues3Table::RemoveMember( KeyValues3 *parent, KV3MemberId_t id ) { - CKeyValues3Context* context = GetContext(); + m_nCount--; - if ( context ) + Hash_t* hashes_base = HashesBase(); + Member_t* members_base = MembersBase(); + Name_t* names_base = NamesBase(); + Flags_t* flags_base = FlagsBase(); + + parent->FreeMember( members_base[id] ); + + if((flags_base[id] & TABLEFL_NAME_EXTERNAL) == 0 && !parent->GetContext() && names_base[id]) { - context->FreeKV( m_Members[ id ] ); - } - else - { - delete m_Members[ id ]; - free( (void*)m_Names[ id ] ); + free( (void *)names_base[id] ); } - m_Hashes.Remove( id ); - m_Members.Remove( id ); - m_Names.Remove( id ); - m_IsExternalName.Remove( id ); + if ( id < m_nCount ) + { + int shift_size = m_nCount - id; + int shift_from = id + 1; + + memmove( &hashes_base[id], &hashes_base[shift_from], shift_size * sizeof(Hash_t) ); + memmove( &members_base[id], &members_base[shift_from], shift_size * sizeof(Member_t) ); + memmove( &names_base[id], &names_base[shift_from], shift_size * sizeof(Name_t) ); + memmove( &flags_base[id], &flags_base[shift_from], shift_size * sizeof(Flags_t) ); + } if ( m_pFastSearch ) { @@ -1453,273 +1725,113 @@ void CKeyValues3Table::RemoveMember( KV3MemberId_t id ) } } -void CKeyValues3Table::RemoveAll( int nAllocSize ) +void CKeyValues3Table::RemoveAll( KeyValues3 *parent, int new_size ) { - CKeyValues3Context* context = GetContext(); + Member_t *members_base = MembersBase(); + Name_t *names_base = NamesBase(); + Flags_t *flags_base = FlagsBase(); - for ( int i = 0; i < m_Hashes.Count(); ++i ) + for(int i = 0; i < m_nCount; i++) { - if ( context ) + parent->FreeMember( members_base[i] ); + + if((flags_base[i] & TABLEFL_NAME_EXTERNAL) == 0 && !parent->GetContext() && names_base[i]) { - context->FreeKV( m_Members[i] ); - } - else - { - delete m_Members[i]; - free( (void*)m_Names[i] ); + free( (void *)names_base[i] ); } } - m_Hashes.RemoveAll(); - m_Members.RemoveAll(); - m_Names.RemoveAll(); - m_IsExternalName.RemoveAll(); - - if ( nAllocSize > 0 ) + m_nCount = 0; + if(new_size > 0) { - m_Hashes.EnsureCapacity( nAllocSize ); - m_Members.EnsureCapacity( nAllocSize ); - m_Names.EnsureCapacity( nAllocSize ); - m_IsExternalName.EnsureCapacity( nAllocSize ); + EnsureMemberCapacity( new_size, true, true ); } - if ( m_pFastSearch ) + if(new_size < 128) { - if ( nAllocSize >= 128 ) - { - m_pFastSearch->Clear(); - } - else - { - delete m_pFastSearch; - m_pFastSearch = NULL; - } - } -} - -void CKeyValues3Table::Purge( bool bClearingContext ) -{ - CKeyValues3Context* context = GetContext(); - - for ( int i = 0; i < m_Hashes.Count(); ++i ) - { - if ( context ) - { - if ( !bClearingContext ) - context->FreeKV( m_Members[i] ); - } - else - { - delete m_Members[i]; - free( (void*)m_Names[i] ); - } - } - - if ( m_pFastSearch ) - delete m_pFastSearch; - m_pFastSearch = NULL; - - m_Hashes.Purge(); - m_Members.Purge(); - m_Names.Purge(); - m_IsExternalName.Purge(); -} - -CKeyValues3Cluster::CKeyValues3Cluster( CKeyValues3Context* context ) : - m_pContext( context ), - m_nAllocatedElements( 0 ), - m_pMetaData( NULL ), - m_pNextFree( NULL ) -{ - memset( &m_KeyValues, 0, sizeof( m_KeyValues ) ); -} - -CKeyValues3Cluster::~CKeyValues3Cluster() -{ - FreeMetaData(); -} - -#include "tier0/memdbgoff.h" - -KeyValues3* CKeyValues3Cluster::Alloc( KV3TypeEx_t type, KV3SubType_t subtype ) -{ - Assert( IsFree() ); - int element = KV3Helpers::BitScanFwd( ~m_nAllocatedElements ); - m_nAllocatedElements |= ( 1ull << element ); - KeyValues3* kv = &m_KeyValues[ element ]; - new( kv ) KeyValues3( element, type, subtype ); - return kv; -} - -#include "tier0/memdbgon.h" - -void CKeyValues3Cluster::Free( int element ) -{ - Assert( element >= 0 && element < KV3_CLUSTER_MAX_ELEMENTS ); - KeyValues3* kv = &m_KeyValues[ element ]; - Destruct( kv ); - memset( (void *)kv, 0, sizeof( KeyValues3 ) ); - m_nAllocatedElements &= ~( 1ull << element ); -} - -void CKeyValues3Cluster::PurgeElements() -{ - uint64 mask = 1; - for ( int i = 0; i < KV3_CLUSTER_MAX_ELEMENTS; ++i ) - { - if ( ( m_nAllocatedElements & mask ) != 0 ) - m_KeyValues[ i ].OnClearContext(); - mask <<= 1; - } - - m_nAllocatedElements = 0; -} - -void CKeyValues3Cluster::Purge() -{ - PurgeElements(); - - if ( m_pMetaData ) - { - for ( int i = 0; i < KV3_CLUSTER_MAX_ELEMENTS; ++i ) - m_pMetaData->m_elements[ i ].Purge(); - } -} - -void CKeyValues3Cluster::Clear() -{ - PurgeElements(); - - if ( m_pMetaData ) - { - for ( int i = 0; i < KV3_CLUSTER_MAX_ELEMENTS; ++i ) - m_pMetaData->m_elements[ i ].Clear(); - } -} - -void CKeyValues3Cluster::EnableMetaData( bool bEnable ) -{ - if ( bEnable ) - { - if ( !m_pMetaData ) - m_pMetaData = new kv3metadata_t; + PurgeFastSearch(); } else { - FreeMetaData(); + EnableFastSearch(); + m_pFastSearch->m_member_ids.Reserve( new_size ); } } -void CKeyValues3Cluster::FreeMetaData() +void CKeyValues3Table::PurgeFastSearch() { - if ( m_pMetaData ) - delete m_pMetaData; - m_pMetaData = NULL; + if(m_pFastSearch) + delete m_pFastSearch; + + m_pFastSearch = nullptr; } -KV3MetaData_t* CKeyValues3Cluster::GetMetaData( int element ) const +void CKeyValues3Table::PurgeContent( KeyValues3 *parent, bool bClearingContext ) { - Assert( element >= 0 && element < KV3_CLUSTER_MAX_ELEMENTS ); + Member_t *members_base = MembersBase(); + Name_t *names_base = NamesBase(); + Flags_t *flags_base = FlagsBase(); - if ( !m_pMetaData ) - return NULL; + for ( int i = 0; i < m_nCount; ++i ) + { + if(!bClearingContext && parent) + { + parent->FreeMember( members_base[i] ); + } - return &m_pMetaData->m_elements[ element ]; + if((flags_base[i] & TABLEFL_NAME_EXTERNAL) == 0 && parent && !parent->GetContext() && names_base[i]) + { + free( (void *)names_base[i] ); + } + } + + m_nCount = 0; + + PurgeFastSearch(); +} + +void CKeyValues3Table::PurgeBuffers() +{ + if(m_bIsDynamicallySized) + { + free( m_pDynamicBuffer ); + m_nAllocatedChunks = m_nInitialSize; + m_bIsDynamicallySized = false; + } + + m_nCount = 0; } CKeyValues3ContextBase::CKeyValues3ContextBase( CKeyValues3Context* context ) : m_pContext( context ), m_KV3BaseCluster( context ), - m_pKV3FreeCluster( &m_KV3BaseCluster ), - m_pArrayFreeCluster( NULL ), - m_pTableFreeCluster( NULL ), - m_pParsingErrorListener( NULL ) + m_bMetaDataEnabled( false ), + m_bFormatConverted( false ), + m_bRootAvailabe( false ), + m_pParsingErrorListener( nullptr ) { -} - -CKeyValues3ContextBase::~CKeyValues3ContextBase() -{ - Purge(); + m_KV3PartialClusters.AddToChain( &m_KV3BaseCluster ); } void CKeyValues3ContextBase::Clear() { m_BinaryData.Clear(); - m_KV3BaseCluster.Clear(); - m_KV3BaseCluster.SetNextFree( NULL ); - m_pKV3FreeCluster = &m_KV3BaseCluster; - - FOR_EACH_LEANVEC( m_KV3Clusters, iter ) - { - m_KV3Clusters[ iter ]->Clear(); - m_KV3Clusters[ iter ]->SetNextFree( m_pKV3FreeCluster ); - m_pKV3FreeCluster = m_KV3Clusters[ iter ]; - } - - m_pArrayFreeCluster = NULL; - - FOR_EACH_LEANVEC( m_ArrayClusters, iter ) - { - m_ArrayClusters[ iter ]->Clear(); - m_ArrayClusters[ iter ]->SetNextFree( m_pArrayFreeCluster ); - m_pArrayFreeCluster = m_ArrayClusters[ iter ]; - } - - m_pTableFreeCluster = NULL; - - FOR_EACH_LEANVEC( m_TableClusters, iter ) - { - m_TableClusters[ iter ]->Clear(); - m_TableClusters[ iter ]->SetNextFree( m_pTableFreeCluster ); - m_pTableFreeCluster = m_TableClusters[ iter ]; - } - m_Symbols.RemoveAll(); - + m_bFormatConverted = false; } void CKeyValues3ContextBase::Purge() { m_BinaryData.Purge(); - m_KV3BaseCluster.Purge(); - m_KV3BaseCluster.SetNextFree( NULL ); - m_pKV3FreeCluster = &m_KV3BaseCluster; - - FOR_EACH_LEANVEC( m_KV3Clusters, iter ) - { - m_KV3Clusters[ iter ]->Purge(); - delete m_KV3Clusters[ iter ]; - } - - m_KV3Clusters.Purge(); - - FOR_EACH_LEANVEC( m_ArrayClusters, iter ) - { - m_ArrayClusters[ iter ]->Purge(); - delete m_ArrayClusters[ iter ]; - } - - m_pArrayFreeCluster = NULL; - m_ArrayClusters.Purge(); - - FOR_EACH_LEANVEC( m_TableClusters, iter ) - { - m_TableClusters[ iter ]->Purge(); - delete m_TableClusters[ iter ]; - } - - m_pTableFreeCluster = NULL; - m_TableClusters.Purge(); - m_Symbols.Purge(); m_bFormatConverted = false; } -CKeyValues3Context::CKeyValues3Context( bool bNoRoot ) : BaseClass( this ) +CKeyValues3Context::CKeyValues3Context( bool bNoRoot ) : BaseClass( this ), pad{} { if ( bNoRoot ) { @@ -1735,14 +1847,24 @@ CKeyValues3Context::CKeyValues3Context( bool bNoRoot ) : BaseClass( this ) m_bFormatConverted = false; } -CKeyValues3Context::~CKeyValues3Context() -{ -} - void CKeyValues3Context::Clear() { BaseClass::Clear(); + ClearClusterNodeChain( m_KV3PartialClusters ); + ClearClusterNodeChain( m_KV3FullClusters ); + MoveToPartial( m_KV3FullClusters, m_KV3PartialClusters ); + + ClearClusterNodeChain( m_PartialArrayClusters ); + ClearClusterNodeChain( m_FullArrayClusters ); + MoveToPartial( m_FullArrayClusters, m_PartialArrayClusters ); + m_RawArrayEntries.Clear(); + + ClearClusterNodeChain( m_PartialTableClusters ); + ClearClusterNodeChain( m_FullTableClusters ); + MoveToPartial( m_FullTableClusters, m_PartialTableClusters ); + m_RawTableEntries.Clear(); + if ( m_bRootAvailabe ) m_KV3BaseCluster.Alloc(); } @@ -1751,6 +1873,18 @@ void CKeyValues3Context::Purge() { BaseClass::Purge(); + PurgeClusterNodeChain( m_KV3PartialClusters ); + PurgeClusterNodeChain( m_KV3FullClusters ); + m_KV3PartialClusters.AddToChain( &m_KV3BaseCluster ); + + PurgeClusterNodeChain( m_PartialArrayClusters ); + PurgeClusterNodeChain( m_FullArrayClusters ); + m_RawArrayEntries.Purge(); + + PurgeClusterNodeChain( m_PartialTableClusters ); + PurgeClusterNodeChain( m_FullTableClusters ); + m_RawTableEntries.Purge(); + if ( m_bRootAvailabe ) m_KV3BaseCluster.Alloc(); } @@ -1763,7 +1897,7 @@ KeyValues3* CKeyValues3Context::Root() DebuggerBreak(); } - return m_KV3BaseCluster.Head(); + return &m_KV3BaseCluster.Head()->m_Value; } const char* CKeyValues3Context::AllocString( const char* pString ) @@ -1777,9 +1911,6 @@ void CKeyValues3Context::EnableMetaData( bool bEnable ) { m_KV3BaseCluster.EnableMetaData( bEnable ); - for ( int i = 0; i < m_KV3Clusters.Count(); ++i ) - m_KV3Clusters[ i ]->EnableMetaData( bEnable ); - m_bMetaDataEnabled = bEnable; } } @@ -1802,29 +1933,7 @@ void CKeyValues3Context::CopyMetaData( KV3MetaData_t* pDest, const KV3MetaData_t KeyValues3* CKeyValues3Context::AllocKV( KV3TypeEx_t type, KV3SubType_t subtype ) { - KeyValues3* kv; - - if ( m_pKV3FreeCluster ) - { - kv = m_pKV3FreeCluster->Alloc( type, subtype ); - - if ( !m_pKV3FreeCluster->IsFree() ) - { - CKeyValues3Cluster* cluster = m_pKV3FreeCluster->GetNextFree(); - m_pKV3FreeCluster->SetNextFree( NULL ); - m_pKV3FreeCluster = cluster; - } - } - else - { - CKeyValues3Cluster* cluster = new CKeyValues3Cluster( m_pContext ); - cluster->EnableMetaData( m_bMetaDataEnabled ); - *m_KV3Clusters.AddToTailGetPtr() = cluster; - m_pKV3FreeCluster = cluster; - kv = cluster->Alloc( type, subtype ); - } - - return kv; + return Alloc( m_KV3PartialClusters, m_KV3FullClusters, CKeyValues3Cluster::CLUSTER_SIZE, type, subtype ); } void CKeyValues3Context::FreeKV( KeyValues3* kv ) @@ -1832,10 +1941,10 @@ void CKeyValues3Context::FreeKV( KeyValues3* kv ) CKeyValues3Context* context; KV3MetaData_t* metadata = kv->GetMetaData( &context ); - Assert( context == m_pContext ); - if ( metadata ) metadata->Clear(); - Free( kv, &m_KV3BaseCluster, m_pKV3FreeCluster, m_KV3Clusters ); + // Free( kv, &m_KV3BaseCluster, m_pKV3FreeCluster ); } + +#include "tier0/memdbgoff.h" \ No newline at end of file