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