Cleanups
[xonotic/gmqcc.git] / util.c
diff --git a/util.c b/util.c
index ae95df53a1cb0118dcee54f6c9373b2ccabd580e..ecae50516514e45db673cd10966ac408a010b0d1 100644 (file)
--- a/util.c
+++ b/util.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
-#include <stdarg.h>
-#include <errno.h>
-#include "gmqcc.h"
-
-/* TODO: remove globals ... */
-static uint64_t mem_ab = 0;
-static uint64_t mem_db = 0;
-static uint64_t mem_at = 0;
-static uint64_t mem_dt = 0;
-static uint64_t mem_pk = 0;
-static uint64_t mem_hw = 0;
-
-struct memblock_t {
-    const char  *file;
-    unsigned int line;
-    size_t       byte;
-    struct memblock_t *next;
-    struct memblock_t *prev;
-};
-
-#define PEAK_MEM             \
-    do {                     \
-        if (mem_hw > mem_pk) \
-            mem_pk = mem_hw; \
-    } while (0)
-
-static struct memblock_t *mem_start = NULL;
-
-void *util_memory_a(size_t byte, unsigned int line, const char *file) {
-    struct memblock_t *info = (struct memblock_t*)malloc(sizeof(struct memblock_t) + byte);
-    void              *data = (void*)(info+1);
-    if (!info) return NULL;
-    info->line = line;
-    info->byte = byte;
-    info->file = file;
-    info->prev = NULL;
-    info->next = mem_start;
-    if (mem_start)
-        mem_start->prev = info;
-    mem_start = info;
-
-    mem_at++;
-    mem_ab += info->byte;
-    mem_hw += info->byte;
-
-    PEAK_MEM;
-
-    return data;
-}
-
-void util_memory_d(void *ptrn) {
-    struct memblock_t *info = NULL;
-
-    if (!ptrn) return;
-    info = ((struct memblock_t*)ptrn - 1);
-
-    mem_db += info->byte;
-    mem_hw -= info->byte;
-    mem_dt++;
-
-    if (info->prev)
-        info->prev->next = info->next;
-    if (info->next)
-        info->next->prev = info->prev;
-    if (info == mem_start)
-        mem_start = info->next;
-
-    free(info);
-}
-
-void *util_memory_r(void *ptrn, size_t byte, unsigned int line, const char *file) {
-    struct memblock_t *oldinfo = NULL;
-
-    struct memblock_t *newinfo;
-
-    if (!ptrn)
-        return util_memory_a(byte, line, file);
-    if (!byte) {
-        util_memory_d(ptrn);
-        return NULL;
-    }
-
-    oldinfo = ((struct memblock_t*)ptrn - 1);
-    newinfo = ((struct memblock_t*)malloc(sizeof(struct memblock_t) + byte));
-
-    /* new data */
-    if (!newinfo) {
-        util_memory_d(oldinfo+1);
-        return NULL;
-    }
-
-    /* copy old */
-    memcpy(newinfo+1, oldinfo+1, oldinfo->byte);
-
-    /* free old */
-    if (oldinfo->prev)
-        oldinfo->prev->next = oldinfo->next;
-    if (oldinfo->next)
-        oldinfo->next->prev = oldinfo->prev;
-    if (oldinfo == mem_start)
-        mem_start = oldinfo->next;
-
-    /* fill info */
-    newinfo->line = line;
-    newinfo->byte = byte;
-    newinfo->file = file;
-    newinfo->prev = NULL;
-    newinfo->next = mem_start;
-    if (mem_start)
-        mem_start->prev = newinfo;
-    mem_start = newinfo;
-
-    mem_ab -= oldinfo->byte;
-    mem_hw -= oldinfo->byte;
-    mem_ab += newinfo->byte;
-    mem_hw += newinfo->byte;
-
-    PEAK_MEM;
-
-    free(oldinfo);
-
-    return newinfo+1;
-}
-
-static void util_dumpmem(struct memblock_t *memory, uint16_t cols) {
-    uint32_t i, j;
-    for (i = 0; i < memory->byte + ((memory->byte % cols) ? (cols - memory->byte % cols) : 0); i++) {
-        if (i % cols == 0)    con_out("    0x%06X: ", i);
-        if (i < memory->byte) con_out("%02X "   , 0xFF & ((char*)(memory + 1))[i]);
-        else                  con_out("    ");
-
-        if ((uint16_t)(i % cols) == (cols - 1)) {
-            for (j = i - (cols - 1); j <= i; j++) {
-                con_out("%c",
-                    (j >= memory->byte)
-                        ? ' '
-                        : (isprint(((char*)(memory + 1))[j]))
-                            ? 0xFF & ((char*)(memory + 1)) [j]
-                            : '.'
-                );
-            }
-            con_out("\n");
-        }
-    }
-}
-
-/*
- * The following is a VERY tight, efficent, hashtable for integer
- * values and keys, and for nothing more. We could make our existing
- * hashtable support type-genericness through a void * pointer but,
- * ideally that would make things more complicated. We also don't need
- * that much of a bloat for something as basic as this.
- */
-typedef struct {
-    size_t key;
-    size_t value;
-} size_entry_t;
-#define ST_SIZE 1024
+#include <string.h>
+#include <stdlib.h>
 
