public static bool TryParseInt64(ReadOnlySpan <byte> text, out long value, out int bytesConsumed, StandardFormat format = default, SymbolTable symbolTable = null) { symbolTable = symbolTable ?? SymbolTable.InvariantUtf8; if (!format.IsDefault && format.HasPrecision) { throw new NotImplementedException("Format with precision not supported."); } if (symbolTable == SymbolTable.InvariantUtf8) { if (Parsers.IsHexFormat(format)) { return(Utf8Parser.TryParse(text, out value, out bytesConsumed, 'X')); } else { return(Utf8Parser.TryParse(text, out value, out bytesConsumed)); } } else if (symbolTable == SymbolTable.InvariantUtf16) { ReadOnlySpan <char> utf16Text = MemoryMarshal.Cast <byte, char>(text); int charactersConsumed; bool result; if (Parsers.IsHexFormat(format)) { result = Utf16Parser.Hex.TryParseInt64(utf16Text, out value, out charactersConsumed); } else { result = Utf16Parser.TryParseInt64(utf16Text, out value, out charactersConsumed); } bytesConsumed = charactersConsumed * sizeof(char); return(result); } if (Parsers.IsHexFormat(format)) { throw new NotImplementedException("The only supported encodings for hexadecimal parsing are InvariantUtf8 and InvariantUtf16."); } if (!(format.IsDefault || format.Symbol == 'G' || format.Symbol == 'g')) { throw new NotImplementedException(String.Format("Format '{0}' not supported.", format.Symbol)); } if (!symbolTable.TryParse(text, out SymbolTable.Symbol nextSymbol, out int thisSymbolConsumed)) { value = default; bytesConsumed = 0; return(false); } int sign = 1; if (nextSymbol == SymbolTable.Symbol.MinusSign) { sign = -1; } int signConsumed = 0; if (nextSymbol == SymbolTable.Symbol.PlusSign || nextSymbol == SymbolTable.Symbol.MinusSign) { signConsumed = thisSymbolConsumed; if (!symbolTable.TryParse(text.Slice(signConsumed), out nextSymbol, out thisSymbolConsumed)) { value = default; bytesConsumed = 0; return(false); } } if (nextSymbol > SymbolTable.Symbol.D9) { value = default; bytesConsumed = 0; return(false); } long parsedValue = (long)nextSymbol; int index = signConsumed + thisSymbolConsumed; while (index < text.Length) { bool success = symbolTable.TryParse(text.Slice(index), out nextSymbol, out thisSymbolConsumed); if (!success || nextSymbol > SymbolTable.Symbol.D9) { bytesConsumed = index; value = (long)(parsedValue * sign); return(true); } // If parsedValue > (long.MaxValue / 10), any more appended digits will cause overflow. // if parsedValue == (long.MaxValue / 10), any nextDigit greater than 7 or 8 (depending on sign) implies overflow. bool positive = sign > 0; bool nextDigitTooLarge = nextSymbol > SymbolTable.Symbol.D8 || (positive && nextSymbol > SymbolTable.Symbol.D7); if (parsedValue > long.MaxValue / 10 || (parsedValue == long.MaxValue / 10 && nextDigitTooLarge)) { bytesConsumed = 0; value = default; return(false); } index += thisSymbolConsumed; parsedValue = parsedValue * 10 + (long)nextSymbol; } bytesConsumed = text.Length; value = (long)(parsedValue * sign); return(true); }