/* =====================================
 * Generated by Mod-c 0.26.5
 * MODULE arena
 * ===================================== */

#include "arena.h"

void arena(void);

/**
 * Mod-c
 * By M. Scott Reynolds
 * Date 20 February 2026
 *
 * arena.c - Linear / bump allocator with linked chunks
 * 
 * 25 July 2026
 * Growth never relocates existing slabs (pointer-stable).
 * Old bug: single-slab realloc invalidated interior pointers (AST, symtab).
 */
#include "stddef.h"
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
static const cardinal ARENA_ALIGNMENT = 8;
static const cardinal ARENA_MIN_SIZE = 1048576;
/** One malloc'd slab: header + payload. Never realloc this block */
typedef ArenaChunk* pArenaChunk;
/** 
 * Opaque arena allocator structure.
 */
/**
 * Payload starts immediately after the chunk header. 
 */
static pchar arena_chunk_data(pArenaChunk c)
{
    /* return value captured before defers */
    pchar __ret_l54 = ((pchar)c) + ((integer)sizeof(ArenaChunk));
    return __ret_l54;
}

/**
 * Allocate a new chunk with at least payload_size bytes of payload.
 * Links are left nil; caller attaches to the list.
 */
static pArenaChunk arena_chunk_create(size_t payload_size)
{
    size_t total = {0};
    pvoid raw = {0};
    pArenaChunk c = {0};
    size_t ps = payload_size;
    if (ps < ARENA_MIN_SIZE)
    {
        ps = ARENA_MIN_SIZE;
    }
    total = ((integer)sizeof(ArenaChunk)) + ps;
    if (total < ps)
    {
        fprintf(stderr, "ERROR: arena_chunk_create: size overflow\n");
        exit(1);
    }
        raw = calloc(1, total);
    if (raw == nil)
    {
        fprintf(stderr, "ERROR: arena_chunk_create: calloc(1, %zu) failed\n", total);
        exit(1);
    }
    c = (pArenaChunk)raw;
    ((*c)).next = nil;
    ((*c)).size = ps;
    ((*c)).used = 0;
    /* return value captured before defers */
    pArenaChunk __ret_l93 = c;
    return __ret_l93;
}

/**
 * Initialize an arena with given initial capacity.
 * Exits program on allocation failure.
 */
void arena_init(pArena a, size_t initial_size)
{
    assert(a != nil); /* precondition */
    size_t n = initial_size;
    if (a == nil)
    {
        fprintf(stderr, "ERROR: arena_init: NULL arena\n");
        exit(1);
    }
    if (n < ARENA_MIN_SIZE)
    {
        n = ARENA_MIN_SIZE;
    }
    ((*a)).head = arena_chunk_create(n);
    ((*a)).current = ((*a)).head;
}

/**
 * Append a new chunk large enough for 'needed' payload bytes.
 * Previous chunks are left intact (pointers into them stay valid).
 */
static void arena_add_chunk(pArena a, size_t needed)
{
    size_t chunk_size = {0};
    size_t doubled = {0};
    pArenaChunk c = {0};
    if (a == nil || ((*a)).current == nil)
    {
        fprintf(stderr, "ERROR: arena_add_chunk: arena not initialized\n");
        exit(1);
    }
    chunk_size = ARENA_MIN_SIZE;
    if (((*((*a)).current)).size > chunk_size)
    {
        chunk_size = ((*((*a)).current)).size;
    }
    doubled = chunk_size * 2u;
    if (doubled / 2u == chunk_size && doubled > chunk_size)
    {
        chunk_size = doubled;
    }
    if (needed > chunk_size)
    {
        chunk_size = needed;
    }
    c = arena_chunk_create(chunk_size);
    ((*((*a)).current)).next = c;
    ((*a)).current = c;
}

/**
 * Allocate 'size' bytes with ARENA_ALIGNMENT alignment.
 * Automatically grows arena if needed.
 * Never returns NULL (exits on failure).
 */
