Skip to content

Instantly share code, notes, and snippets.

@RichardD2
Last active January 7, 2026 11:28
Show Gist options
  • Select an option

  • Save RichardD2/ee6c02a4386812d882ec630b6d1a3472 to your computer and use it in GitHub Desktop.

Select an option

Save RichardD2/ee6c02a4386812d882ec630b6d1a3472 to your computer and use it in GitHub Desktop.
Simple integer parsing from a ReadOnlySpan<char>
using System;
using System.Globalization;
using System.Runtime.CompilerServices;
internal static class Number
{
#if NET8_0_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool TryParseInt32(ReadOnlySpan<char> input, out int value) => int.TryParse(input, out value);
#else
internal static bool TryParseInt32(ReadOnlySpan<char> input, out int value)
{
// Ignore all leading and trailing white-space:
input = input.Trim();
if (input.IsEmpty)
{
value = 0;
return false;
}
// Check for a leading sign (+/-):
NumberFormatInfo format = NumberFormatInfo.CurrentInfo;
int sign = ExtractSign(ref input, format);
// Check that we have something other than the sign:
if (input.IsEmpty)
{
value = 0;
return false;
}
const uint Limit = int.MaxValue / 10; // Once we exceed this value, we cannot add another digit.
const uint PositiveLimit = (uint)int.MaxValue; // Maximum absolute value for positive integers.
const uint NegativeLimit = PositiveLimit + 1; // Maximum absolute value for negative integers.
uint result = 0;
foreach (char c in input)
{
// If it's not a valid digit, or we've already exceeded the limit, we cannot add another digit:
if (c < '0' || c > '9' || result > Limit)
{
value = 0;
return false;
}
result *= 10;
result += (uint)(c - '0');
// For positive values, verify that the result is not greater than int.MaxValue [2147483647];
// For negative values, verify that the result is not greater than Abs(int.MinValue) [2147483648]:
if (result > PositiveLimit)
{
if (sign == 1 || result > NegativeLimit)
{
value = 0;
return false;
}
}
}
value = sign * (int)result;
return true;
}
private static int ExtractSign(ref ReadOnlySpan<char> input, NumberFormatInfo format)
{
if (!string.IsNullOrEmpty(format.NegativeSign))
{
if (format.NegativeSign.Length == 1)
{
if (input[0] == format.NegativeSign[0])
{
input = input.Slice(1);
return -1; // Negative
}
}
else
{
if (input.StartsWith(format.NegativeSign))
{
input = input.Slice(format.NegativeSign.Length);
return -1; // Negative
}
}
}
if (!string.IsNullOrEmpty(format.PositiveSign))
{
if (format.PositiveSign.Length == 1)
{
if (input[0] == format.PositiveSign[0])
{
input = input.Slice(1);
}
}
else
{
if (input.StartsWith(format.PositiveSign))
{
input = input.Slice(format.PositiveSign.Length);
}
}
}
return 1; // Positive
}
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment