Skip to content

Commit 1e622fb

Browse files
committed
Use ref fields in ReadOnlySpan2D<T>
1 parent e98a494 commit 1e622fb

File tree

2 files changed

+96
-20
lines changed

2 files changed

+96
-20
lines changed

src/CommunityToolkit.HighPerformance/Memory/ReadOnlySpan2D{T}.Enumerator.cs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
#if !NET7_0_OR_GREATER
56
using System;
7+
#endif
68
using System.Runtime.CompilerServices;
79
using CommunityToolkit.HighPerformance.Enumerables;
810
using CommunityToolkit.HighPerformance.Memory.Internals;
9-
#if NETSTANDARD2_1_OR_GREATER
11+
#if NETSTANDARD2_1_OR_GREATER && !NET7_0_OR_GREATER
1012
using System.Runtime.InteropServices;
11-
#else
13+
#elif NETSTANDARD2_0
1214
using RuntimeHelpers = CommunityToolkit.HighPerformance.Helpers.Internals.RuntimeHelpers;
1315
#endif
1416

@@ -84,7 +86,17 @@ public ReadOnlyRefEnumerable<T> GetColumn(int column)
8486
/// </summary>
8587
public ref struct Enumerator
8688
{
87-
#if NETSTANDARD2_1_OR_GREATER
89+
#if NET7_0_OR_GREATER
90+
/// <summary>
91+
/// The <typeparamref name="T"/> reference for the <see cref="ReadOnlySpan2D{T}"/> instance.
92+
/// </summary>
93+
private readonly ref readonly T reference;
94+
95+
/// <summary>
96+
/// The height of the specified 2D region.
97+
/// </summary>
98+
private readonly int height;
99+
#elif NETSTANDARD2_1_OR_GREATER
88100
/// <summary>
89101
/// The <see cref="ReadOnlySpan{T}"/> instance pointing to the first item in the target memory area.
90102
/// </summary>
@@ -133,7 +145,10 @@ public ref struct Enumerator
133145
/// <param name="span">The target <see cref="ReadOnlySpan2D{T}"/> instance to enumerate.</param>
134146
internal Enumerator(ReadOnlySpan2D<T> span)
135147
{
136-
#if NETSTANDARD2_1_OR_GREATER
148+
#if NET7_0_OR_GREATER
149+
this.reference = ref span.reference;
150+
this.height = span.height;
151+
#elif NETSTANDARD2_1_OR_GREATER
137152
this.span = span.span;
138153
#else
139154
this.instance = span.instance;
@@ -167,7 +182,9 @@ public bool MoveNext()
167182
// another row available: wrap to a new line and continue.
168183
this.x = 0;
169184

170-
#if NETSTANDARD2_1_OR_GREATER
185+
#if NET7_0_OR_GREATER
186+
return ++this.y < this.height;
187+
#elif NETSTANDARD2_1_OR_GREATER
171188
return ++this.y < this.span.Length;
172189
#else
173190
return ++this.y < this.height;
@@ -182,7 +199,9 @@ public readonly ref readonly T Current
182199
[MethodImpl(MethodImplOptions.AggressiveInlining)]
183200
get
184201
{
185-
#if NETSTANDARD2_1_OR_GREATER
202+
#if NET7_0_OR_GREATER
203+
ref T r0 = ref Unsafe.AsRef(in this.reference);
204+
#elif NETSTANDARD2_1_OR_GREATER
186205
ref T r0 = ref MemoryMarshal.GetReference(this.span);
187206
#else
188207
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);

src/CommunityToolkit.HighPerformance/Memory/ReadOnlySpan2D{T}.cs

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,17 @@ namespace CommunityToolkit.HighPerformance;
2828
[DebuggerDisplay("{ToString(),raw}")]
2929
public readonly ref partial struct ReadOnlySpan2D<T>
3030
{
31-
#if NETSTANDARD2_1_OR_GREATER
31+
#if NET7_0_OR_GREATER
32+
/// <summary>
33+
/// The <typeparamref name="T"/> reference for the <see cref="ReadOnlySpan2D{T}"/> instance.
34+
/// </summary>
35+
private readonly ref readonly T reference;
36+
37+
/// <summary>
38+
/// The height of the specified 2D region.
39+
/// </summary>
40+
private readonly int height;
41+
#elif NETSTANDARD2_1_OR_GREATER
3242
/// <summary>
3343
/// The <see cref="ReadOnlySpan{T}"/> instance pointing to the first item in the target memory area.
3444
/// </summary>
@@ -71,7 +81,12 @@ public readonly ref partial struct ReadOnlySpan2D<T>
7181
[MethodImpl(MethodImplOptions.AggressiveInlining)]
7282
internal ReadOnlySpan2D(in T value, int height, int width, int pitch)
7383
{
84+
#if NET7_0_OR_GREATER
85+
this.reference = ref value;
86+
this.height = height;
87+
#else
7488
this.span = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(value), height);
89+
#endif
7590
this.width = width;
7691
this.stride = width + pitch;
7792
}
@@ -109,7 +124,10 @@ public unsafe ReadOnlySpan2D(void* pointer, int height, int width, int pitch)
109124

110125
OverflowHelper.EnsureIsInNativeIntRange(height, width, pitch);
111126

112-
#if NETSTANDARD2_1_OR_GREATER
127+
#if NET7_0_OR_GREATER
128+
this.reference = ref Unsafe.AsRef<T>(pointer);
129+
this.height = height;
130+
#elif NETSTANDARD2_1_OR_GREATER
113131
this.span = new ReadOnlySpan<T>(pointer, height);
114132
#else
115133
this.instance = null;
@@ -206,7 +224,10 @@ public ReadOnlySpan2D(T[] array, int offset, int height, int width, int pitch)
206224
ThrowHelper.ThrowArgumentException();
207225
}
208226

209-
#if NETSTANDARD2_1_OR_GREATER
227+
#if NET7_0_OR_GREATER
228+
this.reference = ref array.DangerousGetReferenceAt(offset);
229+
this.height = height;
230+
#elif NETSTANDARD2_1_OR_GREATER
210231
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReferenceAt(offset), height);
211232
#else
212233
this.instance = array;
@@ -230,7 +251,10 @@ public ReadOnlySpan2D(T[,]? array)
230251
return;
231252
}
232253

