Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

BufferReader over sequences #2015

Merged
merged 2 commits into from
Jan 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,32 @@

namespace System.Buffers
{
public ref struct BufferReader
public class BufferReader
{
public static BufferReader<TSequence> Create<TSequence>(TSequence buffer) where TSequence : ISequence<ReadOnlyMemory<byte>>
{
return new BufferReader<TSequence>(buffer);
}
}

public ref struct BufferReader<TSequence> where TSequence : ISequence<ReadOnlyMemory<byte>>
{
private ReadOnlySpan<byte> _currentSpan;
private int _index;
private ReadOnlyBuffer.Enumerator _enumerator;
private TSequence _sequence;
private Position _currentPosition;
private Position _nextPosition;
private int _consumedBytes;
private bool _end;

public BufferReader(ReadOnlyBuffer buffer)
public BufferReader(TSequence buffer)
{
_end = false;
_index = 0;
_consumedBytes = 0;
_enumerator = buffer.GetEnumerator();
_sequence = buffer;
_currentPosition = _sequence.Start;
_nextPosition = _currentPosition;
_currentSpan = default;
MoveNext();
}
Expand All @@ -28,7 +40,7 @@ public BufferReader(ReadOnlyBuffer buffer)

public int Index => _index;

public Position Cursor => _enumerator.CreateCursor(_index);
public Position Position => _currentPosition + _index;

public ReadOnlySpan<byte> Span => _currentSpan;

Expand Down Expand Up @@ -68,18 +80,17 @@ public int Take()
[MethodImpl(MethodImplOptions.NoInlining)]
private void MoveNext()
{
while (_enumerator.MoveNext())
var previous = _nextPosition;
while(_sequence.TryGet(ref _nextPosition, out var memory, true))
{
_currentPosition = previous;
_currentSpan = memory.Span;
_index = 0;
var memory = _enumerator.Current;
var length = memory.Length;
if (length != 0)
if (_currentSpan.Length > 0)
{
_currentSpan = memory.Span;
return;
}
}

_end = true;
}

Expand Down
8 changes: 4 additions & 4 deletions src/System.Text.Http.Parser/HttpParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ public unsafe bool ParseHeaders<T>(T handler, in ReadOnlyBuffer buffer, out Posi

var bufferEnd = buffer.End;

var reader = new BufferReader(buffer);
var start = default(BufferReader);
var reader = BufferReader.Create(buffer);
var start = default(BufferReader<ReadOnlyBuffer>);
var done = false;

try
Expand Down Expand Up @@ -319,7 +319,7 @@ public unsafe bool ParseHeaders<T>(T handler, in ReadOnlyBuffer buffer, out Posi
}
else
{
var current = reader.Cursor;
var current = reader.Position;

// Split buffers
if (ReadOnlyBuffer.Seek(current, bufferEnd, out var lineEnd, ByteLF) == -1)
Expand Down Expand Up @@ -355,7 +355,7 @@ public unsafe bool ParseHeaders<T>(T handler, in ReadOnlyBuffer buffer, out Posi
}
finally
{
consumed = reader.Cursor;
consumed = reader.Position;
consumedBytes = reader.ConsumedBytes;

if (done)
Expand Down
2 changes: 1 addition & 1 deletion tests/Benchmarks/BytesReaderBench.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ static void ParseInt32ReadableBufferReader()
foreach (var iteration in Benchmark.Iterations)
{
var buffer = new ReadOnlyBuffer(s_data);
var reader = new BufferReader(buffer);
var reader = BufferReader.Create(buffer);

using (iteration.StartMeasurement())
{
Expand Down
48 changes: 24 additions & 24 deletions tests/System.Buffers.Primitives.Tests/ReadableBufferReaderFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ internal SingleSegment(ReadOnlyBufferFactory factory) : base(factory) { }
[Fact]
public void SkipSingleBufferSkipsBytes()
{
var reader = new BufferReader(BufferUtilities.CreateBuffer(new byte[] { 1, 2, 3, 4, 5 }));
var reader = BufferReader.Create(BufferUtilities.CreateBuffer(new byte[] { 1, 2, 3, 4, 5 }));
reader.Skip(2);
Assert.Equal(2, reader.Index);
Assert.Equal(3, reader.Span[reader.Index]);
Expand All @@ -44,7 +44,7 @@ public void SkipSingleBufferSkipsBytes()
[Fact]
public void TakeReturnsByteAndMoves()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { 1, 2 }));
var reader = BufferReader.Create(Factory.CreateWithContent(new byte[] { 1, 2 }));
Assert.Equal(0, reader.Index);
Assert.Equal(1, reader.Span[reader.Index]);
Assert.Equal(1, reader.Take());
Expand All @@ -71,15 +71,15 @@ internal ReadableBufferReaderFacts(ReadOnlyBufferFactory factory)
[Fact]
public void PeekReturnsByteWithoutMoving()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { 1, 2 }));
var reader = BufferReader.Create(Factory.CreateWithContent(new byte[] { 1, 2 }));
Assert.Equal(1, reader.Peek());
Assert.Equal(1, reader.Peek());
}

[Fact]
public void CursorIsCorrectAtEnd()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { 1, 2 }));
var reader = BufferReader.Create(Factory.CreateWithContent(new byte[] { 1, 2 }));
reader.Take();
reader.Take();
Assert.True(reader.End);
Expand All @@ -98,19 +98,19 @@ public void CursorIsCorrectWithEmptyLastBlock()
var start = new Position(first, first.Start);
var end = new Position(last, last.Start);

var reader = new BufferReader(new ReadOnlyBuffer(start, end));
var reader = BufferReader.Create(new ReadOnlyBuffer(start, end));
reader.Take();
reader.Take();
reader.Take();
Assert.Same(last, reader.Cursor.Segment);
Assert.Equal(0, reader.Cursor.Index);
Assert.Same(last, reader.Position.Segment);
Assert.Equal(0, reader.Position.Index);
Assert.True(reader.End);
}

