std/mem.zc
Rama main · réplica de lectura del repositorio original.
import "./core.zc"
// --- MISRA static arena ---
// A fixed-size arena used as the allocation backend in MISRA mode (where
// malloc/calloc/free are disallowed). It lives here rather than in arena.zc so
// that mem.zc does not import arena.zc: arena.zc implements Drop (which
// auto-imports mem.zc), so a mem.zc -> arena.zc edge would form an import cycle.
struct StaticArena {
data: byte*;
capacity: usize;
used: usize;
}
// 64KB static buffer for MISRA modes
let _z_misra_static_buffer: [byte; 65536];
impl StaticArena {
fn init(self) {
self.data = (byte*) &_z_misra_static_buffer;
self.capacity = 65536;
self.used = 0;
}
fn alloc_bytes(self, size: usize) -> void* {
// Simple 8-byte alignment
let aligned = (self.used + 7) & ~7;
if (aligned + size > self.capacity) {
// In MISRA mode, we panic on exhaustion rather than returning NULL
// to ensure deterministic failure.
!"Panic: MISRA Static Arena exhausted!";
exit(1);
}
let ptr: void* = (byte*)self.data + aligned;
self.used = aligned + size;
return ptr;
}
fn alloc<T>(self) -> T* {
let ptr: T* = (T*)self.alloc_bytes(sizeof(T));
if (ptr != NULL) {
memset(ptr, 0, sizeof(T));
}
return ptr;
}
fn alloc_n<T>(self, count: usize) -> T* {
let size = sizeof(T) * count;
let ptr: T* = (T*)self.alloc_bytes(size);
if (ptr != NULL) {
memset(ptr, 0, size);
}
return ptr;
}
fn realloc<T>(self, old_ptr: T*, old_count: usize, new_count: usize) -> T* {
let new_size = sizeof(T) * new_count;
let old_size = sizeof(T) * old_count;
// If it's the most recent allocation, we can just grow it in place!
let aligned_old = (self.used - old_size + 7) & ~7;
if ((byte*)self.data + aligned_old == (byte*)old_ptr) {
let new_aligned = (aligned_old + new_size + 7) & ~7;
if (new_aligned <= self.capacity) {
self.used = aligned_old + new_size;
return old_ptr;
}
}
// Otherwise, allocate new space and copy
let new_ptr = (T*)self.alloc_bytes(new_size);
if (old_ptr != NULL && old_size > 0) {
memcpy(new_ptr, old_ptr, old_size);
}
return new_ptr;
}
}
let _z_internal_arena: StaticArena;
let _z_arena_initialized: bool = false;
fn _z_get_std_arena() -> StaticArena* {
if (!_z_arena_initialized) {
_z_internal_arena.init();
_z_arena_initialized = true;
}
return &_z_internal_arena;
}
// --- Non-generic internal helpers for conditional compilation ---
// These avoid the 'StringPtr' mangling bug in generic functions with @cfg attributes.
@cfg(misra)
fn _z_internal_alloc_bytes(size: usize) -> void* {
return _z_get_std_arena().alloc_bytes(size);
}
@cfg(not(misra))
fn _z_internal_alloc_bytes(size: usize) -> void* {
return calloc(1, size);
}
@cfg(misra)
fn _z_internal_zalloc_bytes(size: usize) -> void* {
let ptr = _z_get_std_arena().alloc_bytes(size);
if (ptr != NULL) {
memset(ptr, 0, size);
}
return ptr;
}
@cfg(not(misra))
fn _z_internal_zalloc_bytes(size: usize) -> void* {
return calloc(1, size);
}
@cfg(misra)
fn _z_internal_realloc_bytes(ptr: void*, old_size: usize, new_size: usize) -> void* {
// In StaticArena, realloc needs the original type/count, but we can approximate
// if we treat it as an array of bytes.
return _z_get_std_arena().realloc<byte>((byte*)ptr, old_size, new_size);
}
@cfg(not(misra))
fn _z_internal_realloc_bytes(ptr: void*, old_size: usize, new_size: usize) -> void* {
let new_ptr = realloc(ptr, new_size);
if (new_ptr != NULL && new_size > old_size) {
memset((char*)new_ptr + old_size, 0, new_size - old_size);
}
return new_ptr;
}
@cfg(misra)
fn _z_internal_free(ptr: void*) {
(void)ptr;
// No-op in MISRA arena mode
}
@cfg(not(misra))
fn _z_internal_free(ptr: void*) {
if (ptr != NULL) {
free(ptr);
}
}
// --- Public Generic API ---
// These are NOT attribute-guarded to avoid compiler template bugs.
fn alloc<T>() -> T* {
return (T*)_z_internal_alloc_bytes(sizeof(T));
}
fn zalloc<T>() -> T* {
return (T*)_z_internal_zalloc_bytes(sizeof(T));
}
fn alloc_n<T>(n: usize) -> T* {
return (T*)_z_internal_alloc_bytes(sizeof(T) * n);
}
fn realloc_n<T>(ptr: T*, old_n: usize, new_n: usize) -> T* {
return (T*)_z_internal_realloc_bytes((void*)ptr, sizeof(T) * old_n, sizeof(T) * new_n);
}
fn dealloc<T>(ptr: T*) {
_z_internal_free((void*)ptr);
}
// --- Raw Byte API for C Interop ---
fn alloc_bytes(size: usize) -> void* {
return _z_internal_alloc_bytes(size);
}
fn zalloc_bytes(size: usize) -> void* {
return _z_internal_zalloc_bytes(size);
}
// --- Box and Traits ---
trait Drop {
fn drop(self);
}
trait Copy {}
trait Clone {
fn clone(self) -> Self;
}
struct Box<T> {
ptr: T*;
}
impl Box<T> {
fn new() -> Self {
return Self { ptr: alloc<T>() };
}
fn from_ptr(p: T*) -> Self {
return Self { ptr: p };
}
fn get(self) -> T* {
return self.ptr;
}
fn is_null(self) -> bool {
return self.ptr == NULL;
}
fn free(self) {
if self.ptr != NULL {
dealloc<T>(self.ptr);
self.ptr = NULL;
}
}
}
impl Drop for Box {
fn drop(self) {
self.free();
}
}
// Note: Slice<T> is defined in std/slice.zc with iteration support
fn mem_zero<T>(ptr: T*, count: usize) {
memset(ptr, 0, sizeof(T) * count);
}
fn mem_copy<T>(dst: T*, src: T*, count: usize) {
memcpy(dst, src, sizeof(T) * count);
}
fn swap<T>(a: T*, b: T*) {
let tmp = *a;
*a = *b;
*b = tmp;
}