@@ -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