From 98d82de47a4e709f45eb0a10a1b0517824840a2e Mon Sep 17 00:00:00 2001 From: Max Wash Date: Fri, 11 Apr 2025 13:40:37 +0100 Subject: [PATCH] mie: add name_map to generate unique value names --- mie/include/mie/name.h | 42 ++++++++++ mie/include/mie/value.h | 12 ++- mie/name.c | 167 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 mie/include/mie/name.h create mode 100644 mie/name.c diff --git a/mie/include/mie/name.h b/mie/include/mie/name.h new file mode 100644 index 0000000..7b99230 --- /dev/null +++ b/mie/include/mie/name.h @@ -0,0 +1,42 @@ +#ifndef MIE_NAME_H_ +#define MIE_NAME_H_ + +#include +#include + +enum mie_name_map_entry_type { + MIE_NAME_MAP_E_NONE = 0, + MIE_NAME_MAP_E_NAME, + MIE_NAME_MAP_E_BUCKET, +}; + +struct mie_name_map_entry { + enum mie_name_map_entry_type e_type; + uint64_t e_hash; + union { + b_queue_entry e_entry; + b_btree_node e_node; + }; +}; + +struct mie_name { + struct mie_name_map_entry n_base; + char *n_str; +}; + +struct mie_name_bucket { + struct mie_name_map_entry b_base; + b_queue b_names; +}; + +struct mie_name_map { + b_btree m_entries; +}; + +extern struct mie_name_map *mie_name_map_create(void); +extern void mie_name_map_destroy(struct mie_name_map *map); + +extern struct mie_name *mie_name_map_put( + struct mie_name_map *map, struct mie_name *entry, const char *hint); + +#endif diff --git a/mie/include/mie/value.h b/mie/include/mie/value.h index 3bc7d21..7f62296 100644 --- a/mie/include/mie/value.h +++ b/mie/include/mie/value.h @@ -3,6 +3,9 @@ #include #include +#include + +#define MIE_VALUE(p) ((struct mie_value *)(p)) enum mie_value_type { MIE_VALUE_NONE = 0, @@ -14,13 +17,20 @@ enum mie_value_type { MIE_VALUE_RECORD, }; +enum mie_value_flags { + MIE_VALUE_F_NONE = 0x00u, + MIE_VALUE_F_STATIC = 0x01u, +}; + struct mie_value { unsigned int v_ref; - char *v_name; + struct mie_name v_name; enum mie_value_type v_type; + enum mie_value_flags v_flags; b_queue_entry v_entry; }; +MIE_API void mie_value_init(struct mie_value *val, enum mie_value_type type); MIE_API struct mie_value *mie_value_retain(struct mie_value *val); MIE_API void mie_value_release(struct mie_value *val); diff --git a/mie/name.c b/mie/name.c new file mode 100644 index 0000000..e8179ac --- /dev/null +++ b/mie/name.c @@ -0,0 +1,167 @@ +#include +#include +#include +#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 struct mie_name_bucket *create_bucket(void) +{ + struct mie_name_bucket *out = malloc(sizeof *out); + + if (!out) { + return NULL; + } + + memset(out, 0x0, sizeof *out); + + out->b_base.e_type = MIE_NAME_MAP_E_BUCKET; + + return out; +} + +static void destroy_bucket(struct mie_name_bucket *bucket) +{ + b_queue_iterator it; + b_queue_iterator_begin(&bucket->b_names, &it); + + while (b_queue_iterator_is_valid(&it)) { + b_queue_iterator_erase(&it); + } + + free(bucket); +} + +struct mie_name_map *mie_name_map_create(void) +{ + struct mie_name_map *out = malloc(sizeof *out); + if (!out) { + return NULL; + } + + memset(out, 0x0, sizeof *out); + return out; +} + +void mie_name_map_destroy(struct mie_name_map *map) +{ + b_btree_iterator it; + b_btree_iterator_begin(&map->m_entries, &it); + + while (b_btree_iterator_is_valid(&it)) { + struct mie_name_map_entry *entry + = b_unbox(struct mie_name_map_entry, it.node, e_node); + b_btree_iterator_erase(&it); + + if (entry->e_type == MIE_NAME_MAP_E_BUCKET) { + struct mie_name_bucket *bucket + = (struct mie_name_bucket *)entry; + destroy_bucket(bucket); + } + } + + free(map); +} + +static b_status put_name_in_bucket( + struct mie_name_bucket *bucket, struct mie_name *name) +{ + b_queue_iterator it; + b_queue_foreach (&it, &bucket->b_names) { + struct mie_name *cur = (struct mie_name *)b_unbox( + struct mie_name_map_entry, it.entry, e_entry); + + if (!strcmp(cur->n_str, name->n_str)) { + return B_ERR_NAME_EXISTS; + } + } + + b_queue_push_back(&bucket->b_names, &name->n_base.e_entry); + + return B_SUCCESS; +} + +static b_status put_name(struct mie_name_map *map, struct mie_name *name) +{ + struct mie_name_map_entry *entry + = get_entry(&map->m_entries, name->n_base.e_hash); + + if (!entry) { + put_entry(&map->m_entries, &name->n_base); + return B_SUCCESS; + } + + if (entry->e_type == MIE_NAME_MAP_E_BUCKET) { + struct mie_name_bucket *bucket = (struct mie_name_bucket *)entry; + return put_name_in_bucket(bucket, name); + } + + struct mie_name *existing_name = (struct mie_name *)entry; + + if (!strcmp(existing_name->n_str, name->n_str)) { + return B_ERR_NAME_EXISTS; + } + + struct mie_name_bucket *bucket = create_bucket(); + if (!bucket) { + return B_ERR_NO_MEMORY; + } + + b_btree_delete(&map->m_entries, &entry->e_node); + entry->e_entry = B_QUEUE_ENTRY_INIT; + + bucket->b_base.e_hash = name->n_base.e_hash; + b_queue_push_back(&bucket->b_names, &existing_name->n_base.e_entry); + b_queue_push_back(&bucket->b_names, &name->n_base.e_entry); + + put_entry(&map->m_entries, &bucket->b_base); + + return B_SUCCESS; +} + +struct mie_name *mie_name_map_put( + struct mie_name_map *map, struct mie_name *entry, const char *hint) +{ + memset(entry, 0x0, sizeof *entry); + entry->n_base.e_type = MIE_NAME_MAP_E_NAME; + + b_rope base = B_ROPE_CSTR(hint); + + char str[256]; + + /* first try just the hint on its own */ + b_rope_to_cstr(&base, str, sizeof str); + entry->n_str = str; + entry->n_base.e_hash = base.r_v.v_cstr.hash; + b_status status = put_name(map, entry); + + if (B_OK(status)) { + entry->n_str = b_strdup(str); + return entry; + } + + /* that name already exists, use a suffix to make the name unique. */ + b_rope suffix = B_ROPE_UINT(0); + b_rope unique_name; + b_rope_concat(&unique_name, &base, &suffix); + + for (unsigned int i = 0;; i++) { + suffix.r_v.v_uint = i; + + b_rope_to_cstr(&unique_name, str, sizeof str); + + entry->n_str = str; + entry->n_base.e_hash = b_hash_string(str); + b_status status = put_name(map, entry); + + if (B_OK(status)) { + entry->n_str = b_strdup(str); + return entry; + } + } + + return NULL; +}