49 void init(uint32_t initialTableSize,
float loadFactor)
57 mLoadFactor = loadFactor;
58 mFreeList = uint32_t(EOL);
63 reserveInternal(initialTableSize);
67 typedef Entry EntryType;
71 init(initialTableSize, loadFactor);
76 init(initialTableSize, loadFactor);
89 PxAllocator::deallocate(mBuffer);
92 static const uint32_t EOL = 0xffffffff;
94 PX_INLINE Entry* create(
const Key& k,
bool& exists)
100 uint32_t index = mHash[h];
101 while(index != EOL && !HashFn().equal(GetKey()(mEntries[index]), k))
102 index = mEntriesNext[index];
103 exists = index != EOL;
105 return mEntries + index;
116 uint32_t entryIndex = freeListGetNext();
118 mEntriesNext[entryIndex] = mHash[h];
119 mHash[h] = entryIndex;
124 return mEntries + entryIndex;
127 PX_INLINE const Entry* find(
const Key& k)
const
132 const uint32_t h = hash(k);
133 uint32_t index = mHash[h];
134 while(index != EOL && !HashFn().equal(GetKey()(mEntries[index]), k))
135 index = mEntriesNext[index];
136 return index != EOL ? mEntries + index : NULL;
139 PX_INLINE bool erase(
const Key& k, Entry& e)
144 const uint32_t h = hash(k);
145 uint32_t* ptr = mHash + h;
146 while(*ptr != EOL && !HashFn().equal(GetKey()(mEntries[*ptr]), k))
147 ptr = mEntriesNext + *ptr;
152 PX_PLACEMENT_NEW(&e, Entry)(mEntries[*ptr]);
154 return eraseInternal(ptr);
162 const uint32_t h = hash(k);
163 uint32_t* ptr = mHash + h;
164 while(*ptr != EOL && !HashFn().equal(GetKey()(mEntries[*ptr]), k))
165 ptr = mEntriesNext + *ptr;
170 return eraseInternal(ptr);
175 return mEntriesCount;
185 if(!mHashSize || mEntriesCount == 0)
190 intrinsics::memSet(mHash, EOL, mHashSize *
sizeof(uint32_t));
192 const uint32_t sizeMinus1 = mEntriesCapacity - 1;
193 for(uint32_t i = 0; i < sizeMinus1; i++)
196 mEntriesNext[i] = i + 1;
198 mEntriesNext[mEntriesCapacity - 1] = uint32_t(EOL);
203 void reserve(uint32_t size)
206 reserveInternal(size);
209 PX_INLINE const Entry* getEntries()
const
214 PX_INLINE Entry* insertUnique(
const Key& k)
216 PX_ASSERT(find(k) == NULL);
217 uint32_t h = hash(k);
219 uint32_t entryIndex = freeListGetNext();
221 mEntriesNext[entryIndex] = mHash[h];
222 mHash[h] = entryIndex;
227 return mEntries + entryIndex;
233 for(uint32_t i = 0; i < mHashSize; i++)
235 for(uint32_t j = mHash[i]; j != EOL; j = mEntriesNext[j])
236 mEntries[j].~Entry();
240 template <
typename HK,
typename GK,
class A,
bool comp>
247 PX_INLINE void freeListAdd(uint32_t index)
252 PX_ASSERT(mFreeList == mEntriesCount);
256 mEntriesNext[index] = mFreeList;
261 PX_INLINE void freeListAdd(uint32_t start, uint32_t end)
265 for(uint32_t i = start; i < end - 1; i++)
266 mEntriesNext[i] = i + 1;
269 mEntriesNext[end - 1] = mFreeList;
270 PX_ASSERT(mFreeList != end - 1);
273 else if(mFreeList == EOL)
279 PX_ASSERT(!freeListEmpty());
282 PX_ASSERT(mFreeList == mEntriesCount);
287 uint32_t entryIndex = mFreeList;
288 mFreeList = mEntriesNext[mFreeList];
296 return mEntriesCount == mEntriesCapacity;
298 return mFreeList == EOL;
301 PX_INLINE void replaceWithLast(uint32_t index)
303 PX_PLACEMENT_NEW(mEntries + index, Entry)(mEntries[mEntriesCount]);
304 mEntries[mEntriesCount].~Entry();
305 mEntriesNext[index] = mEntriesNext[mEntriesCount];
307 uint32_t h = hash(GetKey()(mEntries[index]));
309 for(ptr = mHash + h; *ptr != mEntriesCount; ptr = mEntriesNext + *ptr)
310 PX_ASSERT(*ptr != EOL);
314 PX_INLINE uint32_t hash(
const Key& k, uint32_t hashSize)
const
316 return HashFn()(k) & (hashSize - 1);
319 PX_INLINE uint32_t hash(
const Key& k)
const
321 return hash(k, mHashSize);
324 PX_INLINE bool eraseInternal(uint32_t* ptr)
326 const uint32_t index = *ptr;
328 *ptr = mEntriesNext[index];
330 mEntries[index].~Entry();
335 if (compacting && index != mEntriesCount)
336 replaceWithLast(index);
344 if(!PxIsPowerOfTwo(size))
345 size = PxNextPowerOfTwo(size);
347 PX_ASSERT(!(size & (size - 1)));
350 bool resizeCompact = compacting || freeListEmpty();
353 uint32_t oldEntriesCapacity = mEntriesCapacity;
354 uint32_t newEntriesCapacity = uint32_t(
float(size) * mLoadFactor);
355 uint32_t newHashSize = size;
360 uint32_t* newEntriesNext;
363 uint32_t newHashByteOffset = 0;
364 uint32_t newEntriesNextBytesOffset = newHashByteOffset + newHashSize *
sizeof(uint32_t);
365 uint32_t newEntriesByteOffset = newEntriesNextBytesOffset + newEntriesCapacity *
sizeof(uint32_t);
366 newEntriesByteOffset += (16 - (newEntriesByteOffset & 15)) & 15;
367 uint32_t newBufferByteSize = newEntriesByteOffset + newEntriesCapacity *
sizeof(Entry);
369 newBuffer =
reinterpret_cast<uint8_t*
>(PxAllocator::allocate(newBufferByteSize, __FILE__, __LINE__));
370 PX_ASSERT(newBuffer);
372 newHash =
reinterpret_cast<uint32_t*
>(newBuffer + newHashByteOffset);
373 newEntriesNext =
reinterpret_cast<uint32_t*
>(newBuffer + newEntriesNextBytesOffset);
374 newEntries =
reinterpret_cast<Entry*
>(newBuffer + newEntriesByteOffset);
378 intrinsics::memSet(newHash, uint32_t(EOL), newHashSize *
sizeof(uint32_t));
384 PX_ASSERT(compacting || mFreeList == EOL);
386 for(uint32_t index = 0; index < mEntriesCount; ++index)
388 uint32_t h = hash(GetKey()(mEntries[index]), newHashSize);
389 newEntriesNext[index] = newHash[h];
392 PX_PLACEMENT_NEW(newEntries + index, Entry)(mEntries[index]);
393 mEntries[index].~Entry();
399 intrinsics::memCopy(newEntriesNext, mEntriesNext, mEntriesCapacity *
sizeof(uint32_t));
401 for(uint32_t bucket = 0; bucket < mHashSize; bucket++)
403 uint32_t index = mHash[bucket];
406 uint32_t h = hash(GetKey()(mEntries[index]), newHashSize);
407 newEntriesNext[index] = newHash[h];
408 PX_ASSERT(index != newHash[h]);
412 PX_PLACEMENT_NEW(newEntries + index, Entry)(mEntries[index]);
413 mEntries[index].~Entry();
415 index = mEntriesNext[index];
421 PxAllocator::deallocate(mBuffer);
424 mHashSize = newHashSize;
425 mEntriesNext = newEntriesNext;
426 mEntries = newEntries;
427 mEntriesCapacity = newEntriesCapacity;
429 freeListAdd(oldEntriesCapacity, newEntriesCapacity);
434 PX_ASSERT((mFreeList == EOL) || (compacting && (mEntriesCount == mEntriesCapacity)));
436 uint32_t size = mHashSize == 0 ? 16 : mHashSize * 2;
442 uint32_t* mEntriesNext;
444 uint32_t mEntriesCapacity;
449 uint32_t mEntriesCount;
457 if(mBase.mEntriesCapacity > 0)
459 mEntry = mBase.mHash[0];
466 PX_ASSERT(mTimestamp == mBase.mTimestamp);
471 return mBase.mEntries[mEntry];
476 return mBase.mEntries[mEntry];
478 PX_INLINE const Entry* operator->()
const
481 return mBase.mEntries + mEntry;
486 return mBase.mEntries + mEntry;
504 return mEntry == mBase.EOL;
510 mEntry = mBase.mEntriesNext[mEntry];
515 while(mEntry == mBase.EOL)
517 if(++mBucket == mBase.mHashSize)
519 mEntry = mBase.mHash[mBucket];
542 PX_INLINE Entry* eraseCurrentGetNext(
bool eraseCurrent)
544 if(eraseCurrent && mCurrentEntryIndexPtr)
546 mBase.eraseInternal(mCurrentEntryIndexPtr);
548 if(*mCurrentEntryIndexPtr != mBase.EOL)
549 return mBase.mEntries + *mCurrentEntryIndexPtr;
551 return traverseHashEntries();
555 if(mCurrentEntryIndexPtr == NULL)
556 return traverseHashEntries();
558 const uint32_t index = *mCurrentEntryIndexPtr;
559 if(mBase.mEntriesNext[index] == mBase.EOL)
561 return traverseHashEntries();
565 mCurrentEntryIndexPtr = mBase.mEntriesNext + index;
566 return mBase.mEntries + *mCurrentEntryIndexPtr;
572 mCurrentHashIndex = 0;
573 mCurrentEntryIndexPtr = NULL;
579 mCurrentEntryIndexPtr = NULL;
580 while (mCurrentEntryIndexPtr == NULL && mCurrentHashIndex < mBase.mHashSize)
582 if (mBase.mHash[mCurrentHashIndex] != mBase.EOL)
584 mCurrentEntryIndexPtr = mBase.mHash + mCurrentHashIndex;
586 return mBase.mEntries + *mCurrentEntryIndexPtr;
598 uint32_t* mCurrentEntryIndexPtr;
599 uint32_t mCurrentHashIndex;