4# define plInvalidIndex 0xFFFFFFFF
9template <
typename K,
typename V,
typename H>
11 : m_pHashTable(&hashTable)
15template <
typename K,
typename V,
typename H>
18 if (m_pHashTable->IsEmpty())
20 m_uiCurrentIndex = m_pHashTable->m_uiCapacity;
23 while (!m_pHashTable->IsValidEntry(m_uiCurrentIndex))
29template <
typename K,
typename V,
typename H>
32 m_uiCurrentCount = m_pHashTable->m_uiCount;
33 m_uiCurrentIndex = m_pHashTable->m_uiCapacity;
37template <
typename K,
typename V,
typename H>
40 return m_uiCurrentCount < m_pHashTable->m_uiCount;
43template <
typename K,
typename V,
typename H>
46 return m_uiCurrentIndex == rhs.m_uiCurrentIndex && m_pHashTable->m_pEntries == rhs.m_pHashTable->m_pEntries;
49template <
typename K,
typename V,
typename H>
52 return m_pHashTable->m_pEntries[m_uiCurrentIndex].key;
55template <
typename K,
typename V,
typename H>
58 return m_pHashTable->m_pEntries[m_uiCurrentIndex].value;
61template <
typename K,
typename V,
typename H>
65 if (m_uiCurrentCount >= m_pHashTable->m_uiCount)
74 while (m_uiCurrentIndex < m_pHashTable->m_uiCapacity)
76 if (m_pHashTable->IsValidEntry(m_uiCurrentIndex))
84 m_uiCurrentCount = m_pHashTable->m_uiCount;
87template <
typename K,
typename V,
typename H>
93#if PL_ENABLED(PL_USE_CPP20_OPERATORS)
98 template <
typename K,
typename V,
typename H>
103 template <
typename K,
typename V,
typename H>
106 using type =
const K&;
109 template <
typename K,
typename V,
typename H>
112 using type =
const V&;
119template <
typename K,
typename V,
typename H>
125template <
typename K,
typename V,
typename H>
129 this->m_uiCurrentIndex = rhs.m_uiCurrentIndex;
130 this->m_uiCurrentCount = rhs.m_uiCurrentCount;
133template <
typename K,
typename V,
typename H>
136 this->m_pHashTable = rhs.m_pHashTable;
137 this->m_uiCurrentIndex = rhs.m_uiCurrentIndex;
138 this->m_uiCurrentCount = rhs.m_uiCurrentCount;
141template <
typename K,
typename V,
typename H>
144 return this->m_pHashTable->m_pEntries[this->m_uiCurrentIndex].value;
147template <
typename K,
typename V,
typename H>
150 return this->m_pHashTable->m_pEntries[this->m_uiCurrentIndex].value;
154#if PL_ENABLED(PL_USE_CPP20_OPERATORS)
159 template <
typename K,
typename V,
typename H>
164 template <
typename K,
typename V,
typename H>
167 using type =
const K&;
170 template <
typename K,
typename V,
typename H>
180template <
typename K,
typename V,
typename H>
183 m_pEntries =
nullptr;
184 m_pEntryFlags =
nullptr;
187 m_pAllocator = pAllocator;
190template <
typename K,
typename V,
typename H>
193 m_pEntries =
nullptr;
194 m_pEntryFlags =
nullptr;
197 m_pAllocator = pAllocator;
202template <
typename K,
typename V,
typename H>
205 m_pEntries =
nullptr;
206 m_pEntryFlags =
nullptr;
209 m_pAllocator = pAllocator;
211 *
this = std::move(other);
214template <
typename K,
typename V,
typename H>
218 PL_DELETE_RAW_BUFFER(m_pAllocator, m_pEntries);
219 PL_DELETE_RAW_BUFFER(m_pAllocator, m_pEntryFlags);
223template <
typename K,
typename V,
typename H>
229 plUInt32 uiCopied = 0;
230 for (plUInt32 i = 0; uiCopied < rhs.
GetCount(); ++i)
232 if (rhs.IsValidEntry(i))
234 Insert(rhs.m_pEntries[i].key, rhs.m_pEntries[i].value);
240template <
typename K,
typename V,
typename H>
246 if (m_pAllocator != rhs.m_pAllocator)
248 Reserve(rhs.m_uiCapacity);
250 plUInt32 uiCopied = 0;
251 for (plUInt32 i = 0; uiCopied < rhs.
GetCount(); ++i)
253 if (rhs.IsValidEntry(i))
255 Insert(std::move(rhs.m_pEntries[i].key), std::move(rhs.m_pEntries[i].value));
264 PL_DELETE_RAW_BUFFER(m_pAllocator, m_pEntries);
265 PL_DELETE_RAW_BUFFER(m_pAllocator, m_pEntryFlags);
268 m_pEntries = rhs.m_pEntries;
269 m_pEntryFlags = rhs.m_pEntryFlags;
270 m_uiCount = rhs.m_uiCount;
271 m_uiCapacity = rhs.m_uiCapacity;
274 rhs.m_pEntries =
nullptr;
275 rhs.m_pEntryFlags =
nullptr;
277 rhs.m_uiCapacity = 0;
281template <
typename K,
typename V,
typename H>
284 if (m_uiCount != rhs.m_uiCount)
287 plUInt32 uiCompared = 0;
288 for (plUInt32 i = 0; uiCompared < m_uiCount; ++i)
292 const V* pRhsValue =
nullptr;
293 if (!rhs.
TryGetValue(m_pEntries[i].key, pRhsValue))
296 if (m_pEntries[i].value != *pRhsValue)
306template <
typename K,
typename V,
typename H>
309 const plUInt64 uiCap64 =
static_cast<plUInt64
>(uiCapacity);
310 plUInt64 uiNewCapacity64 = uiCap64 + (uiCap64 * 2 / 3);
314 plUInt32 uiNewCapacity32 =
static_cast<plUInt32
>(uiNewCapacity64 & 0xFFFFFFFF);
315 PL_ASSERT_DEBUG(uiCapacity <= uiNewCapacity32,
"plHashSet/Map do not support more than 2 billion entries.");
317 if (m_uiCapacity >= uiNewCapacity32)
321 SetCapacity(uiNewCapacity32);
324template <
typename K,
typename V,
typename H>
330 PL_DELETE_RAW_BUFFER(m_pAllocator, m_pEntries);
331 PL_DELETE_RAW_BUFFER(m_pAllocator, m_pEntryFlags);
336 const plUInt32 uiNewCapacity =
plMath::PowerOfTwo_Ceil(m_uiCount + (CAPACITY_ALIGNMENT - 1)) & ~(CAPACITY_ALIGNMENT - 1);
337 if (m_uiCapacity != uiNewCapacity)
338 SetCapacity(uiNewCapacity);
342template <
typename K,
typename V,
typename H>
348template <
typename K,
typename V,
typename H>
351 return m_uiCount == 0;
354template <
typename K,
typename V,
typename H>
357 for (plUInt32 i = 0; i < m_uiCapacity; ++i)
370template <
typename K,
typename V,
typename H>
371template <
typename CompatibleKeyType,
typename CompatibleValueType>
374 Reserve(m_uiCount + 1);
376 plUInt32 uiIndex = H::Hash(key) & (m_uiCapacity - 1);
377 plUInt32 uiDeletedIndex = plInvalidIndex;
379 plUInt32 uiCounter = 0;
380 while (!IsFreeEntry(uiIndex) && uiCounter < m_uiCapacity)
382 if (IsDeletedEntry(uiIndex))
384 if (uiDeletedIndex == plInvalidIndex)
385 uiDeletedIndex = uiIndex;
387 else if (H::Equal(m_pEntries[uiIndex].key, key))
389 if (out_pOldValue !=
nullptr)
390 *out_pOldValue = std::move(m_pEntries[uiIndex].value);
392 m_pEntries[uiIndex].value = std::forward<CompatibleValueType>(value);
396 if (uiIndex == m_uiCapacity)
403 uiIndex = uiDeletedIndex != plInvalidIndex ? uiDeletedIndex : uiIndex;
409 MarkEntryAsValid(uiIndex);
415template <
typename K,
typename V,
typename H>
416template <
typename CompatibleKeyType>
419 plUInt32 uiIndex = FindEntry(key);
420 if (uiIndex != plInvalidIndex)
422 if (out_pOldValue !=
nullptr)
423 *out_pOldValue = std::move(m_pEntries[uiIndex].value);
425 RemoveInternal(uiIndex);
432template <
typename K,
typename V,
typename H>
435 PL_ASSERT_DEBUG(pos.m_pHashTable ==
this,
"Iterator from wrong hashtable");
437 plUInt32 uiIndex = pos.m_uiCurrentIndex;
439 --it.m_uiCurrentCount;
440 RemoveInternal(uiIndex);
444template <
typename K,
typename V,
typename H>
450 plUInt32 uiNextIndex = uiIndex + 1;
451 if (uiNextIndex == m_uiCapacity)
456 if (IsFreeEntry(uiNextIndex))
458 MarkEntryAsFree(uiIndex);
461 plUInt32 uiPrevIndex = (uiIndex != 0) ? uiIndex : m_uiCapacity;
464 while (IsDeletedEntry(uiPrevIndex))
466 MarkEntryAsFree(uiPrevIndex);
468 if (uiPrevIndex == 0)
469 uiPrevIndex = m_uiCapacity;
475 MarkEntryAsDeleted(uiIndex);
481template <
typename K,
typename V,
typename H>
482template <
typename CompatibleKeyType>
485 plUInt32 uiIndex = FindEntry(key);
486 if (uiIndex != plInvalidIndex)
488 PL_ASSERT_DEBUG(m_pEntries !=
nullptr,
"No entries present");
489 out_value = m_pEntries[uiIndex].value;
496template <
typename K,
typename V,
typename H>
497template <
typename CompatibleKeyType>
500 plUInt32 uiIndex = FindEntry(key);
501 if (uiIndex != plInvalidIndex)
503 out_pValue = &m_pEntries[uiIndex].value;
504 PL_ANALYSIS_ASSUME(out_pValue !=
nullptr);
511template <
typename K,
typename V,
typename H>
512template <
typename CompatibleKeyType>
515 plUInt32 uiIndex = FindEntry(key);
516 if (uiIndex != plInvalidIndex)
518 out_pValue = &m_pEntries[uiIndex].value;
519 PL_ANALYSIS_ASSUME(out_pValue !=
nullptr);
526template <
typename K,
typename V,
typename H>
527template <
typename CompatibleKeyType>
530 plUInt32 uiIndex = FindEntry(key);
531 if (uiIndex == plInvalidIndex)
533 return GetEndIterator();
537 it.m_uiCurrentIndex = uiIndex;
538 it.m_uiCurrentCount = 0;
543template <
typename K,
typename V,
typename H>
544template <
typename CompatibleKeyType>
547 plUInt32 uiIndex = FindEntry(key);
548 if (uiIndex == plInvalidIndex)
550 return GetEndIterator();
554 it.m_uiCurrentIndex = uiIndex;
555 it.m_uiCurrentCount = 0;
560template <
typename K,
typename V,
typename H>
561template <
typename CompatibleKeyType>
564 plUInt32 uiIndex = FindEntry(key);
565 return (uiIndex != plInvalidIndex) ? &m_pEntries[uiIndex].value :
nullptr;
568template <
typename K,
typename V,
typename H>
569template <
typename CompatibleKeyType>
572 plUInt32 uiIndex = FindEntry(key);
573 return (uiIndex != plInvalidIndex) ? &m_pEntries[uiIndex].value :
nullptr;
576template <
typename K,
typename V,
typename H>
579 return FindOrAdd(key,
nullptr);
582template <
typename K,
typename V,
typename H>
585 const plUInt32 uiHash = H::Hash(key);
586 plUInt32 uiIndex = FindEntry(uiHash, key);
590 *out_pExisted = uiIndex != plInvalidIndex;
593 if (uiIndex == plInvalidIndex)
595 Reserve(m_uiCount + 1);
598 uiIndex = uiHash & (m_uiCapacity - 1);
599 while (IsValidEntry(uiIndex))
602 if (uiIndex == m_uiCapacity)
609 MarkEntryAsValid(uiIndex);
613 PL_ASSERT_DEBUG(m_pEntries !=
nullptr,
"Entries should be present");
614 return m_pEntries[uiIndex].value;
617template <
typename K,
typename V,
typename H>
618template <
typename CompatibleKeyType>
621 return FindEntry(key) != plInvalidIndex;
624template <
typename K,
typename V,
typename H>
628 iterator.SetToBegin();
632template <
typename K,
typename V,
typename H>
640template <
typename K,
typename V,
typename H>
644 iterator.SetToBegin();
648template <
typename K,
typename V,
typename H>
656template <
typename K,
typename V,
typename H>
662template <
typename K,
typename V,
typename H>
665 return ((plUInt64)m_uiCapacity *
sizeof(Entry)) + (
sizeof(plUInt32) * (plUInt64)GetFlagsCapacity());
669template <
typename K,
typename V,
typename H>
672 PL_ASSERT_DEBUG(
plMath::IsPowerOf2(uiCapacity),
"uiCapacity must be a power of two to avoid modulo during lookup.");
673 const plUInt32 uiOldCapacity = m_uiCapacity;
674 m_uiCapacity = uiCapacity;
676 Entry* pOldEntries = m_pEntries;
677 plUInt32* pOldEntryFlags = m_pEntryFlags;
679 m_pEntries = PL_NEW_RAW_BUFFER(m_pAllocator, Entry, m_uiCapacity);
680 m_pEntryFlags = PL_NEW_RAW_BUFFER(m_pAllocator, plUInt32, GetFlagsCapacity());
684 for (plUInt32 i = 0; i < uiOldCapacity; ++i)
686 if (GetFlags(pOldEntryFlags, i) == VALID_ENTRY)
688 PL_VERIFY(!Insert(std::move(pOldEntries[i].key), std::move(pOldEntries[i].value)),
"Implementation error");
695 PL_DELETE_RAW_BUFFER(m_pAllocator, pOldEntries);
696 PL_DELETE_RAW_BUFFER(m_pAllocator, pOldEntryFlags);
699template <
typename K,
typename V,
typename H>
700template <
typename CompatibleKeyType>
703 return FindEntry(H::Hash(key), key);
706template <
typename K,
typename V,
typename H>
707template <
typename CompatibleKeyType>
710 if (m_uiCapacity > 0)
712 plUInt32 uiIndex = uiHash & (m_uiCapacity - 1);
713 plUInt32 uiCounter = 0;
714 while (!IsFreeEntry(uiIndex) && uiCounter < m_uiCapacity)
716 if (IsValidEntry(uiIndex) && H::Equal(m_pEntries[uiIndex].key, key))
720 if (uiIndex == m_uiCapacity)
727 return plInvalidIndex;
730#define PL_HASHTABLE_USE_BITFLAGS PL_ON
732template <
typename K,
typename V,
typename H>
735#if PL_ENABLED(PL_HASHTABLE_USE_BITFLAGS)
736 return (m_uiCapacity + 15) / 16;
742template <
typename K,
typename V,
typename H>
745#if PL_ENABLED(PL_HASHTABLE_USE_BITFLAGS)
746 const plUInt32 uiIndex = uiEntryIndex / 16;
747 const plUInt32 uiSubIndex = (uiEntryIndex & 15) * 2;
748 return (pFlags[uiIndex] >> uiSubIndex) & FLAGS_MASK;
750 return pFlags[uiEntryIndex] & FLAGS_MASK;
754template <
typename K,
typename V,
typename H>
757#if PL_ENABLED(PL_HASHTABLE_USE_BITFLAGS)
758 const plUInt32 uiIndex = uiEntryIndex / 16;
759 const plUInt32 uiSubIndex = (uiEntryIndex & 15) * 2;
760 PL_ASSERT_DEBUG(uiIndex < GetFlagsCapacity(),
"Out of bounds access");
761 m_pEntryFlags[uiIndex] &= ~(FLAGS_MASK << uiSubIndex);
762 m_pEntryFlags[uiIndex] |= (uiFlags << uiSubIndex);
764 PL_ASSERT_DEBUG(uiEntryIndex < GetFlagsCapacity(),
"Out of bounds access");
765 m_pEntryFlags[uiEntryIndex] = uiFlags;
769template <
typename K,
typename V,
typename H>
772 return GetFlags(m_pEntryFlags, uiEntryIndex) == FREE_ENTRY;
775template <
typename K,
typename V,
typename H>
778 return GetFlags(m_pEntryFlags, uiEntryIndex) == VALID_ENTRY;
781template <
typename K,
typename V,
typename H>
784 return GetFlags(m_pEntryFlags, uiEntryIndex) == DELETED_ENTRY;
787template <
typename K,
typename V,
typename H>
790 SetFlags(uiEntryIndex, FREE_ENTRY);
793template <
typename K,
typename V,
typename H>
796 SetFlags(uiEntryIndex, VALID_ENTRY);
799template <
typename K,
typename V,
typename H>
802 SetFlags(uiEntryIndex, DELETED_ENTRY);
806template <
typename K,
typename V,
typename H,
typename A>
812template <
typename K,
typename V,
typename H,
typename A>
818template <
typename K,
typename V,
typename H,
typename A>
824template <
typename K,
typename V,
typename H,
typename A>
830template <
typename K,
typename V,
typename H,
typename A>
836template <
typename K,
typename V,
typename H,
typename A>
842template <
typename K,
typename V,
typename H,
typename A>
848template <
typename K,
typename V,
typename H,
typename A>
854template <
typename K,
typename V,
typename H,
typename A>
860template <
typename K,
typename V,
typename H,
typename A>
866template <
typename KeyType,
typename ValueType,
typename Hasher>
Base class for all memory allocators.
Definition Allocator.h:23
Implementation of a hashtable which stores key/value pairs.
Definition HashTable.h:157
bool operator==(const plHashTableBase< KeyType, ValueType, Hasher > &rhs) const
Compares this table to another table.
Definition HashTable_inl.h:282
ValueType & FindOrAdd(const KeyType &key, bool *out_pExisted=nullptr)
Returns the value stored at the given key. If none exists, one is created. bExisted indicates whether...
Definition HashTable_inl.h:583
Iterator GetIterator()
Returns an Iterator to the very first element.
Definition HashTable_inl.h:625
plAllocator * GetAllocator() const
Returns the allocator that is used by this instance.
Definition HashTable_inl.h:657
bool Contains(const CompatibleKeyType &key) const
Returns if an entry with given key exists in the table.
plUInt64 GetHeapMemoryUsage() const
Returns the amount of bytes that are currently allocated on the heap.
Definition HashTable_inl.h:663
void operator=(const plHashTableBase< KeyType, ValueType, Hasher > &rhs)
Copies the data from another hashtable into this one.
plUInt32 GetCount() const
Returns the number of active entries in the table.
Definition HashTable_inl.h:343
bool TryGetValue(const CompatibleKeyType &key, ValueType &out_value) const
Returns whether an entry with the given key was found and if found writes out the corresponding value...
ValueType & operator[](const KeyType &key)
Returns the value to the given key if found or creates a new entry with the given key and a default c...
Definition HashTable_inl.h:577
const ValueType * GetValue(const CompatibleKeyType &key) const
Returns a pointer to the value of the entry with the given key if found, otherwise returns nullptr.
ConstIterator Find(const CompatibleKeyType &key) const
Searches for key, returns a plHashTableBaseConstIterator to it or an invalid iterator,...
Definition HashTable_inl.h:528
~plHashTableBase()
Destructor.
Definition HashTable_inl.h:215
Iterator GetEndIterator()
Returns an Iterator to the first element that is not part of the hash-table. Needed to support range ...
Definition HashTable_inl.h:633
void Compact()
Tries to compact the hashtable to avoid wasting memory.
Definition HashTable_inl.h:325
bool IsEmpty() const
Returns true, if the hashtable does not contain any elements.
Definition HashTable_inl.h:349
bool Insert(CompatibleKeyType &&key, CompatibleValueType &&value, ValueType *out_pOldValue=nullptr)
Inserts the key value pair or replaces value if an entry with the given key already exists.
void Clear()
Clears the table.
Definition HashTable_inl.h:355
void Reserve(plUInt32 uiCapacity)
Expands the hashtable by over-allocating the internal storage so that the load factor is lower or equ...
Definition HashTable_inl.h:307
bool Remove(const CompatibleKeyType &key, ValueType *out_pOldValue=nullptr)
Removes the entry with the given key. Returns whether an entry was removed and optionally writes out ...
void Swap(plHashTableBase< KeyType, ValueType, Hasher > &other)
Swaps this map with the other one.
Definition HashTable_inl.h:867
plHashTableBase(plAllocator *pAllocator)
Creates an empty hashtable. Does not allocate any data yet.
Definition HashTable_inl.h:181
Definition HashTable.h:333
static void CopyConstruct(Destination *pDestination, const Source ©, size_t uiCount=1)
Constructs uiCount objects of type T in a raw buffer at pDestination, by creating uiCount copies of c...
static void CopyOrMoveConstruct(Destination *pDestination, Source &&source)
This function will either move call MoveConstruct or CopyConstruct for a single element source,...
static void Construct(T *pDestination, size_t uiCount=1)
Constructs uiCount objects of type T in a raw buffer at pDestination.
static void ZeroFill(T *pDestination, size_t uiCount=1)
Zeros every byte in the provided memory buffer.
static void Destruct(T *pDestination, size_t uiCount=1)
Destructs uiCount objects of type T at pDestination.
constexpr PL_ALWAYS_INLINE T Min(T f1, T f2)
Returns the smaller value, f1 or f2.
Definition Math_inl.h:27
PL_ALWAYS_INLINE void Swap(T &ref_f1, T &ref_f2)
Swaps the values in the two variables f1 and f2.
Definition Math_inl.h:224
constexpr PL_ALWAYS_INLINE T Max(T f1, T f2)
Returns the greater value, f1 or f2.
Definition Math_inl.h:39
PL_FOUNDATION_DLL plUInt32 PowerOfTwo_Ceil(plUInt32 value)
Returns the next power-of-two that is >= value.
Definition Math.cpp:53
constexpr PL_FORCE_INLINE bool IsPowerOf2(plInt32 value)
Returns true, if there exists some x with 2^x == value.
Definition Math_inl.h:260
Const iterator.
Definition HashTable.h:13
void operator++()
Shorthand for 'Next'.
Definition HashTable_inl.h:88
void Next()
Advances the iterator to the next element in the map. The iterator will not be valid anymore,...
Definition HashTable_inl.h:62
const ValueType & Value() const
Returns the 'value' of the element that this iterator points to.
Definition HashTable_inl.h:56
const KeyType & Key() const
Returns the 'key' of the element that this iterator points to.
Definition HashTable_inl.h:50
bool IsValid() const
Checks whether this iterator points to a valid element.
Definition HashTable_inl.h:38
bool operator==(const plHashTableBaseConstIterator &rhs) const
Checks whether the two iterators point to the same element.
Definition HashTable_inl.h:44
Iterator with write access.
Definition HashTable.h:84
PL_ALWAYS_INLINE plHashTableBaseIterator(const plHashTableBaseIterator &rhs)
Creates a new iterator from another.
PL_ALWAYS_INLINE void operator=(const plHashTableBaseIterator &rhs)
Assigns one iterator no another.
Definition HashTable_inl.h:134
PL_FORCE_INLINE ValueType & Value()
Returns the 'value' of the element that this iterator points to.
Definition HashTable_inl.h:142