public ReadOnlyBytes(IMemoryList <byte> segments, long length) { // TODO: should we skip all empty buffers, i.e. of _first.IsEmpty? _first = segments.Memory; _all = segments; _totalLengthOrVirtualIndex = length; }
private ReadOnlyBytes(ReadOnlyMemory <byte> first, IMemoryList <byte> all, long length) { // TODO: add assert that first overlaps all (once we have Overlap on Span) _first = first; _all = all; _totalLengthOrVirtualIndex = _all == null ? 0 : length; }
/// <summary> /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from linked memory list represented by start and end segments /// and corresponding indexes in them. /// </summary> public ReadOnlySequence(IMemoryList <T> startSegment, int startIndex, IMemoryList <T> endSegment, int endIndex) { if (startSegment == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.startSegment); } if (endSegment == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.endSegment); } if (startIndex < 0 || startSegment.Memory.Length < startIndex) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex); } if (endIndex < 0 || endSegment.Memory.Length < endIndex) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.endIndex); } if (startSegment == endSegment && endIndex < startIndex) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.endIndex); } _sequenceStart = new SequencePosition(startSegment, startIndex | MemoryListStartMask); _sequenceEnd = new SequencePosition(endSegment, endIndex | MemoryListEndMask); }
public static long IndexOf(this IMemoryList <byte> sequence, byte value) { var first = sequence.Memory.Span; long index = first.IndexOf(value); if (index != -1) { return(index); } Position position = default; int virtualIndex = first.Length; while (sequence.TryGet(ref position, out ReadOnlyMemory <byte> memory)) { index = memory.Span.IndexOf(value); if (index != -1) { return(index + virtualIndex); } virtualIndex += memory.Length; } return(-1); }
private void BoundsCheck(SequencePosition start, SequencePosition position) { int startIndex = start.Index; int endIndex = position.Index; SequenceType type = GetSequenceType(); startIndex = GetIndex(startIndex); endIndex = GetIndex(endIndex); switch (type) { case SequenceType.OwnedMemory: case SequenceType.Array: if (endIndex > startIndex) { ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); } return; case SequenceType.MemoryList: IMemoryList <T> segment = (IMemoryList <T>)position.Segment; IMemoryList <T> memoryList = (IMemoryList <T>)start.Segment; if (segment.RunningIndex - startIndex > memoryList.RunningIndex - endIndex) { ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); } return; default: ThrowHelper.ThrowInvalidOperationException_UnexpectedSegmentType(); return; } }
/// <summary> /// Get <see cref="IMemoryList{T}"/> from the underlying <see cref="ReadOnlySequence{T}"/>. /// If unable to get the <see cref="IMemoryList{T}"/>, return false. /// </summary> public static bool TryGetMemoryList <T>(ReadOnlySequence <T> sequence, out IMemoryList <T> startSegment, out int startIndex, out IMemoryList <T> endSegment, out int endIndex) { return(sequence.TryGetMemoryList(out startSegment, out startIndex, out endSegment, out endIndex)); }
public ReadWriteBytes(IMemoryList <byte> first, IMemoryList <byte> last) { _start = first; _startIndex = 0; _end = last; _endIndex = last.Memory.Length; Validate(); }
public ReadOnlyBuffer(IMemoryList <T> startSegment, int offset, IMemoryList <T> endSegment, int endIndex) { Debug.Assert(startSegment != null); Debug.Assert(endSegment != null); Debug.Assert(startSegment.Memory.Length >= offset); Debug.Assert(endSegment.Memory.Length >= endIndex); BufferStart = new SequencePosition(startSegment, offset | MemoryListStartMask); BufferEnd = new SequencePosition(endSegment, endIndex | MemoryListEndMask); }
public BufferSegment Append(Memory <byte> memory) { var segment = new BufferSegment(memory) { RunningIndex = RunningIndex + Memory.Length }; Next = segment; return(segment); }
internal ReadableBuffer(IMemoryList <byte> startSegment, int startIndex, IMemoryList <byte> endSegment, int endIndex) { Debug.Assert(startSegment != null); Debug.Assert(endSegment != null); Debug.Assert(startSegment.Memory.Length >= startIndex); Debug.Assert(endSegment.Memory.Length >= endIndex); BufferStart = new ReadCursor(startSegment, startIndex); BufferEnd = new ReadCursor(endSegment, endIndex); }
public ReadOnlyBuffer(IMemoryList <byte> startSegment, int offset, IMemoryList <byte> endSegment, int endIndex) { Debug.Assert(startSegment != null); Debug.Assert(endSegment != null); Debug.Assert(startSegment.Memory.Length >= offset); Debug.Assert(endSegment.Memory.Length >= endIndex); BufferStart = new Position(startSegment, offset); BufferEnd = new Position(endSegment, endIndex); }
private static long GetLength(IMemoryList <T> start, int startIndex, IMemoryList <T> endSegment, int endIndex) { if (start == endSegment) { return(endIndex - startIndex); } return((endSegment.RunningIndex - start.Next.RunningIndex) // Length of data in between first and last segment + (start.Memory.Length - startIndex) // Length of data in first segment + endIndex); // Length of data in last segment }
public static Position PositionOf(this IMemoryList <byte> sequence, byte value) { while (sequence != null) { var index = sequence.Memory.Span.IndexOf(value); if (index != -1) { return(Position.Create(index, sequence)); } sequence = sequence.Rest; } return(Position.End); }
public static Position?PositionOf(this IMemoryList <byte> list, byte value) { while (list != null) { var current = list.Memory.Span; var index = current.IndexOf(value); if (index != -1) { return(Position.Create(list, index)); } list = list.Next; } return(null); }
/// <summary> /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from linked memory list represented by start and end segments /// and corresponding indexes in them. /// </summary> public ReadOnlySequence(IMemoryList <T> startSegment, int startIndex, IMemoryList <T> endSegment, int endIndex) { if (startSegment == null || endSegment == null || (uint)startSegment.Memory.Length < (uint)startIndex || (uint)endSegment.Memory.Length < (uint)endIndex || (startSegment == endSegment && endIndex < startIndex)) { ThrowHelper.ThrowArgumentValidationException(startSegment, startIndex, endSegment); } _sequenceStart = new SequencePosition(startSegment, ReadOnlySequence.MemoryListToSequenceStart(startIndex)); _sequenceEnd = new SequencePosition(endSegment, ReadOnlySequence.MemoryListToSequenceEnd(endIndex)); }
private static SequencePosition SeekMultiSegment(IMemoryList <byte> start, int startIndex, IMemoryList <byte> end, int endPosition, long count, bool checkEndReachable) { SequencePosition result = default; bool foundResult = false; IMemoryList <byte> current = start; int currentIndex = startIndex; while (current != null) { // We need to loop up until the end to make sure start and end are connected // if end is not trusted if (!foundResult) { var isEnd = current == end; int currentEnd = isEnd ? endPosition : current.Memory.Length; int currentLength = currentEnd - currentIndex; // We would prefer to put position in the beginning of next segment // then past the end of previous one, but only if we are not leaving current buffer if (currentLength > count || (currentLength == count && isEnd)) { result = new SequencePosition(current, currentIndex + (int)count); foundResult = true; if (!checkEndReachable) { break; } } count -= currentLength; } if (current.Next == null && current != end) { ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached(); } current = current.Next; currentIndex = 0; } if (!foundResult) { ThrowHelper.ThrowArgumentOutOfRangeException_CountOutOfRange(); } return(result); }
private static SequencePosition SeekMultiSegment(IMemoryList <byte> start, int startIndex, IMemoryList <byte> end, int endPosition, long bytes, bool checkEndReachable) { SequencePosition result = default(SequencePosition); var foundResult = false; var current = start; var currentIndex = startIndex; while (current != null) { // We need to loop up until the end to make sure start and end are connected // if end is not trusted if (!foundResult) { var memory = current.Memory; var currentEnd = current == end ? endPosition : memory.Length; memory = memory.Slice(0, currentEnd - currentIndex); // We would prefer to put cursor in the beginning of next segment // then past the end of previous one, but only if we are not leaving current buffer if (memory.Length > bytes || (memory.Length == bytes && current == end)) { result = new SequencePosition(current, currentIndex + (int)bytes); foundResult = true; if (!checkEndReachable) { break; } } bytes -= memory.Length; } if (current.Next == null && current != end) { ThrowHelper.ThrowInvalidOperationException(ExceptionResource.EndCursorNotReached); } current = current.Next; currentIndex = 0; } if (!foundResult) { ThrowHelper.ThrowCursorOutOfBoundsException(); } return(result); }
private static long GetLength( IMemoryList <T> start, int startIndex, IMemoryList <T> endSegment, int endIndex) { if (start == endSegment) { return(endIndex - startIndex); } return((endSegment.RunningIndex - start.Next.RunningIndex) + (start.Memory.Length - startIndex) + endIndex); }
internal bool TryGetMemoryList(out IMemoryList <T> startSegment, out int startIndex, out IMemoryList <T> endSegment, out int endIndex) { if (Start.GetObject() == null || GetSequenceType() != SequenceType.MemoryList) { startSegment = null; endSegment = null; startIndex = 0; endIndex = 0; return(false); } startIndex = GetIndex(Start.GetInteger()); endIndex = GetIndex(End.GetInteger()); startSegment = (IMemoryList <T>)Start.GetObject(); endSegment = (IMemoryList <T>)End.GetObject(); return(true); }
private static Exception CreateArgumentValidationException <T>(IMemoryList <T> startSegment, int startIndex, IMemoryList <T> endSegment) { if (startSegment == null) { return(CreateArgumentNullException(ExceptionArgument.startSegment)); } else if (endSegment == null) { return(CreateArgumentNullException(ExceptionArgument.endSegment)); } else if ((uint)startSegment.Memory.Length < (uint)startIndex) { return(CreateArgumentOutOfRangeException(ExceptionArgument.startIndex)); } else { return(CreateArgumentOutOfRangeException(ExceptionArgument.endIndex)); } }
public static long IndexOf(this IMemoryList <byte> list, ReadOnlySpan <byte> value) { var first = list.Memory.Span; var index = first.IndexOf(value); if (index != -1) { return(index); } var rest = list.Next; if (rest == null) { return(-1); } return(IndexOfStraddling(first, list.Next, value)); }
public static int CopyTo(this IMemoryList <byte> list, Span <byte> destination) { var current = list.Memory.Span; int copied = 0; while (destination.Length > 0) { if (current.Length >= destination.Length) { current.Slice(0, destination.Length).CopyTo(destination); copied += destination.Length; return(copied); } else { current.CopyTo(destination); copied += current.Length; destination = destination.Slice(current.Length); } } return(copied); }
public ReadWriteBytes(IMemoryList <byte> segments) : this(segments.First, segments.Rest, Unspecified) { }
// // ReadOnlySequence .ctor validation Throws coalesced to enable inlining of the .ctor // public static void ThrowArgumentValidationException <T>(IMemoryList <T> startSegment, int startIndex, IMemoryList <T> endSegment) => throw CreateArgumentValidationException(startSegment, startIndex, endSegment);
long IndexOf(IMemoryList <byte> sequence, byte value) => sequence.IndexOf(value);
internal bool TryGetBuffer(SequencePosition start, SequencePosition end, out ReadOnlyMemory <T> data, out SequencePosition next) { if (start.Segment == null) { data = default; next = default; return(false); } int startIndex = start.Index; int endIndex = end.Index; SequenceType type = GetSequenceType(); startIndex = GetIndex(startIndex); endIndex = GetIndex(endIndex); switch (type) { case SequenceType.MemoryList: var segment = (IMemoryList <T>)start.Segment; Memory <T> bufferSegmentMemory = segment.Memory; int currentEndIndex = bufferSegmentMemory.Length; if (segment == end.Segment) { currentEndIndex = endIndex; next = default; } else { IMemoryList <T> nextSegment = segment.Next; if (nextSegment == null) { if (end.Segment != null) { ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached(); } next = default; } else { next = new SequencePosition(nextSegment, 0); } } data = bufferSegmentMemory.Slice(startIndex, currentEndIndex - startIndex); return(true); case SequenceType.OwnedMemory: var ownedMemory = (OwnedMemory <T>)start.Segment; if (ownedMemory != end.Segment) { ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached(); } data = ownedMemory.Memory.Slice(startIndex, endIndex - startIndex); next = default; return(true); case SequenceType.Array: var array = (T[])start.Segment; if (array != end.Segment) { ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached(); } data = new Memory <T>(array, startIndex, endIndex - startIndex); next = default; return(true); default: ThrowHelper.ThrowInvalidOperationException_UnexpectedSegmentType(); next = default; data = default; return(false); } }
public ReadWriteBytes(Memory <byte> first, IMemoryList <byte> rest) : this(first, rest, Unspecified) { }
public ReadWriteBytes(IMemoryList <byte> segments, int length) : this(segments.First, segments.Rest, length) { }
// TODO (pri 3): I am pretty sure this whole routine can be written much better // searches values that potentially straddle between first and rest internal static long IndexOfStraddling(this ReadOnlySpan <byte> first, IMemoryList <byte> rest, ReadOnlySpan <byte> value) { Debug.Assert(first.IndexOf(value) == -1); if (rest == null) { return(-1); } // we only need to search the end of the first buffer. More precisely, only up to value.Length - 1 bytes in the first buffer // The other bytes in first, were already search and presumably did not match int bytesToSkipFromFirst = 0; if (first.Length > value.Length - 1) { bytesToSkipFromFirst = first.Length - value.Length - 1; } // now that we know how many bytes we need to skip, create slice of first buffer with bytes that need to be searched. ReadOnlySpan <byte> bytesToSearchAgain; if (bytesToSkipFromFirst > 0) { bytesToSearchAgain = first.Slice(bytesToSkipFromFirst); } else { bytesToSearchAgain = first; } long index; // now combine the bytes from the end of the first buffer with bytes in the rest, and serarch the combined buffer // this check is a small optimization: if the first byte from the value does not exist in the bytesToSearchAgain, there is no reason to combine if (bytesToSearchAgain.IndexOf(value[0]) != -1) { var combinedBufferLength = value.Length << 1; var combined = combinedBufferLength < 128 ? stackalloc byte[combinedBufferLength] : // TODO (pri 3): I think this could be eliminated by chunking values new byte[combinedBufferLength]; bytesToSearchAgain.CopyTo(combined); int combinedLength = bytesToSearchAgain.Length + rest.CopyTo(combined.Slice(bytesToSearchAgain.Length)); combined = combined.Slice(0, combinedLength); if (combined.Length < value.Length) { return(-1); } index = combined.IndexOf(value); if (index != -1) { return(index + bytesToSkipFromFirst); } } // try to find the bytes in _rest index = rest.IndexOf(value); if (index != -1) { return(first.Length + index); } return(-1); }
private ReadOnlyBytes(ReadOnlyMemory <byte> memory, int virtualIndex) { _first = memory; _all = null; _totalLengthOrVirtualIndex = virtualIndex; }