/* =========================================================================== Copyright (C) 2015 the OpenMoHAA team This file is part of OpenMoHAA source code. OpenMoHAA source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. OpenMoHAA source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenMoHAA source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ // con_arrayset.h: con_set with an index table #pragma once #include "mem_blockalloc.h" template class con_arrayset_enum; template class con_arrayset : public con_set { friend class con_arrayset_enum; public: class Entry { public: k key; v value; unsigned int index; Entry *next; public: void *operator new(size_t size); void operator delete(void *ptr); Entry(); #ifdef ARCHIVE_SUPPORTED void Archive(Archiver& arc); #endif }; public: static MEM_BlockAlloc Entry_allocator; private: Entry **table; // hashtable unsigned int tableLength; unsigned int threshold; unsigned int count; // num of entries short unsigned int tableLengthIndex; Entry *defaultEntry; Entry **reverseTable; // the index table protected: Entry *findKeyEntry(const k& key) const; Entry *addKeyEntry(const k& key); Entry *addNewKeyEntry(const k& key); public: con_arrayset(); ~con_arrayset(); #ifdef ARCHIVE_SUPPORTED void Archive(Archiver& arc); #endif void clear(); void resize(int count = 0); unsigned int findKeyIndex(const k& key); unsigned int addKeyIndex(const k& key); unsigned int addNewKeyIndex(const k& key); bool remove(const k &key); v& operator[](unsigned int index); }; template MEM_BlockAlloc::Entry> con_arrayset::Entry_allocator; template void *con_arrayset::Entry::operator new(size_t size) { return Entry_allocator.Alloc(); } template void con_arrayset::Entry::operator delete(void *ptr) { Entry_allocator.Free(ptr); } template con_arrayset::Entry::Entry() { this->key = k(); this->value = v(); index = 0; next = NULL; } template con_arrayset::con_arrayset() { tableLength = 1; table = &defaultEntry; threshold = 1; count = 0; tableLengthIndex = 0; defaultEntry = NULL; reverseTable = (&this->defaultEntry) - 1; } template con_arrayset::~con_arrayset() { clear(); } template void con_arrayset::resize(int count) { Entry **oldReverseTable = reverseTable; Entry **oldTable = table; Entry *e, *old; unsigned int index; unsigned int oldTableLength = tableLength; unsigned int i; if (count > 0) { tableLength += count; threshold = tableLength; } else { //threshold = ( unsigned int )( ( float )tableLength * 0.75f ); threshold = (unsigned int)((float)tableLength * 0.75); if (threshold < 1) { threshold = 1; } tableLength += threshold; } // allocate a new table table = new Entry *[tableLength](); memset(table, 0, tableLength * sizeof(Entry *)); // rehash the table for (i = oldTableLength; i > 0; i--) { // rehash all entries from the old table for (e = oldTable[i - 1]; e != NULL; e = old) { old = e->next; // insert the old entry to the table hashindex index = HashCode(e->key) % tableLength; e->next = table[index]; table[index] = e; } } if (oldTableLength > 1) { // delete the previous table delete[] oldTable; } // allocate a bigger reverse table reverseTable = (new Entry *[this->tableLength]()) - 1; for (i = 1; i <= oldTableLength; i++) { reverseTable[i] = oldReverseTable[i]; } if (oldTableLength > 1) { ++oldReverseTable; delete[] oldReverseTable; } } template void con_arrayset::clear() { Entry *entry = NULL; Entry *next = NULL; unsigned int i; if (this->tableLength > 1) { reverseTable++; delete[] reverseTable; reverseTable = (&this->defaultEntry) - 1; } for (i = 0; i < tableLength; i++) { for (entry = table[i]; entry != NULL; entry = next) { next = entry->next; delete entry; } } if (tableLength > 1) { delete[] table; } tableLength = 1; table = &defaultEntry; threshold = 1; count = 0; tableLengthIndex = 0; defaultEntry = NULL; } template typename con_arrayset::Entry *con_arrayset::findKeyEntry(const k& key) const { Entry *entry; entry = table[HashCode(key) % tableLength]; for (; entry != NULL; entry = entry->next) { if (entry->key == key) { return entry; } } return NULL; } template typename con_arrayset::Entry *con_arrayset::addKeyEntry(const k& key) { Entry *entry; entry = findKeyEntry(key); if (entry != NULL) { return entry; } else { return addNewKeyEntry(key); } } template typename con_arrayset::Entry *con_arrayset::addNewKeyEntry(const k& key) { Entry *entry; int index; if (count >= threshold) { resize(); } index = HashCode(key) % tableLength; count++; entry = new Entry; if (defaultEntry == NULL) { defaultEntry = entry; entry->next = NULL; } else { entry->next = table[index]; } entry->key = key; entry->index = count; table[index] = entry; reverseTable[count] = entry; return entry; } template unsigned int con_arrayset::addKeyIndex(const k& key) { Entry *entry = this->addKeyEntry(key); return entry->index; } template unsigned int con_arrayset::addNewKeyIndex(const k& key) { Entry *entry = this->addNewKeyEntry(key); return entry->index; } template unsigned int con_arrayset::findKeyIndex(const k& key) { Entry *entry = this->findKeyEntry(key); if (entry != NULL) { return entry->index; } else { return 0; } } template bool con_arrayset::remove(const k& key) { int i; for (i = 1; i <= this->tableLength; i++) { if (reverseTable[i] && reverseTable[i]->key == key) { reverseTable[i] = NULL; } } return con_set::remove(key); } template value& con_arrayset::operator[](unsigned int index) { return reverseTable[index]->key; } template class con_arrayset_enum { friend class con_map_enum; public: using Entry = typename con_arrayset::Entry; protected: con_arrayset *m_Set; unsigned int m_Index; Entry *m_CurrentEntry; Entry *m_NextEntry; public: con_arrayset_enum(); con_arrayset_enum(con_arrayset& set); bool operator=(con_arrayset& set); Entry *NextElement(void); Entry *CurrentElement(void); }; template con_arrayset_enum::con_arrayset_enum() { m_Set = NULL; m_Index = 0; m_CurrentEntry = NULL; m_NextEntry = NULL; } template con_arrayset_enum::con_arrayset_enum(con_arrayset& set) { *this = set; } template bool con_arrayset_enum::operator=(con_arrayset& set) { m_Set = &set; m_Index = m_Set->tableLength; m_CurrentEntry = NULL; m_NextEntry = NULL; return true; } template typename con_arrayset_enum::Entry *con_arrayset_enum::CurrentElement(void) { return m_CurrentEntry; } template typename con_arrayset_enum::Entry *con_arrayset_enum::NextElement(void) { if (!m_NextEntry) { while (1) { if (!m_Index) { break; } m_Index--; m_NextEntry = m_Set->table[m_Index]; if (m_NextEntry) { break; } } if (!m_NextEntry) { m_CurrentEntry = NULL; return NULL; } } m_CurrentEntry = m_NextEntry; m_NextEntry = m_NextEntry->next; return m_CurrentEntry; }