import "libc.hff"; defmacro ALIGNUP(x,a) [ (((x) + ((a) - 1)) & -(a)) ] def ARENA_SIZE = 4z * 1024; extern fn xmalloc(n usize) *void; extern fn xcalloc(n usize, m usize) *void; extern fn xrealloc(p *void, n usize) *void; struct ArenaRegion { prev *ArenaRegion, idx usize, siz usize, mem [0]u8, } struct Arena { r *ArenaRegion, fn addregion(a *Arena, siz usize) void { let r *ArenaRegion = xcalloc(sizeof ArenaRegion + siz, 1); r.siz = siz; r.prev = a.r; a.r = r; } fn allocf(a *void, n usize, align usize) *void { let a *Arena = a; if a.r { a.r.idx = ALIGNUP(a.r.idx, align); } if n > ARENA_SIZE { a->addregion(n); let p *void = a.r.mem; a->addregion(ARENA_SIZE); return p; } else if a.r == #null { a->addregion(ARENA_SIZE); return allocf(a, n, align); } else if n > a.r.siz - a.r.idx { a->addregion(ARENA_SIZE); return allocf(a, n, align); } else { let p = &a.r.mem[a.r.idx]; a.r.idx += n; return p; } } fn destroy(a *Arena) void { for let r = a.r, next *ArenaRegion = #null; r; r = next { next = r.prev; free(r); } } } struct Allocator { a *void, allocf *fn(*void, usize, usize) *void, freef *fn(*void, *void) void, fn alloc(self *Allocator, n usize, align usize) *void { if self.allocf { let p = self.allocf(self.a, n, align); return p; } return #null; } fn free(self *Allocator, ptr *void) void { if self.freef { self.freef(self.a, ptr); } } } defmacro anew(a, T) [ ((a)->alloc(sizeof T, alignof T)) ]