fx: add simple cstr-based hashmap data structure

This commit is contained in:
2026-05-05 12:38:34 +01:00
parent 2966934cd8
commit 8c12868651
2 changed files with 303 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
#ifndef FX_NAMEMAP_H_
#define FX_NAMEMAP_H_
#include <fx/bst.h>
#include <fx/misc.h>
#include <fx/queue.h>
#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
+255
View File
@@ -0,0 +1,255 @@
#include <fx/hash.h>
#include <fx/namemap.h>
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;
}