in csharp/src/Drivers/Apache/Hive2/DecimalUtility.cs [247:458]
private static void ParseDecimal(ReadOnlySpan<byte> value, out ParserState parserState)
{
ParserState state = new();
int index = 0;
int length = value.Length;
while (index < length)
{
byte c = value[index];
switch (state.CurrentState)
{
case ParseState.StartWhiteSpace:
if (c != AsciiSpace)
{
state.CurrentState = ParseState.SignOrDigitOrDecimal;
}
else
{
index++;
}
break;
case ParseState.SignOrDigitOrDecimal:
// Is Ascii Numeric
if ((uint)(c - AsciiZero) <= AsciiDigitMaxIndex)
{
if (!state.HasZero && c == AsciiZero) state.HasZero |= true;
state.IntegerStart = index;
state.IntegerEnd = index;
index++;
state.CurrentState = ParseState.DigitOrDecimalOrExponent;
}
else if (c == AsciiMinus || c == AsciiPlus)
{
state.SignIndex = index;
index++;
state.CurrentState = ParseState.DigitOrDecimalOrExponent;
}
else if (c == AsciiPeriod)
{
state.DecimalIndex = index;
index++;
state.CurrentState = ParseState.FractionOrExponent;
}
else if (c == AsciiSpace)
{
index++;
state.CurrentState = ParseState.EndWhiteSpace;
}
else
{
state.CurrentState = ParseState.Invalid;
}
break;
case ParseState.DigitOrDecimalOrExponent:
// Is Ascii Numeric
if ((uint)(c - AsciiZero) <= AsciiDigitMaxIndex)
{
if (state.IntegerStart == -1) state.IntegerStart = index;
if (!state.HasZero && c == AsciiZero) state.HasZero |= true;
state.IntegerEnd = index;
index++;
}
else if (c == AsciiPeriod)
{
state.DecimalIndex = index;
index++;
state.CurrentState = ParseState.FractionOrExponent;
}
else if (c == AsciiUpperE || c == AsciiLowerE)
{
state.ExponentIndex = index;
index++;
state.CurrentState = ParseState.ExpSignOrExpValue;
}
else if (c == AsciiSpace)
{
index++;
state.CurrentState = ParseState.EndWhiteSpace;
}
else
{
state.CurrentState = ParseState.Invalid;
}
break;
case ParseState.FractionOrExponent:
// Is Ascii Numeric
if ((uint)(c - AsciiZero) <= AsciiDigitMaxIndex)
{
if (state.FractionalStart == -1) state.FractionalStart = index;
if (!state.HasZero && c == AsciiZero) state.HasZero |= true;
state.FractionalEnd = index;
index++;
}
else if (c == AsciiUpperE || c == AsciiLowerE)
{
state.ExponentIndex = index;
index++;
state.CurrentState = ParseState.ExpSignOrExpValue;
}
else if (c == AsciiSpace)
{
index++;
state.CurrentState = ParseState.EndWhiteSpace;
}
else
{
state.CurrentState = ParseState.Invalid;
}
break;
case ParseState.ExpSignOrExpValue:
// Is Ascii Numeric
if ((uint)(c - AsciiZero) <= AsciiDigitMaxIndex)
{
if (state.ExponentStart == -1) state.ExponentStart = index;
state.ExponentEnd = index;
index++;
state.CurrentState = ParseState.ExpValue;
}
else if (c == AsciiMinus || c == AsciiPlus)
{
state.ExpSignIndex = index;
index++;
state.CurrentState = ParseState.ExpValue;
}
else if (c == AsciiSpace)
{
index++;
state.CurrentState = ParseState.EndWhiteSpace;
}
else
{
state.CurrentState = ParseState.Invalid;
}
break;
case ParseState.ExpValue:
// Is Ascii Numeric
if ((uint)(c - AsciiZero) <= AsciiDigitMaxIndex)
{
if (state.ExponentStart == -1) state.ExponentStart = index;
state.ExponentEnd = index;
index++;
}
else if (c == AsciiSpace)
{
index++;
state.CurrentState = ParseState.EndWhiteSpace;
}
else
{
state.CurrentState = ParseState.Invalid;
}
break;
case ParseState.EndWhiteSpace:
if (c == AsciiSpace)
{
index++;
state.CurrentState = ParseState.EndWhiteSpace;
}
else
{
state.CurrentState = ParseState.Invalid;
}
break;
case ParseState.Invalid:
throw new ArgumentOutOfRangeException(nameof(value), Encoding.UTF8.GetString(value), $"Invalid numeric value at index {index}.");
}
}
// Trim leading zeros from integer portion
if (state.IntegerStart != -1 && state.IntegerEnd != -1)
{
for (int i = state.IntegerStart; i <= state.IntegerEnd; i++)
{
if (value[i] != AsciiZero) break;
state.IntegerStart = i + 1;
if (state.IntegerStart > state.IntegerEnd)
{
state.IntegerStart = -1;
state.IntegerEnd = -1;
break;
}
}
}
// Trim trailing zeros from fractional portion
if (state.FractionalStart != -1 && state.FractionalEnd != -1)
{
for (int i = state.FractionalEnd; i >= state.FractionalStart; i--)
{
if (value[i] != AsciiZero) break;
state.FractionalEnd = i - 1;
if (state.FractionalStart > state.FractionalEnd)
{
state.FractionalStart = -1;
state.FractionalEnd = -1;
break;
}
}
}
// Must have a integer or fractional part.
if (state.IntegerStart == -1 && state.FractionalStart == -1)
{
if (!state.HasZero)
throw new ArgumentOutOfRangeException(nameof(value), Encoding.UTF8.GetString(value), "input does not contain a valid numeric value.");
else
{
state.IntegerStart = value.IndexOf(AsciiZero);
state.IntegerEnd = state.IntegerStart;
}
}
parserState = state;
}