fx: add simple cstr-based hashmap data structure
This commit is contained in:
@@ -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
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user