@@ -20,7 +20,7 @@ namespace Microsoft.Toolkit.HighPerformance.Enumerables
2020 /// A <see langword="ref"/> <see langword="struct"/> that iterates readonly items from arbitrary memory locations.
2121 /// </summary>
2222 /// <typeparam name="T">The type of items to enumerate.</typeparam>
23- public ref struct ReadOnlyRefEnumerable < T >
23+ public readonly ref struct ReadOnlyRefEnumerable < T >
2424 {
2525#if SPAN_RUNTIME_SUPPORT
2626 /// <summary>
@@ -51,24 +51,17 @@ public ref struct ReadOnlyRefEnumerable<T>
5151 /// <remarks>The distance refers to <typeparamref name="T"/> items, not byte offset.</remarks>
5252 private readonly int step ;
5353
54- /// <summary>
55- /// The current position in the sequence.
56- /// </summary>
57- private int position ;
58-
5954#if SPAN_RUNTIME_SUPPORT
6055 /// <summary>
6156 /// Initializes a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct.
6257 /// </summary>
6358 /// <param name="span">The <see cref="ReadOnlySpan{T}"/> instance pointing to the first item in the target memory area.</param>
6459 /// <param name="step">The distance between items in the sequence to enumerate.</param>
65- /// <param name="position">The current position in the sequence.</param>
6660 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
67- private ReadOnlyRefEnumerable ( ReadOnlySpan < T > span , int step , int position )
61+ private ReadOnlyRefEnumerable ( ReadOnlySpan < T > span , int step )
6862 {
6963 this . span = span ;
7064 this . step = step ;
71- this . position = position ;
7265 }
7366
7467 /// <summary>
@@ -82,27 +75,8 @@ internal ReadOnlyRefEnumerable(in T reference, int length, int step)
8275 {
8376 this . span = MemoryMarshal . CreateReadOnlySpan ( ref Unsafe . AsRef ( reference ) , length ) ;
8477 this . step = step ;
85- this . position = - 1 ;
8678 }
8779#else
88- /// <summary>
89- /// Initializes a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct.
90- /// </summary>
91- /// <param name="instance">The target <see cref="object"/> instance.</param>
92- /// <param name="offset">The initial offset within <see paramref="instance"/>.</param>
93- /// <param name="length">The number of items in the sequence.</param>
94- /// <param name="step">The distance between items in the sequence to enumerate.</param>
95- /// <param name="position">The current position in the sequence.</param>
96- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
97- private ReadOnlyRefEnumerable ( object ? instance , IntPtr offset , int length , int step , int position )
98- {
99- this . instance = instance ;
100- this . offset = offset ;
101- this . length = length ;
102- this . step = step ;
103- this . position = position ;
104- }
105-
10680 /// <summary>
10781 /// Initializes a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct.
10882 /// </summary>
@@ -117,42 +91,19 @@ internal ReadOnlyRefEnumerable(object? instance, IntPtr offset, int length, int
11791 this . offset = offset ;
11892 this . length = length ;
11993 this . step = step ;
120- this . position = - 1 ;
12194 }
12295#endif
12396
12497 /// <inheritdoc cref="System.Collections.IEnumerable.GetEnumerator"/>
12598 [ Pure ]
12699 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
127- public readonly ReadOnlyRefEnumerable < T > GetEnumerator ( ) => this ;
128-
129- /// <inheritdoc cref="System.Collections.IEnumerator.MoveNext"/>
130- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
131- public bool MoveNext ( )
132- {
133- #if SPAN_RUNTIME_SUPPORT
134- return ++ this . position < this . span . Length ;
135- #else
136- return ++ this . position < this . length ;
137- #endif
138- }
139-
140- /// <inheritdoc cref="System.Collections.Generic.IEnumerator{T}.Current"/>
141- public readonly ref readonly T Current
100+ public Enumerator GetEnumerator ( )
142101 {
143- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
144- get
145- {
146102#if SPAN_RUNTIME_SUPPORT
147- ref T r0 = ref this . span . DangerousGetReference ( ) ;
103+ return new Enumerator ( this . span , this . step ) ;
148104#else
149- ref T r0 = ref RuntimeHelpers . GetObjectDataAtOffsetOrPointerReference < T > ( this . instance , this . offset ) ;
105+ return new Enumerator ( this . instance , this . offset , this . length , this . step ) ;
150106#endif
151- nint offset = ( nint ) ( uint ) this . position * ( nint ) ( uint ) this . step ;
152- ref T ri = ref Unsafe . Add ( ref r0 , offset ) ;
153-
154- return ref ri ;
155- }
156107 }
157108
158109 /// <summary>
@@ -162,7 +113,7 @@ public readonly ref readonly T Current
162113 /// <exception cref="ArgumentException">
163114 /// Thrown when <paramref name="destination"/> is shorter than the source <see cref="ReadOnlyRefEnumerable{T}"/> instance.
164115 /// </exception>
165- public readonly void CopyTo ( RefEnumerable < T > destination )
116+ public void CopyTo ( RefEnumerable < T > destination )
166117 {
167118#if SPAN_RUNTIME_SUPPORT
168119 if ( this . step == 1 )
@@ -205,7 +156,7 @@ public readonly void CopyTo(RefEnumerable<T> destination)
205156 /// </summary>
206157 /// <param name="destination">The target <see cref="RefEnumerable{T}"/> of the copy operation.</param>
207158 /// <returns>Whether or not the operation was successful.</returns>
208- public readonly bool TryCopyTo ( RefEnumerable < T > destination )
159+ public bool TryCopyTo ( RefEnumerable < T > destination )
209160 {
210161#if SPAN_RUNTIME_SUPPORT
211162 int
@@ -234,7 +185,7 @@ public readonly bool TryCopyTo(RefEnumerable<T> destination)
234185 /// <exception cref="ArgumentException">
235186 /// Thrown when <paramref name="destination"/> is shorter than the source <see cref="RefEnumerable{T}"/> instance.
236187 /// </exception>
237- public readonly void CopyTo ( Span < T > destination )
188+ public void CopyTo ( Span < T > destination )
238189 {
239190#if SPAN_RUNTIME_SUPPORT
240191 if ( this . step == 1 )
@@ -265,7 +216,7 @@ public readonly void CopyTo(Span<T> destination)
265216 /// </summary>
266217 /// <param name="destination">The target <see cref="Span{T}"/> of the copy operation.</param>
267218 /// <returns>Whether or not the operation was successful.</returns>
268- public readonly bool TryCopyTo ( Span < T > destination )
219+ public bool TryCopyTo ( Span < T > destination )
269220 {
270221#if SPAN_RUNTIME_SUPPORT
271222 int length = this . span . Length ;
@@ -285,7 +236,7 @@ public readonly bool TryCopyTo(Span<T> destination)
285236
286237 /// <inheritdoc cref="RefEnumerable{T}.ToArray"/>
287238 [ Pure ]
288- public readonly T [ ] ToArray ( )
239+ public T [ ] ToArray ( )
289240 {
290241#if SPAN_RUNTIME_SUPPORT
291242 int length = this . span . Length ;
@@ -314,10 +265,99 @@ public readonly T[] ToArray()
314265 public static implicit operator ReadOnlyRefEnumerable < T > ( RefEnumerable < T > enumerable )
315266 {
316267#if SPAN_RUNTIME_SUPPORT
317- return new ReadOnlyRefEnumerable < T > ( enumerable . Span , enumerable . Step , enumerable . Position ) ;
268+ return new ReadOnlyRefEnumerable < T > ( enumerable . Span , enumerable . Step ) ;
269+ #else
270+ return new ReadOnlyRefEnumerable < T > ( enumerable . Instance , enumerable . Offset , enumerable . Length , enumerable . Step ) ;
271+ #endif
272+ }
273+
274+ /// <summary>
275+ /// A custom enumerator type to traverse items within a <see cref="ReadOnlyRefEnumerable{T}"/> instance.
276+ /// </summary>
277+ public ref struct Enumerator
278+ {
279+ #if SPAN_RUNTIME_SUPPORT
280+ /// <inheritdoc cref="ReadOnlyRefEnumerable{T}.span"/>
281+ private readonly ReadOnlySpan < T > span ;
318282#else
319- return new ReadOnlyRefEnumerable < T > ( enumerable . Instance , enumerable . Offset , enumerable . Length , enumerable . Step , enumerable . Position ) ;
283+ /// <inheritdoc cref="ReadOnlyRefEnumerable{T}.instance"/>
284+ private readonly object ? instance ;
285+
286+ /// <inheritdoc cref="ReadOnlyRefEnumerable{T}.offset"/>
287+ private readonly IntPtr offset ;
288+
289+ /// <inheritdoc cref="ReadOnlyRefEnumerable{T}.length"/>
290+ private readonly int length ;
320291#endif
292+
293+ /// <inheritdoc cref="ReadOnlyRefEnumerable{T}.step"/>
294+ private readonly int step ;
295+
296+ /// <summary>
297+ /// The current position in the sequence.
298+ /// </summary>
299+ private int position ;
300+
301+ #if SPAN_RUNTIME_SUPPORT
302+ /// <summary>
303+ /// Initializes a new instance of the <see cref="Enumerator"/> struct.
304+ /// </summary>
305+ /// <param name="span">The <see cref="ReadOnlySpan{T}"/> instance with the info on the items to traverse.</param>
306+ /// <param name="step">The distance between items in the sequence to enumerate.</param>
307+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
308+ internal Enumerator ( ReadOnlySpan < T > span , int step )
309+ {
310+ this . span = span ;
311+ this . step = step ;
312+ this . position = - 1 ;
313+ }
314+ #else
315+ /// <summary>
316+ /// Initializes a new instance of the <see cref="Enumerator"/> struct.
317+ /// </summary>
318+ /// <param name="instance">The target <see cref="object"/> instance.</param>
319+ /// <param name="offset">The initial offset within <see paramref="instance"/>.</param>
320+ /// <param name="length">The number of items in the sequence.</param>
321+ /// <param name="step">The distance between items in the sequence to enumerate.</param>
322+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
323+ internal Enumerator ( object ? instance , IntPtr offset , int length , int step )
324+ {
325+ this . instance = instance ;
326+ this . offset = offset ;
327+ this . length = length ;
328+ this . step = step ;
329+ this . position = - 1 ;
330+ }
331+ #endif
332+
333+ /// <inheritdoc cref="System.Collections.IEnumerator.MoveNext"/>
334+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
335+ public bool MoveNext ( )
336+ {
337+ #if SPAN_RUNTIME_SUPPORT
338+ return ++ this . position < this . span . Length ;
339+ #else
340+ return ++ this . position < this . length ;
341+ #endif
342+ }
343+
344+ /// <inheritdoc cref="System.Collections.Generic.IEnumerator{T}.Current"/>
345+ public readonly ref readonly T Current
346+ {
347+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
348+ get
349+ {
350+ #if SPAN_RUNTIME_SUPPORT
351+ ref T r0 = ref this . span . DangerousGetReference ( ) ;
352+ #else
353+ ref T r0 = ref RuntimeHelpers . GetObjectDataAtOffsetOrPointerReference < T > ( this . instance , this . offset ) ;
354+ #endif
355+ nint offset = ( nint ) ( uint ) this . position * ( nint ) ( uint ) this . step ;
356+ ref T ri = ref Unsafe . Add ( ref r0 , offset ) ;
357+
358+ return ref ri ;
359+ }
360+ }
321361 }
322362
323363 /// <summary>
0 commit comments