@@ -669,4 +669,325 @@ private static byte ParseHexByte(char c1, char c2)
669669 }
670670 }
671671 }
672+
673+ enum ParseState
674+ {
675+ LeadingWhite ,
676+ Sign ,
677+ Number ,
678+ DecimalPoint ,
679+ FractionNumber ,
680+ Exponent ,
681+ ExponentSign ,
682+ ExponentValue ,
683+ TrailingWhite
684+ }
685+
686+ internal static class SignedInteger < T > where T : struct , IComparable < T > , IEquatable < T > , IConvertible
687+ {
688+ private static readonly TypeCode typeCode ;
689+ private static readonly long minValue ;
690+ private static readonly long maxValue ;
691+
692+ static SignedInteger ( )
693+ {
694+ typeCode = Type . GetTypeCode ( typeof ( T ) ) ;
695+
696+ switch ( typeCode )
697+ {
698+ case TypeCode . SByte :
699+ minValue = sbyte . MinValue ;
700+ maxValue = sbyte . MaxValue ;
701+ break ;
702+ case TypeCode . Int16 :
703+ minValue = short . MinValue ;
704+ maxValue = short . MaxValue ;
705+ break ;
706+ case TypeCode . Int32 :
707+ minValue = int . MinValue ;
708+ maxValue = int . MaxValue ;
709+ break ;
710+ case TypeCode . Int64 :
711+ minValue = long . MinValue ;
712+ maxValue = long . MaxValue ;
713+ break ;
714+ default :
715+ throw new NotSupportedException ( $ "{ typeof ( T ) . Name } is not a signed integer") ;
716+ }
717+ }
718+
719+ internal static object ParseNullableObject ( ReadOnlySpan < char > value )
720+ {
721+ if ( value . IsNullOrEmpty ( ) )
722+ return null ;
723+
724+ return ParseObject ( value ) ;
725+ }
726+
727+ internal static object ParseObject ( ReadOnlySpan < char > value )
728+ {
729+ var result = ParseInt64 ( value ) ;
730+ switch ( typeCode )
731+ {
732+ case TypeCode . SByte :
733+ return ( sbyte ) result ;
734+ case TypeCode . Int16 :
735+ return ( short ) result ;
736+ case TypeCode . Int32 :
737+ return ( int ) result ;
738+ default :
739+ return result ;
740+ }
741+ }
742+
743+ public static sbyte ParseSByte ( ReadOnlySpan < char > value ) => ( sbyte ) ParseInt64 ( value ) ;
744+ public static short ParseInt16 ( ReadOnlySpan < char > value ) => ( short ) ParseInt64 ( value ) ;
745+ public static int ParseInt32 ( ReadOnlySpan < char > value ) => ( int ) ParseInt64 ( value ) ;
746+
747+ public static long ParseInt64 ( ReadOnlySpan < char > value )
748+ {
749+ if ( value . IsEmpty )
750+ throw new FormatException ( MemoryProvider . BadFormat ) ;
751+
752+ long result = 0 ;
753+ int i = 0 ;
754+ int end = value . Length ;
755+ var state = ParseState . LeadingWhite ;
756+ bool negative = false ;
757+
758+ //skip leading whitespaces
759+ while ( i < end && JsonUtils . IsWhiteSpace ( value [ i ] ) ) i ++ ;
760+
761+ if ( i == end )
762+ throw new FormatException ( MemoryProvider . BadFormat ) ;
763+
764+ //skip leading zeros
765+ while ( i < end && value [ i ] == '0' )
766+ {
767+ state = ParseState . Number ;
768+ i ++ ;
769+ }
770+
771+ while ( i < end )
772+ {
773+ var c = value [ i ++ ] ;
774+
775+ switch ( state )
776+ {
777+ case ParseState . LeadingWhite :
778+ if ( c == '-' )
779+ {
780+ negative = true ;
781+ state = ParseState . Sign ;
782+ }
783+ else if ( c == '0' )
784+ {
785+ state = ParseState . TrailingWhite ;
786+ }
787+ else if ( c > '0' && c <= '9' )
788+ {
789+ result = - ( c - '0' ) ;
790+ state = ParseState . Number ;
791+ }
792+ else throw new FormatException ( MemoryProvider . BadFormat ) ;
793+
794+ break ;
795+ case ParseState . Sign :
796+ if ( c == '0' )
797+ {
798+ state = ParseState . TrailingWhite ;
799+ }
800+ else if ( c > '0' && c <= '9' )
801+ {
802+ result = - ( c - '0' ) ;
803+ state = ParseState . Number ;
804+ }
805+ else throw new FormatException ( MemoryProvider . BadFormat ) ;
806+
807+ break ;
808+ case ParseState . Number :
809+ if ( c >= '0' && c <= '9' )
810+ {
811+ checked
812+ {
813+ result = 10 * result - ( c - '0' ) ;
814+ }
815+
816+ if ( result < minValue
817+ ) //check only minvalue, because in absolute value it's greater than maxvalue
818+ throw DefaultMemory . CreateOverflowException ( maxValue ) ;
819+ }
820+ else if ( JsonUtils . IsWhiteSpace ( c ) )
821+ {
822+ state = ParseState . TrailingWhite ;
823+ }
824+ else throw new FormatException ( MemoryProvider . BadFormat ) ;
825+
826+ break ;
827+ case ParseState . TrailingWhite :
828+ if ( JsonUtils . IsWhiteSpace ( c ) )
829+ {
830+ state = ParseState . TrailingWhite ;
831+ }
832+ else throw new FormatException ( MemoryProvider . BadFormat ) ;
833+
834+ break ;
835+ }
836+ }
837+
838+ if ( state != ParseState . Number && state != ParseState . TrailingWhite )
839+ throw new FormatException ( MemoryProvider . BadFormat ) ;
840+
841+ if ( negative )
842+ return result ;
843+
844+ checked
845+ {
846+ result = - result ;
847+ }
848+
849+ if ( result > maxValue )
850+ throw DefaultMemory . CreateOverflowException ( maxValue ) ;
851+
852+ return result ;
853+ }
854+ }
855+
856+ internal static class UnsignedInteger < T > where T : struct , IComparable < T > , IEquatable < T > , IConvertible
857+ {
858+ private static readonly TypeCode typeCode ;
859+ private static readonly ulong maxValue ;
860+
861+ static UnsignedInteger ( )
862+ {
863+ typeCode = Type . GetTypeCode ( typeof ( T ) ) ;
864+
865+ switch ( typeCode )
866+ {
867+ case TypeCode . Byte :
868+ maxValue = byte . MaxValue ;
869+ break ;
870+ case TypeCode . UInt16 :
871+ maxValue = ushort . MaxValue ;
872+ break ;
873+ case TypeCode . UInt32 :
874+ maxValue = uint . MaxValue ;
875+ break ;
876+ case TypeCode . UInt64 :
877+ maxValue = ulong . MaxValue ;
878+ break ;
879+ default :
880+ throw new NotSupportedException ( $ "{ typeof ( T ) . Name } is not a signed integer") ;
881+ }
882+ }
883+
884+ internal static object ParseNullableObject ( ReadOnlySpan < char > value )
885+ {
886+ if ( value . IsNullOrEmpty ( ) )
887+ return null ;
888+
889+ return ParseObject ( value ) ;
890+ }
891+
892+ internal static object ParseObject ( ReadOnlySpan < char > value )
893+ {
894+ var result = ParseUInt64 ( value ) ;
895+ switch ( typeCode )
896+ {
897+ case TypeCode . Byte :
898+ return ( byte ) result ;
899+ case TypeCode . UInt16 :
900+ return ( ushort ) result ;
901+ case TypeCode . UInt32 :
902+ return ( uint ) result ;
903+ default :
904+ return result ;
905+ }
906+ }
907+
908+ public static byte ParseByte ( ReadOnlySpan < char > value ) => ( byte ) ParseUInt64 ( value ) ;
909+ public static ushort ParseUInt16 ( ReadOnlySpan < char > value ) => ( ushort ) ParseUInt64 ( value ) ;
910+ public static uint ParseUInt32 ( ReadOnlySpan < char > value ) => ( uint ) ParseUInt64 ( value ) ;
911+
912+ internal static ulong ParseUInt64 ( ReadOnlySpan < char > value )
913+ {
914+ if ( value . IsEmpty )
915+ throw new FormatException ( MemoryProvider . BadFormat ) ;
916+
917+ ulong result = 0 ;
918+ int i = 0 ;
919+ int end = value . Length ;
920+ var state = ParseState . LeadingWhite ;
921+
922+ //skip leading whitespaces
923+ while ( i < end && JsonUtils . IsWhiteSpace ( value [ i ] ) ) i ++ ;
924+
925+ if ( i == end )
926+ throw new FormatException ( MemoryProvider . BadFormat ) ;
927+
928+ //skip leading zeros
929+ while ( i < end && value [ i ] == '0' )
930+ {
931+ state = ParseState . Number ;
932+ i ++ ;
933+ }
934+
935+ while ( i < end )
936+ {
937+ var c = value [ i ++ ] ;
938+
939+ switch ( state )
940+ {
941+ case ParseState . LeadingWhite :
942+ if ( JsonUtils . IsWhiteSpace ( c ) )
943+ break ;
944+ if ( c == '0' )
945+ {
946+ state = ParseState . TrailingWhite ;
947+ }
948+ else if ( c > '0' && c <= '9' )
949+ {
950+ result = ( ulong ) ( c - '0' ) ;
951+ state = ParseState . Number ;
952+ }
953+ else throw new FormatException ( MemoryProvider . BadFormat ) ;
954+
955+
956+ break ;
957+ case ParseState . Number :
958+ if ( c >= '0' && c <= '9' )
959+ {
960+ checked
961+ {
962+ result = 10 * result + ( ulong ) ( c - '0' ) ;
963+ }
964+
965+ if ( result > maxValue
966+ ) //check only minvalue, because in absolute value it's greater than maxvalue
967+ throw DefaultMemory . CreateOverflowException ( maxValue ) ;
968+ }
969+ else if ( JsonUtils . IsWhiteSpace ( c ) )
970+ {
971+ state = ParseState . TrailingWhite ;
972+ }
973+ else throw new FormatException ( MemoryProvider . BadFormat ) ;
974+
975+ break ;
976+ case ParseState . TrailingWhite :
977+ if ( JsonUtils . IsWhiteSpace ( c ) )
978+ {
979+ state = ParseState . TrailingWhite ;
980+ }
981+ else throw new FormatException ( MemoryProvider . BadFormat ) ;
982+
983+ break ;
984+ }
985+ }
986+
987+ if ( state != ParseState . Number && state != ParseState . TrailingWhite )
988+ throw new FormatException ( MemoryProvider . BadFormat ) ;
989+
990+ return result ;
991+ }
992+ }
672993}
0 commit comments