From eea1f4b4ec2b68a3d4e37e5c3427661af29d3f5f Mon Sep 17 00:00:00 2001 From: disinvite Date: Tue, 11 Jul 2023 11:23:36 -0400 Subject: [PATCH] meh --- LEGO1/mxvariabletable.cpp | 19 +++++- LEGO1/mxvariabletable.h | 129 +++++++++++++++++++++++++++++++------- 2 files changed, 124 insertions(+), 24 deletions(-) diff --git a/LEGO1/mxvariabletable.cpp b/LEGO1/mxvariabletable.cpp index fe11b538..33805e8c 100644 --- a/LEGO1/mxvariabletable.cpp +++ b/LEGO1/mxvariabletable.cpp @@ -1,5 +1,6 @@ #include "mxvariabletable.h" +// OFFSET: LEGO1 0x100b7330 MxS8 MxVariableTable::Compare(MxVariable *p_var0, MxVariable *p_var1) { return strcmp(p_var0->GetKey()->GetData(), @@ -27,6 +28,13 @@ void MxVariableTable::SetVariable(const char *p_key, const char *p_value) if (cursor.Find(var)) { delete var; + cursor.GetMatch(&var); + var->SetValue(p_value); + } else { + if (m_option && m_numKeys / m_numSlots > m_autoResizeRatio) + Resize(); + + Add(var); } // TODO } @@ -34,7 +42,16 @@ void MxVariableTable::SetVariable(const char *p_key, const char *p_value) // OFFSET: LEGO1 0x100b7740 void MxVariableTable::SetVariable(MxVariable *var) { - // TODO + MxHashTableCursor cursor(this); + MxBool found = cursor.Find(var); + + if (found) + cursor.DeleteMatch(); + + if (m_option && m_numKeys / m_numSlots > m_autoResizeRatio) + Resize(); + + Add(var); } // OFFSET: LEGO1 0x100b78f0 diff --git a/LEGO1/mxvariabletable.h b/LEGO1/mxvariabletable.h index c635099b..d0b717cb 100644 --- a/LEGO1/mxvariabletable.h +++ b/LEGO1/mxvariabletable.h @@ -31,27 +31,96 @@ class MxHashTable : public MxCore public: MxHashTable() { - m_size = 128; - m_table = new MxHashTableNode*[128]; + m_numSlots = 128; + m_slots = new MxHashTableNode*[128]; } ~MxHashTable() { - delete[] m_table; + // TODO: Walk table to delete nodes? + delete[] m_slots; + } + + // OFFSET: LEGO1 0x100b7ab0 + void Resize() + { + // Save a reference to the current table + // so we can walk nodes and re-insert + MxHashTableNode **old_table = m_slots; + MxU32 old_size = m_numSlots; + + switch (m_option) { + case 1: // flat increase by x + m_numSlots = old_size + (int)m_increaseAmount; + break; + case 2: // increase by a factor of x + m_numSlots = (int)(old_size * m_increaseFactor); + break; + } + + MxHashTableNode **new_table = new MxHashTableNode*[m_numSlots]; + // FIXME: order? m_numKeys set after `rep stosd` + m_slots = new_table; + m_numKeys = 0; + memset(m_slots, 0, sizeof(MxHashTableNode *) * m_numSlots); + + + for (MxU32 i = 0; i < old_size; i++) { + MxHashTableNode *t = old_table[i]; + + while (t) { + MxHashTableNode *next = t->m_next; + int new_bucket = t->m_hash % m_numSlots; + + t->m_next = m_slots[new_bucket]; + + // If the new bucket is not empty, make the reshuffled node + // the new head of the bucket. + if (m_slots[new_bucket]) + m_slots[new_bucket]->m_prev = t; + + m_slots[new_bucket] = t; + t = next; + m_numKeys++; + } + } + + delete[] old_table; + } + + void Add(T* p_newobj) + { + MxU32 hash = Hash(p_newobj); + MxHashTableNode *node = new MxHashTableNode(p_newobj, hash); + + int bucket = node->m_hash % m_numSlots; + + node->m_next = m_slots[bucket]; + + if (m_slots[bucket]) + m_slots[bucket]->m_prev = node; + + m_slots[bucket] = node; + m_numKeys++; } virtual MxS8 Compare(T*, T*); virtual MxU32 Hash(T*); //private: - int m_used; // +0x8 - void (*m_unkc)(void *); // +0xc - MxHashTableNode **m_table; // +0x10 - int m_size; // +0x14 - int m_unk18; - int m_unk1c; - int m_unk20; - int m_unk24; + int m_numKeys; // +0x8 + void (*m_customDestructor)(T*); // +0xc + MxHashTableNode **m_slots; // +0x10 + MxU32 m_numSlots; // +0x14 + int m_autoResizeRatio; + int m_option; // +0x1c + // FIXME: or FIXME? This qword is used as an integer or double depending + // on the value of m_option. Hard to say whether this is how the devs + // did it, but a simple cast in either direction doesn't match. + union { + MxS64 m_increaseAmount; + double m_increaseFactor; + }; }; template @@ -60,19 +129,19 @@ class MxHashTableCursor : public MxCore public: MxHashTableCursor(MxHashTable *p_hashTable) { - m_hashTable = p_hashTable; + m_table = p_hashTable; m_match = NULL; } MxBool Find(T *p_obj) { - MxU32 hash = m_hashTable->Hash(p_obj); - int bucket = hash % m_hashTable->m_size; + MxU32 hash = m_table->Hash(p_obj); + int bucket = hash % m_table->m_numSlots; - MxHashTableNode *t = m_hashTable->m_table[bucket]; + MxHashTableNode *t = m_table->m_slots[bucket]; while (t) { - if (t->m_hash == hash && !m_hashTable->Compare(t->m_obj, p_obj)) + if (t->m_hash == hash && !m_table->Compare(t->m_obj, p_obj)) m_match = t; t = t->m_next; } @@ -82,20 +151,34 @@ class MxHashTableCursor : public MxCore void GetMatch(T **p_obj) { - if (m_match) + if (m_match) { *p_obj = m_match->m_obj; - //p_obj = m_match ? m_match->m_obj : NULL; // ? + } } - /* - T* GetMatch() + void DeleteMatch() { - return m_match ? m_match->m_obj : NULL; + // Cut the matching node out of the linked list + // by updating pointer references. + + if (m_match->m_prev) { + m_match->m_prev->m_next = m_match->m_next; + } else { + // No "prev" node, so move "next" to the head of the list. + int bucket = m_match->m_hash % m_table->m_numSlots; + m_table->m_slots[bucket] = m_match->m_next; + } + + if (m_match->m_next) + m_match->m_next->m_prev = m_match->m_prev; + + m_table->m_customDestructor(m_match->m_obj); + delete m_match; + m_table->m_numKeys--; } - */ private: - MxHashTable *m_hashTable; + MxHashTable *m_table; MxHashTableNode *m_match; // type ? };