-
-
Notifications
You must be signed in to change notification settings - Fork 112
Open
Description
Could you add IDisposable to ZeroLib please? I'm testing out building an allocator with bflat but because Zero doesn't come with IDisposable I can't use the using keyword meaning it will always need to be done manually.
using System.Runtime.InteropServices;
Console.Write("Free bytes: ");
Console.WriteInt(Allocator.Available);
Console.WriteLine("");
var array = new int[1000];
var objects = new object[10];
for (var i = 0; i < 10; i++)
objects[i] = new object();
object boxed = 42;
var box = new Box<int>(100);
Console.Write("Box value: ");
Console.WriteInt(box.Value);
Console.WriteLine("");
var vec = new Vec<int>();
for (var i = 0; i < 5; i++)
{
vec.Push(i * i);
}
Console.Write("Vec contents: ");
for (var i = 0; i < vec.Length; i++)
{
Console.WriteInt(vec[i]);
Console.Write(" ");
}
Console.WriteLine("");
Console.Write("Free bytes: ");
Console.WriteInt(Allocator.Available);
Console.WriteLine("");
box.Dispose();
vec.Dispose();
public unsafe struct Console
{
[DllImport("kernel32.dll")]
private static extern void* GetStdHandle(uint nStdHandle);
[DllImport("kernel32.dll")]
private static extern bool WriteFile(void* hFile, void* lpBuffer, uint nNumberOfBytesToWrite, uint* lpNumberOfBytesWritten, void* lpOverlapped);
private static void* _stdoutHandle;
private static void EnsureHandle()
{
if (_stdoutHandle == null)
_stdoutHandle = GetStdHandle(0xFFFFFFF5);
}
private static void WriteString(string message)
{
EnsureHandle();
var bytes = stackalloc byte[message.Length];
for (var i = 0; i < message.Length; i++)
bytes[i] = (byte)message[i];
uint written;
WriteFile(_stdoutHandle, bytes, (uint)message.Length, &written, null);
}
public static void Write(string message) => WriteString(message);
public static void WriteLine(string message)
{
WriteString(message);
WriteString("\n");
}
public static void WriteInt(int value)
{
if (value == 0)
{
WriteString("0");
return;
}
var isNegative = value < 0;
if (isNegative) value = -value;
var temp = value;
var digitCount = 0;
while (temp > 0)
{
temp /= 10;
digitCount++;
}
var totalLen = digitCount + (isNegative ? 1 : 0);
var buffer = stackalloc byte[totalLen];
var pos = totalLen - 1;
temp = value;
while (temp > 0)
{
buffer[pos--] = (byte)('0' + (temp % 10));
temp /= 10;
}
if (isNegative)
buffer[0] = (byte)'-';
EnsureHandle();
uint written;
WriteFile(_stdoutHandle, buffer, (uint)totalLen, &written, null);
}
}
public unsafe struct Allocator
{
[StructLayout(LayoutKind.Sequential, Size = 16 * 1024 * 1024)]
private struct Heap;
private struct Block
{
public int Size;
public bool Used;
}
private static readonly Heap _heap;
private static readonly byte* _start;
private static readonly byte* _end;
static Allocator()
{
fixed (Heap* pointer = &_heap)
{
_start = (byte*)pointer;
_end = _start + sizeof(Heap);
}
var block = (Block*)_start;
block->Size = sizeof(Heap) - sizeof(Block);
block->Used = false;
}
#if WINDOWS
[UnmanagedCallersOnly(EntryPoint = "LocalAlloc")]
public static void* LocalAlloc(uint flags, uint size)
{
var result = Allocate((int)size);
if (result != null && (flags & 0x40) != 0)
Set(result, 0, (int)size);
return result;
}
[UnmanagedCallersOnly(EntryPoint = "LocalFree")]
public static void* LocalFree(void* ptr)
{
Free(ptr);
return null;
}
#else
[UnmanagedCallersOnly(EntryPoint = "SystemNative_Malloc")]
public static void* SystemNative_Malloc(nuint size) => Allocate((int)size);
[UnmanagedCallersOnly(EntryPoint = "SystemNative_Free")]
public static void SystemNative_Free(void* pointer) => Free(pointer);
#endif
public static void* Allocate(int size)
{
if (size <= 0) return null;
size = (size + 7) & ~7;
var current = (Block*)_start;
while ((byte*)current < _end)
{
if (!current->Used && current->Size >= size)
{
if (current->Size > size + sizeof(Block) + 16)
{
var next = (Block*)((byte*)current + sizeof(Block) + size);
next->Size = current->Size - size - sizeof(Block);
next->Used = false;
current->Size = size;
}
current->Used = true;
return (byte*)current + sizeof(Block);
}
current = (Block*)((byte*)current + sizeof(Block) + current->Size);
}
return null;
}
public static void Free(void* pointer)
{
if (pointer == null) return;
var block = (Block*)((byte*)pointer - sizeof(Block));
block->Used = false;
var next = (Block*)((byte*)block + sizeof(Block) + block->Size);
if ((byte*)next < _end && !next->Used)
block->Size += sizeof(Block) + next->Size;
CoalescePrevious(block);
}
private static void CoalescePrevious(Block* target)
{
var current = (Block*)_start;
while (current < target)
{
var next = (Block*)((byte*)current + sizeof(Block) + current->Size);
if (next == target && !current->Used)
{
current->Size += sizeof(Block) + target->Size;
return;
}
current = next;
}
}
public static void* Set(void* pointer, int value, int count)
{
var bytes = (byte*)pointer;
for (var i = 0; i < count; i++)
bytes[i] = (byte)value;
return pointer;
}
public static void* Copy(void* destination, void* source, int count)
{
for (var i = 0; i < count; i++)
((byte*)destination)[i] = ((byte*)source)[i];
return destination;
}
public static int Available
{
get
{
var free = 0;
var current = (Block*)_start;
while ((byte*)current < _end)
{
if (!current->Used)
free += current->Size;
current = (Block*)((byte*)current + sizeof(Block) + current->Size);
}
return free;
}
}
}
public unsafe struct Box<T> : IDisposable where T : unmanaged
{
private T* _pointer;
public Box(T value)
{
_pointer = (T*)Allocator.Allocate(sizeof(T));
if (_pointer != null) *_pointer = value;
}
public ref T Value => ref *_pointer;
public void Dispose()
{
if (_pointer == null) return;
Allocator.Free(_pointer);
_pointer = null;
}
}
public unsafe struct Vec<T> : IDisposable where T : unmanaged
{
private T* _data;
private int _capacity;
public Vec()
{
_capacity = 4;
Length = 0;
_data = (T*)Allocator.Allocate(sizeof(T) * 4);
if (_data == null)
_capacity = 0;
}
public Vec(int capacity)
{
_capacity = capacity;
Length = 0;
_data = (T*)Allocator.Allocate(sizeof(T) * capacity);
if (_data == null)
_capacity = 0;
}
public int Length { get; private set; }
public ref T this[int index] => ref _data[index];
public void Push(T item)
{
if (_data == null)
return;
if (Length >= _capacity)
{
var capacity = _capacity * 2;
var data = (T*)Allocator.Allocate(sizeof(T) * capacity);
if (data != null)
{
Allocator.Copy(data, _data, sizeof(T) * Length);
Allocator.Free(_data);
_data = data;
_capacity = capacity;
}
else
{
return;
}
}
if (Length < _capacity)
{
_data[Length++] = item;
}
}
public void Dispose()
{
if (_data == null) return;
Allocator.Free(_data);
_data = null;
}
}
public interface IDisposable
{
void Dispose();
}guylangstonguylangston
Metadata
Metadata
Assignees
Labels
No labels