Example #1
0
        // 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));
        }
Example #2
0
        // 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));
        }
Example #9
0
        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);
        }
Example #10
0
        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);
        }