From 724b3ce15ab9beb8d56b838369c838469c8be3ca Mon Sep 17 00:00:00 2001 From: Krzysztof Cwalina Date: Tue, 9 Jan 2018 15:41:01 -0800 Subject: [PATCH] Removed operator+ from Position (#2041) * Added ISequence.Seek * Remove Position.GetItem and Position_op+ --- .../System/Buffers/Sequences/ReadOnlyBytes.cs | 40 +++++++++++++++++++ .../Buffers/Sequences/ReadWriteBytes.cs | 22 ++++++++++ .../Buffers/Sequences/SequenceExtensions.cs | 4 +- .../System/Buffers/ReadOnlyBuffer.cs | 8 ++-- .../System/Buffers/ReadOnlyBufferReader.cs | 2 +- .../System/Buffers/ReadOnlyBuffer_helpers.cs | 5 ++- .../System/Collections/ISequence.cs | 2 + .../System/Collections/Position.cs | 18 --------- .../System/Collections/Sequences/ArrayList.cs | 7 ++++ .../Collections/Sequences/ResizableArray.cs | 2 +- .../ReadableBufferSequence.cs | 17 +++----- .../System/IO/Pipelines/Pipe.cs | 2 +- .../SampleCollections/Hashtable.cs | 8 ++++ .../SampleCollections/LinkedContainer.cs | 18 +++++++++ 14 files changed, 114 insertions(+), 41 deletions(-) diff --git a/src/System.Buffers.Experimental/System/Buffers/Sequences/ReadOnlyBytes.cs b/src/System.Buffers.Experimental/System/Buffers/Sequences/ReadOnlyBytes.cs index 25df3547fd4..9df0294d736 100644 --- a/src/System.Buffers.Experimental/System/Buffers/Sequences/ReadOnlyBytes.cs +++ b/src/System.Buffers.Experimental/System/Buffers/Sequences/ReadOnlyBytes.cs @@ -324,6 +324,46 @@ public bool TryGet(ref Position position, out ReadOnlyMemory item, bool ad throw new NotImplementedException(); } + public Position Seek(Position origin, long offset) + { + if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset)); + + switch (Kind) + { + case Type.Array: + { + var (array, index) = origin.Get(); + if (index + offset > array.Length) throw new ArgumentOutOfRangeException(nameof(offset)); + return new Position(array, (int)(index + offset)); + } + case Type.OwnedMemory: + { + var (om, index) = origin.Get>(); + if (index + offset > om.Length) throw new ArgumentOutOfRangeException(nameof(offset)); + return new Position(om, (int)(index + offset)); + } + case Type.MemoryList: + var previous = origin; + while (TryGet(ref origin, out var memory)) + { + var length = memory.Length; + if (length < offset) + { + offset -= length; + previous = origin; + } + else + { + var (segment, index) = previous.Get(); + return new Position(segment, (int)(index + offset)); + } + } + throw new ArgumentOutOfRangeException(nameof(offset)); + default: + throw new NotSupportedException(); + } + } + enum Type : byte { Array, diff --git a/src/System.Buffers.Experimental/System/Buffers/Sequences/ReadWriteBytes.cs b/src/System.Buffers.Experimental/System/Buffers/Sequences/ReadWriteBytes.cs index 03a67de62f8..a14105268ec 100644 --- a/src/System.Buffers.Experimental/System/Buffers/Sequences/ReadWriteBytes.cs +++ b/src/System.Buffers.Experimental/System/Buffers/Sequences/ReadWriteBytes.cs @@ -304,6 +304,28 @@ public bool TryGet(ref Position position, out Memory item, bool advance = throw new NotImplementedException(); } + public Position Seek(Position origin, long offset) + { + if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset)); + + var previous = origin; + while(TryGet(ref origin, out var memory)) + { + var length = memory.Length; + if(length < offset) + { + offset -= length; + previous = origin; + } + else + { + var (segment, index) = origin.Get(); + return new Position(segment, (int)(index + offset)); + } + } + throw new ArgumentOutOfRangeException(nameof(offset)); + } + enum Type : byte { Array, diff --git a/src/System.Buffers.Experimental/System/Buffers/Sequences/SequenceExtensions.cs b/src/System.Buffers.Experimental/System/Buffers/Sequences/SequenceExtensions.cs index e3b492087d9..491fb9317d4 100644 --- a/src/System.Buffers.Experimental/System/Buffers/Sequences/SequenceExtensions.cs +++ b/src/System.Buffers.Experimental/System/Buffers/Sequences/SequenceExtensions.cs @@ -79,7 +79,7 @@ public static long IndexOf(TSequence sequence, byte v1, byte v2) wher var index = MemoryExtensions.IndexOf(memory.Span, value); if (index != -1) { - result += index; + result = sequence.Seek(result, index); return result; } result = position; @@ -98,7 +98,7 @@ public static long IndexOf(TSequence sequence, byte v1, byte v2) wher var span = memory.Span; if(span.Length > index) { - result += (int)index; + result = sequence.Seek(result, index); return result; } index -= span.Length; diff --git a/src/System.Buffers.Primitives/System/Buffers/ReadOnlyBuffer.cs b/src/System.Buffers.Primitives/System/Buffers/ReadOnlyBuffer.cs index dafe9c05f00..661d901288e 100644 --- a/src/System.Buffers.Primitives/System/Buffers/ReadOnlyBuffer.cs +++ b/src/System.Buffers.Primitives/System/Buffers/ReadOnlyBuffer.cs @@ -269,13 +269,13 @@ public Enumerator GetEnumerator() return new Enumerator(this); } - public Position Seek(Position position, long count) + public Position Seek(Position origin, long offset) { - if (count < 0) + if (offset < 0) { - throw new ArgumentOutOfRangeException(nameof(count)); + throw new ArgumentOutOfRangeException(nameof(offset)); } - return Seek(position, BufferEnd, count, false); + return Seek(origin, BufferEnd, offset, false); } public bool TryGet(ref Position cursor, out ReadOnlyMemory data, bool advance = true) diff --git a/src/System.Buffers.Primitives/System/Buffers/ReadOnlyBufferReader.cs b/src/System.Buffers.Primitives/System/Buffers/ReadOnlyBufferReader.cs index 6eb27cd5b39..14733536db3 100644 --- a/src/System.Buffers.Primitives/System/Buffers/ReadOnlyBufferReader.cs +++ b/src/System.Buffers.Primitives/System/Buffers/ReadOnlyBufferReader.cs @@ -46,7 +46,7 @@ public BufferReader(TSequence buffer) public int Index => _index; - public Position Position => _currentPosition + _index; + public Position Position => _sequence.Seek(_currentPosition, _index); public ReadOnlySpan CurrentSegment => _currentSpan; diff --git a/src/System.Buffers.Primitives/System/Buffers/ReadOnlyBuffer_helpers.cs b/src/System.Buffers.Primitives/System/Buffers/ReadOnlyBuffer_helpers.cs index 8e8baf8df92..3d35596f62d 100644 --- a/src/System.Buffers.Primitives/System/Buffers/ReadOnlyBuffer_helpers.cs +++ b/src/System.Buffers.Primitives/System/Buffers/ReadOnlyBuffer_helpers.cs @@ -149,7 +149,7 @@ private static long GetLength(Position begin, Position end) switch (segment) { case IBufferList bufferSegment: - return GetLength(bufferSegment, begin.Index, end.GetSegment(), end.Index); + return GetLength(bufferSegment, begin.Index, (IBufferList)end.Segment, end.Index); case byte[] _: case OwnedMemory _: return end.Index - begin.Index; @@ -189,7 +189,8 @@ private static void BoundsCheck(Position end, Position newCursor) } return; case IBufferList memoryList: - if(newCursor.GetSegment().VirtualIndex - end.Index > memoryList.VirtualIndex - newCursor.Index) + var segment = (IBufferList)newCursor.Segment; + if(segment.VirtualIndex - end.Index > memoryList.VirtualIndex - newCursor.Index) { ThrowHelper.ThrowCursorOutOfBoundsException(); } diff --git a/src/System.Buffers.Primitives/System/Collections/ISequence.cs b/src/System.Buffers.Primitives/System/Collections/ISequence.cs index bffaa90b46b..f9ee7b962b5 100644 --- a/src/System.Buffers.Primitives/System/Collections/ISequence.cs +++ b/src/System.Buffers.Primitives/System/Collections/ISequence.cs @@ -15,6 +15,8 @@ public interface ISequence /// bool TryGet(ref Position position, out T item, bool advance = true); + Position Seek(Position origin, long offset); + Position Start { get; } } } diff --git a/src/System.Buffers.Primitives/System/Collections/Position.cs b/src/System.Buffers.Primitives/System/Collections/Position.cs index c8f58414891..c98ba36062b 100644 --- a/src/System.Buffers.Primitives/System/Collections/Position.cs +++ b/src/System.Buffers.Primitives/System/Collections/Position.cs @@ -37,27 +37,9 @@ public Position(object segment) return (segment, _index); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public T GetSegment() - { - switch (Segment) - { - case null: - return default; - case T segment: - return segment; - } - - ThrowHelper.ThrowInvalidOperationException(ExceptionResource.UnexpectedSegmentType); - return default; - } - public static bool operator ==(Position left, Position right) => left._index == right._index && left._segment == right._segment; public static bool operator !=(Position left, Position right) => left._index != right._index || left._segment != right._segment; - public static Position operator +(Position value, int index) - => new Position(value._segment, value._index + index); - [EditorBrowsable(EditorBrowsableState.Never)] public bool Equals(Position position) => this == position; diff --git a/src/System.Collections.Sequences/System/Collections/Sequences/ArrayList.cs b/src/System.Collections.Sequences/System/Collections/Sequences/ArrayList.cs index c079436b519..8c291085f74 100644 --- a/src/System.Collections.Sequences/System/Collections/Sequences/ArrayList.cs +++ b/src/System.Collections.Sequences/System/Collections/Sequences/ArrayList.cs @@ -25,5 +25,12 @@ public sealed class ArrayList : ISequence public bool TryGet(ref Position position, out T item, bool advance = true) => _items.TryGet(ref position, out item, advance); + + public Position Seek(Position origin, long offset) + { + long index = (int)origin + offset; + if (index < 0 || index >= Length) throw new ArgumentOutOfRangeException(nameof(offset)); + return new Position(null, (int)index); + } } } diff --git a/src/System.Collections.Sequences/System/Collections/Sequences/ResizableArray.cs b/src/System.Collections.Sequences/System/Collections/Sequences/ResizableArray.cs index 0f07f4668e0..5330ea6c115 100644 --- a/src/System.Collections.Sequences/System/Collections/Sequences/ResizableArray.cs +++ b/src/System.Collections.Sequences/System/Collections/Sequences/ResizableArray.cs @@ -111,7 +111,7 @@ public bool TryGet(ref Position position, out T item, bool advance = true) int index = (int)position; if (index < _count) { item = _array[index]; - if (advance) { position +=1; } + if (advance) { position = new Position(null, index+1); } return true; } diff --git a/src/System.IO.Pipelines.Extensions/ReadableBufferSequence.cs b/src/System.IO.Pipelines.Extensions/ReadableBufferSequence.cs index ed8515a6d6d..629547edf98 100644 --- a/src/System.IO.Pipelines.Extensions/ReadableBufferSequence.cs +++ b/src/System.IO.Pipelines.Extensions/ReadableBufferSequence.cs @@ -15,19 +15,12 @@ public ReadableBufferSequence(ReadOnlyBuffer buffer) : this() _buffer = buffer; } - public Position Start => new Position(_buffer.Start.Segment, _buffer.Start.Index); + public Position Start => _buffer.Start; - public bool TryGet(ref Position position, out ReadOnlyMemory item, bool advance = true) - { - var (data, index) = position.Get(); - var p = new Position(data, index); - var result = _buffer.TryGet(ref p, out item); - if (advance) - { - position = new Position(p.Segment, p.Index); - } + public Position Seek(Position origin, long offset) + => _buffer.Seek(origin, offset); - return result; - } + public bool TryGet(ref Position position, out ReadOnlyMemory item, bool advance = true) + => _buffer.TryGet(ref position, out item, advance); } } diff --git a/src/System.IO.Pipelines/System/IO/Pipelines/Pipe.cs b/src/System.IO.Pipelines/System/IO/Pipelines/Pipe.cs index c35e5e5cbd5..a908de0ea12 100644 --- a/src/System.IO.Pipelines/System/IO/Pipelines/Pipe.cs +++ b/src/System.IO.Pipelines/System/IO/Pipelines/Pipe.cs @@ -421,7 +421,7 @@ void IPipeReader.Advance(Position consumed, Position examined) return; } - var consumedSegment = consumed.GetSegment(); + var consumedSegment = (BufferSegment)consumed.Segment; returnStart = _readHead; returnEnd = consumedSegment; diff --git a/tests/System.Collections.Sequences.Tests/SampleCollections/Hashtable.cs b/tests/System.Collections.Sequences.Tests/SampleCollections/Hashtable.cs index 1aebb813461..78a06ea32fa 100644 --- a/tests/System.Collections.Sequences.Tests/SampleCollections/Hashtable.cs +++ b/tests/System.Collections.Sequences.Tests/SampleCollections/Hashtable.cs @@ -141,5 +141,13 @@ public SequenceEnumerator> GetEnumerator() { return new SequenceEnumerator>(this); } + + public Position Seek(Position origin, long offset) + { + if (offset<0) throw new ArgumentOutOfRangeException(nameof(offset)); + while (offset-- > 0 && TryGet(ref origin, out _)); + if (offset == 0) return origin; + throw new ArgumentOutOfRangeException(nameof(offset)); + } } } diff --git a/tests/System.Collections.Sequences.Tests/SampleCollections/LinkedContainer.cs b/tests/System.Collections.Sequences.Tests/SampleCollections/LinkedContainer.cs index f0d3f8fd948..f2bcca2943a 100644 --- a/tests/System.Collections.Sequences.Tests/SampleCollections/LinkedContainer.cs +++ b/tests/System.Collections.Sequences.Tests/SampleCollections/LinkedContainer.cs @@ -52,5 +52,23 @@ public SequenceEnumerator GetEnumerator() { return new SequenceEnumerator(this); } + + public Position Seek(Position origin, long offset) + { + if (offset < 0) throw new InvalidOperationException("cannot seek backwards"); + var (node, index) = origin.Get(); + while(offset-- > 0) + { + if (node != null) + { + node = node._next; + } + else + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + } + return new Position(node, 0); + } } }