diff --git a/src/CountExceedingBehaviour.cs b/src/CountExceedingBehaviour.cs
index eacc395..f89443e 100644
--- a/src/CountExceedingBehaviour.cs
+++ b/src/CountExceedingBehaviour.cs
@@ -1,17 +1,78 @@
-namespace SpanExtensions
+using System;
+using System.Globalization;
+
+namespace SpanExtensions
{
///
- /// Defines the behaviour of a split operation when there are more split instances than there may be.
- ///
+ /// Defines the behaviour of a split operation when there are more split instances than desired.
+ ///
public enum CountExceedingBehaviour
{
///
- /// The last element returned will be all the remaining elements appended as one.
+ /// The last split returned will include all the remaining elements.
///
- AppendLastElements,
+ AppendRemainingElements,
///
- /// Every split instance more than permitted will not be returned.
- ///
- CutLastElements
+ /// Splits after the desired split count will be cut.
+ ///
+ CutRemainingElements
+ }
+
+ ///
+ /// Extension methods for .
+ ///
+ static class CountExceedingBehaviourExtensions
+ {
+ static string? CountExceedingBehaviourInvalidFormat;
+
+ ///
+ /// Validates whether a specified value is a valid .
+ ///
+ /// The to validate.
+ /// The specified if valid.
+ /// If is not valid.
+ public static CountExceedingBehaviour ThrowIfInvalid(this CountExceedingBehaviour countExceedingBehaviour)
+ {
+#if NET5_0_OR_GREATER
+ if(!Enum.IsDefined(countExceedingBehaviour))
+#else
+ if(!Enum.IsDefined(typeof(CountExceedingBehaviour), countExceedingBehaviour))
+#endif
+ {
+ if(CountExceedingBehaviourInvalidFormat == null)
+ {
+#if NET5_0_OR_GREATER
+ string[] names = Enum.GetNames();
+#else
+ string[] names = Enum.GetNames(typeof(CountExceedingBehaviour));
+#endif
+ CountExceedingBehaviourInvalidFormat = $"{nameof(CountExceedingBehaviour)} doesn't define an option with the value '{{0}}'. Valid values are {string.Join(", ", names)}.";
+ }
+
+ throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, CountExceedingBehaviourInvalidFormat, (int)countExceedingBehaviour), nameof(countExceedingBehaviour));
+ }
+
+ return countExceedingBehaviour;
+ }
+
+ ///
+ /// Determines whether the current instance is .
+ ///
+ /// The instance to test.
+ /// if is ; otherwise.
+ public static bool IsAppendRemainingElements(this CountExceedingBehaviour countExceedingBehaviour)
+ {
+ return countExceedingBehaviour == CountExceedingBehaviour.AppendRemainingElements;
+ }
+
+ ///
+ /// Determines whether the current instance is .
+ ///
+ /// The instance to test.
+ /// if is ; otherwise.
+ public static bool IsCutRemainingElements(this CountExceedingBehaviour countExceedingBehaviour)
+ {
+ return countExceedingBehaviour == CountExceedingBehaviour.CutRemainingElements;
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/Enumerators/Split/SpanSplitEnumerator.cs b/src/Enumerators/Split/SpanSplitEnumerator.cs
index 0fafb2b..7d16683 100644
--- a/src/Enumerators/Split/SpanSplitEnumerator.cs
+++ b/src/Enumerators/Split/SpanSplitEnumerator.cs
@@ -10,7 +10,8 @@ namespace SpanExtensions.Enumerators
{
ReadOnlySpan Span;
readonly T Delimiter;
- bool enumerationDone;
+ const int DelimiterLength = 1;
+ bool EnumerationDone;
///
/// Gets the element in the collection at the current position of the enumerator.
@@ -26,8 +27,8 @@ public SpanSplitEnumerator(ReadOnlySpan source, T delimiter)
{
Span = source;
Delimiter = delimiter;
+ EnumerationDone = false;
Current = default;
- enumerationDone = false;
}
///
@@ -44,22 +45,25 @@ public readonly SpanSplitEnumerator GetEnumerator()
/// if the enumerator was successfully advanced to the next element; if the enumerator has passed the end of the collection.
public bool MoveNext()
{
- if(enumerationDone)
+ if(EnumerationDone)
{
return false;
}
- ReadOnlySpan span = Span;
- int index = span.IndexOf(Delimiter);
+ int delimiterIndex = Span.IndexOf(Delimiter);
- if(index == -1 || index >= span.Length)
+ if(delimiterIndex == -1)
{
- enumerationDone = true;
- Current = span;
+ EnumerationDone = true;
+
+ Current = Span;
+
return true;
}
- Current = span[..index];
- Span = span[(index + 1)..];
+
+ Current = Span[..delimiterIndex];
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+
return true;
}
}
diff --git a/src/Enumerators/Split/SpanSplitStringSplitOptionsEnumerator.cs b/src/Enumerators/Split/SpanSplitStringSplitOptionsEnumerator.cs
index 3248861..0b2118c 100644
--- a/src/Enumerators/Split/SpanSplitStringSplitOptionsEnumerator.cs
+++ b/src/Enumerators/Split/SpanSplitStringSplitOptionsEnumerator.cs
@@ -9,8 +9,10 @@ public ref struct SpanSplitStringSplitOptionsEnumerator
{
ReadOnlySpan Span;
readonly char Delimiter;
- readonly StringSplitOptions Options;
- bool enumerationDone;
+ const int DelimiterLength = 1;
+ readonly bool TrimEntries;
+ readonly bool RemoveEmptyEntries;
+ bool EnumerationDone;
///
/// Gets the element in the collection at the current position of the enumerator.
@@ -27,9 +29,10 @@ public SpanSplitStringSplitOptionsEnumerator(ReadOnlySpan source, char del
{
Span = source;
Delimiter = delimiter;
- Options = options;
+ TrimEntries = options.ThrowIfInvalid().IsTrimEntriesSet();
+ RemoveEmptyEntries = options.IsRemoveEmptyEntriesSet();
+ EnumerationDone = false;
Current = default;
- enumerationDone = false;
}
///
@@ -46,49 +49,44 @@ public readonly SpanSplitStringSplitOptionsEnumerator GetEnumerator()
/// if the enumerator was successfully advanced to the next element; if the enumerator has passed the end of the collection.
public bool MoveNext()
{
- if(enumerationDone)
+ if(EnumerationDone)
{
return false;
}
- ReadOnlySpan span = Span;
- int index = span.IndexOf(Delimiter);
-
- if(index == -1 || index >= span.Length)
- {
- enumerationDone = true;
- Current = span;
- return true;
- }
- Current = span[..index];
-#if NET5_0_OR_GREATER
- if(Options.HasFlag(StringSplitOptions.TrimEntries))
+ while(true) // if RemoveEmptyEntries options flag is set, repeat until a non-empty span is found, or the end is reached
{
- Current = Current.Trim();
- }
-#endif
- if(Options.HasFlag(StringSplitOptions.RemoveEmptyEntries))
- {
- if(Current.IsEmpty)
+ int delimiterIndex = Span.IndexOf(Delimiter);
+
+ if(delimiterIndex == -1)
{
- Span = span[(index + 1)..];
- if(Span.IsEmpty)
+ EnumerationDone = true;
+
+ Current = Span;
+
+ if(TrimEntries)
{
- enumerationDone = true;
- return false;
+ Current = Current.Trim();
}
- return MoveNext();
+
+ return !(RemoveEmptyEntries && Current.IsEmpty);
}
- Span = span[(index + 1)..];
- if(Span.IsEmpty)
+ Current = Span[..delimiterIndex];
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+
+ if(TrimEntries)
{
- enumerationDone = true;
+ Current = Current.Trim();
}
+
+ if(RemoveEmptyEntries && Current.IsEmpty)
+ {
+ continue;
+ }
+
return true;
}
- Span = span[(index + 1)..];
- return true;
}
}
}
\ No newline at end of file
diff --git a/src/Enumerators/Split/SpanSplitStringSplitOptionsWithCountEnumerator.cs b/src/Enumerators/Split/SpanSplitStringSplitOptionsWithCountEnumerator.cs
index 231e568..44731ec 100644
--- a/src/Enumerators/Split/SpanSplitStringSplitOptionsWithCountEnumerator.cs
+++ b/src/Enumerators/Split/SpanSplitStringSplitOptionsWithCountEnumerator.cs
@@ -9,12 +9,12 @@ public ref struct SpanSplitStringSplitOptionsWithCountEnumerator
{
ReadOnlySpan Span;
readonly char Delimiter;
- readonly StringSplitOptions Options;
- readonly int Count;
+ const int DelimiterLength = 1;
+ readonly bool TrimEntries;
+ readonly bool RemoveEmptyEntries;
readonly CountExceedingBehaviour CountExceedingBehaviour;
- int currentCount;
- bool enumerationDone;
- readonly int CountMinusOne;
+ int CurrentCount;
+ bool EnumerationDone;
///
/// Gets the element in the collection at the current position of the enumerator.
@@ -29,17 +29,21 @@ public ref struct SpanSplitStringSplitOptionsWithCountEnumerator
/// The maximum number of sub-ReadOnlySpans to split into.
/// A bitwise combination of the enumeration values that specifies whether to trim results and include empty results.
/// The handling of the instances more than count.
- public SpanSplitStringSplitOptionsWithCountEnumerator(ReadOnlySpan source, char delimiter, int count, StringSplitOptions options, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements)
+ public SpanSplitStringSplitOptionsWithCountEnumerator(ReadOnlySpan source, char delimiter, int count, StringSplitOptions options, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements)
{
Span = source;
Delimiter = delimiter;
- Count = count;
- CountExceedingBehaviour = countExceedingBehaviour;
- Options = options;
+ CurrentCount = count.ThrowIfNegative();
+ TrimEntries = options.ThrowIfInvalid().IsTrimEntriesSet();
+ RemoveEmptyEntries = options.IsRemoveEmptyEntriesSet();
+ CountExceedingBehaviour = countExceedingBehaviour.ThrowIfInvalid();
+ EnumerationDone = count == 0;
Current = default;
- currentCount = 0;
- enumerationDone = false;
- CountMinusOne = Math.Max(Count - 1, 0);
+
+ if(count == 1) // special case
+ {
+ CurrentCount = 0;
+ }
}
///
@@ -56,75 +60,72 @@ public readonly SpanSplitStringSplitOptionsWithCountEnumerator GetEnumerator()
/// if the enumerator was successfully advanced to the next element; if the enumerator has passed the end of the collection.
public bool MoveNext()
{
- if(enumerationDone)
+ if(EnumerationDone)
{
return false;
}
- ReadOnlySpan span = Span;
- if(currentCount == Count)
+ while(true) // if RemoveEmptyEntries options flag is set, repeat until a non-empty span is found, or the end is reached
{
- return false;
- }
- int index = span.IndexOf(Delimiter);
+ int delimiterIndex = Span.IndexOf(Delimiter);
- switch(CountExceedingBehaviour)
- {
- case CountExceedingBehaviour.CutLastElements:
- break;
- case CountExceedingBehaviour.AppendLastElements:
- if(currentCount == CountMinusOne)
+ if(delimiterIndex == -1 || CurrentCount <= 1)
+ {
+ EnumerationDone = true;
+
+ if(CurrentCount != 0 && delimiterIndex != -1 && RemoveEmptyEntries) // skip all empty (after trimming if necessary) entries from the left
{
- ReadOnlySpan lower = span[..index];
- ReadOnlySpan upper = span[(index + 1)..];
- Span temp = new char[lower.Length + upper.Length];
- lower.CopyTo(temp[..index]);
- upper.CopyTo(temp[index..]);
- Current = temp;
- currentCount++;
- return true;
+ do
+ {
+ ReadOnlySpan beforeDelimiter = Span[..delimiterIndex];
+
+ if(TrimEntries ? beforeDelimiter.IsWhiteSpace() : beforeDelimiter.IsEmpty)
+ {
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+ delimiterIndex = Span.IndexOf(Delimiter);
+
+ continue;
+ }
+
+ if(CountExceedingBehaviour.IsCutRemainingElements())
+ {
+ Span = beforeDelimiter;
+ }
+ break;
+ }
+ while(delimiterIndex != -1);
+
+ Current = Span;
+ }
+ else
+ {
+ Current = delimiterIndex == -1 || CountExceedingBehaviour.IsAppendRemainingElements() ? Span : Span[..delimiterIndex];
}
- break;
- default:
- throw new InvalidCountExceedingBehaviourException(CountExceedingBehaviour);
- }
- if(index == -1 || index >= span.Length)
- {
- enumerationDone = true;
- Current = span;
- return true;
- }
- currentCount++;
- Current = span[..index];
-#if NET5_0_OR_GREATER
- if(Options.HasFlag(StringSplitOptions.TrimEntries))
- {
- Current = Current.Trim();
- }
-#endif
- if(Options.HasFlag(StringSplitOptions.RemoveEmptyEntries))
- {
- if(Current.IsEmpty)
- {
- Span = span[(index + 1)..];
- if(Span.IsEmpty)
+ if(TrimEntries)
{
- enumerationDone = true;
- return false;
+ Current = Current.Trim();
}
- return MoveNext();
+
+ return !(RemoveEmptyEntries && Current.IsEmpty);
}
- Span = span[(index + 1)..];
- if(Span.IsEmpty)
+ Current = Span[..delimiterIndex];
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+
+ if(TrimEntries)
{
- enumerationDone = true;
+ Current = Current.Trim();
}
+
+ if(RemoveEmptyEntries && Current.IsEmpty)
+ {
+ continue;
+ }
+
+ CurrentCount--;
return true;
}
- Span = span[(index + 1)..];
- return true;
}
}
}
\ No newline at end of file
diff --git a/src/Enumerators/Split/SpanSplitWithCountEnumerator.cs b/src/Enumerators/Split/SpanSplitWithCountEnumerator.cs
index e65a913..9bf1cf6 100644
--- a/src/Enumerators/Split/SpanSplitWithCountEnumerator.cs
+++ b/src/Enumerators/Split/SpanSplitWithCountEnumerator.cs
@@ -6,15 +6,14 @@ namespace SpanExtensions.Enumerators
/// Supports iteration over a by splitting it a a specified delimiter of type with an upper limit of splits performed.
///
/// The type of elements in the enumerated .
- public ref struct SpanSplitWithCountEnumerator where T : IEquatable
+ public ref struct SpanSplitWithCountEnumerator where T : IEquatable
{
ReadOnlySpan Span;
readonly T Delimiter;
- readonly int Count;
- readonly CountExceedingBehaviour CountExceedingBehaviour;
- int currentCount;
- bool enumerationDone;
- readonly int CountMinusOne;
+ const int DelimiterLength = 1;
+ readonly CountExceedingBehaviour CountExceedingBehaviour;
+ int CurrentCount;
+ bool EnumerationDone;
///
/// Gets the element in the collection at the current position of the enumerator.
@@ -28,16 +27,14 @@ namespace SpanExtensions.Enumerators
/// An instance of that delimits the various sub-ReadOnlySpans in .
/// The maximum number of sub-ReadOnlySpans to split into.
/// The handling of the instances more than count.
- public SpanSplitWithCountEnumerator(ReadOnlySpan source, T delimiter, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements)
+ public SpanSplitWithCountEnumerator(ReadOnlySpan source, T delimiter, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements)
{
Span = source;
Delimiter = delimiter;
- Count = count;
- CountExceedingBehaviour = countExceedingBehaviour;
+ CurrentCount = count.ThrowIfNegative();
+ CountExceedingBehaviour = countExceedingBehaviour.ThrowIfInvalid();
+ EnumerationDone = count == 0;
Current = default;
- currentCount = 0;
- enumerationDone = false;
- CountMinusOne = Math.Max(Count - 1, 0);
}
///
@@ -54,46 +51,26 @@ public readonly SpanSplitWithCountEnumerator GetEnumerator()
/// if the enumerator was successfully advanced to the next element; if the enumerator has passed the end of the collection.
public bool MoveNext()
{
- if(enumerationDone)
+ if(EnumerationDone)
{
return false;
}
- ReadOnlySpan span = Span;
- if(currentCount == Count)
- {
- return false;
- }
- int index = span.IndexOf(Delimiter);
- switch(CountExceedingBehaviour)
- {
- case CountExceedingBehaviour.CutLastElements:
- break;
- case CountExceedingBehaviour.AppendLastElements:
- if(currentCount == CountMinusOne)
- {
- ReadOnlySpan lower = span[..index];
- ReadOnlySpan upper = span[(index + 1)..];
- Span temp = new T[lower.Length + upper.Length];
- lower.CopyTo(temp[..index]);
- upper.CopyTo(temp[index..]);
- Current = temp;
- currentCount++;
- return true;
- }
- break;
- default:
- throw new InvalidCountExceedingBehaviourException(CountExceedingBehaviour);
- }
- if(index == -1 || index >= span.Length)
+ int delimiterIndex = Span.IndexOf(Delimiter);
+
+ if(delimiterIndex == -1 || CurrentCount == 1)
{
- enumerationDone = true;
- Current = span;
+ EnumerationDone = true;
+
+ Current = delimiterIndex == -1 || CountExceedingBehaviour.IsAppendRemainingElements() ? Span : Span[..delimiterIndex];
+
return true;
}
- currentCount++;
- Current = span[..index];
- Span = span[(index + 1)..];
+
+ Current = Span[..delimiterIndex];
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+
+ CurrentCount--;
return true;
}
}
diff --git a/src/Enumerators/SplitAny/SpanSplitAnyEnumerator.cs b/src/Enumerators/SplitAny/SpanSplitAnyEnumerator.cs
index 104361b..cf96c1b 100644
--- a/src/Enumerators/SplitAny/SpanSplitAnyEnumerator.cs
+++ b/src/Enumerators/SplitAny/SpanSplitAnyEnumerator.cs
@@ -11,7 +11,8 @@ namespace SpanExtensions.Enumerators
{
ReadOnlySpan Span;
readonly ReadOnlySpan Delimiters;
- bool enumerationDone;
+ const int DelimiterLength = 1;
+ bool EnumerationDone;
///
/// Gets the element in the collection at the current position of the enumerator.
@@ -27,8 +28,8 @@ public SpanSplitAnyEnumerator(ReadOnlySpan source, ReadOnlySpan delimiters
{
Span = source;
Delimiters = delimiters;
+ EnumerationDone = false;
Current = default;
- enumerationDone = false;
}
///
@@ -45,22 +46,25 @@ public readonly SpanSplitAnyEnumerator GetEnumerator()
/// if the enumerator was successfully advanced to the next element; if the enumerator has passed the end of the collection.
public bool MoveNext()
{
- if(enumerationDone)
+ if(EnumerationDone)
{
return false;
}
- ReadOnlySpan span = Span;
- int index = span.IndexOfAny(Delimiters);
+ int delimiterIndex = Span.IndexOfAny(Delimiters);
- if(index == -1 || index >= span.Length)
+ if(delimiterIndex == -1)
{
- enumerationDone = true;
- Current = span;
+ EnumerationDone = true;
+
+ Current = Span;
+
return true;
}
- Current = span[..index];
- Span = span[(index + 1)..];
+
+ Current = Span[..delimiterIndex];
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+
return true;
}
}
diff --git a/src/Enumerators/SplitAny/SpanSplitAnyStringSplitOptionsEnumerator.cs b/src/Enumerators/SplitAny/SpanSplitAnyStringSplitOptionsEnumerator.cs
index e49cd02..1cf2843 100644
--- a/src/Enumerators/SplitAny/SpanSplitAnyStringSplitOptionsEnumerator.cs
+++ b/src/Enumerators/SplitAny/SpanSplitAnyStringSplitOptionsEnumerator.cs
@@ -9,8 +9,10 @@ public ref struct SpanSplitAnyStringSplitOptionsEnumerator
{
ReadOnlySpan Span;
readonly ReadOnlySpan Delimiters;
- readonly StringSplitOptions Options;
- bool enumerationDone;
+ const int DelimiterLength = 1;
+ readonly bool TrimEntries;
+ readonly bool RemoveEmptyEntries;
+ bool EnumerationDone;
///
/// Gets the element in the collection at the current position of the enumerator.
@@ -27,9 +29,10 @@ public SpanSplitAnyStringSplitOptionsEnumerator(ReadOnlySpan source, ReadO
{
Span = source;
Delimiters = delimiters;
- Options = options;
+ TrimEntries = options.ThrowIfInvalid().IsTrimEntriesSet();
+ RemoveEmptyEntries = options.IsRemoveEmptyEntriesSet();
+ EnumerationDone = false;
Current = default;
- enumerationDone = false;
}
///
@@ -46,50 +49,44 @@ public readonly SpanSplitAnyStringSplitOptionsEnumerator GetEnumerator()
/// if the enumerator was successfully advanced to the next element; if the enumerator has passed the end of the collection.
public bool MoveNext()
{
- if(enumerationDone)
+ if(EnumerationDone)
{
return false;
}
- ReadOnlySpan span = Span;
- int index = span.IndexOfAny(Delimiters);
-
- if(index == -1 || index >= span.Length)
+ while(true) // if RemoveEmptyEntries options flag is set, repeat until a non-empty span is found, or the end is reached
{
- enumerationDone = true;
- Current = span;
- return true;
- }
- Current = span[..index];
+ int delimiterIndex = Span.IndexOfAny(Delimiters);
-#if NET5_0_OR_GREATER
- if(Options.HasFlag(StringSplitOptions.TrimEntries))
- {
- Current = Current.Trim();
- }
-#endif
- if(Options.HasFlag(StringSplitOptions.RemoveEmptyEntries))
- {
- if(Current.IsEmpty)
+ if(delimiterIndex == -1)
{
- Span = span[(index + 1)..];
- if(Span.IsEmpty)
+ EnumerationDone = true;
+
+ Current = Span;
+
+ if(TrimEntries)
{
- enumerationDone = true;
- return false;
+ Current = Current.Trim();
}
- return MoveNext();
+
+ return !(RemoveEmptyEntries && Current.IsEmpty);
}
- Span = span[(index + 1)..];
- if(Span.IsEmpty)
+ Current = Span[..delimiterIndex];
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+
+ if(TrimEntries)
{
- enumerationDone = true;
+ Current = Current.Trim();
}
+
+ if(RemoveEmptyEntries && Current.IsEmpty)
+ {
+ continue;
+ }
+
return true;
}
- Span = span[(index + 1)..];
- return true;
}
}
}
\ No newline at end of file
diff --git a/src/Enumerators/SplitAny/SpanSplitAnyStringSplitOptionsWithCountEnumerator.cs b/src/Enumerators/SplitAny/SpanSplitAnyStringSplitOptionsWithCountEnumerator.cs
index 40af53a..45af869 100644
--- a/src/Enumerators/SplitAny/SpanSplitAnyStringSplitOptionsWithCountEnumerator.cs
+++ b/src/Enumerators/SplitAny/SpanSplitAnyStringSplitOptionsWithCountEnumerator.cs
@@ -9,12 +9,12 @@ public ref struct SpanSplitAnyStringSplitOptionsWithCountEnumerator
{
ReadOnlySpan Span;
readonly ReadOnlySpan Delimiters;
- readonly StringSplitOptions Options;
- readonly int Count;
+ const int DelimiterLength = 1;
+ readonly bool TrimEntries;
+ readonly bool RemoveEmptyEntries;
readonly CountExceedingBehaviour CountExceedingBehaviour;
- int currentCount;
- bool enumerationDone;
- readonly int CountMinusOne;
+ int CurrentCount;
+ bool EnumerationDone;
///
/// Gets the element in the collection at the current position of the enumerator.
@@ -29,17 +29,21 @@ public ref struct SpanSplitAnyStringSplitOptionsWithCountEnumerator
/// The maximum number of sub-ReadOnlySpans to split into.
/// A bitwise combination of the enumeration values that specifies whether to trim results and include empty results.
/// The handling of the instances more than count.
- public SpanSplitAnyStringSplitOptionsWithCountEnumerator(ReadOnlySpan source, ReadOnlySpan delimiters, int count, StringSplitOptions options, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements)
+ public SpanSplitAnyStringSplitOptionsWithCountEnumerator(ReadOnlySpan source, ReadOnlySpan delimiters, int count, StringSplitOptions options, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements)
{
Span = source;
Delimiters = delimiters;
- Count = count;
- Options = options;
- CountExceedingBehaviour = countExceedingBehaviour;
+ CurrentCount = count.ThrowIfNegative();
+ TrimEntries = options.ThrowIfInvalid().IsTrimEntriesSet();
+ RemoveEmptyEntries = options.IsRemoveEmptyEntriesSet();
+ CountExceedingBehaviour = countExceedingBehaviour.ThrowIfInvalid();
+ EnumerationDone = count == 0;
Current = default;
- currentCount = 0;
- enumerationDone = false;
- CountMinusOne = Math.Max(Count - 1, 0);
+
+ if(count == 1) // special case
+ {
+ CurrentCount = 0;
+ }
}
///
@@ -56,75 +60,72 @@ public readonly SpanSplitAnyStringSplitOptionsWithCountEnumerator GetEnumerator(
/// if the enumerator was successfully advanced to the next element; if the enumerator has passed the end of the collection.
public bool MoveNext()
{
- if(enumerationDone)
+ if(EnumerationDone)
{
return false;
}
- ReadOnlySpan span = Span;
- if(currentCount == Count)
+ while(true) // if RemoveEmptyEntries options flag is set, repeat until a non-empty span is found, or the end is reached
{
- return false;
- }
- int index = span.IndexOfAny(Delimiters);
+ int delimiterIndex = Span.IndexOfAny(Delimiters);
- switch(CountExceedingBehaviour)
- {
- case CountExceedingBehaviour.CutLastElements:
- break;
- case CountExceedingBehaviour.AppendLastElements:
- if(currentCount == CountMinusOne)
+ if(delimiterIndex == -1 || CurrentCount <= 1)
+ {
+ EnumerationDone = true;
+
+ if(CurrentCount != 0 && delimiterIndex != -1 && RemoveEmptyEntries) // skip all empty (after trimming if necessary) entries from the left
{
- ReadOnlySpan lower = span[..index];
- ReadOnlySpan upper = span[(index + 1)..];
- Span temp = new char[lower.Length + upper.Length];
- lower.CopyTo(temp[..index]);
- upper.CopyTo(temp[index..]);
- Current = temp;
- currentCount++;
- return true;
+ do
+ {
+ ReadOnlySpan beforeDelimiter = Span[..delimiterIndex];
+
+ if(TrimEntries ? beforeDelimiter.IsWhiteSpace() : beforeDelimiter.IsEmpty)
+ {
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+ delimiterIndex = Span.IndexOfAny(Delimiters);
+
+ continue;
+ }
+
+ if(CountExceedingBehaviour.IsCutRemainingElements())
+ {
+ Span = beforeDelimiter;
+ }
+ break;
+ }
+ while(delimiterIndex != -1);
+
+ Current = Span;
+ }
+ else
+ {
+ Current = delimiterIndex == -1 || CountExceedingBehaviour.IsAppendRemainingElements() ? Span : Span[..delimiterIndex];
}
- break;
- default:
- throw new InvalidCountExceedingBehaviourException(CountExceedingBehaviour);
- }
- if(index == -1 || index >= span.Length)
- {
- enumerationDone = true;
- Current = span;
- return true;
- }
- currentCount++;
- Current = span[..index];
-#if NET5_0_OR_GREATER
- if(Options.HasFlag(StringSplitOptions.TrimEntries))
- {
- Current = Current.Trim();
- }
-#endif
- if(Options.HasFlag(StringSplitOptions.RemoveEmptyEntries))
- {
- if(Current.IsEmpty)
- {
- Span = span[(index + 1)..];
- if(Span.IsEmpty)
+ if(TrimEntries)
{
- enumerationDone = true;
- return false;
+ Current = Current.Trim();
}
- return MoveNext();
+
+ return !(RemoveEmptyEntries && Current.IsEmpty);
}
- Span = span[(index + 1)..];
- if(Span.IsEmpty)
+ Current = Span[..delimiterIndex];
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+
+ if(TrimEntries)
{
- enumerationDone = true;
+ Current = Current.Trim();
}
+
+ if(RemoveEmptyEntries && Current.IsEmpty)
+ {
+ continue;
+ }
+
+ CurrentCount--;
return true;
}
- Span = span[(index + 1)..];
- return true;
}
}
}
\ No newline at end of file
diff --git a/src/Enumerators/SplitAny/SpanSplitAnyWithCountEnumerator.cs b/src/Enumerators/SplitAny/SpanSplitAnyWithCountEnumerator.cs
index 79ead32..d7e0a19 100644
--- a/src/Enumerators/SplitAny/SpanSplitAnyWithCountEnumerator.cs
+++ b/src/Enumerators/SplitAny/SpanSplitAnyWithCountEnumerator.cs
@@ -10,11 +10,10 @@ namespace SpanExtensions.Enumerators
{
ReadOnlySpan Span;
readonly ReadOnlySpan Delimiters;
- readonly int Count;
+ const int DelimiterLength = 1;
readonly CountExceedingBehaviour CountExceedingBehaviour;
- int currentCount;
- bool enumerationDone;
- readonly int CountMinusOne;
+ int CurrentCount;
+ bool EnumerationDone;
///
/// Gets the element in the collection at the current position of the enumerator.
@@ -28,16 +27,14 @@ namespace SpanExtensions.Enumerators
/// A with the instances of that delimit the various sub-ReadOnlySpans in .
/// The maximum number of sub-ReadOnlySpans to split into.
/// The handling of the instances more than count.
- public SpanSplitAnyWithCountEnumerator(ReadOnlySpan source, ReadOnlySpan delimiters, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements)
+ public SpanSplitAnyWithCountEnumerator(ReadOnlySpan source, ReadOnlySpan delimiters, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements)
{
Span = source;
Delimiters = delimiters;
- Count = count;
- CountExceedingBehaviour = countExceedingBehaviour;
+ CurrentCount = count.ThrowIfNegative();
+ CountExceedingBehaviour = countExceedingBehaviour.ThrowIfInvalid();
+ EnumerationDone = count == 0;
Current = default;
- currentCount = 0;
- enumerationDone = false;
- CountMinusOne = Math.Max(Count - 1, 0);
}
///
@@ -54,46 +51,26 @@ public readonly SpanSplitAnyWithCountEnumerator GetEnumerator()
/// if the enumerator was successfully advanced to the next element; if the enumerator has passed the end of the collection.
public bool MoveNext()
{
- if(enumerationDone)
+ if(EnumerationDone)
{
return false;
}
- ReadOnlySpan span = Span;
- if(currentCount == Count)
- {
- return false;
- }
- int index = span.IndexOfAny(Delimiters);
- switch(CountExceedingBehaviour)
- {
- case CountExceedingBehaviour.CutLastElements:
- break;
- case CountExceedingBehaviour.AppendLastElements:
- if(currentCount == CountMinusOne)
- {
- ReadOnlySpan lower = span[..index];
- ReadOnlySpan upper = span[(index + 1)..];
- Span temp = new T[lower.Length + upper.Length];
- lower.CopyTo(temp[..index]);
- upper.CopyTo(temp[index..]);
- Current = temp;
- currentCount++;
- return true;
- }
- break;
- default:
- throw new InvalidCountExceedingBehaviourException(CountExceedingBehaviour);
- }
- if(index == -1 || index >= span.Length)
+ int delimiterIndex = Span.IndexOfAny(Delimiters);
+
+ if(delimiterIndex == -1 || CurrentCount == 1)
{
- enumerationDone = true;
- Current = span;
+ EnumerationDone = true;
+
+ Current = delimiterIndex == -1 || CountExceedingBehaviour.IsAppendRemainingElements() ? Span : Span[..delimiterIndex];
+
return true;
}
- currentCount++;
- Current = span[..index];
- Span = span[(index + 1)..];
+
+ Current = Span[..delimiterIndex];
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+
+ CurrentCount--;
return true;
}
}
diff --git a/src/Enumerators/SplitSequence/SpanSplitSequenceEnumerator.cs b/src/Enumerators/SplitSequence/SpanSplitSequenceEnumerator.cs
index 013936d..4dc24c9 100644
--- a/src/Enumerators/SplitSequence/SpanSplitSequenceEnumerator.cs
+++ b/src/Enumerators/SplitSequence/SpanSplitSequenceEnumerator.cs
@@ -10,7 +10,9 @@ namespace SpanExtensions.Enumerators
{
ReadOnlySpan Span;
readonly ReadOnlySpan Delimiter;
- bool enumerationDone;
+ readonly int DelimiterLength;
+ readonly bool DelimiterIsEmpty;
+ bool EnumerationDone;
///
/// Gets the element in the collection at the current position of the enumerator.
@@ -26,8 +28,10 @@ public SpanSplitSequenceEnumerator(ReadOnlySpan source, ReadOnlySpan delim
{
Span = source;
Delimiter = delimiter;
+ DelimiterLength = Delimiter.Length;
+ DelimiterIsEmpty = Delimiter.IsEmpty;
+ EnumerationDone = false;
Current = default;
- enumerationDone = false;
}
///
@@ -44,22 +48,25 @@ public readonly SpanSplitSequenceEnumerator GetEnumerator()
/// if the enumerator was successfully advanced to the next element; if the enumerator has passed the end of the collection.
public bool MoveNext()
{
- if(enumerationDone)
+ if(EnumerationDone)
{
return false;
}
- ReadOnlySpan span = Span;
- int index = span.IndexOf(Delimiter);
+ int delimiterIndex = Span.IndexOf(Delimiter);
- if(index == -1 || index >= span.Length)
+ if(delimiterIndex == -1 || DelimiterIsEmpty)
{
- enumerationDone = true;
- Current = span;
+ EnumerationDone = true;
+
+ Current = Span;
+
return true;
}
- Current = span[..index];
- Span = span[(index + Delimiter.Length)..];
+
+ Current = Span[..delimiterIndex];
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+
return true;
}
}
diff --git a/src/Enumerators/SplitSequence/SpanSplitSequenceStringSplitOptionsEnumerator.cs b/src/Enumerators/SplitSequence/SpanSplitSequenceStringSplitOptionsEnumerator.cs
index a7dad72..f7f13ab 100644
--- a/src/Enumerators/SplitSequence/SpanSplitSequenceStringSplitOptionsEnumerator.cs
+++ b/src/Enumerators/SplitSequence/SpanSplitSequenceStringSplitOptionsEnumerator.cs
@@ -9,8 +9,11 @@ public ref struct SpanSplitSequenceStringSplitOptionsEnumerator
{
ReadOnlySpan Span;
readonly ReadOnlySpan Delimiter;
- readonly StringSplitOptions Options;
- bool enumerationDone;
+ readonly int DelimiterLength;
+ readonly bool DelimiterIsEmpty;
+ readonly bool TrimEntries;
+ readonly bool RemoveEmptyEntries;
+ bool EnumerationDone;
///
/// Gets the element in the collection at the current position of the enumerator.
@@ -27,9 +30,12 @@ public SpanSplitSequenceStringSplitOptionsEnumerator(ReadOnlySpan source,
{
Span = source;
Delimiter = delimiter;
- Options = options;
+ DelimiterLength = Delimiter.Length;
+ DelimiterIsEmpty = Delimiter.IsEmpty;
+ TrimEntries = options.ThrowIfInvalid().IsTrimEntriesSet();
+ RemoveEmptyEntries = options.IsRemoveEmptyEntriesSet();
+ EnumerationDone = false;
Current = default;
- enumerationDone = false;
}
///
@@ -46,50 +52,44 @@ public readonly SpanSplitSequenceStringSplitOptionsEnumerator GetEnumerator()
/// if the enumerator was successfully advanced to the next element; if the enumerator has passed the end of the collection.
public bool MoveNext()
{
- if(enumerationDone)
+ if(EnumerationDone)
{
return false;
}
- ReadOnlySpan span = Span;
- int index = span.IndexOf(Delimiter);
-
- if(index == -1 || index >= span.Length)
+ while(true) // if RemoveEmptyEntries options flag is set, repeat until a non-empty span is found, or the end is reached
{
- enumerationDone = true;
- Current = span;
- return true;
- }
- Current = span[..index];
+ int delimiterIndex = Span.IndexOf(Delimiter);
-#if NET5_0_OR_GREATER
- if(Options.HasFlag(StringSplitOptions.TrimEntries))
- {
- Current = Current.Trim();
- }
-#endif
- if(Options.HasFlag(StringSplitOptions.RemoveEmptyEntries))
- {
- if(Current.IsEmpty)
+ if(delimiterIndex == -1 || DelimiterIsEmpty)
{
- Span = span[(index + Delimiter.Length)..];
- if(Span.IsEmpty)
+ EnumerationDone = true;
+
+ Current = Span;
+
+ if(TrimEntries)
{
- enumerationDone = true;
- return false;
+ Current = Current.Trim();
}
- return MoveNext();
+
+ return !(RemoveEmptyEntries && Current.IsEmpty);
}
- Span = span[(index + 1)..];
- if(Span.IsEmpty)
+ Current = Span[..delimiterIndex];
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+
+ if(TrimEntries)
{
- enumerationDone = true;
+ Current = Current.Trim();
}
+
+ if(RemoveEmptyEntries && Current.IsEmpty)
+ {
+ continue;
+ }
+
return true;
}
- Span = span[(index + Delimiter.Length)..];
- return true;
}
}
}
\ No newline at end of file
diff --git a/src/Enumerators/SplitSequence/SpanSplitSequenceStringSplitOptionsWithCountEnumerator.cs b/src/Enumerators/SplitSequence/SpanSplitSequenceStringSplitOptionsWithCountEnumerator.cs
index 7eb4ebe..065716b 100644
--- a/src/Enumerators/SplitSequence/SpanSplitSequenceStringSplitOptionsWithCountEnumerator.cs
+++ b/src/Enumerators/SplitSequence/SpanSplitSequenceStringSplitOptionsWithCountEnumerator.cs
@@ -9,12 +9,14 @@ public ref struct SpanSplitSequenceStringSplitOptionsWithCountEnumerator
{
ReadOnlySpan Span;
readonly ReadOnlySpan Delimiter;
- readonly StringSplitOptions Options;
- readonly int Count;
+ readonly int DelimiterLength;
+ readonly bool DelimiterIsEmpty;
+ readonly bool TrimEntries;
+ readonly bool RemoveEmptyEntries;
readonly CountExceedingBehaviour CountExceedingBehaviour;
- int currentCount;
- bool enumerationDone;
- readonly int CountMinusOne;
+ int CurrentCount;
+ bool EnumerationDone;
+
///
/// Gets the element in the collection at the current position of the enumerator.
///
@@ -25,20 +27,26 @@ public ref struct SpanSplitSequenceStringSplitOptionsWithCountEnumerator
///
/// The to be split.
/// An instance of that delimits the various sub-ReadOnlySpans in .
- /// A bitwise combination of the enumeration values that specifies whether to trim results and include empty results.
/// The maximum number of sub-ReadOnlySpans to split into.
+ /// A bitwise combination of the enumeration values that specifies whether to trim results and include empty results.
/// The handling of the instances more than count.
- public SpanSplitSequenceStringSplitOptionsWithCountEnumerator(ReadOnlySpan source, ReadOnlySpan delimiter, int count, StringSplitOptions options, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements)
+ public SpanSplitSequenceStringSplitOptionsWithCountEnumerator(ReadOnlySpan source, ReadOnlySpan delimiter, int count, StringSplitOptions options, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements)
{
Span = source;
Delimiter = delimiter;
- Count = count;
- Options = options;
- CountExceedingBehaviour = countExceedingBehaviour;
+ DelimiterLength = Delimiter.Length;
+ DelimiterIsEmpty = Delimiter.IsEmpty;
+ CurrentCount = DelimiterIsEmpty ? 0 : count.ThrowIfNegative();
+ TrimEntries = options.ThrowIfInvalid().IsTrimEntriesSet();
+ RemoveEmptyEntries = options.IsRemoveEmptyEntriesSet();
+ CountExceedingBehaviour = countExceedingBehaviour.ThrowIfInvalid();
+ EnumerationDone = count == 0;
Current = default;
- currentCount = 0;
- enumerationDone = false;
- CountMinusOne = Math.Max(Count - 1, 0);
+
+ if(count == 1) // special case
+ {
+ CurrentCount = 0;
+ }
}
///
@@ -55,75 +63,72 @@ public readonly SpanSplitSequenceStringSplitOptionsWithCountEnumerator GetEnumer
/// if the enumerator was successfully advanced to the next element; if the enumerator has passed the end of the collection.
public bool MoveNext()
{
- if(enumerationDone)
+ if(EnumerationDone)
{
return false;
}
- ReadOnlySpan span = Span;
- if(currentCount == Count)
+ while(true) // if RemoveEmptyEntries options flag is set, repeat until a non-empty span is found, or the end is reached
{
- return false;
- }
- int index = span.IndexOf(Delimiter);
+ int delimiterIndex = Span.IndexOf(Delimiter);
- switch(CountExceedingBehaviour)
- {
- case CountExceedingBehaviour.CutLastElements:
- break;
- case CountExceedingBehaviour.AppendLastElements:
- if(currentCount == CountMinusOne)
+ if(delimiterIndex == -1 || CurrentCount <= 1)
+ {
+ EnumerationDone = true;
+
+ if(CurrentCount != 0 && delimiterIndex != -1 && RemoveEmptyEntries) // skip all empty (after trimming if necessary) entries from the left
{
- ReadOnlySpan lower = span[..index];
- ReadOnlySpan upper = span[(index + Delimiter.Length)..];
- Span temp = new char[lower.Length + upper.Length];
- lower.CopyTo(temp[..index]);
- upper.CopyTo(temp[(index + Delimiter.Length - 1)..]);
- Current = temp;
- currentCount++;
- return true;
+ do
+ {
+ ReadOnlySpan beforeDelimiter = Span[..delimiterIndex];
+
+ if(TrimEntries ? beforeDelimiter.IsWhiteSpace() : beforeDelimiter.IsEmpty)
+ {
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+ delimiterIndex = Span.IndexOf(Delimiter);
+
+ continue;
+ }
+
+ if(CountExceedingBehaviour.IsCutRemainingElements())
+ {
+ Span = beforeDelimiter;
+ }
+ break;
+ }
+ while(delimiterIndex != -1);
+
+ Current = Span;
+ }
+ else
+ {
+ Current = delimiterIndex == -1 || CountExceedingBehaviour.IsAppendRemainingElements() || DelimiterIsEmpty ? Span : Span[..delimiterIndex];
}
- break;
- default:
- throw new InvalidCountExceedingBehaviourException(CountExceedingBehaviour);
- }
- if(index == -1 || index >= span.Length)
- {
- enumerationDone = true;
- Current = span;
- return true;
- }
- currentCount++;
- Current = span[..index];
-#if NET5_0_OR_GREATER
- if(Options.HasFlag(StringSplitOptions.TrimEntries))
- {
- Current = Current.Trim();
- }
-#endif
- if(Options.HasFlag(StringSplitOptions.RemoveEmptyEntries))
- {
- if(Current.IsEmpty)
- {
- Span = span[(index + Delimiter.Length)..];
- if(Span.IsEmpty)
+ if(TrimEntries)
{
- enumerationDone = true;
- return false;
+ Current = Current.Trim();
}
- return MoveNext();
+
+ return !(RemoveEmptyEntries && Current.IsEmpty);
}
- Span = span[(index + 1)..];
- if(Span.IsEmpty)
+ Current = Span[..delimiterIndex];
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+
+ if(TrimEntries)
{
- enumerationDone = true;
+ Current = Current.Trim();
}
+
+ if(RemoveEmptyEntries && Current.IsEmpty)
+ {
+ continue;
+ }
+
+ CurrentCount--;
return true;
}
- Span = span[(index + Delimiter.Length)..];
- return true;
}
}
}
\ No newline at end of file
diff --git a/src/Enumerators/SplitSequence/SpanSplitSequenceWithCountEnumerator.cs b/src/Enumerators/SplitSequence/SpanSplitSequenceWithCountEnumerator.cs
index 2af86d4..5c8274c 100644
--- a/src/Enumerators/SplitSequence/SpanSplitSequenceWithCountEnumerator.cs
+++ b/src/Enumerators/SplitSequence/SpanSplitSequenceWithCountEnumerator.cs
@@ -10,11 +10,11 @@ namespace SpanExtensions.Enumerators
{
ReadOnlySpan Span;
readonly ReadOnlySpan Delimiter;
- readonly int Count;
+ readonly int DelimiterLength;
+ readonly bool DelimiterIsEmpty;
readonly CountExceedingBehaviour CountExceedingBehaviour;
- int currentCount;
- bool enumerationDone;
- readonly int CountMinusOne;
+ int CurrentCount;
+ bool EnumerationDone;
///
/// Gets the element in the collection at the current position of the enumerator.
@@ -28,16 +28,16 @@ namespace SpanExtensions.Enumerators
/// An instance of that delimits the various sub-ReadOnlySpans in .
/// The maximum number of sub-ReadOnlySpans to split into.
/// The handling of the instances more than count.
- public SpanSplitSequenceWithCountEnumerator(ReadOnlySpan source, ReadOnlySpan delimiter, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements)
+ public SpanSplitSequenceWithCountEnumerator(ReadOnlySpan source, ReadOnlySpan delimiter, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements)
{
Span = source;
Delimiter = delimiter;
- Count = count;
- CountExceedingBehaviour = countExceedingBehaviour;
+ DelimiterLength = Delimiter.Length;
+ DelimiterIsEmpty = Delimiter.IsEmpty;
+ CurrentCount = DelimiterIsEmpty ? 1 : count.ThrowIfNegative();
+ CountExceedingBehaviour = countExceedingBehaviour.ThrowIfInvalid();
+ EnumerationDone = count == 0;
Current = default;
- currentCount = 0;
- enumerationDone = false;
- CountMinusOne = Math.Max(Count - 1, 0);
}
///
@@ -54,46 +54,26 @@ public readonly SpanSplitSequenceWithCountEnumerator GetEnumerator()
/// if the enumerator was successfully advanced to the next element; if the enumerator has passed the end of the collection.
public bool MoveNext()
{
- if(enumerationDone)
+ if(EnumerationDone)
{
return false;
}
- ReadOnlySpan span = Span;
- if(currentCount == Count)
- {
- return false;
- }
- int index = span.IndexOf(Delimiter);
- switch(CountExceedingBehaviour)
- {
- case CountExceedingBehaviour.CutLastElements:
- break;
- case CountExceedingBehaviour.AppendLastElements:
- if(currentCount == CountMinusOne)
- {
- ReadOnlySpan lower = span[..index];
- ReadOnlySpan upper = span[(index + Delimiter.Length)..];
- Span temp = new T[lower.Length + upper.Length];
- lower.CopyTo(temp[..index]);
- upper.CopyTo(temp[(index + Delimiter.Length - 1)..]);
- Current = temp;
- currentCount++;
- return true;
- }
- break;
- default:
- throw new InvalidCountExceedingBehaviourException(CountExceedingBehaviour);
- }
- if(index == -1 || index >= span.Length)
+ int delimiterIndex = Span.IndexOf(Delimiter);
+
+ if(delimiterIndex == -1 || CurrentCount == 1)
{
- enumerationDone = true;
- Current = span;
+ EnumerationDone = true;
+
+ Current = delimiterIndex == -1 || CountExceedingBehaviour.IsAppendRemainingElements() || DelimiterIsEmpty ? Span : Span[..delimiterIndex];
+
return true;
}
- currentCount++;
- Current = span[..index];
- Span = span[(index + Delimiter.Length)..];
+
+ Current = Span[..delimiterIndex];
+ Span = Span[(delimiterIndex + DelimiterLength)..];
+
+ CurrentCount--;
return true;
}
}
diff --git a/src/Extensions/ReadOnlySpan/ReadOnlySpanExtensions.Split.cs b/src/Extensions/ReadOnlySpan/ReadOnlySpanExtensions.Split.cs
index 501a28e..a819c4c 100644
--- a/src/Extensions/ReadOnlySpan/ReadOnlySpanExtensions.Split.cs
+++ b/src/Extensions/ReadOnlySpan/ReadOnlySpanExtensions.Split.cs
@@ -30,7 +30,7 @@ public static SpanSplitEnumerator Split(this ReadOnlySpan source, T del
/// The maximum number of sub-ReadOnlySpans to split into.
/// The handling of the instances more than count.
/// An instance of the ref struct , which works the same way as every does and can be used in a foreach construct.
- public static SpanSplitWithCountEnumerator Split(this ReadOnlySpan source, T delimiter, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements) where T : IEquatable
+ public static SpanSplitWithCountEnumerator Split(this ReadOnlySpan source, T delimiter, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements) where T : IEquatable
{
return new SpanSplitWithCountEnumerator(source, delimiter, count, countExceedingBehaviour);
}
@@ -56,7 +56,7 @@ public static SpanSplitStringSplitOptionsEnumerator Split(this ReadOnlySpanA bitwise combination of the enumeration values that specifies whether to trim results and include empty results.
/// The handling of the instances more than count.
/// An instance of the ref struct , which works the same way as every does and can be used in a foreach construct.
- public static SpanSplitStringSplitOptionsWithCountEnumerator Split(this ReadOnlySpan source, char delimiter, int count, StringSplitOptions options, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements)
+ public static SpanSplitStringSplitOptionsWithCountEnumerator Split(this ReadOnlySpan source, char delimiter, int count, StringSplitOptions options, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements)
{
return new SpanSplitStringSplitOptionsWithCountEnumerator(source, delimiter, count, options, countExceedingBehaviour);
}
@@ -82,7 +82,7 @@ public static SpanSplitAnyEnumerator SplitAny(this ReadOnlySpan source,
/// The maximum number of sub-ReadOnlySpans to split into.
/// The handling of the instances more than count.
/// An instance of the ref struct , which works the same way as every does and can be used in a foreach construct.
- public static SpanSplitAnyWithCountEnumerator SplitAny(this ReadOnlySpan source, ReadOnlySpan delimiters, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements) where T : IEquatable
+ public static SpanSplitAnyWithCountEnumerator SplitAny(this ReadOnlySpan source, ReadOnlySpan delimiters, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements) where T : IEquatable
{
return new SpanSplitAnyWithCountEnumerator(source, delimiters, count, countExceedingBehaviour);
}
@@ -108,7 +108,7 @@ public static SpanSplitAnyStringSplitOptionsEnumerator SplitAny(this ReadOnlySpa
/// A bitwise combination of the enumeration values that specifies whether to trim results and include empty results.
/// The handling of the instances more than count.
/// An instance of the ref struct , which works the same way as every does and can be used in a foreach construct.
- public static SpanSplitAnyStringSplitOptionsWithCountEnumerator SplitAny(this ReadOnlySpan source, ReadOnlySpan delimiters, int count, StringSplitOptions options, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements)
+ public static SpanSplitAnyStringSplitOptionsWithCountEnumerator SplitAny(this ReadOnlySpan source, ReadOnlySpan delimiters, int count, StringSplitOptions options, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements)
{
return new SpanSplitAnyStringSplitOptionsWithCountEnumerator(source, delimiters, count, options, countExceedingBehaviour);
}
@@ -134,7 +134,7 @@ public static SpanSplitSequenceEnumerator Split(this ReadOnlySpan sourc
/// The maximum number of sub-ReadOnlySpans to split into.
/// The handling of the instances more than count.
/// An instance of the ref struct , which works the same way as every does and can be used in a foreach construct.
- public static SpanSplitSequenceWithCountEnumerator Split(this ReadOnlySpan source, ReadOnlySpan delimiter, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements) where T : IEquatable
+ public static SpanSplitSequenceWithCountEnumerator Split(this ReadOnlySpan source, ReadOnlySpan delimiter, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements) where T : IEquatable
{
return new SpanSplitSequenceWithCountEnumerator(source, delimiter, count, countExceedingBehaviour);
}
@@ -160,7 +160,7 @@ public static SpanSplitSequenceStringSplitOptionsEnumerator Split(this ReadOnlyS
/// A bitwise combination of the enumeration values that specifies whether to trim results and include empty results.
/// The handling of the instances more than count.
/// An instance of the ref struct , which works the same way as every does and can be used in a foreach construct.
- public static SpanSplitSequenceStringSplitOptionsWithCountEnumerator Split(this ReadOnlySpan source, ReadOnlySpan delimiter, int count, StringSplitOptions options, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements)
+ public static SpanSplitSequenceStringSplitOptionsWithCountEnumerator Split(this ReadOnlySpan source, ReadOnlySpan delimiter, int count, StringSplitOptions options, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements)
{
return new SpanSplitSequenceStringSplitOptionsWithCountEnumerator(source, delimiter, count, options, countExceedingBehaviour);
}
diff --git a/src/Extensions/Span/SpanExtensions.Split.cs b/src/Extensions/Span/SpanExtensions.Split.cs
index 6a2f427..8247e40 100644
--- a/src/Extensions/Span/SpanExtensions.Split.cs
+++ b/src/Extensions/Span/SpanExtensions.Split.cs
@@ -30,7 +30,7 @@ public static SpanSplitEnumerator Split(this Span source, T delimiter)
/// The maximum number of sub-ReadOnlySpans to split into.
/// The handling of the instances more than count.
/// An instance of the ref struct , which works the same way as every does and can be used in a foreach construct.
- public static SpanSplitWithCountEnumerator Split(this Span source, T delimiter, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements) where T : IEquatable
+ public static SpanSplitWithCountEnumerator Split(this Span source, T delimiter, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements) where T : IEquatable
{
return new SpanSplitWithCountEnumerator(source, delimiter, count, countExceedingBehaviour);
}
@@ -56,7 +56,7 @@ public static SpanSplitStringSplitOptionsEnumerator Split(this Span source
/// A bitwise combination of the enumeration values that specifies whether to trim results and include empty results.
/// The handling of the instances more than count.
/// An instance of the ref struct , which works the same way as every does and can be used in a foreach construct.
- public static SpanSplitStringSplitOptionsWithCountEnumerator Split(this Span source, char delimiter, StringSplitOptions options, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements)
+ public static SpanSplitStringSplitOptionsWithCountEnumerator Split(this Span source, char delimiter, StringSplitOptions options, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements)
{
return new SpanSplitStringSplitOptionsWithCountEnumerator(source, delimiter, count, options, countExceedingBehaviour);
}
@@ -78,11 +78,11 @@ public static SpanSplitAnyEnumerator SplitAny(this Span source, ReadOnl
///
/// The type of elements in the .
/// The to be split.
- /// The maximum number of sub-ReadOnlySpans to split into.
/// A , that delimit the various sub-ReadOnlySpans in .
+ /// The maximum number of sub-ReadOnlySpans to split into.
/// The handling of the instances more than count.
/// An instance of the ref struct , which works the same way as every does and can be used in a foreach construct.
- public static SpanSplitAnyWithCountEnumerator SplitAny(this Span source, ReadOnlySpan delimiters, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements) where T : IEquatable
+ public static SpanSplitAnyWithCountEnumerator SplitAny(this Span source, ReadOnlySpan delimiters, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements) where T : IEquatable
{
return new SpanSplitAnyWithCountEnumerator(source, delimiters, count, countExceedingBehaviour);
}
@@ -104,11 +104,11 @@ public static SpanSplitAnyStringSplitOptionsEnumerator SplitAny(this Span
///
/// The to be split.
/// A , that delimit the various sub-ReadOnlySpans in .
- /// A bitwise combination of the enumeration values that specifies whether to trim results and include empty results.
/// The maximum number of sub-ReadOnlySpans to split into.
+ /// A bitwise combination of the enumeration values that specifies whether to trim results and include empty results.
/// The handling of the instances more than count.
/// An instance of the ref struct , which works the same way as every does and can be used in a foreach construct.
- public static SpanSplitAnyStringSplitOptionsWithCountEnumerator SplitAny(this Span source, ReadOnlySpan delimiters, StringSplitOptions options, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements)
+ public static SpanSplitAnyStringSplitOptionsWithCountEnumerator SplitAny(this Span source, ReadOnlySpan delimiters, StringSplitOptions options, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements)
{
return new SpanSplitAnyStringSplitOptionsWithCountEnumerator(source, delimiters, count, options, countExceedingBehaviour);
}
@@ -134,7 +134,7 @@ public static SpanSplitSequenceEnumerator Split(this Span source, ReadO
/// The maximum number of sub-ReadOnlySpans to split into.
/// The handling of the instances more than count.
/// An instance of the ref struct , which works the same way as every does and can be used in a foreach construct.
- public static SpanSplitSequenceWithCountEnumerator Split(this Span source, ReadOnlySpan delimiter, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements) where T : IEquatable
+ public static SpanSplitSequenceWithCountEnumerator Split(this Span source, ReadOnlySpan delimiter, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements) where T : IEquatable
{
return new SpanSplitSequenceWithCountEnumerator(source, delimiter, count, countExceedingBehaviour);
}
@@ -160,7 +160,7 @@ public static SpanSplitSequenceStringSplitOptionsEnumerator Split(this SpanA bitwise combination of the enumeration values that specifies whether to trim results and include empty results.
/// The handling of the instances more than count.
/// An instance of the ref struct , which works the same way as every does and can be used in a foreach construct.
- public static SpanSplitSequenceStringSplitOptionsWithCountEnumerator Split(this Span source, ReadOnlySpan delimiter, StringSplitOptions options, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendLastElements)
+ public static SpanSplitSequenceStringSplitOptionsWithCountEnumerator Split(this Span source, ReadOnlySpan delimiter, StringSplitOptions options, int count, CountExceedingBehaviour countExceedingBehaviour = CountExceedingBehaviour.AppendRemainingElements)
{
return new SpanSplitSequenceStringSplitOptionsWithCountEnumerator(source, delimiter, count, options, countExceedingBehaviour);
}
diff --git a/src/InternalExtensions.cs b/src/InternalExtensions.cs
new file mode 100644
index 0000000..dfe3e43
--- /dev/null
+++ b/src/InternalExtensions.cs
@@ -0,0 +1,140 @@
+using System;
+#if NETCOREAPP3_0_OR_GREATER
+using System.Runtime.CompilerServices;
+#endif
+
+namespace SpanExtensions
+{
+ static class InternalExtensions
+ {
+#if NETCOREAPP3_0_OR_GREATER
+ ///
+ /// Throws an if is negative.
+ ///
+ /// The argument to validate as non-negative.
+ /// The name of the parameter with which corresponds.
+ /// .
+ public static int ThrowIfNegative(this int value, [CallerArgumentExpression(nameof(value))] string? paramName = null)
+ {
+#if NET8_0_OR_GREATER
+ ArgumentOutOfRangeException.ThrowIfNegative(value, paramName);
+#else
+ if(value < 0)
+ {
+ throw new ArgumentOutOfRangeException(paramName, value, $"{paramName} ('{value}') must be a non-negative value.");
+ }
+#endif
+
+ return value;
+ }
+#else
+ ///
+ /// Throws an if is negative.
+ ///
+ /// The argument to validate as non-negative.
+ /// .
+ public static int ThrowIfNegative(this int value)
+ {
+ if(value < 0)
+ {
+#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ throw new ArgumentOutOfRangeException(null, value, $" ('{value}') must be a non-negative value.");
+#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ }
+
+ return value;
+ }
+#endif
+
+#if NETCOREAPP3_0_OR_GREATER
+ ///
+ /// Throws an if is not a valid flag.
+ ///
+ /// The argument to validate as a valid flag.
+ /// The name of the parameter with which corresponds.
+ /// .
+ public static StringSplitOptions ThrowIfInvalid(this StringSplitOptions options, [CallerArgumentExpression(nameof(options))] string? paramName = null)
+ {
+ if((options & ~CombinationOfAllValidStringSplitOptions) != 0)
+ {
+ throw new ArgumentException("Value of flag is invalid.", paramName);
+ }
+
+ return options;
+ }
+#else
+ ///
+ /// Throws an if is not a valid flag.
+ ///
+ /// The argument to validate as a valid flag.
+ /// .
+ public static StringSplitOptions ThrowIfInvalid(this StringSplitOptions options)
+ {
+ if((options & ~CombinationOfAllValidStringSplitOptions) != 0)
+ {
+ throw new ArgumentException("Value of flag is invalid.");
+ }
+
+ return options;
+ }
+#endif
+
+ ///
+ /// Determines whether the bit field is set in the current instance.
+ ///
+ /// The instance to test.
+ /// if has the bit field set; otherwise.
+ public static bool IsRemoveEmptyEntriesSet(this StringSplitOptions options)
+ {
+ return options.HasFlag(StringSplitOptions.RemoveEmptyEntries);
+ }
+
+#if NET5_0_OR_GREATER
+ ///
+ /// Determines whether the bit field is set in the current instance.
+ ///
+ ///
+ /// In runtimes before .NET 5 this always returns .
+ ///
+ /// The instance to test.
+ /// if has the bit field set; otherwise.
+ public static bool IsTrimEntriesSet(this StringSplitOptions options)
+ {
+ return options.HasFlag(StringSplitOptions.TrimEntries);
+ }
+#else
+ ///
+ /// Always returns false.
+ ///
+ /// The instance to test.
+ /// .
+ public static bool IsTrimEntriesSet(this StringSplitOptions options)
+ {
+ return false;
+ }
+#endif
+
+ ///
+ /// Gets all values of an enum and applies the or operation on them.
+ ///
+ /// The target enum type.
+ /// The combination of all valid enum values.
+ public static T GetCombinationOfAllValidFlags() where T : struct, Enum
+ {
+#if NET5_0_OR_GREATER
+ T[] flags = Enum.GetValues();
+#else
+ T[] flags = (T[])Enum.GetValues(typeof(T));
+#endif
+
+ int combination = 0;
+ foreach(T flag in flags)
+ {
+ combination |= (int)(object)flag;
+ }
+ return (T)(object)combination;
+ }
+
+ static readonly StringSplitOptions CombinationOfAllValidStringSplitOptions = GetCombinationOfAllValidFlags();
+ }
+}
diff --git a/src/InvalidCountExceedingBehaviourException.cs b/src/InvalidCountExceedingBehaviourException.cs
deleted file mode 100644
index 75eed7e..0000000
--- a/src/InvalidCountExceedingBehaviourException.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-
-namespace SpanExtensions
-{
- ///
- /// The Exception that is thrown for an undefined enumeration value of .
- ///
- [Serializable]
- public class InvalidCountExceedingBehaviourException : Exception
- {
- ///
- /// Initializes a new instance of the class with a system-supplied message.
- ///
- /// The invalid .
- public InvalidCountExceedingBehaviourException(CountExceedingBehaviour countExceedingBehaviour) :
- base($"CountExceedingBehaviour with ID '{(int) countExceedingBehaviour} is not defined. CountExceedingBehaviour only defines {GetCountExceedingBehaviourNamesListed()}.")
- {
-
- }
-
- static string GetCountExceedingBehaviourNamesListed()
- {
- string[] countExceedingBehaviourNames = Array.Empty();
-#if NET5_0_OR_GREATER
- countExceedingBehaviourNames = Enum.GetNames();
-#else
- countExceedingBehaviourNames = (string[]) Enum.GetNames(typeof(CountExceedingBehaviour));
-#endif
- switch(countExceedingBehaviourNames.Length)
- {
- case 0:
- return "";
- case 1:
- return countExceedingBehaviourNames[0];
- default:
- string first = countExceedingBehaviourNames[0];
- string end = string.Join(',', countExceedingBehaviourNames, 1, countExceedingBehaviourNames.Length - 1);
- return $"{first} and {end}";
- }
-
- }
- }
-}
\ No newline at end of file