diff --git a/src/libraries/System.Memory/tests/ReadOnlySpan/Split.char.cs b/src/libraries/System.Memory/tests/ReadOnlySpan/Split.char.cs index 10a832270163f4..710d5e5d2d88de 100644 --- a/src/libraries/System.Memory/tests/ReadOnlySpan/Split.char.cs +++ b/src/libraries/System.Memory/tests/ReadOnlySpan/Split.char.cs @@ -15,7 +15,11 @@ public static void SplitNoMatchSingleResult() ReadOnlySpan value = "a b"; string expected = value.ToString(); - var enumerator = value.Split(','); + SpanSplitEnumerator enumerator = value.Split(','); + Assert.True(enumerator.MoveNext()); + Assert.Equal(expected, value[enumerator.Current].ToString()); + + enumerator = value.Split(","); Assert.True(enumerator.MoveNext()); Assert.Equal(expected, value[enumerator.Current].ToString()); } @@ -23,7 +27,7 @@ public static void SplitNoMatchSingleResult() [Fact] public static void DefaultSpanSplitEnumeratorBehavior() { - var charSpanEnumerator = new SpanSplitEnumerator(); + var charSpanEnumerator = new SpanSplitEnumerator(); Assert.Equal(new Range(0, 0), charSpanEnumerator.Current); Assert.False(charSpanEnumerator.MoveNext()); @@ -41,7 +45,7 @@ public static void ValidateArguments_OverloadWithoutSeparator() { ReadOnlySpan buffer = default; - SpanSplitEnumerator enumerator = buffer.Split(); + SpanSplitEnumerator enumerator = buffer.Split(); Assert.True(enumerator.MoveNext()); Assert.Equal(new Range(0, 0), enumerator.Current); Assert.False(enumerator.MoveNext()); @@ -67,14 +71,14 @@ public static void ValidateArguments_OverloadWithROSSeparator() // Default buffer ReadOnlySpan buffer = default; - SpanSplitEnumerator enumerator = buffer.Split(default(char)); + SpanSplitEnumerator enumerator = buffer.Split(default(char)); Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(0, 0)); + Assert.Equal(new Range(0, 0), enumerator.Current); Assert.False(enumerator.MoveNext()); enumerator = buffer.Split(' '); Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(0, 0)); + Assert.Equal(new Range(0, 0), enumerator.Current); Assert.False(enumerator.MoveNext()); // Empty buffer @@ -82,12 +86,12 @@ public static void ValidateArguments_OverloadWithROSSeparator() enumerator = buffer.Split(default(char)); Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(0, 0)); + Assert.Equal(new Range(0, 0), enumerator.Current); Assert.False(enumerator.MoveNext()); enumerator = buffer.Split(' '); Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(0, 0)); + Assert.Equal(new Range(0, 0), enumerator.Current); Assert.False(enumerator.MoveNext()); // Single whitespace buffer @@ -114,17 +118,17 @@ public static void ValidateArguments_OverloadWithStringSeparator() SpanSplitEnumerator enumerator = buffer.Split(null); // null is treated as empty string Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(0, 0)); + Assert.Equal(new Range(0, 0), enumerator.Current); Assert.False(enumerator.MoveNext()); enumerator = buffer.Split(""); Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(0, 0)); + Assert.Equal(new Range(0, 0), enumerator.Current); Assert.False(enumerator.MoveNext()); enumerator = buffer.Split(" "); Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(0, 0)); + Assert.Equal(new Range(0, 0), enumerator.Current); Assert.False(enumerator.MoveNext()); // Empty buffer @@ -132,17 +136,17 @@ public static void ValidateArguments_OverloadWithStringSeparator() enumerator = buffer.Split(null); Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(0, 0)); + Assert.Equal(new Range(0, 0), enumerator.Current); Assert.False(enumerator.MoveNext()); enumerator = buffer.Split(""); Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(0, 0)); + Assert.Equal(new Range(0, 0), enumerator.Current); Assert.False(enumerator.MoveNext()); enumerator = buffer.Split(" "); Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(0, 0)); + Assert.Equal(new Range(0, 0), enumerator.Current); Assert.False(enumerator.MoveNext()); // Single whitespace buffer @@ -150,24 +154,19 @@ public static void ValidateArguments_OverloadWithStringSeparator() enumerator = buffer.Split(null); // null is treated as empty string Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(0, 0)); - Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(1, 1)); + Assert.Equal(new Range(0, 1), enumerator.Current); Assert.False(enumerator.MoveNext()); enumerator = buffer.Split(""); Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(0, 0)); - Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(1, 1)); + Assert.Equal(new Range(0, 1), enumerator.Current); Assert.False(enumerator.MoveNext()); enumerator = buffer.Split(" "); - Assert.Equal(enumerator.Current, new Range(0, 0)); Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(0, 0)); + Assert.Equal(new Range(0, 0), enumerator.Current); Assert.True(enumerator.MoveNext()); - Assert.Equal(enumerator.Current, new Range(1, 1)); + Assert.Equal(new Range(1, 1), enumerator.Current); Assert.False(enumerator.MoveNext()); } @@ -231,6 +230,14 @@ public static void SpanSplitDefaultCharSeparator(string valueParam, string[] exp } [Theory] + [InlineData("a,b,c", null, new[] { "a,b,c" })] + [InlineData("a,b,c", "", new[] { "a,b,c" })] + [InlineData("a,b,c,", null, new[] { "a,b,c," })] + [InlineData("a,b,c,", "", new[] { "a,b,c," })] + [InlineData(" a,b,c,", null, new[] { " a,b,c," })] + [InlineData(" a,b,c,", "", new[] { " a,b,c," })] + [InlineData("aaabaaabaaa", "aa", new[] { "", "ab", "ab", "a" })] + [InlineData("this, is, a, string, with some spaces", ", ", new[] { "this", "is", "a", "string", "with some spaces" })] [InlineData(" Foo Bar Baz,", ", ", new[] { " Foo Bar Baz," })] [InlineData(" Foo Bar Baz, ", ", ", new[] { " Foo Bar Baz", "" })] [InlineData(", Foo Bar Baz, ", ", ", new[] { "", "Foo Bar Baz", "" })] @@ -251,7 +258,7 @@ private static void AssertEqual(T[][] items, ReadOnlySpan orig, SpanSplitE foreach (var item in items) { Assert.True(source.MoveNext()); - var slice = orig[source.Current]; + ReadOnlySpan slice = orig[source.Current]; Assert.Equal(item, slice.ToArray()); } Assert.False(source.MoveNext()); diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanSplitEnumerator.T.cs b/src/libraries/System.Private.CoreLib/src/System/SpanSplitEnumerator.T.cs index 69382459b26e4a..4ff5065f8da0bc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanSplitEnumerator.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanSplitEnumerator.T.cs @@ -43,7 +43,7 @@ internal SpanSplitEnumerator(ReadOnlySpan span, ReadOnlySpan separators) _separators = separators; _separator = default!; _splitOnSingleToken = false; - _separatorLength = _separators.Length != 0 ? _separators.Length : 1; + _separatorLength = _separators.Length; _startCurrent = 0; _endCurrent = 0; _startNext = 0; @@ -76,7 +76,22 @@ public bool MoveNext() ReadOnlySpan slice = _buffer.Slice(_startNext); _startCurrent = _startNext; - int separatorIndex = _splitOnSingleToken ? slice.IndexOf(_separator) : slice.IndexOf(_separators); + int separatorIndex; + if (_splitOnSingleToken) + { + separatorIndex = slice.IndexOf(_separator); + } + else if (_separators.Length > 0) + { + separatorIndex = slice.IndexOf(_separators); + } + else + { + _endCurrent = _startCurrent + slice.Length; + _startNext = _endCurrent + 1; + return true; + } + int elementLength = (separatorIndex != -1 ? separatorIndex : slice.Length); _endCurrent = _startCurrent + elementLength;