From 957cb2016408e17296dd3c15ba09536b87fcedcb Mon Sep 17 00:00:00 2001 From: disinvite Date: Sat, 15 Jul 2023 13:50:30 -0400 Subject: [PATCH] variable table init in mxomni, some reshuffling --- LEGO1/mxhashtable.h | 199 ++++++++++++++++++++++++-------------- LEGO1/mxomni.cpp | 9 ++ LEGO1/mxvariabletable.cpp | 10 -- LEGO1/mxvariabletable.h | 8 +- 4 files changed, 140 insertions(+), 86 deletions(-) diff --git a/LEGO1/mxhashtable.h b/LEGO1/mxhashtable.h index 3f85fc52..f9505bb5 100644 --- a/LEGO1/mxhashtable.h +++ b/LEGO1/mxhashtable.h @@ -29,94 +29,57 @@ class MxHashTableNode MxHashTableNode *m_next; }; +// See MxOmni::Create +// VTABLE 0x100dc1b0 template -class MxHashTable : public MxCore +class HashTableParent : public MxCore +{ +public: + HashTableParent() { + m_numKeys = 0; + m_customDestructor = Destroy; + } + + // OFFSET: LEGO1 0x100afd30 + static void Destroy(T*) {}; + + // OFFSET: LEGO1 0x100afcd0 + virtual MxS8 Compare(T*, T*) = 0; + +protected: + MxU32 m_numKeys; // +0x8 + void (*m_customDestructor)(T*); // +0xc +}; + +// VTABLE 0x100dc1e8 +template +class MxHashTable : protected HashTableParent { public: MxHashTable() { m_numSlots = HASH_TABLE_INIT_SIZE; m_slots = new MxHashTableNode*[HASH_TABLE_INIT_SIZE]; + memset(m_slots, 0, sizeof(MxHashTableNode *) * m_numSlots); m_resizeOption = HASH_TABLE_OPT_NO_EXPAND; } - ~MxHashTable() - { - // TODO: Walk table to delete nodes? - delete[] m_slots; - } + virtual ~MxHashTable(); - // for convenience - inline int GetBucket(int hash) { - return hash % m_numSlots; - } + void Resize(); + void MxHashTable::Add(T* ); - // OFFSET: LEGO1 0x100b7ab0 - void MxHashTable::Resize() - { - // Save a reference to the current table - // so we can walk nodes and re-insert - MxU32 old_size = m_numSlots; - MxHashTableNode **old_table = m_slots; + virtual MxS8 Compare(T*, T*) = 0; - switch (m_resizeOption) { - case HASH_TABLE_OPT_EXPAND_ADD: - m_numSlots = old_size + m_increaseAmount; - break; - case HASH_TABLE_OPT_EXPAND_MULTIPLY: - m_numSlots = old_size * m_increaseFactor; - break; - } + // OFFSET: LEGO1 0x100afdc0 + virtual MxU32 Hash(T*) = 0; - MxHashTableNode **new_table = new MxHashTableNode*[m_numSlots]; - // FIXME: order? m_numKeys set after `rep stosd` - m_slots = new_table; - memset(m_slots, 0, sizeof(MxHashTableNode *) * m_numSlots); - m_numKeys = 0; + // FIXME: use of friend here? + friend class MxHashTableCursor; - for (int i = 0; i != old_size; i++) { - MxHashTableNode *t = old_table[i]; - - while (t) { - MxHashTableNode *next = t->m_next; - _NodeInsert(t); - t = next; - } - } +protected: + void _NodeInsert(MxHashTableNode *); - delete[] old_table; - } - - // OFFSET: LEGO1 0x100b7b80 - void MxHashTable::_NodeInsert(MxHashTableNode *p_node) { - int bucket = GetBucket(p_node->m_hash); - - p_node->m_next = m_slots[bucket]; - - if (m_slots[bucket]) - m_slots[bucket]->m_prev = p_node; - - m_slots[bucket] = p_node; - m_numKeys++; - } - - void MxHashTable::Add(T* p_newobj) - { - if (m_resizeOption && ((m_numKeys + 1) / m_numSlots) > m_autoResizeRatio) - MxHashTable::Resize(); - - MxU32 hash = Hash(p_newobj); - MxHashTableNode *node = new MxHashTableNode(p_newobj, hash); - - MxHashTable::_NodeInsert(node); - } - - virtual MxS8 Compare(T*, T*); - virtual MxU32 Hash(T*); - -//private: - MxU32 m_numKeys; // +0x8 - void (*m_customDestructor)(T*); // +0xc MxHashTableNode **m_slots; // +0x10 MxU32 m_numSlots; // +0x14 MxU32 m_autoResizeRatio; @@ -125,7 +88,7 @@ class MxHashTable : public MxCore // on the value of m_resizeOption. 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; + MxU32 m_increaseAmount; double m_increaseFactor; }; }; @@ -143,7 +106,7 @@ class MxHashTableCursor : public MxCore MxBool Find(T *p_obj) { MxU32 hash = m_table->Hash(p_obj); - int bucket = m_table->GetBucket(hash); + int bucket = hash % m_table->m_numSlots; MxHashTableNode *t = m_table->m_slots[bucket]; @@ -172,7 +135,7 @@ class MxHashTableCursor : public MxCore 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_table->GetBucket(m_match->m_hash); + int bucket = m_match->m_hash % m_table->m_numSlots; m_table->m_slots[bucket] = m_match->m_next; } @@ -189,4 +152,90 @@ class MxHashTableCursor : public MxCore MxHashTableNode *m_match; }; + +template +// OFFSET: LEGO1 0x100b0bd0 +MxHashTable::~MxHashTable() +{ + for (int i = 0; i < m_numSlots; i++) { + MxHashTableNode *t = m_slots[i]; + + while (t) { + MxHashTableNode *next = t->m_next; + m_customDestructor(t->m_obj); + delete t; + t = next; + } + } + + m_numKeys = 0; + memset(m_slots, 0, sizeof(MxHashTableNode *) * m_numSlots); + + delete[] m_slots; +} + +template +// OFFSET: LEGO1 0x100b7ab0 +inline void MxHashTable::Resize() +{ + // Save a reference to the current table + // so we can walk nodes and re-insert + MxU32 old_size = m_numSlots; + MxHashTableNode **old_table = m_slots; + + switch (m_resizeOption) { + case HASH_TABLE_OPT_EXPAND_ADD: + m_numSlots = old_size + m_increaseAmount; + break; + case HASH_TABLE_OPT_EXPAND_MULTIPLY: + m_numSlots = old_size * m_increaseFactor; + break; + } + + MxHashTableNode **new_table = new MxHashTableNode*[m_numSlots]; + // FIXME: order? m_numKeys set after `rep stosd` + m_slots = new_table; + memset(m_slots, 0, sizeof(MxHashTableNode *) * m_numSlots); + m_numKeys = 0; + + for (int i = 0; i != old_size; i++) { + MxHashTableNode *t = old_table[i]; + + while (t) { + MxHashTableNode *next = t->m_next; + _NodeInsert(t); + t = next; + } + } + + delete[] old_table; +} + +template +// OFFSET: LEGO1 0x100b7b80 +inline void MxHashTable::_NodeInsert(MxHashTableNode *p_node) +{ + int bucket = p_node->m_hash % m_numSlots; + + p_node->m_next = m_slots[bucket]; + + if (m_slots[bucket]) + m_slots[bucket]->m_prev = p_node; + + m_slots[bucket] = p_node; + m_numKeys++; +} + +template +inline void MxHashTable::Add(T* p_newobj) +{ + if (m_resizeOption && ((m_numKeys + 1) / m_numSlots) > m_autoResizeRatio) + MxHashTable::Resize(); + + MxU32 hash = Hash(p_newobj); + MxHashTableNode *node = new MxHashTableNode(p_newobj, hash); + + MxHashTable::_NodeInsert(node); +} + #endif // MXHASHTABLE_H \ No newline at end of file diff --git a/LEGO1/mxomni.cpp b/LEGO1/mxomni.cpp index 10e8eccb..f5022b30 100644 --- a/LEGO1/mxomni.cpp +++ b/LEGO1/mxomni.cpp @@ -104,6 +104,15 @@ void MxOmni::SetInstance(MxOmni *instance) // OFFSET: LEGO1 0x100af0c0 MxResult MxOmni::Create(MxOmniCreateParam &p) { + if (p.CreateFlags().CreateVariableTable()) + { + MxVariableTable *variableTable = new MxVariableTable(); + this->m_variableTable = variableTable; + + if (variableTable == NULL) + return FAILURE; + } + if (p.CreateFlags().CreateTimer()) { MxTimer *timer = new MxTimer(); diff --git a/LEGO1/mxvariabletable.cpp b/LEGO1/mxvariabletable.cpp index 9a87d397..81628993 100644 --- a/LEGO1/mxvariabletable.cpp +++ b/LEGO1/mxvariabletable.cpp @@ -33,11 +33,6 @@ void MxVariableTable::SetVariable(const char *p_key, const char *p_value) } else { MxHashTable::Add(var); } - - // create new var object here? - - // Resize inlined - // Add not } // OFFSET: LEGO1 0x100b7740 @@ -50,11 +45,6 @@ void MxVariableTable::SetVariable(MxVariable *var) cursor.DeleteMatch(); MxHashTable::Add(var); - - // we already have the new variable to add. - - // Resize not - // Add inlined } // OFFSET: LEGO1 0x100b78f0 diff --git a/LEGO1/mxvariabletable.h b/LEGO1/mxvariabletable.h index 7e31f7c0..b9ecf174 100644 --- a/LEGO1/mxvariabletable.h +++ b/LEGO1/mxvariabletable.h @@ -8,13 +8,19 @@ // VTABLE 0x100dc1c8 // SIZE 0x28 -class MxVariableTable : protected MxHashTable +class MxVariableTable : public MxHashTable { public: + MxVariableTable() { + m_customDestructor = Destroy; + } __declspec(dllexport) void SetVariable(const char *key, const char *value); __declspec(dllexport) void SetVariable(MxVariable *var); __declspec(dllexport) const char * GetVariable(const char *key); + // OFFSET: LEGO1 0x100afdb0 + static void Destroy(MxVariable *p_obj) { p_obj->Destroy(); } + virtual MxS8 Compare(MxVariable *, MxVariable *); // +0x14 virtual MxU32 Hash(MxVariable *); // +0x18 };