import std.stdio; import core.stdc.string : memset; alias i8 = byte; alias i16 = short; alias i32 = int; alias i64 = long; alias u8 = ubyte; alias u16 = ushort; alias u32 = uint; alias u64 = ulong; alias f32 = float; alias f64 = double; alias b32 = uint; alias usize = size_t; alias intptr = i64; alias uintptr = u64; const DEFAULT_ALIGNMENT = (void *).sizeof * 2; version(linux) { import core.sys.posix.sys.mman; import core.sys.posix.dlfcn; struct Library { void* ptr; }; struct Function { void* ptr; }; Library LoadLibrary(string name) { Library lib = { ptr: null, }; lib.ptr = dlopen(name.ptr, RTLD_NOW); return lib; }; Function LoadFunction(Library lib, string name) { Function fn = { ptr: null, }; fn.ptr = dlsym(lib.ptr, name.ptr); return fn; }; void* MemAlloc(u64 size) { return mmap(null, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); } void MemFree(void* ptr, u64 size) { assert(munmap(ptr, size) == 0, "MemFree failure"); } } bool BitEq(u64 l, u64 r) { return (l & r) == r; } void Logf(Args...)(string fmt, Args args) { try { writefln(fmt, args); } catch (Exception e) { assert(false, "Incompatible format type"); } } void Log(string str) { writeln(str); } void Log(char* str) { writeln(str); } u64 KB(u64 v) { return v * 1024; }; u64 MB(u64 v) { return KB(v) * 1024; }; u64 GB(u64 v) { return MB(v) * 1024; }; struct Node(T) { Node!(T)* next; T value; } struct SLList(T) { Node!(T)* first; Node!(T)* last; } pragma(inline): void Push(T)(SLList!(T)*list, Node!(T)* node, Node!(T)* nil) { if (CheckNil(nil, list.first)) { list.first = list.last = node; node.next = nil; } else { list.last.next = node; list.last = node; node.next = nil; } } pragma(inline): void PushFront(T)(SLList!(T)*list, Node!(T)* node, Node!(T)* nil) { if (CheckNil(nil, list.first)) { list.first = list.last = node; node.next = nil; } else { node.next = list.first; list.first = node; } } pragma(inline): bool CheckNil(T)(Node!(T)* nil, Node!(T)* node) { return node == null || node == nil; } T* Alloc(T)() { void* mem = MemAlloc(T.sizeof); memset(mem, 0, T.sizeof); return (cast(T*)mem); } T[] AllocArray(T)(u64 count) { void* mem = MemAlloc(T.sizeof * count); memset(mem, 0, T.sizeof * count); return (cast(T*)mem)[0 .. count]; } void FreeArray(T)(T[] arr) { MemFree(cast(void*)arr.ptr, T.sizeof * arr.length); } void Free(T)(T* ptr) { MemFree(cast(void*)ptr, T.sizeof); } struct Arena { u8* mem; u64 length; u64 pos; }; Arena CreateArena(u64 size) { Arena arena = { mem: cast(u8 *)MemAlloc(size), length: size, pos: 0, }; assert(arena.mem != null, "Unable to allocate memory for arena"); return arena; }; T[] AllocArray(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* 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 = cast(uintptr)arena.mem; uintptr current = mem_pos + arena.pos; uintptr offset = AlignPow2(current, alignment) - mem_pos; if (offset+size <= arena.length) { ptr = &arena.mem[offset]; arena.pos = offset+size; } else { writefln("AllocAlign failure: out of memory, size requested: %s", size); assert(0); } return ptr; }; void Reset(Arena* arena) { memset(arena.mem, 0, arena.pos); arena.pos = 0; } void Free(Arena* arena) { MemFree(arena.mem, arena.length); } T AlignPow2(T)(T v, T a) { return (v + a - 1) & ~(a - 1); } u8[] Embed(string file_name) { import std.file; return read(file_name); }