vtables, protocol
This commit is contained in:
@@ -1,47 +1,34 @@
|
||||
#import "std.sx";
|
||||
|
||||
// --- Allocator protocol ---
|
||||
// --- Allocator protocol (inline: ctx + fn-ptrs, no vtable indirection) ---
|
||||
|
||||
Allocator :: struct {
|
||||
ctx: *void;
|
||||
alloc_fn: (*void, s64) -> *void;
|
||||
free_fn: (*void, *void) -> void;
|
||||
Allocator :: protocol #inline {
|
||||
alloc :: (size: s64) -> *void;
|
||||
dealloc :: (ptr: *void);
|
||||
}
|
||||
|
||||
allocator_alloc :: (a: Allocator, size: s64) -> *void {
|
||||
a.alloc_fn(a.ctx, size);
|
||||
}
|
||||
|
||||
allocator_dealloc :: (a: Allocator, ptr: *void) {
|
||||
a.free_fn(a.ctx, ptr);
|
||||
}
|
||||
|
||||
alloc :: ufcs allocator_alloc;
|
||||
dealloc :: ufcs allocator_dealloc;
|
||||
|
||||
// --- GPA: general purpose allocator (malloc/free wrapper) ---
|
||||
|
||||
GPA :: struct {
|
||||
alloc_count: s64;
|
||||
|
||||
create :: (gpa: *GPA) -> Allocator {
|
||||
xx gpa;
|
||||
}
|
||||
}
|
||||
|
||||
gpa_alloc :: (ctx: *void, size: s64) -> *void {
|
||||
gpa : *GPA = xx ctx;
|
||||
gpa.alloc_count += 1;
|
||||
malloc(size);
|
||||
impl Allocator for GPA {
|
||||
alloc :: (self: *GPA, size: s64) -> *void {
|
||||
self.alloc_count += 1;
|
||||
malloc(size);
|
||||
}
|
||||
dealloc :: (self: *GPA, ptr: *void) {
|
||||
self.alloc_count -= 1;
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
gpa_free :: (ctx: *void, ptr: *void) {
|
||||
gpa : *GPA = xx ctx;
|
||||
gpa.alloc_count -= 1;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
gpa_create :: (gpa: *GPA) -> Allocator {
|
||||
Allocator.{ ctx = gpa, alloc_fn = gpa_alloc, free_fn = gpa_free };
|
||||
}
|
||||
|
||||
// --- Arena: multi-chunk bump allocator (Zig-inspired) ---
|
||||
// --- Arena: multi-chunk bump allocator ---
|
||||
|
||||
ArenaChunk :: struct {
|
||||
next: *ArenaChunk;
|
||||
@@ -52,73 +39,71 @@ Arena :: struct {
|
||||
first: *ArenaChunk;
|
||||
end_index: s64;
|
||||
parent: Allocator;
|
||||
}
|
||||
|
||||
arena_add_chunk :: (a: *Arena, min_size: s64) {
|
||||
prev_cap := if a.first != null then a.first.cap else 0;
|
||||
needed := min_size + 16 + 16;
|
||||
len := (prev_cap + needed) * 3 / 2;
|
||||
raw := a.parent.alloc(len);
|
||||
chunk : *ArenaChunk = xx raw;
|
||||
chunk.next = a.first;
|
||||
chunk.cap = len;
|
||||
a.first = chunk;
|
||||
a.end_index = 0;
|
||||
}
|
||||
|
||||
arena_alloc :: (ctx: *void, size: s64) -> *void {
|
||||
a : *Arena = xx ctx;
|
||||
aligned := (size + 7) & (0 - 8);
|
||||
if a.first != null {
|
||||
usable := a.first.cap - 16;
|
||||
if a.end_index + aligned <= usable {
|
||||
buf : [*]u8 = xx a.first;
|
||||
ptr := @buf[16 + a.end_index];
|
||||
a.end_index = a.end_index + aligned;
|
||||
return ptr;
|
||||
}
|
||||
add_chunk :: (a: *Arena, min_size: s64) {
|
||||
prev_cap := if a.first != null then a.first.cap else 0;
|
||||
needed := min_size + 16 + 16;
|
||||
len := (prev_cap + needed) * 3 / 2;
|
||||
raw := a.parent.alloc(len);
|
||||
chunk : *ArenaChunk = xx raw;
|
||||
chunk.next = a.first;
|
||||
chunk.cap = len;
|
||||
a.first = chunk;
|
||||
a.end_index = 0;
|
||||
}
|
||||
arena_add_chunk(a, aligned);
|
||||
buf : [*]u8 = xx a.first;
|
||||
ptr := @buf[16 + a.end_index];
|
||||
a.end_index = a.end_index + aligned;
|
||||
ptr;
|
||||
}
|
||||
|
||||
arena_free :: (ctx: *void, ptr: *void) {
|
||||
}
|
||||
create :: (a: *Arena, parent: Allocator, size: s64) -> Allocator {
|
||||
a.first = null;
|
||||
a.end_index = 0;
|
||||
a.parent = parent;
|
||||
a.add_chunk(size);
|
||||
xx a;
|
||||
}
|
||||
|
||||
arena_create :: (a: *Arena, parent: Allocator, size: s64) -> Allocator {
|
||||
a.first = null;
|
||||
a.end_index = 0;
|
||||
a.parent = parent;
|
||||
arena_add_chunk(a, size);
|
||||
Allocator.{ ctx = a, alloc_fn = arena_alloc, free_fn = arena_free };
|
||||
}
|
||||
reset :: (a: *Arena) {
|
||||
if a.first != null {
|
||||
it := a.first.next;
|
||||
while it != null {
|
||||
next := it.next;
|
||||
a.parent.dealloc(it);
|
||||
it = next;
|
||||
}
|
||||
a.first.next = null;
|
||||
}
|
||||
a.end_index = 0;
|
||||
}
|
||||
|
||||
arena_reset :: (a: *Arena) {
|
||||
// Keep first chunk (newest/largest), free the rest
|
||||
if a.first != null {
|
||||
it := a.first.next;
|
||||
deinit :: (a: *Arena) {
|
||||
it := a.first;
|
||||
while it != null {
|
||||
next := it.next;
|
||||
a.parent.dealloc(it);
|
||||
it = next;
|
||||
}
|
||||
a.first.next = null;
|
||||
a.first = null;
|
||||
a.end_index = 0;
|
||||
}
|
||||
a.end_index = 0;
|
||||
}
|
||||
|
||||
arena_deinit :: (a: *Arena) {
|
||||
it := a.first;
|
||||
while it != null {
|
||||
next := it.next;
|
||||
a.parent.dealloc(it);
|
||||
it = next;
|
||||
impl Allocator for Arena {
|
||||
alloc :: (self: *Arena, size: s64) -> *void {
|
||||
aligned := (size + 7) & (0 - 8);
|
||||
if self.first != null {
|
||||
usable := self.first.cap - 16;
|
||||
if self.end_index + aligned <= usable {
|
||||
buf : [*]u8 = xx self.first;
|
||||
ptr := @buf[16 + self.end_index];
|
||||
self.end_index = self.end_index + aligned;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
self.add_chunk(aligned);
|
||||
buf : [*]u8 = xx self.first;
|
||||
ptr := @buf[16 + self.end_index];
|
||||
self.end_index = self.end_index + aligned;
|
||||
ptr;
|
||||
}
|
||||
a.first = null;
|
||||
a.end_index = 0;
|
||||
dealloc :: (self: *Arena, ptr: *void) {}
|
||||
}
|
||||
|
||||
// --- BufAlloc: bump allocator backed by a user-provided slice ---
|
||||
@@ -127,29 +112,28 @@ 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;
|
||||
create :: (b: *BufAlloc, buf: [*]u8, len: s64) -> Allocator {
|
||||
b.buf = buf;
|
||||
b.len = len;
|
||||
b.pos = 0;
|
||||
xx b;
|
||||
}
|
||||
|
||||
reset :: (b: *BufAlloc) {
|
||||
b.pos = 0;
|
||||
}
|
||||
ptr := @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;
|
||||
Allocator.{ ctx = b, alloc_fn = buf_alloc, free_fn = buf_free };
|
||||
}
|
||||
|
||||
buf_reset :: (b: *BufAlloc) {
|
||||
b.pos = 0;
|
||||
impl Allocator for BufAlloc {
|
||||
alloc :: (self: *BufAlloc, size: s64) -> *void {
|
||||
aligned := (size + 7) & (0 - 8);
|
||||
if self.pos + aligned > self.len {
|
||||
return null;
|
||||
}
|
||||
ptr := @self.buf[self.pos];
|
||||
self.pos = self.pos + aligned;
|
||||
ptr;
|
||||
}
|
||||
dealloc :: (self: *BufAlloc, ptr: *void) {}
|
||||
}
|
||||
|
||||
@@ -31,12 +31,8 @@ context : Context = ---;
|
||||
|
||||
// --- Slice & string allocation ---
|
||||
|
||||
context_alloc :: (size: s64) -> *void {
|
||||
if context.allocator.ctx != null then context.allocator.alloc(size) else malloc(size);
|
||||
}
|
||||
|
||||
cstring :: (size: s64) -> string {
|
||||
raw := context_alloc(size + 1);
|
||||
raw := context.allocator.alloc(size + 1);
|
||||
memset(raw, 0, size + 1);
|
||||
s : string = ---;
|
||||
s.ptr = xx raw;
|
||||
@@ -45,7 +41,7 @@ cstring :: (size: s64) -> string {
|
||||
}
|
||||
|
||||
alloc_slice :: ($T: Type, count: s64) -> []T {
|
||||
raw := context_alloc(count * size_of(T));
|
||||
raw := context.allocator.alloc(count * size_of(T));
|
||||
memset(raw, 0, count * size_of(T));
|
||||
s : []T = ---;
|
||||
s.ptr = xx raw;
|
||||
@@ -337,19 +333,19 @@ List :: struct ($T: Type) {
|
||||
items: [*]T = null;
|
||||
len: s64 = 0;
|
||||
cap: s64 = 0;
|
||||
}
|
||||
|
||||
append ::(list: *List($T), item: T) {
|
||||
if list.len >= list.cap {
|
||||
new_cap := if list.cap == 0 then 4 else list.cap * 2;
|
||||
new_items : [*]T = xx malloc(new_cap * size_of(T));
|
||||
if list.len > 0 {
|
||||
memcpy(new_items, list.items, list.len * size_of(T));
|
||||
free(list.items);
|
||||
append :: (list: *List(T), item: T) {
|
||||
if list.len >= list.cap {
|
||||
new_cap := if list.cap == 0 then 4 else list.cap * 2;
|
||||
new_items : [*]T = xx context.allocator.alloc(new_cap * size_of(T));
|
||||
if list.len > 0 {
|
||||
memcpy(new_items, list.items, list.len * size_of(T));
|
||||
context.allocator.dealloc(list.items);
|
||||
}
|
||||
list.items = new_items;
|
||||
list.cap = new_cap;
|
||||
}
|
||||
list.items = new_items;
|
||||
list.cap = new_cap;
|
||||
list.items[list.len] = item;
|
||||
list.len += 1;
|
||||
}
|
||||
list.items[list.len] = item;
|
||||
list.len += 1;
|
||||
}
|
||||
Reference in New Issue
Block a user