From 3f22819e4ec16e1790dde724122ac13b86fa8094 Mon Sep 17 00:00:00 2001 From: ikpil Date: Wed, 10 Jun 2026 01:14:12 +0900 Subject: [PATCH] refactor: add span extension helpers for fixed arrays Expose AsSpan through extension methods, add readonly AsReadOnlySpan accessors, and move mutable span creation behind internal AsSpanUnsafe helpers. Add the Unsafe package reference for netstandard2.1. --- src/Box2D.NET/B2FixedArray1.cs | 12 +++- src/Box2D.NET/B2FixedArray1024.cs | 12 +++- src/Box2D.NET/B2FixedArray11.cs | 12 +++- src/Box2D.NET/B2FixedArray12.cs | 12 +++- src/Box2D.NET/B2FixedArray16.cs | 12 +++- src/Box2D.NET/B2FixedArray2.cs | 12 +++- src/Box2D.NET/B2FixedArray24.cs | 12 +++- src/Box2D.NET/B2FixedArray3.cs | 12 +++- src/Box2D.NET/B2FixedArray32.cs | 12 +++- src/Box2D.NET/B2FixedArray4.cs | 12 +++- src/Box2D.NET/B2FixedArray64.cs | 12 +++- src/Box2D.NET/B2FixedArray7.cs | 12 +++- src/Box2D.NET/B2FixedArray8.cs | 14 ++-- src/Box2D.NET/B2FixedArrayExtensions.cs | 89 +++++++++++++++++++++++++ src/Box2D.NET/Box2D.NET.csproj | 6 +- 15 files changed, 212 insertions(+), 41 deletions(-) create mode 100644 src/Box2D.NET/B2FixedArrayExtensions.cs diff --git a/src/Box2D.NET/B2FixedArray1.cs b/src/Box2D.NET/B2FixedArray1.cs index d8ba46c1..e7de8968 100644 --- a/src/Box2D.NET/B2FixedArray1.cs +++ b/src/Box2D.NET/B2FixedArray1.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) +// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT using System; @@ -21,13 +21,19 @@ public struct B2FixedArray1 where T : unmanaged public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref AsSpan()[index]; + get => ref AsSpanUnsafe()[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() + internal Span AsSpanUnsafe() { return MemoryMarshal.CreateSpan(ref _v0000, Size); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ReadOnlySpan AsReadOnlySpan() + { + return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _v0000), Size); + } } } \ No newline at end of file diff --git a/src/Box2D.NET/B2FixedArray1024.cs b/src/Box2D.NET/B2FixedArray1024.cs index ff9f8a97..afaeaf0f 100644 --- a/src/Box2D.NET/B2FixedArray1024.cs +++ b/src/Box2D.NET/B2FixedArray1024.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) +// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT using System; @@ -1044,14 +1044,20 @@ public struct B2FixedArray1024 where T : unmanaged public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref AsSpan()[index]; + get => ref AsSpanUnsafe()[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() + internal Span AsSpanUnsafe() { return MemoryMarshal.CreateSpan(ref _v0000, Size); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ReadOnlySpan AsReadOnlySpan() + { + return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _v0000), Size); + } + } } \ No newline at end of file diff --git a/src/Box2D.NET/B2FixedArray11.cs b/src/Box2D.NET/B2FixedArray11.cs index 4d07526c..72fa8a32 100644 --- a/src/Box2D.NET/B2FixedArray11.cs +++ b/src/Box2D.NET/B2FixedArray11.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) +// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT using System; @@ -31,13 +31,19 @@ public struct B2FixedArray11 where T : unmanaged public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref AsSpan()[index]; + get => ref AsSpanUnsafe()[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() + internal Span AsSpanUnsafe() { return MemoryMarshal.CreateSpan(ref _v0000, Size); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ReadOnlySpan AsReadOnlySpan() + { + return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _v0000), Size); + } } } \ No newline at end of file diff --git a/src/Box2D.NET/B2FixedArray12.cs b/src/Box2D.NET/B2FixedArray12.cs index e2ef267c..eae31b1d 100644 --- a/src/Box2D.NET/B2FixedArray12.cs +++ b/src/Box2D.NET/B2FixedArray12.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) +// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT using System; @@ -32,14 +32,20 @@ public struct B2FixedArray12 where T : unmanaged public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref AsSpan()[index]; + get => ref AsSpanUnsafe()[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() + internal Span AsSpanUnsafe() { return MemoryMarshal.CreateSpan(ref _v0000, Size); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ReadOnlySpan AsReadOnlySpan() + { + return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _v0000), Size); + } + } } \ No newline at end of file diff --git a/src/Box2D.NET/B2FixedArray16.cs b/src/Box2D.NET/B2FixedArray16.cs index e38dde3d..66b7e6f8 100644 --- a/src/Box2D.NET/B2FixedArray16.cs +++ b/src/Box2D.NET/B2FixedArray16.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) +// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT using System; @@ -36,13 +36,19 @@ public struct B2FixedArray16 where T : unmanaged public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref AsSpan()[index]; + get => ref AsSpanUnsafe()[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() + internal Span AsSpanUnsafe() { return MemoryMarshal.CreateSpan(ref _v0000, Size); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ReadOnlySpan AsReadOnlySpan() + { + return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _v0000), Size); + } } } \ No newline at end of file diff --git a/src/Box2D.NET/B2FixedArray2.cs b/src/Box2D.NET/B2FixedArray2.cs index c83115d2..63a027ad 100644 --- a/src/Box2D.NET/B2FixedArray2.cs +++ b/src/Box2D.NET/B2FixedArray2.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) +// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT using System; @@ -28,14 +28,20 @@ public B2FixedArray2(T v0000, T v0001) public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref AsSpan()[index]; + get => ref AsSpanUnsafe()[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() + internal Span AsSpanUnsafe() { return MemoryMarshal.CreateSpan(ref _v0000, Size); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ReadOnlySpan AsReadOnlySpan() + { + return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _v0000), Size); + } + } } \ No newline at end of file diff --git a/src/Box2D.NET/B2FixedArray24.cs b/src/Box2D.NET/B2FixedArray24.cs index 1108f4da..1862293c 100644 --- a/src/Box2D.NET/B2FixedArray24.cs +++ b/src/Box2D.NET/B2FixedArray24.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) +// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT using System; @@ -44,14 +44,20 @@ public struct B2FixedArray24 where T : unmanaged public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref AsSpan()[index]; + get => ref AsSpanUnsafe()[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() + internal Span AsSpanUnsafe() { return MemoryMarshal.CreateSpan(ref _v0000, Size); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ReadOnlySpan AsReadOnlySpan() + { + return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _v0000), Size); + } + } } \ No newline at end of file diff --git a/src/Box2D.NET/B2FixedArray3.cs b/src/Box2D.NET/B2FixedArray3.cs index 46c4b0c0..a6032cc8 100644 --- a/src/Box2D.NET/B2FixedArray3.cs +++ b/src/Box2D.NET/B2FixedArray3.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) +// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT using System; @@ -23,14 +23,20 @@ public struct B2FixedArray3 where T : unmanaged public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref AsSpan()[index]; + get => ref AsSpanUnsafe()[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() + internal Span AsSpanUnsafe() { return MemoryMarshal.CreateSpan(ref _v0000, Size); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ReadOnlySpan AsReadOnlySpan() + { + return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _v0000), Size); + } + } } \ No newline at end of file diff --git a/src/Box2D.NET/B2FixedArray32.cs b/src/Box2D.NET/B2FixedArray32.cs index 97490cbb..b62b4608 100644 --- a/src/Box2D.NET/B2FixedArray32.cs +++ b/src/Box2D.NET/B2FixedArray32.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) +// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT using System; @@ -52,14 +52,20 @@ public struct B2FixedArray32 where T : unmanaged public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref AsSpan()[index]; + get => ref AsSpanUnsafe()[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() + internal Span AsSpanUnsafe() { return MemoryMarshal.CreateSpan(ref _v0000, Size); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ReadOnlySpan AsReadOnlySpan() + { + return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _v0000), Size); + } + } } \ No newline at end of file diff --git a/src/Box2D.NET/B2FixedArray4.cs b/src/Box2D.NET/B2FixedArray4.cs index 4e7b0d3e..ebf1b90c 100644 --- a/src/Box2D.NET/B2FixedArray4.cs +++ b/src/Box2D.NET/B2FixedArray4.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) +// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT using System; @@ -24,13 +24,19 @@ public struct B2FixedArray4 where T : unmanaged public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref AsSpan()[index]; + get => ref AsSpanUnsafe()[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() + internal Span AsSpanUnsafe() { return MemoryMarshal.CreateSpan(ref _v0000, Size); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ReadOnlySpan AsReadOnlySpan() + { + return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _v0000), Size); + } } } \ No newline at end of file diff --git a/src/Box2D.NET/B2FixedArray64.cs b/src/Box2D.NET/B2FixedArray64.cs index 11ced7cb..e04bf163 100644 --- a/src/Box2D.NET/B2FixedArray64.cs +++ b/src/Box2D.NET/B2FixedArray64.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) +// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT using System; @@ -84,14 +84,20 @@ public struct B2FixedArray64 where T : unmanaged public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref AsSpan()[index]; + get => ref AsSpanUnsafe()[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() + internal Span AsSpanUnsafe() { return MemoryMarshal.CreateSpan(ref _v0000, Size); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ReadOnlySpan AsReadOnlySpan() + { + return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _v0000), Size); + } + } } \ No newline at end of file diff --git a/src/Box2D.NET/B2FixedArray7.cs b/src/Box2D.NET/B2FixedArray7.cs index e3e99a00..c1a98850 100644 --- a/src/Box2D.NET/B2FixedArray7.cs +++ b/src/Box2D.NET/B2FixedArray7.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) +// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT using System; @@ -27,14 +27,20 @@ public struct B2FixedArray7 where T : unmanaged public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref AsSpan()[index]; + get => ref AsSpanUnsafe()[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() + internal Span AsSpanUnsafe() { return MemoryMarshal.CreateSpan(ref _v0000, Size); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ReadOnlySpan AsReadOnlySpan() + { + return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _v0000), Size); + } + } } \ No newline at end of file diff --git a/src/Box2D.NET/B2FixedArray8.cs b/src/Box2D.NET/B2FixedArray8.cs index 19f65a4d..154e58bf 100644 --- a/src/Box2D.NET/B2FixedArray8.cs +++ b/src/Box2D.NET/B2FixedArray8.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) +// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT using System; @@ -28,14 +28,20 @@ public struct B2FixedArray8 where T : unmanaged public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref AsSpan()[index]; + get => ref AsSpanUnsafe()[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() + internal Span AsSpanUnsafe() { return MemoryMarshal.CreateSpan(ref _v0000, Size); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ReadOnlySpan AsReadOnlySpan() + { + return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _v0000), Size); + } } -} \ No newline at end of file +} diff --git a/src/Box2D.NET/B2FixedArrayExtensions.cs b/src/Box2D.NET/B2FixedArrayExtensions.cs new file mode 100644 index 00000000..6b53502a --- /dev/null +++ b/src/Box2D.NET/B2FixedArrayExtensions.cs @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) +// SPDX-License-Identifier: MIT + +using System; +using System.Runtime.CompilerServices; + +namespace Box2D.NET +{ + public static class B2FixedArrayExtensions + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this ref B2FixedArray1 array) where T : unmanaged + { + return array.AsSpanUnsafe(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this ref B2FixedArray2 array) where T : unmanaged + { + return array.AsSpanUnsafe(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this ref B2FixedArray3 array) where T : unmanaged + { + return array.AsSpanUnsafe(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this ref B2FixedArray4 array) where T : unmanaged + { + return array.AsSpanUnsafe(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this ref B2FixedArray7 array) where T : unmanaged + { + return array.AsSpanUnsafe(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this ref B2FixedArray8 array) where T : unmanaged + { + return array.AsSpanUnsafe(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this ref B2FixedArray11 array) where T : unmanaged + { + return array.AsSpanUnsafe(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this ref B2FixedArray12 array) where T : unmanaged + { + return array.AsSpanUnsafe(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this ref B2FixedArray16 array) where T : unmanaged + { + return array.AsSpanUnsafe(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this ref B2FixedArray24 array) where T : unmanaged + { + return array.AsSpanUnsafe(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this ref B2FixedArray32 array) where T : unmanaged + { + return array.AsSpanUnsafe(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this ref B2FixedArray64 array) where T : unmanaged + { + return array.AsSpanUnsafe(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this ref B2FixedArray1024 array) where T : unmanaged + { + return array.AsSpanUnsafe(); + } + } +} diff --git a/src/Box2D.NET/Box2D.NET.csproj b/src/Box2D.NET/Box2D.NET.csproj index 22dd8a1f..77b9c436 100644 --- a/src/Box2D.NET/Box2D.NET.csproj +++ b/src/Box2D.NET/Box2D.NET.csproj @@ -1,4 +1,4 @@ - + netstandard2.1;net8.0;net9.0;net10.0 @@ -26,4 +26,8 @@ $(DefineConstants);B2_SNOOP_TOI_COUNTERS;ENABLED;B2_SNOOP_TABLE_COUNTERS;B2_SNOOP_PAIR_COUNTERS + + + +