@@ -690,6 +690,42 @@ static T ParseArgument<T>(ref Span<string> args, int i)
690690 return default;
691691 }
692692
693+ static void RemoveRange(ref Span<string> args, int index, int length)
694+ {
695+ if (length <= 0) return;
696+
697+ // Fast path(removing from start/end) no need copy
698+ if (index == 0)
699+ {
700+ args = args.Slice(length);
701+ return;
702+ }
703+ else if (index + length == args.Length)
704+ {
705+ args = args.Slice(0, index);
706+ return;
707+ }
708+
709+ // Otherwise, need to copy
710+ var temp = new string[args.Length - length];
711+ args.Slice(0, index).CopyTo(temp);
712+ args.Slice(index + length).CopyTo(temp.AsSpan(index));
713+ args = temp;
714+ }
715+
716+ static bool Contains(ReadOnlySpan<char> nameToSlice, Span<Range> ranges, string target)
717+ {
718+ for (int i = 0; i < ranges.Length; i++)
719+ {
720+ var name = nameToSlice[ranges[i]].Trim();
721+ if (name.Equals(target, StringComparison.OrdinalIgnoreCase))
722+ {
723+ return true;
724+ }
725+ }
726+ return false;
727+ }
728+
693729 static bool TryParse<T>(string s, out T result)
694730 {
695731 if (typeof(T) == typeof(string))
@@ -737,31 +773,31 @@ static bool TryParse<T>(string s, out T result)
737773 result = default;
738774 return false;
739775 }
740- else if (typeof(T) == typeof(ushort ))
776+ else if (typeof(T) == typeof(int ))
741777 {
742- if (ushort .TryParse(s, out var v))
778+ if (int .TryParse(s, out var v))
743779 {
744- result = Unsafe.As<ushort , T>(ref v);
780+ result = Unsafe.As<int , T>(ref v);
745781 return true;
746782 }
747783 result = default;
748784 return false;
749785 }
750- else if (typeof(T) == typeof(int ))
786+ else if (typeof(T) == typeof(long ))
751787 {
752- if (int .TryParse(s, out var v))
788+ if (long .TryParse(s, out var v))
753789 {
754- result = Unsafe.As<int , T>(ref v);
790+ result = Unsafe.As<long , T>(ref v);
755791 return true;
756792 }
757793 result = default;
758794 return false;
759795 }
760- else if (typeof(T) == typeof(long ))
796+ else if (typeof(T) == typeof(ushort ))
761797 {
762- if (long .TryParse(s, out var v))
798+ if (ushort .TryParse(s, out var v))
763799 {
764- result = Unsafe.As<long , T>(ref v);
800+ result = Unsafe.As<ushort , T>(ref v);
765801 return true;
766802 }
767803 result = default;
@@ -787,31 +823,31 @@ static bool TryParse<T>(string s, out T result)
787823 result = default;
788824 return false;
789825 }
790- else if (typeof(T) == typeof(decimal ))
826+ else if (typeof(T) == typeof(float ))
791827 {
792- if (decimal .TryParse(s, out var v))
828+ if (float .TryParse(s, out var v))
793829 {
794- result = Unsafe.As<decimal , T>(ref v);
830+ result = Unsafe.As<float , T>(ref v);
795831 return true;
796832 }
797833 result = default;
798834 return false;
799835 }
800- else if (typeof(T) == typeof(float ))
836+ else if (typeof(T) == typeof(double ))
801837 {
802- if (float .TryParse(s, out var v))
838+ if (double .TryParse(s, out var v))
803839 {
804- result = Unsafe.As<float , T>(ref v);
840+ result = Unsafe.As<double , T>(ref v);
805841 return true;
806842 }
807843 result = default;
808844 return false;
809845 }
810- else if (typeof(T) == typeof(double ))
846+ else if (typeof(T) == typeof(decimal ))
811847 {
812- if (double .TryParse(s, out var v))
848+ if (decimal .TryParse(s, out var v))
813849 {
814- result = Unsafe.As<double , T>(ref v);
850+ result = Unsafe.As<decimal , T>(ref v);
815851 return true;
816852 }
817853 result = default;
@@ -827,44 +863,138 @@ static bool TryParse<T>(string s, out T result)
827863 return true;
828864 }
829865 }
866+
867+ var underlyingType = Nullable.GetUnderlyingType(typeof(T));
868+ if (underlyingType != null)
869+ {
870+ return TryParseNullable<T>(underlyingType, s, out result);
871+ }
872+
830873 result = default;
831874 return false;
832875 }
833876 }
834877
835- static void RemoveRange(ref Span<string> args, int index, int length )
878+ static bool TryParseNullable<T>(Type underlyingType, string s, out T result )
836879 {
837- if (length <= 0) return;
838-
839- // Fast path(removing from start/end) no need copy
840- if (index == 0)
880+ if (underlyingType == typeof(char))
841881 {
842- args = args.Slice(length);
843- return;
882+ if (char.TryParse(s, out var v))
883+ {
884+ var nullableValue = new char?(v);
885+ result = Unsafe.As<char?, T>(ref nullableValue);
886+ return true;
887+ }
844888 }
845- else if (index + length == args.Length )
889+ else if (underlyingType == typeof(sbyte) )
846890 {
847- args = args.Slice(0, index);
848- return;
891+ if (sbyte.TryParse(s, out var v))
892+ {
893+ var nullableValue = new sbyte?(v);
894+ result = Unsafe.As<sbyte?, T>(ref nullableValue);
895+ return true;
896+ }
849897 }
850-
851- // Otherwise, need to copy
852- var temp = new string[args.Length - length];
853- args.Slice(0, index).CopyTo(temp);
854- args.Slice(index + length).CopyTo(temp.AsSpan(index));
855- args = temp;
856- }
857-
858- static bool Contains(ReadOnlySpan<char> nameToSlice, Span<Range> ranges, string target)
859- {
860- for (int i = 0; i < ranges.Length; i++)
898+ else if (underlyingType == typeof(byte))
861899 {
862- var name = nameToSlice[ranges[i]].Trim();
863- if (name.Equals(target, StringComparison.OrdinalIgnoreCase))
900+ if (byte.TryParse(s, out var v))
901+ {
902+ var nullableValue = new byte?(v);
903+ result = Unsafe.As<byte?, T>(ref nullableValue);
904+ return true;
905+ }
906+ }
907+ else if (underlyingType == typeof(short))
908+ {
909+ if (short.TryParse(s, out var v))
910+ {
911+ var nullableValue = new short?(v);
912+ result = Unsafe.As<short?, T>(ref nullableValue);
913+ return true;
914+ }
915+ }
916+ else if (underlyingType == typeof(int))
917+ {
918+ if (int.TryParse(s, out var v))
919+ {
920+ var nullableValue = new int?(v);
921+ result = Unsafe.As<int?, T>(ref nullableValue);
922+ return true;
923+ }
924+ }
925+ else if (underlyingType == typeof(long))
926+ {
927+ if (long.TryParse(s, out var v))
864928 {
929+ var nullableValue = new long?(v);
930+ result = Unsafe.As<long?, T>(ref nullableValue);
865931 return true;
866932 }
867933 }
934+ else if (underlyingType == typeof(ushort))
935+ {
936+ if (ushort.TryParse(s, out var v))
937+ {
938+ var nullableValue = new ushort?(v);
939+ result = Unsafe.As<ushort?, T>(ref nullableValue);
940+ return true;
941+ }
942+ }
943+ else if (underlyingType == typeof(uint))
944+ {
945+ if (uint.TryParse(s, out var v))
946+ {
947+ var nullableValue = new uint?(v);
948+ result = Unsafe.As<uint?, T>(ref nullableValue);
949+ return true;
950+ }
951+ }
952+ else if (underlyingType == typeof(ulong))
953+ {
954+ if (ulong.TryParse(s, out var v))
955+ {
956+ var nullableValue = new ulong?(v);
957+ result = Unsafe.As<ulong?, T>(ref nullableValue);
958+ return true;
959+ }
960+ }
961+ else if (underlyingType == typeof(float))
962+ {
963+ if (float.TryParse(s, out var v))
964+ {
965+ var nullableValue = new float?(v);
966+ result = Unsafe.As<float?, T>(ref nullableValue);
967+ return true;
968+ }
969+ }
970+ else if (underlyingType == typeof(double))
971+ {
972+ if (double.TryParse(s, out var v))
973+ {
974+ var nullableValue = new double?(v);
975+ result = Unsafe.As<double?, T>(ref nullableValue);
976+ return true;
977+ }
978+ }
979+ else if (underlyingType == typeof(decimal))
980+ {
981+ if (decimal.TryParse(s, out var v))
982+ {
983+ var nullableValue = new decimal?(v);
984+ result = Unsafe.As<decimal?, T>(ref nullableValue);
985+ return true;
986+ }
987+ }
988+ else if (underlyingType.IsEnum)
989+ {
990+ if (Enum.TryParse(underlyingType, s, ignoreCase: true, out var v))
991+ {
992+ result = (T)v;
993+ return true;
994+ }
995+ }
996+
997+ result = default;
868998 return false;
869999 }
8701000 }
0 commit comments