#include #include #include "common.h" #include "env.h" #include "list.h" #include "value.h" #define HAS(v, flag) (((v) & (flag)) == (flag)) struct env { struct env *parent; struct list_head *head; size_t refs; size_t circular_refs; }; struct env_kv { char *key; _value_t value; struct list_head list; int flags; }; #include "mempool.h" MEMPOOL_GENERATE(env, struct env, 256) MEMPOOL_GENERATE(env_kv, struct env_kv, 1024) static int equal(char *key1, char *key2) { return (strcmp(key1, key2) == 0); } static struct env_kv *env_kv_create(char *key, value_t value, int flags) { struct env_kv *pair = env_kv_mempool_allocate(); pair->key = key; pair->value = value; LIST_EMPTY(&pair->list); pair->flags = flags; return pair; } static void env_kv_destroy(struct env_kv *pair) { if(HAS(pair->flags, ENV_KV_FREE_KEY)) free(pair->key); value_destroy(pair->value); env_kv_mempool_free(pair); } env_t env_create(env_t parent) { env_t env = env_mempool_allocate(); 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 == ENV_EMPTY) return; if(env->refs > env->circular_refs) { env->refs--; return; } list_for_each_safe(head, env->head) { struct env_kv *p = list_entry(head, struct env_kv, list); if(HAS(p->flags, ENV_KV_CIRCULAR_REF)) env->circular_refs--; env_kv_destroy(p); } env_destroy(env->parent); env_mempool_free(env); } int env_insert(env_t env, char *key, _value_t value, _value_t *prevval, int flags) { 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) { 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) return env; env->refs++; return env; } // 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"); // } // }