Skip to content

Commit 7ec35da

Browse files
committed
perf: cache StringBuilder per-thread
1 parent bf51b15 commit 7ec35da

File tree

1 file changed

+79
-55
lines changed

1 file changed

+79
-55
lines changed

StructuredFieldValues/Rfc8941Parser.cs

Lines changed: 79 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ internal static class Rfc8941Parser
1616

1717
private static readonly object True = true;
1818

19+
[ThreadStatic]
20+
private static StringBuilder? _builderCache;
21+
1922
public static ParseError? ParseItemField(ReadOnlySpan<char> source, ref int index, out ParsedItem result)
2023
{
2124
index = BeginParse(source, index);
@@ -789,78 +792,99 @@ internal static class Rfc8941Parser
789792
var initialIndex = index;
790793
var localIndex = initialIndex;
791794
StringBuilder? buffer = null;
792-
while (localIndex != spanLength)
795+
try
793796
{
794-
var character = source[localIndex];
795-
switch (character)
797+
while (localIndex != spanLength)
796798
{
797-
case '\\':
798-
++localIndex;
799-
if (localIndex == spanLength)
800-
{
801-
index = localIndex;
802-
result = "";
803-
return new(localIndex, "missing escaped character");
804-
}
799+
var character = source[localIndex];
800+
switch (character)
801+
{
802+
case '\\':
803+
++localIndex;
804+
if (localIndex == spanLength)
805+
{
806+
index = localIndex;
807+
result = "";
808+
return new(localIndex, "missing escaped character");
809+
}
805810

806-
character = source[localIndex];
807-
switch (character)
808-
{
809-
case '\\':
810-
case '"':
811-
if (buffer is null)
812-
{
813-
buffer = new StringBuilder(spanLength - 2);
814-
var slice = source.Slice(initialIndex, localIndex - initialIndex - 1);
811+
character = source[localIndex];
812+
switch (character)
813+
{
814+
case '\\':
815+
case '"':
816+
if (buffer is null)
817+
{
818+
var capacity = spanLength - 2;
819+
if (_builderCache is not null)
820+
{
821+
buffer = _builderCache;
822+
buffer.EnsureCapacity(capacity);
823+
}
824+
else
825+
{
826+
buffer = new(capacity);
827+
}
828+
829+
var slice = source.Slice(initialIndex, localIndex - initialIndex - 1);
815830
#if NET5_0_OR_GREATER
816-
buffer.Append(slice);
831+
buffer.Append(slice);
817832
#else
818-
buffer.Append(slice.ToArray());
833+
buffer.Append(slice.ToArray());
819834
#endif
820-
}
835+
}
821836

822-
buffer.Append(character);
823-
break;
837+
buffer.Append(character);
838+
break;
824839

825-
default:
826-
index = localIndex;
827-
result = "";
828-
return new(localIndex, "invalid escaped character");
829-
}
840+
default:
841+
index = localIndex;
842+
result = "";
843+
return new(localIndex, "invalid escaped character");
844+
}
830845

831-
break;
846+
break;
832847

833-
case '"':
834-
if (buffer is not null)
835-
{
836-
result = buffer.ToString();
837-
}
838-
else
839-
{
840-
var slice = source.Slice(initialIndex, localIndex - initialIndex);
848+
case '"':
849+
if (buffer is not null)
850+
{
851+
result = buffer.ToString();
852+
}
853+
else
854+
{
855+
var slice = source.Slice(initialIndex, localIndex - initialIndex);
841856
#if NET5_0_OR_GREATER
842-
result = new(slice);
857+
result = new(slice);
843858
#else
844-
result = new(slice.ToArray());
859+
result = new(slice.ToArray());
845860
#endif
846-
}
861+
}
847862

848-
index = localIndex + 1;
849-
return null;
863+
index = localIndex + 1;
864+
return null;
850865

851-
default:
852-
if ((int)character is not (>= 0x20 and <= 0x7E))
853-
{
854-
index = localIndex;
855-
result = "";
856-
return new(localIndex, "string character is out of range");
857-
}
866+
default:
867+
if ((int)character is not (>= 0x20 and <= 0x7E))
868+
{
869+
index = localIndex;
870+
result = "";
871+
return new(localIndex, "string character is out of range");
872+
}
858873

859-
buffer?.Append(character);
860-
break;
861-
}
874+
buffer?.Append(character);
875+
break;
876+
}
862877

863-
++localIndex;
878+
++localIndex;
879+
}
880+
}
881+
finally
882+
{
883+
if (buffer is { Capacity: <= 42000 })
884+
{
885+
buffer.Clear();
886+
_builderCache = buffer;
887+
}
864888
}
865889

866890
index = localIndex;

0 commit comments

Comments
 (0)