예제 #1
0
            // This test verifies that optimization for known cursors works and
            // avoids additional walk but it's only valid for multi segmented buffers
            public void ReadCursorSeekDoesNotCheckEndIfTrustingEnd()
            {
                var buffer  = Factory.CreateOfSize(3);
                var buffer2 = Factory.CreateOfSize(3);

                ReadOnlyBuffer <byte> .Seek(buffer.Start, buffer2.End, 2, false);
            }
예제 #2
0
        public void MemorySeek(string raw, string search, char expectResult, int expectIndex)
        {
            var      cursors = Factory.CreateWithContent(raw);
            Position start   = cursors.Start;
            Position end     = cursors.End;
            Position result  = default;

            var searchFor = search.ToCharArray();

            int found = -1;

            if (searchFor.Length == 1)
            {
                found = ReadOnlyBuffer.Seek(start, end, out result, (byte)searchFor[0]);
            }
            else if (searchFor.Length == 2)
            {
                found = ReadOnlyBuffer.Seek(start, end, out result, (byte)searchFor[0], (byte)searchFor[1]);
            }
            else if (searchFor.Length == 3)
            {
                found = ReadOnlyBuffer.Seek(start, end, out result, (byte)searchFor[0], (byte)searchFor[1], (byte)searchFor[2]);
            }
            else
            {
                Assert.False(true, "Invalid test sample.");
            }

            Assert.Equal(expectResult, found);
            Assert.Equal(cursors.Slice(result).ToArray(), Encoding.ASCII.GetBytes(raw.Substring(expectIndex)));
        }
예제 #3
0
        public void ReadCursorSeekChecksEndIfNotTrustingEnd()
        {
            var buffer  = Factory.CreateOfSize(3);
            var buffer2 = Factory.CreateOfSize(3);

            Assert.Throws <InvalidOperationException>(() => ReadOnlyBuffer <byte> .Seek(buffer.Start, buffer2.End, 2, true));
        }
