Skip to content

Instantly share code, notes, and snippets.

@neon-sunset
Last active April 12, 2024 03:28
Show Gist options
  • Save neon-sunset/fdec70f44535272512de875f5a6907a5 to your computer and use it in GitHub Desktop.
Save neon-sunset/fdec70f44535272512de875f5a6907a5 to your computer and use it in GitHub Desktop.
Never tested, likely explodes
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
unsafe class PoorMansArena : IDisposable
{
byte* _buffer = (byte*)NativeMemory.AlignedAlloc(16384, 4096);
int _filled;
int _size;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T Get<T>(int offset) where T : unmanaged
{
var bound = (ulong)(uint)_filled;
var end = (ulong)(uint)offset + (uint)Unsafe.SizeOf<T>();
ArgumentOutOfRangeException.ThrowIfGreaterThan(end, bound);
return ref Unsafe.AsRef<T>(_buffer + (nint)(uint)offset);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Append<T>(T value) where T : unmanaged
{
Retry:
var size = Unsafe.SizeOf<T>();
var offset = _filled;
var free = _size - offset;
if (free >= size)
{
ref var dst = ref Unsafe.AsRef<T>(_buffer + (nint)(uint)offset);
dst = value;
_filled = offset + size;
return offset;
}
Grow();
goto Retry;
}
[MethodImpl(MethodImplOptions.NoInlining)]
void Grow()
{
var size = (uint)_size * 2;
ArgumentOutOfRangeException.ThrowIfGreaterThan(size, (uint)int.MaxValue);
_buffer = (byte*)NativeMemory.AlignedRealloc(_buffer, size, 4096);
_size = (int)size;
}
public void Dispose()
{
var buffer = Interlocked.Exchange(ref Unsafe.AsRef<nint>(_buffer), 0);
if (buffer != 0)
{
NativeMemory.AlignedFree((void*)buffer);
GC.SuppressFinalize(this);
}
}
~PoorMansArena() => Dispose();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment