dlib/alloc.d
2025-09-27 20:40:36 +10:00

349 lines
4.8 KiB
D

module dlib.alloc;
import dlib.aliases;
import dlib.math;
import dlib.platform;
import dlib.util;
import std.stdio;
import core.stdc.string : memset;
import core.memory;
static Scratch g_scratch;
static u64 g_scratch_index;
const DEFAULT_ALIGNMENT = (void *).sizeof * 2;
struct Scratch
{
Arena arena;
bool init;
}
struct ArenaPool
{
u8* mem;
u64 pos;
u64 length;
}
struct Arena
{
SLList!(ArenaPool) pools;
u64 def_size;
}
struct TempArena
{
Arena* arena;
Node!(ArenaPool)* start_node;
u64 start_pos;
}
T*
MAlloc(T)()
{
void* mem = MemAlloc(T.sizeof);
return cast(T*)mem;
}
T[]
MAllocArray(T)(u64 count)
{
void* mem = MemAlloc(T.sizeof * count);
return (cast(T*)mem)[0 .. count];
}
void
MFree(T)(T* ptr)
{
MemFree(ptr, T.sizeof);
}
void
MFreeArray(T)(T[] slice)
{
MemFree(slice.ptr, cast(u64)slice.length * T.sizeof);
}
T*
Alloc(T)()
{
void* mem = pureMalloc(T.sizeof);
memset(mem, 0, T.sizeof);
return (cast(T*)mem);
}
T[]
Alloc(T)(u64 count)
{
void* mem = pureMalloc(T.sizeof * count);
memset(mem, 0, T.sizeof * count);
return (cast(T*)mem)[0 .. count];
}
T[]
AllocCopy(T)(T[] target)
{
T[] arr = Alloc!(T)(target.length);
arr[] = target[];
return arr;
}
T[]
AllocArray(T)(u64 count)
{
return Alloc!(T)(count);
}
T[]
ReallocArray(T)(T[] arr, u64 count)
{
void* mem = pureRealloc(arr.ptr, T.sizeof * count);
return (cast(T*)mem)[0 .. count];
}
Arena
CreateArena(u64 size)
{
Arena arena = {
def_size: size,
};
AddArenaPool(&arena, size);
return arena;
}
TempArena
BeginTempArena(Arena* arena)
{
TempArena t = {
arena: arena,
};
auto n = arena.pools.first;
for(;;)
{
if(n.next == null)
{
t.start_node = n;
t.start_pos = n.value.pos;
break;
}
n = n.next;
}
return t;
}
void
End(TempArena* t)
{
bool resetting = false;
for(auto n = t.arena.pools.first; n != null; n = n.next)
{
if(t.start_node == n)
{
n.value.pos = t.start_pos;
resetting = true;
}
else if(resetting)
{
n.value.pos = 0;
}
}
}
T[]
AllocCopy(T)(TempArena* t, T[] target)
{
return AllocCopy!(T)(t.arena, target);
}
T[]
Alloc(T)(TempArena* t, u64 count)
{
return Alloc!(T)(t.arena, count);
}
T[]
AllocArray(T)(TempArena* t, u64 count)
{
return Alloc!(T)(t.arena, count);
}
T*
Alloc(T)(TempArena* t)
{
return Alloc!(T)(t.arena);
}
void
AddArenaPool(Arena* arena, u64 size)
{
u8* mem = Alloc!(u8)(size + Node!(ArenaPool).sizeof).ptr;
Node!(ArenaPool)* node = cast(Node!(ArenaPool)*)mem;
node.value.mem = (cast(u8*)mem) + Node!(ArenaPool).sizeof;
node.value.pos = 0;
node.value.length = size;
assert(node.value.mem != null, "Unable to allocate memory for arena");
SLLPushFront(&arena.pools, node, null);
}
T[]
Alloc(T)(Arena* arena, u64 count)
{
void* mem = AllocAlign(arena, T.sizeof * count, DEFAULT_ALIGNMENT);
memset(mem, 0, T.sizeof * count);
return (cast(T*)mem)[0 .. count];
}
T[]
AllocArray(T)(Arena* arena, u64 count)
{
return Alloc!(T)(arena, count);
}
T[]
AllocCopy(T)(Arena* arena, T[] target)
{
T[] arr = Alloc!(T)(arena, target.length);
arr[] = target[];
return arr;
}
T*
Alloc(T)(Arena* arena)
{
void* mem = AllocAlign(arena, T.sizeof, DEFAULT_ALIGNMENT);
memset(mem, 0, T.sizeof);
return cast(T*)mem;
};
void*
AllocAlign(Arena* arena, u64 size, u64 alignment)
{
void* ptr = null;
uintptr mem_pos, current, offset;
Node!(ArenaPool)* node = arena.pools.first;
while (true)
{
if(node == null)
{
if(size > arena.def_size)
{
size += arena.def_size;
}
AddArenaPool(arena, Max(size, arena.def_size));
node = arena.pools.first;
}
mem_pos = cast(uintptr)node.value.mem;
current = mem_pos + node.value.pos;
offset = AlignPow2(current, alignment) - mem_pos;
if(offset+size <= node.value.length)
{
break;
}
node = node.next;
}
ptr = &node.value.mem[offset];
node.value.pos = offset+size;
return ptr;
};
void
Reset(Arena* arena)
{
Node!(ArenaPool)* node = arena.pools.first;
while (node != null)
{
node.value.pos = 0;
node = node.next;
}
}
void
Free(Arena* arena)
{
Node!(ArenaPool)* node = arena.pools.first;
while (node != null)
{
Free(node);
node = node.next;
}
}
void
FreeArray(T)(T[] arr)
{
pureFree(arr.ptr);
}
void
Free(T)(T* ptr)
{
pureFree(ptr);
}
void
ResetScratch(u64 size)
{
if(!g_scratch.init)
{
g_scratch.arena = CreateArena(size);
g_scratch.init = true;
}
Reset(&g_scratch.arena);
}
T*
ScratchAlloc(T)()
{
return Alloc!(T)(&g_scratch.arena);
}
T[]
ScratchAlloc(T)(u64 count)
{
return AllocArray!(T)(&g_scratch.arena, count);
}
T[]
ScratchAllocCopy(T)(T[] target)
{
T[] arr = ScratchAlloc!(T)(target.length);
arr[] = target[];
return arr;
}
unittest
{
{
u64[5] arr = [1, 2, 3, 4, 5];
u64[] copy = AllocCopy!(u64)(arr);
assert(arr == copy);
}
{
Arena a = CreateArena(64);
u64[] arr = Alloc!(u64)(&a, 128);
}
}