<PackageReference Include="System.Memory" Version="4.5.2" />

ReadOnlySequence<T>

public struct ReadOnlySequence<T>
using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace System.Buffers { [DebuggerTypeProxy(typeof(System.Buffers.ReadOnlySequenceDebugView<>))] [DebuggerDisplay("{ToString(),raw}")] public readonly struct ReadOnlySequence<T> { public struct Enumerator { private readonly ReadOnlySequence<T> _sequence; private SequencePosition _next; private ReadOnlyMemory<T> _currentMemory; public ReadOnlyMemory<T> Current => _currentMemory; public Enumerator([In] [System.Runtime.CompilerServices.IsReadOnly] ref ReadOnlySequence<T> sequence) { _currentMemory = default(ReadOnlyMemory<T>); _next = sequence.Start; _sequence = sequence; } public bool MoveNext() { if (_next.GetObject() == null) return false; return _sequence.TryGet(ref _next, out _currentMemory, true); } } private enum SequenceType { MultiSegment, Array, MemoryManager, String, Empty } private readonly SequencePosition _sequenceStart; private readonly SequencePosition _sequenceEnd; public static readonly ReadOnlySequence<T> Empty = new ReadOnlySequence<T>(System.SpanHelpers.PerTypeValues<T>.EmptyArray); public long Length => GetLength(); public bool IsEmpty => Length == 0; public bool IsSingleSegment { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _sequenceStart.GetObject() == _sequenceEnd.GetObject(); } } public ReadOnlyMemory<T> First => GetFirstBuffer(); public SequencePosition Start => _sequenceStart; public SequencePosition End => _sequenceEnd; [MethodImpl(MethodImplOptions.AggressiveInlining)] private ReadOnlySequence(object startSegment, int startIndexAndFlags, object endSegment, int endIndexAndFlags) { _sequenceStart = new SequencePosition(startSegment, startIndexAndFlags); _sequenceEnd = new SequencePosition(endSegment, endIndexAndFlags); } public ReadOnlySequence(ReadOnlySequenceSegment<T> startSegment, int startIndex, ReadOnlySequenceSegment<T> endSegment, int endIndex) { if (startSegment != null && endSegment != null && (startSegment == endSegment || startSegment.RunningIndex <= endSegment.RunningIndex)) { ReadOnlyMemory<T> memory = startSegment.Memory; if ((uint)memory.Length >= (uint)startIndex) { memory = endSegment.Memory; if ((uint)memory.Length >= (uint)endIndex && (startSegment != endSegment || endIndex >= startIndex)) goto IL_004c; } } System.ThrowHelper.ThrowArgumentValidationException<T>(startSegment, startIndex, endSegment); goto IL_004c; IL_004c: _sequenceStart = new SequencePosition(startSegment, System.Buffers.ReadOnlySequence.SegmentToSequenceStart(startIndex)); _sequenceEnd = new SequencePosition(endSegment, System.Buffers.ReadOnlySequence.SegmentToSequenceEnd(endIndex)); } public ReadOnlySequence(T[] array) { if (array == null) System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument.array); _sequenceStart = new SequencePosition(array, System.Buffers.ReadOnlySequence.ArrayToSequenceStart(0)); _sequenceEnd = new SequencePosition(array, System.Buffers.ReadOnlySequence.ArrayToSequenceEnd(array.Length)); } public ReadOnlySequence(T[] array, int start, int length) { if (array == null || (uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) System.ThrowHelper.ThrowArgumentValidationException(array, start); _sequenceStart = new SequencePosition(array, System.Buffers.ReadOnlySequence.ArrayToSequenceStart(start)); _sequenceEnd = new SequencePosition(array, System.Buffers.ReadOnlySequence.ArrayToSequenceEnd(start + length)); } public ReadOnlySequence(ReadOnlyMemory<T> memory) { ArraySegment<T> segment; if (MemoryMarshal.TryGetMemoryManager<T, MemoryManager<T>>(memory, out MemoryManager<T> manager, out int start, out int length)) { _sequenceStart = new SequencePosition(manager, System.Buffers.ReadOnlySequence.MemoryManagerToSequenceStart(start)); _sequenceEnd = new SequencePosition(manager, System.Buffers.ReadOnlySequence.MemoryManagerToSequenceEnd(length)); } else if (MemoryMarshal.TryGetArray<T>(memory, out segment)) { T[] array = segment.Array; int offset = segment.Offset; _sequenceStart = new SequencePosition(array, System.Buffers.ReadOnlySequence.ArrayToSequenceStart(offset)); _sequenceEnd = new SequencePosition(array, System.Buffers.ReadOnlySequence.ArrayToSequenceEnd(offset + segment.Count)); } else if (typeof(T) == typeof(char)) { if (!MemoryMarshal.TryGetString((ReadOnlyMemory<char>)(object)memory, out string text, out int start2, out length)) System.ThrowHelper.ThrowInvalidOperationException(); _sequenceStart = new SequencePosition(text, System.Buffers.ReadOnlySequence.StringToSequenceStart(start2)); _sequenceEnd = new SequencePosition(text, System.Buffers.ReadOnlySequence.StringToSequenceEnd(start2 + length)); } else { System.ThrowHelper.ThrowInvalidOperationException(); _sequenceStart = default(SequencePosition); _sequenceEnd = default(SequencePosition); } } public ReadOnlySequence<T> Slice(long start, long length) { if (start < 0 || length < 0) System.ThrowHelper.ThrowStartOrEndArgumentValidationException(start); int index = GetIndex(ref _sequenceStart); int index2 = GetIndex(ref _sequenceEnd); object object = _sequenceStart.GetObject(); object object2 = _sequenceEnd.GetObject(); SequencePosition start2; SequencePosition end; if (object != object2) { ReadOnlySequenceSegment<T> readOnlySequenceSegment = (ReadOnlySequenceSegment<T>)object; int num = readOnlySequenceSegment.Memory.Length - index; if (num > start) { index += (int)start; start2 = new SequencePosition(object, index); end = GetEndPosition(readOnlySequenceSegment, object, index, object2, index2, length); } else { if (num < 0) System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); start2 = SeekMultiSegment(readOnlySequenceSegment.Next, object2, index2, start - num, System.ExceptionArgument.start); int index3 = GetIndex(ref start2); object object3 = start2.GetObject(); if (object3 != object2) end = GetEndPosition((ReadOnlySequenceSegment<T>)object3, object3, index3, object2, index2, length); else { if (index2 - index3 < length) System.ThrowHelper.ThrowStartOrEndArgumentValidationException(0); end = new SequencePosition(object3, index3 + (int)length); } } } else { if (index2 - index < start) System.ThrowHelper.ThrowStartOrEndArgumentValidationException(-1); index += (int)start; start2 = new SequencePosition(object, index); if (index2 - index < length) System.ThrowHelper.ThrowStartOrEndArgumentValidationException(0); end = new SequencePosition(object, index + (int)length); } return SliceImpl(ref start2, ref end); } public ReadOnlySequence<T> Slice(long start, SequencePosition end) { if (start < 0) System.ThrowHelper.ThrowStartOrEndArgumentValidationException(start); uint index = (uint)GetIndex(ref end); object object = end.GetObject(); uint index2 = (uint)GetIndex(ref _sequenceStart); object object2 = _sequenceStart.GetObject(); uint index3 = (uint)GetIndex(ref _sequenceEnd); object object3 = _sequenceEnd.GetObject(); if (object2 == object3) { if (!InRange(index, index2, index3)) System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); if (index - index2 < start) System.ThrowHelper.ThrowStartOrEndArgumentValidationException(-1); } else { ReadOnlySequenceSegment<T> readOnlySequenceSegment = (ReadOnlySequenceSegment<T>)object2; ulong num = (ulong)(readOnlySequenceSegment.RunningIndex + index2); ulong num2 = (ulong)(((ReadOnlySequenceSegment<T>)object).RunningIndex + index); if (!InRange(num2, num, (ulong)(((ReadOnlySequenceSegment<T>)object3).RunningIndex + index3))) System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); if ((ulong)((long)num + start) > num2) System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.start); int num3 = readOnlySequenceSegment.Memory.Length - (int)index2; if (num3 <= start) { if (num3 < 0) System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); SequencePosition start2 = SeekMultiSegment(readOnlySequenceSegment.Next, object, (int)index, start - num3, System.ExceptionArgument.start); return SliceImpl(ref start2, ref end); } } SequencePosition start3 = new SequencePosition(object2, (int)index2 + (int)start); return SliceImpl(ref start3, ref end); } public ReadOnlySequence<T> Slice(SequencePosition start, long length) { uint index = (uint)GetIndex(ref start); object object = start.GetObject(); uint index2 = (uint)GetIndex(ref _sequenceStart); object object2 = _sequenceStart.GetObject(); uint index3 = (uint)GetIndex(ref _sequenceEnd); object object3 = _sequenceEnd.GetObject(); if (object2 == object3) { if (!InRange(index, index2, index3)) System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); if (length < 0) System.ThrowHelper.ThrowStartOrEndArgumentValidationException(0); if (index3 - index < length) System.ThrowHelper.ThrowStartOrEndArgumentValidationException(0); } else { ReadOnlySequenceSegment<T> readOnlySequenceSegment = (ReadOnlySequenceSegment<T>)object; ulong num = (ulong)(readOnlySequenceSegment.RunningIndex + index); ulong start2 = (ulong)(((ReadOnlySequenceSegment<T>)object2).RunningIndex + index2); ulong num2 = (ulong)(((ReadOnlySequenceSegment<T>)object3).RunningIndex + index3); if (!InRange(num, start2, num2)) System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); if (length < 0) System.ThrowHelper.ThrowStartOrEndArgumentValidationException(0); if ((ulong)((long)num + length) > num2) System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.length); int num3 = readOnlySequenceSegment.Memory.Length - (int)index; if (num3 < length) { if (num3 < 0) System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); SequencePosition end = SeekMultiSegment(readOnlySequenceSegment.Next, object3, (int)index3, length - num3, System.ExceptionArgument.length); return SliceImpl(ref start, ref end); } } SequencePosition end2 = new SequencePosition(object, (int)index + (int)length); return SliceImpl(ref start, ref end2); } public ReadOnlySequence<T> Slice(int start, int length) { return Slice((long)start, (long)length); } public ReadOnlySequence<T> Slice(int start, SequencePosition end) { return Slice((long)start, end); } public ReadOnlySequence<T> Slice(SequencePosition start, int length) { return Slice(start, (long)length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlySequence<T> Slice(SequencePosition start, SequencePosition end) { BoundsCheck((uint)GetIndex(ref start), start.GetObject(), (uint)GetIndex(ref end), end.GetObject()); return SliceImpl(ref start, ref end); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlySequence<T> Slice(SequencePosition start) { BoundsCheck(ref start); return SliceImpl(ref start, ref _sequenceEnd); } public ReadOnlySequence<T> Slice(long start) { if (start < 0) System.ThrowHelper.ThrowStartOrEndArgumentValidationException(start); if (start == 0) return this; SequencePosition start2 = Seek(ref _sequenceStart, ref _sequenceEnd, start, System.ExceptionArgument.start); return SliceImpl(ref start2, ref _sequenceEnd); } public override string ToString() { if (typeof(T) == typeof(char)) { ReadOnlySequence<T> source = this; ReadOnlySequence<char> sequence = Unsafe.As<ReadOnlySequence<T>, ReadOnlySequence<char>>(ref source); if (SequenceMarshal.TryGetString(sequence, out string text, out int start, out int length)) return text.Substring(start, length); if (Length < 2147483647) return new string(BuffersExtensions.ToArray<char>(ref sequence)); } return $"""{typeof(T).Name}""{Length}"""; } public Enumerator GetEnumerator() { return new Enumerator(ref this); } public SequencePosition GetPosition(long offset) { return GetPosition(offset, _sequenceStart); } public SequencePosition GetPosition(long offset, SequencePosition origin) { if (offset < 0) System.ThrowHelper.ThrowArgumentOutOfRangeException_OffsetOutOfRange(); return Seek(ref origin, ref _sequenceEnd, offset, System.ExceptionArgument.offset); } public bool TryGet(ref SequencePosition position, out ReadOnlyMemory<T> memory, bool advance = true) { SequencePosition next; bool result = TryGetBuffer(ref position, out memory, out next); if (advance) position = next; return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal bool TryGetBuffer([In] [System.Runtime.CompilerServices.IsReadOnly] ref SequencePosition position, out ReadOnlyMemory<T> memory, out SequencePosition next) { object object = position.GetObject(); next = default(SequencePosition); if (object == null) { memory = default(ReadOnlyMemory<T>); return false; } SequenceType sequenceType = GetSequenceType(); object object2 = _sequenceEnd.GetObject(); int index = GetIndex(ref position); int index2 = GetIndex(ref _sequenceEnd); if (sequenceType == SequenceType.MultiSegment) { ReadOnlySequenceSegment<T> readOnlySequenceSegment = (ReadOnlySequenceSegment<T>)object; ReadOnlyMemory<T> memory2; if (readOnlySequenceSegment != object2) { ReadOnlySequenceSegment<T> next2 = readOnlySequenceSegment.Next; if (next2 == null) System.ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached(); next = new SequencePosition(next2, 0); memory2 = readOnlySequenceSegment.Memory; memory = memory2.Slice(index); } else { memory2 = readOnlySequenceSegment.Memory; memory = memory2.Slice(index, index2 - index); } } else { if (object != object2) System.ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached(); if (sequenceType == SequenceType.Array) memory = new ReadOnlyMemory<T>((T[])object, index, index2 - index); else if (typeof(T) == typeof(char) && sequenceType == SequenceType.String) { memory = (ReadOnlyMemory<T>)(object)MemoryExtensions.AsMemory((string)object, index, index2 - index); } else { memory = ((MemoryManager<T>)object).Memory.Slice(index, index2 - index); } } return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private ReadOnlyMemory<T> GetFirstBuffer() { object object = _sequenceStart.GetObject(); if (object == null) return default(ReadOnlyMemory<T>); int integer = _sequenceStart.GetInteger(); int integer2 = _sequenceEnd.GetInteger(); bool flag = object != _sequenceEnd.GetObject(); if (integer >= 0) { if (integer2 >= 0) { ReadOnlyMemory<T> memory = ((ReadOnlySequenceSegment<T>)object).Memory; if (flag) return memory.Slice(integer); return memory.Slice(integer, integer2 - integer); } if (flag) System.ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached(); return new ReadOnlyMemory<T>((T[])object, integer, (integer2 & 2147483647) - integer); } if (flag) System.ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached(); if (typeof(T) == typeof(char) && integer2 < 0) return (ReadOnlyMemory<T>)(object)MemoryExtensions.AsMemory((string)object, integer & 2147483647, integer2 - integer); integer &= 2147483647; return ((MemoryManager<T>)object).Memory.Slice(integer, integer2 - integer); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private SequencePosition Seek([In] [System.Runtime.CompilerServices.IsReadOnly] ref SequencePosition start, [In] [System.Runtime.CompilerServices.IsReadOnly] ref SequencePosition end, long offset, System.ExceptionArgument argument) { int index = GetIndex(ref start); int index2 = GetIndex(ref end); object object = start.GetObject(); object object2 = end.GetObject(); if (object != object2) { ReadOnlySequenceSegment<T> readOnlySequenceSegment = (ReadOnlySequenceSegment<T>)object; int num = readOnlySequenceSegment.Memory.Length - index; if (num <= offset) { if (num < 0) System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); return SeekMultiSegment(readOnlySequenceSegment.Next, object2, index2, offset - num, argument); } } else if (index2 - index < offset) { System.ThrowHelper.ThrowArgumentOutOfRangeException(argument); } return new SequencePosition(object, index + (int)offset); } [MethodImpl(MethodImplOptions.NoInlining)] private static SequencePosition SeekMultiSegment(ReadOnlySequenceSegment<T> currentSegment, object endObject, int endIndex, long offset, System.ExceptionArgument argument) { while (true) { if (currentSegment == null || currentSegment == endObject) { if (currentSegment == null || endIndex < offset) System.ThrowHelper.ThrowArgumentOutOfRangeException(argument); break; } int length = currentSegment.Memory.Length; if (length > offset) break; offset -= length; currentSegment = currentSegment.Next; } return new SequencePosition(currentSegment, (int)offset); } private void BoundsCheck([In] [System.Runtime.CompilerServices.IsReadOnly] ref SequencePosition position) { uint index = (uint)GetIndex(ref position); uint index2 = (uint)GetIndex(ref _sequenceStart); uint index3 = (uint)GetIndex(ref _sequenceEnd); object object = _sequenceStart.GetObject(); object object2 = _sequenceEnd.GetObject(); if (object == object2) { if (!InRange(index, index2, index3)) System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); } else { ulong start = (ulong)(((ReadOnlySequenceSegment<T>)object).RunningIndex + index2); if (!InRange((ulong)(((ReadOnlySequenceSegment<T>)position.GetObject()).RunningIndex + index), start, (ulong)(((ReadOnlySequenceSegment<T>)object2).RunningIndex + index3))) System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); } } private void BoundsCheck(uint sliceStartIndex, object sliceStartObject, uint sliceEndIndex, object sliceEndObject) { uint index = (uint)GetIndex(ref _sequenceStart); uint index2 = (uint)GetIndex(ref _sequenceEnd); object object = _sequenceStart.GetObject(); object object2 = _sequenceEnd.GetObject(); if (object == object2) { if (sliceStartObject != sliceEndObject || sliceStartObject != object || sliceStartIndex > sliceEndIndex || sliceStartIndex < index || sliceEndIndex > index2) System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); } else { ulong num = (ulong)(((ReadOnlySequenceSegment<T>)sliceStartObject).RunningIndex + sliceStartIndex); ulong num2 = (ulong)(((ReadOnlySequenceSegment<T>)sliceEndObject).RunningIndex + sliceEndIndex); if (num > num2) System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); if (num < (ulong)(((ReadOnlySequenceSegment<T>)object).RunningIndex + index) || num2 > (ulong)(((ReadOnlySequenceSegment<T>)object2).RunningIndex + index2)) System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); } } private static SequencePosition GetEndPosition(ReadOnlySequenceSegment<T> startSegment, object startObject, int startIndex, object endObject, int endIndex, long length) { int num = startSegment.Memory.Length - startIndex; if (num > length) return new SequencePosition(startObject, startIndex + (int)length); if (num < 0) System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); return SeekMultiSegment(startSegment.Next, endObject, endIndex, length - num, System.ExceptionArgument.length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private SequenceType GetSequenceType() { return (SequenceType)(-(2 * (_sequenceStart.GetInteger() >> 31) + (_sequenceEnd.GetInteger() >> 31))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int GetIndex([In] [System.Runtime.CompilerServices.IsReadOnly] ref SequencePosition position) { return position.GetInteger() & 2147483647; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private ReadOnlySequence<T> SliceImpl([In] [System.Runtime.CompilerServices.IsReadOnly] ref SequencePosition start, [In] [System.Runtime.CompilerServices.IsReadOnly] ref SequencePosition end) { return new ReadOnlySequence<T>(start.GetObject(), GetIndex(ref start) | (_sequenceStart.GetInteger() & -2147483648), end.GetObject(), GetIndex(ref end) | (_sequenceEnd.GetInteger() & -2147483648)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private long GetLength() { int index = GetIndex(ref _sequenceStart); int index2 = GetIndex(ref _sequenceEnd); object object = _sequenceStart.GetObject(); object object2 = _sequenceEnd.GetObject(); if (object != object2) { ReadOnlySequenceSegment<T> readOnlySequenceSegment = (ReadOnlySequenceSegment<T>)object; ReadOnlySequenceSegment<T> readOnlySequenceSegment2 = (ReadOnlySequenceSegment<T>)object2; return readOnlySequenceSegment2.RunningIndex + index2 - (readOnlySequenceSegment.RunningIndex + index); } return index2 - index; } internal bool TryGetReadOnlySequenceSegment(out ReadOnlySequenceSegment<T> startSegment, out int startIndex, out ReadOnlySequenceSegment<T> endSegment, out int endIndex) { object object = _sequenceStart.GetObject(); if (object == null || GetSequenceType() != 0) { startSegment = null; startIndex = 0; endSegment = null; endIndex = 0; return false; } startSegment = (ReadOnlySequenceSegment<T>)object; startIndex = GetIndex(ref _sequenceStart); endSegment = (ReadOnlySequenceSegment<T>)_sequenceEnd.GetObject(); endIndex = GetIndex(ref _sequenceEnd); return true; } internal bool TryGetArray(out ArraySegment<T> segment) { if (GetSequenceType() != SequenceType.Array) { segment = default(ArraySegment<T>); return false; } int index = GetIndex(ref _sequenceStart); segment = new ArraySegment<T>((T[])_sequenceStart.GetObject(), index, GetIndex(ref _sequenceEnd) - index); return true; } internal bool TryGetString(out string text, out int start, out int length) { if (typeof(T) != typeof(char) || GetSequenceType() != SequenceType.String) { start = 0; length = 0; text = null; return false; } start = GetIndex(ref _sequenceStart); length = GetIndex(ref _sequenceEnd) - start; text = (string)_sequenceStart.GetObject(); return true; } private static bool InRange(uint value, uint start, uint end) { return value - start <= end - start; } private static bool InRange(ulong value, ulong start, ulong end) { return value - start <= end - start; } } }