Skip to content

Commit

Permalink
Add GetPosition overload to ReadOnlySequence (dotnet/corefx#27633)
Browse files Browse the repository at this point in the history
* Add GetPosition overload to ReadOnlySequence

* Address feedback (split tests)

* Use new GetPosition overload whenever passing start is redundant.


Commit migrated from dotnet/corefx@9ff60da
  • Loading branch information
ahsonkhan authored Mar 2, 2018
1 parent 0aa965e commit 3bf27df
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 45 deletions.
8 changes: 4 additions & 4 deletions src/libraries/System.IO.Pipelines/tests/BackpressureTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public void AdvanceThrowsIfFlushActiveAndNotConsumedPastThreshold()
Assert.False(flushAsync.IsCompleted);

ReadResult result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
SequencePosition consumed = result.Buffer.GetPosition(result.Buffer.Start, 31);
SequencePosition consumed = result.Buffer.GetPosition(31);
Assert.Throws<InvalidOperationException>(() => _pipe.Reader.AdvanceTo(consumed, result.Buffer.End));

_pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
Expand All @@ -49,7 +49,7 @@ public void FlushAsyncAwaitableCompletesWhenReaderAdvancesUnderLow()
Assert.False(flushAsync.IsCompleted);

ReadResult result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
SequencePosition consumed = result.Buffer.GetPosition(result.Buffer.Start, 33);
SequencePosition consumed = result.Buffer.GetPosition(33);
_pipe.Reader.AdvanceTo(consumed, consumed);

Assert.True(flushAsync.IsCompleted);
Expand All @@ -66,7 +66,7 @@ public void FlushAsyncAwaitableDoesNotCompletesWhenReaderAdvancesUnderHight()
Assert.False(flushAsync.IsCompleted);

ReadResult result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
SequencePosition consumed = result.Buffer.GetPosition(result.Buffer.Start, 32);
SequencePosition consumed = result.Buffer.GetPosition(32);
_pipe.Reader.AdvanceTo(consumed, consumed);

Assert.False(flushAsync.IsCompleted);
Expand All @@ -81,7 +81,7 @@ public void FlushAsyncAwaitableResetsOnCommit()
Assert.False(flushAsync.IsCompleted);

ReadResult result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
SequencePosition consumed = result.Buffer.GetPosition(result.Buffer.Start, 33);
SequencePosition consumed = result.Buffer.GetPosition(33);
_pipe.Reader.AdvanceTo(consumed, consumed);

Assert.True(flushAsync.IsCompleted);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public async Task AdvanceWithGetPositionCrossingIntoWriteHeadWorks()

// Create position that would cross into write head
ReadOnlySequence<byte> buffer = readResult.Buffer;
SequencePosition position = buffer.GetPosition(buffer.Start, buffer.Length);
SequencePosition position = buffer.GetPosition(buffer.Length);

// Return everything
_pipe.Reader.AdvanceTo(position);
Expand Down Expand Up @@ -512,7 +512,7 @@ public async Task SyncReadThenAsyncRead()

Assert.Equal("Hello World", Encoding.ASCII.GetString(result.Buffer.ToArray()));

_pipe.Reader.AdvanceTo(result.Buffer.GetPosition(result.Buffer.Start, 6));
_pipe.Reader.AdvanceTo(result.Buffer.GetPosition(6));

result = await _pipe.Reader.ReadAsync();

Expand Down
3 changes: 2 additions & 1 deletion src/libraries/System.Memory/ref/System.Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,8 @@ public readonly partial struct ReadOnlySequence<T>
public long Length { get { throw null; } }
public System.SequencePosition Start { get { throw null; } }
public System.Buffers.ReadOnlySequence<T>.Enumerator GetEnumerator() { throw null; }
public System.SequencePosition GetPosition(System.SequencePosition origin, long offset) { throw null; }
public System.SequencePosition GetPosition(long offset) { throw null; }
public System.SequencePosition GetPosition(long offset, System.SequencePosition origin) { throw null; }
public System.Buffers.ReadOnlySequence<T> Slice(int start, int length) { throw null; }
public System.Buffers.ReadOnlySequence<T> Slice(int start, System.SequencePosition end) { throw null; }
public System.Buffers.ReadOnlySequence<T> Slice(long start) { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static class BuffersExtensions
int index = sequence.First.Span.IndexOf(value);
if (index != -1)
{
return sequence.GetPosition(sequence.Start, index);
return sequence.GetPosition(index);
}

return null;
Expand All @@ -39,7 +39,7 @@ public static class BuffersExtensions
int index = memory.Span.IndexOf(value);
if (index != -1)
{
return sequence.GetPosition(result, index);
return sequence.GetPosition(index, result);
}
else if (position.GetObject() == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,10 +310,15 @@ public ReadOnlySequence<T> Slice(long start)
/// </summary>
public Enumerator GetEnumerator() => new Enumerator(this);

/// <summary>
/// Returns a new <see cref="SequencePosition"/> at an <paramref name="offset"/> from the start of the sequence.
/// </summary>
public SequencePosition GetPosition(long offset) => GetPosition(offset, _sequenceStart);

/// <summary>
/// Returns a new <see cref="SequencePosition"/> at an <paramref name="offset"/> from the <paramref name="origin"/>
/// </summary>
public SequencePosition GetPosition(SequencePosition origin, long offset)
public SequencePosition GetPosition(long offset, SequencePosition origin)
{
if (offset < 0)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.offset);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,17 @@ public void SegmentStartIsConsideredInBoundsCheck()

var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 50);

SequencePosition c1 = buffer.GetPosition(buffer.Start, 25); // segment 1 index 75
SequencePosition c2 = buffer.GetPosition(buffer.Start, 55); // segment 2 index 5
SequencePosition c1 = buffer.GetPosition(25); // segment 1 index 75
SequencePosition c2 = buffer.GetPosition(55); // segment 2 index 5

ReadOnlySequence<byte> sliced = buffer.Slice(c1, c2);
Assert.Equal(30, sliced.Length);

c1 = buffer.GetPosition(25, buffer.Start); // segment 1 index 75
c2 = buffer.GetPosition(55, buffer.Start); // segment 2 index 5

sliced = buffer.Slice(c1, c2);
Assert.Equal(30, sliced.Length);
}

[Fact]
Expand All @@ -39,7 +45,12 @@ public void GetPositionPrefersNextSegment()

ReadOnlySequence<byte> buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 0);

