Summary

Class:System.Buffers.ReadOnlySequence`1
Assembly:System.Memory
File(s):C:\GitHub\corefx\src\System.Memory\src\System\Buffers\ReadOnlySequence.cs
C:\GitHub\corefx\src\System.Memory\src\System\Buffers\ReadOnlySequence_helpers.cs
Covered lines:455
Uncovered lines:33
Coverable lines:488
Total lines:953
Line coverage:93.2%
Branch coverage:86.8%

Metrics

MethodCyclomatic complexity NPath complexity Sequence coverage Branch coverage
.ctor(...)10100100
.ctor(...)82100100
.ctor(...)2283.3366.67
.ctor(...)42100100
.ctor(...)51661.5466.67
.ctor(...)2283.3366.67
.ctor(...)42100100
Slice(...)10100100
Slice(...)22100100
Slice(...)10100100
Slice(...)10100100
Slice(...)22100100
Slice(...)10100100
Slice(...)10100100
Slice(...)10100100
Slice(...)22100100
ToString()10100100
GetEnumerator()10100100
GetPosition(...)10100100
GetPosition(...)22100100
TryGet(...)2210066.67
SliceImpl(...)10100100
GetTypeAndIndices(...)20100100
.cctor()10100100
.ctor(...)10100100
MoveNext()22100100
TryGetBuffer(...)1112872.3473.33
GetFirstBuffer(...)1112886.3680
GetBufferCrossSegment(...)93296.1590.91
Seek(...)58100100
Seek(...)58100100
SeekMultiSegment(...)816100100
CheckEndReachable(...)3492.8680
GetLength(...)32100100
BoundsCheck(...)58100100
TryGetReadOnlySequenceSegment(...)22100100
TryGetArray(...)22100100
TryGetOwnedMemory(...)22100100
TryGetReadOnlyMemory(...)616100100

File(s)

C:\GitHub\corefx\src\System.Memory\src\System\Buffers\ReadOnlySequence.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3// See the LICENSE file in the project root for more information.
 4
 5using System.Diagnostics;
 6using System.Runtime.CompilerServices;
 7using System.Runtime.InteropServices;
 8
 9namespace System.Buffers
 10{
 11    /// <summary>
 12    /// Represents a sequence that can read a sequential series of <typeparam name="T" />.
 13    /// </summary>
 14    public readonly partial struct ReadOnlySequence<T>
 15    {
 16        private readonly SequencePosition _sequenceStart;
 17        private readonly SequencePosition _sequenceEnd;
 18
 19        /// <summary>
 20        /// Returns empty <see cref="ReadOnlySequence{T}"/>
 21        /// </summary>
 22#if FEATURE_PORTABLE_SPAN
 23        public static readonly ReadOnlySequence<T> Empty = new ReadOnlySequence<T>(SpanHelpers.PerTypeValues<T>.EmptyArr
 24#else
 125        public static readonly ReadOnlySequence<T> Empty = new ReadOnlySequence<T>(Array.Empty<T>());
 26#endif // FEATURE_PORTABLE_SPAN
 27        /// <summary>
 28        /// Length of the <see cref="ReadOnlySequence{T}"/>.
 29        /// </summary>
 130        public long Length => GetLength(_sequenceStart, _sequenceEnd);
 31
 32        /// <summary>
 33        /// Determines if the <see cref="ReadOnlySequence{T}"/> is empty.
 34        /// </summary>
 135        public bool IsEmpty => Length == 0;
 36
 37        /// <summary>
 38        /// Determines if the <see cref="ReadOnlySequence{T}"/> contains a single <see cref="ReadOnlyMemory{T}"/> segmen
 39        /// </summary>
 40        public bool IsSingleSegment
 41        {
 42            [MethodImpl(MethodImplOptions.AggressiveInlining)]
 143            get => _sequenceStart.GetObject() == _sequenceEnd.GetObject();
 44        }
 45
 46        /// <summary>
 47        /// Gets <see cref="ReadOnlyMemory{T}"/> from the first segment.
 48        /// </summary>
 149        public ReadOnlyMemory<T> First => GetFirstBuffer(_sequenceStart, _sequenceEnd);
 50
 51        /// <summary>
 52        /// A position to the start of the <see cref="ReadOnlySequence{T}"/>.
 53        /// </summary>
 154        public SequencePosition Start => _sequenceStart;
 55
 56        /// <summary>
 57        /// A position to the end of the <see cref="ReadOnlySequence{T}"/>
 58        /// </summary>
 159        public SequencePosition End => _sequenceEnd;
 60
 61        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 62        private ReadOnlySequence(object startSegment, int startIndexAndFlags, object endSegment, int endIndexAndFlags)
 163        {
 64            // Used by SliceImpl to create new ReadOnlySequence
 165            Debug.Assert(startSegment != null);
 166            Debug.Assert(endSegment != null);
 67
 168            _sequenceStart = new SequencePosition(startSegment, startIndexAndFlags);
 169            _sequenceEnd = new SequencePosition(endSegment, endIndexAndFlags);
 170        }
 71
 72        /// <summary>
 73        /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from linked memory list represented by start and en
 74        /// and corresponding indexes in them.
 75        /// </summary>
 76        public ReadOnlySequence(ReadOnlySequenceSegment<T> startSegment, int startIndex, ReadOnlySequenceSegment<T> endS
 177        {
 178            if (startSegment == null ||
 179                endSegment == null ||
 180                (uint)startSegment.Memory.Length < (uint)startIndex ||
 181                (uint)endSegment.Memory.Length < (uint)endIndex ||
 182                (startSegment == endSegment && endIndex < startIndex))
 183                ThrowHelper.ThrowArgumentValidationException(startSegment, startIndex, endSegment);
 84
 185            _sequenceStart = new SequencePosition(startSegment, ReadOnlySequence.SegmentToSequenceStart(startIndex));
 186            _sequenceEnd = new SequencePosition(endSegment, ReadOnlySequence.SegmentToSequenceEnd(endIndex));
 187        }
 88
 89        /// <summary>
 90        /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the <see cref="T:T[]"/>.
 91        /// </summary>
 92        public ReadOnlySequence(T[] array)
 193        {
 194            if (array == null)
 095                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
 96
 197            _sequenceStart = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceStart(0));
 198            _sequenceEnd = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceEnd(array.Length));
 199        }
 100
 101        /// <summary>
 102        /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the <see cref="T:T[]"/>, start and index.
 103        /// </summary>
 104        public ReadOnlySequence(T[] array, int start, int length)
 1105        {
 1106            if (array == null ||
 1107                (uint)start > (uint)array.Length ||
 1108                (uint)length > (uint)(array.Length - start))
 1109                ThrowHelper.ThrowArgumentValidationException(array, start);
 110
 1111            _sequenceStart = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceStart(start));
 1112            _sequenceEnd = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceEnd(start + length));
 1113        }
 114
 115        /// <summary>
 116        /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the <see cref="ReadOnlyMemory{T}"/>.
 117        /// Consumer is expected to manage lifetime of memory until <see cref="ReadOnlySequence{T}"/> is not used anymor
 118        /// </summary>
 119        public ReadOnlySequence(ReadOnlyMemory<T> readOnlyMemory)
 1120        {
 1121            if (MemoryMarshal.TryGetOwnedMemory(readOnlyMemory, out OwnedMemory<T> ownedMemory, out int index, out int l
 0122            {
 0123                _sequenceStart = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceStart(index));
 0124                _sequenceEnd = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceEnd(length));
 0125            }
 1126            else if (MemoryMarshal.TryGetArray(readOnlyMemory, out ArraySegment<T> arraySegment))
 1127            {
 1128                T[] array = arraySegment.Array;
 1129                int start = arraySegment.Offset;
 1130                _sequenceStart = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceStart(start));
 1131                _sequenceEnd = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceEnd(start + arraySegment.Coun
 1132            }
 1133            else if (typeof(T) == typeof(char))
 1134            {
 1135                if (!MemoryMarshal.TryGetString(((ReadOnlyMemory<char>)(object)readOnlyMemory), out string text, out int
 0136                    ThrowHelper.ThrowInvalidOperationException();
 137
 1138                _sequenceStart = new SequencePosition(text, ReadOnlySequence.StringToSequenceStart(start));
 1139                _sequenceEnd = new SequencePosition(text, ReadOnlySequence.StringToSequenceEnd(start + length));
 1140            }
 141            else
 0142            {
 143                // Should never be reached
 0144                ThrowHelper.ThrowInvalidOperationException();
 0145                _sequenceStart = default;
 0146                _sequenceEnd = default;
 0147            }
 1148        }
 149
 150        /// <summary>
 151        /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the <see cref="OwnedMemory{T}"/>.
 152        /// Consumer is expected to manage lifetime of memory until <see cref="ReadOnlySequence{T}"/> is not used anymor
 153        /// </summary>
 154        public ReadOnlySequence(OwnedMemory<T> ownedMemory)
 1155        {
 1156            if (ownedMemory == null)
 0157                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.ownedMemory);
 158
 1159            _sequenceStart = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceStart(0));
 1160            _sequenceEnd = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceEnd(ownedMemory.Lengt
 1161        }
 162
 163        /// <summary>
 164        /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the <see cref="OwnedMemory{T}"/>, start and le
 165        /// Consumer is expected to manage lifetime of memory until <see cref="ReadOnlySequence{T}"/> is not used anymor
 166        /// </summary>
 167        public ReadOnlySequence(OwnedMemory<T> ownedMemory, int start, int length)
 1168        {
 1169            if (ownedMemory == null ||
 1170                (uint)start > (uint)ownedMemory.Length ||
 1171                (uint)length > (uint)(ownedMemory.Length - start))
 1172                ThrowHelper.ThrowArgumentValidationException(ownedMemory, start);
 173
 1174            _sequenceStart = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceStart(start));
 1175            _sequenceEnd = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceEnd(start + length));
 1176        }
 177
 178        /// <summary>
 179        /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, wit
 180        /// </summary>
 181        /// <param name="start">The index at which to begin this slice.</param>
 182        /// <param name="length">The length of the slice</param>
 183        public ReadOnlySequence<T> Slice(long start, long length)
 1184        {
 1185            SequencePosition begin = Seek(_sequenceStart, _sequenceEnd, start);
 2186            SequencePosition end = Seek(begin, _sequenceEnd, length);
 1187            return SliceImpl(begin, end);
 1188        }
 189
 190        /// <summary>
 191        /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, end
 192        /// </summary>
 193        /// <param name="start">The index at which to begin this slice.</param>
 194        /// <param name="end">The end (inclusive) of the slice</param>
 195        public ReadOnlySequence<T> Slice(long start, SequencePosition end)
 1196        {
 1197            BoundsCheck(end, _sequenceEnd);
 198
 1199            SequencePosition begin = Seek(_sequenceStart, end, start);
 1200            object beginObject = begin.GetObject();
 1201            object endObject = end.GetObject();
 1202            if (beginObject != endObject)
 1203            {
 1204                CheckEndReachable(beginObject, endObject);
 1205            }
 1206            return SliceImpl(begin, end);
 1207        }
 208
 209        /// <summary>
 210        /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, wit
 211        /// </summary>
 212        /// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</p
 213        /// <param name="length">The length of the slice</param>
 214        public ReadOnlySequence<T> Slice(SequencePosition start, long length)
 1215        {
 1216            BoundsCheck(start, _sequenceEnd);
 217
 1218            SequencePosition end = Seek(start, _sequenceEnd, length);
 1219            return SliceImpl(start, end);
 1220        }
 221
 222        /// <summary>
 223        /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, wit
 224        /// </summary>
 225        /// <param name="start">The index at which to begin this slice.</param>
 226        /// <param name="length">The length of the slice</param>
 227        public ReadOnlySequence<T> Slice(int start, int length)
 1228        {
 1229            SequencePosition begin = Seek(_sequenceStart, _sequenceEnd, start);
 1230            SequencePosition end = Seek(begin, _sequenceEnd, length);
 1231            return SliceImpl(begin, end);
 1232        }
 233
 234        /// <summary>
 235        /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, end
 236        /// </summary>
 237        /// <param name="start">The index at which to begin this slice.</param>
 238        /// <param name="end">The end (inclusive) of the slice</param>
 239        public ReadOnlySequence<T> Slice(int start, SequencePosition end)
 1240        {
 1241            BoundsCheck(end, _sequenceEnd);
 242
 1243            SequencePosition begin = Seek(_sequenceStart, end, start);
 1244            object beginObject = begin.GetObject();
 1245            object endObject = end.GetObject();
 1246            if (beginObject != endObject)
 1247            {
 1248                CheckEndReachable(beginObject, endObject);
 1249            }
 1250            return SliceImpl(begin, end);
 1251        }
 252
 253        /// <summary>
 254        /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at '<paramref name="start"/>, wi
 255        /// </summary>
 256        /// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</p
 257        /// <param name="length">The length of the slice</param>
 258        public ReadOnlySequence<T> Slice(SequencePosition start, int length)
 1259        {
 1260            BoundsCheck(start, _sequenceEnd);
 261
 1262            SequencePosition end = Seek(start, _sequenceEnd, length);
 1263            return SliceImpl(start, end);
 1264        }
 265
 266        /// <summary>
 267        /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, end
 268        /// </summary>
 269        /// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</p
 270        /// <param name="end">The ending (inclusive) <see cref="SequencePosition"/> of the slice</param>
 271        public ReadOnlySequence<T> Slice(SequencePosition start, SequencePosition end)
 1272        {
 1273            BoundsCheck(end, _sequenceEnd);
 1274            BoundsCheck(start, end);
 275
 1276            return SliceImpl(start, end);
 1277        }
 278
 279        /// <summary>
 280        /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, end
 281        /// </summary>
 282        /// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</p
 283        public ReadOnlySequence<T> Slice(SequencePosition start)
 1284        {
 1285            BoundsCheck(start, _sequenceEnd);
 286
 1287            return SliceImpl(start, _sequenceEnd);
 1288        }
 289
 290        /// <summary>
 291        /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, end
 292        /// </summary>
 293        /// <param name="start">The start index at which to begin this slice.</param>
 294        public ReadOnlySequence<T> Slice(long start)
 1295        {
 1296            if (start == 0)
 1297            {
 1298                return this;
 299            }
 300
 1301            SequencePosition begin = Seek(_sequenceStart, _sequenceEnd, start);
 1302            return SliceImpl(begin, _sequenceEnd);
 1303        }
 304
 305        /// <inheritdoc />
 1306        public override string ToString() => string.Format("System.Buffers.ReadOnlySequence<{0}>[{1}]", typeof(T).Name, 
 307
 308        /// <summary>
 309        /// Returns an enumerator over the <see cref="ReadOnlySequence{T}"/>
 310        /// </summary>
 1311        public Enumerator GetEnumerator() => new Enumerator(this);
 312
 313        /// <summary>
 314        /// Returns a new <see cref="SequencePosition"/> at an <paramref name="offset"/> from the start of the sequence.
 315        /// </summary>
 1316        public SequencePosition GetPosition(long offset) => GetPosition(offset, _sequenceStart);
 317
 318        /// <summary>
 319        /// Returns a new <see cref="SequencePosition"/> at an <paramref name="offset"/> from the <paramref name="origin
 320        /// </summary>
 321        public SequencePosition GetPosition(long offset, SequencePosition origin)
 1322        {
 1323            if (offset < 0)
 1324                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.offset);
 325
 1326            return Seek(origin, _sequenceEnd, offset);
 1327        }
 328
 329        /// <summary>
 330        /// Tries to retrieve next segment after <paramref name="position"/> and return its contents in <paramref name="
 331        /// Returns <code>false</code> if end of <see cref="ReadOnlySequence{T}"/> was reached otherwise <code>true</cod
 332        /// Sets <paramref name="position"/> to the beginning of next segment if <paramref name="advance"/> is set to <c
 333        /// </summary>
 334        public bool TryGet(ref SequencePosition position, out ReadOnlyMemory<T> data, bool advance = true)
 1335        {
 1336            bool result = TryGetBuffer(position, End, out data, out SequencePosition next);
 1337            if (advance)
 1338            {
 1339                position = next;
 1340            }
 341
 1342            return result;
 1343        }
 344
 345        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 346        private ReadOnlySequence<T> SliceImpl(in SequencePosition begin, in SequencePosition end)
 1347        {
 348            // In this method we reset high order bits from indices
 349            // of positions that were passed in
 350            // and apply type bits specific for current ReadOnlySequence type
 351
 1352            return new ReadOnlySequence<T>(
 1353                begin.GetObject(),
 1354                begin.GetInteger() & ReadOnlySequence.IndexBitMask | (Start.GetInteger() & ReadOnlySequence.FlagBitMask)
 1355                end.GetObject(),
 1356                end.GetInteger() & ReadOnlySequence.IndexBitMask | (End.GetInteger() & ReadOnlySequence.FlagBitMask)
 1357            );
 1358        }
 359
 360        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 361        private void GetTypeAndIndices(int start, int end, out SequenceType sequenceType, out int startIndex, out int en
 1362        {
 1363            startIndex = start & ReadOnlySequence.IndexBitMask;
 1364            endIndex = end & ReadOnlySequence.IndexBitMask;
 365            // We take high order bits of two indexes index and move them
 366            // to a first and second position to convert to BufferType
 367            // Masking with 2 is required to only keep the second bit of Start.GetInteger()
 1368            sequenceType = Start.GetObject() == null ? SequenceType.Empty : (SequenceType)((((uint)Start.GetInteger() >>
 1369        }
 370
 371        /// <summary>
 372        /// An enumerator over the <see cref="ReadOnlySequence{T}"/>
 373        /// </summary>
 374        public struct Enumerator
 375        {
 376            private readonly ReadOnlySequence<T> _sequence;
 377            private SequencePosition _next;
 378            private ReadOnlyMemory<T> _currentMemory;
 379
 380            /// <summary>Initialize the enumerator.</summary>
 381            /// <param name="sequence">The <see cref="ReadOnlySequence{T}"/> to enumerate.</param>
 382            public Enumerator(in ReadOnlySequence<T> sequence)
 1383            {
 1384                _currentMemory = default;
 1385                _next = sequence.Start;
 1386                _sequence = sequence;
 1387            }
 388
 389            /// <summary>
 390            /// The current <see cref="ReadOnlyMemory{T}"/>
 391            /// </summary>
 1392            public ReadOnlyMemory<T> Current => _currentMemory;
 393
 394            /// <summary>
 395            /// Moves to the next <see cref="ReadOnlyMemory{T}"/> in the <see cref="ReadOnlySequence{T}"/>
 396            /// </summary>
 397            /// <returns></returns>
 398            public bool MoveNext()
 1399            {
 1400                if (_next.GetObject() == null)
 1401                {
 1402                    return false;
 403                }
 404
 1405                return _sequence.TryGet(ref _next, out _currentMemory);
 1406            }
 407        }
 408
 409        private enum SequenceType
 410        {
 411            MultiSegment = 0x00,
 412            Array = 0x1,
 413            OwnedMemory = 0x2,
 414            String = 0x3,
 415            Empty = 0x4
 416        }
 417    }
 418
 419    internal static class ReadOnlySequence
 420    {
 421        public const int FlagBitMask = 1 << 31;
 422        public const int IndexBitMask = ~FlagBitMask;
 423
 424        public const int SegmentStartMask = 0;
 425        public const int SegmentEndMask = 0;
 426
 427        public const int ArrayStartMask = 0;
 428        public const int ArrayEndMask = FlagBitMask;
 429
 430        public const int OwnedMemoryStartMask = FlagBitMask;
 431        public const int OwnedMemoryEndMask = 0;
 432
 433        public const int StringStartMask = FlagBitMask;
 434        public const int StringEndMask = FlagBitMask;
 435
 436        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 437        public static int SegmentToSequenceStart(int startIndex) => startIndex | SegmentStartMask;
 438        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 439        public static int SegmentToSequenceEnd(int endIndex) => endIndex | SegmentEndMask;
 440        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 441        public static int ArrayToSequenceStart(int startIndex) => startIndex | ArrayStartMask;
 442        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 443        public static int ArrayToSequenceEnd(int endIndex) => endIndex | ArrayEndMask;
 444        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 445        public static int OwnedMemoryToSequenceStart(int startIndex) => startIndex | OwnedMemoryStartMask;
 446        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 447        public static int OwnedMemoryToSequenceEnd(int endIndex) => endIndex | OwnedMemoryEndMask;
 448        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 449        public static int StringToSequenceStart(int startIndex) => startIndex | StringStartMask;
 450        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 451        public static int StringToSequenceEnd(int endIndex) => endIndex | StringEndMask;
 452    }
 453}

C:\GitHub\corefx\src\System.Memory\src\System\Buffers\ReadOnlySequence_helpers.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3// See the LICENSE file in the project root for more information.
 4
 5using System.Diagnostics;
 6using System.Runtime.CompilerServices;
 7
 8#if !netstandard
 9using Internal.Runtime.CompilerServices;
 10#endif
 11
 12namespace System.Buffers
 13{
 14    public readonly partial struct ReadOnlySequence<T>
 15    {
 16        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 17        internal bool TryGetBuffer(in SequencePosition start, in SequencePosition end, out ReadOnlyMemory<T> data, out S
 118        {
 19            SequenceType type;
 120            int startIndex = 0;
 121            int endIndex = 0;
 122            next = default;
 123            object startObject = start.GetObject();
 124            if (startObject != null)
 125            {
 126                GetTypeAndIndices(start.GetInteger(), end.GetInteger(), out type, out startIndex, out endIndex);
 127            }
 28            else
 129            {
 130                type = SequenceType.Empty;
 131            }
 32
 133            int length = endIndex - startIndex;
 134            object endObject = end.GetObject();
 35
 136            if (type != SequenceType.MultiSegment && type != SequenceType.Empty && startObject != endObject)
 037                ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
 38
 139            if (type == SequenceType.MultiSegment)
 140            {
 141                Debug.Assert(startObject is ReadOnlySequenceSegment<T>);
 142                ReadOnlySequenceSegment<T> startSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(startObject);
 43
 144                if (startSegment != endObject)
 145                {
 146                    next = GetBufferCrossSegment(startIndex, endObject, ref startSegment, ref length);
 147                }
 48
 149                data = startSegment.Memory;
 150            }
 151            else if (type == SequenceType.Array)
 052            {
 053                Debug.Assert(startObject is T[]);
 54
 055                data = new ReadOnlyMemory<T>(Unsafe.As<T[]>(startObject));
 056            }
 157            else if (type == SequenceType.OwnedMemory)
 058            {
 059                Debug.Assert(startObject is OwnedMemory<T>);
 60
 061                data = (Unsafe.As<OwnedMemory<T>>(startObject)).Memory;
 062            }
 163            else if (typeof(T) == typeof(char) && type == SequenceType.String)
 064            {
 065                Debug.Assert(startObject is string);
 66
 067                data = (ReadOnlyMemory<T>)(object)(Unsafe.As<string>(startObject)).AsMemory();
 068            }
 69            else
 170            {
 171                data = default;
 172                return false;
 73            }
 74
 175            data = data.Slice(startIndex, length);
 176            return true;
 177        }
 78
 79        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 80        internal ReadOnlyMemory<T> GetFirstBuffer(in SequencePosition start, in SequencePosition end)
 181        {
 82            SequenceType type;
 183            int startIndex = 0;
 184            int endIndex = 0;
 185            object startObject = start.GetObject();
 186            if (startObject != null)
 187            {
 188                GetTypeAndIndices(start.GetInteger(), end.GetInteger(), out type, out startIndex, out endIndex);
 189            }
 90            else
 091            {
 092                type = SequenceType.Empty;
 093            }
 94
 195            int length = endIndex - startIndex;
 196            object endObject = end.GetObject();
 97
 198            if (type != SequenceType.MultiSegment && type != SequenceType.Empty && startObject != endObject)
 099                ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
 100
 101            ReadOnlyMemory<T> memory;
 1102            if (type == SequenceType.MultiSegment)
 1103            {
 1104                Debug.Assert(startObject is ReadOnlySequenceSegment<T>);
 1105                ReadOnlySequenceSegment<T> startSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(startObject);
 1106                memory = startSegment.Memory;
 1107                if (startObject != endObject)
 1108                {
 1109                    length = memory.Length - startIndex;
 1110                }
 1111            }
 1112            else if (type == SequenceType.Array)
 1113            {
 1114                Debug.Assert(startObject is T[]);
 115
 1116                memory = new ReadOnlyMemory<T>(Unsafe.As<T[]>(startObject));
 1117            }
 1118            else if (type == SequenceType.OwnedMemory)
 1119            {
 1120                Debug.Assert(startObject is OwnedMemory<T>);
 121
 1122                memory = (Unsafe.As<OwnedMemory<T>>(startObject)).Memory;
 1123            }
 1124            else if (typeof(T) == typeof(char) && type == SequenceType.String)
 1125            {
 1126                Debug.Assert(startObject is string);
 127
 1128                memory = (ReadOnlyMemory<T>)(object)(Unsafe.As<string>(startObject)).AsMemory();
 1129            }
 130            else
 0131            {
 0132                return default;
 133            }
 134
 1135            return memory.Slice(startIndex, length);
 1136        }
 137
 138        private static SequencePosition GetBufferCrossSegment(int startIndex, object endObject, ref ReadOnlySequenceSegm
 1139        {
 1140            Debug.Assert(startSegment != null);
 141
 1142            ReadOnlySequenceSegment<T> nextSegment = startSegment.Next;
 1143            int currentLength = startSegment.Memory.Length - startIndex;
 144
 1145            while (currentLength == 0 && nextSegment != endObject && nextSegment != null)
 1146            {
 147                // startSegment is at the end of a segment; move it to start of the next.
 148                // However, skip any empty segments, else the caller will immedately run out of data and call back
 1149                startSegment = nextSegment;
 1150                nextSegment = nextSegment.Next;
 1151                currentLength = startSegment.Memory.Length;
 1152            }
 153
 1154            length = currentLength;
 1155            while (nextSegment != null && nextSegment.Memory.Length == 0)
 1156            {
 157                // nextSegment is an empty segment, skip until one is found with data.
 1158                if (nextSegment == endObject)
 1159                {
 160                    // Reached the end and no segment with data found,
 161                    // set nextSegment to null as if there were no following segments.
 1162                    endObject = nextSegment = null;
 1163                    break;
 164                }
 165
 1166                nextSegment = nextSegment.Next;
 1167            }
 168
 1169            if (nextSegment != null)
 1170            {
 1171                return new SequencePosition(nextSegment, 0);
 172            }
 1173            else if (endObject != null)
 0174                ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
 175
 1176            return default;
 1177        }
 178
 179        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 180        internal SequencePosition Seek(in SequencePosition start, in SequencePosition end, int count)
 1181        {
 1182            GetTypeAndIndices(start.GetInteger(), end.GetInteger(), out SequenceType type, out int startIndex, out int e
 183
 1184            object startObject = start.GetObject();
 1185            object endObject = end.GetObject();
 186
 1187            bool notInRange = endIndex - startIndex < count;
 1188            if (type == SequenceType.MultiSegment && startObject != endObject)
 1189            {
 1190                Debug.Assert(startObject is ReadOnlySequenceSegment<T>);
 1191                var startSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(startObject);
 192
 1193                int currentLength = startSegment.Memory.Length - startIndex;
 1194                if (currentLength > count)
 1195                {
 196                    // Position in start segment, defer to single segment seek
 1197                    notInRange = false;
 1198                }
 199                else
 1200                {
 1201                    return SeekMultiSegment(startSegment, startIndex, endObject, endIndex, count - currentLength);
 202                }
 1203            }
 204            else
 1205            {
 1206                Debug.Assert(startObject == endObject);
 1207            }
 208
 1209            if (notInRange)
 1210                ThrowHelper.ThrowArgumentOutOfRangeException_CountOutOfRange();
 211
 212            // Single segment Seek
 1213            return new SequencePosition(startObject, startIndex + count);
 1214        }
 215
 216        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 217        internal SequencePosition Seek(in SequencePosition start, in SequencePosition end, long count)
 1218        {
 1219            GetTypeAndIndices(start.GetInteger(), end.GetInteger(), out SequenceType type, out int startIndex, out int e
 220
 1221            object startObject = start.GetObject();
 1222            object endObject = end.GetObject();
 223
 1224            bool notInRange = endIndex - startIndex < count;
 1225            if (type == SequenceType.MultiSegment && startObject != endObject)
 1226            {
 1227                Debug.Assert(startObject is ReadOnlySequenceSegment<T>);
 1228                var startSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(startObject);
 229
 1230                int currentLength = startSegment.Memory.Length - startIndex;
 1231                if (currentLength > count)
 1232                {
 233                    // Position in start segment, defer to single segment seek
 1234                    notInRange = false;
 1235                }
 236                else
 1237                {
 1238                    return SeekMultiSegment(startSegment, startIndex, endObject, endIndex, count - currentLength);
 239                }
 1240            }
 241            else
 1242            {
 1243                Debug.Assert(startObject == endObject);
 1244            }
 245
 1246            if (notInRange)
 1247                ThrowHelper.ThrowArgumentOutOfRangeException_CountOutOfRange();
 248
 249            // Single segment Seek
 1250            return new SequencePosition(startObject, startIndex + (int)count);
 1251        }
 252
 253        [MethodImpl(MethodImplOptions.NoInlining)]
 254        private static SequencePosition SeekMultiSegment(ReadOnlySequenceSegment<T> currentSegment, int startIndex, obje
 1255        {
 1256            Debug.Assert(currentSegment != null);
 1257            Debug.Assert(currentSegment.Next != null);
 1258            Debug.Assert(count >= 0);
 259
 260            // End of segment. Move to start of next.
 1261            currentSegment = currentSegment.Next;
 262
 1263            if (count > 0 || currentSegment.Memory.Length == 0)
 1264            {
 1265                while (currentSegment != null)
 1266                {
 1267                    bool isCurrentAtEnd = currentSegment == endObject;
 1268                    int memoryLength = isCurrentAtEnd ? endPosition : currentSegment.Memory.Length;
 269
 1270                    if (memoryLength > count || (memoryLength == count && isCurrentAtEnd))
 1271                    {
 272                        // Fully contained in this segment; or at end of segment but there isn't a next one to move to
 1273                        break;
 274                    }
 275
 276                    // Move to next
 1277                    count -= memoryLength;
 1278                    currentSegment = currentSegment.Next;
 1279                }
 1280            }
 281
 282            // Hit the end of the segments but didn't reach the count
 1283            if (currentSegment == null)
 1284                ThrowHelper.ThrowArgumentOutOfRangeException_CountOutOfRange();
 285
 1286            return new SequencePosition(currentSegment, (int)count);
 1287        }
 288
 289        private static void CheckEndReachable(object startSegment, object endSegment)
 1290        {
 1291            Debug.Assert(startSegment != null);
 1292            Debug.Assert(startSegment is ReadOnlySequenceSegment<T>);
 1293            Debug.Assert(endSegment != null);
 294
 1295            var current = Unsafe.As<ReadOnlySequenceSegment<T>>(startSegment);
 296
 1297            while (current.Next != null)
 1298            {
 1299                current = current.Next;
 1300                if (current == endSegment)
 1301                {
 302                    // Found end
 1303                    return;
 304                }
 1305            }
 306
 0307            ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
 1308        }
 309
 310        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 311        private long GetLength(in SequencePosition start, in SequencePosition end)
 1312        {
 1313            GetTypeAndIndices(start.GetInteger(), end.GetInteger(), out SequenceType type, out int startIndex, out int e
 314
 1315            object startObject = start.GetObject();
 1316            object endObject = end.GetObject();
 1317            if (type == SequenceType.MultiSegment && startObject != endObject)
 1318            {
 1319                Debug.Assert(startObject != null);
 1320                Debug.Assert(startObject is ReadOnlySequenceSegment<T>);
 1321                Debug.Assert(endObject != null);
 1322                Debug.Assert(endObject is ReadOnlySequenceSegment<T>);
 323
 1324                var startSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(startObject);
 1325                var endSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(endObject);
 326                // (end.RunningIndex + endIndex) - (start.RunningIndex + startIndex) // (End offset) - (start offset)
 1327                return endSegment.RunningIndex - startSegment.RunningIndex - startIndex + endIndex; // Rearranged to avo
 328            }
 329
 1330            Debug.Assert(startObject == endObject);
 331            // Single segment length
 1332            return endIndex - startIndex;
 1333        }
 334
 335        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 336        private void BoundsCheck(in SequencePosition start, in SequencePosition end)
 1337        {
 1338            GetTypeAndIndices(start.GetInteger(), end.GetInteger(), out SequenceType type, out int startIndex, out int e
 339
 1340            object startObject = start.GetObject();
 1341            object endObject = end.GetObject();
 1342            if (type == SequenceType.MultiSegment && startObject != endObject)
 1343            {
 1344                Debug.Assert(startObject != null);
 1345                Debug.Assert(startObject is ReadOnlySequenceSegment<T>);
 1346                Debug.Assert(endObject != null);
 1347                Debug.Assert(endObject is ReadOnlySequenceSegment<T>);
 348
 1349                var startSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(startObject);
 1350                var endSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(endObject);
 351
 352                // start.RunningIndex + startIndex <= end.RunningIndex + endIndex
 1353                if (startSegment.RunningIndex - endIndex <= endSegment.RunningIndex - startIndex) // Rearranged to avoid
 1354                {
 355                    // Mult-segment in bounds
 1356                    return;
 357                }
 1358            }
 1359            else if (startIndex <= endIndex)
 1360            {
 1361                Debug.Assert(startObject == endObject);
 362                // Single segment in bounds
 1363                return;
 364            }
 365
 1366            ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
 1367        }
 368
 369        internal bool TryGetReadOnlySequenceSegment(out ReadOnlySequenceSegment<T> startSegment, out int startIndex, out
 1370        {
 1371            GetTypeAndIndices(Start.GetInteger(), End.GetInteger(), out SequenceType type, out startIndex, out endIndex)
 372
 1373            if (type != SequenceType.MultiSegment)
 1374            {
 1375                startSegment = null;
 1376                endSegment = null;
 1377                return false;
 378            }
 379
 1380            Debug.Assert(Start.GetObject() != null);
 1381            Debug.Assert(Start.GetObject() is ReadOnlySequenceSegment<T>);
 1382            Debug.Assert(End.GetObject() != null);
 1383            Debug.Assert(End.GetObject() is ReadOnlySequenceSegment<T>);
 384
 1385            startSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(Start.GetObject());
 1386            endSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(End.GetObject());
 1387            return true;
 1388        }
 389
 390        internal bool TryGetArray(out ArraySegment<T> array)
 1391        {
 1392            GetTypeAndIndices(Start.GetInteger(), End.GetInteger(), out SequenceType type, out int startIndex, out int e
 393
 1394            if (type != SequenceType.Array)
 1395            {
 1396                array = default;
 1397                return false;
 398            }
 399
 1400            Debug.Assert(Start.GetObject() != null);
 1401            Debug.Assert(Start.GetObject() is T[]);
 402
 1403            array = new ArraySegment<T>(Unsafe.As<T[]>(Start.GetObject()), startIndex, endIndex - startIndex);
 1404            return true;
 1405        }
 406
 407        internal bool TryGetOwnedMemory(out OwnedMemory<T> ownedMemory, out int start, out int length)
 1408        {
 1409            GetTypeAndIndices(Start.GetInteger(), End.GetInteger(), out SequenceType type, out start, out int endIndex);
 410
 1411            if (type != SequenceType.OwnedMemory)
 1412            {
 1413                ownedMemory = default;
 1414                length = 0;
 1415                return false;
 416            }
 417
 1418            Debug.Assert(Start.GetObject() != null);
 1419            Debug.Assert(Start.GetObject() is OwnedMemory<T>);
 420
 1421            ownedMemory = Unsafe.As<OwnedMemory<T>>(Start.GetObject());
 1422            length = endIndex - start;
 1423            return true;
 1424        }
 425
 426        internal bool TryGetReadOnlyMemory(out ReadOnlyMemory<T> memory)
 1427        {
 1428            GetTypeAndIndices(Start.GetInteger(), End.GetInteger(), out SequenceType type, out int startIndex, out int e
 429
 1430            object startObject = Start.GetObject();
 1431            object endObject = End.GetObject();
 432
 1433            Debug.Assert(startObject != null);
 1434            Debug.Assert(endObject != null);
 435
 1436            int length = endIndex - startIndex;
 1437            if (startObject != endObject)
 1438            {
 439                // Can't get ReadOnlyMemory from multi-block segments
 1440                memory = default;
 1441                return false;
 442            }
 1443            else if (type == SequenceType.Array)
 1444            {
 1445                Debug.Assert(startObject is T[]);
 446
 1447                memory = new ReadOnlyMemory<T>(Unsafe.As<T[]>(startObject));
 1448            }
 1449            else if (type == SequenceType.OwnedMemory)
 1450            {
 1451                Debug.Assert(startObject is OwnedMemory<T>);
 452
 1453                memory = Unsafe.As<OwnedMemory<T>>(startObject).Memory;
 1454            }
 1455            else if (typeof(T) == typeof(char) && type == SequenceType.String)
 1456            {
 1457                Debug.Assert(startObject is string);
 458
 1459                var text = Unsafe.As<string>(startObject);
 1460                memory = (ReadOnlyMemory<T>)(object)text.AsMemory();
 1461            }
 462            else // ReadOnlySequenceSegment
 1463            {
 1464                Debug.Assert(startObject is ReadOnlySequenceSegment<T>);
 465
 1466                memory = Unsafe.As<ReadOnlySequenceSegment<T>>(startObject).Memory;
 1467            }
 468
 1469            memory = memory.Slice(startIndex, length);
 1470            return true;
 1471        }
 472
 473        internal bool TryGetString(out string text, out int start, out int length)
 474        {
 475            if (typeof(T) != typeof(char))
 476            {
 477                start = 0;
 478                length = 0;
 479                text = null;
 480                return false;
 481            }
 482
 483            GetTypeAndIndices(Start.GetInteger(), End.GetInteger(), out SequenceType type, out int startIndex, out int e
 484
 485            if (type != SequenceType.String)
 486            {
 487                start = 0;
 488                length = 0;
 489                text = null;
 490                return false;
 491            }
 492
 493            start = startIndex;
 494            length = endIndex - startIndex;
 495            text = (string)Start.GetObject();
 496
 497            return true;
 498        }
 499    }
 500}

Methods/Properties

.cctor()
Length()
IsEmpty()
IsSingleSegment()
First()
Start()
End()
.ctor(System.Object,System.Int32,System.Object,System.Int32)
.ctor(System.Buffers.ReadOnlySequenceSegment`1<T>,System.Int32,System.Buffers.ReadOnlySequenceSegment`1<T>,System.Int32)
.ctor(T[])
.ctor(T[],System.Int32,System.Int32)
.ctor(System.ReadOnlyMemory`1<T>)
.ctor(System.Buffers.OwnedMemory`1<T>)
.ctor(System.Buffers.OwnedMemory`1<T>,System.Int32,System.Int32)
Slice(System.Int64,System.Int64)
Slice(System.Int64,System.SequencePosition)
Slice(System.SequencePosition,System.Int64)
Slice(System.Int32,System.Int32)
Slice(System.Int32,System.SequencePosition)
Slice(System.SequencePosition,System.Int32)
Slice(System.SequencePosition,System.SequencePosition)
Slice(System.SequencePosition)
Slice(System.Int64)
ToString()
GetEnumerator()
GetPosition(System.Int64)
GetPosition(System.Int64,System.SequencePosition)
TryGet(System.SequencePosition&,System.ReadOnlyMemory`1<T>&,System.Boolean)
SliceImpl(System.SequencePosition&,System.SequencePosition&)
GetTypeAndIndices(System.Int32,System.Int32,System.Buffers.ReadOnlySequence`1/SequenceType<T>&,System.Int32&,System.Int32&)
.ctor(System.Buffers.ReadOnlySequence`1<T>&)
Current()
MoveNext()
TryGetBuffer(System.SequencePosition&,System.SequencePosition&,System.ReadOnlyMemory`1<T>&,System.SequencePosition&)
GetFirstBuffer(System.SequencePosition&,System.SequencePosition&)
GetBufferCrossSegment(System.Int32,System.Object,System.Buffers.ReadOnlySequenceSegment`1<T>&,System.Int32&)
Seek(System.SequencePosition&,System.SequencePosition&,System.Int32)
Seek(System.SequencePosition&,System.SequencePosition&,System.Int64)
SeekMultiSegment(System.Buffers.ReadOnlySequenceSegment`1<T>,System.Int32,System.Object,System.Int32,System.Int64)
CheckEndReachable(System.Object,System.Object)
GetLength(System.SequencePosition&,System.SequencePosition&)
BoundsCheck(System.SequencePosition&,System.SequencePosition&)
TryGetReadOnlySequenceSegment(System.Buffers.ReadOnlySequenceSegment`1<T>&,System.Int32&,System.Buffers.ReadOnlySequenceSegment`1<T>&,System.Int32&)
TryGetArray(System.ArraySegment`1<T>&)
TryGetOwnedMemory(System.Buffers.OwnedMemory`1<T>&,System.Int32&,System.Int32&)
TryGetReadOnlyMemory(System.ReadOnlyMemory`1<T>&)