-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Description
Current Behaviour
The current behaviour of ReadOnlySequence<T>.GetPosition() is demonstrated in the following code:
ReadOnlySequence<byte> sequence = new ReadOnlySequence<byte>(new byte[size]);
object firstObject = sequence.Start.GetObject();
// End returns a sequence with index int.MinValue, and object is set to last segment
Console.WriteLine(ReferenceEquals(sequence.End.GetObject(), firstObject).ToString()); // True
Console.WriteLine(sequence.End.GetInteger().ToString()); // -2147483647
// GetPosition(0) returns a sequence with index 0, and object is set to first segment
SequencePosition zeroPosition = sequence.GetPosition(0); // True
Console.WriteLine(ReferenceEquals(zeroPosition.GetObject(), firstObject).ToString()); // 0
Console.WriteLine(zeroPosition.GetInteger().ToString()); // True
// GetPosition(0) returns a sequence that equals sequence.Start
Console.WriteLine(zeroPosition.Equals(sequence.Start).ToString()); // True
// GetPosition(size) returns a sequence with last object and index = size ?
SequencePosition sizePosition = sequence.GetPosition(size);
Console.WriteLine(ReferenceEquals(sizePosition.GetObject(), firstObject).ToString()); // True
Console.WriteLine(sizePosition.GetInteger().ToString()); // size
// GetPosition(size) does not match sequence.End
Console.WriteLine(sizePosition.Equals(sequence.End).ToString()); // False
// Asking for size + 1 correctly detects OOB, throwing ArgumentOutOfRangeException
Sequence sizePlusOnePosition = sequence.GetPosition(size + 1);Summary
The following behaviour is intuitive:
ReadOnlySequence<T>.Endappears to point after the end of the sequence (index = index.MaxValue, object is last segment).ReadOnlySequence<T>.Startpoints to first segment, index 0ReadOnlySequence<T>.GetPosition(0)is identical toSequence.StartReadOnlySequence<T>.GetPosition(-1)throws anArgumentOutOfRangeExceptionReadOnlySequence<T>.GetPosition(<size> + 1)throws anArgumentOutOfRangeException
However, ReadOnlySequence<T>.GetPosition(<size>) does not appear intuitive to me, unless I'm missing something? Although SequencePosition.GetObject() returns the last segment, SequencePosition.GetIndex() seems to indicate an index beyond the sequence and does not match ReadOnlySequence<T>.End. In the absence of any other indicator there is no obvious way to see this SequencePosition is outside the bounds of the sequence. In constrast, asking for -1 and size+1 throw exceptions indicating that the parameter is bounded.
Expected Behaviour
I would expect one of the following to occur (in order of preference):
ReadOnlySequence<T>.GetPosition(<size>)throws anArgumentOutOfRangeExceptionas it is beyond the bounds of the sequence - this makes it act more like an array accessor and is more like the rest of the framework. [Preferred]ReadOnlySequence<T>.GetPosition(<size>)returns aSequencePositionequal toReadOnlySequence<T>.End, indicating it's immediately beyond the end of the sequence.ReadOnlySequence<T>.GetPosition(<size>)returnsdefault(SequencePosition), to indicate out of bounds of the array - this is non-intuitive as it implies -1 andsize+ 1 should also return this value.
On a related note, it would be nice if ReadOnlySequence<T>.GetPosition(offset, origin) supported negative offsets. I understand this may have an impact on pipes, but on many sequences it would be an entirely valid concept.