diff --git a/public/tier1/keyvalues3.h b/public/tier1/keyvalues3.h index 999c624f..f0aae34a 100644 --- a/public/tier1/keyvalues3.h +++ b/public/tier1/keyvalues3.h @@ -46,6 +46,11 @@ struct KV3ToKV1Translation_t; 2. Directly through the constructor. */ +// Quick way to iterate across whole kv3, to access currently iterated kv3 use iter.Get() +// Mostly useful to iterate unnamed data, like arrays of primitives +#define FOR_EACH_KV3( kv, iter ) \ + for ( CKeyValues3Iterator iter( kv ); iter.IsValid(); iter.Advance() ) + struct KV3ID_t { const char* m_name; @@ -606,6 +611,29 @@ private: }; COMPILE_TIME_ASSERT(sizeof(KeyValues3) == 16); +class CKeyValues3Iterator +{ +public: + CKeyValues3Iterator() : m_Stack() {} + CKeyValues3Iterator( KeyValues3 *kv ) : CKeyValues3Iterator() { Init( kv ); } + + void Init( KeyValues3 *kv ); + + void Advance(); + + KeyValues3 *Get() const { return IsValid() ? m_Stack[m_Stack.Count() - 1].m_pKV : nullptr; } + bool IsValid() const { return m_Stack.Count() > 0; } + +private: + struct StackEntry_t + { + KeyValues3 *m_pKV; + int m_nIndex; + }; + + CUtlVectorFixedGrowable m_Stack; +}; + class CKeyValues3Array { public: diff --git a/tier1/keyvalues3.cpp b/tier1/keyvalues3.cpp index b9758638..98759b21 100644 --- a/tier1/keyvalues3.cpp +++ b/tier1/keyvalues3.cpp @@ -1269,6 +1269,54 @@ KeyValues3& KeyValues3::operator=( const KeyValues3& src ) return *this; } +void CKeyValues3Iterator::Init( KeyValues3 *kv ) +{ + m_Stack.Purge(); + + if(kv) + { + auto entry = m_Stack.AddToTailGetPtr(); + entry->m_nIndex = -1; + entry->m_pKV = kv; + } +} + +void CKeyValues3Iterator::Advance() +{ + while(m_Stack.Count() > 0) + { + auto &entry = m_Stack[m_Stack.Count() - 1]; + auto kv = entry.m_pKV; + + if(kv->GetType() == KV3_TYPE_ARRAY) + { + entry.m_nIndex++; + + if(entry.m_nIndex < kv->GetArrayElementCount()) + { + auto new_entry = m_Stack.AddToTailGetPtr(); + new_entry->m_nIndex = -1; + new_entry->m_pKV = kv->GetArrayElement( entry.m_nIndex ); + return; + } + } + else if(kv->GetType() == KV3_TYPE_TABLE) + { + entry.m_nIndex++; + + if(entry.m_nIndex < kv->GetMemberCount()) + { + auto new_entry = m_Stack.AddToTailGetPtr(); + new_entry->m_nIndex = -1; + new_entry->m_pKV = kv->GetMember( entry.m_nIndex ); + return; + } + } + + m_Stack.RemoveMultipleFromTail( 1 ); + } +} + CKeyValues3Array::CKeyValues3Array( int cluster_elem, int alloc_size ) : m_nClusterElement( cluster_elem ), m_nAllocatedChunks( alloc_size ),