packages feed

nova-nix-0.1.9.0: cbits/nn_ctxstr.c

/*
 * nn_ctxstr.c — Context-bearing string allocation and tracking.
 *
 * Each nn_ctxstr_t is a single contiguous malloc (header + flexible
 * array of nn_sce_t elements).  Pointers are tracked in a global
 * dynamic array for bulk cleanup via nn_ctxstr_free_all().
 */

#include "nn_ctxstr.h"
#include "nn_assert.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* --- Tracking array --- */

#define NN_CTXSTR_INITIAL_CAPACITY 256u

static nn_ctxstr_t **g_tracked = NULL;
static uint32_t      g_tracked_count = 0;
static uint32_t      g_tracked_capacity = 0;

static void
track(nn_ctxstr_t *s)
{
    if (g_tracked_count >= g_tracked_capacity) {
        uint32_t new_cap = g_tracked_capacity == 0
                               ? NN_CTXSTR_INITIAL_CAPACITY
                               : g_tracked_capacity * 2;
        nn_ctxstr_t **new_arr = (nn_ctxstr_t **)realloc(
            g_tracked, (size_t)new_cap * sizeof(nn_ctxstr_t *));
        if (!new_arr) {
            fprintf(stderr, "nn_ctxstr_track: realloc failed\n");
            abort();
        }
        g_tracked = new_arr;
        g_tracked_capacity = new_cap;
    }
    g_tracked[g_tracked_count++] = s;
}

/* --- Lifecycle --- */

nn_ctxstr_t *
nn_ctxstr_new(uint32_t text, uint16_t ctx_count)
{
    size_t size = sizeof(nn_ctxstr_t) + (size_t)ctx_count * sizeof(nn_sce_t);
    nn_ctxstr_t *s = (nn_ctxstr_t *)malloc(size);
    if (!s) return NULL;
    s->text = text;
    s->ctx_count = ctx_count;
    memset(s->ctx, 0, (size_t)ctx_count * sizeof(nn_sce_t));
    track(s);
    return s;
}

void
nn_ctxstr_free_all(void)
{
    uint32_t i;
    for (i = 0; i < g_tracked_count; i++) {
        free(g_tracked[i]);
    }
    free(g_tracked);
    g_tracked = NULL;
    g_tracked_count = 0;
    g_tracked_capacity = 0;
}

/* --- Element setters --- */

void
nn_ctxstr_set_plain(nn_ctxstr_t *s, uint16_t idx,
                    uint32_t sp_hash, uint32_t sp_name)
{
    NN_ASSERT(idx < s->ctx_count, "nn_ctxstr_set_plain: idx out of bounds");
    s->ctx[idx].tag = NN_SCE_PLAIN;
    s->ctx[idx].sp_hash = sp_hash;
    s->ctx[idx].sp_name = sp_name;
    s->ctx[idx].output = 0;
}

void
nn_ctxstr_set_drv_output(nn_ctxstr_t *s, uint16_t idx,
                         uint32_t sp_hash, uint32_t sp_name,
                         uint32_t output)
{
    NN_ASSERT(idx < s->ctx_count, "nn_ctxstr_set_drv_output: idx out of bounds");
    s->ctx[idx].tag = NN_SCE_DRV_OUTPUT;
    s->ctx[idx].sp_hash = sp_hash;
    s->ctx[idx].sp_name = sp_name;
    s->ctx[idx].output = output;
}

void
nn_ctxstr_set_all_outputs(nn_ctxstr_t *s, uint16_t idx,
                          uint32_t sp_hash, uint32_t sp_name)
{
    NN_ASSERT(idx < s->ctx_count, "nn_ctxstr_set_all_outputs: idx out of bounds");
    s->ctx[idx].tag = NN_SCE_ALL_OUTPUTS;
    s->ctx[idx].sp_hash = sp_hash;
    s->ctx[idx].sp_name = sp_name;
    s->ctx[idx].output = 0;
}

/* --- Accessors --- */

uint32_t
nn_ctxstr_text(const nn_ctxstr_t *s)
{
    return s->text;
}

uint16_t
nn_ctxstr_ctx_count(const nn_ctxstr_t *s)
{
    return s->ctx_count;
}

uint8_t
nn_ctxstr_elem_tag(const nn_ctxstr_t *s, uint16_t idx)
{
    NN_ASSERT(idx < s->ctx_count, "nn_ctxstr_elem_tag: idx out of bounds");
    return s->ctx[idx].tag;
}

uint32_t
nn_ctxstr_elem_hash(const nn_ctxstr_t *s, uint16_t idx)
{
    NN_ASSERT(idx < s->ctx_count, "nn_ctxstr_elem_hash: idx out of bounds");
    return s->ctx[idx].sp_hash;
}

uint32_t
nn_ctxstr_elem_name(const nn_ctxstr_t *s, uint16_t idx)
{
    NN_ASSERT(idx < s->ctx_count, "nn_ctxstr_elem_name: idx out of bounds");
    return s->ctx[idx].sp_name;
}

uint32_t
nn_ctxstr_elem_output(const nn_ctxstr_t *s, uint16_t idx)
{
    NN_ASSERT(idx < s->ctx_count, "nn_ctxstr_elem_output: idx out of bounds");
    return s->ctx[idx].output;
}