public static bool TryFormat(this DateTime value, Span<byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { if (format.IsDefault) { format.Symbol = 'G'; } Precondition.Require(format.Symbol == 'R' || format.Symbol == 'O' || format.Symbol == 'G'); switch (format.Symbol) { case 'R': var utc = value.ToUniversalTime(); if (formattingData.IsUtf16) { return TryFormatDateTimeRfc1123(utc, buffer, EncodingData.InvariantUtf16, out bytesWritten); } else { return TryFormatDateTimeRfc1123(utc, buffer, EncodingData.InvariantUtf8, out bytesWritten); } case 'O': if (formattingData.IsUtf16) { return TryFormatDateTimeFormatO(value, true, buffer, EncodingData.InvariantUtf16, out bytesWritten); } else { return TryFormatDateTimeFormatO(value, true, buffer, EncodingData.InvariantUtf8, out bytesWritten); } case 'G': return TryFormatDateTimeFormagG(value, buffer, formattingData, out bytesWritten); default: throw new NotImplementedException(); } }
public static bool TryFormat(this DateTimeOffset value, Span<byte> buffer, TextFormat format, EncodingData formattingData, out int bytesWritten) { if (format.IsDefault) { format.Symbol = 'G'; } Precondition.Require(format.Symbol == 'R' || format.Symbol == 'O' || format.Symbol == 'G'); switch (format.Symbol) { case 'R': if (formattingData.IsInvariantUtf16) // TODO: there are many checks like this one in the code. They need to also verify that the UTF8 branch is invariant. { return TryFormatDateTimeRfc1123(value.UtcDateTime, buffer, EncodingData.InvariantUtf16, out bytesWritten); } else { return TryFormatDateTimeRfc1123(value.UtcDateTime, buffer, EncodingData.InvariantUtf8, out bytesWritten); } case 'O': if (formattingData.IsInvariantUtf16) { return TryFormatDateTimeFormatO(value.UtcDateTime, false, buffer, EncodingData.InvariantUtf16, out bytesWritten); } else { return TryFormatDateTimeFormatO(value.UtcDateTime, false, buffer, EncodingData.InvariantUtf8, out bytesWritten); } case 'G': return TryFormatDateTimeFormagG(value.DateTime, buffer, formattingData, out bytesWritten); default: throw new NotImplementedException(); } }
internal static bool TryFormatInt64(long value, byte numberOfBytes, Span<byte> buffer, TextFormat format, EncodingData formattingData, out int bytesWritten) { Precondition.Require(numberOfBytes <= sizeof(long)); if (value >= 0) { return TryFormatUInt64(unchecked((ulong)value), numberOfBytes, buffer, format, formattingData, out bytesWritten); } else if (format.IsHexadecimal) { ulong bitMask = GetBitMask(numberOfBytes); return TryFormatUInt64(unchecked((ulong)value) & bitMask, numberOfBytes, buffer, format, formattingData, out bytesWritten); } else { int minusSignBytes = 0; if(!formattingData.TryEncode(EncodingData.Symbol.MinusSign, buffer, out minusSignBytes)) { bytesWritten = 0; return false; } int digitBytes = 0; if(!TryFormatUInt64(unchecked((ulong)-value), numberOfBytes, buffer.Slice(minusSignBytes), format, formattingData, out digitBytes)) { bytesWritten = 0; return false; } bytesWritten = digitBytes + minusSignBytes; return true; } }
// TODO: format should be ReadOnlySpan<char> internal static bool TryFormatInt64(long value, byte numberOfBytes, Span<byte> buffer, ReadOnlySpan<char> format, EncodingData formattingData, out int bytesWritten) { Precondition.Require(numberOfBytes <= sizeof(long)); TextFormat parsedFormat = TextFormat.Parse(format); return TryFormatInt64(value, numberOfBytes, buffer, parsedFormat, formattingData, out bytesWritten); }
internal static bool TryFormatUInt64(ulong value, byte numberOfBytes, Span<byte> buffer, TextFormat format, EncodingData formattingData, out int bytesWritten) { if(format.Symbol == 'g') { format.Symbol = 'G'; } if (format.IsHexadecimal && formattingData.IsInvariantUtf16) { return TryFormatHexadecimalInvariantCultureUtf16(value, buffer, format, out bytesWritten); } if (format.IsHexadecimal && formattingData.IsInvariantUtf8) { return TryFormatHexadecimalInvariantCultureUtf8(value, buffer, format, out bytesWritten); } if ((formattingData.IsInvariantUtf16) && (format.Symbol == 'D' || format.Symbol == 'G')) { return TryFormatDecimalInvariantCultureUtf16(value, buffer, format, out bytesWritten); } if ((formattingData.IsInvariantUtf8) && (format.Symbol == 'D' || format.Symbol == 'G')) { return TryFormatDecimalInvariantCultureUtf8(value, buffer, format, out bytesWritten); } return TryFormatDecimal(value, buffer, format, formattingData, out bytesWritten); }
// Sets up cultures with digits represented by 1 or 5 'A's (0) through 1 or 5 'J's (9) and the minus sigh represented by an underscore followed by a question mark static CustomCultureTests() { byte[][] utf16digitsAndSymbols = new byte[17][]; for (ushort digit = 0; digit < 10; digit++) { char digitChar = (char)(digit + 'A'); var digitString = new string(digitChar, 5); utf16digitsAndSymbols[digit] = GetBytesUtf16(digitString); } utf16digitsAndSymbols[(ushort)EncodingData.Symbol.DecimalSeparator] = GetBytesUtf16("."); utf16digitsAndSymbols[(ushort)EncodingData.Symbol.GroupSeparator] = GetBytesUtf16(","); utf16digitsAndSymbols[(ushort)EncodingData.Symbol.MinusSign] = GetBytesUtf16("_?"); Culture5 = new EncodingData(utf16digitsAndSymbols, EncodingData.Encoding.Utf16); utf16digitsAndSymbols = new byte[17][]; for (ushort digit = 0; digit < 10; digit++) { char digitChar = (char)(digit + 'A'); var digitString = new string(digitChar, 1); utf16digitsAndSymbols[digit] = GetBytesUtf16(digitString); } utf16digitsAndSymbols[(ushort)EncodingData.Symbol.DecimalSeparator] = GetBytesUtf16("."); utf16digitsAndSymbols[(ushort)EncodingData.Symbol.GroupSeparator] = GetBytesUtf16(","); utf16digitsAndSymbols[(ushort)EncodingData.Symbol.MinusSign] = GetBytesUtf16("_?"); Culture1 = new EncodingData(utf16digitsAndSymbols, EncodingData.Encoding.Utf16); }
public static bool TryFormat(this float value, Span<byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { if (format.IsDefault) { format.Symbol = 'G'; } Precondition.Require(format.Symbol == 'G'); return FloatFormatter.TryFormatNumber(value, true, buffer, format, formattingData, out bytesWritten); }
public StreamFormatter(Stream stream, EncodingData encoding, ArrayPool<byte> pool, int bufferSize = 256) { _pool = pool; _buffer = null; if (bufferSize > 0) { _buffer = _pool.Rent(bufferSize); } _encoding = encoding; _stream = stream; }
public static bool TryFormat(this char value, Span<byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { if (formattingData.IsUtf16) { if (buffer.Length < 2) { bytesWritten = 0; return false; } buffer[0] = (byte)value; buffer[1] = (byte)(value >> 8); bytesWritten = 2; return true; } if (buffer.Length < 1) { bytesWritten = 0; return false; } // fast path for ASCII if (value <= 127) { buffer[0] = (byte)value; bytesWritten = 1; return true; } // TODO: This can be directly encoded to SpanByte. There is no conversion between spans yet var encoded = new Utf8EncodedCodePoint(value); bytesWritten = encoded.Length; if (buffer.Length < bytesWritten) { bytesWritten = 0; return false; } buffer[0] = encoded.Byte0; if(bytesWritten > 1) { buffer[1] = encoded.Byte1; } if(bytesWritten > 2) { buffer[2] = encoded.Byte2; } if(bytesWritten > 3) { buffer[3] = encoded.Byte3; } return true; }
public bool TryFormat(Span<byte> buffer, Format.Parsed format, EncodingData encoding, out int bytesWritten) { if (!PrimitiveFormatter.TryFormat(_age, buffer, format, encoding, out bytesWritten)) return false; char symbol = _inMonths ? 'm' : 'y'; int symbolBytes; if (!PrimitiveFormatter.TryFormat(symbol, buffer.Slice(bytesWritten), format, encoding, out symbolBytes)) return false; bytesWritten += symbolBytes; return true; }
public bool TryFormat(Span<byte> buffer, out int bytesWritten, TextFormat format, EncodingData encoding) { if (!PrimitiveFormatter.TryFormat(_age, buffer, out bytesWritten, format, encoding)) return false; char symbol = _inMonths ? 'm' : 'y'; int symbolBytes; if (!PrimitiveFormatter.TryEncode(symbol, buffer.Slice(bytesWritten), out symbolBytes, encoding.TextEncoding)) return false; bytesWritten += symbolBytes; return true; }
public static bool TryParseDecimal(ReadOnlySpan<byte> text, out decimal value, out int bytesConsumed, EncodingData encoding = default(EncodingData)) { bytesConsumed = 0; value = default(decimal); if (encoding.IsInvariantUtf8) { return InvariantUtf8.TryParseDecimal(text, out value, out bytesConsumed); } else if (encoding.IsInvariantUtf16) { ReadOnlySpan<char> textChars = text.Cast<byte, char>(); int charactersConsumed; bool result = InvariantUtf16.TryParseDecimal(textChars, out value, out charactersConsumed); bytesConsumed = charactersConsumed * sizeof(char); return result; } return false; }
public static bool TryFormatNumber(double value, bool isSingle, Span<byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { Precondition.Require(format.Symbol == 'G' || format.Symbol == 'E' || format.Symbol == 'F'); bytesWritten = 0; int written; if (Double.IsNaN(value)) { return formattingData.TryWriteSymbol(EncodingData.Symbol.NaN, buffer, out bytesWritten); } if (Double.IsInfinity(value)) { if (Double.IsNegativeInfinity(value)) { if (!formattingData.TryWriteSymbol(EncodingData.Symbol.MinusSign, buffer, out written)) { bytesWritten = 0; return false; } bytesWritten += written; } if (!formattingData.TryWriteSymbol(EncodingData.Symbol.InfinitySign, buffer.Slice(bytesWritten), out written)) { bytesWritten = 0; return false; } bytesWritten += written; return true; } // TODO: the lines below need to be replaced with properly implemented algorithm // the problem is the algorithm is complex, so I am commiting a stub for now var hack = value.ToString(format.Symbol.ToString()); return hack.TryFormat(buffer, default(Format.Parsed), formattingData, out bytesWritten); }
internal static bool TryFormatInt64(long value, byte numberOfBytes, Span <byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { Precondition.Require(numberOfBytes <= sizeof(long)); if (value >= 0) { return(TryFormatUInt64(unchecked ((ulong)value), numberOfBytes, buffer, format, formattingData, out bytesWritten)); } else if (format.IsHexadecimal) { ulong bitMask = GetBitMask(numberOfBytes); return(TryFormatUInt64(unchecked ((ulong)value) & bitMask, numberOfBytes, buffer, format, formattingData, out bytesWritten)); } else { int minusSignBytes = 0; if (!formattingData.TryWriteSymbol(EncodingData.Symbol.MinusSign, buffer, out minusSignBytes)) { bytesWritten = 0; return(false); } int digitBytes = 0; if (!TryFormatUInt64(unchecked ((ulong)-value), numberOfBytes, buffer.Slice(minusSignBytes), format, formattingData, out digitBytes)) { bytesWritten = 0; return(false); } bytesWritten = digitBytes + minusSignBytes; return(true); } }
public static bool TryFormat(this long value, Span <byte> buffer, out int bytesWritten, TextFormat format = default(TextFormat), EncodingData encoding = default(EncodingData)) { return(IntegerFormatter.TryFormatInt64(value, 8, buffer, out bytesWritten, format, encoding)); }
// TODO: this whole routine is too slow. It does div and mod twice, which are both costly (especially that some JITs cannot optimize it). // It does it twice to avoid reversing the formatted buffer, which can be tricky given it should handle arbitrary cultures. // One optimization I thought we could do is to do div/mod once and store digits in a temp buffer (but that would allocate). Modification to the idea would be to store the digits in a local struct // Another idea possibly worth tying would be to special case cultures that have constant digit size, and go back to the format + reverse buffer approach. private static bool TryFormatDecimal(ulong value, Span<byte> buffer, TextFormat format, EncodingData formattingData, out int bytesWritten) { if(format.IsDefault) { format.Symbol = 'G'; } format.Symbol = Char.ToUpperInvariant(format.Symbol); // TODO: this is costly. I think the transformation should happen in Parse Precondition.Require(format.Symbol == 'D' || format.Symbol == 'G' || format.Symbol == 'N'); // Reverse value on decimal basis, count digits and trailing zeros before the decimal separator ulong reversedValueExceptFirst = 0; var digitsCount = 1; var trailingZerosCount = 0; // We reverse the digits in numeric form because reversing encoded digits is hard and/or costly. // If value contains 20 digits, its reversed value will not fit into ulong size. // So reverse it till last digit (reversedValueExceptFirst will have all the digits except the first one). while (value >= 10) { var digit = value % 10UL; value = value / 10UL; if (reversedValueExceptFirst == 0 && digit == 0) { trailingZerosCount++; } else { reversedValueExceptFirst = reversedValueExceptFirst * 10UL + digit; digitsCount++; } } bytesWritten = 0; int digitBytes; // If format is D and precision is greater than digitsCount + trailingZerosCount, append leading zeros if (format.Symbol == 'D' && format.HasPrecision) { var leadingZerosCount = format.Precision - digitsCount - trailingZerosCount; while (leadingZerosCount-- > 0) { if (!formattingData.TryEncode(EncodingData.Symbol.D0, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return false; } bytesWritten += digitBytes; } } // Append first digit if (!formattingData.TryEncode((EncodingData.Symbol)value, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return false; } bytesWritten += digitBytes; digitsCount--; if (format.Symbol == 'N') { const int GroupSize = 3; // Count amount of digits before first group separator. It will be reset to groupSize every time digitsLeftInGroup == zero var digitsLeftInGroup = (digitsCount + trailingZerosCount) % GroupSize; if (digitsLeftInGroup == 0) { if (digitsCount + trailingZerosCount > 0) { // There is a new group immediately after the first digit if (!formattingData.TryEncode(EncodingData.Symbol.GroupSeparator, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return false; } bytesWritten += digitBytes; } digitsLeftInGroup = GroupSize; } // Append digits while (reversedValueExceptFirst > 0) { if (digitsLeftInGroup == 0) { if (!formattingData.TryEncode(EncodingData.Symbol.GroupSeparator, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return false; } bytesWritten += digitBytes; digitsLeftInGroup = GroupSize; } var nextDigit = reversedValueExceptFirst % 10UL; reversedValueExceptFirst = reversedValueExceptFirst / 10UL; if (!formattingData.TryEncode((EncodingData.Symbol)nextDigit, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return false; } bytesWritten += digitBytes; digitsLeftInGroup--; } // Append trailing zeros if any while (trailingZerosCount-- > 0) { if (digitsLeftInGroup == 0) { if (!formattingData.TryEncode(EncodingData.Symbol.GroupSeparator, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return false; } bytesWritten += digitBytes; digitsLeftInGroup = GroupSize; } if (!formattingData.TryEncode(EncodingData.Symbol.D0, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return false; } bytesWritten += digitBytes; digitsLeftInGroup--; } } else { while (reversedValueExceptFirst > 0) { var bufferSlice = buffer.Slice(bytesWritten); var nextDigit = reversedValueExceptFirst % 10UL; reversedValueExceptFirst = reversedValueExceptFirst / 10UL; if (!formattingData.TryEncode((EncodingData.Symbol)nextDigit, bufferSlice, out digitBytes)) { bytesWritten = 0; return false; } bytesWritten += digitBytes; } // Append trailing zeros if any while (trailingZerosCount-- > 0) { if (!formattingData.TryEncode(EncodingData.Symbol.D0, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return false; } bytesWritten += digitBytes; } } // If format is N and precision is not defined or is greater than zero, append trailing zeros after decimal point if (format.Symbol == 'N') { int trailingZerosAfterDecimalCount = format.HasPrecision ? format.Precision : 2; if (trailingZerosAfterDecimalCount > 0) { if (!formattingData.TryEncode(EncodingData.Symbol.DecimalSeparator, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return false; } bytesWritten += digitBytes; while (trailingZerosAfterDecimalCount-- > 0) { if (!formattingData.TryEncode(EncodingData.Symbol.D0, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return false; } bytesWritten += digitBytes; } } } return true; }
public static bool TryFormat(this Utf8String value, Span <byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { if (formattingData.IsUtf16) { bytesWritten = 0; int justWritten; foreach (var cp in value.CodePoints) { if (!Utf16.Utf16LittleEndianEncoder.TryEncodeCodePoint(cp, buffer.Slice(bytesWritten), out justWritten)) { bytesWritten = 0; return(false); } bytesWritten += justWritten; } return(true); } if (buffer.Length < value.Length) { bytesWritten = 0; return(false); } buffer.Set(value.Bytes); bytesWritten = value.Length; return(true); }
[InlineData("ลป๑", false, 0, 0, 0)] // public unsafe void ParseCustomCultureThaiByteArrayToLong(string text, bool expectSuccess, int index, long expectedValue, int expectedBytesConsumed) { long parsedValue; int bytesConsumed; var thaiUtf8DigitsAndSymbols = new byte[][] { new byte[] { 0xe0, 0xb9, 0x90 }, new byte[] { 0xe0, 0xb9, 0x91 }, new byte[] { 0xe0, 0xb9, 0x92 }, new byte[] { 0xe0, 0xb9, 0x93 }, new byte[] { 0xe0, 0xb9, 0x94 }, new byte[] { 0xe0, 0xb9, 0x95 }, new byte[] { 0xe0, 0xb9, 0x96 }, new byte[] { 0xe0, 0xb9, 0x97 }, new byte[] { 0xe0, 0xb9, 0x98 }, new byte[] { 0xe0, 0xb9, 0x99 }, new byte[] { 0xE0, 0xB8, 0x88, 0xE0, 0xB8, 0x94 }, null, new byte[] { 0xE0, 0xB8, 0xAA, 0xE0, 0xB8, 0xB4, 0xE0, 0xB9, 0x88, 0xE0, 0xB8, 0x87, 0xE0, 0xB8, 0x97, 0xE0, 0xB8, 0xB5, 0xE0, 0xB9, 0x88, 0xE0, 0xB9, 0x83, 0xE0, 0xB8, 0xAB, 0xE0, 0xB8, 0x8D, 0xE0, 0xB9, 0x88, 0xE0, 0xB9, 0x82, 0xE0, 0xB8, 0x95, 0xE0, 0xB9, 0x80, 0xE0, 0xB8, 0xAB, 0xE0, 0xB8, 0xA5, 0xE0, 0xB8, 0xB7, 0xE0, 0xB8, 0xAD, 0xE0, 0xB9, 0x80, 0xE0, 0xB8, 0x81, 0xE0, 0xB8, 0xB4, 0xE0, 0xB8, 0x99 }, new byte[] { 0xE0, 0xB8, 0xA5, 0xE0, 0xB8, 0x9A }, new byte[] { 43 }, new byte[] { 0xE0, 0xB9, 0x84, 0xE0, 0xB8, 0xA1, 0xE0, 0xB9, 0x88, 0xE0, 0xB9, 0x83, 0xE0, 0xB8, 0x8A, 0xE0, 0xB9, 0x88, 0xE0, 0xB8, 0x95, 0xE0, 0xB8, 0xB1, 0xE0, 0xB8, 0xA7, 0xE0, 0xB9, 0x80, 0xE0, 0xB8, 0xA5, 0xE0, 0xB8, 0x82 }, new byte[] { 69 }, new byte[] { 101 }, }; var thaiUtf8ParsingTrie = new EncodingData.TrieNode[] { new EncodingData.TrieNode { valueOrNumChildren = 4, index = 0 }, new EncodingData.TrieNode { valueOrNumChildren = 43, index = 5 }, new EncodingData.TrieNode { valueOrNumChildren = 69, index = 6 }, new EncodingData.TrieNode { valueOrNumChildren = 101, index = 7 }, new EncodingData.TrieNode { valueOrNumChildren = 0xE0, index = 8 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 14 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 16 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 16 }, new EncodingData.TrieNode { valueOrNumChildren = 2, index = 0 }, new EncodingData.TrieNode { valueOrNumChildren = 0xB8, index = 11 }, new EncodingData.TrieNode { valueOrNumChildren = 0xB9, index = 15 }, new EncodingData.TrieNode { valueOrNumChildren = 3, index = 0 }, new EncodingData.TrieNode { valueOrNumChildren = 0x88, index = 27 }, new EncodingData.TrieNode { valueOrNumChildren = 0xA5, index = 28 }, new EncodingData.TrieNode { valueOrNumChildren = 0xAA, index = 29 }, new EncodingData.TrieNode { valueOrNumChildren = 11, index = -1878877941 /* 0x9002990B */ }, new EncodingData.TrieNode { valueOrNumChildren = 0x84, index = 30 }, new EncodingData.TrieNode { valueOrNumChildren = 0x90, index = 31 }, new EncodingData.TrieNode { valueOrNumChildren = 0x91, index = 32 }, new EncodingData.TrieNode { valueOrNumChildren = 0x92, index = 33 }, new EncodingData.TrieNode { valueOrNumChildren = 0x93, index = 34 }, new EncodingData.TrieNode { valueOrNumChildren = 0x94, index = 35 }, new EncodingData.TrieNode { valueOrNumChildren = 0x95, index = 36 }, new EncodingData.TrieNode { valueOrNumChildren = 0x96, index = 37 }, new EncodingData.TrieNode { valueOrNumChildren = 0x97, index = 38 }, new EncodingData.TrieNode { valueOrNumChildren = 0x98, index = 39 }, new EncodingData.TrieNode { valueOrNumChildren = 0x99, index = 40 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 10 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 13 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 12 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 15 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 0 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 1 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 2 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 3 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 4 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 5 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 6 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 7 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 8 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 9 }, }; EncodingData fd = new EncodingData(thaiUtf8DigitsAndSymbols, thaiUtf8ParsingTrie, EncodingData.Encoding.Utf8); Format.Parsed nf = new Format.Parsed('R'); bool result = PrimitiveParser.TryParseInt64(UtfEncode(text, false), index, fd, nf, out parsedValue, out bytesConsumed); Assert.Equal(expectSuccess, result); Assert.Equal(expectedValue, parsedValue); Assert.Equal(expectedBytesConsumed, bytesConsumed); }
public static bool TryParseBoolean(ReadOnlySpan<byte> text, out bool value, out int consumedBytes, EncodingData encoding = default(EncodingData)) { consumedBytes = 0; value = default(bool); if (text.Length < 1) { return false; } if (encoding.IsInvariantUtf8) { byte firstCodeUnit = text[0]; if (firstCodeUnit == '1') { consumedBytes = 1; value = true; return true; } else if (firstCodeUnit == '0') { consumedBytes = 1; value = false; return true; } else if (IsTrue(text)) { consumedBytes = 4; value = true; return true; } else if (IsFalse(text)) { consumedBytes = 5; value = false; return true; } else { return false; } } if (encoding.IsInvariantUtf16) { ReadOnlySpan<char> textChars = text.Cast<byte, char>(); char firstCodeUnit = textChars[0]; if (firstCodeUnit == '1') { consumedBytes = 2; value = true; return true; } else if (firstCodeUnit == '0') { consumedBytes = 2; value = false; return true; } else if (IsTrue(textChars)) { consumedBytes = 8; value = true; return true; } else if (IsFalse(textChars)) { consumedBytes = 10; value = false; return true; } else { return false; } } return false; }
public static bool TryParseByte(ReadOnlySpan <byte> text, out byte value, out int bytesConsumed, EncodingData encoding = default(EncodingData), TextFormat format = default(TextFormat)) { return(Internal.InternalParser.TryParseByte(text, encoding, format, out value, out bytesConsumed)); }
static bool TryFormatDateTimeRfc1123(DateTime value, Span <byte> buffer, out int bytesWritten, EncodingData encoding) { if (encoding.IsInvariantUtf8) { bytesWritten = 0; if (buffer.Length < 29) { return(false); } s_dayNamesUtf8[(int)value.DayOfWeek].CopyTo(buffer); TryFormat(value.Day, buffer.Slice(5), out bytesWritten, D2, encoding); buffer[7] = (byte)' '; var monthBytes = s_monthNamesUtf8[value.Month - 1]; monthBytes.CopyTo(buffer.Slice(8)); buffer[11] = (byte)' '; TryFormat(value.Year, buffer.Slice(12), out bytesWritten, D4, encoding); buffer[16] = (byte)' '; TryFormat(value.Hour, buffer.Slice(17), out bytesWritten, D2, encoding); buffer[19] = (byte)':'; TryFormat(value.Minute, buffer.Slice(20), out bytesWritten, D2, encoding); buffer[22] = (byte)':'; TryFormat(value.Second, buffer.Slice(23), out bytesWritten, D2, encoding); s_gmtUtf8Bytes.CopyTo(buffer.Slice(25)); bytesWritten = 29; return(true); } bytesWritten = 0; if (!TryWriteString(s_dayNames[(int)value.DayOfWeek], buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteInt32(value.Day, buffer, ref bytesWritten, D2, encoding)) { return(false); } if (!TryWriteChar(' ', buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteString(s_monthNames[value.Month - 1], buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteChar(' ', buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteInt32(value.Year, buffer, ref bytesWritten, D4, encoding)) { return(false); } if (!TryWriteChar(' ', buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteInt32(value.Hour, buffer, ref bytesWritten, D2, encoding)) { return(false); } if (!TryWriteChar(':', buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteInt32(value.Minute, buffer, ref bytesWritten, D2, encoding)) { return(false); } if (!TryWriteChar(':', buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteInt32(value.Second, buffer, ref bytesWritten, D2, encoding)) { return(false); } if (!TryWriteString(" GMT", buffer, ref bytesWritten, encoding)) { return(false); } return(true); }
static bool TryFormatDateTimeFormatO(DateTimeOffset value, bool isDateTime, Span <byte> buffer, out int bytesWritten, EncodingData encoding) { bytesWritten = 0; if (!TryWriteInt32(value.Year, buffer, ref bytesWritten, D4, encoding)) { return(false); } if (!TryWriteChar('-', buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteInt32(value.Month, buffer, ref bytesWritten, D2, encoding)) { return(false); } if (!TryWriteChar('-', buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteInt32(value.Day, buffer, ref bytesWritten, D2, encoding)) { return(false); } if (!TryWriteChar('T', buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteInt32(value.Hour, buffer, ref bytesWritten, D2, encoding)) { return(false); } if (!TryWriteChar(':', buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteInt32(value.Minute, buffer, ref bytesWritten, D2, encoding)) { return(false); } if (!TryWriteChar(':', buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteInt32(value.Second, buffer, ref bytesWritten, D2, encoding)) { return(false); } // add optional fractional second only if needed... var rounded = new DateTimeOffset(value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second, TimeSpan.Zero); var delta = value - rounded; if (delta.Ticks != 0) { if (!TryWriteChar('.', buffer, ref bytesWritten, encoding)) { return(false); } var timeFrac = delta.Ticks * FractionalTimeScale / System.TimeSpan.TicksPerSecond; if (!TryWriteInt64(timeFrac, buffer, ref bytesWritten, D7, encoding)) { return(false); } } if (isDateTime) { if (!TryWriteChar('Z', buffer, ref bytesWritten, encoding)) { return(false); } } else { if (!TryWriteChar('+', buffer, ref bytesWritten, encoding)) { return(false); } int bytes; if (!value.Offset.TryFormat(buffer.Slice(bytesWritten), out bytes, t, encoding)) { return(false); } bytesWritten += bytes; } return(true); }
public static bool TryParseBoolean(ReadOnlySpan <byte> text, out bool value, out int bytesConsumed, EncodingData encoding = default(EncodingData)) { bytesConsumed = 0; value = default(bool); if (encoding.IsInvariantUtf8) { return(InvariantUtf8.TryParseBoolean(text, out value, out bytesConsumed)); } if (encoding.IsInvariantUtf16) { ReadOnlySpan <char> textChars = text.Cast <byte, char>(); int charactersConsumed; bool result = InvariantUtf16.TryParseBoolean(textChars, out value, out charactersConsumed); bytesConsumed = charactersConsumed * 2; return(result); } return(false); }
public unsafe static bool TryParse(byte *text, int index, int length, EncodingData encoding, Format.Parsed format, out double value, out int bytesConsumed) { // Precondition replacement if (length < 1 || index < 0) { value = 0; bytesConsumed = 0; return(false); } value = 0.0; bytesConsumed = 0; if (encoding.IsInvariantUtf8) { string doubleString = ""; bool decimalPlace = false, e = false, signed = false, digitLast = false, eLast = false; if ((length) >= 3 && text[index] == 'N' && text[index + 1] == 'a' && text[index + 2] == 'N') { value = double.NaN; bytesConsumed = 3; return(true); } if (text[index] == '-' || text[index] == '+') { signed = true; doubleString += (char)text[index]; index++; bytesConsumed++; } if ((length - index) >= 8 && text[index] == 'I' && text[index + 1] == 'n' && text[index + 2] == 'f' && text[index + 3] == 'i' && text[index + 4] == 'n' && text[index + 5] == 'i' && text[index + 6] == 't' && text[index + 7] == 'y') { if (signed && text[index - 1] == '-') { value = double.NegativeInfinity; } else { value = double.PositiveInfinity; } bytesConsumed += 8; return(true); } for (int byteIndex = index; byteIndex < length; byteIndex++) { byte nextByte = text[byteIndex]; byte nextByteVal = (byte)(nextByte - '0'); if (nextByteVal > 9) { if (!decimalPlace && nextByte == '.') { if (digitLast) { digitLast = false; } if (eLast) { eLast = false; } bytesConsumed++; decimalPlace = true; doubleString += (char)nextByte; } else if (!e && nextByte == 'e' || nextByte == 'E') { e = true; eLast = true; bytesConsumed++; doubleString += (char)nextByte; } else if (eLast && nextByte == '+' || nextByte == '-') { eLast = false; bytesConsumed++; doubleString += (char)nextByte; } else if ((decimalPlace && signed && bytesConsumed == 2) || ((signed || decimalPlace) && bytesConsumed == 1)) { value = 0; bytesConsumed = 0; return(false); } else { if (double.TryParse(doubleString, out value)) { return(true); } else { bytesConsumed = 0; return(false); } } } else { if (eLast) { eLast = false; } if (!digitLast) { digitLast = true; } bytesConsumed++; doubleString += (char)nextByte; } } if ((decimalPlace && signed && bytesConsumed == 2) || ((signed || decimalPlace) && bytesConsumed == 1)) { value = 0; bytesConsumed = 0; return(false); } else { if (double.TryParse(doubleString, out value)) { return(true); } else { bytesConsumed = 0; return(false); } } } return(false); }
public static bool TryFormat(this float value, Span <byte> buffer, out int bytesWritten, TextFormat format, EncodingData encoding) { if (format.IsDefault) { format.Symbol = 'G'; } Precondition.Require(format.Symbol == 'G'); return(FloatFormatter.TryFormatNumber(value, true, buffer, out bytesWritten, format, encoding)); }
public static bool TryFormat(this char value, Span <byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { if (formattingData.IsUtf16) { if (buffer.Length < 2) { bytesWritten = 0; return(false); } buffer[0] = (byte)value; buffer[1] = (byte)(value >> 8); bytesWritten = 2; return(true); } if (buffer.Length < 1) { bytesWritten = 0; return(false); } // fast path for ASCII if (value <= 127) { buffer[0] = (byte)value; bytesWritten = 1; return(true); } // TODO: This can be directly encoded to SpanByte. There is no conversion between spans yet var encoded = new Utf8EncodedCodePoint(value); bytesWritten = encoded.Length; if (buffer.Length < bytesWritten) { bytesWritten = 0; return(false); } buffer[0] = encoded.Byte0; if (bytesWritten > 1) { buffer[1] = encoded.Byte1; } if (bytesWritten > 2) { buffer[2] = encoded.Byte2; } if (bytesWritten > 3) { buffer[3] = encoded.Byte3; } return(true); }
public static bool TryFormat(this long value, Span <byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { return(IntegerFormatter.TryFormatInt64(value, 8, buffer, format, formattingData, out bytesWritten)); }
internal static bool TryFormatUInt64(ulong value, byte numberOfBytes, Span <byte> buffer, Span <char> format, EncodingData formattingData, out int bytesWritten) { Format.Parsed parsedFormat = Format.Parse(format); return(TryFormatUInt64(value, numberOfBytes, buffer, parsedFormat, formattingData, out bytesWritten)); }
static bool TryWriteInt64(long i, Span<byte> buffer, TextFormat byteFormat, EncodingData formattingData, ref int bytesWritten) { int written; if (!i.TryFormat(buffer.Slice(bytesWritten), out written, byteFormat, formattingData)) { bytesWritten = 0; return false; } bytesWritten += written; return true; }
public static bool TryFormat(this TimeSpan value, Span <byte> buffer, out int bytesWritten, TextFormat format = default(TextFormat), EncodingData encoding = default(EncodingData)) { if (format.IsDefault) { format.Symbol = 'c'; } Precondition.Require(format.Symbol == 'G' || format.Symbol == 't' || format.Symbol == 'c' || format.Symbol == 'g'); if (format.Symbol != 't') { return(TryFormatTimeSpanG(value, buffer, out bytesWritten, format, encoding)); } // else it's format 't' (short time used to print time offsets) return(TryFormatTimeSpanT(value, buffer, out bytesWritten, encoding)); }
private static bool TryFormatTimeSpanG(TimeSpan value, Span <byte> buffer, out int bytesWritten, TextFormat format = default(TextFormat), EncodingData encoding = default(EncodingData)) { bytesWritten = 0; if (value.Ticks < 0) { if (!TryWriteChar('-', buffer, ref bytesWritten, encoding)) { return(false); } } bool daysWritten = false; if (value.Days != 0 || format.Symbol == 'G') { if (!TryWriteInt32(Abs(value.Days), buffer, ref bytesWritten, default(TextFormat), encoding)) { return(false); } daysWritten = true; if (format.Symbol == 'c') { if (!TryWriteChar('.', buffer, ref bytesWritten, encoding)) { return(false); } } else { if (!TryWriteChar(':', buffer, ref bytesWritten, encoding)) { return(false); } } } var hourFormat = default(TextFormat); if ((daysWritten || format.Symbol == 'c') && format.Symbol != 'g') { hourFormat = D2; } if (!TryWriteInt32(Abs(value.Hours), buffer, ref bytesWritten, hourFormat, encoding)) { return(false); } if (!TryWriteChar(':', buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteInt32(Abs(value.Minutes), buffer, ref bytesWritten, D2, encoding)) { return(false); } if (!TryWriteChar(':', buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteInt32(Abs(value.Seconds), buffer, ref bytesWritten, D2, encoding)) { return(false); } long remainingTicks; if (value.Ticks != long.MinValue) { remainingTicks = Abs(value.Ticks) % TimeSpan.TicksPerSecond; } else { remainingTicks = long.MaxValue % TimeSpan.TicksPerSecond; remainingTicks = (remainingTicks + 1) % TimeSpan.TicksPerSecond; } var ticksFormat = D7; if (remainingTicks != 0) { if (!TryWriteChar('.', buffer, ref bytesWritten, encoding)) { return(false); } var fraction = remainingTicks * FractionalTimeScale / TimeSpan.TicksPerSecond; if (!TryWriteInt64(fraction, buffer, ref bytesWritten, ticksFormat, encoding)) { return(false); } } return(true); }
private static bool TryFormatTimeSpanT(TimeSpan value, Span<byte> buffer, EncodingData formattingData, out int bytesWritten) { bytesWritten = 0; if (value.Ticks < 0) { if (!TryWriteChar('-', buffer, formattingData, ref bytesWritten)) { return false; } } if (!TryWriteInt32(Abs((int)value.TotalHours), buffer, D2, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(Abs(value.Minutes), buffer, D2, formattingData, ref bytesWritten)) { return false; } return true; }
public static bool TryParseByte(ReadOnlySpan<byte> text, out byte value, out int bytesConsumed, EncodingData encoding = default(EncodingData), TextFormat format = default(TextFormat)) { return Internal.InternalParser.TryParseByte(text, encoding, format, out value, out bytesConsumed); }
static bool TryWriteChar(char character, Span <byte> buffer, ref int bytesWritten, EncodingData encoding) { int consumed; int written; unsafe { ReadOnlySpan <char> charSpan = new ReadOnlySpan <char>(&character, 1); if (!encoding.TextEncoder.TryEncode(charSpan, buffer.Slice(bytesWritten), out consumed, out written)) { bytesWritten = 0; return(false); } } bytesWritten += written; return(true); }
public static bool TryFormat(this DateTimeOffset value, Span <byte> buffer, out int bytesWritten, TextFormat format = default(TextFormat), EncodingData encoding = default(EncodingData)) { if (format.IsDefault) { format.Symbol = 'G'; } Precondition.Require(format.Symbol == 'R' || format.Symbol == 'O' || format.Symbol == 'G'); switch (format.Symbol) { case 'R': if (encoding.IsInvariantUtf16) // TODO: there are many checks like this one in the code. They need to also verify that the UTF8 branch is invariant. { return(TryFormatDateTimeRfc1123(value.UtcDateTime, buffer, out bytesWritten, EncodingData.InvariantUtf16)); } else { return(TryFormatDateTimeRfc1123(value.UtcDateTime, buffer, out bytesWritten, EncodingData.InvariantUtf8)); } case 'O': if (encoding.IsInvariantUtf16) { return(TryFormatDateTimeFormatO(value.UtcDateTime, false, buffer, out bytesWritten, EncodingData.InvariantUtf16)); } else { return(TryFormatDateTimeFormatO(value.UtcDateTime, false, buffer, out bytesWritten, EncodingData.InvariantUtf8)); } case 'G': return(TryFormatDateTimeFormatG(value.DateTime, buffer, out bytesWritten, encoding)); default: throw new NotImplementedException(); } }
public static bool TryFormat(this string value, Span <byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { if (formattingData.IsUtf16) { var valueBytes = value.Length << 1; if (valueBytes > buffer.Length) { bytesWritten = 0; return(false); } unsafe { fixed(char *pCharacters = value) { byte *pBytes = (byte *)pCharacters; buffer.Set(pBytes, valueBytes); } } bytesWritten = valueBytes; return(true); } var avaliableBytes = buffer.Length; bytesWritten = 0; for (int i = 0; i < value.Length; i++) { var c = value[i]; var codepoint = (ushort)c; if (codepoint <= 0x7f) // this if block just optimizes for ascii { if (bytesWritten + 1 > avaliableBytes) { bytesWritten = 0; return(false); } buffer[bytesWritten++] = (byte)codepoint; } else { Utf8EncodedCodePoint encoded; if (!char.IsSurrogate(c)) { encoded = new Utf8EncodedCodePoint(c); } else { if (++i >= value.Length) { throw new ArgumentException("Invalid surrogate pair.", nameof(value)); } char lowSurrogate = value[i]; encoded = new Utf8EncodedCodePoint(c, lowSurrogate); } if (bytesWritten + encoded.Length > avaliableBytes) { bytesWritten = 0; return(false); } buffer[bytesWritten] = encoded.Byte0; if (encoded.Length > 1) { buffer[bytesWritten + 1] = encoded.Byte1; if (encoded.Length > 2) { buffer[bytesWritten + 2] = encoded.Byte2; if (encoded.Length > 3) { buffer[bytesWritten + 3] = encoded.Byte3; } } } bytesWritten += encoded.Length; } } return(true); }
static bool TryWriteString(string text, Span <byte> buffer, ref int bytesWritten, EncodingData encoding) { int written; if (!encoding.TextEncoder.TryEncode(text, buffer.Slice(bytesWritten), out written)) { bytesWritten = 0; return(false); } bytesWritten += written; return(true); }
private static bool TryFormatTimeSpanT(TimeSpan value, Span <byte> buffer, out int bytesWritten, EncodingData encoding) { bytesWritten = 0; if (value.Ticks < 0) { if (!TryWriteChar('-', buffer, ref bytesWritten, encoding)) { return(false); } } if (!TryWriteInt32(Abs((int)value.TotalHours), buffer, ref bytesWritten, D2, encoding)) { return(false); } if (!TryWriteChar(':', buffer, ref bytesWritten, encoding)) { return(false); } if (!TryWriteInt32(Abs(value.Minutes), buffer, ref bytesWritten, D2, encoding)) { return(false); } return(true); }
static bool TryWriteInt64(long i, Span <byte> buffer, ref int bytesWritten, TextFormat byteFormat, EncodingData encoding) { int written; if (!i.TryFormat(buffer.Slice(bytesWritten), out written, byteFormat, encoding)) { bytesWritten = 0; return(false); } bytesWritten += written; return(true); }
public static bool TryFormat(this DateTime value, Span <byte> buffer, out int bytesWritten, TextFormat format = default(TextFormat), EncodingData encoding = default(EncodingData)) { if (format.IsDefault) { format.Symbol = 'G'; } Precondition.Require(format.Symbol == 'R' || format.Symbol == 'O' || format.Symbol == 'G'); switch (format.Symbol) { case 'R': var utc = value.ToUniversalTime(); if (encoding.IsInvariantUtf16) { return(TryFormatDateTimeRfc1123(utc, buffer, out bytesWritten, EncodingData.InvariantUtf16)); } else { return(TryFormatDateTimeRfc1123(utc, buffer, out bytesWritten, EncodingData.InvariantUtf8)); } case 'O': if (encoding.IsInvariantUtf16) { return(TryFormatDateTimeFormatO(value, true, buffer, out bytesWritten, EncodingData.InvariantUtf16)); } else { return(TryFormatDateTimeFormatO(value, true, buffer, out bytesWritten, EncodingData.InvariantUtf8)); } case 'G': return(TryFormatDateTimeFormatG(value, buffer, out bytesWritten, encoding)); default: throw new NotImplementedException(); } }
internal static bool TryFormatUInt64(ulong value, byte numberOfBytes, Span<byte> buffer, ReadOnlySpan<char> format, EncodingData formattingData, out int bytesWritten) { TextFormat parsedFormat = TextFormat.Parse(format); return TryFormatUInt64(value, numberOfBytes, buffer, parsedFormat, formattingData, out bytesWritten); }
public static bool TryFormat(this Guid value, Span <byte> buffer, ReadOnlySpan <char> format, EncodingData formattingData, out int bytesWritten) { Format.Parsed parsedFormat = Format.Parse(format); return(TryFormat(value, buffer, parsedFormat, formattingData, out bytesWritten)); }
// TODO: format should be ReadOnlySpan<char> internal static bool TryFormatInt64(long value, byte numberOfBytes, Span <byte> buffer, Span <char> format, EncodingData formattingData, out int bytesWritten) { Precondition.Require(numberOfBytes <= sizeof(long)); Format.Parsed parsedFormat = Format.Parse(format); return(TryFormatInt64(value, numberOfBytes, buffer, parsedFormat, formattingData, out bytesWritten)); }
public static bool TryFormat(this Guid value, Span <byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { if (format.IsDefault) { format.Symbol = 'G'; } Precondition.Require(format.Symbol == 'G' || format.Symbol == 'D' || format.Symbol == 'N' || format.Symbol == 'B' || format.Symbol == 'P'); bool dash = true; char tail = '\0'; bytesWritten = 0; switch (format.Symbol) { case 'D': case 'G': break; case 'N': dash = false; break; case 'B': if (!TryWriteChar('{', buffer, formattingData, ref bytesWritten)) { return(false); } tail = '}'; break; case 'P': if (!TryWriteChar('(', buffer, formattingData, ref bytesWritten)) { return(false); } tail = ')'; break; default: Precondition.Require(false); // how did we get here? break; } var byteFormat = new Format.Parsed('x', 2); unsafe { byte *bytes = (byte *)&value; if (!TryWriteByte(bytes[3], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteByte(bytes[2], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteByte(bytes[1], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteByte(bytes[0], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (dash) { if (!TryWriteChar('-', buffer, formattingData, ref bytesWritten)) { return(false); } } if (!TryWriteByte(bytes[5], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteByte(bytes[4], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (dash) { if (!TryWriteChar('-', buffer, formattingData, ref bytesWritten)) { return(false); } } if (!TryWriteByte(bytes[7], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteByte(bytes[6], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (dash) { if (!TryWriteChar('-', buffer, formattingData, ref bytesWritten)) { return(false); } } if (!TryWriteByte(bytes[8], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteByte(bytes[9], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (dash) { if (!TryWriteChar('-', buffer, formattingData, ref bytesWritten)) { return(false); } } if (!TryWriteByte(bytes[10], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteByte(bytes[11], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteByte(bytes[12], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteByte(bytes[13], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteByte(bytes[14], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteByte(bytes[15], buffer, byteFormat, formattingData, ref bytesWritten)) { return(false); } } if (tail != '\0') { if (!TryWriteChar(tail, buffer, formattingData, ref bytesWritten)) { return(false); } } return(true); }
// TODO: this whole routine is too slow. It does div and mod twice, which are both costly (especially that some JITs cannot optimize it). // It does it twice to avoid reversing the formatted buffer, which can be tricky given it should handle arbitrary cultures. // One optimization I thought we could do is to do div/mod once and store digits in a temp buffer (but that would allocate). Modification to the idea would be to store the digits in a local struct // Another idea possibly worth tying would be to special case cultures that have constant digit size, and go back to the format + reverse buffer approach. private static bool TryFormatDecimal(ulong value, Span <byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { if (format.IsDefault) { format.Symbol = 'G'; } format.Symbol = Char.ToUpperInvariant(format.Symbol); // TODO: this is costly. I think the transformation should happen in Parse Precondition.Require(format.Symbol == 'D' || format.Symbol == 'G' || format.Symbol == 'N'); // Reverse value on decimal basis, count digits and trailing zeros before the decimal separator ulong reversedValueExceptFirst = 0; var digitsCount = 1; var trailingZerosCount = 0; // We reverse the digits in numeric form because reversing encoded digits is hard and/or costly. // If value contains 20 digits, its reversed value will not fit into ulong size. // So reverse it till last digit (reversedValueExceptFirst will have all the digits except the first one). while (value >= 10) { var digit = value % 10UL; value = value / 10UL; if (reversedValueExceptFirst == 0 && digit == 0) { trailingZerosCount++; } else { reversedValueExceptFirst = reversedValueExceptFirst * 10UL + digit; digitsCount++; } } bytesWritten = 0; int digitBytes; // If format is D and precision is greater than digitsCount + trailingZerosCount, append leading zeros if (format.Symbol == 'D' && format.HasPrecision) { var leadingZerosCount = format.Precision - digitsCount - trailingZerosCount; while (leadingZerosCount-- > 0) { if (!formattingData.TryWriteDigitOrSymbol(0, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return(false); } bytesWritten += digitBytes; } } // Append first digit if (!formattingData.TryWriteDigit(value, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return(false); } bytesWritten += digitBytes; digitsCount--; if (format.Symbol == 'N') { const int GroupSize = 3; // Count amount of digits before first group separator. It will be reset to groupSize every time digitsLeftInGroup == zero var digitsLeftInGroup = (digitsCount + trailingZerosCount) % GroupSize; if (digitsLeftInGroup == 0) { if (digitsCount + trailingZerosCount > 0) { // There is a new group immediately after the first digit if (!formattingData.TryWriteSymbol(EncodingData.Symbol.GroupSeparator, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return(false); } bytesWritten += digitBytes; } digitsLeftInGroup = GroupSize; } // Append digits while (reversedValueExceptFirst > 0) { if (digitsLeftInGroup == 0) { if (!formattingData.TryWriteSymbol(EncodingData.Symbol.GroupSeparator, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return(false); } bytesWritten += digitBytes; digitsLeftInGroup = GroupSize; } var nextDigit = reversedValueExceptFirst % 10UL; reversedValueExceptFirst = reversedValueExceptFirst / 10UL; if (!formattingData.TryWriteDigit(nextDigit, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return(false); } bytesWritten += digitBytes; digitsLeftInGroup--; } // Append trailing zeros if any while (trailingZerosCount-- > 0) { if (digitsLeftInGroup == 0) { if (!formattingData.TryWriteSymbol(EncodingData.Symbol.GroupSeparator, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return(false); } bytesWritten += digitBytes; digitsLeftInGroup = GroupSize; } if (!formattingData.TryWriteDigitOrSymbol(0, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return(false); } bytesWritten += digitBytes; digitsLeftInGroup--; } } else { while (reversedValueExceptFirst > 0) { var bufferSlice = buffer.Slice(bytesWritten); var nextDigit = reversedValueExceptFirst % 10UL; reversedValueExceptFirst = reversedValueExceptFirst / 10UL; if (!formattingData.TryWriteDigit(nextDigit, bufferSlice, out digitBytes)) { bytesWritten = 0; return(false); } bytesWritten += digitBytes; } // Append trailing zeros if any while (trailingZerosCount-- > 0) { if (!formattingData.TryWriteDigitOrSymbol(0, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return(false); } bytesWritten += digitBytes; } } // If format is N and precision is not defined or is greater than zero, append trailing zeros after decimal point if (format.Symbol == 'N') { int trailingZerosAfterDecimalCount = format.HasPrecision ? format.Precision : 2; if (trailingZerosAfterDecimalCount > 0) { if (!formattingData.TryWriteSymbol(EncodingData.Symbol.DecimalSeparator, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return(false); } bytesWritten += digitBytes; while (trailingZerosAfterDecimalCount-- > 0) { if (!formattingData.TryWriteDigitOrSymbol(0, buffer.Slice(bytesWritten), out digitBytes)) { bytesWritten = 0; return(false); } bytesWritten += digitBytes; } } } return(true); }
static bool TryWriteInt64(long i, Span <byte> buffer, Format.Parsed byteFormat, EncodingData formattingData, ref int bytesWritten) { int written; if (!i.TryFormat(buffer.Slice(bytesWritten), byteFormat, formattingData, out written)) { bytesWritten = 0; return(false); } bytesWritten += written; return(true); }
internal static bool TryFormatUInt64(ulong value, byte numberOfBytes, Span <byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { if (format.Symbol == 'g') { format.Symbol = 'G'; } if (format.IsHexadecimal && formattingData.IsUtf16) { return(TryFormatHexadecimalInvariantCultureUtf16(value, buffer, format, out bytesWritten)); } if (format.IsHexadecimal && formattingData.IsUtf8) { return(TryFormatHexadecimalInvariantCultureUtf8(value, buffer, format, out bytesWritten)); } if ((formattingData.IsInvariantUtf16) && (format.Symbol == 'D' || format.Symbol == 'G')) { return(TryFormatDecimalInvariantCultureUtf16(value, buffer, format, out bytesWritten)); } if ((formattingData.IsInvariantUtf8) && (format.Symbol == 'D' || format.Symbol == 'G')) { return(TryFormatDecimalInvariantCultureUtf8(value, buffer, format, out bytesWritten)); } return(TryFormatDecimal(value, buffer, format, formattingData, out bytesWritten)); }
public static bool TryFormat(this long value, Span<byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { return IntegerFormatter.TryFormatInt64(value, 8, buffer, format, formattingData, out bytesWritten); }
public static bool TryFormat(this Guid value, Span<byte> buffer, TextFormat format, EncodingData encoding, out int bytesWritten) { if (format.IsDefault) { format.Symbol = 'G'; } Precondition.Require(format.Symbol == 'G' || format.Symbol == 'D' || format.Symbol == 'N' || format.Symbol == 'B' || format.Symbol == 'P'); bool dash = true; char tail = '\0'; bytesWritten = 0; switch (format.Symbol) { case 'D': case 'G': break; case 'N': dash = false; break; case 'B': if (!TryWriteChar('{', buffer, encoding.TextEncoding, ref bytesWritten)) { return false; } tail = '}'; break; case 'P': if (!TryWriteChar('(', buffer, encoding.TextEncoding, ref bytesWritten)) { return false; } tail = ')'; break; default: Precondition.Require(false); // how did we get here? break; } var byteFormat = new TextFormat('x', 2); unsafe { byte* bytes = (byte*)&value; if (!TryWriteByte(bytes[3], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (!TryWriteByte(bytes[2], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (!TryWriteByte(bytes[1], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (!TryWriteByte(bytes[0], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (dash) { if (!TryWriteChar('-', buffer, encoding.TextEncoding, ref bytesWritten)) { return false; } } if (!TryWriteByte(bytes[5], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (!TryWriteByte(bytes[4], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (dash) { if (!TryWriteChar('-', buffer, encoding.TextEncoding, ref bytesWritten)) { return false; } } if (!TryWriteByte(bytes[7], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (!TryWriteByte(bytes[6], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (dash) { if (!TryWriteChar('-', buffer, encoding.TextEncoding, ref bytesWritten)) { return false; } } if (!TryWriteByte(bytes[8], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (!TryWriteByte(bytes[9], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (dash) { if (!TryWriteChar('-', buffer, encoding.TextEncoding, ref bytesWritten)) { return false; } } if (!TryWriteByte(bytes[10], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (!TryWriteByte(bytes[11], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (!TryWriteByte(bytes[12], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (!TryWriteByte(bytes[13], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (!TryWriteByte(bytes[14], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } if (!TryWriteByte(bytes[15], buffer, byteFormat, encoding, ref bytesWritten)) { return false; } } if (tail != '\0') { if (!TryWriteChar(tail, buffer, encoding.TextEncoding, ref bytesWritten)) { return false; } } return true; }
internal static bool TryFormatUInt64(ulong value, byte numberOfBytes, Span <byte> buffer, out int bytesWritten, TextFormat format, EncodingData encoding) { if (format.Symbol == 'g') { format.Symbol = 'G'; } if (format.IsHexadecimal && encoding.IsInvariantUtf16) { return(TryFormatHexadecimalInvariantCultureUtf16(value, buffer, out bytesWritten, format)); } if (format.IsHexadecimal && encoding.IsInvariantUtf8) { return(TryFormatHexadecimalInvariantCultureUtf8(value, buffer, out bytesWritten, format)); } if ((encoding.IsInvariantUtf16) && (format.Symbol == 'D' || format.Symbol == 'G')) { return(TryFormatDecimalInvariantCultureUtf16(value, buffer, out bytesWritten, format)); } if ((encoding.IsInvariantUtf8) && (format.Symbol == 'D' || format.Symbol == 'G')) { return(TryFormatDecimalInvariantCultureUtf8(value, buffer, out bytesWritten, format)); } return(TryFormatDecimal(value, buffer, out bytesWritten, format, encoding)); }
public static bool TryFormat(this float value, Span<byte> buffer, ReadOnlySpan<char> format, EncodingData formattingData, out int bytesWritten) { Format.Parsed parsedFormat = Format.Parse(format); return TryFormat(value, buffer, parsedFormat, formattingData, out bytesWritten); }
static bool TryFormatDateTimeFormagG(DateTime value, Span<byte> buffer, EncodingData formattingData, out int bytesWritten) { // for now it only works for invariant culture if(!formattingData.IsInvariantUtf16 && !formattingData.IsInvariantUtf8) { throw new NotImplementedException(); } bytesWritten = 0; if (!TryWriteInt32(value.Month, buffer, G, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar('/', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(value.Day, buffer, G, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar('/', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(value.Year, buffer, G, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar(' ', buffer, formattingData, ref bytesWritten)) { return false; } var hour = value.Hour; if(hour == 0) { hour = 12; } if(hour > 12) { hour = hour - 12; } if (!TryWriteInt32(hour, buffer, G, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(value.Minute, buffer, D2, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(value.Second, buffer, D2, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar(' ', buffer, formattingData, ref bytesWritten)) { return false; } if(value.Hour > 11) { TryWriteString("PM", buffer, formattingData, ref bytesWritten); } else { TryWriteString("AM", buffer, formattingData, ref bytesWritten); } return true; }
static bool TryFormatDateTimeFormagG(DateTime value, Span <byte> buffer, EncodingData formattingData, out int bytesWritten) { // for now it only works for invariant culture if (!formattingData.IsInvariantUtf16 && !formattingData.IsInvariantUtf8) { throw new NotImplementedException(); } bytesWritten = 0; if (!TryWriteInt32(value.Month, buffer, G, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteChar('/', buffer, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteInt32(value.Day, buffer, G, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteChar('/', buffer, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteInt32(value.Year, buffer, G, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteChar(' ', buffer, formattingData, ref bytesWritten)) { return(false); } var hour = value.Hour; if (hour == 0) { hour = 12; } if (hour > 12) { hour = hour - 12; } if (!TryWriteInt32(hour, buffer, G, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteInt32(value.Minute, buffer, D2, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteInt32(value.Second, buffer, D2, formattingData, ref bytesWritten)) { return(false); } if (!TryWriteChar(' ', buffer, formattingData, ref bytesWritten)) { return(false); } if (value.Hour > 11) { TryWriteString("PM", buffer, formattingData, ref bytesWritten); } else { TryWriteString("AM", buffer, formattingData, ref bytesWritten); } return(true); }
static bool TryFormatDateTimeFormatO(DateTimeOffset value, bool isDateTime, Span<byte> buffer, EncodingData formattingData, out int bytesWritten) { bytesWritten = 0; if (!TryWriteInt32(value.Year, buffer, D4, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar('-', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(value.Month, buffer, D2, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar('-', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(value.Day, buffer, D2, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar('T', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(value.Hour, buffer, D2, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(value.Minute, buffer, D2, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(value.Second, buffer, D2, formattingData, ref bytesWritten)) { return false; } // add optional fractional second only if needed... var rounded = new DateTimeOffset(value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second, TimeSpan.Zero); var delta = value - rounded; if (delta.Ticks != 0) { if (!TryWriteChar('.', buffer, formattingData, ref bytesWritten)) { return false; } var timeFrac = delta.Ticks * FractionalTimeScale / System.TimeSpan.TicksPerSecond; if (!TryWriteInt64(timeFrac, buffer, D7, formattingData, ref bytesWritten)) { return false; } } if (isDateTime) { if (!TryWriteChar('Z', buffer, formattingData, ref bytesWritten)) { return false; } } else { if (!TryWriteChar('+', buffer, formattingData, ref bytesWritten)) { return false; } int bytes; if (!value.Offset.TryFormat(buffer.Slice(bytesWritten), t, formattingData, out bytes)) { return false; } bytesWritten += bytes; } return true; }
public unsafe static bool TryParseDouble(byte* text, int index, int length, EncodingData encoding, Format.Parsed format, out double value, out int bytesConsumed) { // Precondition replacement if (length < 1 || index < 0) { value = 0; bytesConsumed = 0; return false; } value = 0.0; bytesConsumed = 0; if (encoding.IsInvariantUtf8) { string doubleString = ""; bool decimalPlace = false, e = false, signed = false, digitLast = false, eLast = false; if ((length) >= 3 && text[index] == 'N' && text[index + 1] == 'a' && text[index + 2] == 'N') { value = double.NaN; bytesConsumed = 3; return true; } if (text[index] == '-' || text[index] == '+') { signed = true; doubleString += (char)text[index]; index++; bytesConsumed++; } if ((length - index) >= 8 && text[index] == 'I' && text[index + 1] == 'n' && text[index + 2] == 'f' && text[index + 3] == 'i' && text[index + 4] == 'n' && text[index + 5] == 'i' && text[index + 6] == 't' && text[index + 7] == 'y') { if (signed && text[index - 1] == '-') { value = double.NegativeInfinity; } else { value = double.PositiveInfinity; } bytesConsumed += 8; return true; } for (int byteIndex = index; byteIndex < length; byteIndex++) { byte nextByte = text[byteIndex]; byte nextByteVal = (byte)(nextByte - '0'); if (nextByteVal > 9) { if (!decimalPlace && nextByte == '.') { if (digitLast) { digitLast = false; } if (eLast) { eLast = false; } bytesConsumed++; decimalPlace = true; doubleString += (char)nextByte; } else if (!e && nextByte == 'e' || nextByte == 'E') { e = true; eLast = true; bytesConsumed++; doubleString += (char)nextByte; } else if (eLast && nextByte == '+' || nextByte == '-') { eLast = false; bytesConsumed++; doubleString += (char)nextByte; } else if ((decimalPlace && signed && bytesConsumed == 2) || ((signed || decimalPlace) && bytesConsumed == 1)) { value = 0; bytesConsumed = 0; return false; } else { if (double.TryParse(doubleString, out value)) { return true; } else { bytesConsumed = 0; return false; } } } else { if (eLast) eLast = false; if (!digitLast) digitLast = true; bytesConsumed++; doubleString += (char)nextByte; } } if ((decimalPlace && signed && bytesConsumed == 2) || ((signed || decimalPlace) && bytesConsumed == 1)) { value = 0; bytesConsumed = 0; return false; } else { if (double.TryParse(doubleString, out value)) { return true; } else { bytesConsumed = 0; return false; } } } return false; }
static bool TryFormatDateTimeRfc1123(DateTime value, Span<byte> buffer, EncodingData formattingData, out int bytesWritten) { bytesWritten = 0; if (!TryWriteString(s_dayNames[(int)value.DayOfWeek], buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(value.Day, buffer, D2, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar(' ', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteString(s_monthNames[value.Month - 1], buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar(' ', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(value.Year, buffer, D4, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar(' ', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(value.Hour, buffer, D2, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(value.Minute, buffer, D2, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(value.Second, buffer, D2, formattingData, ref bytesWritten)) { return false; } if (!TryWriteString(" GMT", buffer, formattingData, ref bytesWritten)) { return false; } return true; }
public static bool TryFormat(this TimeSpan value, Span<byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { if (format.IsDefault) { format.Symbol = 'c'; } Precondition.Require(format.Symbol == 'G' || format.Symbol == 't' || format.Symbol == 'c' || format.Symbol == 'g'); if (format.Symbol != 't') { return TryFormatTimeSpanG(value, buffer, format, formattingData, out bytesWritten); } // else it's format 't' (short time used to print time offsets) return TryFormatTimeSpanT(value, buffer, formattingData, out bytesWritten); }
private static bool TryFormatTimeSpanG(TimeSpan value, Span<byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { bytesWritten = 0; if (value.Ticks < 0) { if (!TryWriteChar('-', buffer, formattingData, ref bytesWritten)) { return false; } } bool daysWritten = false; if (value.Days != 0 || format.Symbol == 'G') { if (!TryWriteInt32(Abs(value.Days), buffer, default(Format.Parsed), formattingData, ref bytesWritten)) { return false; } daysWritten = true; if (format.Symbol == 'c') { if (!TryWriteChar('.', buffer, formattingData, ref bytesWritten)) { return false; } } else { if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return false; } } } var hourFormat = default(Format.Parsed); if ((daysWritten || format.Symbol == 'c') && format.Symbol != 'g') { hourFormat = D2; } if (!TryWriteInt32(Abs(value.Hours), buffer, hourFormat, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(Abs(value.Minutes), buffer, D2, formattingData, ref bytesWritten)) { return false; } if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return false; } if (!TryWriteInt32(Abs(value.Seconds), buffer, D2, formattingData, ref bytesWritten)) { return false; } long remainingTicks; if (value.Ticks != long.MinValue) { remainingTicks = Abs(value.Ticks) % TimeSpan.TicksPerSecond; } else { remainingTicks = long.MaxValue % TimeSpan.TicksPerSecond; remainingTicks = (remainingTicks + 1) % TimeSpan.TicksPerSecond; } var ticksFormat = D7; if (remainingTicks != 0) { if (!TryWriteChar('.', buffer, formattingData, ref bytesWritten)) { return false; } var fraction = remainingTicks * FractionalTimeScale / TimeSpan.TicksPerSecond; if (!TryWriteInt64(fraction, buffer, ticksFormat, formattingData, ref bytesWritten)) { return false; } } return true; }
[InlineData("-129", false, 0, 0, 0)] // negative overflow test public unsafe void ParseCustomCultureByteArrayToSbyte(string text, bool expectSuccess, int index, sbyte expectedValue, int expectedBytesConsumed) { sbyte parsedValue; int bytesConsumed; var utf8digitsAndSymbols = new byte[][] { new byte[] { 48, }, new byte[] { 49, }, new byte[] { 50, }, new byte[] { 51, }, new byte[] { 52, }, new byte[] { 53, }, new byte[] { 54, }, new byte[] { 55, }, new byte[] { 56, }, new byte[] { 57, }, // digit 9 new byte[] { 46, }, // decimal separator null, // so that it is != to uft8DigitsAndSymbols new byte[] { 73, 110, 102, 105, 110, 105, 116, 121, }, new byte[] { 45, }, // minus sign new byte[] { 43, }, // plus sign new byte[] { 78, 97, 78, }, // NaN new byte[] { 69, }, // E }; var utf8ParsingTrie = new EncodingData.TrieNode[] { new EncodingData.TrieNode { valueOrNumChildren = 17, index = 0x3004390D }, new EncodingData.TrieNode { valueOrNumChildren = 43, index = 18 }, new EncodingData.TrieNode { valueOrNumChildren = 45, index = 19 }, new EncodingData.TrieNode { valueOrNumChildren = 46, index = 20 }, new EncodingData.TrieNode { valueOrNumChildren = 48, index = 21 }, new EncodingData.TrieNode { valueOrNumChildren = 49, index = 22 }, new EncodingData.TrieNode { valueOrNumChildren = 50, index = 23 }, new EncodingData.TrieNode { valueOrNumChildren = 51, index = 24 }, new EncodingData.TrieNode { valueOrNumChildren = 52, index = 25 }, new EncodingData.TrieNode { valueOrNumChildren = 53, index = 26 }, new EncodingData.TrieNode { valueOrNumChildren = 54, index = 27 }, new EncodingData.TrieNode { valueOrNumChildren = 55, index = 28 }, new EncodingData.TrieNode { valueOrNumChildren = 56, index = 29 }, new EncodingData.TrieNode { valueOrNumChildren = 57, index = 30 }, new EncodingData.TrieNode { valueOrNumChildren = 69, index = 31 }, new EncodingData.TrieNode { valueOrNumChildren = 73, index = 32 }, new EncodingData.TrieNode { valueOrNumChildren = 78, index = 33 }, new EncodingData.TrieNode { valueOrNumChildren = 101, index = 34 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 14 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 13 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 10 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 0 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 1 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 2 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 3 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 4 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 5 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 6 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 7 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 8 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 9 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 16 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 12 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 15 }, new EncodingData.TrieNode { valueOrNumChildren = 0, index = 16 }, }; EncodingData fd = new EncodingData(utf8digitsAndSymbols, utf8ParsingTrie, EncodingData.Encoding.Utf8); Format.Parsed nf = new Format.Parsed('R'); bool result = PrimitiveParser.TryParseSByte(UtfEncode(text, false), index, fd, nf, out parsedValue, out bytesConsumed); Assert.Equal(expectSuccess, result); Assert.Equal(expectedValue, parsedValue); Assert.Equal(expectedBytesConsumed, bytesConsumed); }
public static bool TryFormatNumber(double value, bool isSingle, Span <byte> buffer, Format.Parsed format, EncodingData formattingData, out int bytesWritten) { Precondition.Require(format.Symbol == 'G' || format.Symbol == 'E' || format.Symbol == 'F'); bytesWritten = 0; int written; if (Double.IsNaN(value)) { return(formattingData.TryWriteSymbol(EncodingData.Symbol.NaN, buffer, out bytesWritten)); } if (Double.IsInfinity(value)) { if (Double.IsNegativeInfinity(value)) { if (!formattingData.TryWriteSymbol(EncodingData.Symbol.MinusSign, buffer, out written)) { bytesWritten = 0; return(false); } bytesWritten += written; } if (!formattingData.TryWriteSymbol(EncodingData.Symbol.InfinitySign, buffer.Slice(bytesWritten), out written)) { bytesWritten = 0; return(false); } bytesWritten += written; return(true); } // TODO: the lines below need to be replaced with properly implemented algorithm // the problem is the algorithm is complex, so I am commiting a stub for now var hack = value.ToString(format.Symbol.ToString()); return(hack.TryFormat(buffer, default(Format.Parsed), formattingData, out bytesWritten)); }