diff --git a/Source/Engine/Core/Collections/HashSetBase.h b/Source/Engine/Core/Collections/HashSetBase.h index 36fcf275d..94bbd149d 100644 --- a/Source/Engine/Core/Collections/HashSetBase.h +++ b/Source/Engine/Core/Collections/HashSetBase.h @@ -409,27 +409,36 @@ protected: else { // Rebuild entire table completely + const int32 elementsCount = _elementsCount; + const int32 oldSize = _size; AllocationData oldAllocation; - AllocationUtils::MoveToEmpty(oldAllocation, _allocation, _size, _size); + AllocationUtils::MoveToEmpty(oldAllocation, _allocation, oldSize, oldSize); _allocation.Allocate(_size); BucketType* data = _allocation.Get(); - for (int32 i = 0; i < _size; ++i) + for (int32 i = 0; i < oldSize; ++i) data[i]._state = HashSetBucketState::Empty; BucketType* oldData = oldAllocation.Get(); FindPositionResult pos; - for (int32 i = 0; i < _size; ++i) + for (int32 i = 0; i < oldSize; ++i) { BucketType& oldBucket = oldData[i]; if (oldBucket.IsOccupied()) { FindPosition(oldBucket.GetKey(), pos); - ASSERT(pos.FreeSlotIndex != -1); + if (pos.FreeSlotIndex == -1) + { + // Grow and retry to handle pathological cases (eg. heavy collisions) + EnsureCapacity(_size + 1, true); + FindPosition(oldBucket.GetKey(), pos); + ASSERT(pos.FreeSlotIndex != -1); + } BucketType& bucket = _allocation.Get()[pos.FreeSlotIndex]; bucket = MoveTemp(oldBucket); } } - for (int32 i = 0; i < _size; ++i) + for (int32 i = 0; i < oldSize; ++i) oldData[i].Free(); + _elementsCount = elementsCount; } _deletedCount = 0; }