63 static_assert(InitialBuckets > 0,
"At least one initial bucket must be available.");
66 bucket() : key(), value(), set(
false), parent(
nullptr) {}
78 struct bucket* node =
this;
79 while (++node < (parent->m_Buckets + parent->m_nBuckets)) {
88 struct bucket* previous() {
93 struct bucket* node =
this;
94 while (--node >= parent->m_Buckets) {
105 typedef ::Iterator<V, struct bucket>
Iterator;
111 HashTable() : m_Buckets(nullptr), m_Default(), m_nBuckets(0), m_nItems(0), m_nMask(0) {}
117 m_Default = customDefault;
139 if ((!m_Buckets) || (!m_nItems)) {
143 const uint32_t khash = k.hash();
144 size_t hash = khash & m_nMask;
146 const bucket* b = &m_Buckets[hash];
152 b = findNextSet(hash, k, khash);
169 HashTableError::Error err;
170 const struct bucket* b = doLookup<K>(k, err);
172 return LookupResult::withValue(b->value);
174 return LookupResult::withError(err);
178 template <
typename SK = SiblingK>
179 typename pedigree_std::enable_if<!pedigree_std::is_same<K, SK>::value, LookupResult>::type
lookup(
181 HashTableError::Error err;
182 const struct bucket* b = doLookup<SK>(k, err);
184 return LookupResult::withValue(b->value);
186 return LookupResult::withError(err);
200 for (
size_t i = 0; i < m_nBuckets; ++i) {
201 if (!m_Buckets[i].set) {
206 Pair<K, V> result(m_Buckets[i].key, m_Buckets[i].value);
207 return PairLookupResult::withValue(result);
212 return PairLookupResult::withError(HashTableError::IterationComplete);
224 const uint32_t khash = k.hash();
225 size_t hash = khash & m_nMask;
228 bucket* b = &m_Buckets[hash];
231 if (b->key == k || findNextSet(hash, k, khash)) {
236 b = findNextEmpty(hash);
246 bool wasEmpty = m_nItems == 0;
258 HashTableError::Error err;
259 struct bucket* b =
const_cast<struct
bucket*
>(doLookup(k, err));
276 const uint32_t khash = k.hash();
277 size_t hash = khash & m_nMask;
279 bucket* b = &m_Buckets[hash];
284 bool didRemove =
false;
288 b->value = m_Default;
291 b = findNextSet(hash, k, khash);
294 b->value = m_Default;
315 if (numItems < m_nBuckets) {
326 size_t nextpow2 = 1ULL << (64 - __builtin_clzll(numItems));
327 size_t numItemsRounded = max(InitialBuckets, nextpow2);
328 if (m_nBuckets == numItemsRounded) {
334 size_t origCount = m_nBuckets;
335 m_nBuckets = numItemsRounded;
336 m_nMask = m_nBuckets - 1;
342 m_Buckets =
new bucket[m_nBuckets];
347 size_t count()
const {
352 return m_nItems ?
Iterator(getFirstSetBucket()) : end();
355 ConstIterator begin()
const {
356 return m_nItems ? ConstIterator(getFirstSetBucket()) : end();
363 ConstIterator end()
const {
364 return ConstIterator(0);
372 if (node && node->set) {
406 m_Default = other.m_Default;
407 m_nBuckets = other.m_nBuckets;
408 m_nItems = other.m_nItems;
409 m_nMask = other.m_nMask;
411 m_Buckets =
new bucket[m_nBuckets];
412 pedigree_std::copy(m_Buckets, other.m_Buckets, m_nBuckets);
417 SelfType& operator=(SelfType&& p)
noexcept(
noexcept(m_Default =
static_cast<V&&
>(p.m_Default))) {
423 m_Default =
static_cast<V&&
>(p.m_Default);
424 m_nBuckets = p.m_nBuckets;
425 m_nItems = p.m_nItems;
427 m_Buckets = p.m_Buckets;
429 p.m_Buckets =
nullptr;
436 struct bucket* getFirstSetBucket()
const {
437 struct bucket* result = m_Buckets;
438 while (result < (m_Buckets + m_nBuckets)) {
450 if (m_Buckets ==
nullptr) {
451 m_Buckets =
new bucket[InitialBuckets];
452 m_nBuckets = InitialBuckets;
453 m_nMask = InitialBuckets - 1;
458 void rehash(
size_t oldCount = 0) {
460 oldCount = m_nBuckets;
463 bucket* oldBuckets = m_Buckets;
464 m_Buckets =
new bucket[m_nBuckets];
472 for (
size_t i = 0; i < oldCount; ++i) {
473 if (oldBuckets[i].set) {
474 insert(oldBuckets[i].key, oldBuckets[i].value);
481 size_t nextIndex(
size_t i,
size_t& index,
size_t& step)
const {
482 if (QuadraticProbe) {
483 index = (index + step) & m_nMask;
492 bucket* findNextEmpty(
size_t currentHash) {
495 for (
size_t i = 0; i < m_nBuckets; ++i) {
496 size_t nextHash = (currentHash + nextIndex(i, index, step)) & m_nMask;
497 bucket* b = &m_Buckets[nextHash];
506 bucket* findNextSet(
size_t currentHash,
const K& k, uint32_t khash = 0) {
512 for (
size_t i = 0; i < m_nBuckets; ++i) {
513 size_t nextHash = (currentHash + nextIndex(i, index, step)) & m_nMask;
514 bucket* b = &m_Buckets[nextHash];
522 if (b->key.hash() == khash) {
532 template <
class FindK = K>
533 const bucket* findNextSet(
size_t currentHash,
const FindK& k, uint32_t khash = 0)
const {
539 for (
size_t i = 0; i < m_nBuckets; ++i) {
540 size_t nextHash = (currentHash + nextIndex(i, index, step)) & m_nMask;
541 const bucket* b = &m_Buckets[nextHash];
549 if (b->key.hash() == khash) {
559 template <
class LookupK>
560 const struct bucket* doLookup(
const LookupK& k, HashTableError::Error& err)
const {
561 if ((!m_Buckets) || (!m_nItems)) {
562 err = HashTableError::HashTableEmpty;
566 const uint32_t khash = k.hash();
567 size_t hash = khash & m_nMask;
569 const bucket* b = &m_Buckets[hash];
571 err = HashTableError::NotFound;
576 b = findNextSet(hash, k, khash);
578 err = HashTableError::NotFound;
588 for (
size_t i = 0; i < m_nBuckets; ++i) {
590 m_Buckets[i].parent =
this;
593 if (m_Buckets[i].set) {
597 m_Buckets[i].value = m_Default;
601 void resetParents() {
602 for (
size_t i = 0; i < m_nBuckets; ++i) {
603 m_Buckets[i].parent =
this;