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
4 changes: 2 additions & 2 deletions src/Polyfill/Regex/Polyfill_Regex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public static ValueMatchEnumerator EnumerateMatches(this Regex target, ReadOnlyS

//Link: https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex.enumeratesplits?view=net-11.0#system-text-regularexpressions-regex-enumeratesplits(system-readonlyspan((system-char)))
public static ValueSplitEnumerator EnumerateSplits(this Regex regex, ReadOnlySpan<char> input) =>
new(input, regex, 0, 0);
new(input, regex, 0);

//Link: https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex.enumeratesplits?view=net-11.0#system-text-regularexpressions-regex-enumeratesplits(system-readonlyspan((system-char))-system-int32)
public static ValueSplitEnumerator EnumerateSplits(this Regex regex, ReadOnlySpan<char> input, int count)
Expand All @@ -94,7 +94,7 @@ public static ValueSplitEnumerator EnumerateSplits(this Regex regex, ReadOnlySpa
throw new ArgumentOutOfRangeException(nameof(count), "Count must be non-negative.");
}

return new ValueSplitEnumerator(input, regex, count, 0);
return new ValueSplitEnumerator(input, regex, count);
}

//Link: https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex.enumeratesplits?view=net-11.0#system-text-regularexpressions-regex-enumeratesplits(system-readonlyspan((system-char))-system-int32-system-int32)
Expand Down
6 changes: 3 additions & 3 deletions src/Polyfill/Regex/RegexPolyfill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,21 +115,21 @@ public static ValueMatchEnumerator EnumerateMatches(ReadOnlySpan<char> input, st
public static ValueSplitEnumerator EnumerateSplits(ReadOnlySpan<char> input, string pattern)
{
var regex = new Regex(pattern);
return new ValueSplitEnumerator(input, regex, 0, 0);
return new ValueSplitEnumerator(input, regex, 0);
}

//Link: https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex.enumeratesplits?view=net-11.0#system-text-regularexpressions-regex-enumeratesplits(system-readonlyspan((system-char))-system-string-system-text-regularexpressions-regexoptions)
public static ValueSplitEnumerator EnumerateSplits(ReadOnlySpan<char> input, string pattern, RegexOptions options)
{
var regex = new Regex(pattern, options);
return new ValueSplitEnumerator(input, regex, 0, 0);
return new ValueSplitEnumerator(input, regex, 0);
}

//Link: https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex.enumeratesplits?view=net-11.0#system-text-regularexpressions-regex-enumeratesplits(system-readonlyspan((system-char))-system-string-system-text-regularexpressions-regexoptions-system-timespan)
public static ValueSplitEnumerator EnumerateSplits(ReadOnlySpan<char> input, string pattern, RegexOptions options, TimeSpan matchTimeout)
{
var regex = new Regex(pattern, options, matchTimeout);
return new ValueSplitEnumerator(input, regex, 0, 0);
return new ValueSplitEnumerator(input, regex, 0);
}

#endif
Expand Down
115 changes: 68 additions & 47 deletions src/Polyfill/Regex/ValueSplitEnumerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

namespace System.Text.RegularExpressions;

using System.Collections.Generic;
using System;
using System.Runtime.CompilerServices;
using System.Diagnostics;
Expand All @@ -28,83 +27,105 @@ ref struct ValueSplitEnumerator
{
private readonly ReadOnlySpan<char> _input;
private readonly Regex _regex;
private readonly int _count;
private readonly int _startat;
private Range[]? _ranges;
private int _currentIndex;
private bool _initialized;
private int _remaining;
private Match? _match;
private int _previous;
private bool _completed;
private Range _current;

internal ValueSplitEnumerator(ReadOnlySpan<char> input, Regex regex, int count)
: this(input, regex, count, GetDefaultStartat(input, regex))
{
}

internal ValueSplitEnumerator(ReadOnlySpan<char> input, Regex regex, int count, int startat)
{
_input = input;
_regex = regex;
_count = count;
_startat = startat;
_ranges = null;
_currentIndex = -1;
_initialized = false;
}
_remaining = count;
if (count == 0)
{
_remaining = int.MaxValue;
}

public Range Current => _ranges![_currentIndex];
_match = null;
_previous = 0;
if (regex.RightToLeft)
{
_previous = input.Length;
}

public ValueSplitEnumerator GetEnumerator() => this;
_completed = false;
_current = default;
}

public bool MoveNext()
static int GetDefaultStartat(ReadOnlySpan<char> input, Regex regex)
{
if (!_initialized)
if (regex.RightToLeft)
{
Initialize();
_initialized = true;
return input.Length;
}

_currentIndex++;
return _currentIndex < _ranges!.Length;
return 0;
}

private void Initialize()
{
string inputString = _input.ToString();
string[] splits;
public readonly Range Current => _current;

if (_count == 0 && _startat == 0)
{
splits = _regex.Split(inputString);
}
else if (_startat == 0)
{
splits = _regex.Split(inputString, _count == 0 ? int.MaxValue : _count);
}
else
public readonly ValueSplitEnumerator GetEnumerator() => this;

public bool MoveNext()
{
if (_completed)
{
splits = _regex.Split(inputString, _count == 0 ? int.MaxValue : _count, _startat);
return false;
}

var ranges = new List<Range>();
int currentPos = 0;

for (int i = 0; i < splits.Length; i++)
// The last permitted split is always the remainder of the input, so only look for
// a further match when at least one more split is allowed after this one.
if (_remaining > 1)
{
int length = splits[i].Length;
int start = currentPos;
int end = currentPos + length;

ranges.Add(new Range(start, end));
Match match;
if (_match is null)
{
match = _regex.Match(_input.ToString(), _startat);
}
else
{
match = _match.NextMatch();
}

if (i < splits.Length - 1)
if (match.Success)
{
Match match = _regex.Match(inputString, end);
if (match.Success)
_match = match;
_remaining--;
if (_regex.RightToLeft)
{
currentPos = match.Index + match.Length;
_current = new Range(match.Index + match.Length, _previous);
_previous = match.Index;
}
else
{
currentPos = end;
_current = new Range(_previous, match.Index);
_previous = match.Index + match.Length;
}

return true;
}
}

_ranges = ranges.ToArray();
_completed = true;
if (_regex.RightToLeft)
{
_current = new Range(0, _previous);
}
else
{
_current = new Range(_previous, _input.Length);
}

return true;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/Split/net461/Regex/Polyfill_Regex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ public static ValueMatchEnumerator EnumerateMatches(this Regex target, ReadOnlyS
#endif
#if FeatureMemory && FeatureValueTuple
public static ValueSplitEnumerator EnumerateSplits(this Regex regex, ReadOnlySpan<char> input) =>
new(input, regex, 0, 0);
new(input, regex, 0);
public static ValueSplitEnumerator EnumerateSplits(this Regex regex, ReadOnlySpan<char> input, int count)
{
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count), "Count must be non-negative.");
}
return new ValueSplitEnumerator(input, regex, count, 0);
return new ValueSplitEnumerator(input, regex, count);
}
public static ValueSplitEnumerator EnumerateSplits(this Regex regex, ReadOnlySpan<char> input, int count, int startat)
{
Expand Down
6 changes: 3 additions & 3 deletions src/Split/net461/Regex/RegexPolyfill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,17 @@ public static ValueMatchEnumerator EnumerateMatches(ReadOnlySpan<char> input, st
public static ValueSplitEnumerator EnumerateSplits(ReadOnlySpan<char> input, string pattern)
{
var regex = new Regex(pattern);
return new ValueSplitEnumerator(input, regex, 0, 0);
return new ValueSplitEnumerator(input, regex, 0);
}
public static ValueSplitEnumerator EnumerateSplits(ReadOnlySpan<char> input, string pattern, RegexOptions options)
{
var regex = new Regex(pattern, options);
return new ValueSplitEnumerator(input, regex, 0, 0);
return new ValueSplitEnumerator(input, regex, 0);
}
public static ValueSplitEnumerator EnumerateSplits(ReadOnlySpan<char> input, string pattern, RegexOptions options, TimeSpan matchTimeout)
{
var regex = new Regex(pattern, options, matchTimeout);
return new ValueSplitEnumerator(input, regex, 0, 0);
return new ValueSplitEnumerator(input, regex, 0);
}
#endif
}
Expand Down
103 changes: 60 additions & 43 deletions src/Split/net461/Regex/ValueSplitEnumerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#pragma warning disable
#if FeatureMemory && FeatureValueTuple
namespace System.Text.RegularExpressions;
using System.Collections.Generic;
using System;
using System.Runtime.CompilerServices;
using System.Diagnostics;
Expand All @@ -22,71 +21,89 @@ ref struct ValueSplitEnumerator
{
private readonly ReadOnlySpan<char> _input;
private readonly Regex _regex;
private readonly int _count;
private readonly int _startat;
private Range[]? _ranges;
private int _currentIndex;
private bool _initialized;
private int _remaining;
private Match? _match;
private int _previous;
private bool _completed;
private Range _current;
internal ValueSplitEnumerator(ReadOnlySpan<char> input, Regex regex, int count)
: this(input, regex, count, GetDefaultStartat(input, regex))
{
}
internal ValueSplitEnumerator(ReadOnlySpan<char> input, Regex regex, int count, int startat)
{
_input = input;
_regex = regex;
_count = count;
_startat = startat;
_ranges = null;
_currentIndex = -1;
_initialized = false;
}
public Range Current => _ranges![_currentIndex];
public ValueSplitEnumerator GetEnumerator() => this;
public bool MoveNext()
{
if (!_initialized)
_remaining = count;
if (count == 0)
{
Initialize();
_initialized = true;
_remaining = int.MaxValue;
}
_currentIndex++;
return _currentIndex < _ranges!.Length;
}
private void Initialize()
{
string inputString = _input.ToString();
string[] splits;
if (_count == 0 && _startat == 0)
_match = null;
_previous = 0;
if (regex.RightToLeft)
{
splits = _regex.Split(inputString);
_previous = input.Length;
}
else if (_startat == 0)
_completed = false;
_current = default;
}
static int GetDefaultStartat(ReadOnlySpan<char> input, Regex regex)
{
if (regex.RightToLeft)
{
splits = _regex.Split(inputString, _count == 0 ? int.MaxValue : _count);
return input.Length;
}
else
return 0;
}
public readonly Range Current => _current;
public readonly ValueSplitEnumerator GetEnumerator() => this;
public bool MoveNext()
{
if (_completed)
{
splits = _regex.Split(inputString, _count == 0 ? int.MaxValue : _count, _startat);
return false;
}
var ranges = new List<Range>();
int currentPos = 0;
for (int i = 0; i < splits.Length; i++)
if (_remaining > 1)
{
int length = splits[i].Length;
int start = currentPos;
int end = currentPos + length;
ranges.Add(new Range(start, end));
if (i < splits.Length - 1)
Match match;
if (_match is null)
{
match = _regex.Match(_input.ToString(), _startat);
}
else
{
match = _match.NextMatch();
}
if (match.Success)
{
Match match = _regex.Match(inputString, end);
if (match.Success)
_match = match;
_remaining--;
if (_regex.RightToLeft)
{
currentPos = match.Index + match.Length;
_current = new Range(match.Index + match.Length, _previous);
_previous = match.Index;
}
else
{
currentPos = end;
_current = new Range(_previous, match.Index);
_previous = match.Index + match.Length;
}
return true;
}
}
_ranges = ranges.ToArray();
_completed = true;
if (_regex.RightToLeft)
{
_current = new Range(0, _previous);
}
else
{
_current = new Range(_previous, _input.Length);
}
return true;
}
}
#endif
4 changes: 2 additions & 2 deletions src/Split/net462/Regex/Polyfill_Regex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ public static ValueMatchEnumerator EnumerateMatches(this Regex target, ReadOnlyS
#endif
#if FeatureMemory && FeatureValueTuple
public static ValueSplitEnumerator EnumerateSplits(this Regex regex, ReadOnlySpan<char> input) =>
new(input, regex, 0, 0);
new(input, regex, 0);
public static ValueSplitEnumerator EnumerateSplits(this Regex regex, ReadOnlySpan<char> input, int count)
{
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count), "Count must be non-negative.");
}
return new ValueSplitEnumerator(input, regex, count, 0);
return new ValueSplitEnumerator(input, regex, count);
}
public static ValueSplitEnumerator EnumerateSplits(this Regex regex, ReadOnlySpan<char> input, int count, int startat)
{
Expand Down
Loading
Loading