#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; }; // #ifdef ENABLE_MEMPOOL #include "mempool.h" MEMPOOL_GENERATE(env, struct env, 256) MEMPOOL_GENERATE(env_kv, struct env_kv, 1024) #define env_alloc() env_mempool_allocate() #define env_free(v) env_mempool_free(v) #define env_kv_alloc() env_kv_mempool_allocate() #define env_kv_free(v) env_kv_mempool_free(v) // #else // #define env_alloc() malloc(sizeof(struct env)) // #define env_free(v) free(v) // #define env_kv_alloc() malloc(sizeof(struct env_kv)) // #define env_kv_free(v) free(v) // #endif 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_alloc(); 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_free(pair); } env_t env_create(env_t parent) { env_t env = env_alloc(); 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_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; } int env_depend(env_t parent, env_t dep) { if(!dep || !parent) return 0; if(dep == parent) return 1; return env_depend(parent, dep->parent); } #ifdef DEBUG static void _env_print(env_t env, int depth) { (void)depth; 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(" %s %s\n", pair->key, pair->value); } if(env->parent) { printf("--- parent start ---\n"); _env_print(env->parent, depth+2); printf("---- parent end ----\n"); } } void env_print(env_t env) { printf("--- env start ---\n"); _env_print(env, 0); printf("---- env end ----\n"); } #endif