File: src\libraries\System.Private.CoreLib\src\System\Buffers\Text\Utf8Parser\Utf8Parser.Integer.Signed.N.cs
Web Access
Project: src\src\coreclr\System.Private.CoreLib\System.Private.CoreLib.csproj (System.Private.CoreLib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
namespace System.Buffers.Text
{
    public static partial class Utf8Parser
    {
        private static bool TryParseSByteN(ReadOnlySpan<byte> source, out sbyte value, out int bytesConsumed)
        {
            if (source.Length < 1)
                goto FalseExit;
 
            int sign = 1;
            int index = 0;
            int c = source[index];
            if (c == '-')
            {
                sign = -1;
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto FalseExit;
                c = source[index];
            }
            else if (c == '+')
            {
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto FalseExit;
                c = source[index];
            }
 
            int answer;
 
            // Handle the first digit (or period) as a special case. This ensures some compatible edge-case behavior with the classic parse routines
            // (at least one digit must precede any commas, and a string without any digits prior to the decimal point must have at least
            // one digit after the decimal point.)
            if (c == Utf8Constants.Period)
                goto FractionalPartWithoutLeadingDigits;
            if (!ParserHelpers.IsDigit(c))
                goto FalseExit;
            answer = c - '0';
 
            while (true)
            {
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto Done;
 
                c = source[index];
                if (c == Utf8Constants.Comma)
                    continue;
 
                if (c == Utf8Constants.Period)
                    goto FractionalDigits;
 
                if (!ParserHelpers.IsDigit(c))
                    goto Done;
 
                answer = answer * 10 + c - '0';
 
                // if sign < 0, (-1 * sign + 1) / 2 = 1
                // else, (-1 * sign + 1) / 2 = 0
                if (answer > sbyte.MaxValue + (-1 * sign + 1) / 2)
                    goto FalseExit; // Overflow
            }
 
        FractionalPartWithoutLeadingDigits: // If we got here, we found a decimal point before we found any digits. This is legal as long as there's at least one zero after the decimal point.
            answer = 0;
            index++;
            if ((uint)index >= (uint)source.Length)
                goto FalseExit;
            if (source[index] != '0')
                goto FalseExit;
 
        FractionalDigits: // "N" format allows a fractional portion despite being an integer format but only if the post-fraction digits are all 0.
            do
            {
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto Done;
                c = source[index];
            }
            while (c == '0');
 
            if (ParserHelpers.IsDigit(c))
                goto FalseExit; // The fractional portion contained a non-zero digit. Treat this as an error, not an early termination.
            goto Done;
 
        FalseExit:
            bytesConsumed = default;
            value = default;
            return false;
 
        Done:
            bytesConsumed = index;
            value = (sbyte)(answer * sign);
            return true;
        }
 
        private static bool TryParseInt16N(ReadOnlySpan<byte> source, out short value, out int bytesConsumed)
        {
            if (source.Length < 1)
                goto FalseExit;
 
            int sign = 1;
            int index = 0;
            int c = source[index];
            if (c == '-')
            {
                sign = -1;
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto FalseExit;
                c = source[index];
            }
            else if (c == '+')
            {
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto FalseExit;
                c = source[index];
            }
 
            int answer;
 
            // Handle the first digit (or period) as a special case. This ensures some compatible edge-case behavior with the classic parse routines
            // (at least one digit must precede any commas, and a string without any digits prior to the decimal point must have at least
            // one digit after the decimal point.)
            if (c == Utf8Constants.Period)
                goto FractionalPartWithoutLeadingDigits;
            if (!ParserHelpers.IsDigit(c))
                goto FalseExit;
            answer = c - '0';
 
            while (true)
            {
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto Done;
 
                c = source[index];
                if (c == Utf8Constants.Comma)
                    continue;
 
                if (c == Utf8Constants.Period)
                    goto FractionalDigits;
 
                if (!ParserHelpers.IsDigit(c))
                    goto Done;
 
                answer = answer * 10 + c - '0';
 
                // if sign < 0, (-1 * sign + 1) / 2 = 1
                // else, (-1 * sign + 1) / 2 = 0
                if (answer > short.MaxValue + (-1 * sign + 1) / 2)
                    goto FalseExit; // Overflow
            }
 
        FractionalPartWithoutLeadingDigits: // If we got here, we found a decimal point before we found any digits. This is legal as long as there's at least one zero after the decimal point.
            answer = 0;
            index++;
            if ((uint)index >= (uint)source.Length)
                goto FalseExit;
            if (source[index] != '0')
                goto FalseExit;
 
        FractionalDigits: // "N" format allows a fractional portion despite being an integer format but only if the post-fraction digits are all 0.
            do
            {
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto Done;
                c = source[index];
            }
            while (c == '0');
 
            if (ParserHelpers.IsDigit(c))
                goto FalseExit; // The fractional portion contained a non-zero digit. Treat this as an error, not an early termination.
            goto Done;
 
        FalseExit:
            bytesConsumed = default;
            value = default;
            return false;
 
        Done:
            bytesConsumed = index;
            value = (short)(answer * sign);
            return true;
        }
 
        private static bool TryParseInt32N(ReadOnlySpan<byte> source, out int value, out int bytesConsumed)
        {
            if (source.Length < 1)
                goto FalseExit;
 
            int sign = 1;
            int index = 0;
            int c = source[index];
            if (c == '-')
            {
                sign = -1;
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto FalseExit;
                c = source[index];
            }
            else if (c == '+')
            {
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto FalseExit;
                c = source[index];
            }
 
            int answer;
 
            // Handle the first digit (or period) as a special case. This ensures some compatible edge-case behavior with the classic parse routines
            // (at least one digit must precede any commas, and a string without any digits prior to the decimal point must have at least
            // one digit after the decimal point.)
            if (c == Utf8Constants.Period)
                goto FractionalPartWithoutLeadingDigits;
            if (!ParserHelpers.IsDigit(c))
                goto FalseExit;
            answer = c - '0';
 
            while (true)
            {
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto Done;
 
                c = source[index];
                if (c == Utf8Constants.Comma)
                    continue;
 
                if (c == Utf8Constants.Period)
                    goto FractionalDigits;
 
                if (!ParserHelpers.IsDigit(c))
                    goto Done;
 
                if (((uint)answer) > int.MaxValue / 10)
                    goto FalseExit;
 
                answer = answer * 10 + c - '0';
 
                // if sign < 0, (-1 * sign + 1) / 2 = 1
                // else, (-1 * sign + 1) / 2 = 0
                if ((uint)answer > (uint)int.MaxValue + (-1 * sign + 1) / 2)
                    goto FalseExit; // Overflow
            }
 
        FractionalPartWithoutLeadingDigits: // If we got here, we found a decimal point before we found any digits. This is legal as long as there's at least one zero after the decimal point.
            answer = 0;
            index++;
            if ((uint)index >= (uint)source.Length)
                goto FalseExit;
            if (source[index] != '0')
                goto FalseExit;
 
        FractionalDigits: // "N" format allows a fractional portion despite being an integer format but only if the post-fraction digits are all 0.
            do
            {
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto Done;
                c = source[index];
            }
            while (c == '0');
 
            if (ParserHelpers.IsDigit(c))
                goto FalseExit; // The fractional portion contained a non-zero digit. Treat this as an error, not an early termination.
            goto Done;
 
        FalseExit:
            bytesConsumed = default;
            value = default;
            return false;
 
        Done:
            bytesConsumed = index;
            value = answer * sign;
            return true;
        }
 
        private static bool TryParseInt64N(ReadOnlySpan<byte> source, out long value, out int bytesConsumed)
        {
            if (source.Length < 1)
                goto FalseExit;
 
            int sign = 1;
            int index = 0;
            int c = source[index];
            if (c == '-')
            {
                sign = -1;
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto FalseExit;
                c = source[index];
            }
            else if (c == '+')
            {
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto FalseExit;
                c = source[index];
            }
 
            long answer;
 
            // Handle the first digit (or period) as a special case. This ensures some compatible edge-case behavior with the classic parse routines
            // (at least one digit must precede any commas, and a string without any digits prior to the decimal point must have at least
            // one digit after the decimal point.)
            if (c == Utf8Constants.Period)
                goto FractionalPartWithoutLeadingDigits;
            if (!ParserHelpers.IsDigit(c))
                goto FalseExit;
            answer = c - '0';
 
            while (true)
            {
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto Done;
 
                c = source[index];
                if (c == Utf8Constants.Comma)
                    continue;
 
                if (c == Utf8Constants.Period)
                    goto FractionalDigits;
 
                if (!ParserHelpers.IsDigit(c))
                    goto Done;
 
                if (((ulong)answer) > long.MaxValue / 10)
                    goto FalseExit;
 
                answer = answer * 10 + c - '0';
 
                // if sign < 0, (-1 * sign + 1) / 2 = 1
                // else, (-1 * sign + 1) / 2 = 0
                if ((ulong)answer > (ulong)(long.MaxValue + (-1 * sign + 1) / 2))
                    goto FalseExit; // Overflow
            }
 
        FractionalPartWithoutLeadingDigits: // If we got here, we found a decimal point before we found any digits. This is legal as long as there's at least one zero after the decimal point.
            answer = 0;
            index++;
            if ((uint)index >= (uint)source.Length)
                goto FalseExit;
            if (source[index] != '0')
                goto FalseExit;
 
        FractionalDigits: // "N" format allows a fractional portion despite being an integer format but only if the post-fraction digits are all 0.
            do
            {
                index++;
                if ((uint)index >= (uint)source.Length)
                    goto Done;
                c = source[index];
            }
            while (c == '0');
 
            if (ParserHelpers.IsDigit(c))
                goto FalseExit; // The fractional portion contained a non-zero digit. Treat this as an error, not an early termination.
            goto Done;
 
        FalseExit:
            bytesConsumed = default;
            value = default;
            return false;
 
        Done:
            bytesConsumed = index;
            value = answer * sign;
            return true;
        }
    }
}