public static bool TryParseUInt32(byte[] text, int index, EncodingData encoding, TextFormat numericFormat, out uint value, out int bytesConsumed) { // Precondition replacement if (text.Length < 1 || index < 0 || index >= text.Length) { value = default(uint); bytesConsumed = 0; return false; } value = default(uint); bytesConsumed = 0; if (encoding.IsInvariantUtf8) { for (int byteIndex = index; byteIndex < text.Length; byteIndex++) // loop through the byte array { byte nextByteVal = (byte)(text[byteIndex] - '0'); if (nextByteVal > 9) // if nextByteVal > 9, we know it is not a digit because any value less than '0' will overflow // to greater than 9 since byte is an unsigned type. { if (bytesConsumed == 0) // check to see if we've processed any digits at all { return false; } else { return true; // otherwise return true } } else if (value > UInt32.MaxValue / 10) { value = default(uint); bytesConsumed = 0; return false; } // This next check uses a hardcoded 6 because the max values for unsigned types all end in 5s. else if (value == UInt32.MaxValue / 10 && nextByteVal >= 6) // overflow { value = default(uint); bytesConsumed = 0; return false; } value = (uint)(value * 10 + nextByteVal); // left shift the value and add the nextByte bytesConsumed++; } return true; } else if (encoding.IsInvariantUtf16) { for (int byteIndex = index; byteIndex < text.Length - 1; byteIndex += 2) // loop through the byte array two bytes at a time for UTF-16 { byte byteAfterNext = text[byteIndex + 1]; byte nextByteVal = (byte)(text[byteIndex] - '0'); if (nextByteVal > 9 || byteAfterNext != 0) // if the second byte isn't zero, this isn't an ASCII-equivalent code unit and we can quit here // if nextByteVal > 9, we know it is not a digit because any value less than '0' will overflow // to greater than 9 since byte is an unsigned type. { if (bytesConsumed == 0) // check to see if we've processed any digits at all { return false; } else { return true; // otherwise return true } } else if (value > UInt32.MaxValue / 10) { value = default(uint); bytesConsumed = 0; return false; } // This next check uses a hardcoded 6 because the max values for unsigned types all end in 5s. else if (value == UInt32.MaxValue / 10 && nextByteVal >= 6) // overflow { value = default(uint); bytesConsumed = 0; return false; } value = (uint)(value * 10 + nextByteVal); // left shift the value and add the nextByte bytesConsumed += 2; } return true; } else { while (bytesConsumed + index < text.Length) { uint result; int consumed; bool success = encoding.TryParseSymbol(text.Slice(bytesConsumed + index), out result, out consumed); if (!success || result > 9) { if (bytesConsumed == 0) // check to see if we've processed any digits at all { return false; } else { return true; // otherwise return true } } else if (value > UInt32.MaxValue / 10) { value = default(uint); bytesConsumed = 0; return false; } // This next check uses a hardcoded 6 because the max values for unsigned types all end in 5s. else if (value == UInt32.MaxValue / 10 && result >= 6) // overflow { value = default(uint); bytesConsumed = 0; return false; } value = (uint)(value * 10 + result); // left shift the value and add the nextByte bytesConsumed += consumed; } return true; } }
public static bool TryParseUInt64(ReadOnlySpan <byte> text, out ulong value, out int bytesConsumed, TextFormat format = default(TextFormat), EncodingData encoding = default(EncodingData)) { if (encoding == default(EncodingData)) { encoding = EncodingData.InvariantUtf8; } if (!format.IsDefault && format.HasPrecision) { throw new NotImplementedException("Format with precision not supported."); } if (encoding.IsInvariantUtf8) { if (format.IsHexadecimal) { return(InvariantUtf8.Hex.TryParseUInt64(text, out value, out bytesConsumed)); } else { return(InvariantUtf8.TryParseUInt64(text, out value, out bytesConsumed)); } } else if (encoding.IsInvariantUtf16) { ReadOnlySpan <char> utf16Text = text.Cast <byte, char>(); int charsConsumed; bool result; if (format.IsHexadecimal) { result = InvariantUtf16.Hex.TryParseUInt64(utf16Text, out value, out charsConsumed); } else { result = InvariantUtf16.TryParseUInt64(utf16Text, out value, out charsConsumed); } bytesConsumed = charsConsumed * sizeof(char); return(result); } if (format.IsHexadecimal) { 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)); } uint nextSymbol; int thisSymbolConsumed; if (!encoding.TryParseSymbol(text, out nextSymbol, out thisSymbolConsumed)) { value = default(ulong); bytesConsumed = 0; return(false); } if (nextSymbol > 9) { value = default(ulong); bytesConsumed = 0; return(false); } ulong parsedValue = nextSymbol; int index = thisSymbolConsumed; while (index < text.Length) { bool success = encoding.TryParseSymbol(text.Slice(index), out nextSymbol, out thisSymbolConsumed); if (!success || nextSymbol > 9) { bytesConsumed = index; value = (ulong)parsedValue; return(true); } // If parsedValue > (ulong.MaxValue / 10), any more appended digits will cause overflow. // if parsedValue == (ulong.MaxValue / 10), any nextDigit greater than 5 implies overflow. if (parsedValue > ulong.MaxValue / 10 || (parsedValue == ulong.MaxValue / 10 && nextSymbol > 5)) { bytesConsumed = 0; value = default(ulong); return(false); } index += thisSymbolConsumed; parsedValue = parsedValue * 10 + nextSymbol; } bytesConsumed = text.Length; value = (ulong)parsedValue; return(true); }
public static bool TryParseInt64(ReadOnlySpan <byte> text, out long value, out int bytesConsumed, EncodingData encoding = default(EncodingData), TextFormat format = default(TextFormat)) { if (format.HasPrecision) { throw new NotImplementedException("Format with precision not supported."); } if (encoding.IsInvariantUtf8) { if (format.IsHexadecimal) { return(InvariantUtf8.Hex.TryParseInt64(text, out value, out bytesConsumed)); } else { return(InvariantUtf8.TryParseInt64(text, out value, out bytesConsumed)); } } else if (encoding.IsInvariantUtf16) { ReadOnlySpan <char> utf16Text = text.Cast <byte, char>(); int charsConsumed; bool result; if (format.IsHexadecimal) { result = InvariantUtf16.Hex.TryParseInt64(utf16Text, out value, out charsConsumed); } else { result = InvariantUtf16.TryParseInt64(utf16Text, out value, out charsConsumed); } bytesConsumed = charsConsumed * sizeof(char); return(result); } if (format.IsHexadecimal) { 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)); } uint nextSymbol; int thisSymbolConsumed; if (!encoding.TryParseSymbol(text, out nextSymbol, out thisSymbolConsumed)) { value = default(long); bytesConsumed = 0; return(false); } int sign = 1; if ((EncodingData.Symbol)nextSymbol == EncodingData.Symbol.MinusSign) { sign = -1; } int signConsumed = 0; if ((EncodingData.Symbol)nextSymbol == EncodingData.Symbol.PlusSign || (EncodingData.Symbol)nextSymbol == EncodingData.Symbol.MinusSign) { signConsumed = thisSymbolConsumed; if (!encoding.TryParseSymbol(text.Slice(signConsumed), out nextSymbol, out thisSymbolConsumed)) { value = default(long); bytesConsumed = 0; return(false); } } if (nextSymbol > 9) { value = default(long); bytesConsumed = 0; return(false); } long parsedValue = (long)nextSymbol; int index = signConsumed + thisSymbolConsumed; while (index < text.Length) { bool success = encoding.TryParseSymbol(text.Slice(index), out nextSymbol, out thisSymbolConsumed); if (!success || nextSymbol > 9) { 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 > 8 || (positive && nextSymbol > 7); if (parsedValue > long.MaxValue / 10 || (parsedValue == long.MaxValue / 10 && nextDigitTooLarge)) { bytesConsumed = 0; value = default(long); return(false); } index += thisSymbolConsumed; parsedValue = parsedValue * 10 + (long)nextSymbol; } bytesConsumed = text.Length; value = (long)(parsedValue * sign); return(true); }
public static bool TryParseInt16(byte[] text, int index, EncodingData encoding, TextFormat numericFormat, out short value, out int bytesConsumed) { // Precondition replacement if (text.Length < 1 || index < 0 || index >= text.Length) { value = default(short); bytesConsumed = 0; return false; } value = default(short); bytesConsumed = 0; bool negative = false; bool signed = false; if (encoding.IsInvariantUtf8) { if (text[index] == '-') { negative = true; signed = true; index++; bytesConsumed++; } else if (text[index] == '+') { signed = true; index++; bytesConsumed++; } for (int byteIndex = index; byteIndex < text.Length; byteIndex++) // loop through the byte array { byte nextByteVal = (byte)(text[byteIndex] - '0'); if (nextByteVal > 9) // if nextByteVal > 9, we know it is not a digit because any value less than '0' will overflow // to greater than 9 since byte is an unsigned type. { if (bytesConsumed == 1 && signed) // if the first character happened to be a '-' or a '+', we reset the byte counter so logic proceeds as normal. { bytesConsumed = 0; } if (bytesConsumed == 0) // check to see if we've processed any digits at all { return false; } else { if (negative) // We check if the value is negative at the very end to save on comp time { value = (short)-value; if (value > 0) { value = 0; bytesConsumed = 0; return false; } } return true; // otherwise return true } } else if (value > Int16.MaxValue / 10) // overflow { value = default(short); bytesConsumed = 0; return false; } // This next check uses a hardcoded 8 because the max values for unsigned types all end in 7s. // The min values all end in 8s, which is why that addition exists. else if (value == Int16.MaxValue / 10 && nextByteVal >= 8 + (negative ? 1 : 0) ) // overflow { value = default(short); bytesConsumed = 0; return false; } value = (short)(value * 10 + nextByteVal); // parse the current digit to a short and add it to the left-shifted value bytesConsumed++; // increment the number of bytes consumed, then loop } if (negative) // We check if the value is negative at the very end to save on comp time { value = (short)-value; if (value > 0) { value = 0; bytesConsumed = 0; return false; } } return true; } else if (encoding.IsInvariantUtf16) { if (text[index] == '-' && text[index + 1] == 0) { negative = true; signed = true; index += 2; bytesConsumed += 2; } else if (text[index] == '+' && text[index + 1] == 0) { signed = true; index += 2; bytesConsumed += 2; } for (int byteIndex = index; byteIndex < text.Length - 1; byteIndex += 2) // loop through the byte array two bytes at a time for UTF-16 { byte byteAfterNext = text[byteIndex + 1]; byte nextByteVal = (byte)(text[byteIndex] - '0'); if (nextByteVal > 9 || byteAfterNext != 0) // if the second byte isn't zero, this isn't an ASCII-equivalent code unit and we can quit here // if nextByteVal > 9, we know it is not a digit because any value less than '0' will overflow // to greater than 9 since byte is an unsigned type. { if (bytesConsumed == 2 && signed) // if the first character happened to be a '-' or a '+', we reset the byte counter so logic proceeds as normal { bytesConsumed = 0; } if (bytesConsumed == 0) // check to see if we've processed any digits at all { return false; } else { if (negative) // We check if the value is negative at the very end to save on comp time { value = (short)-value; if (value > 0) { value = 0; bytesConsumed = 0; return false; } } return true; // otherwise return true } } else if (value > Int16.MaxValue / 10) // overflow { value = default(short); bytesConsumed = 0; return false; } // This next check uses a hardcoded 8 because the max values for unsigned types all end in 7s. // The min values all end in 8s, which is why that addition exists. else if (value == Int16.MaxValue / 10 && nextByteVal >= 8 + (negative ? 1 : 0) ) // overflow { value = default(short); bytesConsumed = 0; return false; } value = (short)(value * 10 + nextByteVal); // parse the current digit to a short and add it to the left-shifted value bytesConsumed += 2; // increment the number of bytes consumed, then loop } if (negative) // We check if the value is negative at the very end to save on comp time { value = (short)-value; if (value > 0) { value = 0; bytesConsumed = 0; return false; } } return true; } else { int codeUnitsConsumed = 0; while (bytesConsumed + index < text.Length) { uint result; int consumed; bool success = encoding.TryParseSymbol(text.Slice(bytesConsumed + index), out result, out consumed); if (!success || result > 9) { if (bytesConsumed == 0 && result == (int)EncodingData.Symbol.MinusSign) { negative = true; signed = true; bytesConsumed += consumed; codeUnitsConsumed++; } else if (bytesConsumed == 0 && result == (int)EncodingData.Symbol.PlusSign) { negative = true; signed = true; bytesConsumed += consumed; } else if (codeUnitsConsumed == 1 && signed) // if the first character happened to be a '-' or a '+', we reset the byte counter so logic proceeds as normal. { bytesConsumed = 0; return false; } else if (bytesConsumed == 0) // check to see if we've processed any digits at all { return false; } else { if (negative) // We check if the value is negative at the very end to save on comp time { value = (short)-value; if (value > 0) { value = 0; bytesConsumed = 0; return false; } } return true; // otherwise return true } } else if (value > Int16.MaxValue / 10) { value = default(short); bytesConsumed = 0; return false; } // This next check uses a hardcoded 8 because the max values for unsigned types all end in 7s. // The min values all end in 8s, which is why that addition exists. else if (value == Int16.MaxValue / 10 && result >= 8 + (negative ? 1 : 0) ) // overflow { value = default(short); bytesConsumed = 0; return false; } else { value = (short)(value * 10 + result); // left shift the value and add the nextByte bytesConsumed += consumed; codeUnitsConsumed++; } } if (negative) // We check if the value is negative at the very end to save on comp time { value = (short)-value; if (value > 0) { value = default(short); bytesConsumed = 0; return false; } } return true; // otherwise return true } }