From 6d3df6f63417382a41666cead84fbb98f15d982a Mon Sep 17 00:00:00 2001 From: disinvite Date: Tue, 11 Jul 2023 18:15:39 -0400 Subject: [PATCH] move to header file --- LEGO1/mxhashtable.h | 192 ++++++++++++++++++++++++++++++++++++++ LEGO1/mxvariabletable.cpp | 14 ++- LEGO1/mxvariabletable.h | 179 +---------------------------------- 3 files changed, 205 insertions(+), 180 deletions(-) create mode 100644 LEGO1/mxhashtable.h diff --git a/LEGO1/mxhashtable.h b/LEGO1/mxhashtable.h new file mode 100644 index 00000000..f3449453 --- /dev/null +++ b/LEGO1/mxhashtable.h @@ -0,0 +1,192 @@ +#ifndef MXHASHTABLE_H +#define MXHASHTABLE_H + +#include "mxtypes.h" +#include "mxcore.h" + +#define HASH_TABLE_INIT_SIZE 128 +#define HASH_TABLE_OPT_NO_EXPAND 0 +#define HASH_TABLE_OPT_EXPAND_ADD 1 +#define HASH_TABLE_OPT_EXPAND_MULTIPLY 2 + +template +class MxHashTableNode +{ +public: + MxHashTableNode() {} + MxHashTableNode(T *p_obj, MxU32 p_hash) + { + m_obj = p_obj; + m_hash = p_hash; + m_prev = NULL; + m_next = NULL; + } + +//private: + T* m_obj; + MxU32 m_hash; + MxHashTableNode *m_prev; + MxHashTableNode *m_next; +}; + +template +class MxHashTable : public MxCore +{ +public: + MxHashTable() + { + m_numSlots = HASH_TABLE_INIT_SIZE; + m_slots = new MxHashTableNode*[HASH_TABLE_INIT_SIZE]; + m_resizeOption = HASH_TABLE_OPT_NO_EXPAND; + } + + ~MxHashTable() + { + // TODO: Walk table to delete nodes? + delete[] m_slots; + } + + // for convenience + inline int GetBucket(int hash) { + return hash % m_numSlots; + } + + // OFFSET: LEGO1 0x100b7ab0 + void MxHashTable::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_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; + } + + // 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; + int m_resizeOption; // +0x1c + // FIXME: or FIXME? This qword is used as an integer or double depending + // 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; + double m_increaseFactor; + }; +}; + +template +class MxHashTableCursor : public MxCore +{ +public: + MxHashTableCursor(MxHashTable *p_hashTable) + { + m_table = p_hashTable; + m_match = NULL; + } + + MxBool Find(T *p_obj) + { + MxU32 hash = m_table->Hash(p_obj); + int bucket = m_table->GetBucket(hash); + + MxHashTableNode *t = m_table->m_slots[bucket]; + + while (t) { + if (t->m_hash == hash && !m_table->Compare(t->m_obj, p_obj)) + m_match = t; + t = t->m_next; + } + + return m_match != NULL; + } + + void GetMatch(T **p_obj) + { + if (m_match) { + *p_obj = m_match->m_obj; + } + } + + void DeleteMatch() + { + // 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_table->GetBucket(m_match->m_hash); + 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_table; + MxHashTableNode *m_match; +}; + +#endif // MXHASHTABLE_H \ No newline at end of file diff --git a/LEGO1/mxvariabletable.cpp b/LEGO1/mxvariabletable.cpp index c4fa34d6..f960f917 100644 --- a/LEGO1/mxvariabletable.cpp +++ b/LEGO1/mxvariabletable.cpp @@ -31,8 +31,13 @@ void MxVariableTable::SetVariable(const char *p_key, const char *p_value) cursor.GetMatch(&var); var->SetValue(p_value); } else { - Add(var); + MxHashTable::Add(var); } + + // create new var object here? + + // Resize inlined + // Add not } // OFFSET: LEGO1 0x100b7740 @@ -44,7 +49,12 @@ void MxVariableTable::SetVariable(MxVariable *var) if (found) cursor.DeleteMatch(); - Add(var); + 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 37a5a168..c94894fd 100644 --- a/LEGO1/mxvariabletable.h +++ b/LEGO1/mxvariabletable.h @@ -2,186 +2,9 @@ #define MXVARIABLETABLE_H #include "mxtypes.h" -#include "mxcore.h" +#include "mxhashtable.h" #include "mxvariable.h" -template -class MxHashTableNode -{ -public: - MxHashTableNode() {} - MxHashTableNode(T *p_obj, MxU32 p_hash) - { - m_obj = p_obj; - m_hash = p_hash; - m_prev = NULL; - m_next = NULL; - } - -//private: - T* m_obj; - MxU32 m_hash; - MxHashTableNode *m_prev; - MxHashTableNode *m_next; -}; - -template -class MxHashTable : public MxCore -{ -public: - MxHashTable() - { - m_numSlots = 128; - m_slots = new MxHashTableNode*[128]; - } - - ~MxHashTable() - { - // TODO: Walk table to delete nodes? - delete[] m_slots; - } - - // for convenience - inline int GetBucket(int hash) { - return hash % m_numSlots; - } - - inline void _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++; - } - - // 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 + m_increaseAmount; - break; - case 2: // increase by a factor of x - 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; - } - - void Add(T* p_newobj) - { - if (m_option && ((m_numKeys + 1) / m_numSlots) > m_autoResizeRatio) - Resize(); - - MxU32 hash = Hash(p_newobj); - MxHashTableNode *node = new MxHashTableNode(p_newobj, hash); - - _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; - 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 -class MxHashTableCursor : public MxCore -{ -public: - MxHashTableCursor(MxHashTable *p_hashTable) - { - m_table = p_hashTable; - m_match = NULL; - } - - MxBool Find(T *p_obj) - { - MxU32 hash = m_table->Hash(p_obj); - int bucket = m_table->GetBucket(hash); - - MxHashTableNode *t = m_table->m_slots[bucket]; - - while (t) { - if (t->m_hash == hash && !m_table->Compare(t->m_obj, p_obj)) - m_match = t; - t = t->m_next; - } - - return m_match != NULL; - } - - void GetMatch(T **p_obj) - { - if (m_match) { - *p_obj = m_match->m_obj; - } - } - - void DeleteMatch() - { - // 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_table->GetBucket(m_match->m_hash); - 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_table; - MxHashTableNode *m_match; // type ? -}; // VTABLE 0x100dc1c8 // SIZE 0x28