diff --git a/fx/include/fx/namemap.h b/fx/include/fx/namemap.h new file mode 100644 index 0000000..b040782 --- /dev/null +++ b/fx/include/fx/namemap.h @@ -0,0 +1,48 @@ +#ifndef FX_NAMEMAP_H_ +#define FX_NAMEMAP_H_ + +#include +#include +#include + +#define FX_NAMEMAP_INIT ((fx_namemap) {0}) + +typedef struct fx_namemap { + fx_bst m_entries; +} fx_namemap; + +struct __fx_namemap_entry { + int e_flags; + uint64_t e_hash; + void *e_bucket; + union { + fx_queue_entry e_entry; + fx_bst_node e_node; + }; +}; + +typedef struct fx_namemap_entry { + struct __fx_namemap_entry e_opaque; + const char *e_name; +} fx_namemap_entry; + +FX_API fx_status fx_namemap_cleanup(fx_namemap *map); + +FX_API fx_status +fx_namemap_put(fx_namemap *map, const char *name, fx_namemap_entry *entry); + +FX_API fx_namemap_entry *fx_namemap_get( + const fx_namemap *map, + const char *name); + +FX_API fx_namemap_entry *fx_namemap_first(const fx_namemap *map); +FX_API fx_namemap_entry *fx_namemap_last(const fx_namemap *map); + +FX_API fx_namemap_entry *fx_namemap_next( + const fx_namemap *map, + fx_namemap_entry *entry); +FX_API fx_namemap_entry *fx_namemap_prev( + const fx_namemap *map, + fx_namemap_entry *entry); + +#endif diff --git a/fx/namemap.c b/fx/namemap.c new file mode 100644 index 0000000..128ec19 --- /dev/null +++ b/fx/namemap.c @@ -0,0 +1,255 @@ +#include +#include + +enum map_entry_type { + MAP_ENTRY_NONE = 0, + MAP_ENTRY_ITEM, + MAP_ENTRY_BUCKET, +}; + +FX_BST_DEFINE_SIMPLE_GET( + struct __fx_namemap_entry, + uint64_t, + e_node, + e_hash, + map_get_entry); +FX_BST_DEFINE_SIMPLE_INSERT( + struct __fx_namemap_entry, + e_node, + e_hash, + map_put_entry); + +struct map_bucket { + struct __fx_namemap_entry b_entry; + fx_queue b_items; +}; + +static struct map_bucket *map_item_convert_to_bucket( + struct fx_namemap *map, + struct fx_namemap_entry *item) +{ + struct map_bucket *bucket = malloc(sizeof *bucket); + + memset(bucket, 0x0, sizeof *bucket); + + bucket->b_entry.e_hash = item->e_opaque.e_hash; + bucket->b_entry.e_flags = MAP_ENTRY_BUCKET; + + fx_bst_delete(&map->m_entries, &item->e_opaque.e_node); + fx_queue_push_back(&bucket->b_items, &item->e_opaque.e_entry); + item->e_opaque.e_bucket = bucket; + map_put_entry(&map->m_entries, &bucket->b_entry); + + return bucket; +} + +enum fx_status fx_namemap_cleanup(struct fx_namemap *map) +{ + return FX_SUCCESS; +} + +enum fx_status fx_namemap_put( + struct fx_namemap *map, + const char *name, + struct fx_namemap_entry *new_item) +{ + uint64_t hash = fx_hash_cstr(name); + + new_item->e_opaque.e_flags = MAP_ENTRY_ITEM; + new_item->e_opaque.e_hash = hash; + new_item->e_name = name; + + struct __fx_namemap_entry *entry = map_get_entry(&map->m_entries, hash); + if (!entry) { + map_put_entry(&map->m_entries, &new_item->e_opaque); + return FX_SUCCESS; + } + + struct fx_namemap_entry *existing_item = NULL; + struct map_bucket *bucket = NULL; + switch (entry->e_flags) { + case MAP_ENTRY_ITEM: + existing_item = (struct fx_namemap_entry *)entry; + bucket = map_item_convert_to_bucket(map, existing_item); + new_item->e_opaque.e_bucket = bucket; + fx_queue_push_back( + &bucket->b_items, + &new_item->e_opaque.e_entry); + break; + case MAP_ENTRY_BUCKET: + bucket = (struct map_bucket *)entry; + new_item->e_opaque.e_bucket = bucket; + fx_queue_push_back( + &bucket->b_items, + &new_item->e_opaque.e_entry); + break; + default: + break; + } + + return FX_SUCCESS; +} + +fx_namemap_entry *fx_namemap_get(const fx_namemap *map, const char *name) +{ + uint64_t hash = fx_hash_cstr(name); + struct __fx_namemap_entry *entry = map_get_entry(&map->m_entries, hash); + if (!entry) { + return NULL; + } + + struct fx_namemap_entry *item = NULL; + struct map_bucket *bucket = NULL; + struct fx_queue_entry *cur = NULL; + + switch (entry->e_flags) { + case MAP_ENTRY_ITEM: + item = (struct fx_namemap_entry *)entry; + if (!strcmp(item->e_name, name)) { + return item; + } + + break; + case MAP_ENTRY_BUCKET: + bucket = (struct map_bucket *)entry; + cur = fx_queue_first(&bucket->b_items); + while (cur) { + entry = fx_unbox( + struct __fx_namemap_entry, + cur, + e_entry); + item = (struct fx_namemap_entry *)entry; + if (!strcmp(item->e_name, name)) { + return item; + } + cur = fx_queue_next(cur); + } + break; + default: + break; + } + + return NULL; +} + +struct fx_namemap_entry *fx_namemap_first(const struct fx_namemap *map) +{ + struct fx_bst_node *first = fx_bst_first(&map->m_entries); + struct __fx_namemap_entry *entry = fx_unbox( + struct __fx_namemap_entry, + first, + e_node); + if (entry->e_flags == MAP_ENTRY_ITEM) { + return (struct fx_namemap_entry *)entry; + } + + struct map_bucket *bucket = (struct map_bucket *)entry; + struct fx_queue_entry *first_entry = fx_queue_first(&bucket->b_items); + return (struct fx_namemap_entry *) + fx_unbox(struct __fx_namemap_entry, first_entry, e_entry); +} + +struct fx_namemap_entry *fx_namemap_last(const struct fx_namemap *map) +{ + struct fx_bst_node *last = fx_bst_last(&map->m_entries); + struct __fx_namemap_entry *entry = fx_unbox( + struct __fx_namemap_entry, + last, + e_node); + if (entry->e_flags == MAP_ENTRY_ITEM) { + return (struct fx_namemap_entry *)entry; + } + + struct map_bucket *bucket = (struct map_bucket *)entry; + struct fx_queue_entry *last_entry = fx_queue_last(&bucket->b_items); + return (struct fx_namemap_entry *) + fx_unbox(struct __fx_namemap_entry, last_entry, e_entry); +} + +struct fx_namemap_entry *fx_namemap_next( + const struct fx_namemap *map, + struct fx_namemap_entry *entry) +{ + struct map_bucket *bucket = entry->e_opaque.e_bucket; + struct __fx_namemap_entry *next_entry = NULL; + if (bucket) { + struct fx_queue_entry *q_entry = fx_queue_next( + &entry->e_opaque.e_entry); + if (!q_entry) { + struct fx_bst_node *node = fx_bst_next( + &bucket->b_entry.e_node); + next_entry = fx_unbox( + struct __fx_namemap_entry, + node, + e_node); + } else { + next_entry = fx_unbox( + struct __fx_namemap_entry, + q_entry, + e_entry); + } + } else { + struct fx_bst_node *node = fx_bst_next(&entry->e_opaque.e_node); + next_entry = fx_unbox(struct __fx_namemap_entry, node, e_node); + } + + if (!next_entry) { + return NULL; + } + + if (next_entry->e_flags == MAP_ENTRY_BUCKET) { + bucket = (struct map_bucket *)next_entry; + struct fx_queue_entry *q_entry = fx_queue_first( + &bucket->b_items); + next_entry = fx_unbox( + struct __fx_namemap_entry, + q_entry, + e_entry); + } + + return (struct fx_namemap_entry *)next_entry; +} + +struct fx_namemap_entry *fx_namemap_prev( + const struct fx_namemap *map, + struct fx_namemap_entry *entry) +{ + struct map_bucket *bucket = entry->e_opaque.e_bucket; + struct __fx_namemap_entry *prev_entry = NULL; + if (bucket) { + struct fx_queue_entry *q_entry = fx_queue_prev( + &entry->e_opaque.e_entry); + if (!q_entry) { + struct fx_bst_node *node = fx_bst_prev( + &bucket->b_entry.e_node); + prev_entry = fx_unbox( + struct __fx_namemap_entry, + node, + e_node); + } else { + prev_entry = fx_unbox( + struct __fx_namemap_entry, + q_entry, + e_entry); + } + } else { + struct fx_bst_node *node = fx_bst_prev(&entry->e_opaque.e_node); + prev_entry = fx_unbox(struct __fx_namemap_entry, node, e_node); + } + + if (!prev_entry) { + return NULL; + } + + if (prev_entry->e_flags == MAP_ENTRY_BUCKET) { + bucket = (struct map_bucket *)prev_entry; + struct fx_queue_entry *q_entry = fx_queue_last( + &bucket->b_items); + prev_entry = fx_unbox( + struct __fx_namemap_entry, + q_entry, + e_entry); + } + + return (struct fx_namemap_entry *)prev_entry; +}