DotNext by .NET Foundation and Contributors

<PackageReference Include="DotNext" Version="4.2.0-beta.2" />

 BufferWriterSlim<T>

public struct BufferWriterSlim<T>
Represents stack-allocated buffer writer.
using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; 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> { [StructLayout(LayoutKind.Auto)] internal readonly ref struct Ref { [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ReadOnlySpan<byte> reference; [DebuggerBrowsable(DebuggerBrowsableState.Never)] internal ref BufferWriterSlim<T> Value { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return ref <get_Value>g__AsWriter|3_0(ref MemoryMarshal.GetReference<byte>(reference)); } } internal Ref(ref BufferWriterSlim<T> writer) { reference = MemoryMarshal.CreateSpan<byte>(ref <.ctor>g__AsRef|1_0(ref writer), BufferWriterSlim<T>.Size); } } private readonly Span<T> initialBuffer; private readonly MemoryAllocator<T> allocator; private MemoryOwner<T> extraBuffer; private int position; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private unsafe static int Size { get { return sizeof(BufferWriterSlim<T>); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] [ExcludeFromCodeCoverage] 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; } } private bool NoOverflow { [IsReadOnly] get { return position <= initialBuffer.Length; } } [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public ReadOnlySpan<T> WrittenSpan { [IsReadOnly] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] get { return (NoOverflow ? initialBuffer : extraBuffer.Span).Slice(0, position); } } public ref T this[int index] { [IsReadOnly] get { if ((uint)index >= (uint)position) throw new ArgumentOutOfRangeException("index"); return ref Unsafe.Add<T>(ref NoOverflow ? ref MemoryMarshal.GetReference<T>(initialBuffer) : ref extraBuffer.First, 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"); int newSize; Span<T> span; if (extraBuffer.IsEmpty) { int length = initialBuffer.Length; int writtenCount = position; if (((IGrowableBuffer<T>)).GetBufferSize(sizeHint, length, writtenCount, out newSize)) { extraBuffer = MemoryAllocator.Invoke<T>(allocator, newSize, false); initialBuffer.CopyTo(span = extraBuffer.Span); } else span = initialBuffer; } else { int length2 = extraBuffer.Length; int writtenCount2 = position; if (((IGrowableBuffer<T>)).GetBufferSize(sizeHint, length2, writtenCount2, out newSize)) BufferHelpers.Resize<T>(ref extraBuffer, newSize, false, allocator); span = extraBuffer.Span; } return span.Slice(position); } public void Advance(int count) { if (count < 0) <Advance>g__ThrowArgumentOutOfRangeException|22_0(); if (position > Capacity - count) <Advance>g__ThrowInvalidOperationException|22_1(); 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) { MemoryMarshal.GetReference<T>(GetSpan(1)) = item; position++; } public bool TryDetachBuffer([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] out MemoryOwner<T> owner) { if (NoOverflow) { owner = default(MemoryOwner<T>); return false; } owner = extraBuffer; owner.Truncate(position); position = 0; extraBuffer = default(MemoryOwner<T>); return true; } public void Clear(bool reuseBuffer = false) { initialBuffer.Clear(); if (!reuseBuffer) extraBuffer.Dispose(); else if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) { extraBuffer.Span.Clear(); } position = 0; } public void Dispose() { if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) initialBuffer.Clear(); extraBuffer.Dispose(); this = default(BufferWriterSlim<T>); } [IsReadOnly] public override string ToString() { return WrittenSpan.ToString(); } } }