From c0580d2b460337e369ffe77d3c62ad6677376a89 Mon Sep 17 00:00:00 2001 From: Misaki Date: Fri, 3 Apr 2026 00:00:09 +0900 Subject: [PATCH] feat(core): add scalar ops and improve memory handling 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. --- .../Collections/UnsafeSlotMap.cs | 4 +- .../Collections/UnsafeSparseSet.cs | 8 +-- .../Misaki.HighPerformance.LowLevel.csproj | 2 +- ...ki.HighPerformance.Mathematics.SPMD.csproj | 2 +- .../Templates/Vector2.gen.cs | 18 +++--- .../Templates/Vector3.gen.cs | 24 ++++---- .../Templates/Vector4.gen.cs | 26 ++++---- .../Templates/Vector{T}Helper.ttinclude | 2 +- Misaki.HighPerformance.Test/Program.cs | 2 +- .../UnitTest/Buffer/TestAllocationManager.cs | 61 ------------------- .../Collections/TestConcurrentSlotMap.cs | 18 +++--- .../UnitTest/GlobalSetup.cs | 19 ++++++ 12 files changed, 73 insertions(+), 113 deletions(-) delete mode 100644 Misaki.HighPerformance.Test/UnitTest/Buffer/TestAllocationManager.cs create mode 100644 Misaki.HighPerformance.Test/UnitTest/GlobalSetup.cs diff --git a/Misaki.HighPerformance.LowLevel/Collections/UnsafeSlotMap.cs b/Misaki.HighPerformance.LowLevel/Collections/UnsafeSlotMap.cs index eefc1f6..2130c9e 100644 --- a/Misaki.HighPerformance.LowLevel/Collections/UnsafeSlotMap.cs +++ b/Misaki.HighPerformance.LowLevel/Collections/UnsafeSlotMap.cs @@ -54,7 +54,7 @@ public unsafe struct UnsafeSlotMap : IUnsafeCollection public Enumerator(UnsafeSlotMap* collection) { _collection = collection; - _currentIndex = 0; + _currentIndex = -1; } public bool MoveNext() @@ -65,7 +65,7 @@ public unsafe struct UnsafeSlotMap : IUnsafeCollection public void Reset() { - _currentIndex = 0; + _currentIndex = -1; } public void Dispose() diff --git a/Misaki.HighPerformance.LowLevel/Collections/UnsafeSparseSet.cs b/Misaki.HighPerformance.LowLevel/Collections/UnsafeSparseSet.cs index 91547d4..6ec1700 100644 --- a/Misaki.HighPerformance.LowLevel/Collections/UnsafeSparseSet.cs +++ b/Misaki.HighPerformance.LowLevel/Collections/UnsafeSparseSet.cs @@ -56,7 +56,7 @@ public unsafe struct UnsafeSparseSet : IUnsafeCollection public Enumerator(UnsafeSparseSet* collection) { _collection = collection; - _currentIndex = 0; + _currentIndex = -1; } public bool MoveNext() @@ -67,7 +67,7 @@ public unsafe struct UnsafeSparseSet : IUnsafeCollection public void Reset() { - _currentIndex = 0; + _currentIndex = -1; } public readonly void Dispose() @@ -364,7 +364,7 @@ public unsafe struct UnsafeSparseSet : IUnsafeCollection /// The Generation number to validate against the stored Generation. /// The new value. /// True if the value was updated, false if the sparse index was not found. - public bool SetValue(int sparseIndex, int generation, T value) + public readonly bool SetValue(int sparseIndex, int generation, T value) { if (!Contains(sparseIndex, generation)) { @@ -422,7 +422,7 @@ public unsafe struct UnsafeSparseSet : IUnsafeCollection [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void* GetUnsafePtr() { - return (T*)_dense.GetUnsafePtr() + 1; + return (T*)_dense.GetUnsafePtr(); } /// diff --git a/Misaki.HighPerformance.LowLevel/Misaki.HighPerformance.LowLevel.csproj b/Misaki.HighPerformance.LowLevel/Misaki.HighPerformance.LowLevel.csproj index f677728..6233797 100644 --- a/Misaki.HighPerformance.LowLevel/Misaki.HighPerformance.LowLevel.csproj +++ b/Misaki.HighPerformance.LowLevel/Misaki.HighPerformance.LowLevel.csproj @@ -7,7 +7,7 @@ true true Misaki - 1.6.7 + 1.6.8 $(AssemblyVersion) https://git.personalnas.com/Misaki/Misaki.HighPerformance.git https://git.personalnas.com/Misaki/Misaki.HighPerformance.git diff --git a/Misaki.HighPerformance.Mathematics.SPMD/Misaki.HighPerformance.Mathematics.SPMD.csproj b/Misaki.HighPerformance.Mathematics.SPMD/Misaki.HighPerformance.Mathematics.SPMD.csproj index 7ff03a4..ffcb1e8 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/Misaki.HighPerformance.Mathematics.SPMD.csproj +++ b/Misaki.HighPerformance.Mathematics.SPMD/Misaki.HighPerformance.Mathematics.SPMD.csproj @@ -7,7 +7,7 @@ true true Misaki - 1.1.0 + 1.1.1 $(AssemblyVersion) https://git.personalnas.com/Misaki/Misaki.HighPerformance.git https://git.personalnas.com/Misaki/Misaki.HighPerformance.git diff --git a/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector2.gen.cs b/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector2.gen.cs index 0a79589..28f4373 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector2.gen.cs +++ b/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector2.gen.cs @@ -83,14 +83,14 @@ public unsafe struct Vector2 : IEquatable : IEquatable operator -(TLane lane, in Vector2 vector) { @@ -175,7 +175,7 @@ public unsafe struct Vector2 : IEquatable operator *(TLane lane, in Vector2 vector) { @@ -195,7 +195,7 @@ public unsafe struct Vector2 : IEquatable operator /(in Vector2 vector, TLane lane) { @@ -205,7 +205,7 @@ public unsafe struct Vector2 : IEquatable operator /(TLane lane, in Vector2 vector) { @@ -226,7 +226,7 @@ public unsafe struct Vector2 : IEquatable operator ==(in Vector2 vector, TLane lane) { @@ -236,7 +236,7 @@ public unsafe struct Vector2 : IEquatable operator ==(TLane lane, in Vector2 vector) { @@ -276,7 +276,7 @@ public unsafe struct Vector2 : IEquatable operator >(in Vector2 left, in Vector2 right) { diff --git a/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector3.gen.cs b/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector3.gen.cs index bab1dd9..8372084 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector3.gen.cs +++ b/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector3.gen.cs @@ -76,9 +76,9 @@ public unsafe struct Vector3 : IEquatable : IEquatable : IEquatable : IEquatable operator -(TLane lane, in Vector3 vector) { @@ -191,7 +191,7 @@ public unsafe struct Vector3 : IEquatable operator *(TLane lane, in Vector3 vector) { @@ -213,7 +213,7 @@ public unsafe struct Vector3 : IEquatable operator /(in Vector3 vector, TLane lane) { @@ -224,7 +224,7 @@ public unsafe struct Vector3 : IEquatable operator /(TLane lane, in Vector3 vector) { @@ -247,7 +247,7 @@ public unsafe struct Vector3 : IEquatable operator ==(in Vector3 vector, TLane lane) { @@ -258,7 +258,7 @@ public unsafe struct Vector3 : IEquatable operator ==(TLane lane, in Vector3 vector) { @@ -302,7 +302,7 @@ public unsafe struct Vector3 : IEquatable operator >(in Vector3 left, in Vector3 right) { diff --git a/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector4.gen.cs b/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector4.gen.cs index 4f8edff..9352461 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector4.gen.cs +++ b/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector4.gen.cs @@ -81,10 +81,10 @@ public unsafe struct Vector4 : IEquatable : IEquatable : IEquatable : IEquatable operator -(TLane lane, in Vector4 vector) { @@ -207,7 +207,7 @@ public unsafe struct Vector4 : IEquatable operator *(TLane lane, in Vector4 vector) { @@ -231,7 +231,7 @@ public unsafe struct Vector4 : IEquatable operator /(in Vector4 vector, TLane lane) { @@ -243,7 +243,7 @@ public unsafe struct Vector4 : IEquatable operator /(TLane lane, in Vector4 vector) { @@ -268,7 +268,7 @@ public unsafe struct Vector4 : IEquatable operator ==(in Vector4 vector, TLane lane) { @@ -280,7 +280,7 @@ public unsafe struct Vector4 : IEquatable operator ==(TLane lane, in Vector4 vector) { @@ -328,7 +328,7 @@ public unsafe struct Vector4 : IEquatable operator >(in Vector4 left, in Vector4 right) { diff --git a/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector{T}Helper.ttinclude b/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector{T}Helper.ttinclude index 2af19af..8340bb9 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector{T}Helper.ttinclude +++ b/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector{T}Helper.ttinclude @@ -103,7 +103,7 @@ public unsafe struct {typeName} : IEquatable<{typeName}> for (var i = 0; i < width; i++) {{ -{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"pDst[i * 2 + {dim}] = {components[dim]}[i];"))} +{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"pDst[i * {dimension} + {dim}] = {components[dim]}[i];"))} }} }} diff --git a/Misaki.HighPerformance.Test/Program.cs b/Misaki.HighPerformance.Test/Program.cs index 77541d2..57bfbd8 100644 --- a/Misaki.HighPerformance.Test/Program.cs +++ b/Misaki.HighPerformance.Test/Program.cs @@ -39,4 +39,4 @@ UnsafeArray Test2(ref readonly MemoryPool(1000, pool.AllocationHandle); var arr1 = new UnsafeArray(1000, pool.AllocationHandle); return arr1; -} +} \ No newline at end of file diff --git a/Misaki.HighPerformance.Test/UnitTest/Buffer/TestAllocationManager.cs b/Misaki.HighPerformance.Test/UnitTest/Buffer/TestAllocationManager.cs deleted file mode 100644 index a4cb3c8..0000000 --- a/Misaki.HighPerformance.Test/UnitTest/Buffer/TestAllocationManager.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Misaki.HighPerformance.LowLevel; -using Misaki.HighPerformance.LowLevel.Buffer; -using Misaki.HighPerformance.LowLevel.Collections; - -namespace Misaki.HighPerformance.Test.UnitTest.Buffer; - -[TestClass] -public class TestAllocationManager -{ - [TestMethod] - public void ShouldNotLeakTest() - { - try - { - var array = new UnsafeArray(10, Allocator.Persistent); - var array2 = new UnsafeArray(10, Allocator.Persistent); - - array.Dispose(); - array2.Dispose(); - - AllocationManager.Dispose(); - } - finally - { -#if MHP_ENABLE_SAFETY_CHECKS - var leaks = AllocationManager.LiveAllocationCount; - Assert.AreEqual(0, leaks); -#endif - } - } - - [TestMethod] - public void ShouldLeakTest() - { - var array = new UnsafeArray(10, Allocator.Persistent); - var array2 = new UnsafeArray(10, Allocator.Persistent); - - try - { - AllocationManager.Dispose(); - } - catch (MemoryLeakException) - { -#if MHP_ENABLE_SAFETY_CHECKS - var leaks = AllocationManager.LiveAllocationCount; - Assert.AreEqual(2, leaks); -#endif - - return; - } - finally - { - array.Dispose(); - array2.Dispose(); - } - -#if ENABLE_SAFETY_CHECKS - Assert.Fail("Expected MemoryLeakException was not thrown."); -#endif - } -} \ No newline at end of file diff --git a/Misaki.HighPerformance.Test/UnitTest/Collections/TestConcurrentSlotMap.cs b/Misaki.HighPerformance.Test/UnitTest/Collections/TestConcurrentSlotMap.cs index a5df032..613a6f7 100644 --- a/Misaki.HighPerformance.Test/UnitTest/Collections/TestConcurrentSlotMap.cs +++ b/Misaki.HighPerformance.Test/UnitTest/Collections/TestConcurrentSlotMap.cs @@ -4,6 +4,7 @@ using System.Collections.Concurrent; namespace Misaki.HighPerformance.Test.UnitTest.Collections; [TestClass] +[DoNotParallelize] public class TestConcurrentSlotMap { private ConcurrentSlotMap _slotMap = null!; @@ -79,10 +80,10 @@ public class TestConcurrentSlotMap { _slotMap.Add(i, out _); } - }, TestContext.CancellationTokenSource.Token)); + }, TestContext.CancellationToken)); } - Task.WaitAll(tasks, TestContext.CancellationTokenSource.Token); + Task.WaitAll(tasks, TestContext.CancellationToken); Assert.AreEqual(threadCount * itemsPerThread, _slotMap.Count); } @@ -93,7 +94,6 @@ public class TestConcurrentSlotMap const int operationsPerThread = 1000; var tasks = new List(); - var rand = new Random(); var addedItems = new ConcurrentBag<(int slotIndex, int generation)>(); var count = 0; @@ -104,7 +104,7 @@ public class TestConcurrentSlotMap { for (var i = 0; i < operationsPerThread; i++) { - if (rand.NextDouble() < 0.5) + if (Random.Shared.NextDouble() < 0.5) { var slotIndex = _slotMap.Add(i, out var generation); addedItems.Add((slotIndex, generation)); @@ -113,14 +113,16 @@ public class TestConcurrentSlotMap } else if (addedItems.TryTake(out var item)) { - _slotMap.Remove(item.slotIndex, item.generation); - Interlocked.Decrement(ref count); + if (_slotMap.Remove(item.slotIndex, item.generation)) + { + Interlocked.Decrement(ref count); + } } } - }, TestContext.CancellationTokenSource.Token)); + }, TestContext.CancellationToken)); } - Task.WaitAll(tasks, TestContext.CancellationTokenSource.Token); + Task.WaitAll(tasks, TestContext.CancellationToken); Assert.AreEqual(count, _slotMap.Count); } diff --git a/Misaki.HighPerformance.Test/UnitTest/GlobalSetup.cs b/Misaki.HighPerformance.Test/UnitTest/GlobalSetup.cs new file mode 100644 index 0000000..514d8e4 --- /dev/null +++ b/Misaki.HighPerformance.Test/UnitTest/GlobalSetup.cs @@ -0,0 +1,19 @@ +using Misaki.HighPerformance.LowLevel.Buffer; + +namespace Misaki.HighPerformance.Test.UnitTest; + +[TestClass] +public static class GlobalSetup +{ + [GlobalTestInitialize] + public static void GlobalInitialize(TestContext ctx) + { + AllocationManager.Initialize(AllocationManagerInitOpts.Default); + } + + [GlobalTestCleanup] + public static void GlobalCleanup(TestContext ctx) + { + AllocationManager.Dispose(); + } +}