-typedef size_entry_t **size_table_t;
-
-size_table_t util_st_new() {
-    return (size_table_t)memset(
-        mem_a(sizeof(size_entry_t*) * ST_SIZE),
-        0, ST_SIZE * sizeof(size_entry_t*)
-    );
-}
-void util_st_del(size_table_t table) {
-    size_t i = 0;
-    for (; i < ST_SIZE; i++) if(table[i]) mem_d(table[i]);
-    mem_d(table);
-}
-size_entry_t *util_st_get(size_table_t table, size_t key) {
-    size_t hash = (key % ST_SIZE);
-    while (table[hash] && table[hash]->key != key)
-        hash = (hash + 1) % ST_SIZE;
-    return table[hash];
-}
-void util_st_put(size_table_t table, size_t key, size_t value) {
-    size_t hash = (key % ST_SIZE);
-    while (table[hash] && table[hash]->key != key)
-        hash = (hash + 1) % ST_SIZE;
-    table[hash]        = (size_entry_t*)mem_a(sizeof(size_entry_t));
-    table[hash]->key   = key;
-    table[hash]->value = value;
-}
-
-static uint64_t      strdups           = 0;
-static uint64_t      vectors           = 0;
-static uint64_t      vector_sizes      = 0;
-static uint64_t      hashtables        = 0;
-static uint64_t      hashtable_sizes   = 0;
-static size_table_t  vector_usage      = NULL;
-static size_table_t  hashtable_usage   = NULL;
-
-void util_meminfo() {
-    struct memblock_t *info;
-
-    if (OPTS_OPTION_BOOL(OPTION_DEBUG)) {
-        for (info = mem_start; info; info = info->next) {
-            con_out("lost: %u (bytes) at %s:%u\n",
-                info->byte,
-                info->file,
-                info->line);
-
-            util_dumpmem(info, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS));
-        }
-    }
-
-    if (OPTS_OPTION_BOOL(OPTION_DEBUG) ||
-        OPTS_OPTION_BOOL(OPTION_MEMCHK)) {
-        con_out("Memory information:\n\
-            Total allocations:   %llu\n\
-            Total deallocations: %llu\n\
-            Total allocated:     %f (MB)\n\
-            Total deallocated:   %f (MB)\n\
-            Total peak memory:   %f (MB)\n\
-            Total leaked memory: %f (MB) in %llu allocations\n",
-                mem_at,
-                mem_dt,
-                (float)(mem_ab)           / 1048576.0f,
-                (float)(mem_db)           / 1048576.0f,
-                (float)(mem_pk)           / 1048576.0f,
-                (float)(mem_ab -  mem_db) / 1048576.0f,
-
-                /* could be more clever */
-                (mem_at -  mem_dt)
-        );
-    }
-    
-    if (OPTS_OPTION_BOOL(OPTION_STATISTICS) ||
-        OPTS_OPTION_BOOL(OPTION_MEMCHK)) {
-        size_t   i         = 0;
-        size_t   e         = 1;
-        uint64_t vectormem = 0;
-        
-        con_out("\nAdditional Statistics:\n\
-            Total vectors allocated:      %llu\n\
-            Total string duplicates:      %llu\n\
-            Total hashtables allocated:   %llu\n\
-            Total unique vector sizes:    %llu\n",
-            vectors,
-            strdups,
-            hashtables,
-            vector_sizes
-        );
-        
-        for (; i < ST_SIZE; i++) {
-            size_entry_t *entry;
-            
-            if (!(entry = vector_usage[i]))
-                continue;
-            
-            con_out("                %2u| # of %4u byte vectors: %u\n",
-                (unsigned)e,
-                (unsigned)entry->key,
-                (unsigned)entry->value
-            );
-            e++;
-            
-            vectormem += entry->key * entry->value;
-        }
-
-        con_out("\
-            Total unique hashtable sizes: %llu\n",
-            hashtable_sizes
-        );
-        
-        for (i = 0, e = 1; i < ST_SIZE; i++) {
-            size_entry_t *entry;
-            
-            if (!(entry = hashtable_usage[i]))
-                continue;
-                
-            con_out("                %2u| # of %4u element hashtables: %u\n",
-                (unsigned)e,
-                (unsigned)entry->key,
-                (unsigned)entry->value
-            );
-            e++;
-        }
-        
-        con_out("            Total vector memory:          %f (MB)\n",
-            (float)(vectormem) / 1048576.0f
-        );
-    }
-
-    if (vector_usage)
-        util_st_del(vector_usage);
-    if (hashtable_usage)
-        util_st_del(hashtable_usage);
-}
+#include "gmqcc.h"
 
 /*
- * Some string utility functions, because strdup uses malloc, and we want
- * to track all memory (without replacing malloc).
+ * Initially this was handled with a table in the gmqcc.h header, but 
+ * much to my surprise the contents of the table was duplicated for
+ * each translation unit, causing all these strings to be duplicated
+ * for every .c file it was included into. This method culls back on
+ * it. This is a 'utility' function because the executor also depends
+ * on this for dissasembled bytecode.
  */
