Skip to content

Commit a4cd949

Browse files
committed
Reverted changes for 2D array enumerables
- The one for rows is not needed from .NET Core 2.1 and above - The other has the extra ToArray API which needs the initial values to remain available, and the type to be readonly
1 parent 26768a5 commit a4cd949

File tree

2 files changed

+213
-155
lines changed

2 files changed

+213
-155
lines changed

Microsoft.Toolkit.HighPerformance/Enumerables/Array2DColumnEnumerable{T}.cs

Lines changed: 128 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -16,35 +16,10 @@ namespace Microsoft.Toolkit.HighPerformance.Enumerables
1616
/// </summary>
1717
/// <typeparam name="T">The type of items to enumerate.</typeparam>
1818
[EditorBrowsable(EditorBrowsableState.Never)]
19-
public ref struct Array2DColumnEnumerable<T>
19+
public readonly ref struct Array2DColumnEnumerable<T>
2020
{
21-
#if SPAN_RUNTIME_SUPPORT
22-
/// <summary>
23-
/// The <see cref="Span{T}"/> instance mapping the target 2D array.
24-
/// </summary>
25-
/// <remarks>
26-
/// In runtimes where we have support for the <see cref="Span{T}"/> type, we can
27-
/// create one from the input 2D array and use that to traverse the target column.
28-
/// This reduces the number of operations to perform for the offsetting to the right
29-
/// column element (we simply need to add <see cref="width"/> to the offset at each
30-
/// iteration to move down by one row), and allows us to use the fast <see cref="Span{T}"/>
31-
/// accessor instead of the slower indexer for 2D arrays, as we can then access each
32-
/// individual item linearly, since we know the absolute offset from the base location.
33-
/// </remarks>
34-
private readonly Span<T> span;
35-
36-
/// <summary>
37-
/// The width of the target 2D array.
38-
/// </summary>
39-
private readonly int width;
40-
41-
/// <summary>
42-
/// The current absolute offset within <see cref="span"/>.
43-
/// </summary>
44-
private int offset;
45-
#else
4621
/// <summary>
47-
/// The source 2D array instance.
22+
/// The source 2D <typeparamref name="T"/> array instance.
4823
/// </summary>
4924
private readonly T[,] array;
5025

@@ -53,93 +28,24 @@ public ref struct Array2DColumnEnumerable<T>
5328
/// </summary>
5429
private readonly int column;
5530

56-
/// <summary>
57-
/// The height of a column in <see cref="array"/>.
58-
/// </summary>
59-
private readonly int height;
60-
61-
/// <summary>
62-
/// The current row.
63-
/// </summary>
64-
private int row;
65-
#endif
66-
6731
/// <summary>
6832
/// Initializes a new instance of the <see cref="Array2DColumnEnumerable{T}"/> struct.
6933
/// </summary>
70-
/// <param name="array">The source 2D array instance.</param>
34+
/// <param name="array">The source 2D <typeparamref name="T"/> array instance.</param>
7135
/// <param name="column">The target column to iterate within <paramref name="array"/>.</param>
7236
[MethodImpl(MethodImplOptions.AggressiveInlining)]
7337
public Array2DColumnEnumerable(T[,] array, int column)
7438
{
75-
if ((uint)column >= (uint)array.GetLength(1))
76-
{
77-
ThrowArgumentOutOfRangeExceptionForInvalidColumn();
78-
}
79-
80-
#if SPAN_RUNTIME_SUPPORT
81-
this.span = array.AsSpan();
82-
this.width = array.GetLength(1);
83-
this.offset = column - this.width;
84-
#else
8539
this.array = array;
8640
this.column = column;
87-
this.height = array.GetLength(0);
88-
this.row = -1;
89-
#endif
9041
}
9142

9243
/// <summary>
9344
/// Implements the duck-typed <see cref="IEnumerable{T}.GetEnumerator"/> method.
9445
/// </summary>
95-
/// <returns>An <see cref="Array2DColumnEnumerable{T}"/> instance targeting the current 2D <typeparamref name="T"/> array instance.</returns>
46+
/// <returns>An <see cref="Enumerator"/> instance targeting the current 2D <typeparamref name="T"/> array instance.</returns>
9647
[MethodImpl(MethodImplOptions.AggressiveInlining)]
97-
public Array2DColumnEnumerable<T> GetEnumerator() => this;
98-
99-
/// <summary>
100-
/// Implements the duck-typed <see cref="System.Collections.IEnumerator.MoveNext"/> method.
101-
/// </summary>
102-
/// <returns><see langword="true"/> whether a new element is available, <see langword="false"/> otherwise</returns>
103-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
104-
public bool MoveNext()
105-
{
106-
#if SPAN_RUNTIME_SUPPORT
107-
int offset = this.offset + this.width;
108-
109-
if ((uint)offset < (uint)this.span.Length)
110-
{
111-
this.offset = offset;
112-
113-
return true;
114-
}
115-
#else
116-
int row = this.row + 1;
117-
118-
if (row < this.height)
119-
{
120-
this.row = row;
121-
122-
return true;
123-
}
124-
#endif
125-
return false;
126-
}
127-
128-
/// <summary>
129-
/// Gets the duck-typed <see cref="IEnumerator{T}.Current"/> property.
130-
/// </summary>
131-
public ref T Current
132-
{
133-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
134-
get
135-
{
136-
#if SPAN_RUNTIME_SUPPORT
137-
return ref this.span.DangerousGetReferenceAt(this.offset);
138-
#else
139-
return ref this.array[this.row, this.column];
140-
#endif
141-
}
142-
}
48+
public Enumerator GetEnumerator() => new Enumerator(this.array, this.column);
14349

14450
/// <summary>
14551
/// Returns a <typeparamref name="T"/> array with the values in the target column.
@@ -173,6 +79,129 @@ public T[] ToArray()
17379
return array;
17480
}
17581

82+
/// <summary>
83+
/// An enumerator for a source 2D array instance.
84+
/// </summary>
85+
[EditorBrowsable(EditorBrowsableState.Never)]
86+
public ref struct Enumerator
87+
{
88+
#if SPAN_RUNTIME_SUPPORT
89+
/// <summary>
90+
/// The <see cref="Span{T}"/> instance mapping the target 2D array.
91+
/// </summary>
92+
/// <remarks>
93+
/// In runtimes where we have support for the <see cref="Span{T}"/> type, we can
94+
/// create one from the input 2D array and use that to traverse the target column.
95+
/// This reduces the number of operations to perform for the offsetting to the right
96+
/// column element (we simply need to add <see cref="width"/> to the offset at each
97+
/// iteration to move down by one row), and allows us to use the fast <see cref="Span{T}"/>
98+
/// accessor instead of the slower indexer for 2D arrays, as we can then access each
99+
/// individual item linearly, since we know the absolute offset from the base location.
100+
/// </remarks>
101+
private readonly Span<T> span;
102+
103+
/// <summary>
104+
/// The width of the target 2D array.
105+
/// </summary>
106+
private readonly int width;
107+
108+
/// <summary>
109+
/// The current absolute offset within <see cref="span"/>.
110+
/// </summary>
111+
private int offset;
112+
#else
113+
/// <summary>
114+
/// The source 2D array instance.
115+
/// </summary>
116+
private readonly T[,] array;
117+
118+
/// <summary>
119+
/// The target column to iterate within <see cref="array"/>.
120+
/// </summary>
121+
private readonly int column;
122+
123+
/// <summary>
124+
/// The height of a column in <see cref="array"/>.
125+
/// </summary>
126+
private readonly int height;
127+
128+
/// <summary>
129+
/// The current row.
130+
/// </summary>
131+
private int row;
132+
#endif
133+
134+
/// <summary>
135+
/// Initializes a new instance of the <see cref="Enumerator"/> struct.
136+
/// </summary>
137+
/// <param name="array">The source 2D array instance.</param>
138+
/// <param name="column">The target column to iterate within <paramref name="array"/>.</param>
139+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
140+
public Enumerator(T[,] array, int column)
141+
{
142+
if ((uint)column >= (uint)array.GetLength(1))
143+
{
144+
ThrowArgumentOutOfRangeExceptionForInvalidColumn();
145+
}
146+
147+
#if SPAN_RUNTIME_SUPPORT
148+
this.span = array.AsSpan();
149+
this.width = array.GetLength(1);
150+
this.offset = column - this.width;
151+
#else
152+
this.array = array;
153+
this.column = column;
154+
this.height = array.GetLength(0);
155+
this.row = -1;
156+
#endif
157+
}
158+
159+
/// <summary>
160+
/// Implements the duck-typed <see cref="System.Collections.IEnumerator.MoveNext"/> method.
161+
/// </summary>
162+
/// <returns><see langword="true"/> whether a new element is available, <see langword="false"/> otherwise</returns>
163+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
164+
public bool MoveNext()
165+
{
166+
#if SPAN_RUNTIME_SUPPORT
167+
int offset = this.offset + this.width;
168+
169+
if ((uint)offset < (uint)this.span.Length)
170+
{
171+
this.offset = offset;
172+
173+
return true;
174+
}
175+
#else
176+
int row = this.row + 1;
177+
178+
if (row < this.height)
179+
{
180+
this.row = row;
181+
182+
return true;
183+
}
184+
#endif
185+
return false;
186+
}
187+
188+
/// <summary>
189+
/// Gets the duck-typed <see cref="IEnumerator{T}.Current"/> property.
190+
/// </summary>
191+
public ref T Current
192+
{
193+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
194+
get
195+
{
196+
#if SPAN_RUNTIME_SUPPORT
197+
return ref this.span.DangerousGetReferenceAt(this.offset);
198+
#else
199+
return ref this.array[this.row, this.column];
200+
#endif
201+
}
202+
}
203+
}
204+
176205
/// <summary>
177206
/// Throws an <see cref="ArgumentOutOfRangeException"/> when the <see cref="column"/> is invalid.
178207
/// </summary>

0 commit comments

Comments
 (0)