Skip to content

Commit e98a494

Browse files
committed
Use ref fields in Span2D<T>
1 parent 6fff80d commit e98a494

File tree

2 files changed

+97
-20
lines changed

2 files changed

+97
-20
lines changed

src/CommunityToolkit.HighPerformance/Memory/Span2D{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 RefEnumerable<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="Span2D{T}"/> instance.
92+
/// </summary>
93+
private readonly ref 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="Span{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="Span2D{T}"/> instance to enumerate.</param>
134146
internal Enumerator(Span2D<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 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 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/Span2D{T}.cs

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System;
66
using System.ComponentModel;
7+
using System.Data.Common;
78
using System.Diagnostics;
89
using System.Runtime.CompilerServices;
910
using System.Runtime.InteropServices;
@@ -55,7 +56,17 @@ public readonly ref partial struct Span2D<T>
5556
// discontiguous row, so that any arbitrary memory locations
5657
// can be used to internally represent a 2D span. This gives
5758
// users much more flexibility when creating spans from data.
58-
#if NETSTANDARD2_1_OR_GREATER
59+
#if NET7_0_OR_GREATER
60+
/// <summary>
61+
/// The <typeparamref name="T"/> reference for the <see cref="Span2D{T}"/> instance.
62+
/// </summary>
63+
private readonly ref T reference;
64+
65+
/// <summary>
66+
/// The height of the specified 2D region.
67+
/// </summary>
68+
private readonly int height;
69+
#elif NETSTANDARD2_1_OR_GREATER
5970
/// <summary>
6071
/// The <see cref="Span{T}"/> instance pointing to the first item in the target memory area.
6172
/// </summary>
@@ -106,7 +117,12 @@ public readonly ref partial struct Span2D<T>
106117
[MethodImpl(MethodImplOptions.AggressiveInlining)]
107118
internal Span2D(ref T value, int height, int width, int pitch)
108119
{
120+
#if NET7_0_OR_GREATER
121+
this.reference = ref value;
122+
this.height = height;
123+
#else
109124
this.span = MemoryMarshal.CreateSpan(ref value, height);
125+
#endif
110126
this.width = width;
111127
this.Stride = width + pitch;
112128
}
@@ -144,7 +160,10 @@ public unsafe Span2D(void* pointer, int height, int width, int pitch)
144160

145161
OverflowHelper.EnsureIsInNativeIntRange(height, width, pitch);
146162

147-
#if NETSTANDARD2_1_OR_GREATER
163+
#if NET7_0_OR_GREATER
164+
this.reference = ref Unsafe.AsRef<T>(pointer);
165+
this.height = height;
166+
#elif NETSTANDARD2_1_OR_GREATER
148167
this.span = new Span<T>(pointer, height);
149168
#else
150169
this.Instance = null;
@@ -245,7 +264,10 @@ public Span2D(T[] array, int offset, int height, int width, int pitch)
245264
ThrowHelper.ThrowArgumentException();
246265
}
247266

248-
#if NETSTANDARD2_1_OR_GREATER
267+
#if NET7_0_OR_GREATER
268+
this.reference = ref array.DangerousGetReferenceAt(offset);
269+
this.height = height;
270+
#elif NETSTANDARD2_1_OR_GREATER
249271
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReferenceAt(offset), height);
250272
#else
251273
this.Instance = array;
@@ -277,7 +299,10 @@ public Span2D(T[,]? array)
277299
ThrowHelper.ThrowArrayTypeMismatchException();
278300
}
279301

280-
#if NETSTANDARD2_1_OR_GREATER
302+
#if NET7_0_OR_GREATER
303+
this.reference = ref array.DangerousGetReference();
304+
this.height = array.GetLength(0);
305+
#elif NETSTANDARD2_1_OR_GREATER
281306
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReference(), array.GetLength(0));
282307
#else
283308
this.Instance = array;
@@ -344,7 +369,10 @@ public Span2D(T[,]? array, int row, int column, int height, int width)
344369
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
345370
}
346371

347-
#if NETSTANDARD2_1_OR_GREATER
372+
#if NET7_0_OR_GREATER
373+
this.reference = ref array.DangerousGetReferenceAt(row, column);
374+
this.height = height;
375+
#elif NETSTANDARD2_1_OR_GREATER
348376
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReferenceAt(row, column), height);
349377
#else
350378
this.Instance = array;
@@ -376,7 +404,10 @@ public Span2D(T[,,] array, int depth)
376404
ThrowHelper.ThrowArgumentOutOfRangeExceptionForDepth();
377405
}
378406

379-
#if NETSTANDARD2_1_OR_GREATER
407+
#if NET7_0_OR_GREATER
408+
this.reference = ref array.DangerousGetReferenceAt(depth, 0, 0);
409+
this.height = array.GetLength(1);
410+
#elif NETSTANDARD2_1_OR_GREATER
380411
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReferenceAt(depth, 0, 0), array.GetLength(1));
381412
#else
382413
this.Instance = array;
@@ -434,7 +465,10 @@ public Span2D(T[,,] array, int depth, int row, int column, int height, int width
434465
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
435466
}
436467

