// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System; using System.Buffers; using System.Runtime.CompilerServices; namespace SixLabors.Fonts { /// /// An disposable buffer that is backed by an array pool. /// /// The type of buffer element. internal ref struct Buffer where T : unmanaged { private int length; private readonly byte[] buffer; private readonly Span span; private bool isDisposed; public Buffer(int length) : this(length, clear: false) { } public Buffer(int length, bool clear) { Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length)); int itemSizeBytes = Unsafe.SizeOf(); int bufferSizeInBytes = length * itemSizeBytes; this.buffer = ArrayPool.Shared.Rent(bufferSizeInBytes); this.length = length; using ByteMemoryManager manager = new(this.buffer); this.Memory = manager.Memory[..this.length]; this.span = this.Memory.Span; if (clear) { this.span.Clear(); } this.isDisposed = false; } public Memory Memory { get; } public readonly Span GetSpan() { if (this.buffer is null) { ThrowObjectDisposedException(); } return this.span; } public void Dispose() { if (this.isDisposed) { return; } ArrayPool.Shared.Return(this.buffer); this.length = 0; this.isDisposed = true; } [MethodImpl(MethodImplOptions.NoInlining)] private static void ThrowObjectDisposedException() => throw new ObjectDisposedException("Buffer"); } }