@@ -125,4 +125,146 @@ public void Dispose()
125125 source . Dispose ( ) ;
126126 }
127127 }
128+
129+ [ StructLayout ( LayoutKind . Auto ) ]
130+ [ EditorBrowsable ( EditorBrowsableState . Never ) ]
131+ #if NET9_0_OR_GREATER
132+ public ref
133+ #else
134+ public
135+ #endif
136+ struct SkipTake < TEnumerator , TSource > ( TEnumerator source , Int32 skipCount , Int32 takeCount )
137+ : IValueEnumerator < TSource >
138+ where TEnumerator : struct , IValueEnumerator < TSource >
139+ #if NET9_0_OR_GREATER
140+ , allows ref struct
141+ #endif
142+ {
143+ TEnumerator source = source ;
144+ internal readonly int skipCount = Math . Max ( 0 , skipCount ) ; // ensure non-negative
145+ internal readonly int takeCount = Math . Max ( 0 , takeCount ) ; // ensure non-negative
146+ int skipped ;
147+ int taken ;
148+
149+ public bool TryGetNonEnumeratedCount ( out int count )
150+ {
151+ if ( source . TryGetNonEnumeratedCount ( out count ) )
152+ {
153+ // Calculate elements after skipping
154+ count = Math . Max ( 0 , count - skipCount ) ;
155+ // Apply take limit
156+ count = Math . Min ( count , takeCount ) ;
157+ return true ;
158+ }
159+
160+ count = default ;
161+ return false ;
162+ }
163+
164+ public bool TryCopyTo ( Span < TSource > destination , Index offset )
165+ {
166+ if ( source . TryGetNonEnumeratedCount ( out var sourceCount ) )
167+ {
168+ // Determine actual number of elements after skipping
169+ var actualSkipCount = Math . Min ( sourceCount , skipCount ) ;
170+ var availableAfterSkip = sourceCount - actualSkipCount ;
171+
172+ // Apply take limit
173+ var actualCount = Math . Min ( availableAfterSkip , takeCount ) ;
174+
175+ if ( actualCount <= 0 )
176+ {
177+ return false ;
178+ }
179+
180+ // Calculate offset within the resulting sequence
181+ var offsetInResult = offset . GetOffset ( actualCount ) ;
182+
183+ if ( offsetInResult < 0 || offsetInResult >= actualCount )
184+ {
185+ return false ;
186+ }
187+
188+ // Calculate offset in source sequence (skip + offset)
189+ var sourceOffset = actualSkipCount + offsetInResult ;
190+
191+ // Calculate elements available after offset
192+ var elementsAvailable = actualCount - offsetInResult ;
193+
194+ // Calculate elements to copy
195+ var elementsToCopy = Math . Min ( elementsAvailable , destination . Length ) ;
196+
197+ if ( elementsToCopy <= 0 )
198+ {
199+ return false ;
200+ }
201+
202+ return source . TryCopyTo ( destination . Slice ( 0 , elementsToCopy ) , sourceOffset ) ;
203+ }
204+
205+ return false ;
206+ }
207+
208+ public bool TryGetSpan ( out ReadOnlySpan < TSource > span )
209+ {
210+ if ( source . TryGetSpan ( out span ) )
211+ {
212+ // Skip elements
213+ if ( span . Length <= skipCount )
214+ {
215+ span = default ;
216+ return true ;
217+ }
218+
219+ span = span . Slice ( skipCount ) ;
220+
221+ // Take elements
222+ if ( span . Length > takeCount )
223+ {
224+ span = span . Slice ( 0 , takeCount ) ;
225+ }
226+
227+ return true ;
228+ }
229+
230+ span = default ;
231+ return false ;
232+ }
233+
234+ public bool TryGetNext ( out TSource current )
235+ {
236+ // Skip elements if not already skipped
237+ while ( skipped < skipCount )
238+ {
239+ if ( ! source . TryGetNext ( out var _ ) )
240+ {
241+ Unsafe . SkipInit ( out current ) ;
242+ return false ;
243+ }
244+ skipped ++ ;
245+ }
246+
247+ // Check if we've reached the take limit
248+ if ( taken >= takeCount )
249+ {
250+ Unsafe . SkipInit ( out current ) ;
251+ return false ;
252+ }
253+
254+ // Return elements after skipping and before take limit
255+ if ( source . TryGetNext ( out current ) )
256+ {
257+ taken ++ ;
258+ return true ;
259+ }
260+
261+ Unsafe . SkipInit ( out current ) ;
262+ return false ;
263+ }
264+
265+ public void Dispose ( )
266+ {
267+ source . Dispose ( ) ;
268+ }
269+ }
128270}
0 commit comments