[Fact]
public void PeekReturnsMinuOneByteInTheEnd()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { 1, 2 }));
var reader = BufferReader.Create(Factory.CreateWithContent(new byte[] { 1, 2 }));
Assert.Equal(1, reader.Take());
Assert.Equal(2, reader.Take());
Assert.Equal(-1, reader.Peek());
Expand All @@ -119,7 +119,7 @@ public void PeekReturnsMinuOneByteInTheEnd()
[Fact]
public void SkipToEndThenPeekReturnsMinusOne()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { 1, 2, 3, 4, 5 }));
var reader = BufferReader.Create(Factory.CreateWithContent(new byte[] { 1, 2, 3, 4, 5 }));
reader.Skip(5);
Assert.True(reader.End);
Assert.Equal(-1, reader.Peek());
Expand All @@ -128,7 +128,7 @@ public void SkipToEndThenPeekReturnsMinusOne()
[Fact]
public void SkippingPastLengthThrows()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { 1, 2, 3, 4, 5 }));
var reader = BufferReader.Create(Factory.CreateWithContent(new byte[] { 1, 2, 3, 4, 5 }));
try
{
reader.Skip(6);
Expand All @@ -144,7 +144,7 @@ public void SkippingPastLengthThrows()
public void CtorFindsFirstNonEmptySegment()
{
var buffer = Factory.CreateWithContent(new byte[] { 1 });
var reader = new BufferReader(buffer);
var reader = BufferReader.Create(buffer);

Assert.Equal(1, reader.Peek());
}
Expand All @@ -153,7 +153,7 @@ public void CtorFindsFirstNonEmptySegment()
public void EmptySegmentsAreSkippedOnMoveNext()
{
var buffer = Factory.CreateWithContent(new byte[] { 1, 2 });
var reader = new BufferReader(buffer);
var reader = BufferReader.Create(buffer);

Assert.Equal(1, reader.Peek());
reader.Skip(1);
Expand All @@ -164,7 +164,7 @@ public void EmptySegmentsAreSkippedOnMoveNext()
public void PeekGoesToEndIfAllEmptySegments()
{
var buffer = BufferUtilities.CreateBuffer(new[] { new byte[] { }, new byte[] { }, new byte[] { }, new byte[] { } });
var reader = new BufferReader(buffer);
var reader = BufferReader.Create(buffer);

Assert.Equal(-1, reader.Peek());
Assert.True(reader.End);
Expand All @@ -174,7 +174,7 @@ public void PeekGoesToEndIfAllEmptySegments()
public void SkipTraversesSegments()
{
var buffer = Factory.CreateWithContent(new byte[] { 1, 2, 3 });
var reader = new BufferReader(buffer);
var reader = BufferReader.Create(buffer);

reader.Skip(2);
Assert.Equal(3, reader.Span[reader.Index]);
Expand All @@ -185,7 +185,7 @@ public void SkipTraversesSegments()
public void SkipThrowsPastLengthMultipleSegments()
{
var buffer = Factory.CreateWithContent(new byte[] { 1, 2, 3 });
var reader = new BufferReader(buffer);
var reader = BufferReader.Create(buffer);

try
{
Expand All @@ -202,7 +202,7 @@ public void SkipThrowsPastLengthMultipleSegments()
public void TakeTraversesSegments()
{
var buffer = Factory.CreateWithContent(new byte[] { 1, 2, 3 });
var reader = new BufferReader(buffer);
var reader = BufferReader.Create(buffer);

Assert.Equal(1, reader.Take());
Assert.Equal(2, reader.Take());
Expand All @@ -214,7 +214,7 @@ public void TakeTraversesSegments()
public void PeekTraversesSegments()
{
var buffer = Factory.CreateWithContent(new byte[] { 1, 2 });
var reader = new BufferReader(buffer);
var reader = BufferReader.Create(buffer);

Assert.Equal(1, reader.Span[reader.Index]);
Assert.Equal(1, reader.Take());
Expand All @@ -230,7 +230,7 @@ public void PeekTraversesSegments()
public void PeekWorkesWithEmptySegments()
{
var buffer = Factory.CreateWithContent(new byte[] { 1 });
var reader = new BufferReader(buffer);
var reader = BufferReader.Create(buffer);

Assert.Equal(0, reader.Index);
Assert.Equal(1, reader.Span.Length);
Expand All @@ -243,7 +243,7 @@ public void PeekWorkesWithEmptySegments()
[Fact]
public void WorkesWithEmptyBuffer()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { }));
var reader = BufferReader.Create(Factory.CreateWithContent(new byte[] { }));

Assert.Equal(0, reader.Index);
Assert.Equal(0, reader.Span.Length);
Expand All @@ -261,14 +261,14 @@ public void WorkesWithEmptyBuffer()
public void ReturnsCorrectCursor(int takes, bool end)
{
var readableBuffer = Factory.CreateWithContent(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
var reader = new BufferReader(readableBuffer);
var reader = BufferReader.Create(readableBuffer);
for (int i = 0; i < takes; i++)
{
reader.Take();
}

var expected = end ? new byte[] {} : readableBuffer.Slice((long)takes).ToArray();
Assert.Equal(expected, readableBuffer.Slice(reader.Cursor).ToArray());
Assert.Equal(expected, readableBuffer.Slice(reader.Position).ToArray());
}

[Fact]
Expand All @@ -277,8 +277,8 @@ public void SlicingBufferReturnsCorrectCursor()
var buffer = Factory.CreateWithContent(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
var sliced = buffer.Slice(2L);

var reader = new BufferReader(sliced);
Assert.Equal(sliced.ToArray(), buffer.Slice(reader.Cursor).ToArray());
var reader = BufferReader.Create(sliced);
Assert.Equal(sliced.ToArray(), buffer.Slice(reader.Position).ToArray());
Assert.Equal(2, reader.Peek());
Assert.Equal(0, reader.Index);
}
Expand All @@ -287,7 +287,7 @@ public void SlicingBufferReturnsCorrectCursor()
public void ReaderIndexIsCorrect()
{
var buffer = Factory.CreateWithContent(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
var reader = new BufferReader(buffer);
var reader = BufferReader.Create(buffer);

var counter = 1;
while (!reader.End)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public void SeekLiveAspNetMultiBufferReadableBufferReader()

private static void FindAllNewLinesReadableBufferReader(ReadOnlyBuffer buffer)
{
var reader = new BufferReader(buffer);
var reader = BufferReader.Create(buffer);
var end = buffer.End;

while (!reader.End)
Expand All @@ -128,7 +128,7 @@ private static void FindAllNewLinesReadableBufferReader(ReadOnlyBuffer buffer)

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

if (ReadOnlyBuffer.Seek(current, end, out var found, (byte)'\n') == -1)
{
Expand Down