From bc8b2c0aaabc40783f11097338e7244a61167a21 Mon Sep 17 00:00:00 2001 From: Misaki Date: Tue, 11 Nov 2025 17:38:30 +0900 Subject: [PATCH] Fixed bug that SlotMap.Contains does not return a correct value. --- .../Collections/UnsafeSlotMap.cs | 4 +- .../Misaki.HighPerformance.LowLevel.csproj | 2 +- .../UnitTest/Collections/TestUnsafeSlotMap.cs | 112 ++++++++++++++++++ 3 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 Misaki.HighPerformance.Test/UnitTest/Collections/TestUnsafeSlotMap.cs diff --git a/Misaki.HighPerformance.LowLevel/Collections/UnsafeSlotMap.cs b/Misaki.HighPerformance.LowLevel/Collections/UnsafeSlotMap.cs index 4ab075a..8a52f60 100644 --- a/Misaki.HighPerformance.LowLevel/Collections/UnsafeSlotMap.cs +++ b/Misaki.HighPerformance.LowLevel/Collections/UnsafeSlotMap.cs @@ -96,7 +96,9 @@ public unsafe struct UnsafeSlotMap : IUnsafeCollection _data = new UnsafeArray(capacity, ref handle, allocationOption); _freeSlots = new UnsafeQueue(capacity, ref handle, allocationOption); + _count = 0; + _capacity = capacity; } /// @@ -179,7 +181,7 @@ public unsafe struct UnsafeSlotMap : IUnsafeCollection /// The zero-based index of the slot to check. Must be greater than or equal to 0 and less than the current capacity. /// The generation value to compare against the slot's generation. /// true if the slot at the specified index is valid and its generation matches the specified value; otherwise, false. - public bool Contain(int slotIndex, int generation) + public bool Contains(int slotIndex, int generation) { if (slotIndex < 0 || slotIndex >= Volatile.Read(ref _capacity)) { diff --git a/Misaki.HighPerformance.LowLevel/Misaki.HighPerformance.LowLevel.csproj b/Misaki.HighPerformance.LowLevel/Misaki.HighPerformance.LowLevel.csproj index 0135835..4841398 100644 --- a/Misaki.HighPerformance.LowLevel/Misaki.HighPerformance.LowLevel.csproj +++ b/Misaki.HighPerformance.LowLevel/Misaki.HighPerformance.LowLevel.csproj @@ -6,7 +6,7 @@ enable True Misaki - 1.1.0 + 1.1.1 $(AssemblyVersion) True https://git.personalnas.com/Misaki/Misaki.HighPerformance.git diff --git a/Misaki.HighPerformance.Test/UnitTest/Collections/TestUnsafeSlotMap.cs b/Misaki.HighPerformance.Test/UnitTest/Collections/TestUnsafeSlotMap.cs new file mode 100644 index 0000000..626c73e --- /dev/null +++ b/Misaki.HighPerformance.Test/UnitTest/Collections/TestUnsafeSlotMap.cs @@ -0,0 +1,112 @@ +using Misaki.HighPerformance.LowLevel.Buffer; +using Misaki.HighPerformance.LowLevel.Collections; + +namespace Misaki.HighPerformance.Test.UnitTest.Collections; + +[TestClass] +public class TestUnsafeSlotMap +{ + private UnsafeSlotMap _slotMap; + + [TestInitialize] + public void Initialize() + { + _slotMap = new UnsafeSlotMap(16, Allocator.Persistent, AllocationOption.Clear); + } + + [TestCleanup] + public void Cleanup() + { + _slotMap.Dispose(); + } + + [TestMethod] + public void Add() + { + var id = _slotMap.Add(10, out var gen); + Assert.IsTrue(_slotMap.Contains(id, gen)); + } + + [TestMethod] + public void Remove() + { + var id = _slotMap.Add(20, out var gen); + Assert.IsTrue(_slotMap.Contains(id, gen)); + + _slotMap.Remove(id, gen); + Assert.IsFalse(_slotMap.Contains(id, gen)); + } + + [TestMethod] + public void IndexReuse() + { + var id = _slotMap.Add(20, out var gen); + Assert.IsTrue(_slotMap.Contains(id, gen)); + + _slotMap.Remove(id, gen); + Assert.IsFalse(_slotMap.Contains(id, gen)); + + var newId = _slotMap.Add(30, out var newGen); + Assert.AreEqual(id, newId); + Assert.AreNotEqual(gen, newGen); + } + + [TestMethod] + public unsafe void Resize() + { + const int count = 20; + + var indices = stackalloc int[count]; + var generations = stackalloc int[count]; + + for (var i = 0; i < count; i++) + { + indices[i] = _slotMap.Add(i, out generations[i]); + } + + Assert.AreEqual(count, _slotMap.Count); + for (var i = 0; i < count; i++) + { + Assert.IsTrue(_slotMap.Contains(indices[i], generations[i])); + } + } + + [TestMethod] + public void Clear() + { + var id1 = _slotMap.Add(10, out var gen1); + var id2 = _slotMap.Add(20, out var gen2); + + Assert.AreEqual(2, _slotMap.Count); + + _slotMap.Clear(); + + Assert.AreEqual(0, _slotMap.Count); + Assert.IsFalse(_slotMap.Contains(id1, gen1)); + Assert.IsFalse(_slotMap.Contains(id2, gen2)); + } + + [TestMethod] + public unsafe void Enumerate() + { + const int count = 3; + + var values = stackalloc int[count] { 10, 20, 30 }; + var ids = stackalloc int[count]; + var gens = stackalloc int[count]; + + for (var i = 0; i < count; i++) + { + ids[i] = _slotMap.Add(values[i], out gens[i]); + } + + var index = 0; + foreach (var value in _slotMap) + { + Assert.AreEqual(values[index], value); + index++; + } + + Assert.AreEqual(count, index); + } +} \ No newline at end of file