From fb2288b92a2b85554d9d0937fe12d48b2a62c07f Mon Sep 17 00:00:00 2001 From: Marco Rossignoli Date: Wed, 11 Dec 2019 20:11:32 +0100 Subject: [PATCH 01/12] add GetOffset(long) api --- .../System.Memory/ref/System.Memory.cs | 1 + .../src/System/Buffers/ReadOnlySequence.cs | 49 ++++++++++ .../System.Memory/src/System/ThrowHelper.cs | 2 +- .../ReadOnlySequenceTests.Common.cs | 92 +++++++++++++++++++ 4 files changed, 143 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Memory/ref/System.Memory.cs b/src/libraries/System.Memory/ref/System.Memory.cs index db2eeba8d2a72d..58ac9a782503d5 100644 --- a/src/libraries/System.Memory/ref/System.Memory.cs +++ b/src/libraries/System.Memory/ref/System.Memory.cs @@ -219,6 +219,7 @@ public readonly partial struct ReadOnlySequence public long Length { get { throw null; } } public System.SequencePosition Start { get { throw null; } } public System.Buffers.ReadOnlySequence.Enumerator GetEnumerator() { throw null; } + public long GetOffset(SequencePosition position) { 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 Slice(int start, int length) { throw null; } diff --git a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs index a427620fe6b4aa..4c4a73b01edb2e 100644 --- a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs +++ b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs @@ -528,6 +528,55 @@ public SequencePosition GetPosition(long offset) return Seek(offset); } + /// + /// Translate opaque value to numerical position offset + /// + /// + /// + public long GetOffset(SequencePosition position) + { + bool positionIsNotNull = position.GetObject() != null; + BoundsCheck(position, positionIsNotNull); + + object? startObject = _startObject; + object? endObject = _endObject; + + uint positionIndex = (uint)GetIndex(position); + object? positionSequenceObject = position.GetObject(); + + // if sequence object is null we suppose start segment + if (!positionIsNotNull) + { + positionSequenceObject = _startObject; + positionIndex = (uint)GetIndex(_startInteger); + } + + // Single-Segment Sequence + if (startObject == endObject) + { + return positionIndex; + } + else + { + // Multi-Segment Sequence + ReadOnlySequenceSegment currentSegment = (ReadOnlySequenceSegment)startObject!; + while (currentSegment != null && currentSegment != positionSequenceObject) + { + currentSegment = currentSegment.Next!; + } + + // Hit the end of the segments but didn't find the segment + if (currentSegment is null) + { + ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); + } + + Debug.Assert(currentSegment!.RunningIndex + positionIndex >= 0); + + return currentSegment!.RunningIndex + positionIndex; + } + } + /// /// Returns a new at an from the /// diff --git a/src/libraries/System.Memory/src/System/ThrowHelper.cs b/src/libraries/System.Memory/src/System/ThrowHelper.cs index 9c6c973a20fbc1..0c2f279ac9e526 100644 --- a/src/libraries/System.Memory/src/System/ThrowHelper.cs +++ b/src/libraries/System.Memory/src/System/ThrowHelper.cs @@ -121,6 +121,6 @@ internal enum ExceptionArgument culture, manager, count, - writer, + writer } } diff --git a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs index 427305b825b79b..f3606a2f792087 100644 --- a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs +++ b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs @@ -107,6 +107,98 @@ public void CheckEndReachableDoesNotCrossPastEnd() #endregion + #region Offset + + [Fact] + public void GetOffset_SingleSegment() + { + var buffer = new ReadOnlySequence(new T[50]); + Assert.Equal(25, buffer.GetOffset(buffer.GetPosition(25))); + } + + private (BufferSegment bufferSegment1, BufferSegment bufferSegment4) GetBufferSegment() + { + var bufferSegment1 = new BufferSegment(new T[50]); + BufferSegment bufferSegment2 = bufferSegment1.Append(new T[50]); + BufferSegment bufferSegment3 = bufferSegment2.Append(new T[0]); + return (bufferSegment1, bufferSegment3.Append(new T[50])); + } + + private ReadOnlySequence GetFourSegmentsReadOnlySequence() + { + (BufferSegment bufferSegment1, BufferSegment bufferSegment4) = GetBufferSegment(); + return new ReadOnlySequence(bufferSegment1, 0, bufferSegment4, 50); + } + + [Fact] + public void GetOffset_MultiSegment_FirstSegment() + { + ReadOnlySequence buffer = GetFourSegmentsReadOnlySequence(); + Assert.Equal(25, buffer.GetOffset(buffer.GetPosition(25))); + } + + [Fact] + public void GetOffset_MultiSegment_LastSegment() + { + ReadOnlySequence buffer = GetFourSegmentsReadOnlySequence(); + Assert.Equal(125, buffer.GetOffset(buffer.GetPosition(125))); + } + + [Fact] + public void GetOffset_MultiSegment_MiddleSegment() + { + ReadOnlySequence buffer = GetFourSegmentsReadOnlySequence(); + Assert.Equal(75, buffer.GetOffset(buffer.GetPosition(75))); + } + + [Fact] + public void GetOffset_SingleSegment_NullPositionObject() + { + var buffer = new ReadOnlySequence(new T[50]); + Assert.Equal(0, buffer.GetOffset(new SequencePosition(null, 25))); + } + + [Fact] + public void GetOffset_MultiSegment_NullPositionObject() + { + ReadOnlySequence buffer = GetFourSegmentsReadOnlySequence(); + Assert.Equal(0, buffer.GetOffset(new SequencePosition(null, 25))); + } + + [Fact] + public void GetOffset_SingleSegment_PositionOutOfRange() + { + var positionObject = new T[50]; + var buffer = new ReadOnlySequence(positionObject); + Assert.Throws("position", () => buffer.GetOffset(new SequencePosition(positionObject, 75))); + } + + [Fact] + public void GetOffset_MultiSegment_PositionOutOfRange() + { + (BufferSegment bufferSegment1, BufferSegment bufferSegment4) = GetBufferSegment(); + var buffer = new ReadOnlySequence(bufferSegment1, 0, bufferSegment4, 50); + Assert.Throws("position", () => buffer.GetOffset(new SequencePosition(bufferSegment4, 200))); + } + + [Fact] + public void GetOffset_MultiSegment_PositionOutOfRange_SegmentNotFound() + { + ReadOnlySequence buffer = GetFourSegmentsReadOnlySequence(); + ReadOnlySequence buffer2 = GetFourSegmentsReadOnlySequence(); + Assert.Throws("position", () => buffer.GetOffset(buffer2.GetPosition(25))); + } + + [Fact] + public void GetOffset_MultiSegment_InvalidSequencePositionSegment() + { + ReadOnlySequence buffer = GetFourSegmentsReadOnlySequence(); + ReadOnlySequence buffer2 = new ReadOnlySequence(new T[50]); + Assert.Throws(() => buffer.GetOffset(buffer2.GetPosition(25))); + } + + #endregion + #region First [Fact] From 2a2329ec58f52d9a58de48adee8dbdccb42b8f70 Mon Sep 17 00:00:00 2001 From: Marco Rossignoli Date: Wed, 11 Dec 2019 21:54:34 +0100 Subject: [PATCH 02/12] address PR feedback --- .../System.Memory/src/System/Buffers/ReadOnlySequence.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs index 4c4a73b01edb2e..862831437712c0 100644 --- a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs +++ b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs @@ -535,14 +535,14 @@ public SequencePosition GetPosition(long offset) /// public long GetOffset(SequencePosition position) { - bool positionIsNotNull = position.GetObject() != null; + object? positionSequenceObject; + bool positionIsNotNull = (positionSequenceObject = position.GetObject()) != null; BoundsCheck(position, positionIsNotNull); object? startObject = _startObject; object? endObject = _endObject; uint positionIndex = (uint)GetIndex(position); - object? positionSequenceObject = position.GetObject(); // if sequence object is null we suppose start segment if (!positionIsNotNull) From c5d0aae83d6da0b6af8b2a187db243f084a02330 Mon Sep 17 00:00:00 2001 From: Marco Rossignoli Date: Wed, 11 Dec 2019 22:15:42 +0100 Subject: [PATCH 03/12] simplify code --- .../System.Memory/src/System/Buffers/ReadOnlySequence.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs index 862831437712c0..1b0597ed0c0dab 100644 --- a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs +++ b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs @@ -535,8 +535,8 @@ public SequencePosition GetPosition(long offset) /// public long GetOffset(SequencePosition position) { - object? positionSequenceObject; - bool positionIsNotNull = (positionSequenceObject = position.GetObject()) != null; + object? positionSequenceObject = position.GetObject(); + bool positionIsNotNull = positionSequenceObject != null; BoundsCheck(position, positionIsNotNull); object? startObject = _startObject; From d89937b3f2036b61050bf2538d437a8773896893 Mon Sep 17 00:00:00 2001 From: Marco Rossignoli Date: Wed, 22 Jan 2020 11:31:55 +0100 Subject: [PATCH 04/12] update documentation --- .../System.Memory/src/System/Buffers/ReadOnlySequence.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs index 1b0597ed0c0dab..7d6ae5750b93d6 100644 --- a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs +++ b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs @@ -529,10 +529,11 @@ public SequencePosition GetPosition(long offset) } /// - /// Translate opaque value to numerical position offset + /// Translate opaque value to numerical position offset /// - /// - /// + /// to translate to offset + /// Returns the translated offset from the start of the sequence + /// Thrown when provided is invalid public long GetOffset(SequencePosition position) { object? positionSequenceObject = position.GetObject(); From e287d398fea29fee495b30704f7a05946836a2f9 Mon Sep 17 00:00:00 2001 From: Marco Rossignoli Date: Thu, 23 Jan 2020 10:58:56 +0100 Subject: [PATCH 05/12] Apply suggestions from code review Co-Authored-By: Ahson Khan --- .../System.Memory/src/System/Buffers/ReadOnlySequence.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs index 7d6ae5750b93d6..5842791a995546 100644 --- a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs +++ b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs @@ -531,8 +531,8 @@ public SequencePosition GetPosition(long offset) /// /// Translate opaque value to numerical position offset /// - /// to translate to offset - /// Returns the translated offset from the start of the sequence + /// The of which to get the offset. + /// The offset from the start of the sequence. /// Thrown when provided is invalid public long GetOffset(SequencePosition position) { From 67f0d432168b2d572bdb01dd877a844c1716f464 Mon Sep 17 00:00:00 2001 From: Marco Rossignoli Date: Fri, 7 Feb 2020 14:56:03 +0100 Subject: [PATCH 06/12] revert change, annotate null ref --- .../System.Memory/src/System/Buffers/ReadOnlySequence.cs | 2 +- src/libraries/System.Memory/src/System/ThrowHelper.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs index 5842791a995546..c51364b96285d8 100644 --- a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs +++ b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs @@ -560,7 +560,7 @@ public long GetOffset(SequencePosition position) else { // Multi-Segment Sequence - ReadOnlySequenceSegment currentSegment = (ReadOnlySequenceSegment)startObject!; + ReadOnlySequenceSegment? currentSegment = (ReadOnlySequenceSegment?)startObject; while (currentSegment != null && currentSegment != positionSequenceObject) { currentSegment = currentSegment.Next!; diff --git a/src/libraries/System.Memory/src/System/ThrowHelper.cs b/src/libraries/System.Memory/src/System/ThrowHelper.cs index 0c2f279ac9e526..9c6c973a20fbc1 100644 --- a/src/libraries/System.Memory/src/System/ThrowHelper.cs +++ b/src/libraries/System.Memory/src/System/ThrowHelper.cs @@ -121,6 +121,6 @@ internal enum ExceptionArgument culture, manager, count, - writer + writer, } } From b449ed0ecf4ed187626696d899bede50e1564846 Mon Sep 17 00:00:00 2001 From: Marco Rossignoli Date: Fri, 7 Feb 2020 16:28:25 +0100 Subject: [PATCH 07/12] add check for invalid passed SequencePosition, add tests for boundary condition. --- .../src/System/Buffers/ReadOnlySequence.cs | 15 ++++-- .../ReadOnlySequenceTests.Common.cs | 52 +++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs index c51364b96285d8..11696e288db14d 100644 --- a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs +++ b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs @@ -537,8 +537,8 @@ public SequencePosition GetPosition(long offset) public long GetOffset(SequencePosition position) { object? positionSequenceObject = position.GetObject(); - bool positionIsNotNull = positionSequenceObject != null; - BoundsCheck(position, positionIsNotNull); + bool positionIsNull = positionSequenceObject == null; + BoundsCheck(position, !positionIsNull); object? startObject = _startObject; object? endObject = _endObject; @@ -546,11 +546,20 @@ public long GetOffset(SequencePosition position) uint positionIndex = (uint)GetIndex(position); // if sequence object is null we suppose start segment - if (!positionIsNotNull) + if (positionIsNull) { positionSequenceObject = _startObject; positionIndex = (uint)GetIndex(_startInteger); } + else + { + // Verify position validity + Debug.Assert(positionSequenceObject != null); + + if (((ReadOnlySequenceSegment)positionSequenceObject).Memory.Length - positionIndex < 0) + ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); + } + // Single-Segment Sequence if (startObject == endObject) diff --git a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs index f3606a2f792087..1ebf53e4311cee 100644 --- a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs +++ b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs @@ -118,6 +118,7 @@ public void GetOffset_SingleSegment() private (BufferSegment bufferSegment1, BufferSegment bufferSegment4) GetBufferSegment() { + // [50] -> [50] -> [0] -> [50] var bufferSegment1 = new BufferSegment(new T[50]); BufferSegment bufferSegment2 = bufferSegment1.Append(new T[50]); BufferSegment bufferSegment3 = bufferSegment2.Append(new T[0]); @@ -165,6 +166,31 @@ public void GetOffset_MultiSegment_NullPositionObject() Assert.Equal(0, buffer.GetOffset(new SequencePosition(null, 25))); } + [Fact] + public void GetOffset_MultiSegment_BoundaryConditions() + { + // [50] -> [50] -> [0] -> [50] + var bufferSegment1 = new BufferSegment(new T[50]); + BufferSegment bufferSegment2 = bufferSegment1.Append(new T[50]); + BufferSegment bufferSegment3 = bufferSegment2.Append(new T[0]); + BufferSegment bufferSegment4 = bufferSegment3.Append(new T[50]); + var sequence = new ReadOnlySequence(bufferSegment1, 0, bufferSegment4, 50); + + + // Non empty adjacent segment + Assert.Equal(50, sequence.GetOffset(new SequencePosition(bufferSegment1, 50))); + Assert.Equal(50, sequence.GetOffset(new SequencePosition(bufferSegment2, 0))); + Assert.Equal(51, sequence.GetOffset(new SequencePosition(bufferSegment2, 1))); + + // Empty adjacent segment + Assert.Equal(100, sequence.GetOffset(new SequencePosition(bufferSegment2, 50))); + Assert.Equal(100, sequence.GetOffset(new SequencePosition(bufferSegment3, 0))); + Assert.Equal(101, sequence.GetOffset(new SequencePosition(bufferSegment4, 1))); + + // Cannot get 101 starting from empty adjacent segment + Assert.Throws(() => sequence.GetOffset(new SequencePosition(bufferSegment3, 1))); + } + [Fact] public void GetOffset_SingleSegment_PositionOutOfRange() { @@ -197,6 +223,32 @@ public void GetOffset_MultiSegment_InvalidSequencePositionSegment() Assert.Throws(() => buffer.GetOffset(buffer2.GetPosition(25))); } + [Fact] + public void GetOffset_MultiSegment_SequencePositionSegment() + { + // [0] -> [0] -> [0] -> [50] + var bufferSegment1 = new BufferSegment(new T[0]); + BufferSegment bufferSegment2 = bufferSegment1.Append(new T[0]); + BufferSegment bufferSegment3 = bufferSegment2.Append(new T[0]); + BufferSegment bufferSegment4 = bufferSegment3.Append(new T[50]); + + var sequence = new ReadOnlySequence(bufferSegment1, 0, bufferSegment4, 50); + + Assert.Equal(0, sequence.GetOffset(new SequencePosition(bufferSegment1, 0))); + Assert.Equal(0, sequence.GetOffset(new SequencePosition(bufferSegment2, 0))); + Assert.Equal(0, sequence.GetOffset(new SequencePosition(bufferSegment3, 0))); + Assert.Equal(0, sequence.GetOffset(new SequencePosition(bufferSegment4, 0))); + + // Invalid positions + Assert.Throws(() => sequence.GetOffset(new SequencePosition(bufferSegment1, 1))); + Assert.Throws(() => sequence.GetOffset(new SequencePosition(bufferSegment2, 1))); + Assert.Throws(() => sequence.GetOffset(new SequencePosition(bufferSegment3, 1))); + + for (int i = 0; i <= bufferSegment4.Memory.Length; i++) + { + Assert.Equal(i, sequence.GetOffset(new SequencePosition(bufferSegment4, i))); + } + } #endregion #region First From 22cdb592aaf17f6015cd57f916ff224090ebdad6 Mon Sep 17 00:00:00 2001 From: Marco Rossignoli Date: Fri, 7 Feb 2020 17:08:40 +0100 Subject: [PATCH 08/12] add enumerate and slice tests. --- .../src/System/Buffers/ReadOnlySequence.cs | 17 +++---- .../ReadOnlySequenceTests.Common.cs | 51 +++++++++++++++++++ 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs index 11696e288db14d..35b76b322e234a 100644 --- a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs +++ b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs @@ -551,15 +551,6 @@ public long GetOffset(SequencePosition position) positionSequenceObject = _startObject; positionIndex = (uint)GetIndex(_startInteger); } - else - { - // Verify position validity - Debug.Assert(positionSequenceObject != null); - - if (((ReadOnlySequenceSegment)positionSequenceObject).Memory.Length - positionIndex < 0) - ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); - } - // Single-Segment Sequence if (startObject == endObject) @@ -568,6 +559,14 @@ public long GetOffset(SequencePosition position) } else { + // Verify position validity, this is not covered by BoundsCheck for Multi-Segment Sequence + // BoundsCheck for Multi-Segment Sequence check only validity inside current sequence but not for SequencePosition validity. + // For single segment position bound check is implicit. + Debug.Assert(positionSequenceObject != null); + + if (((ReadOnlySequenceSegment)positionSequenceObject).Memory.Length - positionIndex < 0) + ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); + // Multi-Segment Sequence ReadOnlySequenceSegment? currentSegment = (ReadOnlySequenceSegment?)startObject; while (currentSegment != null && currentSegment != positionSequenceObject) diff --git a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs index 1ebf53e4311cee..7f6596f49fd6e4 100644 --- a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs +++ b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs @@ -191,6 +191,46 @@ public void GetOffset_MultiSegment_BoundaryConditions() Assert.Throws(() => sequence.GetOffset(new SequencePosition(bufferSegment3, 1))); } + [Fact] + public void GetOffset_MultiSegment_Enumerate() + { + ReadOnlySequence buffer = GetFourSegmentsReadOnlySequence(); + for (int i = 0; i <= buffer.Length; i++) + { + Assert.Equal(i, buffer.GetOffset(buffer.GetPosition(i))); + } + } + + [Fact] + public void GetOffset_SingleSegment_Enumerate() + { + ReadOnlySequence buffer = new ReadOnlySequence(new T[50]); + for (int i = 0; i <= buffer.Length; i++) + { + Assert.Equal(i, buffer.GetOffset(buffer.GetPosition(i))); + } + } + + [Fact] + public void GetOffset_MultiSegment_Slice() + { + ReadOnlySequence buffer = GetFourSegmentsReadOnlySequence(); + for (int i = 0; i <= buffer.Length; i++) + { + Assert.Equal(buffer.Slice(0, i).Length, buffer.GetOffset(buffer.GetPosition(i))); + } + } + + [Fact] + public void GetOffset_SingleSegment_Slice() + { + ReadOnlySequence buffer = new ReadOnlySequence(new T[50]); + for (int i = 0; i <= buffer.Length; i++) + { + Assert.Equal(buffer.Slice(0, i).Length, buffer.GetOffset(buffer.GetPosition(i))); + } + } + [Fact] public void GetOffset_SingleSegment_PositionOutOfRange() { @@ -223,6 +263,17 @@ public void GetOffset_MultiSegment_InvalidSequencePositionSegment() Assert.Throws(() => buffer.GetOffset(buffer2.GetPosition(25))); } + [Fact] + public void GetOffset_SingleSegment_SequencePositionSegment() + { + var data = new T[0]; + var sequence = new ReadOnlySequence(data); + Assert.Equal(0, sequence.GetOffset(new SequencePosition(data, 0))); + + // Invalid positions + Assert.Throws(() => sequence.GetOffset(new SequencePosition(data, 1))); + } + [Fact] public void GetOffset_MultiSegment_SequencePositionSegment() { From 6e19c26c1554bda39388017e3302cd79f2e17b63 Mon Sep 17 00:00:00 2001 From: Marco Rossignoli Date: Sat, 8 Feb 2020 09:23:02 +0100 Subject: [PATCH 09/12] Fix method documentation --- .../System.Memory/src/System/Buffers/ReadOnlySequence.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs index 35b76b322e234a..48d6211029dec8 100644 --- a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs +++ b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs @@ -529,11 +529,11 @@ public SequencePosition GetPosition(long offset) } /// - /// Translate opaque value to numerical position offset + /// Returns the offset of a within this sequence from the start. /// /// The of which to get the offset. /// The offset from the start of the sequence. - /// Thrown when provided is invalid + /// The provided is invalid public long GetOffset(SequencePosition position) { object? positionSequenceObject = position.GetObject(); From 658b9e652c0b8b6bcfad8e866f6413c7e4350a28 Mon Sep 17 00:00:00 2001 From: Marco Rossignoli Date: Wed, 12 Feb 2020 13:04:25 +0100 Subject: [PATCH 10/12] address PR feedback --- src/libraries/System.Memory/ref/System.Memory.cs | 10 +++------- .../src/System/Buffers/ReadOnlySequence.cs | 2 +- .../ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs | 1 - 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Memory/ref/System.Memory.cs b/src/libraries/System.Memory/ref/System.Memory.cs index 58ac9a782503d5..b2db8453b15141 100644 --- a/src/libraries/System.Memory/ref/System.Memory.cs +++ b/src/libraries/System.Memory/ref/System.Memory.cs @@ -86,11 +86,11 @@ public static void Reverse(this System.Span span) { } public static bool SequenceEqual(this System.ReadOnlySpan span, System.ReadOnlySpan other) where T : System.IEquatable { throw null; } public static bool SequenceEqual(this System.Span span, System.ReadOnlySpan other) where T : System.IEquatable { throw null; } public static void Sort(this System.Span span) { } - public static void Sort(this System.Span span, TComparer comparer) where TComparer : System.Collections.Generic.IComparer? { } public static void Sort(this System.Span span, System.Comparison comparison) { } public static void Sort(this System.Span keys, System.Span items) { } - public static void Sort(this System.Span keys, System.Span items, TComparer comparer) where TComparer : System.Collections.Generic.IComparer? { } public static void Sort(this System.Span keys, System.Span items, System.Comparison comparison) { } + public static void Sort(this System.Span span, TComparer comparer) where TComparer : System.Collections.Generic.IComparer? { } + public static void Sort(this System.Span keys, System.Span items, TComparer comparer) where TComparer : System.Collections.Generic.IComparer? { } public static bool StartsWith(this System.ReadOnlySpan span, System.ReadOnlySpan value, System.StringComparison comparisonType) { throw null; } public static bool StartsWith(this System.ReadOnlySpan span, System.ReadOnlySpan value) where T : System.IEquatable { throw null; } public static bool StartsWith(this System.Span span, System.ReadOnlySpan value) where T : System.IEquatable { throw null; } @@ -146,14 +146,10 @@ public static void Sort(this System.Span keys, System.Span public long Length { get { throw null; } } public System.SequencePosition Start { get { throw null; } } public System.Buffers.ReadOnlySequence.Enumerator GetEnumerator() { throw null; } - public long GetOffset(SequencePosition position) { throw null; } + public long GetOffset(System.SequencePosition position) { 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 Slice(int start, int length) { throw null; } diff --git a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs index 48d6211029dec8..a7cc154de987ca 100644 --- a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs +++ b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs @@ -533,7 +533,7 @@ public SequencePosition GetPosition(long offset) /// /// The of which to get the offset. /// The offset from the start of the sequence. - /// The provided is invalid + /// The provided is invalid. public long GetOffset(SequencePosition position) { object? positionSequenceObject = position.GetObject(); diff --git a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs index 7f6596f49fd6e4..6a5c86a75c4344 100644 --- a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs +++ b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs @@ -176,7 +176,6 @@ public void GetOffset_MultiSegment_BoundaryConditions() BufferSegment bufferSegment4 = bufferSegment3.Append(new T[50]); var sequence = new ReadOnlySequence(bufferSegment1, 0, bufferSegment4, 50); - // Non empty adjacent segment Assert.Equal(50, sequence.GetOffset(new SequencePosition(bufferSegment1, 50))); Assert.Equal(50, sequence.GetOffset(new SequencePosition(bufferSegment2, 0))); From a68dbb24112c98919d0bf85c4b196b9339894119 Mon Sep 17 00:00:00 2001 From: Marco Rossignoli Date: Wed, 12 Feb 2020 13:07:15 +0100 Subject: [PATCH 11/12] fix codege --- src/libraries/System.Memory/ref/System.Memory.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libraries/System.Memory/ref/System.Memory.cs b/src/libraries/System.Memory/ref/System.Memory.cs index b2db8453b15141..4c1faebc3145b8 100644 --- a/src/libraries/System.Memory/ref/System.Memory.cs +++ b/src/libraries/System.Memory/ref/System.Memory.cs @@ -146,10 +146,14 @@ public static void Sort(this System.Span keys, Sy private readonly object _dummy; private readonly int _dummyPrimitive; public SequencePosition(object? @object, int integer) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public override bool Equals(object? obj) { throw null; } public bool Equals(System.SequencePosition other) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public override int GetHashCode() { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public int GetInteger() { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public object? GetObject() { throw null; } } } From 00241b1f5df5e646d087198ce49c50e64ea80ba3 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Mon, 17 Aug 2020 10:09:35 +0200 Subject: [PATCH 12/12] improve xml comment Co-authored-by: Carlos Sanchez <1175054+carlossanlop@users.noreply.github.com> --- .../System.Memory/src/System/Buffers/ReadOnlySequence.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs index a7cc154de987ca..54f8f44f07b16d 100644 --- a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs +++ b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs @@ -533,7 +533,7 @@ public SequencePosition GetPosition(long offset) /// /// The of which to get the offset. /// The offset from the start of the sequence. - /// The provided is invalid. + /// The position is out of range. public long GetOffset(SequencePosition position) { object? positionSequenceObject = position.GetObject();