예제 #4
0
        public void TestSeekIteratorLimitWithinSameBlock(string input, char seek, char limitAfter, int expectedReturnValue)
        {
            // Arrange
            var afterSeek = (byte)'B';

            var buffer = Factory.CreateWithContent(input);

            var start   = buffer.Start;
            var scan1   = buffer.Start;
            var veryEnd = buffer.End;
            var scan2_1 = scan1;
            var scan2_2 = scan1;
            var scan3_1 = scan1;
            var scan3_2 = scan1;
            var scan3_3 = scan1;
            var end     = buffer.End;

            // Act
            var endReturnValue = ReadOnlyBuffer.Seek(start, veryEnd, out end, (byte)limitAfter);

            if (endReturnValue != -1)
            {
                end = buffer.Slice(end, 1).End;
            }
            var returnValue1   = ReadOnlyBuffer.Seek(start, end, out scan1, (byte)seek);
            var returnValue2_1 = ReadOnlyBuffer.Seek(start, end, out scan2_1, (byte)seek, afterSeek);
            var returnValue2_2 = ReadOnlyBuffer.Seek(start, end, out scan2_2, afterSeek, (byte)seek);
            var returnValue3_1 = ReadOnlyBuffer.Seek(start, end, out scan3_1, (byte)seek, afterSeek, afterSeek);
            var returnValue3_2 = ReadOnlyBuffer.Seek(start, end, out scan3_2, afterSeek, (byte)seek, afterSeek);
            var returnValue3_3 = ReadOnlyBuffer.Seek(start, end, out scan3_3, afterSeek, afterSeek, (byte)seek);


            // Assert
            Assert.Equal(input.Contains(limitAfter) ? limitAfter : -1, endReturnValue);
            Assert.Equal(expectedReturnValue, returnValue1);
            Assert.Equal(expectedReturnValue, returnValue2_1);
            Assert.Equal(expectedReturnValue, returnValue2_2);
            Assert.Equal(expectedReturnValue, returnValue3_1);
            Assert.Equal(expectedReturnValue, returnValue3_2);
            Assert.Equal(expectedReturnValue, returnValue3_3);

            if (expectedReturnValue != -1)
            {
                var expectedEndIndex = input.IndexOf(seek);

                Assert.Equal(buffer.Slice(scan1).ToArray(), Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)));
                Assert.Equal(buffer.Slice(scan2_1).ToArray(), Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)));
                Assert.Equal(buffer.Slice(scan2_2).ToArray(), Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)));
                Assert.Equal(buffer.Slice(scan3_1).ToArray(), Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)));
                Assert.Equal(buffer.Slice(scan3_2).ToArray(), Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)));
                Assert.Equal(buffer.Slice(scan3_3).ToArray(), Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)));
            }
        }
            private void ParseExtension(ReadOnlyBuffer buffer, out Position consumed, out Position examined)
            {
                // Chunk-extensions not currently parsed
                // Just drain the data
                consumed = buffer.Start;
                examined = buffer.Start;

                do
                {
                    Position extensionCursor;
                    if (ReadOnlyBuffer.Seek(buffer.Start, buffer.End, out extensionCursor, ByteCR) == -1)
                    {
                        // End marker not found yet
                        consumed = buffer.End;
                        examined = buffer.End;
                        AddAndCheckConsumedBytes(buffer.Length);
                        return;
                    }
                    ;

                    var charsToByteCRExclusive = buffer.Slice(0, extensionCursor).Length;

                    var sufixBuffer = buffer.Slice(extensionCursor);
                    if (sufixBuffer.Length < 2)
                    {
                        consumed = extensionCursor;
                        examined = buffer.End;
                        AddAndCheckConsumedBytes(charsToByteCRExclusive);
                        return;
                    }

                    sufixBuffer = sufixBuffer.Slice(0, 2);
                    var sufixSpan = sufixBuffer.ToSpan();

                    if (sufixSpan[1] == '\n')
                    {
                        // We consumed the \r\n at the end of the extension, so switch modes.
                        _mode = _inputLength > 0 ? Mode.Data : Mode.Trailer;

                        consumed = sufixBuffer.End;
                        examined = sufixBuffer.End;
                        AddAndCheckConsumedBytes(charsToByteCRExclusive + 2);
                    }
                    else
                    {
                        // Don't consume suffixSpan[1] in case it is also a \r.
                        buffer   = buffer.Slice(charsToByteCRExclusive + 1);
                        consumed = extensionCursor;
                        AddAndCheckConsumedBytes(charsToByteCRExclusive + 1);
                    }
                } while (_mode == Mode.Extension);
            }
예제 #6
0
        public void SegmentStartIsConsideredInBoundsCheck()
        {
            // 0               50           100    0             50             100
            // [                ##############] -> [##############                ]
            //                         ^c1            ^c2
            var bufferSegment1 = new BufferSegment();

            bufferSegment1.SetMemory(new OwnedArray <byte>(new byte[100]), 50, 99);

            var bufferSegment2 = new BufferSegment();

            bufferSegment2.SetMemory(new OwnedArray <byte>(new byte[100]), 0, 50);
            bufferSegment1.SetNext(bufferSegment2);

            var readableBuffer = new ReadOnlyBuffer <byte>(bufferSegment1, 0, bufferSegment2, 50);

            var c1 = readableBuffer.Seek(readableBuffer.Start, 25); // segment 1 index 75
            var c2 = readableBuffer.Seek(readableBuffer.Start, 55); // segment 2 index 5

            var sliced = readableBuffer.Slice(c1, c2);

            Assert.Equal(30, sliced.Length);
        }
        private static void FindAllNewLines(ReadOnlyBuffer buffer)
        {
            var start = buffer.Start;
            var end   = buffer.End;

            while (true)
            {
                if (ReadOnlyBuffer.Seek(start, end, out var found, (byte)'\n') == -1)
                {
                    break;
                }

                start = buffer.Move(found, 1);
            }
        }