SequencePosition c1 = buffer.GetPosition(buffer.Start, 50);
SequencePosition c1 = buffer.GetPosition(50);

Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment2, c1.GetObject());

c1 = buffer.GetPosition(50, buffer.Start);

Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment2, c1.GetObject());
Expand All @@ -54,7 +65,12 @@ public void GetPositionDoesNotCrossOutsideBuffer()

var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 100);

SequencePosition c1 = buffer.GetPosition(buffer.Start, 200);
SequencePosition c1 = buffer.GetPosition(200);

Assert.Equal(100, c1.GetInteger());
Assert.Equal(bufferSegment2, c1.GetObject());

c1 = buffer.GetPosition(200, buffer.Start);

Assert.Equal(100, c1.GetInteger());
Assert.Equal(bufferSegment2, c1.GetObject());
Expand All @@ -70,13 +86,21 @@ public void CheckEndReachableDoesNotCrossPastEnd()

var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment4, 100);

SequencePosition c1 = buffer.GetPosition(buffer.Start, 200);
SequencePosition c1 = buffer.GetPosition(200);

Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment3, c1.GetObject());

ReadOnlySequence<byte> seq = buffer.Slice(0, c1);
Assert.Equal(200, seq.Length);

c1 = buffer.GetPosition(200, buffer.Start);

Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment3, c1.GetObject());

seq = buffer.Slice(0, c1);
Assert.Equal(200, seq.Length);
}

[Fact]
Expand All @@ -89,7 +113,12 @@ public void SeekSkipsEmptySegments()

var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment4, 100);

SequencePosition c1 = buffer.GetPosition(buffer.Start, 100);
SequencePosition c1 = buffer.GetPosition(100);

Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment4, c1.GetObject());

c1 = buffer.GetPosition(100, buffer.Start);

Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment4, c1.GetObject());
Expand All @@ -105,22 +134,54 @@ public void SeekEmptySkipDoesNotCrossPastEnd()

