Example #1
0
        public static bool TryParseDecimal(ReadOnlySpan <char> value, bool allowThousands, out decimal result)
        {
            result = 0;

            if (value.Length == 0)
            {
                return(false);
            }

            ulong preResult     = 0;
            bool  isLargeNumber = false;
            int   i             = 0;
            int   end           = value.Length;
            var   state         = ParseState.LeadingWhite;
            bool  negative      = false;
            bool  noIntegerPart = false;
            sbyte scale         = 0;

            while (i < end)
            {
                var c = value[i++];

                switch (state)
                {
                case ParseState.LeadingWhite:
                    if (JsonUtils.IsWhiteSpace(c))
                    {
                        break;
                    }

                    if (c == '-')
                    {
                        negative = true;
                        state    = ParseState.Sign;
                    }
                    else if (c == '.')
                    {
                        noIntegerPart = true;
                        state         = ParseState.FractionNumber;

                        if (i == end)
                        {
                            return(false);
                        }
                    }
                    else if (c == '0')
                    {
                        state = ParseState.DecimalPoint;
                    }
                    else if (c > '0' && c <= '9')
                    {
                        preResult = (ulong)(c - '0');
                        state     = ParseState.Number;
                    }
                    else
                    {
                        return(false);
                    }

                    break;

                case ParseState.Sign:
                    if (c == '.')
                    {
                        noIntegerPart = true;
                        state         = ParseState.FractionNumber;

                        if (i == end)
                        {
                            return(false);
                        }
                    }
                    else if (c == '0')
                    {
                        state = ParseState.DecimalPoint;
                    }
                    else if (c > '0' && c <= '9')
                    {
                        preResult = (ulong)(c - '0');
                        state     = ParseState.Number;
                    }
                    else
                    {
                        return(false);
                    }

                    break;

                case ParseState.Number:
                    if (c == '.')
                    {
                        state = ParseState.FractionNumber;
                    }
                    else if (c >= '0' && c <= '9')
                    {
                        if (isLargeNumber)
                        {
                            checked
                            {
                                result = 10 * result + (c - '0');
                            }
                        }
                        else
                        {
                            preResult = 10 * preResult + (ulong)(c - '0');
                            if (preResult > ulong.MaxValue / 10 - 10)
                            {
                                isLargeNumber = true;
                                result        = preResult;
                            }
                        }
                    }
                    else if (JsonUtils.IsWhiteSpace(c))
                    {
                        state = ParseState.TrailingWhite;
                    }
                    else if (allowThousands && c == ',')
                    {
                    }
                    else
                    {
                        return(false);
                    }

                    break;

                case ParseState.DecimalPoint:
                    if (c == '.')
                    {
                        state = ParseState.FractionNumber;
                    }
                    else
                    {
                        return(false);
                    }

                    break;

                case ParseState.FractionNumber:
                    if (JsonUtils.IsWhiteSpace(c))
                    {
                        if (noIntegerPart)
                        {
                            return(false);
                        }
                        state = ParseState.TrailingWhite;
                    }
                    else if (c == 'e' || c == 'E')
                    {
                        if (noIntegerPart && scale == 0)
                        {
                            return(false);
                        }
                        state = ParseState.Exponent;
                    }
                    else if (c >= '0' && c <= '9')
                    {
                        if (isLargeNumber)
                        {
                            checked
                            {
                                result = 10 * result + (c - '0');
                            }
                        }
                        else
                        {
                            preResult = 10 * preResult + (ulong)(c - '0');
                            if (preResult > ulong.MaxValue / 10 - 10)
                            {
                                isLargeNumber = true;
                                result        = preResult;
                            }
                        }

                        scale++;
                    }
                    else
                    {
                        return(false);
                    }

                    break;

                case ParseState.Exponent:
                    bool expNegative = false;
                    if (c == '-')
                    {
                        if (i == end)
                        {
                            return(false);
                        }

                        expNegative = true;
                        c           = value[i++];
                    }
                    else if (c == '+')
                    {
                        if (i == end)
                        {
                            return(false);
                        }
                        c = value[i++];
                    }

                    //skip leading zeroes
                    while (c == '0' && i < end)
                    {
                        c = value[i++];
                    }

                    if (c > '0' && c <= '9')
                    {
                        var exp = SignedInteger <long> .ParseInt64(value.Slice(i - 1, end - i + 1));

                        if (exp < sbyte.MinValue || exp > sbyte.MaxValue)
                        {
                            return(false);
                        }

                        if (!expNegative)
                        {
                            exp = (sbyte)-exp;
                        }

                        if (exp >= 0 || scale > -exp)
                        {
                            scale += (sbyte)exp;
                        }
                        else
                        {
                            for (int j = 0; j < -exp - scale; j++)
                            {
                                if (isLargeNumber)
                                {
                                    checked
                                    {
                                        result = 10 * result;
                                    }
                                }
                                else
                                {
                                    preResult = 10 * preResult;
                                    if (preResult > ulong.MaxValue / 10)
                                    {
                                        isLargeNumber = true;
                                        result        = preResult;
                                    }
                                }
                            }

                            scale = 0;
                        }

                        //set i to end of string, because ParseInt16 eats number and all trailing whites
                        i = end;
                    }
                    else
                    {
                        return(false);
                    }

                    break;

                case ParseState.TrailingWhite:
                    if (!JsonUtils.IsWhiteSpace(c))
                    {
                        return(false);
                    }
                    break;
                }
            }

            if (!isLargeNumber)
            {
                var mid = (int)(preResult >> 32);
                var lo  = (int)(preResult & 0xffffffff);
                result = new decimal(lo, mid, 0, negative, (byte)scale);
            }
            else
            {
                var bits = decimal.GetBits(result);
                result = new decimal(bits[0], bits[1], bits[2], negative, (byte)scale);
            }

            return(true);
        }
Example #2
0
 public override long ParseInt64(ReadOnlySpan <char> value) => SignedInteger <int> .ParseInt64(value);