Skip to content

Commit 6b31822

Browse files
committed
Merge branch 'temp' into dev
2 parents 12fa2e5 + 25a53a8 commit 6b31822

15 files changed

+602
-493
lines changed

src/CountExceedingBehaviour.cs

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,78 @@
1-
namespace SpanExtensions
1+
using System;
2+
using System.Globalization;
3+
4+
namespace SpanExtensions
25
{
36
/// <summary>
4-
/// Defines the behaviour of a split operation when there are more split instances than there may be.
7+
/// Defines the behaviour of a split operation when there are more split instances than desired.
58
/// </summary>
69
public enum CountExceedingBehaviour
710
{
811
/// <summary>
9-
/// The last element returned will be all the remaining elements appended as one.
12+
/// The last split returned will include all the remaining elements.
1013
/// </summary>
1114
AppendRemainingElements,
1215
/// <summary>
13-
/// Every split instance more than permitted will not be returned.
16+
/// Splits after the desired split count will be cut.
1417
/// </summary>
1518
CutRemainingElements
1619
}
17-
}
20+
21+
/// <summary>
22+
/// Extension methods for <see cref="CountExceedingBehaviour"/>.
23+
/// </summary>
24+
static class CountExceedingBehaviourExtensions
25+
{
26+
static string? CountExceedingBehaviourInvalidFormat;
27+
28+
/// <summary>
29+
/// Validates whether a specified value is a valid <see cref="CountExceedingBehaviour"/>.
30+
/// </summary>
31+
/// <param name="countExceedingBehaviour">The <see cref="CountExceedingBehaviour"/> to validate.</param>
32+
/// <returns>The specified <see cref="CountExceedingBehaviour"/> if valid.</returns>
33+
/// <exception cref="ArgumentException">If <paramref name="countExceedingBehaviour"/> is not valid.</exception>
34+
public static CountExceedingBehaviour ThrowIfInvalid(this CountExceedingBehaviour countExceedingBehaviour)
35+
{
36+
#if NET5_0_OR_GREATER
37+
if(!Enum.IsDefined(countExceedingBehaviour))
38+
#else
39+
if(!Enum.IsDefined(typeof(CountExceedingBehaviour), countExceedingBehaviour))
40+
#endif
41+
{
42+
if(CountExceedingBehaviourInvalidFormat == null)
43+
{
44+
#if NET5_0_OR_GREATER
45+
string[] names = Enum.GetNames<CountExceedingBehaviour>();
46+
#else
47+
string[] names = Enum.GetNames(typeof(CountExceedingBehaviour));
48+
#endif
49+
CountExceedingBehaviourInvalidFormat = $"{nameof(CountExceedingBehaviour)} doesn't define an option with the value '{{0}}'. Valid values are {string.Join(", ", names)}.";
50+
}
51+
52+
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, CountExceedingBehaviourInvalidFormat, (int)countExceedingBehaviour), nameof(countExceedingBehaviour));
53+
}
54+
55+
return countExceedingBehaviour;
56+
}
57+
58+
/// <summary>
59+
/// Determines whether the current instance is <see cref="CountExceedingBehaviour.AppendRemainingElements"/>.
60+
/// </summary>
61+
/// <param name="countExceedingBehaviour">The <see cref="CountExceedingBehaviour"/> instance to test.</param>
62+
/// <returns><see langword="true"/> if <paramref name="countExceedingBehaviour"/> is <see cref="CountExceedingBehaviour.AppendRemainingElements"/>; <see langword="false"/> otherwise.</returns>
63+
public static bool IsAppendRemainingElements(this CountExceedingBehaviour countExceedingBehaviour)
64+
{
65+
return countExceedingBehaviour == CountExceedingBehaviour.AppendRemainingElements;
66+
}
67+
68+
/// <summary>
69+
/// Determines whether the current instance is <see cref="CountExceedingBehaviour.CutRemainingElements"/>.
70+
/// </summary>
71+
/// <param name="countExceedingBehaviour">The <see cref="CountExceedingBehaviour"/> instance to test.</param>
72+
/// <returns><see langword="true"/> if <paramref name="countExceedingBehaviour"/> is <see cref="CountExceedingBehaviour.CutRemainingElements"/>; <see langword="false"/> otherwise.</returns>
73+
public static bool IsCutRemainingElements(this CountExceedingBehaviour countExceedingBehaviour)
74+
{
75+
return countExceedingBehaviour == CountExceedingBehaviour.CutRemainingElements;
76+
}
77+
}
78+
}