-char *_util_Estrdup(const char *s, const char *file, size_t line) {
-    size_t  len = 0;
-    char   *ptr = NULL;
-
-    /* in case of -DNOTRACK */
-    (void)file;
-    (void)line;
-
-    if (!s)
-        return NULL;
-
-    if ((len = strlen(s)) && (ptr = (char*)mem_af(len+1, line, file))) {
-        memcpy(ptr, s, len);
-        ptr[len] = '\0';
-    }
-    strdups++;
-    return ptr;
-}
-
-char *_util_Estrdup_empty(const char *s, const char *file, size_t line) {
-    size_t  len = 0;
-    char   *ptr = NULL;
-
-    /* in case of -DNOTRACK */
-    (void)file;
-    (void)line;
-
-    if (!s)
-        return NULL;
-
-    len = strlen(s);
-    if ((ptr = (char*)mem_af(len+1, line, file))) {
-        memcpy(ptr, s, len);
-        ptr[len] = '\0';
-    }
-    strdups++;
-    return ptr;
-}
+const char *util_instr_str[VINSTR_END] = {
+    "DONE",       "MUL_F",      "MUL_V",      "MUL_FV",
+    "MUL_VF",     "DIV_F",      "ADD_F",      "ADD_V",
+    "SUB_F",      "SUB_V",      "EQ_F",       "EQ_V",
+    "EQ_S",       "EQ_E",       "EQ_FNC",     "NE_F",
+    "NE_V",       "NE_S",       "NE_E",       "NE_FNC",
+    "LE",         "GE",         "LT",         "GT",
+    "LOAD_F",     "LOAD_V",     "LOAD_S",     "LOAD_ENT",
+    "LOAD_FLD",   "LOAD_FNC",   "ADDRESS",    "STORE_F",
+    "STORE_V",    "STORE_S",    "STORE_ENT",  "STORE_FLD",
+    "STORE_FNC",  "STOREP_F",   "STOREP_V",   "STOREP_S",
+    "STOREP_ENT", "STOREP_FLD", "STOREP_FNC", "RETURN",
+    "NOT_F",      "NOT_V",      "NOT_S",      "NOT_ENT",
+    "NOT_FNC",    "IF",         "IFNOT",      "CALL0",
+    "CALL1",      "CALL2",      "CALL3",      "CALL4",
+    "CALL5",      "CALL6",      "CALL7",      "CALL8",
+    "STATE",      "GOTO",       "AND",        "OR",
+    "BITAND",     "BITOR"
+};
 
 void util_debug(const char *area, const char *ms, ...) {
     va_list  va;
@@ -528,288 +225,31 @@ uint16_t util_crc16(const char *k, int len, const short clamp) {
 }
 #endif
 
-size_t util_strtocmd(const char *in, char *out, size_t outsz) {
-    size_t sz = 1;
-    for (; *in && sz < outsz; ++in, ++out, ++sz)
-        *out = (*in == '-') ? '_' : (isalpha(*in) && !isupper(*in)) ? *in + 'A' - 'a': *in;
-    *out = 0;
-    return sz-1;
-}
-
-size_t util_strtononcmd(const char *in, char *out, size_t outsz) {
+/* 
+ * modifier is the match to make and the transpsition from it, while add is the upper-value that determines the
+ * transposion from uppercase to lower case.
+ */
+static GMQCC_INLINE size_t util_strtransform(const char *in, char *out, size_t outsz, const char *mod, int add) {
     size_t sz = 1;
-    for (; *in && sz < outsz; ++in, ++out, ++sz)
-        *out = (*in == '_') ? '-' : (isalpha(*in) && isupper(*in)) ? *in + 'a' - 'A' : *in;
+    for (; *in && sz < outsz; ++in, ++out, ++sz) {
+        *out = (*in == mod[0])
+                    ? mod[1]
+                    : (util_isalpha(*in) && util_isupper(*in + add))
+                        ? *in + add
+                        : *in;
+    }
     *out = 0;
     return sz-1;
 }
 
-/* TODO: rewrite ... when I redo the ve cleanup */
-void _util_vec_grow(void **a, size_t i, size_t s) {
-    vector_t     *d = vec_meta(*a);
-    size_t        m = 0;
-    size_entry_t *e = NULL;
-    void         *p = NULL;
-    
-    if (*a) {
-        m = 2 * d->allocated + i;
-        p = mem_r(d, s * m + sizeof(vector_t));
-    } else {
-        m = i + 1;
-        p = mem_a(s * m + sizeof(vector_t));
-        ((vector_t*)p)->used = 0;
-        vectors++;
-    }
-    
-    if (!vector_usage)
-        vector_usage = util_st_new();
-
-    if ((e = util_st_get(vector_usage, s))) {
-        e->value ++;
-    } else {
-        util_st_put(vector_usage, s, 1); /* start off with 1 */
-        vector_sizes++;
-    }
-
-    *a = (vector_t*)p + 1;
-    vec_meta(*a)->allocated = m;
-}
-
-/*
- * Hash table for generic data, based on dynamic memory allocations
- * all around.  This is the internal interface, please look for
- * EXPOSED INTERFACE comment below
- */
-typedef struct hash_node_t {
-    char               *key;   /* the key for this node in table */
-    void               *value; /* pointer to the data as void*   */
-    struct hash_node_t *next;  /* next node (linked list)        */
-} hash_node_t;
-
-GMQCC_INLINE size_t util_hthash(hash_table_t *ht, const char *key) {
-    const uint32_t       mix   = 0x5BD1E995;
-    const uint32_t       rot   = 24;
-    size_t               size  = strlen(key);
-    uint32_t             hash  = 0x1EF0 /* LICRC TAB */  ^ size;
-    uint32_t             alias = 0;
-    const unsigned char *data  = (const unsigned char*)key;
-
-    while (size >= 4) {
-        alias  = (data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24));
-        alias *= mix;
-        alias ^= alias >> rot;
-        alias *= mix;
-
-        hash  *= mix;
-        hash  ^= alias;
-
-        data += 4;
-        size -= 4;
-    }
-
-    switch (size) {
-        case 3: hash ^= data[2] << 16;
-        case 2: hash ^= data[1] << 8;
-        case 1: hash ^= data[0];
-                hash *= mix;
-    }
-
-    hash ^= hash >> 13;
-    hash *= mix;
-    hash ^= hash >> 15;
-
-    return (size_t) (hash % ht->size);
-}
-
-static hash_node_t *_util_htnewpair(const char *key, void *value) {
-    hash_node_t *node;
-    if (!(node = (hash_node_t*)mem_a(sizeof(hash_node_t))))
-        return NULL;
-
-    if (!(node->key = util_strdupe(key))) {
-        mem_d(node);
-        return NULL;
-    }
-
-    node->value = value;
-    node->next  = NULL;
-
-    return node;
-}
-
-/*
- * EXPOSED INTERFACE for the hashtable implementation
- * util_htnew(size)                             -- to make a new hashtable
- * util_htset(table, key, value, sizeof(value)) -- to set something in the table
- * util_htget(table, key)                       -- to get something from the table
- * util_htdel(table)                            -- to delete the table
- */
-hash_table_t *util_htnew(size_t size) {
-    hash_table_t *hashtable = NULL;
-    size_entry_t *find;
-    
-    if (size < 1)
-        return NULL;
-        
-    if (!hashtable_usage)
-        hashtable_usage = util_st_new();
-
-    if (!(hashtable = (hash_table_t*)mem_a(sizeof(hash_table_t))))
-        return NULL;
-
-    if (!(hashtable->table = (hash_node_t**)mem_a(sizeof(hash_node_t*) * size))) {
-        mem_d(hashtable);
-        return NULL;
-    }
-    
-    if ((find = util_st_get(hashtable_usage, size)))
-        find->value++;
-    else {
-        hashtable_sizes++;
-        util_st_put(hashtable_usage, size, 1);
-    }
-
-    hashtable->size = size;
-    memset(hashtable->table, 0, sizeof(hash_node_t*) * size);
-
-    hashtables++;
-    return hashtable;
-}
-
-void util_htseth(hash_table_t *ht, const char *key, size_t bin, void *value) {
-    hash_node_t *newnode = NULL;
-    hash_node_t *next    = NULL;
-    hash_node_t *last    = NULL;
-
-    next = ht->table[bin];
-
-    while (next && next->key && strcmp(key, next->key) > 0)
-        last = next, next = next->next;
-
-    /* already in table, do a replace */
-    if (next && next->key && strcmp(key, next->key) == 0) {
-        next->value = value;
-    } else {
-        /* not found, grow a pair man :P */
-        newnode = _util_htnewpair(key, value);
-        if (next == ht->table[bin]) {
-            newnode->next  = next;
-            ht->table[bin] = newnode;
-        } else if (!next) {
-            last->next = newnode;
-        } else {
-            newnode->next = next;
-            last->next = newnode;
-        }
-    }
-}
-
-void util_htset(hash_table_t *ht, const char *key, void *value) {
-    util_htseth(ht, key, util_hthash(ht, key), value);
-}
-
-void *util_htgeth(hash_table_t *ht, const char *key, size_t bin) {
-    hash_node_t *pair = ht->table[bin];
-
-    while (pair && pair->key && strcmp(key, pair->key) > 0)
-        pair = pair->next;
-
-    if (!pair || !pair->key || strcmp(key, pair->key) != 0)
-        return NULL;
-
-    return pair->value;
-}
-
-void *util_htget(hash_table_t *ht, const char *key) {
-    return util_htgeth(ht, key, util_hthash(ht, key));
-}
-
-void *code_util_str_htgeth(hash_table_t *ht, const char *key, size_t bin) {
-    hash_node_t *pair;
-    size_t len, keylen;
-    int cmp;
-
-    keylen = strlen(key);
-
-    pair = ht->table[bin];
-    while (pair && pair->key) {
-        len = strlen(pair->key);
-        if (len < keylen) {
-            pair = pair->next;
-            continue;
-        }
-        if (keylen == len) {
-            cmp = strcmp(key, pair->key);
-            if (cmp == 0)
-                return pair->value;
-            if (cmp < 0)
-                return NULL;
-            pair = pair->next;
-            continue;
-        }
-        cmp = strcmp(key, pair->key + len - keylen);
-        if (cmp == 0) {
-            uintptr_t up = (uintptr_t)pair->value;
-            up += len - keylen;
-            return (void*)up;
-        }
-        pair = pair->next;
-    }
-    return NULL;
-}
-
-/*
- * Free all allocated data in a hashtable, this is quite the amount
- * of work.
- */
-void util_htrem(hash_table_t *ht, void (*callback)(void *data)) {
-    size_t i = 0;
-    for (; i < ht->size; i++) {
-        hash_node_t *n = ht->table[i];
-        hash_node_t *p;
-
-        /* free in list */
-        while (n) {
-            if (n->key)
-                mem_d(n->key);
-            if (callback)
-                callback(n->value);
-            p = n;
-            n = n->next;
-            mem_d(p);
-        }
-
-    }
-    /* free table */
-    mem_d(ht->table);
-    mem_d(ht);
-}
-
-void util_htrmh(hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*)) {
-    hash_node_t **pair = &ht->table[bin];
-    hash_node_t *tmp;
-
-    while (*pair && (*pair)->key && strcmp(key, (*pair)->key) > 0)
-        pair = &(*pair)->next;
-
-    tmp = *pair;
-    if (!tmp || !tmp->key || strcmp(key, tmp->key) != 0)
-        return;
-
-    if (cb)
-        (*cb)(tmp->value);
-
-    *pair = tmp->next;
-    mem_d(tmp->key);
-    mem_d(tmp);
+size_t util_strtocmd(const char *in, char *out, size_t outsz) {
+    return util_strtransform(in, out, outsz, "-_", 'A'-'a');
 }
-
-void util_htrm(hash_table_t *ht, const char *key, void (*cb)(void*)) {
-    util_htrmh(ht, key, util_hthash(ht, key), cb);
+size_t util_strtononcmd(const char *in, char *out, size_t outsz) {
+    return util_strtransform(in, out, outsz, "_-", 'a'-'A');
 }
-
-void util_htdel(hash_table_t *ht) {
-    util_htrem(ht, NULL);
+size_t util_optimizationtostr(const char *in, char *out, size_t outsz) {
+    return util_strtransform(in, out, outsz, "_ ", 'a'-'A');
 }
 
 /*
@@ -919,7 +359,7 @@ int util_asprintf(char **ret, const char *fmt, ...) {
 
         allocated = (char*)mem_a(4096); /* A page must be enough */
         strerror_s(allocated, 4096, num);
-    
+
         vec_push(vector, allocated);
         return (const char *)allocated;
     }
@@ -988,7 +428,7 @@ int util_asprintf(char **ret, const char *fmt, ...) {
 static uint32_t mt_state[MT_SIZE];
 static size_t   mt_index = 0;
 
-static GMQCC_INLINE void mt_generate() {
+static GMQCC_INLINE void mt_generate(void) {
     /*
      * The loop has been unrolled here: the original paper and implemenation
      * Called for the following code:
@@ -1024,7 +464,7 @@ static GMQCC_INLINE void mt_generate() {
      * Said loop has been unrolled for MT_SPACE (226 iterations), opposed
      * to [0, MT_SIZE)  (634 iterations).
      */
-    for (i = 0; i < MT_SPACE; ++i) {
+    for (i = 0; i < MT_SPACE-1; ++i) {
         y           = (0x80000000 & mt_state[i]) | (0x7FFFFFF & mt_state[i + 1]);
         mt_state[i] = mt_state[i + MT_PERIOD] ^ (y >> 1) ^ matrix[y & 1];
 
@@ -1039,7 +479,7 @@ static GMQCC_INLINE void mt_generate() {
      * = 2*2*3*3*11])
      */
     i = MT_SPACE;
-    while (i < MT_SIZE - 1) {
+    while (i < MT_SIZE-2) {
         /*
          * We expand this 11 times .. manually, no macros are required
          * here. This all fits in the CPU cache.