Added scalar operator overloads for Vector types, fixed pointer math in Store methods, and improved enumerator and memory management. Updated test setup and removed allocation leak tests. - Added left-hand scalar operator overloads for Vector2/3/4. - Fixed pointer arithmetic in Store and GetUnsafePtr methods. - Marked SetValue as readonly in UnsafeSparseSet. - Improved enumerator initialization/reset for slot map and sparse set. - Updated test projects' AssemblyVersion. - Removed TestAllocationManager and added global AllocationManager setup/teardown. - Updated TestConcurrentSlotMap for thread safety and correct cancellation. - Minor formatting and parameter improvements.
129 lines
3.7 KiB
C#
129 lines
3.7 KiB
C#
using Misaki.HighPerformance.Collections;
|
|
using System.Collections.Concurrent;
|
|
|
|
namespace Misaki.HighPerformance.Test.UnitTest.Collections;
|
|
|
|
[TestClass]
|
|
[DoNotParallelize]
|
|
public class TestConcurrentSlotMap
|
|
{
|
|
private ConcurrentSlotMap<int> _slotMap = null!;
|
|
|
|
public TestContext TestContext
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[TestInitialize]
|
|
public void Initialize()
|
|
{
|
|
_slotMap = new ConcurrentSlotMap<int>();
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestDefaultIndex()
|
|
{
|
|
Assert.IsFalse(_slotMap.Contains(0, 0));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestAddAndContains()
|
|
{
|
|
var slotIndex = _slotMap.Add(42, out var generation);
|
|
Assert.IsTrue(_slotMap.Contains(slotIndex, generation));
|
|
Assert.AreEqual(42, _slotMap.GetElementAt(slotIndex, generation));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestRemove()
|
|
{
|
|
var slotIndex = _slotMap.Add(100, out var generation);
|
|
Assert.IsTrue(_slotMap.Contains(slotIndex, generation));
|
|
var removed = _slotMap.Remove(slotIndex, generation);
|
|
Assert.IsTrue(removed);
|
|
Assert.IsFalse(_slotMap.Contains(slotIndex, generation));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestRemoveInvalid()
|
|
{
|
|
var slotIndex = _slotMap.Add(200, out var generation);
|
|
Assert.IsTrue(_slotMap.Contains(slotIndex, generation));
|
|
var removed = _slotMap.Remove(slotIndex, generation + 1); // Wrong Generation
|
|
Assert.IsFalse(removed);
|
|
Assert.IsTrue(_slotMap.Contains(slotIndex, generation));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestIndexReuse()
|
|
{
|
|
var slotIndex1 = _slotMap.Add(300, out var generation1);
|
|
_slotMap.Remove(slotIndex1, generation1);
|
|
var slotIndex2 = _slotMap.Add(400, out var generation2);
|
|
Assert.AreEqual(slotIndex1, slotIndex2);
|
|
Assert.AreNotEqual(generation1, generation2);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestConcurrentAdditions()
|
|
{
|
|
const int threadCount = 8;
|
|
const int itemsPerThread = 1000;
|
|
var tasks = new List<Task>();
|
|
|
|
for (var t = 0; t < threadCount; t++)
|
|
{
|
|
tasks.Add(Task.Run(() =>
|
|
{
|
|
for (var i = 0; i < itemsPerThread; i++)
|
|
{
|
|
_slotMap.Add(i, out _);
|
|
}
|
|
}, TestContext.CancellationToken));
|
|
}
|
|
|
|
Task.WaitAll(tasks, TestContext.CancellationToken);
|
|
Assert.AreEqual(threadCount * itemsPerThread, _slotMap.Count);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestConcurrentRandomAddRemove()
|
|
{
|
|
const int threadCount = 8;
|
|
const int operationsPerThread = 1000;
|
|
|
|
var tasks = new List<Task>();
|
|
var addedItems = new ConcurrentBag<(int slotIndex, int generation)>();
|
|
|
|
var count = 0;
|
|
|
|
for (var t = 0; t < threadCount; t++)
|
|
{
|
|
tasks.Add(Task.Run(() =>
|
|
{
|
|
for (var i = 0; i < operationsPerThread; i++)
|
|
{
|
|
if (Random.Shared.NextDouble() < 0.5)
|
|
{
|
|
var slotIndex = _slotMap.Add(i, out var generation);
|
|
addedItems.Add((slotIndex, generation));
|
|
|
|
Interlocked.Increment(ref count);
|
|
}
|
|
else if (addedItems.TryTake(out var item))
|
|
{
|
|
if (_slotMap.Remove(item.slotIndex, item.generation))
|
|
{
|
|
Interlocked.Decrement(ref count);
|
|
}
|
|
}
|
|
}
|
|
}, TestContext.CancellationToken));
|
|
}
|
|
|
|
Task.WaitAll(tasks, TestContext.CancellationToken);
|
|
|
|
Assert.AreEqual(count, _slotMap.Count);
|
|
}
|
|
} |