예제 #8
0
        public void MovePrefersNextSegment()
        {
            var bufferSegment1 = new BufferSegment();

            bufferSegment1.SetMemory(new OwnedArray <byte>(new byte[100]), 49, 99);

            var bufferSegment2 = new BufferSegment();

            bufferSegment2.SetMemory(new OwnedArray <byte>(new byte[100]), 0, 0);
            bufferSegment1.SetNext(bufferSegment2);

            var readableBuffer = new ReadOnlyBuffer <byte>(bufferSegment1, 0, bufferSegment2, 0);

            var c1 = readableBuffer.Seek(readableBuffer.Start, 50);

            Assert.Equal(0, c1.Index);
            Assert.Equal(bufferSegment2, c1.Segment);
        }
        private static void FindAllNewLinesReadableBufferReader(ReadOnlyBuffer buffer)
        {
            var reader = BufferReader.Create(buffer);
            var end    = buffer.End;

            while (!reader.End)
            {
                var span = reader.Span;

                // Trim the start if we have an index
                if (reader.Index > 0)
                {
                    span = span.Slice(reader.Index);
                }

                while (span.Length > 0)
                {
                    var length = span.IndexOf((byte)'\n');
                    var skip   = length;

                    if (length == -1)
                    {
                        var current = reader.Position;

                        if (ReadOnlyBuffer.Seek(current, end, out var found, (byte)'\n') == -1)
                        {
                            // We're done
                            return;
                        }

                        length = span.Length;
                        skip   = (int)buffer.Slice(current, found).Length + 1;
                    }
                    else
                    {
                        length += 1;
                        skip    = length;
                    }

                    span = span.Slice(length);
                    reader.Skip(skip);
                }
            }
        }
예제 #10
0
        public void TestSeekByteLimitWithinSameBlock(string input, char seek, int limit, int expectedBytesScanned, int expectedReturnValue)
        {
            // Arrange
            var buffer = Factory.CreateWithContent(input);

            // Act
            var end           = limit > input.Length ? buffer.End : buffer.Slice(0, limit).End;
            var returnValue   = ReadOnlyBuffer.Seek(buffer.Start, end, out Position result, (byte)seek);
            var returnValue_1 = ReadOnlyBuffer.Seek(buffer.Start, end, out result, (byte)seek, (byte)seek);
            var returnValue_2 = ReadOnlyBuffer.Seek(buffer.Start, end, out result, (byte)seek, (byte)seek, (byte)seek);

            // Assert
            Assert.Equal(expectedReturnValue, returnValue);
            Assert.Equal(expectedReturnValue, returnValue_1);
            Assert.Equal(expectedReturnValue, returnValue_2);

            if (expectedReturnValue != -1)
            {
                Assert.Equal(buffer.Slice(result).ToArray(), Encoding.ASCII.GetBytes(input.Substring(expectedBytesScanned - 1)));
            }
        }
        public ParseResult ParseMessage(ReadOnlyBuffer buffer, out Position consumed, out Position examined, out byte[] message)
        {
            consumed = buffer.Start;
            examined = buffer.End;
            message  = null;

            var start = consumed;
            var end   = examined;

            while (buffer.Length > 0)
            {
                if (ReadOnlyBuffer.Seek(start, end, out var lineEnd, ByteLF) == -1)
                {
                    // For the case of  data: Foo\r\n\r\<Anytine except \n>
                    if (_internalParserState == InternalParseState.ReadEndOfMessage)
                    {
                        if (ConvertBufferToSpan(buffer.Slice(start, buffer.End)).Length > 1)
                        {
                            throw new FormatException("Expected a \\r\\n frame ending");
                        }
                    }

                    // Partial message. We need to read more.
                    return(ParseResult.Incomplete);
                }

                lineEnd = buffer.Move(lineEnd, 1);
                var line = ConvertBufferToSpan(buffer.Slice(start, lineEnd));
                buffer = buffer.Slice(line.Length);

                if (line.Length <= 1)
                {
                    throw new FormatException("There was an error in the frame format");
                }

                // Skip comments
                if (line[0] == ByteColon)
                {
                    start    = lineEnd;
                    consumed = lineEnd;
                    continue;
                }

                if (IsMessageEnd(line))
                {
                    _internalParserState = InternalParseState.ReadEndOfMessage;
                }

                // To ensure that the \n was preceded by a \r
                // since messages can't contain \n.
                // data: foo\n\bar should be encoded as
                // data: foo\r\n
                // data: bar\r\n
                else if (line[line.Length - _sseLineEnding.Length] != ByteCR)
                {
                    throw new FormatException("Unexpected '\n' in message. A '\n' character can only be used as part of the newline sequence '\r\n'");
                }
                else
                {
                    EnsureStartsWithDataPrefix(line);
                }

                var payload = Array.Empty <byte>();
                switch (_internalParserState)
                {
                case InternalParseState.ReadMessagePayload:
                    EnsureStartsWithDataPrefix(line);

                    // Slice away the 'data: '
                    var payloadLength = line.Length - (_dataPrefix.Length + _sseLineEnding.Length);
                    var newData       = line.Slice(_dataPrefix.Length, payloadLength).ToArray();
                    _data.Add(newData);

                    start    = lineEnd;
                    consumed = lineEnd;
                    break;

                case InternalParseState.ReadEndOfMessage:
                    if (_data.Count == 1)
                    {
                        payload = _data[0];
                    }
                    else if (_data.Count > 1)
                    {
                        // Find the final size of the payload
                        var payloadSize = 0;
                        foreach (var dataLine in _data)
                        {
                            payloadSize += dataLine.Length;
                        }

                        payloadSize += _newLine.Length * _data.Count;

                        // Allocate space in the payload buffer for the data and the new lines.
                        // Subtract newLine length because we don't want a trailing newline.
                        payload = new byte[payloadSize - _newLine.Length];

                        var offset = 0;
                        foreach (var dataLine in _data)
                        {
                            dataLine.CopyTo(payload, offset);
                            offset += dataLine.Length;
                            if (offset < payload.Length)
                            {
                                _newLine.CopyTo(payload, offset);
                                offset += _newLine.Length;
                            }
                        }
                    }

                    message  = payload;
                    consumed = lineEnd;
                    examined = consumed;
                    return(ParseResult.Completed);
                }

                if (buffer.Length > 0 && buffer.First.Span[0] == ByteCR)
                {
                    _internalParserState = InternalParseState.ReadEndOfMessage;
                }
            }
            return(ParseResult.Incomplete);
        }
