Added GetUnsafePtr to ReadOnlyUnsafeCollection

This commit is contained in:
2026-03-17 17:27:35 +09:00
parent 8edb04263f
commit 7ffe8bc0d1
5 changed files with 23 additions and 85 deletions

View File

@@ -1,77 +0,0 @@
using System.Runtime.InteropServices;
namespace Misaki.HighPerformance.LowLevel.Buffer;
/// <summary>
/// Represents an allocated memory block with metadata.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly unsafe struct MemoryBlock
{
/// <summary>
/// Pointer to the actual allocated memory.
/// </summary>
public void* Ptr
{
get;
}
/// <summary>
/// The heap from which the memory was allocated.
/// </summary>
public void* Heap
{
get;
}
/// <summary>
/// Size of the allocated memory in bytes.
/// </summary>
public nuint Size
{
get;
}
/// <summary>
/// Alignment of the allocated memory.
/// </summary>
public nuint Alignment
{
get;
}
/// <summary>
/// Indicates whether this memory block is valid.
/// </summary>
public readonly bool IsValid => Ptr != null && Size > 0;
/// <summary>
/// Creates a new MemoryBlock with the specified parameters.
/// </summary>
/// <param name="ptr">Pointer to the allocated memory.</param>
/// <param name="size">Size of the allocated memory.</param>
/// <param name="alignment">Alignment of the allocated memory.</param>
public MemoryBlock(void* ptr, void* heap, nuint size, nuint alignment)
{
Ptr = ptr;
Heap = heap;
Size = size;
Alignment = alignment;
}
/// <summary>
/// Creates an invalid MemoryBlock.
/// </summary>
public static MemoryBlock Invalid => new(null, null, 0, 0);
public Span<T> AsSpan<T>()
where T : unmanaged
{
if (!IsValid)
{
throw new InvalidOperationException("Cannot create span from invalid MemoryBlock.");
}
return new Span<T>(Ptr, (int)(Size / SizeOf<T>()));
}
}

View File

@@ -52,6 +52,7 @@ public readonly unsafe struct ReadOnlyUnsafeCollection<T> : IEnumerable<T>
private readonly int _count; private readonly int _count;
public int Count => _count; public int Count => _count;
public int Length => _count;
public ref readonly T this[int index] public ref readonly T this[int index]
{ {
@@ -108,6 +109,7 @@ public readonly unsafe struct ReadOnlyUnsafeCollection<T> : IEnumerable<T>
/// Returns a read-only span that represents the valid elements in the underlying buffer. /// Returns a read-only span that represents the valid elements in the underlying buffer.
/// </summary> /// </summary>
/// <returns>A <see cref="ReadOnlySpan{T}"/> containing the elements of the buffer up to the current count.</returns> /// <returns>A <see cref="ReadOnlySpan{T}"/> containing the elements of the buffer up to the current count.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<T> AsSpan() public ReadOnlySpan<T> AsSpan()
{ {
return new ReadOnlySpan<T>(_buffer, _count); return new ReadOnlySpan<T>(_buffer, _count);
@@ -122,13 +124,23 @@ public readonly unsafe struct ReadOnlyUnsafeCollection<T> : IEnumerable<T>
public ReadOnlyUnsafeCollection<U> Reinterpret<U>() public ReadOnlyUnsafeCollection<U> Reinterpret<U>()
where U : unmanaged where U : unmanaged
{ {
var totalSize = (nuint)(Count * sizeof(T)); var totalSize = Count * sizeof(T);
if (totalSize % (nuint)sizeof(U) != 0) if (totalSize % sizeof(U) != 0)
{ {
throw new InvalidOperationException("Cannot reinterpret collection: size mismatch."); throw new InvalidOperationException("Cannot reinterpret collection: size mismatch.");
} }
var newCount = (int)(totalSize / (nuint)sizeof(U)); var newCount = totalSize / sizeof(U);
return new ReadOnlyUnsafeCollection<U>((U*)_buffer, newCount); return new ReadOnlyUnsafeCollection<U>((U*)_buffer, newCount);
} }
/// <summary>
/// Returns an unsafe pointer to the underlying buffer of the collection, allowing for low-level access to the memory.
/// </summary>
/// <returns>The pointer to the first element of the collection's buffer.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void* GetUnsafePtr()
{
return _buffer;
}
} }

View File

@@ -6,7 +6,6 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<PublishAot>True</PublishAot>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@@ -16,9 +15,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'" />
<ItemGroup> <ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.15.2" /> <PackageReference Include="BenchmarkDotNet" Version="0.15.8" />
<PackageReference Include="Microsoft.VisualStudio.DiagnosticsHub.BenchmarkDotNetDiagnosers" Version="18.3.36812.1" /> <PackageReference Include="Microsoft.VisualStudio.DiagnosticsHub.BenchmarkDotNetDiagnosers" Version="18.6.37110.2" />
<PackageReference Include="MSTest" Version="3.10.1" /> <PackageReference Include="MSTest" Version="4.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -4,7 +4,11 @@ using Misaki.HighPerformance.LowLevel.Utilities;
using Misaki.HighPerformance.Mathematics.SPMD; using Misaki.HighPerformance.Mathematics.SPMD;
using Misaki.HighPerformance.Test.Benchmark; using Misaki.HighPerformance.Test.Benchmark;
using Misaki.HighPerformance.Test.Jobs; using Misaki.HighPerformance.Test.Jobs;
using System.Dynamic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
BenchmarkRunner.Run<SPMDBenchmark>(); BenchmarkRunner.Run<SPMDBenchmark>();
//var hashMap = new UnsafeHashMap<int, int>(10, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent); //var hashMap = new UnsafeHashMap<int, int>(10, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);

View File

@@ -26,7 +26,7 @@ public unsafe class TestJobSystem
s_jobScheduler = new JobScheduler(3); s_jobScheduler = new JobScheduler(3);
} }
[ClassCleanup(ClassCleanupBehavior.EndOfClass)] [ClassCleanup]
public static void Cleanup() public static void Cleanup()
{ {
s_jobScheduler.Dispose(); s_jobScheduler.Dispose();