diff options
Diffstat (limited to 'src/env.c')
-rw-r--r-- | src/env.c | 151 |
1 files changed, 101 insertions, 50 deletions
@@ -4,102 +4,153 @@ #include "common.h" #include "env.h" -#include "hashtable.h" +#include "list.h" #include "value.h" -struct env { - hashtable_t table; +#define HAS(v, flag) (((v) & (flag)) == (flag)) +struct env { struct env *parent; + struct list_head *head; + size_t refs; + size_t circular_refs; +}; - env_destroy_func destroy_func; +struct env_kv { + char *key; + _value_t value; + struct list_head list; + + int flags; }; #include "mempool.h" -MEMPOOL_GENERATE(env, struct env, 64) - -#define ENV_TABLE_CAP (1 << 3) +MEMPOOL_GENERATE(env, struct env, 256) +MEMPOOL_GENERATE(env_kv, struct env_kv, 1024) -static unsigned long str_hash(char *str) +static int equal(char *key1, char *key2) { - unsigned long hash = 5381; - int c; - - while ((c = *str++)) - hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ - - return hash; + return (strcmp(key1, key2) == 0); } -static size_t hash(void *key) +static struct env_kv *env_kv_create(char *key, value_t value, int flags) { - return str_hash((char*)key); + struct env_kv *pair = env_kv_mempool_allocate(); + + pair->key = key; + pair->value = value; + LIST_EMPTY(&pair->list); + pair->flags = flags; + + return pair; } -static bool equal(void *key1, void *key2) +static void env_kv_destroy(struct env_kv *pair) { - if(strcmp((char *)key1, (char*)key2) == 0) { - return true; - } + if(HAS(pair->flags, ENV_KV_FREE_KEY)) + free(pair->key); - return false; + value_destroy(pair->value); + env_kv_mempool_free(pair); } -env_t env_create(env_t parent, env_destroy_func destroy_func) +env_t env_create(env_t parent) { - // env_t env = malloc(sizeof(*env)); env_t env = env_mempool_allocate(); - env->destroy_func = destroy_func; - env->parent = parent; - env->refs = 1; - - ERR_Z(env->table = hashtable_create(ENV_TABLE_CAP, hash, equal), - env_destroy(env)); + env->parent = env_copy(parent); + env->head = NULL; + env->refs = 0; + env->circular_refs = 0; return env; } void env_destroy(env_t env) { - if(!env) return; + if(env == ENV_EMPTY) return; - env->refs--; - env_destroy(env->parent); + if(env->refs > env->circular_refs) { + env->refs--; + return; + } - if(env->refs > 0) return; + list_for_each_safe(head, env->head) { + struct env_kv *p = list_entry(head, struct env_kv, list); - hashtable_for_each_item(env->table, item, i) { - env->destroy_func((char *)item->key, (value_t)item->data); + if(HAS(p->flags, ENV_KV_CIRCULAR_REF)) env->circular_refs--; + env_kv_destroy(p); } - hashtable_destroy(env->table); - // free(env); + env_destroy(env->parent); env_mempool_free(env); } -int env_insert(env_t env, char *key, value_t data, - char **prevkey, value_t *prevdata) +int env_insert(env_t env, char *key, _value_t value, + _value_t *prevval, int flags) { - return hashtable_insert(env->table, (void *)key, (void *)data, (void **)prevkey, (void **)prevdata); + if(env->head) + list_for_each_entry(struct env_kv, p, list, env->head) { + if(!equal(p->key, key)) continue; + + env->circular_refs += + (HAS(flags, ENV_KV_CIRCULAR_REF) - + HAS(p->flags, ENV_KV_CIRCULAR_REF)); + p->flags = flags; + + if(prevval) *prevval = p->value; + p->value = value; + return 0; + } + + if(HAS(flags, ENV_KV_CIRCULAR_REF)) env->circular_refs++; + + struct env_kv *pair = env_kv_create(key, value, flags); + if(env->head) list_append(&pair->list, env->head); + env->head = &pair->list; + + return 0; } -int env_query(env_t env, char *key, value_t *data) +int env_query(env_t env, char *key, _value_t *data) { - return hashtable_query(env->table, (void *)key, (void **)data); + struct env_kv *pair = NULL; + + for(env_t e = env; e; e = e->parent) { + if(e->head == NULL) continue; + list_for_each_entry(struct env_kv, p, list, e->head) { + if(equal(p->key, key)) pair = p; + } + + if(pair) break; + } + + if(!pair) return 1; + + *data = pair->value; + return 0; } env_t env_copy(env_t env) { - if(env == ENV_EMPTY) return ENV_EMPTY; + if(!env) return env; env->refs++; - env_copy(env->parent); - return env; } -env_t env_parent(env_t env) -{ - return env->parent; -} +// void env_print(env_t env) +// { +// printf("REFS: %d\n", env->refs); +// printf("CREFS: %d\n", env->circular_refs); +// if(!env || !env->head) return; +// list_for_each_entry(struct env_kv, pair, list, env->head) { +// printf("ENTRY: %s %s\n", pair->key, pair->value); +// } + +// if(env->parent) { +// printf("---- PARENT ----\n"); +// env_print(env->parent); +// printf("-- END PARENT --\n"); +// } +// } |