pvoid arena_alloc(pArena a, size_t size)
{
    assert(a != nil); /* precondition */
    size_t aligned = {0};
    pvoid ptr = {0};
    pArenaChunk cur = {0};
    size_t n = size;
    if (a == nil)
    {
        fprintf(stderr, "ERROR: arena_alloc: NULL arena\n");
        exit(1);
    }
    if (n == 0)
    {
        n = 1;
    }
    aligned = (n + ARENA_ALIGNMENT - 1u) & ~(ARENA_ALIGNMENT - 1u);
    cur = ((*a)).current;
    if (cur == nil)
    {
        fprintf(stderr, "ERROR: arena_alloc: arena not initialized\n");
        exit(1);
    }
    if (((*cur)).used + aligned > ((*cur)).size)
    {
        arena_add_chunk(a, aligned);
        cur = ((*a)).current;
    }
    ptr = (pvoid)(arena_chunk_data(cur) + ((*cur)).used);
    memset(ptr, 0, aligned);
    ((*cur)).used = ((*cur)).used + aligned;
    /* return value captured before defers */
    pvoid __ret_l195 = ptr;
    return __ret_l195;
}

/**
 * Reset: keep the first chunk, free any extra chunks, bump from head again.
 * Safe for multi-file compiles in one process.
 */
void arena_reset(pArena a)
{
    pArenaChunk c = {0};
    pArenaChunk next = {0};
    if (a == nil || ((*a)).head == nil)
    {
                return;
    }
    c = ((*((*a)).head)).next;
    while (c != nil)
    {
        {
            next = ((*c)).next;
            free(c);
            c = next;
        }
    }
    ((*((*a)).head)).next = nil;
    ((*((*a)).head)).used = 0;
    ((*a)).current = ((*a)).head;
}

/**
 * Free all memory owned the arena.
 * Safe to call multiple times.
 */
void arena_free(pArena a)
{
    pArenaChunk c = {0};
    pArenaChunk next = {0};
    if (a == nil)
    {
                return;
    }
    c = ((*a)).head;
    while (c != nil)
    {
        {
            next = ((*c)).next;
            free(c);
            c = next;
        }
    }
    ((*a)).head = nil;
    ((*a)).current = nil;
}

/**
 * arena_ensure_capacity - grow pointer array if needed (doubling strategy)
 */
void arena_ensure_capacity(Arena* arena, ppvoid array_ptr, size_t* count, size_t* capacity)
{
    size_t new_capacity = {0};
    ppvoid new_array = {0};
    if ((*count) < (*capacity))
    {
                return;
    }
    new_capacity = ((*capacity) ? (*capacity) * 2u : 8u);
    if ((*capacity) > 0 && new_capacity / 2u != (*capacity))
    {
        fprintf(stderr, "ERROR: arena_ensure_capacity: capacity overflow\n");
        exit(1);
    }
    new_array = (ppvoid)arena_alloc(arena, new_capacity * ((integer)sizeof(pvoid)));
    if ((*array_ptr) != nil)
    {
        memcpy(new_array, (*array_ptr), (*count) * ((integer)sizeof(pvoid)));
    }
    (*array_ptr) = new_array;
    (*capacity) = new_capacity;
}

/**
 * arena_append_ptr - Append one pointer to a dynamic array of pointers.
 * Grows the array using doubling strategy (min 8) if needed.
 * Never returns NULL - exits on fatal error.
 *
 * @param arena 	Initialized arena
 * @param array_ptr	Pointer to the array base pointer (Node**, TType**, etc.)
 * @param count 	Current element count (will be incremented)
 * @param capacity 	Current allocated slots (will be updated if grown)
 * @param item 		Pointer to value to append
 */
void arena_append_ptr(Arena* arena, ppvoid array_ptr, size_t* count, size_t* capacity, pvoid item)
{
    arena_ensure_capacity(arena, array_ptr, count, capacity);
    const ppvoid p_l301_c7 = (ppvoid)(*array_ptr);
    p_l301_c7[(*count)] = item;
    (*count) = (*count) + 1;
}


void arena(void)
{
}
