Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/libraries/System.Memory/ref/System.Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,7 @@ public static void Sort<TKey, TValue, TComparer>(this System.Span<TKey> keys, Sy
private object _dummy;
private int _dummyPrimitive;
public readonly System.Range Current { get { throw null; } }
public readonly System.ReadOnlySpan<T> Source { get { throw null; } }
public System.MemoryExtensions.SpanSplitEnumerator<T> GetEnumerator() { throw null; }
public bool MoveNext() { throw null; }
}
Expand Down
38 changes: 21 additions & 17 deletions src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5822,7 +5822,7 @@ private static bool TryWrite<TArg0, TArg1, TArg2>(Span<char> destination, IForma
public ref struct SpanSplitEnumerator<T> where T : IEquatable<T>
{
/// <summary>The input span being split.</summary>
private readonly ReadOnlySpan<T> _span;
private readonly ReadOnlySpan<T> _source;

/// <summary>A single separator to use when <see cref="_splitMode"/> is <see cref="SpanSplitEnumeratorMode.SingleElement"/>.</summary>
private readonly T _separator = default!;
Expand All @@ -5836,25 +5836,29 @@ private static bool TryWrite<TArg0, TArg1, TArg2>(Span<char> destination, IForma

/// <summary>Mode that dictates how the instance was configured and how its fields should be used in <see cref="MoveNext"/>.</summary>
private SpanSplitEnumeratorMode _splitMode;
/// <summary>The inclusive starting index in <see cref="_span"/> of the current range.</summary>
/// <summary>The inclusive starting index in <see cref="_source"/> of the current range.</summary>
private int _startCurrent = 0;
/// <summary>The exclusive ending index in <see cref="_span"/> of the current range.</summary>
/// <summary>The exclusive ending index in <see cref="_source"/> of the current range.</summary>
private int _endCurrent = 0;
/// <summary>The index in <see cref="_span"/> from which the next separator search should start.</summary>
/// <summary>The index in <see cref="_source"/> from which the next separator search should start.</summary>
private int _startNext = 0;

/// <summary>Gets an enumerator that allows for iteration over the split span.</summary>
/// <returns>Returns a <see cref="SpanSplitEnumerator{T}"/> that can be used to iterate over the split span.</returns>
public SpanSplitEnumerator<T> GetEnumerator() => this;

/// <summary>Gets the source span being enumerated.</summary>
/// <returns>Returns the <see cref="ReadOnlySpan{T}"/> that was provided when creating this enumerator.</returns>
public readonly ReadOnlySpan<T> Source => _source;

/// <summary>Gets the current element of the enumeration.</summary>
/// <returns>Returns a <see cref="Range"/> instance that indicates the bounds of the current element withing the source span.</returns>
public Range Current => new Range(_startCurrent, _endCurrent);

/// <summary>Initializes the enumerator for <see cref="SpanSplitEnumeratorMode.SearchValues"/>.</summary>
internal SpanSplitEnumerator(ReadOnlySpan<T> span, SearchValues<T> searchValues)
internal SpanSplitEnumerator(ReadOnlySpan<T> source, SearchValues<T> searchValues)
{
_span = span;
_source = source;
_splitMode = SpanSplitEnumeratorMode.SearchValues;
_searchValues = searchValues;
}
Expand All @@ -5865,9 +5869,9 @@ internal SpanSplitEnumerator(ReadOnlySpan<T> span, SearchValues<T> searchValues)
/// it will instead use <see cref="SpanSplitEnumeratorMode.SearchValues"/> with a cached <see cref="SearchValues{Char}"/>
/// for all whitespace characters.
/// </remarks>
internal SpanSplitEnumerator(ReadOnlySpan<T> span, ReadOnlySpan<T> separators)
internal SpanSplitEnumerator(ReadOnlySpan<T> source, ReadOnlySpan<T> separators)
{
_span = span;
_source = source;
if (typeof(T) == typeof(char) && separators.Length == 0)
{
_searchValues = Unsafe.As<SearchValues<T>>(string.SearchValuesStorage.WhiteSpaceChars);
Expand All @@ -5882,21 +5886,21 @@ internal SpanSplitEnumerator(ReadOnlySpan<T> span, ReadOnlySpan<T> separators)

/// <summary>Initializes the enumerator for <see cref="SpanSplitEnumeratorMode.Sequence"/> (or <see cref="SpanSplitEnumeratorMode.EmptySequence"/> if the separator is empty).</summary>
/// <remarks><paramref name="treatAsSingleSeparator"/> must be true.</remarks>
internal SpanSplitEnumerator(ReadOnlySpan<T> span, ReadOnlySpan<T> separator, bool treatAsSingleSeparator)
internal SpanSplitEnumerator(ReadOnlySpan<T> source, ReadOnlySpan<T> separator, bool treatAsSingleSeparator)
{
Debug.Assert(treatAsSingleSeparator, "Should only ever be called as true; exists to differentiate from separators overload");

_span = span;
_source = source;
_separatorBuffer = separator;
_splitMode = separator.Length == 0 ?
SpanSplitEnumeratorMode.EmptySequence :
SpanSplitEnumeratorMode.Sequence;
}

/// <summary>Initializes the enumerator for <see cref="SpanSplitEnumeratorMode.SingleElement"/>.</summary>
internal SpanSplitEnumerator(ReadOnlySpan<T> span, T separator)
internal SpanSplitEnumerator(ReadOnlySpan<T> source, T separator)
{
_span = span;
_source = source;
_separator = separator;
_splitMode = SpanSplitEnumeratorMode.SingleElement;
}
Expand All @@ -5915,17 +5919,17 @@ public bool MoveNext()
return false;

case SpanSplitEnumeratorMode.SingleElement:
separatorIndex = _span.Slice(_startNext).IndexOf(_separator);
separatorIndex = _source.Slice(_startNext).IndexOf(_separator);
separatorLength = 1;
break;

case SpanSplitEnumeratorMode.Any:
separatorIndex = _span.Slice(_startNext).IndexOfAny(_separatorBuffer);
separatorIndex = _source.Slice(_startNext).IndexOfAny(_separatorBuffer);
separatorLength = 1;
break;

case SpanSplitEnumeratorMode.Sequence:
separatorIndex = _span.Slice(_startNext).IndexOf(_separatorBuffer);
separatorIndex = _source.Slice(_startNext).IndexOf(_separatorBuffer);
separatorLength = _separatorBuffer.Length;
break;

Expand All @@ -5936,7 +5940,7 @@ public bool MoveNext()

default:
Debug.Assert(_splitMode == SpanSplitEnumeratorMode.SearchValues, $"Unknown split mode: {_splitMode}");
separatorIndex = _span.Slice(_startNext).IndexOfAny(_searchValues);
separatorIndex = _source.Slice(_startNext).IndexOfAny(_searchValues);
separatorLength = 1;
break;
}
Expand All @@ -5949,7 +5953,7 @@ public bool MoveNext()
}
else
{
_startNext = _endCurrent = _span.Length;
_startNext = _endCurrent = _source.Length;

// Set _splitMode to None so that subsequent MoveNext calls will return false.
_splitMode = SpanSplitEnumeratorMode.None;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -730,9 +730,11 @@ private static void AssertEqual(string[] items, ReadOnlySpan<char> source, Memor
{
Assert.True(enumerator.MoveNext());
Assert.Equal(item, source[enumerator.Current].ToString());
Assert.Equal(source.ToString(), enumerator.Source.ToString());
}

Assert.False(enumerator.MoveNext());
Comment thread
stephentoub marked this conversation as resolved.
Assert.Equal(source.ToString(), enumerator.Source.ToString());
}
}
}