-
-
Notifications
You must be signed in to change notification settings - Fork 47
Expand file tree
/
Copy pathTestMemoryAllocator.cs
More file actions
151 lines (117 loc) · 4.7 KB
/
Copy pathTestMemoryAllocator.cs
File metadata and controls
151 lines (117 loc) · 4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using System.Numerics;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Drawing.Tests;
internal class TestMemoryAllocator : MemoryAllocator
{
private readonly List<AllocationRequest> allocationLog = [];
private readonly List<ReturnRequest> returnLog = [];
public TestMemoryAllocator(byte dirtyValue = 42) => this.DirtyValue = dirtyValue;
/// <summary>
/// Gets the value to initialize the result buffer with, with non-clean options (<see cref="AllocationOptions.None"/>)
/// </summary>
public byte DirtyValue { get; }
public int BufferCapacityInBytes { get; set; } = int.MaxValue;
public IReadOnlyList<AllocationRequest> AllocationLog => this.allocationLog;
public IReadOnlyList<ReturnRequest> ReturnLog => this.returnLog;
protected internal override int GetBufferCapacityInBytes() => this.BufferCapacityInBytes;
protected override AllocationTrackedMemoryManager<T> AllocateCore<T>(int length, AllocationOptions options = AllocationOptions.None)
{
T[] array = this.AllocateArray<T>(length, options);
return new BasicArrayBuffer<T>(array, length, this);
}
private T[] AllocateArray<T>(int length, AllocationOptions options)
where T : struct
{
T[] array = new T[length + 42];
this.allocationLog.Add(AllocationRequest.Create(options, length, array));
if (options == AllocationOptions.None)
{
Span<byte> data = MemoryMarshal.Cast<T, byte>(array.AsSpan());
data.Fill(this.DirtyValue);
}
return array;
}
private void Return<T>(BasicArrayBuffer<T> buffer)
where T : struct => this.returnLog.Add(new ReturnRequest(buffer.Array.GetHashCode()));
public struct AllocationRequest
{
private AllocationRequest(Type elementType, AllocationOptions allocationOptions, int length, int lengthInBytes, int hashCodeOfBuffer)
{
this.ElementType = elementType;
this.AllocationOptions = allocationOptions;
this.Length = length;
this.LengthInBytes = lengthInBytes;
this.HashCodeOfBuffer = hashCodeOfBuffer;
if (elementType == typeof(Vector4))
{
}
}
public static AllocationRequest Create<T>(AllocationOptions allocationOptions, int length, T[] buffer)
{
Type type = typeof(T);
int elementSize = Marshal.SizeOf(type);
return new AllocationRequest(type, allocationOptions, length, length * elementSize, buffer.GetHashCode());
}
public Type ElementType { get; }
public AllocationOptions AllocationOptions { get; }
public int Length { get; }
public int LengthInBytes { get; }
public int HashCodeOfBuffer { get; }
}
public struct ReturnRequest
{
public ReturnRequest(int hashCodeOfBuffer) => this.HashCodeOfBuffer = hashCodeOfBuffer;
public int HashCodeOfBuffer { get; }
}
/// <summary>
/// Wraps an array as an <see cref="IManagedByteBuffer"/> instance.
/// </summary>
private class BasicArrayBuffer<T> : AllocationTrackedMemoryManager<T>
where T : struct
{
private readonly TestMemoryAllocator allocator;
private GCHandle pinHandle;
public BasicArrayBuffer(T[] array, int length, TestMemoryAllocator allocator)
{
this.allocator = allocator;
this.Array = array;
this.Length = length;
}
public BasicArrayBuffer(T[] array, TestMemoryAllocator allocator)
: this(array, array.Length, allocator)
{
}
/// <summary>
/// Gets the array.
/// </summary>
public T[] Array { get; }
/// <summary>
/// Gets the length.
/// </summary>
public int Length { get; }
/// <inheritdoc />
public override Span<T> 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();
/// <inheritdoc />
protected override void DisposeCore(bool disposing)
{
if (disposing)
{
this.allocator.Return(this);
}
}
}
}