-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimize ReplaceLineEndings #81630
Optimize ReplaceLineEndings #81630
Conversation
Tagging subscribers to this area: @dotnet/area-system-runtime Issue Details
ReplaceLineEndings LF => LF
ReplaceLineEndings CRLF => LF
ReplaceLineEndings CRLF => CRLF
SpanLineEnumerator
|
Comparing the combined change of #81630 + #80963 + #78678 against main without them (NET 7 vs 8): ReplaceLineEndings LF => LF
ReplaceLineEndings CRLF => LF
ReplaceLineEndings CRLF => CRLF
SpanLineEnumerator
|
Any thoughts on this @dotnet/area-system-runtime? |
src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs
Outdated
Show resolved
Hide resolved
var builder = new ValueStringBuilder(stackalloc char[StackallocCharBufferSizeLimit]); | ||
while (true) | ||
{ | ||
int idx = remaining.IndexOfAny(IndexOfAnyValuesStorage.NewLineCharsExceptLineFeed); | ||
if ((uint)idx >= (uint)remaining.Length) break; // no more newline chars | ||
stride = remaining[idx] == '\r' && (uint)(idx + 1) < (uint)remaining.Length && remaining[idx + 1] == '\n' ? 2 : 1; | ||
builder.Append('\n'); | ||
builder.Append(remaining.Slice(0, idx)); | ||
remaining = remaining.Slice(idx + stride); | ||
} | ||
|
||
return idx; | ||
builder.Append('\n'); | ||
string retVal = Concat(this.AsSpan(0, idxOfFirstNewlineChar), builder.AsSpan(), remaining); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity, I wonder what the performance profile would look like for instead doing the equivalent of a Count("\r\n"), then allocating a string of exactly the right length (string.Length - count), and then formatting directly into that string, rather than going into a growable VSB and then copying into a new string at the end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given this is effectively a glorified string.Replace
, we could use a similar approach of building the list of indices.
I'll try it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested with MihaZupan@b68c952 and it's similar or a bit worse across the board.
56953a0
to
c21efe3
Compare
IndexOfNewlineChar
until something other than thereplacementText
is found'\n'
- default on non-Windows), we can avoid searching for the line feed, thus avoiding breaking out of the vectorized path unnecessarilySpanHelpers.IndexOfAnyValueType
ReplaceLineEndings LF => LF
ReplaceLineEndings CRLF => LF
ReplaceLineEndings CRLF => CRLF
SpanLineEnumerator