Skip to content

Commit 0cc8423

Browse files
committed
added SpanSplitEnumerator
1 parent c95b634 commit 0cc8423

File tree

2 files changed

+128
-1
lines changed

2 files changed

+128
-1
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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+
}

src/ExceptionHelpers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ static ExceptionHelpers()
2323
combination |= flag;
2424
}
2525

26-
NegatedCombinationOfAllValidStringSplitOptions = (StringSplitOptions) ~combination;
26+
NegatedCombinationOfAllValidStringSplitOptions = (StringSplitOptions)~combination;
2727
}
2828

2929
internal static void ThrowIfGreaterThanOrEqual<T>(T value, T other,

0 commit comments

Comments
 (0)