@@ -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