20 #ifndef KERNEL_UTILITIES_HASHTABLE_H 21 #define KERNEL_UTILITIES_HASHTABLE_H 23 #include "pedigree/kernel/processor/types.h" 24 #include "pedigree/kernel/utilities/Iterator.h" 25 #include "pedigree/kernel/utilities/Pair.h" 26 #include "pedigree/kernel/utilities/Result.h" 27 #include "pedigree/kernel/utilities/utility.h" 64 class K,
class V,
class SiblingK = K,
size_t InitialBuckets = 4,
65 bool QuadraticProbe =
true,
size_t GrowthFactor = 2>
70 K, V, SiblingK, InitialBuckets, QuadraticProbe, GrowthFactor>
74 InitialBuckets > 0,
"At least one initial bucket must be available.");
78 bucket() : key(), value(),
set(
false), parent(
nullptr)
94 struct bucket *node =
this;
95 while (++node < (parent->m_Buckets + parent->m_nBuckets))
113 struct bucket *node =
this;
114 while (--node >= parent->m_Buckets)
127 typedef ::Iterator<V, struct bucket>
Iterator;
134 : m_Buckets(
nullptr), m_Default(), m_nBuckets(0), m_nItems(0),
144 m_Default = customDefault;
167 if ((!m_Buckets) || (!m_nItems))
172 const uint32_t khash = k.hash();
173 size_t hash = khash & m_nMask;
175 const bucket *b = &m_Buckets[hash];
183 b = findNextSet(hash, k, khash);
202 HashTableError::Error err;
203 const struct bucket *b = doLookup<K>(k, err);
206 return LookupResult::withValue(b->value);
210 return LookupResult::withError(err);
214 template <
typename SK = SiblingK>
215 typename pedigree_std::enable_if<
216 !pedigree_std::is_same<K, SK>::value, LookupResult>::type
217 lookup(
const SK &k)
const 219 HashTableError::Error err;
220 const struct bucket *b = doLookup<SK>(k, err);
223 return LookupResult::withValue(b->value);
227 return LookupResult::withError(err);
243 for (
size_t i = 0; i < m_nBuckets; ++i)
245 if (!m_Buckets[i].
set)
252 Pair<K, V> result(m_Buckets[i].key, m_Buckets[i].value);
253 return PairLookupResult::withValue(result);
258 return PairLookupResult::withError(HashTableError::IterationComplete);
269 reserve(m_nItems + 1);
271 const uint32_t khash = k.hash();
272 size_t hash = khash & m_nMask;
275 bucket *b = &m_Buckets[hash];
285 b = findNextEmpty(hash);
296 bool wasEmpty = m_nItems == 0;
309 HashTableError::Error err;
310 struct bucket *b =
const_cast<struct bucket *
>(doLookup(k, err));
323 void remove(
const K &k)
330 const uint32_t khash = k.hash();
331 size_t hash = khash & m_nMask;
333 bucket *b = &m_Buckets[hash];
339 bool didRemove =
false;
344 b->value = m_Default;
349 b = findNextSet(hash, k, khash);
353 b->value = m_Default;
377 if (numItems < m_nBuckets)
390 size_t nextpow2 = 1ULL << (64 - __builtin_clzll(numItems));
391 size_t numItemsRounded = max(InitialBuckets, nextpow2);
392 if (m_nBuckets == numItemsRounded)
399 size_t origCount = m_nBuckets;
400 m_nBuckets = numItemsRounded;
401 m_nMask = m_nBuckets - 1;
410 m_Buckets =
new bucket[m_nBuckets];
422 return m_nItems ? Iterator(getFirstSetBucket()) : end();
425 ConstIterator begin()
const 427 return m_nItems ? ConstIterator(getFirstSetBucket()) : end();
435 ConstIterator end()
const 437 return ConstIterator(0);
446 if (node && node->set)
468 HashTable(
const SelfType &other) =
delete;
469 SelfType &operator=(
const SelfType &p) =
delete;
481 m_Default = other.m_Default;
482 m_nBuckets = other.m_nBuckets;
483 m_nItems = other.m_nItems;
484 m_nMask = other.m_nMask;
485 m_Buckets =
new bucket[m_nBuckets];
486 pedigree_std::copy(m_Buckets, other.m_Buckets, m_nBuckets);
490 SelfType &operator=(SelfType &&p)
494 m_Default = pedigree_std::move(p.m_Default);
495 m_nBuckets = pedigree_std::move(p.m_nBuckets);
496 m_nItems = pedigree_std::move(p.m_nItems);
497 m_nMask = pedigree_std::move(p.m_nMask);
498 m_Buckets = pedigree_std::move(p.m_Buckets);
500 p.m_Buckets =
nullptr;
507 struct bucket *getFirstSetBucket()
const 509 struct bucket *result = m_Buckets;
510 while (result < (m_Buckets + m_nBuckets))
525 if (m_Buckets ==
nullptr)
527 m_Buckets =
new bucket[InitialBuckets];
528 m_nBuckets = InitialBuckets;
529 m_nMask = InitialBuckets - 1;
534 void rehash(
size_t oldCount = 0)
538 oldCount = m_nBuckets;
541 bucket *oldBuckets = m_Buckets;
542 m_Buckets =
new bucket[m_nBuckets];
551 for (
size_t i = 0; i < oldCount; ++i)
553 if (oldBuckets[i].
set)
555 insert(oldBuckets[i].key, oldBuckets[i].value);
562 size_t nextIndex(
size_t i,
size_t &index,
size_t &step)
const 566 index = (index + step) & m_nMask;
577 bucket *findNextEmpty(
size_t currentHash)
581 for (
size_t i = 0; i < m_nBuckets; ++i)
584 (currentHash + nextIndex(i, index, step)) & m_nMask;
585 bucket *b = &m_Buckets[nextHash];
595 bucket *findNextSet(
size_t currentHash,
const K &k, uint32_t khash=0)
603 for (
size_t i = 0; i < m_nBuckets; ++i)
606 (currentHash + nextIndex(i, index, step)) & m_nMask;
607 bucket *b = &m_Buckets[nextHash];
611 if (b->set && (b->key.hash() == khash))
623 template <
class FindK = K>
624 const bucket *findNextSet(
size_t currentHash,
const FindK &k, uint32_t khash=0)
const 632 for (
size_t i = 0; i < m_nBuckets; ++i)
635 (currentHash + nextIndex(i, index, step)) & m_nMask;
636 const bucket *b = &m_Buckets[nextHash];
640 if (b->set && (b->key.hash() == khash))
652 template <
class LookupK>
653 const struct bucket *
654 doLookup(
const LookupK &k, HashTableError::Error &err)
const 656 if ((!m_Buckets) || (!m_nItems))
658 err = HashTableError::HashTableEmpty;
662 const uint32_t khash = k.hash();
663 size_t hash = khash & m_nMask;
665 const bucket *b = &m_Buckets[hash];
668 err = HashTableError::NotFound;
674 b = findNextSet(hash, k, khash);
677 err = HashTableError::NotFound;
688 for (
size_t i = 0; i < m_nBuckets; ++i)
692 m_Buckets[i].parent =
this;
695 if (m_Buckets[i].
set)
700 m_Buckets[i].value = m_Default;
706 for (
size_t i = 0; i < m_nBuckets; ++i)
708 m_Buckets[i].parent =
this;
bool contains(const K &k) const
bool update(const K &k, const V &v)
Iterator erase(Iterator &at)
void setDefaults(bool reparentToo=false)
HashTable(const V &customDefault)
void reserve(size_t numItems)
bool insert(const K &k, const V &v)
An iterator applicable for many data structures.
LookupResult lookup(const K &k) const
PairLookupResult getNth(size_t n) const
void copyFrom(const SelfType &other)