DotNext by .NET Foundation and Contributors

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

 PooledArrayBufferWriter<T>

Represents memory writer that is backed by the array obtained from the pool.
using DotNext.Runtime; using System; using System.Buffers; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace DotNext.Buffers { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public sealed class PooledArrayBufferWriter<[System.Runtime.CompilerServices.Nullable(2)] T> : BufferWriter<T>, ISupplier<ArraySegment<T>>, IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable { private readonly ArrayPool<T> pool; private T[] buffer; int ICollection<T>.Count { get { return base.WrittenCount; } } bool ICollection<T>.IsReadOnly { get { return false; } } public new ref T this[int index] { get { return ref this[(long)index]; } } public unsafe ref T this[long index] { get { ThrowIfDisposed(); if ((ulong)index >= (ulong)position) throw new ArgumentOutOfRangeException("index"); return ref Unsafe.Add<T>(ref MemoryMarshal.GetArrayDataReference<T>(buffer), (IntPtr)(void*)index); } } T IList<T>.this[int index] { get { return this[index]; } set { this[index] = value; } } public override int Capacity { get { ThrowIfDisposed(); return buffer.Length; } } [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public override ReadOnlyMemory<T> WrittenMemory { [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] get { ThrowIfDisposed(); return new Memory<T>(buffer, 0, position); } } [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public ArraySegment<T> WrittenArray { [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] get { ThrowIfDisposed(); return new ArraySegment<T>(buffer, 0, position); } } public PooledArrayBufferWriter(ArrayPool<T> pool, int initialCapacity) { if (initialCapacity <= 0) throw new ArgumentOutOfRangeException("initialCapacity"); this.pool = pool; buffer = pool.Rent(initialCapacity); } public PooledArrayBufferWriter(ArrayPool<T> pool) { this.pool = pool; buffer = Array.Empty<T>(); } public PooledArrayBufferWriter() : this(ArrayPool<T>.Shared) { } public PooledArrayBufferWriter(int initialCapacity) : this(ArrayPool<T>.Shared, initialCapacity) { } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { WrittenMemory.CopyTo(MemoryExtensions.AsMemory<T>(array, arrayIndex)); } int IList<T>.IndexOf(T item) { ThrowIfDisposed(); return Array.IndexOf<T>(buffer, item, 0, position); } bool ICollection<T>.Contains(T item) { ThrowIfDisposed(); return Array.IndexOf<T>(buffer, item, 0, position) >= 0; } private void RemoveAt(int index) { Array.Copy(buffer, (long)index + 1, buffer, index, (long)(position - index) - 1); buffer[position - 1] = default(T); if (--position == 0) { ReleaseBuffer(); buffer = Array.Empty<T>(); } } void IList<T>.RemoveAt(int index) { ThrowIfDisposed(); if ((uint)index >= (uint)position) throw new ArgumentOutOfRangeException("index"); RemoveAt(index); } bool ICollection<T>.Remove(T item) { ThrowIfDisposed(); int num = Array.IndexOf<T>(buffer, item, 0, position); if (num < 0) return false; RemoveAt(num); return true; } void IList<T>.Insert(int index, T item) { Insert(index, MemoryMarshal.CreateReadOnlySpan<T>(ref item, 1)); } public void Insert(int index, [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] ReadOnlySpan<T> items) { ThrowIfDisposed(); if ((uint)index > (uint)position) throw new ArgumentOutOfRangeException("index"); if (!items.IsEmpty) { if (Intrinsics.GetLength(buffer) == (IntPtr)0) buffer = pool.Rent(items.Length); else if ((long)(position + items.Length) <= (long)Intrinsics.GetLength(buffer)) { Array.Copy(buffer, index, buffer, index + items.Length, position - index); } else { T[] destinationArray = pool.Rent(buffer.Length + items.Length); Array.Copy(buffer, 0, destinationArray, 0, index); Array.Copy(buffer, index, destinationArray, index + items.Length, buffer.LongLength - index); ReleaseBuffer(); buffer = destinationArray; } items.CopyTo(MemoryExtensions.AsSpan<T>(buffer, index)); position += items.Length; } } public void Overwrite(int index, [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] ReadOnlySpan<T> items) { ThrowIfDisposed(); if ((uint)index > (uint)position) throw new ArgumentOutOfRangeException("index"); if (Intrinsics.GetLength(buffer) == (IntPtr)0) buffer = pool.Rent(items.Length); else if ((long)(index + items.Length) <= (long)Intrinsics.GetLength(buffer)) { if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) Array.Clear(buffer, index, position - index); } else { T[] destinationArray = pool.Rent(index + items.Length); Array.Copy(buffer, 0, destinationArray, 0, index); ReleaseBuffer(); buffer = destinationArray; } items.CopyTo(MemoryExtensions.AsSpan<T>(buffer, index)); position = index + items.Length; } void ICollection<T>.Clear() { Clear(false); } [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] ArraySegment<T> ISupplier<ArraySegment<T>>.Invoke() { return WrittenArray; } private void ReleaseBuffer() { if ((long)Intrinsics.GetLength(buffer) > 0) pool.Return(buffer, RuntimeHelpers.IsReferenceOrContainsReferences<T>()); } public override void Clear(bool reuseBuffer = false) { ThrowIfDisposed(); if (!reuseBuffer) { ReleaseBuffer(); buffer = Array.Empty<T>(); } else if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) { Array.Clear(buffer, 0, position); } position = 0; } [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public override MemoryOwner<T> DetachBuffer() { ThrowIfDisposed(); MemoryOwner<T> result; if (position > 0) { result = new MemoryOwner<T>(pool, buffer, position); buffer = Array.Empty<T>(); position = 0; } else result = default(MemoryOwner<T>); return result; } [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public override Memory<T> GetMemory(int sizeHint = 0) { if (sizeHint < 0) throw new ArgumentOutOfRangeException("sizeHint"); CheckAndResizeBuffer(sizeHint); return MemoryExtensions.AsMemory<T>(buffer, position); } [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public override Span<T> GetSpan(int sizeHint = 0) { if (sizeHint < 0) throw new ArgumentOutOfRangeException("sizeHint"); CheckAndResizeBuffer(sizeHint); return MemoryExtensions.AsSpan<T>(buffer, position); } [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public ArraySegment<T> GetArray(int sizeHint = 0) { if (sizeHint < 0) throw new ArgumentOutOfRangeException("sizeHint"); CheckAndResizeBuffer(sizeHint); return new ArraySegment<T>(buffer, position, buffer.Length - position); } public override void AddAll(ICollection<T> items) { ThrowIfDisposed(); int count = items.Count; if (count > 0) { CheckAndResizeBuffer(count); items.CopyTo(buffer, position); position += count; } } public void RemoveLast(int count) { if (count < 0) throw new ArgumentOutOfRangeException("count"); ThrowIfDisposed(); if (count >= position) { ReleaseBuffer(); buffer = Array.Empty<T>(); position = 0; } else if (count > 0) { int num = position - count; if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) Array.Clear(buffer, num, position - num); position = num; } } public void RemoveFirst(int count) { if (count < 0) throw new ArgumentOutOfRangeException("count"); ThrowIfDisposed(); if (count >= position) { ReleaseBuffer(); buffer = Array.Empty<T>(); position = 0; } else if (count > 0) { int num = position - count; T[] destinationArray = pool.Rent(num); Array.Copy(buffer, count, destinationArray, 0, num); ReleaseBuffer(); buffer = destinationArray; position = num; } } private protected override void Resize(int newSize) { T[] array = pool.Rent(newSize); buffer.CopyTo(array, 0); ReleaseBuffer(); buffer = array; base.AllocationCounter?.WriteMetric((float)array.LongLength); } protected override void Dispose(bool disposing) { if (disposing) { base.BufferSizeCallback?.Invoke(buffer.Length); ReleaseBuffer(); buffer = Array.Empty<T>(); } base.Dispose(disposing); } } }