437-
#if NETSTANDARD2_1_OR_GREATER
468+
#if NET7_0_OR_GREATER
469+
this.reference = ref array.DangerousGetReferenceAt(depth, row, column);
470+
this.height = height;
471+
#elif NETSTANDARD2_1_OR_GREATER
438472
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReferenceAt(depth, row, column), height);
439473
#else
440474
this.Instance = array;
@@ -512,7 +546,12 @@ internal Span2D(Span<T> span, int offset, int height, int width, int pitch)
512546
ThrowHelper.ThrowArgumentException();
513547
}
514548

549+
#if NET7_0_OR_GREATER
550+
this.reference = ref span.DangerousGetReferenceAt(offset);
551+
this.height = height;
552+
#else
515553
this.span = MemoryMarshal.CreateSpan(ref span.DangerousGetReferenceAt(offset), height);
554+
#endif
516555
this.width = width;
517556
this.Stride = width + pitch;
518557
}
@@ -580,7 +619,9 @@ public int Height
580619
[MethodImpl(MethodImplOptions.AggressiveInlining)]
581620
get
582621
{
583-
#if NETSTANDARD2_1_OR_GREATER
622+
#if NET7_0_OR_GREATER
623+
return this.height;
624+
#elif NETSTANDARD2_1_OR_GREATER
584625
return this.span.Length;
585626
#else
586627
return this.height;
@@ -902,7 +943,9 @@ public unsafe ref T GetPinnableReference()
902943

903944
if (Length != 0)
904945
{
905-
#if NETSTANDARD2_1_OR_GREATER
946+
#if NET7_0_OR_GREATER
947+
r0 = ref this.reference;
948+
#elif NETSTANDARD2_1_OR_GREATER
906949
r0 = ref MemoryMarshal.GetReference(this.span);
907950
#else
908951
r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.Instance, this.Offset);
@@ -919,7 +962,9 @@ public unsafe ref T GetPinnableReference()
919962
[MethodImpl(MethodImplOptions.AggressiveInlining)]
920963
public ref T DangerousGetReference()
921964
{
922-
#if NETSTANDARD2_1_OR_GREATER
965+
#if NET7_0_OR_GREATER
966+
return ref this.reference;
967+
#elif NETSTANDARD2_1_OR_GREATER
923968
return ref MemoryMarshal.GetReference(this.span);
924969
#else
925970
return ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.Instance, this.Offset);
@@ -935,7 +980,9 @@ public ref T DangerousGetReference()
935980
[MethodImpl(MethodImplOptions.AggressiveInlining)]
936981
public ref T DangerousGetReferenceAt(int i, int j)
937982
{
938-
#if NETSTANDARD2_1_OR_GREATER
983+
#if NET7_0_OR_GREATER
984+
ref T r0 = ref this.reference;
985+
#elif NETSTANDARD2_1_OR_GREATER
939986
ref T r0 = ref MemoryMarshal.GetReference(this.span);
940987
#else
941988
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.Instance, this.Offset);
@@ -982,7 +1029,11 @@ public unsafe Span2D<T> Slice(int row, int column, int height, int width)
9821029
nint shift = ((nint)(uint)this.Stride * (nint)(uint)row) + (nint)(uint)column;
9831030
int pitch = this.Stride - width;
9841031

985-
#if NETSTANDARD2_1_OR_GREATER
1032+
#if NET7_0_OR_GREATER
1033+
ref T r0 = ref Unsafe.Add(ref this.reference, shift);
1034+
1035+
return new(ref r0, height, width, pitch);
1036+
#elif NETSTANDARD2_1_OR_GREATER
9861037
ref T r0 = ref this.span.DangerousGetReferenceAt(shift);
9871038

9881039
return new(ref r0, height, width, pitch);
@@ -1024,7 +1075,11 @@ public bool TryGetSpan(out Span<T> span)
10241075
if (this.Stride == this.width &&
10251076
Length <= int.MaxValue)
10261077
{
1027-
#if NETSTANDARD2_1_OR_GREATER
1078+
#if NET7_0_OR_GREATER
1079+
span = MemoryMarshal.CreateSpan(ref this.reference, (int)Length);
1080+
1081+
return true;
1082+
#elif NETSTANDARD2_1_OR_GREATER
10281083
span = MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(this.span), (int)Length);
10291084

10301085
return true;
@@ -1135,7 +1190,10 @@ public override string ToString()
11351190
public static bool operator ==(Span2D<T> left, Span2D<T> right)
11361191
{
11371192
return
1138-
#if NETSTANDARD2_1_OR_GREATER
1193+
#if NET7_0_OR_GREATER
1194+
Unsafe.AreSame(ref left.reference, ref right.reference) &&
1195+
left.height == right.height &&
1196+
#elif NETSTANDARD2_1_OR_GREATER
11391197
left.span == right.span &&
11401198
#else
11411199
ReferenceEquals(

0 commit comments

Comments
 (0)