using System; using System.Buffers; using System.Collections.Generic; using System.Numerics; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Tests.Memory { internal class TestMemoryAllocator : MemoryAllocator { private List allocationLog = new List(); public TestMemoryAllocator(byte dirtyValue = 42) { this.DirtyValue = dirtyValue; } /// /// The value to initialize the result buffer with, with non-clean options () /// public byte DirtyValue { get; } public IList AllocationLog => this.allocationLog; public override IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None) { T[] array = this.AllocateArray(length, options); return new BasicArrayBuffer(array, length); } public override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None) { byte[] array = this.AllocateArray(length, options); return new ManagedByteBuffer(array); } private T[] AllocateArray(int length, AllocationOptions options) where T : struct { this.allocationLog.Add(AllocationRequest.Create(options, length)); var array = new T[length + 42]; if (options == AllocationOptions.None) { Span data = MemoryMarshal.Cast(array.AsSpan()); data.Fill(this.DirtyValue); } return array; } public struct AllocationRequest { private AllocationRequest(Type elementType, AllocationOptions allocationOptions, int length, int lengthInBytes) { this.ElementType = elementType; this.AllocationOptions = allocationOptions; this.Length = length; this.LengthInBytes = lengthInBytes; if (elementType == typeof(Vector4)) { } } public static AllocationRequest Create(AllocationOptions allocationOptions, int length) { Type type = typeof(T); int elementSize = Marshal.SizeOf(type); return new AllocationRequest(type, allocationOptions, length, length * elementSize); } public Type ElementType { get; } public AllocationOptions AllocationOptions { get; } public int Length { get; } public int LengthInBytes { get; } } /// /// Wraps an array as an instance. /// private class BasicArrayBuffer : MemoryManager where T : struct { private GCHandle pinHandle; /// /// Initializes a new instance of the class /// /// The array /// The length of the buffer public BasicArrayBuffer(T[] array, int length) { DebugGuard.MustBeLessThanOrEqualTo(length, array.Length, nameof(length)); this.Array = array; this.Length = length; } /// /// Initializes a new instance of the class /// /// The array public BasicArrayBuffer(T[] array) : this(array, array.Length) { } /// /// Gets the array /// public T[] Array { get; } /// /// Gets the length /// public int Length { get; } /// public override Span GetSpan() => this.Array.AsSpan(0, this.Length); public override unsafe MemoryHandle Pin(int elementIndex = 0) { if (!this.pinHandle.IsAllocated) { this.pinHandle = GCHandle.Alloc(this.Array, GCHandleType.Pinned); } void* ptr = (void*)this.pinHandle.AddrOfPinnedObject(); return new MemoryHandle(ptr, this.pinHandle); } public override void Unpin() { throw new NotImplementedException(); } /// protected override void Dispose(bool disposing) { } } private class ManagedByteBuffer : BasicArrayBuffer, IManagedByteBuffer { public ManagedByteBuffer(byte[] array) : base(array) { } } } }