233-
#if NETSTANDARD2_1_OR_GREATER
254+
#if NET7_0_OR_GREATER
255+
this.reference = ref array.DangerousGetReference();
256+
this.height = array.GetLength(0);
257+
#elif NETSTANDARD2_1_OR_GREATER
234258
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReference(), array.GetLength(0));
235259
#else
236260
this.instance = array;
@@ -289,7 +313,10 @@ public ReadOnlySpan2D(T[,]? array, int row, int column, int height, int width)
289313
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
290314
}
291315

292-
#if NETSTANDARD2_1_OR_GREATER
316+
#if NET7_0_OR_GREATER
317+
this.reference = ref array.DangerousGetReferenceAt(row, column);
318+
this.height = height;
319+
#elif NETSTANDARD2_1_OR_GREATER
293320
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReferenceAt(row, column), height);
294321
#else
295322
this.instance = array;
@@ -313,7 +340,10 @@ public ReadOnlySpan2D(T[,,] array, int depth)
313340
ThrowHelper.ThrowArgumentOutOfRangeExceptionForDepth();
314341
}
315342

316-
#if NETSTANDARD2_1_OR_GREATER
343+
#if NET7_0_OR_GREATER
344+
this.reference = ref array.DangerousGetReferenceAt(depth, 0, 0);
345+
this.height = array.GetLength(1);
346+
#elif NETSTANDARD2_1_OR_GREATER
317347
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReferenceAt(depth, 0, 0), array.GetLength(1));
318348
#else
319349
this.instance = array;
@@ -363,7 +393,10 @@ public ReadOnlySpan2D(T[,,] array, int depth, int row, int column, int height, i
363393
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
364394
}
365395

366-
#if NETSTANDARD2_1_OR_GREATER
396+
#if NET7_0_OR_GREATER
397+
this.reference = ref array.DangerousGetReferenceAt(depth, row, column);
398+
this.height = height;
399+
#elif NETSTANDARD2_1_OR_GREATER
367400
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReferenceAt(depth, row, column), height);
368401
#else
369402
this.instance = array;
@@ -441,7 +474,12 @@ internal ReadOnlySpan2D(ReadOnlySpan<T> span, int offset, int height, int width,
441474
ThrowHelper.ThrowArgumentException();
442475
}
443476

