view src/atom.c @ 174:0c4e9e76a2f2

all: Make ylisp work in Release mode too by changing the way asserts are used when there are side-effects.
author Lewin Bormann <lbo@spheniscida.de>
date Mon, 09 Sep 2019 19:57:39 +0200
parents 7887550c61c6
children
line wrap: on
line source

#define _GNU_SOURCE
#include "atom.h"
#include "base/vec.h"

#include <assert.h>
#include <search.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>

// TODO: Adjust this later.
static const size_t YATOM_MAX_NUM_ATOMS = 256;
static const uint64_t YATOM_COUNTER_OFFSET = 0xa0a0a0a0a0;

static bool yatom_table_initialized = false;
// Table from atom name to atom id. This is not in the hot path of important functions!
static struct hsearch_data yatom_table;
static yvec_t yatom_names; // Vector of char*.
static yatom_t yatom_counter =
    YATOM_COUNTER_OFFSET;  // Make atom IDs recognizable.

static void yatom_init_table(void) {
    if (yatom_table_initialized) return;
    yatom_table_initialized = true;
    hcreate_r(YATOM_MAX_NUM_ATOMS, &yatom_table);
    yvec_init(&yatom_names, sizeof(const char*), YATOM_MAX_NUM_ATOMS);
}

yatom_t yatom_get_or_add(const char* name) {
    yatom_init_table();
    ENTRY wanted, *found;
    wanted.key = (char*)name;  // Safe, because we only use it for find.
    if (0 == hsearch_r(wanted, FIND, &found, &yatom_table)) {
        // Not found -- insert.
        wanted.key = strdup(name);
        wanted.data = (void*)yatom_counter++;
        YVEC_PUSH(&yatom_names, &wanted.key);
        assert(yatom_names.len == yatom_counter - YATOM_COUNTER_OFFSET);
        bool atom_found = hsearch_r(wanted, ENTER, &found, &yatom_table);
        assert(atom_found);
        return (yatom_t)wanted.data;
    } else {
        // Found.
        return (yatom_t)found->data;
    }
}

const char* yatom_name(yatom_t atom) {
    yatom_init_table();
    return *YVEC_AT(&yatom_names, atom - YATOM_COUNTER_OFFSET, yconstchar*);
}

void yatom_free_all(void) {
    for (size_t i = 0; i < yatom_counter-YATOM_COUNTER_OFFSET; i++) {
        free(*YVEC_AT(&yatom_names, i, char*));
    }
    yvec_destroy(&yatom_names);
    hdestroy_r(&yatom_table);
}