- examples/modules/ -> library/modules/ (top-level, no more symlink hacks in consumer projects) - compiler discovers stdlib via _NSGetExecutablePath / readlink /proc/self/exe; searches dev layout (../../library), install layout (../library), and alongside-binary fallback - SX_STDLIB_PATH env var overrides for tests / dev convenience - SX_DEBUG_STDLIB env var dumps the discovery results - build.zig installs library/ alongside the binary - Compilation gains stdlib_paths field threaded through resolveImports - 50 tests pass; consumer projects can now build from any cwd
140 lines
3.2 KiB
Plaintext
140 lines
3.2 KiB
Plaintext
#import "std.sx";
|
|
|
|
// --- Allocator protocol (inline: ctx + fn-ptrs, no vtable indirection) ---
|
|
|
|
Allocator :: protocol #inline {
|
|
alloc :: (size: s64) -> *void;
|
|
dealloc :: (ptr: *void);
|
|
}
|
|
|
|
// --- GPA: general purpose allocator (malloc/free wrapper) ---
|
|
|
|
GPA :: struct {
|
|
alloc_count: s64;
|
|
|
|
create :: (gpa: *GPA) -> Allocator {
|
|
xx gpa;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
// --- Arena: multi-chunk bump allocator ---
|
|
|
|
ArenaChunk :: struct {
|
|
next: *ArenaChunk;
|
|
cap: s64;
|
|
}
|
|
|
|
Arena :: struct {
|
|
first: *ArenaChunk;
|
|
end_index: s64;
|
|
parent: Allocator;
|
|
|
|
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;
|
|
}
|
|
|
|
create :: (a: *Arena, parent: Allocator, size: s64) -> Allocator {
|
|
a.first = null;
|
|
a.end_index = 0;
|
|
a.parent = parent;
|
|
a.add_chunk(size);
|
|
xx a;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
deinit :: (a: *Arena) {
|
|
it := a.first;
|
|
while it != null {
|
|
next := it.next;
|
|
a.parent.dealloc(it);
|
|
it = next;
|
|
}
|
|
a.first = null;
|
|
a.end_index = 0;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
dealloc :: (self: *Arena, ptr: *void) {}
|
|
}
|
|
|
|
// --- BufAlloc: bump allocator backed by a user-provided slice ---
|
|
|
|
BufAlloc :: struct {
|
|
buf: [*]u8;
|
|
len: s64;
|
|
pos: s64;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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) {}
|
|
}
|