@@ -547,17 +547,21 @@ private static unsafe bool ParseNumber(ref char* str, NumberStyles options, ref
547547 return false;
548548 }
549549
550- private static bool TrailingZeros( ReadOnlySpan < char > s , int index )
550+ private static unsafe bool TrailingZeros( ReadOnlySpan < char > s , int index )
551551 {
552- // For compatibility, we need to allow trailing zeros at the end of a number string
553- for ( int i = index; i < s . Length ; i++ )
552+ fixed ( char * sPtr = & s. DangerousGetPinnableReference ( ) )
554553 {
555- if ( s [ i ] != '\0 ' )
554+ var span = new Span< char > ( sPtr , s . Length ) ;
555+ // For compatibility, we need to allow trailing zeros at the end of a number string
556+ for ( int i = index; i < s . Length ; i++ )
556557 {
557- return false;
558+ if ( span [ i ] != '\0 ' )
559+ {
560+ return false;
561+ }
558562 }
563+ return true;
559564 }
560- return true;
561565 }
562566
563567 internal static unsafe bool TryStringToNumber( ReadOnlySpan < char > str , NumberStyles options , ref NumberBuffer number , StringBuilder sb , NumberFormatInfo numfmt , bool parseDecimal )
@@ -634,68 +638,72 @@ internal static unsafe void Int32ToDecChars(char* buffer, ref int index, uint va
634638
635639 internal static unsafe char ParseFormatSpecifier( ReadOnlySpan < char > format , out int digits )
636640 {
637- char c = default ;
638- if ( format . Length > 0 )
641+ fixed ( char * formatPtr = & format . DangerousGetPinnableReference ( ) )
639642 {
640- // If the format begins with a symbol, see if it's a standard format
641- // with or without a specified number of digits.
642- c = format [ 0 ] ;
643- if ( ( uint ) ( c - 'A' ) <= 'Z' - 'A' ||
644- ( uint ) ( c - 'a' ) <= 'z' - 'a' )
643+ var formatSpan = new Span < char > ( formatPtr , format . Length ) ;
644+ char c = default ;
645+ if ( format . Length > 0 )
645646 {
646- // Fast path for sole symbol, e.g. "D"
647- if ( format . Length == 1 )
648- {
649- digits = - 1 ;
650- return c;
651- }
652-
653- if ( format . Length == 2 )
647+ // If the format begins with a symbol, see if it's a standard format
648+ // with or without a specified number of digits.
649+ c = formatSpan [ 0 ] ;
650+ if ( ( uint ) ( c - 'A' ) <= 'Z' - 'A' ||
651+ ( uint ) ( c - 'a' ) <= 'z' - 'a' )
654652 {
655- // Fast path for symbol and single digit, e.g. "X4"
656- int d = format[ 1 ] - '0' ;
657- if ( ( uint ) d < 10 )
653+ // Fast path for sole symbol, e.g. "D"
654+ if ( format . Length == 1 )
658655 {
659- digits = d ;
656+ digits = - 1 ;
660657 return c;
661658 }
662- }
663- else if ( format . Length == 3 )
664- {
665- // Fast path for symbol and double digit, e.g. "F12"
666- int d1 = format[ 1 ] - '0' , d2 = format [ 2 ] - '0' ;
667- if ( ( uint ) d1 < 10 && ( uint ) d2 < 10 )
659+
660+ if ( format . Length == 2 )
668661 {
669- digits = d1 * 10 + d2 ;
670- return c;
662+ // Fast path for symbol and single digit, e.g. "X4"
663+ int d = formatSpan[ 1 ] - '0' ;
664+ if ( ( uint ) d < 10 )
665+ {
666+ digits = d ;
667+ return c;
668+ }
669+ }
670+ else if ( format . Length == 3 )
671+ {
672+ // Fast path for symbol and double digit, e.g. "F12"
673+ int d1 = formatSpan[ 1 ] - '0' , d2 = formatSpan [ 2 ] - '0' ;
674+ if ( ( uint ) d1 < 10 && ( uint ) d2 < 10 )
675+ {
676+ digits = d1 * 10 + d2 ;
677+ return c;
678+ }
671679 }
672- }
673680
674- // Fallback for symbol and any length digits. The digits value must be >= 0 && <= 99,
675- // but it can begin with any number of 0s, and thus we may need to check more than two
676- // digits. Further, for compat, we need to stop when we hit a null char.
677- int n = 0 ;
678- int i = 1 ;
679- while ( i < format . Length && ( ( ( uint ) format [ i ] - '0' ) < 10 ) && n < 10 )
680- {
681- n = ( n * 10 ) + format [ i ++ ] - '0' ;
682- }
681+ // Fallback for symbol and any length digits. The digits value must be >= 0 && <= 99,
682+ // but it can begin with any number of 0s, and thus we may need to check more than two
683+ // digits. Further, for compat, we need to stop when we hit a null char.
684+ int n = 0 ;
685+ int i = 1 ;
686+ while ( i < format . Length && ( ( ( uint ) formatSpan [ i ] - '0' ) < 10 ) && n < 10 )
687+ {
688+ n = ( n * 10 ) + formatSpan [ i ++ ] - '0' ;
689+ }
683690
684- // If we're at the end of the digits rather than having stopped because we hit something
685- // other than a digit or overflowed, return the standard format info.
686- if ( i == format . Length || format [ i ] == '\0 ' )
687- {
688- digits = n;
689- return c;
691+ // If we're at the end of the digits rather than having stopped because we hit something
692+ // other than a digit or overflowed, return the standard format info.
693+ if ( i == format . Length || formatSpan [ i ] == '\0 ' )
694+ {
695+ digits = n;
696+ return c;
697+ }
690698 }
691699 }
692- }
693700
694- // Default empty format to be "G"; custom format is signified with '\0'.
695- digits = - 1 ;
696- return format. Length == 0 || c == '\0 ' ? // For compat, treat '\0' as the end of the specifier, even if the specifier extends beyond it.
697- 'G' :
698- '\0 ' ;
701+ // Default empty format to be "G"; custom format is signified with '\0'.
702+ digits = - 1 ;
703+ return format. Length == 0 || c == '\0 ' ? // For compat, treat '\0' as the end of the specifier, even if the specifier extends beyond it.
704+ 'G' :
705+ '\0 ' ;
706+ }
699707 }
700708
701709 internal static unsafe void NumberToString( ref ValueStringBuilder sb , ref NumberBuffer number , char format , int nMaxDigits , NumberFormatInfo info , bool isDecimal )
0 commit comments