From 789bd1309fb6223d229353e79100b1e9ba32b078 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Thu, 8 Jan 2026 18:53:56 +0000 Subject: [PATCH] mie: name: implement parent-child maps and recursive name searches --- mie/include/mie/name.h | 20 +++++++++- mie/name.c | 87 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 100 insertions(+), 7 deletions(-) diff --git a/mie/include/mie/name.h b/mie/include/mie/name.h index e40883a..52a0c7d 100644 --- a/mie/include/mie/name.h +++ b/mie/include/mie/name.h @@ -3,13 +3,21 @@ #include #include +#include +#include #define MIE_NAME_VALID(p) (((p)->n_str) != NULL) struct mie_name_map; enum mie_name_map_flags { - MIE_NAME_MAP_STRICT = 0x01u, + /* put(): take the name hint as the required name, and don't amend it + * to ensure uniqueness. if the given name already exists, the operation + * fails. */ + MIE_NAME_MAP_F_STRICT = 0x01u, + /* get(): if the given name does not exist in the name map, recursively + * search the parent map(s) until a result is found. */ + MIE_NAME_MAP_F_RECURSIVE = 0x02u, }; enum mie_name_map_entry_type { @@ -31,6 +39,10 @@ struct mie_name { struct mie_name_map_entry n_base; struct mie_name_map *n_parent; char *n_str; + + /* if this name was read from a file, these structs can be used to + * record the location within the file where the name is found. */ + struct mie_file_span n_start, n_end; }; struct mie_name_bucket { @@ -39,13 +51,17 @@ struct mie_name_bucket { }; struct mie_name_map { + const struct mie_name_map *m_parent; b_btree m_entries; size_t m_next_id; }; -extern struct mie_name_map *mie_name_map_create(void); +extern struct mie_name_map *mie_name_map_create(const struct mie_name_map *parent); extern void mie_name_map_destroy(struct mie_name_map *map); +extern const struct mie_name *mie_name_map_get( + const struct mie_name_map *map, const char *name, + enum mie_name_map_flags flags); extern struct mie_name *mie_name_map_put( struct mie_name_map *map, struct mie_name *entry, const char *hint, enum mie_name_map_flags flags); diff --git a/mie/name.c b/mie/name.c index 4b99ccf..58caac5 100644 --- a/mie/name.c +++ b/mie/name.c @@ -4,9 +4,10 @@ #include #include -B_BTREE_DEFINE_SIMPLE_INSERT(struct mie_name_map_entry, e_node, e_hash, put_entry) -B_BTREE_DEFINE_SIMPLE_GET( - struct mie_name_map_entry, uint64_t, e_node, e_hash, get_entry) +static B_BTREE_DEFINE_SIMPLE_INSERT( + struct mie_name_map_entry, e_node, e_hash, put_entry); +static B_BTREE_DEFINE_SIMPLE_GET( + struct mie_name_map_entry, uint64_t, e_node, e_hash, get_entry); static struct mie_name_bucket *create_bucket(void) { @@ -36,7 +37,7 @@ static void destroy_bucket(struct mie_name_bucket *bucket) free(bucket); } -struct mie_name_map *mie_name_map_create(void) +struct mie_name_map *mie_name_map_create(const struct mie_name_map *parent) { struct mie_name_map *out = malloc(sizeof *out); if (!out) { @@ -44,6 +45,8 @@ struct mie_name_map *mie_name_map_create(void) } memset(out, 0x0, sizeof *out); + out->m_parent = parent; + return out; } @@ -127,6 +130,80 @@ static b_status put_name(struct mie_name_map *map, struct mie_name *name) return B_SUCCESS; } +static bool check_name(const struct mie_name *name, const char *s, uint64_t hash) +{ + return name->n_base.e_hash == hash && !strcmp(name->n_str, s); +} + +static const struct mie_name *find_name_in_bucket( + const struct mie_name_bucket *bucket, const char *s, uint64_t hash) +{ + b_queue_entry *entry = b_queue_first(&bucket->b_names); + while (entry) { + struct mie_name_map_entry *map_entry + = b_unbox(struct mie_name_map_entry, entry, e_entry); + struct mie_name *name = (struct mie_name *)map_entry; + if (check_name(name, s, hash)) { + return name; + } + + entry = b_queue_next(entry); + } + + return NULL; +} + +static const struct mie_name *name_map_get( + const struct mie_name_map *map, const char *name, uint64_t name_hash) +{ + const struct mie_name_map_entry *entry + = get_entry(&map->m_entries, name_hash); + if (!entry) { + return NULL; + } + + const struct mie_name *name_entry = NULL; + struct mie_name_bucket *bucket = NULL; + + switch (entry->e_type) { + case MIE_NAME_MAP_E_NAME: + name_entry = (struct mie_name *)entry; + if (check_name(name_entry, name, name_hash)) { + return name_entry; + } + break; + case MIE_NAME_MAP_E_BUCKET: + bucket = (struct mie_name_bucket *)entry; + name_entry = find_name_in_bucket(bucket, name, name_hash); + if (name_entry) { + return name_entry; + } + + break; + default: + break; + } + + return NULL; +} + +const struct mie_name *mie_name_map_get( + const struct mie_name_map *map, const char *name, + enum mie_name_map_flags flags) +{ + uint64_t name_hash = b_hash_cstr(name); + while (map) { + const struct mie_name *result = name_map_get(map, name, name_hash); + if (result) { + return result; + } + + map = (flags & MIE_NAME_MAP_F_RECURSIVE) ? map->m_parent : NULL; + } + + return NULL; +} + struct mie_name *mie_name_map_put( struct mie_name_map *map, struct mie_name *entry, const char *hint, enum mie_name_map_flags flags) @@ -156,7 +233,7 @@ struct mie_name *mie_name_map_put( } } - if (flags & MIE_NAME_MAP_STRICT) { + if (flags & MIE_NAME_MAP_F_STRICT) { /* the caller insists that `hint` be used as the name. * such a name already exists, so we can't help them */ return NULL;