src/Enumerators/Split/SpanSplitEnumerator.cs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ namespace SpanExtensions.Enumerators
1010
{
1111
ReadOnlySpan<T> Span;
1212
readonly T Delimiter;
13-
bool enumerationDone;
13+
const int DelimiterLength = 1;
14+
bool EnumerationDone;
1415

1516
/// <summary>
1617
/// Gets the element in the collection at the current position of the enumerator.
@@ -26,8 +27,8 @@ public SpanSplitEnumerator(ReadOnlySpan<T> source, T delimiter)
2627
{
2728
Span = source;
2829
Delimiter = delimiter;
30+
EnumerationDone = false;
2931
Current = default;
30-
enumerationDone = false;
3132
}
3233

3334
/// <summary>
@@ -44,22 +45,25 @@ public readonly SpanSplitEnumerator<T> GetEnumerator()
4445
/// <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>
4546
public bool MoveNext()
4647
{
47-
if(enumerationDone)
48+
if(EnumerationDone)
4849
{
4950
return false;
5051
}
5152

52-
ReadOnlySpan<T> span = Span;
53-
int index = span.IndexOf(Delimiter);
53+
int delimiterIndex = Span.IndexOf(Delimiter);
5454

55-
if(index == -1 || index >= span.Length)
55+
if(delimiterIndex == -1)
5656
{
57-
enumerationDone = true;
58-
Current = span;
57+
EnumerationDone = true;
58+
59+
Current = Span;
60+
5961
return true;
6062
}
61-
Current = span[..index];
62-
Span = span[(index + 1)..];
63+
64+
Current = Span[..delimiterIndex];
65+
Span = Span[(delimiterIndex + DelimiterLength)..];
66+
6367
return true;
6468
}
6569
}

src/Enumerators/Split/SpanSplitStringSplitOptionsEnumerator.cs

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ public ref struct SpanSplitStringSplitOptionsEnumerator
99
{
1010
ReadOnlySpan<char> Span;
1111
readonly char Delimiter;
12-
readonly StringSplitOptions Options;
13-
bool enumerationDone;
12+
const int DelimiterLength = 1;
13+
readonly bool TrimEntries;
14+
readonly bool RemoveEmptyEntries;
15+
bool EnumerationDone;
1416

1517
/// <summary>
1618
/// Gets the element in the collection at the current position of the enumerator.
@@ -27,9 +29,10 @@ public SpanSplitStringSplitOptionsEnumerator(ReadOnlySpan<char> source, char del
2729
{
2830
Span = source;
2931
Delimiter = delimiter;
30-
Options = options;
32+
TrimEntries = options.ThrowIfInvalid().IsTrimEntriesSet();
33+
RemoveEmptyEntries = options.IsRemoveEmptyEntriesSet();
34+
EnumerationDone = false;
3135
Current = default;
32-
enumerationDone = false;
3336
}
3437

3538
/// <summary>
@@ -46,49 +49,44 @@ public readonly SpanSplitStringSplitOptionsEnumerator GetEnumerator()
4649
/// <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>
4750
public bool MoveNext()
4851
{
49-
if(enumerationDone)
52+
if(EnumerationDone)
5053
{
5154
return false;
5255
}
5356

54-
ReadOnlySpan<char> span = Span;
55-
int index = span.IndexOf(Delimiter);
56-
57-
if(index == -1 || index >= span.Length)
58-
{
59-
enumerationDone = true;
60-
Current = span;
61-
return true;
62-
}
63-
Current = span[..index];
64-
#if NET5_0_OR_GREATER
65-
if(Options.HasFlag(StringSplitOptions.TrimEntries))
57+
while(true) // if RemoveEmptyEntries options flag is set, repeat until a non-empty span is found, or the end is reached
6658
{
67-
Current = Current.Trim();
68-
}
69-
#endif
70-
if(Options.HasFlag(StringSplitOptions.RemoveEmptyEntries))
71-
{
72-
if(Current.IsEmpty)
59+
int delimiterIndex = Span.IndexOf(Delimiter);
60+
61+
if(delimiterIndex == -1)
7362
{
74-
Span = span[(index + 1)..];
75-
if(Span.IsEmpty)
63+
EnumerationDone = true;
64+
65+
Current = Span;
66+
67+
if(TrimEntries)
7668
{
77-
enumerationDone = true;
78-
return false;
69+
Current = Current.Trim();
7970
}
80-
return MoveNext();
71+
72+
return !(RemoveEmptyEntries && Current.IsEmpty);
8173
}
8274

83-
Span = span[(index + 1)..];
84-
if(Span.IsEmpty)
75+
Current = Span[..delimiterIndex];
76+
Span = Span[(delimiterIndex + DelimiterLength)..];
77+
78+
if(TrimEntries)
8579
{
86-
enumerationDone = true;
80+
Current = Current.Trim();
8781
}
82+
83+
if(RemoveEmptyEntries && Current.IsEmpty)
84+
{
85+
continue;
86+
}
87+
8888
return true;
8989
}
90-
Span = span[(index + 1)..];
91-
return true;
9290
}
9391
}
9492
}

0 commit comments

Comments
 (0)