예제 #12
0
 public Position Seek(Position origin, long offset)
 => _buffer.Seek(origin, offset);
        /// <summary>
        /// Searches for a byte in the <see cref="ReadOnlyBuffer"/> and returns a sliced <see cref="ReadOnlyBuffer"/> that
        /// contains all data up to and excluding the byte, and a <see cref="Position"/> that points to the byte.
        /// </summary>
        /// <param name="b1">The first byte to search for</param>
        /// <param name="slice">A <see cref="ReadOnlyBuffer"/> slice that contains all data up to and excluding the first byte.</param>
        /// <param name="cursor">A <see cref="Position"/> that points to the second byte</param>
        /// <returns>True if the byte sequence was found, false if not found</returns>
        public static bool TrySliceTo(this ReadOnlyBuffer <byte> buffer, byte b1, out ReadOnlyBuffer <byte> slice, out Position cursor)
        {
            if (buffer.IsEmpty)
            {
                slice  = default;
                cursor = default;
                return(false);
            }

            var byte0Vector = GetVector(b1);

            var seek = 0;

            foreach (var memory in buffer)
            {
                var currentSpan = memory.Span;
                var found       = false;

                if (Vector.IsHardwareAccelerated)
                {
                    while (currentSpan.Length >= VectorWidth)
                    {
                        var data        = ReadMachineEndian <Vector <byte> >(currentSpan);
                        var byte0Equals = Vector.Equals(data, byte0Vector);

                        if (byte0Equals.Equals(Vector <byte> .Zero))
                        {
                            currentSpan = currentSpan.Slice(VectorWidth);
                            seek       += VectorWidth;
                        }
                        else
                        {
                            var index = FindFirstEqualByte(ref byte0Equals);
                            seek += index;
                            found = true;
                            break;
                        }
                    }
                }

                if (!found)
                {
                    // Slow search
                    for (int i = 0; i < currentSpan.Length; i++)
                    {
                        if (currentSpan[i] == b1)
                        {
                            found = true;
                            break;
                        }
                        seek++;
                    }
                }

                if (found)
                {
                    cursor = buffer.Seek(buffer.Start, seek);
                    slice  = buffer.Slice(buffer.Start, cursor);
                    return(true);
                }
            }

            slice  = default;
            cursor = default;
            return(false);
        }