using System.Buffers; namespace UglyToad.PdfPig.Core; /// /// Pooled Buffer Writer /// public sealed class ArrayPoolBufferWriter : IBufferWriter, IDisposable { private const int DefaultBufferSize = 256; private T[] buffer; private int position; /// /// PooledBufferWriter constructor /// public ArrayPoolBufferWriter() { buffer = ArrayPool.Shared.Rent(DefaultBufferSize); position = 0; } /// /// Constructs a PooledBufferWriter /// /// The size of the initial buffer public ArrayPoolBufferWriter(int size) { buffer = ArrayPool.Shared.Rent(size); position = 0; } /// /// Advanced the current position /// /// public void Advance(int count) { position += count; } /// /// Writes the provided value /// public void Write(T value) { GetSpan(1)[0] = value; position += 1; } /// /// Writes the provided values /// /// public void Write(ReadOnlySpan values) { values.CopyTo(GetSpan(values.Length)); position += values.Length; } /// /// Returns a writeable block of memory that can be written to /// public Memory GetMemory(int sizeHint = 0) { EnsureCapacity(sizeHint); return buffer.AsMemory(position); } /// /// Returns a span that can be written to /// public Span GetSpan(int sizeHint = 0) { EnsureCapacity(sizeHint); return buffer.AsSpan(position); } /// /// Returns the number of bytes written to the buffer /// public int WrittenCount => position; /// /// Returns the committed data as Memory /// public ReadOnlyMemory WrittenMemory => buffer.AsMemory(0, position); /// /// Returns the committed data as a Span /// public ReadOnlySpan WrittenSpan => buffer.AsSpan(0, position); private void EnsureCapacity(int sizeHint) { if (sizeHint is 0) { sizeHint = 1; } if (sizeHint > RemainingBytes) { var newBuffer = ArrayPool.Shared.Rent(Math.Max(position + sizeHint, 512)); if (buffer.Length != 0) { Array.Copy(buffer, 0, newBuffer, 0, position); ArrayPool.Shared.Return(buffer); } buffer = newBuffer; } } private int RemainingBytes => buffer.Length - position; /// /// Resets the internal state so the instance can be reused before disposal /// /// public void Reset(bool clearArray = false) { position = 0; if (clearArray) { buffer.AsSpan().Clear(); } } /// /// Disposes the buffer and returns any rented memory to the pool /// public void Dispose() { if (buffer.Length != 0) { ArrayPool.Shared.Return(buffer); buffer = []; } } }