Skip to content

Commit ae73086

Browse files
committed
fix bug with a poisoned hash_map
1 parent b2fcffb commit ae73086

File tree

1 file changed

+14
-3
lines changed

1 file changed

+14
-3
lines changed

ExcaliburHash/ExcaliburHash.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -763,9 +763,20 @@ template <typename TKey, typename TValue, unsigned kNumInlineItems = 1, typename
763763
EXLBR_ASSERT(!TKeyInfo::isEqual(TKeyInfo::getEmpty(), TKeyInfo::getTombstone()));
764764
uint32_t numBuckets = m_numBuckets;
765765

766-
// numBucketsThreshold = (numBuckets * 1/2) (but implemented using bit shifts)
767-
const uint32_t numBucketsThreshold = shr(numBuckets, 1u) + 1;
768-
if (EXLBR_LIKELY(m_numElements < numBucketsThreshold))
766+
// Growth threshold calculation: 75% load factor
767+
// shr(numBuckets, 1u) = numBuckets/2 (50%)
768+
// shr(numBuckets, 2u) = numBuckets/4 (25%)
769+
// Total: 50% + 25% + 1 = 75% + 1
770+
//
771+
// We count both live elements AND tombstones because:
772+
// 1. Tombstones occupy slots and increase probe distances during lookup
773+
// 2. A table full of tombstones can cause infinite loops in linear probing
774+
// 3. Tombstones degrade performance almost as much as live elements
775+
//
776+
// Growing at 75% occupancy (elements + tombstones) maintains good performance
777+
// while preventing pathological cases where tombstones dominate the table.
778+
const uint32_t numBucketsThreshold = shr(numBuckets, 1u) + shr(numBuckets, 2u) + 1;
779+
if (EXLBR_LIKELY(m_numElements + m_numTombstones < numBucketsThreshold))
769780
{
770781
return emplaceToExisting(numBuckets, std::forward<TK>(key), std::forward<Args>(args)...);
771782
}

0 commit comments

Comments
 (0)