DotNext by Roman Sakno

<PackageReference Include="DotNext" Version="2.8.0" />

 ChunkSequence<T>

Represents sequence of memory chunks.
using System; using System.Buffers; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace DotNext.Buffers { [StructLayout(LayoutKind.Auto)] public readonly struct ChunkSequence<[System.Runtime.CompilerServices.Nullable(2)] T> : IEnumerable<ReadOnlyMemory<T>>, IEnumerable { [StructLayout(LayoutKind.Auto)] public struct Enumerator : IEnumerator<ReadOnlyMemory<T>>, IEnumerator, IDisposable { [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] private readonly ReadOnlyMemory<T> source; private readonly int chunkSize; private int startIndex; private int length; [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public ReadOnlyMemory<T> Current { [IsReadOnly] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] get { return source.Slice(startIndex, length); } } [System.Runtime.CompilerServices.Nullable(1)] object IEnumerator.Current { [IsReadOnly] [System.Runtime.CompilerServices.NullableContext(1)] get { return Current; } } internal Enumerator([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] ReadOnlyMemory<T> source, int chunkSize) { this.source = source; this.chunkSize = chunkSize; startIndex = (length = -1); } void IDisposable.Dispose() { this = default(Enumerator); } public bool MoveNext() { if (startIndex == -1) { startIndex = 0; length = Math.Min(chunkSize, source.Length); } else { startIndex += chunkSize; length = Math.Min(source.Length - startIndex, chunkSize); } return startIndex < source.Length; } public void Reset() { startIndex = -1; } } [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] private readonly ReadOnlyMemory<T> memory; private readonly int chunkSize; public ChunkSequence([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] ReadOnlyMemory<T> memory, int chunkSize) { if (chunkSize < 1) throw new ArgumentOutOfRangeException("chunkSize"); this.chunkSize = chunkSize; this.memory = memory; } public Enumerator GetEnumerator() { return new Enumerator(memory, chunkSize); } [return: System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0, 1 })] IEnumerator<ReadOnlyMemory<T>> IEnumerable<ReadOnlyMemory<T>>.GetEnumerator() { return GetEnumerator(); } [System.Runtime.CompilerServices.NullableContext(1)] IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public ReadOnlySequence<T> ToReadOnlySequence() { if (memory.IsEmpty) return ReadOnlySequence<T>.Empty; if (memory.Length < chunkSize) return new ReadOnlySequence<T>(memory); Chunk<T> first = null; Chunk<T> last = null; using (Enumerator enumerator = GetEnumerator()) { while (enumerator.MoveNext()) { Chunk<T>.AddChunk(enumerator.Current, ref first, ref last); } } return Chunk<T>.CreateSequence(first, last); } public static explicit operator ReadOnlySequence<T>([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] ChunkSequence<T> sequence) { return sequence.ToReadOnlySequence(); } } }