@@ -29,11 +29,6 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
2929 /// </summary>
3030 /// <remarks>The <see cref="ReadOnlySpan{T}.Length"/> field maps to the total available length.</remarks>
3131 private readonly ReadOnlySpan < T > span ;
32-
33- /// <summary>
34- /// Gets the total available length for the sequence.
35- /// </summary>
36- public int Length => span . Length ;
3732#else
3833 /// <summary>
3934 /// The target <see cref="object"/> instance, if present.
@@ -46,9 +41,9 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
4641 private readonly IntPtr offset ;
4742
4843 /// <summary>
49- /// Gets the total available length for the sequence.
44+ /// The total available length for the sequence.
5045 /// </summary>
51- public int Length { get ; }
46+ private readonly int length ;
5247#endif
5348
5449 /// <summary>
@@ -57,40 +52,6 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
5752 /// <remarks>The distance refers to <typeparamref name="T"/> items, not byte offset.</remarks>
5853 private readonly int step ;
5954
60- /// <summary>
61- /// Gets the element at the specified zero-based index.
62- /// </summary>
63- /// <returns>A reference to the element at the specified index.</returns>
64- /// <exception cref="IndexOutOfRangeException">
65- /// Thrown when <paramref name="index"/> is invalid.
66- /// </exception>
67- public ref readonly T this [ int index ]
68- {
69- get
70- {
71- if ( ( uint ) index >= ( uint ) Length )
72- {
73- ThrowHelper . ThrowIndexOutOfRangeException ( ) ;
74- }
75-
76- return ref DangerousGetReferenceAt ( index ) ;
77- }
78- }
79-
80- #if NETSTANDARD2_1_OR_GREATER
81- /// <summary>
82- /// Gets the element at the specified zero-based index.
83- /// </summary>
84- /// <returns>A reference to the element at the specified index.</returns>
85- /// <exception cref="IndexOutOfRangeException">
86- /// Thrown when <paramref name="index"/> is invalid.
87- /// </exception>
88- public ref readonly T this [ Index index ]
89- {
90- get => ref this [ index . GetOffset ( Length ) ] ;
91- }
92- #endif
93-
9455#if SPAN_RUNTIME_SUPPORT
9556 /// <summary>
9657 /// Initializes a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct.
@@ -155,53 +116,76 @@ internal ReadOnlyRefEnumerable(object? instance, IntPtr offset, int length, int
155116 {
156117 this . instance = instance ;
157118 this . offset = offset ;
158- Length = length ;
119+ this . length = length ;
159120 this . step = step ;
160121 }
161122#endif
162123
163124 /// <summary>
164- /// Returns a reference to the first element within the current instance, with no bounds check .
125+ /// Gets the total available length for the sequence .
165126 /// </summary>
166- /// <returns>A reference to the first element within the current instance.</returns>
167- internal ref readonly T DangerousGetReference ( )
127+ public int Length
168128 {
169129#if SPAN_RUNTIME_SUPPORT
170- return ref MemoryMarshal . GetReference ( this . span ) ;
130+ get => this . span . Length ;
171131#else
172- return ref RuntimeHelpers . GetObjectDataAtOffsetOrPointerReference < T > ( this . instance , this . offset ) ;
132+ get => this . length ;
173133#endif
174134 }
175135
176136 /// <summary>
177- /// Returns a reference to a specified element within the current instance, with no bounds check .
137+ /// Gets the element at the specified zero-based index .
178138 /// </summary>
179139 /// <returns>A reference to the element at the specified index.</returns>
180- internal ref readonly T DangerousGetReferenceAt ( int index )
140+ /// <exception cref="IndexOutOfRangeException">
141+ /// Thrown when <paramref name="index"/> is invalid.
142+ /// </exception>
143+ public ref readonly T this [ int index ]
181144 {
145+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
146+ get
147+ {
148+ if ( ( uint ) index >= ( uint ) Length )
149+ {
150+ ThrowHelper . ThrowIndexOutOfRangeException ( ) ;
151+ }
152+
182153#if SPAN_RUNTIME_SUPPORT
183- ref T r0 = ref MemoryMarshal . GetReference ( this . span ) ;
154+ ref T r0 = ref MemoryMarshal . GetReference ( this . span ) ;
184155#else
185- ref T r0 = ref RuntimeHelpers . GetObjectDataAtOffsetOrPointerReference < T > ( this . instance , this . offset ) ;
156+ ref T r0 = ref RuntimeHelpers . GetObjectDataAtOffsetOrPointerReference < T > ( this . instance , this . offset ) ;
186157#endif
158+ nint offset = ( nint ) ( uint ) index * ( nint ) ( uint ) this . step ;
159+ ref T ri = ref Unsafe . Add ( ref r0 , offset ) ;
160+ return ref ri ;
161+ }
162+ }
187163
188- // Here we just offset by shifting down as if we were traversing a 2D array with a
189- // a single column, with the width of each row represented by the step, the height
190- // represented by the current position, and with only the first element of each row
191- // being inspected. We can perform all the indexing operations in this type as nint,
192- // as the maximum offset is guaranteed never to exceed the maximum value, since on
193- // 32 bit architectures it's not possible to allocate that much memory anyway.
194- nint offset = ( nint ) ( uint ) index * ( nint ) ( uint ) this . step ;
195- ref T ri = ref Unsafe . Add ( ref r0 , offset ) ;
196- return ref ri ;
164+ #if NETSTANDARD2_1_OR_GREATER
165+ /// <summary>
166+ /// Gets the element at the specified zero-based index.
167+ /// </summary>
168+ /// <returns>A reference to the element at the specified index.</returns>
169+ /// <exception cref="IndexOutOfRangeException">
170+ /// Thrown when <paramref name="index"/> is invalid.
171+ /// </exception>
172+ public ref readonly T this [ Index index ]
173+ {
174+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
175+ get => ref this [ index . GetOffset ( Length ) ] ;
197176 }
177+ #endif
198178
199179 /// <inheritdoc cref="System.Collections.IEnumerable.GetEnumerator"/>
200180 [ Pure ]
201181 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
202182 public Enumerator GetEnumerator ( )
203183 {
204- return new Enumerator ( this ) ;
184+ #if SPAN_RUNTIME_SUPPORT
185+ return new Enumerator ( this . span , this . step ) ;
186+ #else
187+ return new Enumerator ( this . instance , this . offset , this . length , this . step ) ;
188+ #endif
205189 }
206190
207191 /// <summary>
@@ -237,7 +221,7 @@ public void CopyTo(RefEnumerable<T> destination)
237221 ref T sourceRef = ref RuntimeHelpers . GetObjectDataAtOffsetOrPointerReference < T > ( this . instance , this . offset ) ;
238222 ref T destinationRef = ref RuntimeHelpers . GetObjectDataAtOffsetOrPointerReference < T > ( destination . Instance , destination . Offset ) ;
239223 int
240- sourceLength = Length ,
224+ sourceLength = this . length ,
241225 destinationLength = destination . Length ;
242226#endif
243227
@@ -262,7 +246,7 @@ public bool TryCopyTo(RefEnumerable<T> destination)
262246 destinationLength = destination . Span . Length ;
263247#else
264248 int
265- sourceLength = Length ,
249+ sourceLength = this . length ,
266250 destinationLength = destination . Length ;
267251#endif
268252
@@ -297,7 +281,7 @@ public void CopyTo(Span<T> destination)
297281 int length = this . span . Length ;
298282#else
299283 ref T sourceRef = ref RuntimeHelpers . GetObjectDataAtOffsetOrPointerReference < T > ( this . instance , this . offset ) ;
300- int length = Length ;
284+ int length = this . length ;
301285#endif
302286 if ( ( uint ) destination . Length < ( uint ) length )
303287 {
@@ -319,7 +303,7 @@ public bool TryCopyTo(Span<T> destination)
319303#if SPAN_RUNTIME_SUPPORT
320304 int length = this . span . Length ;
321305#else
322- int length = Length ;
306+ int length = this . length ;
323307#endif
324308
325309 if ( destination . Length >= length )
@@ -339,7 +323,7 @@ public T[] ToArray()
339323#if SPAN_RUNTIME_SUPPORT
340324 int length = this . span . Length ;
341325#else
342- int length = Length ;
326+ int length = this . length ;
343327#endif
344328
345329 // Empty array if no data is mapped
@@ -374,10 +358,22 @@ public static implicit operator ReadOnlyRefEnumerable<T>(RefEnumerable<T> enumer
374358 /// </summary>
375359 public ref struct Enumerator
376360 {
377- /// <summary>
378- /// The <see cref="ReadOnlyRefEnumerable{T}"/> used by this enumerator.
379- /// </summary>
380- private readonly ReadOnlyRefEnumerable < T > enumerable ;
361+ #if SPAN_RUNTIME_SUPPORT
362+ /// <inheritdoc cref="ReadOnlyRefEnumerable{T}.span"/>
363+ private readonly ReadOnlySpan < T > span ;
364+ #else
365+ /// <inheritdoc cref="ReadOnlyRefEnumerable{T}.instance"/>
366+ private readonly object ? instance ;
367+
368+ /// <inheritdoc cref="ReadOnlyRefEnumerable{T}.offset"/>
369+ private readonly IntPtr offset ;
370+
371+ /// <inheritdoc cref="ReadOnlyRefEnumerable{T}.length"/>
372+ private readonly int length ;
373+ #endif
374+
375+ /// <inheritdoc cref="ReadOnlyRefEnumerable{T}.step"/>
376+ private readonly int step ;
381377
382378 /// <summary>
383379 /// The current position in the sequence.
@@ -392,8 +388,10 @@ public ref struct Enumerator
392388 /// <param name="step">The distance between items in the sequence to enumerate.</param>
393389 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
394390 internal Enumerator ( ReadOnlySpan < T > span , int step )
395- : this ( new ReadOnlyRefEnumerable < T > ( span , step ) )
396391 {
392+ this . span = span ;
393+ this . step = step ;
394+ this . position = - 1 ;
397395 }
398396#else
399397 /// <summary>
@@ -405,33 +403,42 @@ internal Enumerator(ReadOnlySpan<T> span, int step)
405403 /// <param name="step">The distance between items in the sequence to enumerate.</param>
406404 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
407405 internal Enumerator ( object ? instance , IntPtr offset , int length , int step )
408- : this ( new ReadOnlyRefEnumerable < T > ( instance , offset , length , step ) )
409406 {
410- }
411- #endif
412-
413- internal Enumerator ( ReadOnlyRefEnumerable < T > enumerable )
414- {
415- this . enumerable = enumerable ;
407+ this . instance = instance ;
408+ this . offset = offset ;
409+ this . length = length ;
410+ this . step = step ;
416411 this . position = - 1 ;
417412 }
413+ #endif
418414
419415 /// <inheritdoc cref="System.Collections.IEnumerator.MoveNext"/>
420416 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
421417 public bool MoveNext ( )
422418 {
423419#if SPAN_RUNTIME_SUPPORT
424- return ++ this . position < this . enumerable . span . Length ;
420+ return ++ this . position < this . span . Length ;
425421#else
426- return ++ this . position < this . enumerable . Length ;
422+ return ++ this . position < this . length ;
427423#endif
428424 }
429425
430426 /// <inheritdoc cref="System.Collections.Generic.IEnumerator{T}.Current"/>
431427 public readonly ref readonly T Current
432428 {
433429 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
434- get => ref this . enumerable . DangerousGetReferenceAt ( this . position ) ;
430+ get
431+ {
432+ #if SPAN_RUNTIME_SUPPORT
433+ ref T r0 = ref this . span . DangerousGetReference ( ) ;
434+ #else
435+ ref T r0 = ref RuntimeHelpers . GetObjectDataAtOffsetOrPointerReference < T > ( this . instance , this . offset ) ;
436+ #endif
437+ nint offset = ( nint ) ( uint ) this . position * ( nint ) ( uint ) this . step ;
438+ ref T ri = ref Unsafe . Add ( ref r0 , offset ) ;
439+
440+ return ref ri ;
441+ }
435442 }
436443 }
437444
0 commit comments