var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 0);

SequencePosition c1 = buffer.GetPosition(buffer.Start, 100);
SequencePosition c1 = buffer.GetPosition(100);

Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment2, c1.GetObject());

c1 = buffer.GetPosition(100, buffer.Start);

Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment2, c1.GetObject());
}

[Fact]
public void TryGetSkipsEmptyForNextUsingGetPositionWithOffset()
{
var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[0]);
BufferSegment<byte> bufferSegment3 = bufferSegment2.Append(new byte[0]);
BufferSegment<byte> bufferSegment4 = bufferSegment3.Append(new byte[100]);

var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment4, 100);
SequencePosition c1 = buffer.GetPosition(0);
Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment1, c1.GetObject());

ReadOnlyMemory<byte> data;
Assert.True(buffer.TryGet(ref c1, out data, advance: true));

Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment4, c1.GetObject());

Assert.True(buffer.TryGet(ref c1, out data, advance: true));

Assert.Equal(0, c1.GetInteger());
Assert.Equal(null, c1.GetObject());

Assert.False(buffer.TryGet(ref c1, out data, advance: true));
}

[Fact]
public void TryGetSkipsEmptyForNext()
public void TryGetSkipsEmptyForNextUsingGetPositionWithOffsetAndOrigin()
{
var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[0]);
BufferSegment<byte> bufferSegment3 = bufferSegment2.Append(new byte[0]);
BufferSegment<byte> bufferSegment4 = bufferSegment3.Append(new byte[100]);

var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment4, 100);
SequencePosition c1 = buffer.GetPosition(buffer.Start, 0);
SequencePosition c1 = buffer.GetPosition(0, buffer.Start);
Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment1, c1.GetObject());

Expand All @@ -139,15 +200,37 @@ public void TryGetSkipsEmptyForNext()
}

[Fact]
public void TryGetSkipDoesNotCrossPastEnd()
public void TryGetSkipDoesNotCrossPastEndUsingGetPositionWithOffset()
{
var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[0]);
BufferSegment<byte> bufferSegment3 = bufferSegment2.Append(new byte[0]);
BufferSegment<byte> bufferSegment4 = bufferSegment3.Append(new byte[100]);

var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 0);
SequencePosition c1 = buffer.GetPosition(0);
Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment1, c1.GetObject());

ReadOnlyMemory<byte> data;
Assert.True(buffer.TryGet(ref c1, out data, advance: true));

Assert.Equal(0, c1.GetInteger());
Assert.Equal(null, c1.GetObject());

Assert.False(buffer.TryGet(ref c1, out data, advance: true));
}

[Fact]
public void TryGetSkipDoesNotCrossPastEndUsingGetPositionWithOffsetAndOrigin()
{
var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[0]);
BufferSegment<byte> bufferSegment3 = bufferSegment2.Append(new byte[0]);
BufferSegment<byte> bufferSegment4 = bufferSegment3.Append(new byte[100]);

var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 0);
SequencePosition c1 = buffer.GetPosition(buffer.Start, 0);
SequencePosition c1 = buffer.GetPosition(0, buffer.Start);
Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment1, c1.GetObject());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,22 +99,28 @@ public void ReadOnlyBufferDoesNotAllowSlicingOutOfRange(Action<ReadOnlySequence<
public void ReadOnlyBufferGetPosition_MovesPosition()
{
ReadOnlySequence<byte> buffer = Factory.CreateOfSize(100);
SequencePosition position = buffer.GetPosition(buffer.Start, 65);

SequencePosition position = buffer.GetPosition(65);
Assert.Equal(buffer.Slice(position).Length, 35);

position = buffer.GetPosition(65, buffer.Start);
Assert.Equal(buffer.Slice(position).Length, 35);
}

[Fact]
public void ReadOnlyBufferGetPosition_ChecksBounds()
{
ReadOnlySequence<byte> buffer = Factory.CreateOfSize(100);
Assert.Throws<ArgumentOutOfRangeException>(() => buffer.GetPosition(buffer.Start, 101));
Assert.Throws<ArgumentOutOfRangeException>(() => buffer.GetPosition(101));
Assert.Throws<ArgumentOutOfRangeException>(() => buffer.GetPosition(101, buffer.Start));
}

[Fact]
public void ReadOnlyBufferGetPosition_DoesNotAlowNegative()
{
ReadOnlySequence<byte> buffer = Factory.CreateOfSize(20);
Assert.Throws<ArgumentOutOfRangeException>(() => buffer.GetPosition(buffer.Start, -1));
Assert.Throws<ArgumentOutOfRangeException>(() => buffer.GetPosition(-1));
Assert.Throws<ArgumentOutOfRangeException>(() => buffer.GetPosition(-1, buffer.Start));
}

public void ReadOnlyBufferSlice_ChecksEnd()
Expand All @@ -134,11 +140,17 @@ public void SegmentStartIsConsideredInBoundsCheck()

var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 50);

