// once we have a non allocating conversion from string to ReadOnlySpan<char>, we can remove this overload public static Format.Parsed Parse(string format) { if (format == null || format.Length == 0) { return(default(Format.Parsed)); } uint precision = NoPrecision; if (format.Length > 1) { if (!PrimitiveParser.TryParseUInt32(format, 1, format.Length - 1, out precision)) { throw new NotImplementedException("Unable to parse precision specification"); } if (precision > Parsed.MaxPrecision) { // TODO: this is a contract violation throw new Exception("PrecisionValueOutOfRange"); } } var specifier = format[0]; return(new Parsed(specifier, (byte)precision)); }
// TODO: format should be ReadOnlySpan<T> public static Format.Parsed Parse(ReadOnlySpan <char> format) { if (format.Length == 0) { return(default(Format.Parsed)); } uint precision = NoPrecision; if (format.Length > 1) { var span = format.Slice(1, format.Length - 1); if (!PrimitiveParser.TryParseUInt32(span, out precision)) { throw new NotImplementedException("UnableToParsePrecision"); } if (precision > Parsed.MaxPrecision) { // TODO: this is a contract violation throw new Exception("PrecisionValueOutOfRange"); } } // TODO: this is duplicated from above. It needs to be refactored var specifier = format[0]; return(new Parsed(specifier, (byte)precision)); }
/// <summary> /// Parses a <see cref="uint"/> from the specified <see cref="ReadableBuffer"/> /// </summary> /// <param name="buffer">The <see cref="ReadableBuffer"/> to parse</param> public unsafe static uint GetUInt32(this ReadableBuffer buffer) { ReadOnlySpan <byte> textSpan; if (buffer.IsSingleSpan) { // It fits! textSpan = buffer.First.Span; } else if (buffer.Length < 128) // REVIEW: What's a good number { var data = stackalloc byte[128]; var destination = new Span <byte>(data, 128); buffer.CopyTo(destination); textSpan = destination.Slice(0, buffer.Length); } else { // Heap allocated copy to parse into array (should be rare) textSpan = new ReadOnlySpan <byte>(buffer.ToArray()); } uint value; var utf8Buffer = new Utf8String(textSpan); if (!PrimitiveParser.TryParseUInt32(utf8Buffer, out value)) { throw new InvalidOperationException(); } return(value); }
public unsafe void ParseSubstringToUInt32(string text, int index, int count, uint expectedValue, int expectedConsumed) { uint parsedValue; int charsConsumed; bool result = PrimitiveParser.TryParseUInt32(text, index, count, out parsedValue, out charsConsumed); Assert.True(result); Assert.Equal(expectedValue, parsedValue); Assert.Equal(expectedConsumed, charsConsumed); }
public unsafe void ParseSpanOfCharToUInt32(string text, uint expectedValue, int expectedConsumed) { var span = new ReadOnlySpan <char>(text.ToCharArray()); uint parsedValue; int charsConsumed; bool result = PrimitiveParser.TryParseUInt32(span, out parsedValue, out charsConsumed); Assert.True(result); Assert.Equal(expectedValue, parsedValue); Assert.Equal(expectedConsumed, charsConsumed); }
public unsafe void ParseUtf8StringToUInt32(string text, uint expectedValue, int expectedConsumed) { var utf8 = new Utf8String(text); uint parsedValue; int bytesConsumed; bool result = PrimitiveParser.TryParseUInt32(utf8, out parsedValue, out bytesConsumed); Assert.True(result); Assert.Equal(expectedValue, parsedValue); Assert.Equal(expectedConsumed, bytesConsumed); }
public unsafe void ParseUtf8SpanOfBytesToUInt32(string text, uint expectedValue, int expectedConsumed) { byte[] textBuffer = Encoding.UTF8.GetBytes(text); var span = new ReadOnlySpan <byte>(textBuffer); uint parsedValue; int bytesConsumed; bool result = PrimitiveParser.TryParseUInt32(span, EncodingData.Encoding.Utf8, out parsedValue, out bytesConsumed); Assert.True(result); Assert.Equal(expectedValue, parsedValue); Assert.Equal(expectedConsumed, bytesConsumed); }
public bool TryGetUInt32(Utf8String property, out uint value) { var jsonProperty = new JsonProperty(this, property); JsonValue jsonValue; if (!_properties.TryGetValue(jsonProperty, out jsonValue)) { value = default(uint); return(false); } if (jsonValue.Type != JsonReader.JsonValueType.Number) { throw new InvalidOperationException(); } int consumed; return(PrimitiveParser.TryParseUInt32(jsonValue.Value, out value, out consumed)); }
public static bool TryParseUInt32 <T>(this T memorySequence, out uint value, out int consumed) where T : ISequence <ReadOnlyMemory <byte> > { value = default(uint); consumed = default(int); Position position = Position.First; // Fetch the first segment ReadOnlyMemory <byte> first; if (!memorySequence.TryGet(ref position, out first, advance: true)) { return(false); } // Attempt to parse the first segment. If it works (and it should in most cases), then return success. bool parsed = PrimitiveParser.TryParseUInt32(new Utf8String(first.Span), out value, out consumed); if (parsed && consumed < first.Length) { return(true); } // Apparently the we need data from the second segment to succesfully parse, and so fetch the second segment. ReadOnlyMemory <byte> second; if (!memorySequence.TryGet(ref position, out second, advance: true)) { // if there is no second segment and the first parsed succesfully, return the result of the parsing. if (parsed) { return(true); } return(false); } // Combine the first, the second, and potentially more segments into a stack allocated buffer ReadOnlySpan <byte> combinedSpan; unsafe { if (first.Length < StackBufferSize) { var data = stackalloc byte[StackBufferSize]; var destination = new Span <byte>(data, StackBufferSize); first.CopyTo(destination); var free = destination.Slice(first.Length); if (second.Length > free.Length) { second = second.Slice(0, free.Length); } second.CopyTo(free); free = free.Slice(second.Length); ReadOnlyMemory <byte> next; while (free.Length > 0) { if (memorySequence.TryGet(ref position, out next, advance: true)) { if (next.Length > free.Length) { next = next.Slice(0, free.Length); } next.CopyTo(free); free = free.Slice(next.Length); } else { break; } } combinedSpan = destination.Slice(0, StackBufferSize - free.Length); // if the stack allocated buffer parsed succesfully (and for uint it should always do), then return success. if (PrimitiveParser.TryParseUInt32(new Utf8String(combinedSpan), out value, out consumed)) { if (consumed < combinedSpan.Length || combinedSpan.Length < StackBufferSize) { return(true); } } } } // for invariant culture, we should never reach this point, as invariant uint text is never longer than 127 bytes. // I left this code here, as we will need it for custom cultures and possibly when we shrink the stack allocated buffer. combinedSpan = memorySequence.ToSingleSpan(); if (!PrimitiveParser.TryParseUInt32(new Utf8String(combinedSpan), out value, out consumed)) { return(false); } return(true); }
public static bool TryParseUInt32 <TSequence>(this TSequence bytes, EncodingData encoding, out uint value, out int consumed) where TSequence : ISpanSequence <byte> { Position position = Position.First; Span <byte> first; if (!bytes.TryGet(ref position, out first, advance: true)) { throw new ArgumentException("bytes cannot be empty"); } if (!PrimitiveParser.TryParseUInt32(first, EncodingData.Encoding.Utf8, out value, out consumed)) { return(false); // TODO: maybe we should continue in some cases, e.g. if the first span ends in a decimal separator // ... cont, maybe consumed could be set even if TryParse returns false } if (position.Equals(Position.AfterLast) || first.Length > consumed) { return(true); } Span <byte> second; if (!bytes.TryGet(ref position, out second, advance: true)) { throw new ArgumentException("bytes cannot be empty"); } Span <byte> temp; int numberOfBytesFromSecond = second.Length; if (numberOfBytesFromSecond > 64) { numberOfBytesFromSecond = 64; } var tempBufferLength = first.Length + numberOfBytesFromSecond; if (tempBufferLength > 128) { temp = new byte[tempBufferLength]; } else { unsafe { byte *data = stackalloc byte[tempBufferLength]; temp = new Span <byte>(data, tempBufferLength); } } first.CopyTo(temp); second.Slice(0, numberOfBytesFromSecond).CopyTo(temp.Slice(first.Length)); if (!PrimitiveParser.TryParseUInt32(temp, EncodingData.Encoding.Utf8, out value, out consumed)) { return(false); } if (position.Equals(Position.AfterLast) || temp.Length > consumed) { return(true); } throw new NotImplementedException(); }
public unsafe void UInt32PositiveHexTests(string text, int length, uint expectedValue, int expectedConsumed) { byte[] byteBuffer = new Utf8String(text).CopyBytes(); ReadOnlySpan <byte> byteSpan = new ReadOnlySpan <byte>(byteBuffer); char[] charBuffer = text.ToCharArray(); ReadOnlySpan <char> charSpan = new ReadOnlySpan <char>(charBuffer); bool result; uint actualValue; int actualConsumed; result = PrimitiveParser.TryParseUInt32(byteSpan, out actualValue, out actualConsumed, EncodingData.InvariantUtf8, 'X'); Assert.True(result); Assert.Equal(expectedValue, actualValue); Assert.Equal(expectedConsumed, actualConsumed); fixed(byte *bytePointer = byteBuffer) { result = PrimitiveParser.InvariantUtf8.Hex.TryParseUInt32(bytePointer, length, out actualValue); Assert.True(result); Assert.Equal(expectedValue, actualValue); result = PrimitiveParser.InvariantUtf8.Hex.TryParseUInt32(bytePointer, length, out actualValue, out actualConsumed); Assert.True(result); Assert.Equal(expectedValue, actualValue); Assert.Equal(expectedConsumed, actualConsumed); } result = PrimitiveParser.InvariantUtf8.Hex.TryParseUInt32(byteSpan, out actualValue); Assert.True(result); Assert.Equal(expectedValue, actualValue); result = PrimitiveParser.InvariantUtf8.Hex.TryParseUInt32(byteSpan, out actualValue, out actualConsumed); Assert.True(result); Assert.Equal(expectedValue, actualValue); Assert.Equal(expectedConsumed, actualConsumed); ReadOnlySpan <byte> utf16ByteSpan = charSpan.Cast <char, byte>(); result = PrimitiveParser.TryParseUInt32(utf16ByteSpan, out actualValue, out actualConsumed, EncodingData.InvariantUtf16, 'X'); Assert.True(result); Assert.Equal(expectedValue, actualValue); Assert.Equal(expectedConsumed, actualConsumed / 2); fixed(char *charPointer = charBuffer) { result = PrimitiveParser.InvariantUtf16.Hex.TryParseUInt32(charPointer, length, out actualValue); Assert.True(result); Assert.Equal(expectedValue, actualValue); result = PrimitiveParser.InvariantUtf16.Hex.TryParseUInt32(charPointer, length, out actualValue, out actualConsumed); Assert.True(result); Assert.Equal(expectedValue, actualValue); Assert.Equal(expectedConsumed, actualConsumed); } result = PrimitiveParser.InvariantUtf16.Hex.TryParseUInt32(charSpan, out actualValue); Assert.True(result); Assert.Equal(expectedValue, actualValue); result = PrimitiveParser.InvariantUtf16.Hex.TryParseUInt32(charSpan, out actualValue, out actualConsumed); Assert.True(result); Assert.Equal(expectedValue, actualValue); Assert.Equal(expectedConsumed, actualConsumed); }