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 = [];
}
}
}