477+
#if NET7_0_OR_GREATER
478+
this.reference = ref span.DangerousGetReferenceAt(offset);
479+
this.height = height;
480+
#else
444481
this.span = MemoryMarshal.CreateSpan(ref span.DangerousGetReferenceAt(offset), height);
482+
#endif
445483
this.width = width;
446484
this.stride = width + pitch;
447485
}
@@ -509,7 +547,9 @@ public int Height
509547
[MethodImpl(MethodImplOptions.AggressiveInlining)]
510548
get
511549
{
512-
#if NETSTANDARD2_1_OR_GREATER
550+
#if NET7_0_OR_GREATER
551+
return this.height;
552+
#elif NETSTANDARD2_1_OR_GREATER
513553
return this.span.Length;
514554
#else
515555
return this.height;
@@ -746,7 +786,9 @@ public unsafe ref T GetPinnableReference()
746786

747787
if (Length != 0)
748788
{
749-
#if NETSTANDARD2_1_OR_GREATER
789+
#if NET7_0_OR_GREATER
790+
r0 = ref Unsafe.AsRef(in this.reference);
791+
#elif NETSTANDARD2_1_OR_GREATER
750792
r0 = ref MemoryMarshal.GetReference(this.span);
751793
#else
752794
r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
@@ -763,7 +805,9 @@ public unsafe ref T GetPinnableReference()
763805
[MethodImpl(MethodImplOptions.AggressiveInlining)]
764806
public ref T DangerousGetReference()
765807
{
766-
#if NETSTANDARD2_1_OR_GREATER
808+
#if NET7_0_OR_GREATER
809+
return ref Unsafe.AsRef(in this.reference);
810+
#elif NETSTANDARD2_1_OR_GREATER
767811
return ref MemoryMarshal.GetReference(this.span);
768812
#else
769813
return ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
@@ -779,7 +823,9 @@ public ref T DangerousGetReference()
779823
[MethodImpl(MethodImplOptions.AggressiveInlining)]
780824
public ref T DangerousGetReferenceAt(int i, int j)
781825
{
782-
#if NETSTANDARD2_1_OR_GREATER
826+
#if NET7_0_OR_GREATER
827+
ref T r0 = ref Unsafe.AsRef(in this.reference);
828+
#elif NETSTANDARD2_1_OR_GREATER
783829
ref T r0 = ref MemoryMarshal.GetReference(this.span);
784830
#else
785831
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
@@ -826,7 +872,11 @@ public unsafe ReadOnlySpan2D<T> Slice(int row, int column, int height, int width
826872
nint shift = ((nint)(uint)this.stride * (nint)(uint)row) + (nint)(uint)column;
827873
int pitch = this.stride - width;
828874

829-
#if NETSTANDARD2_1_OR_GREATER
875+
#if NET7_0_OR_GREATER
876+
ref T r0 = ref Unsafe.Add(ref Unsafe.AsRef(in this.reference), shift);
877+
878+
return new(in r0, height, width, pitch);
879+
#elif NETSTANDARD2_1_OR_GREATER
830880
ref T r0 = ref this.span.DangerousGetReferenceAt(shift);
831881

832882
return new(in r0, height, width, pitch);
@@ -868,7 +918,11 @@ public bool TryGetSpan(out ReadOnlySpan<T> span)
868918
if (this.stride == this.width &&
869919
Length <= int.MaxValue)
870920
{
871-
#if NETSTANDARD2_1_OR_GREATER
921+
#if NET7_0_OR_GREATER
922+
span = MemoryMarshal.CreateSpan(ref Unsafe.AsRef(in this.reference), (int)Length);
923+
924+
return true;
925+
#elif NETSTANDARD2_1_OR_GREATER
872926
span = MemoryMarshal.CreateReadOnlySpan(ref MemoryMarshal.GetReference(this.span), (int)Length);
873927

874928
return true;
@@ -979,7 +1033,10 @@ public override string ToString()
9791033
public static bool operator ==(ReadOnlySpan2D<T> left, ReadOnlySpan2D<T> right)
9801034
{
9811035
return
982-
#if NETSTANDARD2_1_OR_GREATER
1036+
#if NET7_0_OR_GREATER
1037+
Unsafe.AreSame(ref Unsafe.AsRef(in left.reference), ref Unsafe.AsRef(in right.reference)) &&
1038+
left.height == right.height &&
1039+
#elif NETSTANDARD2_1_OR_GREATER
9831040
left.span == right.span &&
9841041
#else
9851042
ReferenceEquals(

0 commit comments

Comments
 (0)