Browse Source

Bugfix in HashTable resize

* When resize was called on a hash table that had already been allocated, the table would not be resized properly.
* Added ClearAndKeepMemory function to allow clearing a HashTable without freeing memory. This can avoid some allocations.
Jorrit Rouwe 1 year ago
parent
commit
99aee4a039
1 changed files with 35 additions and 17 deletions
  1. 35 17
      Jolt/Core/HashTable.h

+ 35 - 17
Jolt/Core/HashTable.h

@@ -179,17 +179,9 @@ private:
 		mSize = inRHS.mSize;
 	}
 
-	/// Grow the table to the next power of 2
-	void					GrowTable()
+	/// Grow the table to a new size
+	void					GrowTable(size_type inNewMaxSize)
 	{
-		// Calculate new size
-		size_type new_max_size = max<size_type>(mMaxSize << 1, 16);
-		if (new_max_size < mMaxSize)
-		{
-			JPH_ASSERT(false, "Overflow in hash table size, can't grow!");
-			return;
-		}
-
 		// Move the old table to a temporary structure
 		size_type old_max_size = mMaxSize;
 		KeyValue *old_data = mData;
@@ -201,7 +193,7 @@ private:
 		mLoadLeft = 0;
 
 		// Allocate new table
-		AllocateTable(new_max_size);
+		AllocateTable(inNewMaxSize);
 
 		// Reset all control bytes
 		memset(mControl, cBucketEmpty, mMaxSize + 15);
@@ -252,7 +244,16 @@ protected:
 			if (num_deleted * cMaxDeletedElementsDenominator > mMaxSize * cMaxDeletedElementsNumerator)
 				rehash(0);
 			else
-				GrowTable();
+			{
+				// Grow by a power of 2
+				size_type new_max_size = max<size_type>(mMaxSize << 1, 16);
+				if (new_max_size < mMaxSize)
+				{
+					JPH_ASSERT(false, "Overflow in hash table size, can't grow!");
+					return false;
+				}
+				GrowTable(new_max_size);
+			}
 		}
 
 		// Split hash into index and control value
@@ -489,11 +490,7 @@ public:
 		if (max_size <= mMaxSize)
 			return;
 
-		// Allocate buffers
-		AllocateTable(max_size);
-
-		// Reset all control bytes
-		memset(mControl, cBucketEmpty, mMaxSize + 15);
+		GrowTable(max_size);
 	}
 
 	/// Destroy the entire hash table
@@ -523,6 +520,27 @@ public:
 		}
 	}
 
+	/// Destroy the entire hash table but keeps the memory allocated
+	void					ClearAndKeepMemory()
+	{
+		// Destruct elements
+		if constexpr (!std::is_trivially_destructible<KeyValue>())
+			if (!empty())
+				for (size_type i = 0; i < mMaxSize; ++i)
+					if (mControl[i] & cBucketUsed)
+						mData[i].~KeyValue();
+		mSize = 0;
+
+		// If there are elements that are not marked cBucketEmpty, we reset them
+		size_type max_load = sGetMaxLoad(mMaxSize);
+		if (mLoadLeft != max_load)
+		{
+			// Reset all control bytes
+			memset(mControl, cBucketEmpty, mMaxSize + 15);
+			mLoadLeft = max_load;
+		}
+	}
+
 	/// Iterator to first element
 	iterator				begin()
 	{