void* hashFind( Hashtable tbl, void* key) { HashItem* itemPtr = hashFindInternal(tbl, key); HashItem item = *itemPtr; if (item != NULL) return GET_HASH_KEY(item); return NULL; }
//----------------------------------------------------------------------------------------------------------------------- CResourceBase* EAssetMgr::CreateResource( eRESOURCE_TYPE type, const char* name) { if( GetResource(type , name) != NULL ) { assert(0); return NULL; } CResourceBase* pResource = MemGetNew(type); pResource->loadState = RESOURCE_MEMORY_CREATED; pResource->RID = GET_HASH_KEY( name ); strcpy_s( pResource->name, name); m_ResourceMap[type].SetAt( pResource->RID, pResource ); return pResource; }
TEST(insert_many_ids_into_same_list, then_hash_list_must_be_filled) { int listId = 11111111 & tbl->lowMask; int sNum = listId >> tbl->segmShift; int sInd = listId & (tbl->segmSize - 1); HashItem listPtr = tbl->segments[sNum][sInd]; int numItems = 0; int key = -1; while (listPtr != NULL) { key = *(int*)GET_HASH_KEY(listPtr); TEST_ASSERT_EQUAL_UINT32(key, numItems++); listPtr = listPtr->next; } TEST_ASSERT_EQUAL_UINT32(numItems, 1000); }
HashItem* hashFindInternal( Hashtable tbl, void* key) { HashSegment segm; HashItem* itemPtr; HashItem item; uint keyLen = tbl->keyLen; hashCmpFunc cmpFunc = tbl->hashCmp; uint hash = tbl->hashFunc(key, keyLen); uint listId, sNum, sInd; listId = convertHashToListNumber(tbl, hash); /* Segment size always is a power of 2: 2^n. * SegmentSize is 2^n. * SegmentShift is n. * listId we can represent: listId = segmSize * sNum + sInd; * So sNum = listId/segmSize, sInd = listId mod segmSize; * When we operate with powers of 2, we can compute these operations * using only bitwise operations */ sNum = listId >> tbl->segmShift; sInd = listId & (tbl->segmSize - 1); segm = tbl->segments[sNum]; itemPtr = &segm[sInd]; item = *itemPtr; while (item != NULL) { if (item->hash == hash && cmpFunc(GET_HASH_KEY(item), key, keyLen) == 0) break; itemPtr = &(item->next); item = *itemPtr; } return itemPtr; }
void* hashRemove( void* self, Hashtable tbl, void* key) { IHashtableManager _ = (IHashtableManager)self; ISpinLockManager slog = (ISpinLockManager)_->spinLockHelper; HashItem* itemPtr; HashItem item; HashItem newElem = tbl->freeList; uint keyLen = tbl->keyLen; uint hash = tbl->hashFunc(key, keyLen); /* We need to explain why we use volatile keyword. * We need to pass along volatile long* parameter * to spinlockmanager spinLockAcquire method. * When we declare volatile Hashtable tblLocal * we receive the following declaration: * * typedef struct SHashtable * { * HANDLE mutex; * ... * }; * * volatile SHashtable tbl; will be converted to: * * typedef struct SHashtable * { * volatile HANDLE mutex * ... * }; * * So that we can put &(tbl->mutex) into SPIN_LOCK_ACQUIRE. */ volatile Hashtable tblLocal = tbl; itemPtr = hashFindInternal(tblLocal, key); item = *itemPtr; if (item == NULL) return NULL; if (IS_TABLE_PARTITIONED(tblLocal)) SPIN_LOCK_ACQUIRE(slog, &(tblLocal->mutex)); tblLocal->numItems--; /* Remove the item from a cache's list. */ *itemPtr = item->next; /* Add the item to the free list. */ item->next = tblLocal->freeList; tblLocal->freeList = item; if (IS_TABLE_PARTITIONED(tblLocal)) SPIN_LOCK_RELEASE(slog, &(tblLocal->mutex)); return GET_HASH_KEY(item); }
void* hashInsert( void* self, Hashtable tbl, void* key) { IHashtableManager _ = (IHashtableManager)self; ISpinLockManager slog = (ISpinLockManager)_->spinLockHelper; HashItem* itemPtr; HashItem item; HashItem newElem; uint keyLen = tbl->keyLen; uint hash = tbl->hashFunc(key, keyLen); Bool needToExtend = tbl->numItems > tbl->hashListSize * tbl->numHashLists; /* We assume that our hash function produces completely * uniformly distributed data. We can compute the average * amount of items in each hash list. * tbl->hashListSize is expected average hash list size. * If we exceed this number, we need to add a new hash list */ if (!IS_TABLE_PARTITIONED(tbl) && needToExtend && !tbl->isWithoutExtention) extendHashTable(self, tbl); itemPtr = hashFindInternal(tbl, key); item = *itemPtr; if (item != NULL) return GET_HASH_KEY(item); CYCLE { if (IS_TABLE_PARTITIONED(tbl)) SPIN_LOCK_ACQUIRE(slog, &(tbl->mutex)); newElem = tbl->freeList; if (newElem != NULL) break; if (IS_TABLE_PARTITIONED(tbl)) SPIN_LOCK_RELEASE(slog, &(tbl->mutex)); if (!allocNewItems(_, tbl->numItemsToAlloc)) return NULL; } /* Remove the first entry from freeList */ tbl->freeList = newElem->next; tbl->numItems++; if (IS_TABLE_PARTITIONED(tbl)) SPIN_LOCK_RELEASE(slog, &(tbl->mutex)); *itemPtr = newElem; newElem->next = NULL; newElem->hash = hash; /* SHashItem is a struct with wo fileds: next and hash. * There are no other fields. We want to attach the whole key * to the end of the memory the pointer to SHashItem points to. * Before we need to align already allocated memory. * Memory will look like here: * * [...next...][...hash....][..aligned..][....aligned..key.......][..aligned..value....] * |<------ SHashItem ---->| | * |<--------- aligned SHashItem ------>| */ tbl->hashCpy(GET_HASH_KEY(newElem), key, keyLen); return GET_HASH_KEY(newElem); }