Skip to content

ReadOnlySequence.Slice which accepts a SequencePosition throws ArgumentOutOfRangeException unexpectedly. #27834

@ahsonkhan

Description

@ahsonkhan

The behavior of Slice(offset, SequencePosition) should match GetPosition(offset) and Slice(offset).
I should be able to slice a ReadOnlySequence past the current sequence if the next one is empty (for example: [97] -> []).

[Fact]
public static void ReadOnlySequenceTest()
{
    string jsonString = "a";

    ReadOnlyMemory<byte> dataMemory = Encoding.UTF8.GetBytes(jsonString);

    var firstSegment = new BufferSegment<byte>(dataMemory.Slice(0, 1));
    ReadOnlyMemory<byte> secondMem = dataMemory.Slice(0, 0);
    BufferSegment<byte> secondSegment = firstSegment.Append(secondMem);

    // A two segment sequence where the second one is empty: [a]-> []
    var sequence = new ReadOnlySequence<byte>(firstSegment, 0, secondSegment, secondMem.Length);

    SequencePosition expectedPosition = sequence.GetPosition(1);
    Console.WriteLine(expectedPosition.GetInteger());   // 0
    Console.WriteLine(expectedPosition.GetObject());    // System.Text.Json.Tests.BufferSegment`1[System.Byte]
    Assert.True(((ReadOnlySequenceSegment<byte>)expectedPosition.GetObject()).Memory.IsEmpty);

    SequencePosition actualPosition = sequence.Slice(1).Start;
    Console.WriteLine(actualPosition.GetInteger()); // 0
    Console.WriteLine(actualPosition.GetObject());  // System.Text.Json.Tests.BufferSegment`1[System.Byte]
    Assert.True(((ReadOnlySequenceSegment<byte>)actualPosition.GetObject()).Memory.IsEmpty);
    Assert.Equal(expectedPosition, actualPosition); // True

    SequencePosition actualPosition2 = sequence.GetPosition(1, sequence.Start);
    Console.WriteLine(actualPosition2.GetInteger());   // 0
    Console.WriteLine(actualPosition2.GetObject());    // System.Text.Json.Tests.BufferSegment`1[System.Byte]
    Assert.True(((ReadOnlySequenceSegment<byte>)actualPosition2.GetObject()).Memory.IsEmpty);

    // System.ArgumentOutOfRangeException : Specified argument was out of the range of valid values.

    /*
        System.ArgumentOutOfRangeException : Specified argument was out of the range of valid values.
        Parameter name: start
        Stack Trace:
        E:\GitHub\Fork\corefx\src\System.Memory\src\System\ThrowHelper.cs(31,0): at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument)
        E:\GitHub\Fork\corefx\src\System.Memory\src\System\Buffers\ReadOnlySequence.cs(281,0): at System.Buffers.ReadOnlySequence`1.Slice(Int64 start, SequencePosition end)
        E:\GitHub\Fork\corefx\src\System.Memory\src\System\Buffers\ReadOnlySequence.cs(388,0): at System.Buffers.ReadOnlySequence`1.Slice(Int32 start, SequencePosition end)
        E:\GitHub\Fork\corefx\src\System.Text.Json\tests\Utf8JsonReaderTests.TryGet.cs(357,0): at System.Text.Json.Tests.Utf8JsonReaderTests.ReadOnlySequenceTest()
    */
    sequence = sequence.Slice(1, sequence.Start);
}

We need to use the Slice overload that takes a SequencePosition for performance to avoid having to scan the segments from the beginning every time. Using GetPosition with long is too slow:
https://github.com/dotnet/corefxlab/blob/63ef1a5db4fdbfcf9822b8cd2cbc3921b3d3cb9e/src/System.Text.JsonLab/System/Text/Json/JsonUtf8Reader.cs#L112

cc @pakrym, @davidfowl

Metadata

Metadata

Labels

area-System.Memorybughelp wanted[up-for-grabs] Good issue for external contributorsin-prThere is an active PR which will close this issue when it is merged

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions