Ctrl K
ComunidadGuías…

std/mem.zc

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
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;
}