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

Commit

Permalink
BufferReader over sequences (#2015)
Browse files Browse the repository at this point in the history
* Simplified Position

* Changed BufferReader to work over sequences
  • Loading branch information
KrzysztofCwalina authored Jan 2, 2018
1 parent 10c22e3 commit d0ca6de
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 42 deletions.
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

0 comments on commit d0ca6de

Please sign in to comment.