DotNext by .NET Foundation and Contributors

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

 ReadOnlySequencePartitioner<T>

using DotNext.Collections.Generic; using System; using System.Buffers; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace DotNext.Buffers { internal sealed class ReadOnlySequencePartitioner<T> : OrderablePartitioner<T> { private sealed class SegmentProvider : IEnumerable<KeyValuePair<long, T>>, IEnumerable { private long runningIndex; private ReadOnlySequence<T>.Enumerator enumerator; internal SegmentProvider(ReadOnlySequence<T> sequence) { enumerator = sequence.GetEnumerator(); } [MethodImpl(MethodImplOptions.Synchronized)] private ReadOnlyMemory<T> NextSegment(out long startIndex) { startIndex = runningIndex; ReadOnlyMemory<T> result = enumerator.MoveNext() ? enumerator.Current : ReadOnlyMemory<T>.Empty; runningIndex += result.Length; return result; } public unsafe IEnumerator<KeyValuePair<long, T>> GetEnumerator() { ReadOnlyMemory<T> segment; do { segment = this.NextSegment(out long startIndex); IntPtr i = (IntPtr)0; while ((long)i < (long)segment.Length) { yield return new KeyValuePair<long, T>(startIndex, Unsafe.Add<T>(ref MemoryMarshal.GetReference<T>(segment.Span), i)); i = (IntPtr)(void*)((long)i + 1); startIndex++; } } while (!segment.IsEmpty); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } private readonly ReadOnlySequence<T> sequence; public override bool SupportsDynamicPartitions => !base.KeysOrderedAcrossPartitions; internal ReadOnlySequencePartitioner([In] [IsReadOnly] ref ReadOnlySequence<T> sequence, bool loadBalance) : base(true, !loadBalance, true) { this.sequence = sequence; } private static IEnumerator<KeyValuePair<long, T>> CreatePartition(long startIndex, [In] [IsReadOnly] ref ReadOnlySequence<T> partition) { return <CreatePartition>g__CreatePartition|3_0(startIndex, partition.GetEnumerator()); } private void GetOrderableStaticPartitions(IEnumerator<KeyValuePair<long, T>>[] partitions) { (long, long) valueTuple = Math.DivRem(sequence.Length, (long)partitions.Length); long item = valueTuple.Item1; long item2 = valueTuple.Item2; long num = 0; for (int i = 0; i < partitions.Length; i++) { long num2 = (i < item2) ? (item + 1) : item; int num3 = i; long startIndex = num; ReadOnlySequence<T> partition = sequence.Slice(num, num2); partitions[num3] = CreatePartition(startIndex, ref partition); num += num2; } } private unsafe void GetOrderableDynamicPartitions(IEnumerator<KeyValuePair<long, T>>[] partitions) { OneDimensionalArray.ForEach<IEnumerator<KeyValuePair<long, T>>, IEnumerable<KeyValuePair<long, T>>>(partitions, (IntPtr)(void*), GetOrderableDynamicPartitions()); } public override IList<IEnumerator<KeyValuePair<long, T>>> GetOrderablePartitions(int partitionCount) { if (partitionCount <= 0) throw new ArgumentOutOfRangeException("partitionCount"); IEnumerator<KeyValuePair<long, T>>[] array = new IEnumerator<KeyValuePair<long, T>>[partitionCount]; if (SupportsDynamicPartitions) GetOrderableDynamicPartitions(array); else GetOrderableStaticPartitions(array); return array; } public override IEnumerable<KeyValuePair<long, T>> GetOrderableDynamicPartitions() { return new SegmentProvider(sequence); } public override IList<IEnumerator<T>> GetPartitions(int partitionCount) { if (partitionCount <= 0) throw new ArgumentOutOfRangeException("partitionCount"); IEnumerator<T>[] array = new IEnumerator<T>[partitionCount]; (long, long) valueTuple = Math.DivRem(sequence.Length, (long)array.Length); long item = valueTuple.Item1; long item2 = valueTuple.Item2; SequencePosition start = sequence.Start; for (int i = 0; i < array.Length; i++) { long length = (i < item2) ? (item + 1) : item; ReadOnlySequence<T> readOnlySequence = sequence.Slice(start, length); array[i] = Sequence.ToEnumerator<T>(ref readOnlySequence); start = readOnlySequence.End; } return array; } } }