1+ using System . Buffers ;
2+ using System . Diagnostics ;
3+ using System . Runtime . CompilerServices ;
4+
5+ namespace System
6+ {
7+ public static partial class MemoryExtensions
8+ {
9+ /// <summary>
10+ /// Enables enumerating each split within a <see cref="ReadOnlySpan{T}"/> that has been divided using one or more separators.
11+ /// </summary>
12+ public ref struct SpanSplitEnumerator < T > where T : IEquatable < T >
13+ {
14+ readonly ReadOnlySpan < T > Span ;
15+ readonly T Delimiter ;
16+ readonly ReadOnlySpan < T > DelimiterSpan ;
17+ SpanSplitEnumeratorMode mode ;
18+ #if NET8_0
19+ readonly SearchValues < T > SearchValues = null ! ;
20+ #endif
21+
22+ /// <summary>
23+ /// Gets the current element of the enumeration.
24+ /// </summary>
25+ /// <returns>Returns a <see cref="Range"/> instance that indicates the bounds of the current element withing the source span.</returns>
26+ public Range Current { get ; internal set ; }
27+
28+ internal SpanSplitEnumerator ( ReadOnlySpan < T > source , T delimiter )
29+ {
30+ Span = source ;
31+ Delimiter = delimiter ;
32+ Current = new Range ( 0 , 0 ) ;
33+ DelimiterSpan = default ;
34+ mode = SpanSplitEnumeratorMode . Delimiter ;
35+ }
36+ internal SpanSplitEnumerator ( ReadOnlySpan < T > source , ReadOnlySpan < T > delimiter , SpanSplitEnumeratorMode mode )
37+ {
38+ Span = source ;
39+ DelimiterSpan = delimiter ;
40+ Current = new Range ( 0 , 0 ) ;
41+ Delimiter = default ! ;
42+ this . mode = mode ;
43+ }
44+
45+ #if NET8_0
46+ internal SpanSplitEnumerator ( ReadOnlySpan < T > source , SearchValues < T > searchValues )
47+ {
48+ Span = source ;
49+ Delimiter = default ! ;
50+ SearchValues = searchValues ;
51+ Current = new Range ( 0 , 0 ) ;
52+ DelimiterSpan = default ;
53+ mode = SpanSplitEnumeratorMode . Delimiter ;
54+ }
55+ #endif
56+ /// <summary>
57+ /// Returns an enumerator that iterates through a collection.
58+ /// </summary>
59+ public readonly SpanSplitEnumerator < T > GetEnumerator ( )
60+ {
61+ return this ;
62+ }
63+
64+ /// <summary>
65+ /// Advances the enumerator to the next element of the collection.
66+ /// </summary>
67+ /// <returns><see langword="true"/> if the enumerator was successfully advanced to the next element; <see langword="false"/> if the enumerator has passed the end of the collection.</returns>
68+ public bool MoveNext ( )
69+ {
70+ int index ;
71+ int length ;
72+
73+ switch ( mode )
74+ {
75+ case SpanSplitEnumeratorMode . Delimiter :
76+ index = Span [ Current . Start ..] . IndexOf ( Delimiter ) ;
77+ length = 1 ;
78+ break ;
79+
80+ case SpanSplitEnumeratorMode . Any :
81+ index = Span [ Current . Start ..] . IndexOfAny ( DelimiterSpan ) ;
82+ length = 1 ;
83+ break ;
84+
85+ case SpanSplitEnumeratorMode . Sequence :
86+ index = Span [ Current . Start ..] . IndexOf ( DelimiterSpan ) ;
87+ length = DelimiterSpan . Length ;
88+ break ;
89+
90+ case SpanSplitEnumeratorMode . EmptySequence :
91+ index = - 1 ;
92+ length = 1 ;
93+ break ;
94+
95+ #if NET8_0
96+ case SpanSplitEnumeratorMode . SearchValues:
97+ index = Span [ Current . Start ..] . IndexOfAny ( SearchValues ) ;
98+ length = 1 ;
99+ break ;
100+ #endif
101+ default :
102+ return false ;
103+ }
104+
105+ if ( index < 0 )
106+ {
107+ Current = new Range ( Span . Length , Span . Length ) ;
108+ mode = ( SpanSplitEnumeratorMode ) ( - 1 ) ;
109+ return true ;
110+ }
111+
112+ Current = new Range ( Current . End . Value + length , Current . Start . Value + index ) ;
113+
114+ return true ;
115+ }
116+ }
117+
118+ internal enum SpanSplitEnumeratorMode
119+ {
120+ Delimiter ,
121+ Any ,
122+ Sequence ,
123+ EmptySequence ,
124+ SearchValues
125+ }
126+ }
127+ }
0 commit comments