SequencePosition c1 = buffer.GetPosition(buffer.Start, 25); // segment 1 index 75
SequencePosition c2 = buffer.GetPosition(buffer.Start, 55); // segment 2 index 5
SequencePosition c1 = buffer.GetPosition(25); // segment 1 index 75
SequencePosition c2 = buffer.GetPosition(55); // segment 2 index 5

ReadOnlySequence<byte> sliced = buffer.Slice(c1, c2);
Assert.Equal(30, sliced.Length);

c1 = buffer.GetPosition(25, buffer.Start); // segment 1 index 75
c2 = buffer.GetPosition(55, buffer.Start); // segment 2 index 5

sliced = buffer.Slice(c1, c2);
Assert.Equal(30, sliced.Length);
}

[Fact]
Expand All @@ -149,7 +161,12 @@ public void GetPositionPrefersNextSegment()

ReadOnlySequence<byte> buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 0);

SequencePosition c1 = buffer.GetPosition(buffer.Start, 50);
SequencePosition c1 = buffer.GetPosition(50);

Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment2, c1.GetObject());

c1 = buffer.GetPosition(50, buffer.Start);

Assert.Equal(0, c1.GetInteger());
Assert.Equal(bufferSegment2, c1.GetObject());
Expand All @@ -164,7 +181,12 @@ public void GetPositionDoesNotCrossOutsideBuffer()

var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 100);

SequencePosition c1 = buffer.GetPosition(buffer.Start, 200);
SequencePosition c1 = buffer.GetPosition(200);

Assert.Equal(100, c1.GetInteger());
Assert.Equal(bufferSegment2, c1.GetObject());

c1 = buffer.GetPosition(200, buffer.Start);

Assert.Equal(100, c1.GetInteger());
Assert.Equal(bufferSegment2, c1.GetObject());
Expand Down Expand Up @@ -265,14 +287,19 @@ public void CopyTo_ThrowsWhenSourceLargerThenDestination()
b => b.Slice(5),
b => b.Slice(0).Slice(5),
b => b.Slice(5, 5),
b => b.Slice(b.GetPosition(b.Start, 5), 5),
b => b.Slice(5, b.GetPosition(b.Start, 10)),
b => b.Slice(b.GetPosition(b.Start, 5), b.GetPosition(b.Start, 10)),
b => b.Slice(b.GetPosition(5), 5),
b => b.Slice(5, b.GetPosition(10)),
b => b.Slice(b.GetPosition(5), b.GetPosition(10)),
b => b.Slice(b.GetPosition(5, b.Start), 5),
b => b.Slice(5, b.GetPosition(10, b.Start)),
b => b.Slice(b.GetPosition(5, b.Start), b.GetPosition(10, b.Start)),

b => b.Slice((long)5),
b => b.Slice((long)5, 5),
b => b.Slice(b.GetPosition(b.Start, 5), (long)5),
b => b.Slice((long)5, b.GetPosition(b.Start, 10)),
b => b.Slice(b.GetPosition(5), (long)5),
b => b.Slice((long)5, b.GetPosition(10)),
b => b.Slice(b.GetPosition(5, b.Start), (long)5),
b => b.Slice((long)5, b.GetPosition(10, b.Start)),
};

public static TheoryData<Action<ReadOnlySequence<byte>>> OutOfRangeSliceCases => new TheoryData<Action<ReadOnlySequence<byte>>>
Expand Down
Loading

0 comments on commit 3bf27df

Please sign in to comment.