DotNext by Roman Sakno

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

 BufferWriterSlim<T>

public struct BufferWriterSlim<T>
Represents stack-allocated buffer builder.
using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace DotNext.Buffers { [StructLayout(LayoutKind.Auto)] [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] [DebuggerDisplay("WrittenCount = {WrittenCount}, FreeCapacity = {FreeCapacity}, Overflow = {Overflow}")] public ref struct BufferWriterSlim<[System.Runtime.CompilerServices.Nullable(2)] T> { [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] private readonly Span<T> initialBuffer; [System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1 })] private readonly MemoryAllocator<T> allocator; [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] private MemoryOwner<T> extraBuffer; private int position; private int Overflow { [IsReadOnly] get { return Math.Max(0, position - initialBuffer.Length); } } public int WrittenCount { [IsReadOnly] get { return position; } } public int Capacity { [IsReadOnly] get { if (!extraBuffer.IsEmpty) return extraBuffer.Length; return initialBuffer.Length; } } public int FreeCapacity { [IsReadOnly] get { return Capacity - WrittenCount; } } [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public ReadOnlySpan<T> WrittenSpan { [IsReadOnly] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] get { return ((position <= initialBuffer.Length) ? initialBuffer : extraBuffer.Memory.Span).Slice(0, position); } } public ref T this[int index] { [IsReadOnly] get { if (index < 0 || index >= position) throw new ArgumentOutOfRangeException("index"); return ref Unsafe.Add<T>(ref MemoryMarshal.GetReference<T>((position <= initialBuffer.Length) ? initialBuffer : extraBuffer.Memory.Span), index); } } public BufferWriterSlim([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] Span<T> buffer, [System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1 })] MemoryAllocator<T> allocator = null) { initialBuffer = buffer; this.allocator = allocator; extraBuffer = default(MemoryOwner<T>); position = 0; } public BufferWriterSlim(int initialCapacity, [System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1 })] MemoryAllocator<T> allocator = null) { if (initialCapacity < 0) throw new ArgumentOutOfRangeException("initialCapacity"); initialBuffer = default(Span<T>); this.allocator = allocator; extraBuffer = ((initialCapacity == 0) ? default(MemoryOwner<T>) : MemoryAllocator.Invoke<T>(allocator, initialCapacity, false)); position = 0; } [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public Span<T> GetSpan(int sizeHint = 0) { if (sizeHint < 0) throw new ArgumentOutOfRangeException("sizeHint"); Memory<T> memory; Span<T> span; if (extraBuffer.IsEmpty) { int length = initialBuffer.Length; int writtenCount = position; int? bufferSize = ((IGrowableBuffer<T>)).GetBufferSize(sizeHint, length, writtenCount); if (bufferSize.HasValue) { extraBuffer = MemoryAllocator.Invoke<T>(allocator, bufferSize.GetValueOrDefault(), false); ref Span<T> reference = ref initialBuffer; memory = extraBuffer.Memory; reference.CopyTo(memory.Span); initialBuffer.Clear(); memory = extraBuffer.Memory; span = memory.Span; } else span = initialBuffer; } else { int length2 = extraBuffer.Length; int writtenCount2 = position; int? bufferSize = ((IGrowableBuffer<T>)).GetBufferSize(sizeHint, length2, writtenCount2); if (bufferSize.HasValue) { MemoryOwner<T> memoryOwner = MemoryAllocator.Invoke<T>(allocator, bufferSize.GetValueOrDefault(), false); memory = extraBuffer.Memory; memory.CopyTo(memoryOwner.Memory); extraBuffer.Dispose(); extraBuffer = memoryOwner; } memory = extraBuffer.Memory; span = memory.Span; } return span.Slice(position); } public void Advance(int count) { if (count < 0) throw new ArgumentOutOfRangeException("count"); if (position > Capacity - count) throw new InvalidOperationException(); position += count; } public void Write([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] ReadOnlySpan<T> input) { if (!input.IsEmpty) { input.CopyTo(GetSpan(input.Length)); position += input.Length; } } public void Add(T item) { Write(MemoryMarshal.CreateReadOnlySpan<T>(ref item, 1)); } public void Clear(bool reuseBuffer) { initialBuffer.Clear(); if (!reuseBuffer) { extraBuffer.Dispose(); extraBuffer = default(MemoryOwner<T>); } else if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) { extraBuffer.Memory.Span.Clear(); } position = 0; } public void Dispose() { extraBuffer.Dispose(); this = default(BufferWriterSlim<T>); } public override string ToString() { return WrittenSpan.ToString(); } } }