This commit is contained in:
agra
2026-02-20 18:22:42 +02:00
parent 6f927361aa
commit 2f95810f9d
10 changed files with 510 additions and 77 deletions

View File

@@ -0,0 +1,154 @@
#import "std.sx";
// --- Allocator protocol ---
Allocator :: struct {
ctx: *void;
alloc: (*void, s64) -> *void;
free: (*void, *void) -> void;
}
// --- GPA: general purpose allocator (malloc/free wrapper) ---
GPA :: struct {
alloc_count: s64;
}
gpa_alloc :: (ctx: *void, size: s64) -> *void {
gpa : *GPA = xx ctx;
gpa.alloc_count += 1;
malloc(size);
}
gpa_free :: (ctx: *void, ptr: *void) {
gpa : *GPA = xx ctx;
gpa.alloc_count -= 1;
free(ptr);
}
gpa_create :: (gpa: *GPA) -> Allocator {
ctx : *void = xx gpa;
Allocator.{ ctx = ctx, alloc = gpa_alloc, free = gpa_free };
}
// --- Arena: multi-chunk bump allocator (Zig-inspired) ---
ArenaChunk :: struct {
next: *void; // *ArenaChunk
cap: s64; // total chunk size including this header
}
Arena :: struct {
first: *void; // *ArenaChunk — head of list (newest first)
end_index: s64; // bump position within current chunk's usable area
parent: Allocator; // backing allocator
}
arena_add_chunk :: (a: *Arena, min_size: s64) {
first_i : s64 = xx a.first;
prev_cap := if first_i != 0 then { c : *ArenaChunk = xx a.first; c.cap; } else 0;
needed := min_size + 16 + 16;
len := (prev_cap + needed) * 3 / 2;
raw := a.parent.alloc(a.parent.ctx, len);
chunk : *ArenaChunk = xx raw;
chunk.next = a.first;
chunk.cap = len;
a.first = xx chunk;
a.end_index = 0;
}
arena_alloc :: (ctx: *void, size: s64) -> *void {
a : *Arena = xx ctx;
aligned := (size + 7) & (0 - 8);
first_i : s64 = xx a.first;
if first_i != 0 {
chunk : *ArenaChunk = xx a.first;
usable := chunk.cap - 16;
if a.end_index + aligned <= usable {
buf : [*]u8 = xx a.first;
ptr : *void = xx @buf[16 + a.end_index];
a.end_index = a.end_index + aligned;
return ptr;
}
}
arena_add_chunk(a, aligned);
buf : [*]u8 = xx a.first;
ptr : *void = xx @buf[16 + a.end_index];
a.end_index = a.end_index + aligned;
ptr;
}
arena_free :: (ctx: *void, ptr: *void) {
}
arena_create :: (a: *Arena, parent: Allocator, size: s64) -> Allocator {
a.first = null;
a.end_index = 0;
a.parent = parent;
arena_add_chunk(a, size);
ctx : *void = xx a;
Allocator.{ ctx = ctx, alloc = arena_alloc, free = arena_free };
}
arena_reset :: (a: *Arena) {
// Keep first chunk (newest/largest), free the rest
first_i : s64 = xx a.first;
if first_i != 0 {
chunk : *ArenaChunk = xx a.first;
it : s64 = xx chunk.next;
while it != 0 {
c : *ArenaChunk = xx it;
next_i : s64 = xx c.next;
a.parent.free(a.parent.ctx, xx c);
it = next_i;
}
chunk.next = null;
}
a.end_index = 0;
}
arena_deinit :: (a: *Arena) {
it : s64 = xx a.first;
while it != 0 {
c : *ArenaChunk = xx it;
next_i : s64 = xx c.next;
a.parent.free(a.parent.ctx, xx c);
it = next_i;
}
a.first = null;
a.end_index = 0;
}
// --- BufAlloc: bump allocator backed by a user-provided slice ---
BufAlloc :: struct {
buf: [*]u8;
len: s64;
pos: s64;
}
buf_alloc :: (ctx: *void, size: s64) -> *void {
b : *BufAlloc = xx ctx;
aligned := (size + 7) & (0 - 8);
if b.pos + aligned > b.len {
return null;
}
ptr : *void = xx @b.buf[b.pos];
b.pos = b.pos + aligned;
ptr;
}
buf_free :: (ctx: *void, ptr: *void) {
}
buf_create :: (b: *BufAlloc, buf: [*]u8, len: s64) -> Allocator {
b.buf = buf;
b.len = len;
b.pos = 0;
ctx : *void = xx b;
Allocator.{ ctx = ctx, alloc = buf_alloc, free = buf_free };
}
buf_reset :: (b: *BufAlloc) {
b.pos = 0;
}

View File

@@ -18,57 +18,37 @@ field_value_int :: ($T: Type, idx: s64) -> s64 #builtin;
field_index :: ($T: Type, val: T) -> s64 #builtin;
string :: []u8 #builtin;
// --- Arena allocator & Context ---
#import "allocators.sx";
Arena :: struct {
buf: string;
pos: s64;
}
// --- Context ---
Context :: struct {
arena: *Arena;
allocator: Allocator;
data: *void;
}
context : Context = ---;
arena_create :: (size: s64) -> Arena {
Arena.{ buf = cstring(size), pos = 0 };
}
arena_alloc :: (arena: *Arena, size: s64) -> *void {
aligned := (size + 7) & (0 - 8);
if arena.pos + aligned > arena.buf.len {
return malloc(aligned);
}
ptr : *void = xx @arena.buf[arena.pos];
arena.pos = arena.pos + aligned;
ptr;
}
arena_reset :: (arena: *Arena) {
arena.pos = 0;
}
arena_destroy :: (arena: *Arena) {
free(arena.buf.ptr);
}
// --- String allocation ---
CString :: union {
s: string;
struct { ptr: *void; len: s64; };
}
// --- Slice & string allocation ---
cstring :: (size: s64) -> string {
p : s64 = xx context.arena;
raw := if p != 0 then arena_alloc(context.arena, size + 1) else malloc(size + 1);
p : s64 = xx context.allocator.ctx;
raw := if p != 0 then context.allocator.alloc(context.allocator.ctx, size + 1) else malloc(size + 1);
memset(raw, 0, size + 1);
rs : CString = ---;
rs.ptr = raw;
rs.len = size;
rs.s;
s : string = ---;
s.ptr = xx raw;
s.len = size;
s;
}
alloc_slice :: ($T: Type, count: s64) -> []T {
p : s64 = xx context.allocator.ctx;
raw := if p != 0 then context.allocator.alloc(context.allocator.ctx, count * size_of(T)) else malloc(count * size_of(T));
memset(raw, 0, count * size_of(T));
s : []T = ---;
s.ptr = xx raw;
s.len = count;
s;
}
int_to_string :: (n: s64) -> string {