4# define plInvalidIndex 0xFFFFFFFF
9template <
typename K,
typename H>
11 : m_pHashSet(&hashSet)
15template <
typename K,
typename H>
18 if (m_pHashSet->IsEmpty())
20 m_uiCurrentIndex = m_pHashSet->m_uiCapacity;
23 while (!m_pHashSet->IsValidEntry(m_uiCurrentIndex))
29template <
typename K,
typename H>
32 m_uiCurrentCount = m_pHashSet->m_uiCount;
33 m_uiCurrentIndex = m_pHashSet->m_uiCapacity;
36template <
typename K,
typename H>
39 return m_uiCurrentCount < m_pHashSet->m_uiCount;
42template <
typename K,
typename H>
45 return m_uiCurrentIndex == rhs.m_uiCurrentIndex && m_pHashSet->m_pEntries == rhs.m_pHashSet->m_pEntries;
48template <
typename K,
typename H>
51 return m_pHashSet->m_pEntries[m_uiCurrentIndex];
54template <
typename K,
typename H>
58 if (m_uiCurrentCount == m_pHashSet->m_uiCount)
60 m_uiCurrentIndex = m_pHashSet->m_uiCapacity;
64 for (++m_uiCurrentIndex; m_uiCurrentIndex < m_pHashSet->m_uiCapacity; ++m_uiCurrentIndex)
66 if (m_pHashSet->IsValidEntry(m_uiCurrentIndex))
74template <
typename K,
typename H>
83template <
typename K,
typename H>
87 m_pEntryFlags =
nullptr;
90 m_pAllocator = pAllocator;
93template <
typename K,
typename H>
97 m_pEntryFlags =
nullptr;
100 m_pAllocator = pAllocator;
105template <
typename K,
typename H>
108 m_pEntries =
nullptr;
109 m_pEntryFlags =
nullptr;
112 m_pAllocator = pAllocator;
114 *
this = std::move(other);
117template <
typename K,
typename H>
121 PL_DELETE_RAW_BUFFER(m_pAllocator, m_pEntries);
122 PL_DELETE_RAW_BUFFER(m_pAllocator, m_pEntryFlags);
126template <
typename K,
typename H>
132 plUInt32 uiCopied = 0;
133 for (plUInt32 i = 0; uiCopied < rhs.
GetCount(); ++i)
135 if (rhs.IsValidEntry(i))
137 Insert(rhs.m_pEntries[i]);
143template <
typename K,
typename H>
149 if (m_pAllocator != rhs.m_pAllocator)
153 plUInt32 uiCopied = 0;
154 for (plUInt32 i = 0; uiCopied < rhs.
GetCount(); ++i)
156 if (rhs.IsValidEntry(i))
158 Insert(std::move(rhs.m_pEntries[i]));
167 PL_DELETE_RAW_BUFFER(m_pAllocator, m_pEntries);
168 PL_DELETE_RAW_BUFFER(m_pAllocator, m_pEntryFlags);
171 m_pEntries = rhs.m_pEntries;
172 m_pEntryFlags = rhs.m_pEntryFlags;
173 m_uiCount = rhs.m_uiCount;
174 m_uiCapacity = rhs.m_uiCapacity;
177 rhs.m_pEntries =
nullptr;
178 rhs.m_pEntryFlags =
nullptr;
180 rhs.m_uiCapacity = 0;
184template <
typename K,
typename H>
187 if (m_uiCount != rhs.m_uiCount)
190 plUInt32 uiCompared = 0;
191 for (plUInt32 i = 0; uiCompared < m_uiCount; ++i)
205template <
typename K,
typename H>
208 const plUInt64 uiCap64 =
static_cast<plUInt64
>(uiCapacity);
209 plUInt64 uiNewCapacity64 = uiCap64 + (uiCap64 * 2 / 3);
213 plUInt32 uiNewCapacity32 =
static_cast<plUInt32
>(uiNewCapacity64 & 0xFFFFFFFF);
214 PL_ASSERT_DEBUG(uiCapacity <= uiNewCapacity32,
"plHashSet/Map do not support more than 2 billion entries.");
216 if (m_uiCapacity >= uiNewCapacity32)
220 SetCapacity(uiNewCapacity32);
223template <
typename K,
typename H>
229 PL_DELETE_RAW_BUFFER(m_pAllocator, m_pEntries);
230 PL_DELETE_RAW_BUFFER(m_pAllocator, m_pEntryFlags);
235 const plUInt32 uiNewCapacity = (m_uiCount + (CAPACITY_ALIGNMENT - 1)) & ~(CAPACITY_ALIGNMENT - 1);
236 if (m_uiCapacity != uiNewCapacity)
237 SetCapacity(uiNewCapacity);
241template <
typename K,
typename H>
247template <
typename K,
typename H>
250 return m_uiCount == 0;
253template <
typename K,
typename H>
256 for (plUInt32 i = 0; i < m_uiCapacity; ++i)
268template <
typename K,
typename H>
269template <
typename CompatibleKeyType>
274 plUInt32 uiIndex = H::Hash(key) & (m_uiCapacity - 1);
275 plUInt32 uiDeletedIndex = plInvalidIndex;
277 plUInt32 uiCounter = 0;
278 while (!IsFreeEntry(uiIndex) && uiCounter < m_uiCapacity)
280 if (IsDeletedEntry(uiIndex))
282 if (uiDeletedIndex == plInvalidIndex)
283 uiDeletedIndex = uiIndex;
285 else if (H::Equal(m_pEntries[uiIndex], key))
290 if (uiIndex == m_uiCapacity)
297 uiIndex = uiDeletedIndex != plInvalidIndex ? uiDeletedIndex : uiIndex;
302 MarkEntryAsValid(uiIndex);
308template <
typename K,
typename H>
309template <
typename CompatibleKeyType>
312 plUInt32 uiIndex = FindEntry(key);
313 if (uiIndex != plInvalidIndex)
315 RemoveInternal(uiIndex);
322template <
typename K,
typename H>
325 ConstIterator it = pos;
326 plUInt32 uiIndex = pos.m_uiCurrentIndex;
328 --it.m_uiCurrentCount;
329 RemoveInternal(uiIndex);
333template <
typename K,
typename H>
338 plUInt32 uiNextIndex = uiIndex + 1;
339 if (uiNextIndex == m_uiCapacity)
344 if (IsFreeEntry(uiNextIndex))
346 MarkEntryAsFree(uiIndex);
349 plUInt32 uiPrevIndex = (uiIndex != 0) ? uiIndex : m_uiCapacity;
352 while (IsDeletedEntry(uiPrevIndex))
354 MarkEntryAsFree(uiPrevIndex);
356 if (uiPrevIndex == 0)
357 uiPrevIndex = m_uiCapacity;
363 MarkEntryAsDeleted(uiIndex);
369template <
typename K,
typename H>
370template <
typename CompatibleKeyType>
373 return FindEntry(key) != plInvalidIndex;
376template <
typename K,
typename H>
377template <
typename CompatibleKeyType>
380 plUInt32 uiIndex = FindEntry(key);
381 if (uiIndex == plInvalidIndex)
386 ConstIterator it(*
this);
387 it.m_uiCurrentIndex = uiIndex;
388 it.m_uiCurrentCount = 0;
393template <
typename K,
typename H>
396 for (
const K& key : operand)
405template <
typename K,
typename H>
409 for (
const auto& key : operand)
415template <
typename K,
typename H>
418 for (
const auto& key : operand)
424template <
typename K,
typename H>
436template <
typename K,
typename H>
440 iterator.SetToBegin();
444template <
typename K,
typename H>
452template <
typename K,
typename H>
458template <
typename K,
typename H>
461 return ((plUInt64)m_uiCapacity *
sizeof(K)) + (
sizeof(plUInt32) * (plUInt64)GetFlagsCapacity());
465template <
typename K,
typename H>
468 PL_ASSERT_DEBUG(
plMath::IsPowerOf2(uiCapacity),
"uiCapacity must be a power of two to avoid modulo during lookup.");
469 const plUInt32 uiOldCapacity = m_uiCapacity;
470 m_uiCapacity = uiCapacity;
472 K* pOldEntries = m_pEntries;
473 plUInt32* pOldEntryFlags = m_pEntryFlags;
475 m_pEntries = PL_NEW_RAW_BUFFER(m_pAllocator, K, m_uiCapacity);
476 m_pEntryFlags = PL_NEW_RAW_BUFFER(m_pAllocator, plUInt32, GetFlagsCapacity());
480 for (plUInt32 i = 0; i < uiOldCapacity; ++i)
482 if (GetFlags(pOldEntryFlags, i) == VALID_ENTRY)
484 PL_VERIFY(!
Insert(std::move(pOldEntries[i])),
"Implementation error");
490 PL_DELETE_RAW_BUFFER(m_pAllocator, pOldEntries);
491 PL_DELETE_RAW_BUFFER(m_pAllocator, pOldEntryFlags);
494template <
typename K,
typename H>
495template <
typename CompatibleKeyType>
498 return FindEntry(H::Hash(key), key);
501template <
typename K,
typename H>
502template <
typename CompatibleKeyType>
505 if (m_uiCapacity > 0)
507 plUInt32 uiIndex = uiHash & (m_uiCapacity - 1);
508 plUInt32 uiCounter = 0;
509 while (!IsFreeEntry(uiIndex) && uiCounter < m_uiCapacity)
511 if (IsValidEntry(uiIndex) && H::Equal(m_pEntries[uiIndex], key))
515 if (uiIndex == m_uiCapacity)
522 return plInvalidIndex;
525#define PL_HASHSET_USE_BITFLAGS PL_ON
527template <
typename K,
typename H>
530#if PL_ENABLED(PL_HASHSET_USE_BITFLAGS)
531 return (m_uiCapacity + 15) / 16;
537template <
typename K,
typename H>
540#if PL_ENABLED(PL_HASHSET_USE_BITFLAGS)
541 const plUInt32 uiIndex = uiEntryIndex / 16;
542 const plUInt32 uiSubIndex = (uiEntryIndex & 15) * 2;
543 return (pFlags[uiIndex] >> uiSubIndex) & FLAGS_MASK;
545 return pFlags[uiEntryIndex] & FLAGS_MASK;
549template <
typename K,
typename H>
552#if PL_ENABLED(PL_HASHSET_USE_BITFLAGS)
553 const plUInt32 uiIndex = uiEntryIndex / 16;
554 const plUInt32 uiSubIndex = (uiEntryIndex & 15) * 2;
555 PL_ASSERT_DEBUG(uiIndex < GetFlagsCapacity(),
"Out of bounds access");
556 m_pEntryFlags[uiIndex] &= ~(FLAGS_MASK << uiSubIndex);
557 m_pEntryFlags[uiIndex] |= (uiFlags << uiSubIndex);
559 PL_ASSERT_DEBUG(uiEntryIndex < GetFlagsCapacity(),
"Out of bounds access");
560 m_pEntryFlags[uiEntryIndex] = uiFlags;
564template <
typename K,
typename H>
567 return GetFlags(m_pEntryFlags, uiEntryIndex) == FREE_ENTRY;
570template <
typename K,
typename H>
573 PL_ASSERT_DEBUG(uiEntryIndex < m_uiCapacity,
"Out of bounds access");
574 return GetFlags(m_pEntryFlags, uiEntryIndex) == VALID_ENTRY;
577template <
typename K,
typename H>
580 return GetFlags(m_pEntryFlags, uiEntryIndex) == DELETED_ENTRY;
583template <
typename K,
typename H>
586 SetFlags(uiEntryIndex, FREE_ENTRY);
589template <
typename K,
typename H>
592 SetFlags(uiEntryIndex, VALID_ENTRY);
595template <
typename K,
typename H>
598 SetFlags(uiEntryIndex, DELETED_ENTRY);
602template <
typename K,
typename H,
typename A>
608template <
typename K,
typename H,
typename A>
614template <
typename K,
typename H,
typename A>
620template <
typename K,
typename H,
typename A>
626template <
typename K,
typename H,
typename A>
628 :
plHashSetBase<K, H>(std::move(other), other.GetAllocator())
632template <
typename K,
typename H,
typename A>
634 :
plHashSetBase<K, H>(std::move(other), other.GetAllocator())
638template <
typename K,
typename H,
typename A>
644template <
typename K,
typename H,
typename A>
650template <
typename K,
typename H,
typename A>
656template <
typename K,
typename H,
typename A>
662template <
typename KeyType,
typename Hasher>
Base class for all memory allocators.
Definition Allocator.h:23
Const iterator.
Definition HashSet.h:23
bool IsValid() const
Checks whether this iterator points to a valid element.
Definition HashSet_inl.h:37
void operator++()
Shorthand for 'Next'.
Definition HashSet_inl.h:75
void Next()
Advances the iterator to the next element in the map. The iterator will not be valid anymore,...
Definition HashSet_inl.h:55
const KeyType & Key() const
Returns the 'key' of the element that this iterator points to.
Definition HashSet_inl.h:49
bool operator==(const typename plHashSetBase< KeyType, Hasher >::ConstIterator &rhs) const
Checks whether the two iterators point to the same element.
Definition HashSet_inl.h:43
Implementation of a hashset.
Definition HashSet.h:19
bool operator==(const plHashSetBase< KeyType, Hasher > &rhs) const
Compares this table to another table.
Definition HashSet_inl.h:185
bool Contains(const CompatibleKeyType &key) const
Returns if an entry with given key exists in the table.
void Clear()
Clears the table.
Definition HashSet_inl.h:254
bool Insert(CompatibleKeyType &&key)
Inserts the key. Returns whether the key was already existing.
Definition HashSet_inl.h:270
void Intersection(const plHashSetBase< KeyType, Hasher > &operand)
Makes this set the intersection of itself and the operand.
Definition HashSet_inl.h:425
plAllocator * GetAllocator() const
Returns the allocator that is used by this instance.
Definition HashSet_inl.h:453
void Compact()
Tries to compact the hashset to avoid wasting memory.
Definition HashSet_inl.h:224
void Union(const plHashSetBase< KeyType, Hasher > &operand)
Makes this set the union of itself and the operand.
Definition HashSet_inl.h:406
~plHashSetBase()
Destructor.
Definition HashSet_inl.h:118
bool IsEmpty() const
Returns true, if the hashset does not contain any elements.
Definition HashSet_inl.h:248
ConstIterator Find(const CompatibleKeyType &key) const
Searches for key, returns a ConstIterator to it or an invalid iterator, if no such key is found....
bool ContainsSet(const plHashSetBase< KeyType, Hasher > &operand) const
Checks whether all keys of the given set are in the container.
Definition HashSet_inl.h:394
plHashSetBase(plAllocator *pAllocator)
Creates an empty hashset. Does not allocate any data yet.
Definition HashSet_inl.h:84
plUInt32 GetCount() const
Returns the number of active entries in the table.
Definition HashSet_inl.h:242
void Swap(plHashSetBase< KeyType, Hasher > &other)
Swaps this map with the other one.
Definition HashSet_inl.h:663
void Reserve(plUInt32 uiCapacity)
Expands the hashset by over-allocating the internal storage so that the load factor is lower or equal...
Definition HashSet_inl.h:206
void Difference(const plHashSetBase< KeyType, Hasher > &operand)
Makes this set the difference of itself and the operand, i.e. subtracts operand.
Definition HashSet_inl.h:416
plUInt64 GetHeapMemoryUsage() const
Returns the amount of bytes that are currently allocated on the heap.
Definition HashSet_inl.h:459
ConstIterator GetIterator() const
Returns a constant Iterator to the very first element.
Definition HashSet_inl.h:437
void operator=(const plHashSetBase< KeyType, Hasher > &rhs)
Copies the data from another hashset into this one.
ConstIterator GetEndIterator() const
Returns a constant Iterator to the first element that is not part of the hashset. Needed to implement...
Definition HashSet_inl.h:445
bool Remove(const CompatibleKeyType &key)
Removes the entry with the given key. Returns if an entry was removed.
Definition HashSet_inl.h:310
static void CopyOrMoveConstruct(Destination *pDestination, Source &&source)
This function will either move call MoveConstruct or CopyConstruct for a single element source,...
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