use b_plain typedef char *keymap_t(void *) def namespace_map_key(ns, key) ns->keymap ? ns->keymap(key) : key struct namespace namespace *parent keymap_t *keymap hashtable hash int namespace_buckets = 101 def namespace_init(ns) namespace_init(ns, NULL) def namespace_init(ns, parent) namespace_init(ns, parent, NULL) namespace_init(namespace *ns, namespace *parent, keymap_t *keymap) ns->parent = parent ns->keymap = keymap ? keymap : parent ? parent->keymap : NULL init(&ns->hash, hashtable, namespace_buckets) namespace_free(namespace *ns) hashtable_free(&ns->hash) namespace *namespace_child(namespace *ns) New(child, namespace, ns) return child int lookup_max_depth = 64 def namespace_lookup(ns, key) namespace_lookup(ns, key, 0) void *namespace_lookup(namespace *ns, void *key, int depth) cstr k = namespace_map_key(ns, key) if ++depth > lookup_max_depth error("namespace_lookup is caught in a loop while looking up %s", k) # XXX this is repeated in parent namespaces, # would they ever have different keymaps? let(kv, kv(&ns->hash, k)) if kv return kv->v if ns->parent return namespace_lookup(ns->parent, key, depth) return NULL void *namespace_lookup_skip(namespace *ns, void *key, int n) # this skips the first definition of something # and goes to the "next" one up, times n. if n == 0 return namespace_lookup(ns, key) if !ns->parent return NULL cstr k = namespace_map_key(ns, key) let(kv, kv(&ns->hash, k)) if kv --n return namespace_lookup_skip(ns->parent, key, n) # use let, not set! # set changes the meaning of the existing macro for parent scopes up to the last time it was defined but not above; # probably NOT what you want. # ((WTF @ this) # I could write a "kill" function and a "SET" function to completely redefine a macro for everyone, but YAGNI ATM namespace_set(namespace *ns, void *key, void *val) cstr k = namespace_map_key(ns, key) set(&ns->hash, Strdup(k), val) # NOTE The perl has this which was not used: # $self->{hash_order}{$k} = $self->{counter} namespace *namespace_let(namespace *ns, void *key, void *val) cstr k = namespace_map_key(ns, key) let(kv, kv(&ns->hash, k, val)) if kv->v != val ns = namespace_child(ns) set(&ns->hash, Strdup(k), val) return ns namespace *namespace_delete(namespace *ns, void *key) return namespace_let(ns, key, NULL) boolean namespace_defined(namespace *ns, void *key) return namespace_lookup(ns, key) != NULL