mie: add name_map to generate unique value names
This commit is contained in:
42
mie/include/mie/name.h
Normal file
42
mie/include/mie/name.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#ifndef MIE_NAME_H_
|
||||||
|
#define MIE_NAME_H_
|
||||||
|
|
||||||
|
#include <blue/core/btree.h>
|
||||||
|
#include <blue/core/queue.h>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#include <blue/core/queue.h>
|
#include <blue/core/queue.h>
|
||||||
#include <mie/misc.h>
|
#include <mie/misc.h>
|
||||||
|
#include <mie/name.h>
|
||||||
|
|
||||||
|
#define MIE_VALUE(p) ((struct mie_value *)(p))
|
||||||
|
|
||||||
enum mie_value_type {
|
enum mie_value_type {
|
||||||
MIE_VALUE_NONE = 0,
|
MIE_VALUE_NONE = 0,
|
||||||
@@ -14,13 +17,20 @@ enum mie_value_type {
|
|||||||
MIE_VALUE_RECORD,
|
MIE_VALUE_RECORD,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum mie_value_flags {
|
||||||
|
MIE_VALUE_F_NONE = 0x00u,
|
||||||
|
MIE_VALUE_F_STATIC = 0x01u,
|
||||||
|
};
|
||||||
|
|
||||||
struct mie_value {
|
struct mie_value {
|
||||||
unsigned int v_ref;
|
unsigned int v_ref;
|
||||||
char *v_name;
|
struct mie_name v_name;
|
||||||
enum mie_value_type v_type;
|
enum mie_value_type v_type;
|
||||||
|
enum mie_value_flags v_flags;
|
||||||
b_queue_entry v_entry;
|
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 struct mie_value *mie_value_retain(struct mie_value *val);
|
||||||
MIE_API void mie_value_release(struct mie_value *val);
|
MIE_API void mie_value_release(struct mie_value *val);
|
||||||
|
|
||||||
|
|||||||
167
mie/name.c
Normal file
167
mie/name.c
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
#include <blue/core/rope.h>
|
||||||
|
#include <blue/object/string.h>
|
||||||
|
#include <mie/name.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user