/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation This program 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include // default constructor CHashTable_TYPE::CHashTable_TYPE() { ht_ctCompartments = 0; ht_ctSlotsPerComp = 0; ht_ctSlotsPerCompStep = 0; ht_GetItemKey = NULL; ht_GetItemValue = NULL; } // destructor -- frees all memory CHashTable_TYPE::~CHashTable_TYPE(void) { } // remove all slots, and reset the nametable to initial (empty) state, keeps the callback functions void CHashTable_TYPE::Clear(void) { ht_ctCompartments = 0; ht_ctSlotsPerComp = 0; ht_ctSlotsPerCompStep = 0; ht_ahtsSlots.Clear(); } // internal finding, returns pointer to the the item CHashTableSlot_TYPE *CHashTable_TYPE::FindSlot(ULONG ulKey, VALUE_TYPE &Value) { ASSERT(ht_ctCompartments>0 && ht_ctSlotsPerComp>0); // find compartment number INDEX iComp = ulKey%ht_ctCompartments; // for each slot in the compartment INDEX iSlot = iComp*ht_ctSlotsPerComp; for(INDEX iSlotInComp=0; iSlotInComphts_ptElement==NULL) { // skip it continue; } // if it has same key if (phts->hts_ulKey==ulKey) { // if it is same element if (ht_GetItemValue(phts->hts_ptElement) == Value) { // return it return phts; } } } // not found return NULL; } // internal finding, returns the index of the item in the nametable INDEX CHashTable_TYPE::FindSlotIndex(ULONG ulKey, VALUE_TYPE &Value) { ASSERT(ht_ctCompartments>0 && ht_ctSlotsPerComp>0); // find compartment number INDEX iComp = ulKey%ht_ctCompartments; // for each slot in the compartment INDEX iSlot = iComp*ht_ctSlotsPerComp; for(INDEX iSlotInComp=0; iSlotInComphts_ptElement==NULL) { // skip it continue; } // if it has same key if (phts->hts_ulKey==ulKey) { // if it is same element if (ht_GetItemValue(phts->hts_ptElement) == Value) { // return it return iSlot; } } } // not found return -1; } TYPE* CHashTable_TYPE::GetItemFromIndex(INDEX iIndex) { ASSERT(ht_ctCompartments>0 && ht_ctSlotsPerComp>0); ASSERT(iIndex>=0 && iIndex0 && ht_ctSlotsPerComp>0); ASSERT(iIndex>=0 && iIndex0 && ctSlotsPerComp>0 && ctSlotsPerCompStep>0 ); ht_ctCompartments = ctCompartments; ht_ctSlotsPerComp = ctSlotsPerComp; ht_ctSlotsPerCompStep = ctSlotsPerCompStep; ht_ahtsSlots.New(ht_ctCompartments*ht_ctSlotsPerComp); } void CHashTable_TYPE::SetCallbacks(ULONG (*GetItemKey)(VALUE_TYPE &Item), ULONG (*GetItemValue)(TYPE* Item)) { ASSERT(GetItemKey!=NULL); ASSERT(GetItemValue!=NULL); ht_GetItemKey = GetItemKey; ht_GetItemValue = GetItemValue; } // find an object by name TYPE *CHashTable_TYPE::Find(VALUE_TYPE &Value) { ASSERT(ht_ctCompartments>0 && ht_ctSlotsPerComp>0); CHashTableSlot_TYPE *phts = FindSlot(ht_GetItemKey(Value), Value); if (phts==NULL) return NULL; return phts->hts_ptElement; } // find an object by name, return it's index INDEX CHashTable_TYPE::FindIndex(VALUE_TYPE &Value) { ASSERT(ht_ctCompartments>0 && ht_ctSlotsPerComp>0); return FindSlotIndex(ht_GetItemKey(Value), Value); } // expand the name table to next step void CHashTable_TYPE::Expand(void) { ASSERT(ht_ctCompartments>0 && ht_ctSlotsPerComp>0); // if we are here -> the compartment has overflowed ASSERT(ht_ctSlotsPerCompStep>0); // move the array of slots CStaticArray ahtsSlotsOld; ahtsSlotsOld.MoveArray(ht_ahtsSlots); // allocate new bigger array INDEX ctOldSlotsPerComp = ht_ctSlotsPerComp; ht_ctSlotsPerComp+=ht_ctSlotsPerCompStep; ht_ahtsSlots.New(ht_ctSlotsPerComp*ht_ctCompartments); // for each compartment for(INDEX iComp =0; iComp0 && ht_ctSlotsPerComp>0); VALUE_TYPE Value = ht_GetItemValue(ptNew); ULONG ulKey = ht_GetItemKey(Value); // find compartment number INDEX iComp = ulKey%ht_ctCompartments; // for each slot in the compartment INDEX iSlot = iComp*ht_ctSlotsPerComp; for(INDEX iSlotInComp=0; iSlotInComphts_ptElement==NULL) { // put it here phts->hts_ulKey = ulKey; phts->hts_ptElement = ptNew; return; } // must not already exist //ASSERT(phts->hts_ptElement->GetName()!=ptNew->GetName()); } // if we are here -> the compartment has overflowed // expand the name table to next step ASSERT(!_bExpanding); _bExpanding = TRUE; Expand(); // add the new element Add(ptNew); _bExpanding = FALSE; } // remove an object void CHashTable_TYPE::Remove(TYPE *ptOld) { ASSERT(ht_ctCompartments>0 && ht_ctSlotsPerComp>0); // find its slot VALUE_TYPE Value = ht_GetItemValue(ptOld); CHashTableSlot_TYPE *phts = FindSlot(ht_GetItemKey(Value), Value); if( phts!=NULL) { // mark slot as unused ASSERT( phts->hts_ptElement==ptOld); phts->hts_ptElement = NULL; } } // remove an object void CHashTable_TYPE::RemoveAll() { ASSERT(ht_ctCompartments>0 && ht_ctSlotsPerComp>0); for (INDEX iComp=0;iComp