mie: name: implement parent-child maps and recursive name searches
This commit is contained in:
@@ -3,13 +3,21 @@
|
|||||||
|
|
||||||
#include <blue/core/btree.h>
|
#include <blue/core/btree.h>
|
||||||
#include <blue/core/queue.h>
|
#include <blue/core/queue.h>
|
||||||
|
#include <mie/misc.h>
|
||||||
|
#include <mie/parse/file-span.h>
|
||||||
|
|
||||||
#define MIE_NAME_VALID(p) (((p)->n_str) != NULL)
|
#define MIE_NAME_VALID(p) (((p)->n_str) != NULL)
|
||||||
|
|
||||||
struct mie_name_map;
|
struct mie_name_map;
|
||||||
|
|
||||||
enum mie_name_map_flags {
|
enum mie_name_map_flags {
|
||||||
MIE_NAME_MAP_STRICT = 0x01u,
|
/* put(): take the name hint as the required name, and don't amend it
|
||||||
|
* to ensure uniqueness. if the given name already exists, the operation
|
||||||
|
* fails. */
|
||||||
|
MIE_NAME_MAP_F_STRICT = 0x01u,
|
||||||
|
/* get(): if the given name does not exist in the name map, recursively
|
||||||
|
* search the parent map(s) until a result is found. */
|
||||||
|
MIE_NAME_MAP_F_RECURSIVE = 0x02u,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum mie_name_map_entry_type {
|
enum mie_name_map_entry_type {
|
||||||
@@ -31,6 +39,10 @@ struct mie_name {
|
|||||||
struct mie_name_map_entry n_base;
|
struct mie_name_map_entry n_base;
|
||||||
struct mie_name_map *n_parent;
|
struct mie_name_map *n_parent;
|
||||||
char *n_str;
|
char *n_str;
|
||||||
|
|
||||||
|
/* if this name was read from a file, these structs can be used to
|
||||||
|
* record the location within the file where the name is found. */
|
||||||
|
struct mie_file_span n_start, n_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mie_name_bucket {
|
struct mie_name_bucket {
|
||||||
@@ -39,13 +51,17 @@ struct mie_name_bucket {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct mie_name_map {
|
struct mie_name_map {
|
||||||
|
const struct mie_name_map *m_parent;
|
||||||
b_btree m_entries;
|
b_btree m_entries;
|
||||||
size_t m_next_id;
|
size_t m_next_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct mie_name_map *mie_name_map_create(void);
|
extern struct mie_name_map *mie_name_map_create(const struct mie_name_map *parent);
|
||||||
extern void mie_name_map_destroy(struct mie_name_map *map);
|
extern void mie_name_map_destroy(struct mie_name_map *map);
|
||||||
|
|
||||||
|
extern const struct mie_name *mie_name_map_get(
|
||||||
|
const struct mie_name_map *map, const char *name,
|
||||||
|
enum mie_name_map_flags flags);
|
||||||
extern struct mie_name *mie_name_map_put(
|
extern struct mie_name *mie_name_map_put(
|
||||||
struct mie_name_map *map, struct mie_name *entry, const char *hint,
|
struct mie_name_map *map, struct mie_name *entry, const char *hint,
|
||||||
enum mie_name_map_flags flags);
|
enum mie_name_map_flags flags);
|
||||||
|
|||||||
87
mie/name.c
87
mie/name.c
@@ -4,9 +4,10 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
B_BTREE_DEFINE_SIMPLE_INSERT(struct mie_name_map_entry, e_node, e_hash, put_entry)
|
static B_BTREE_DEFINE_SIMPLE_INSERT(
|
||||||
B_BTREE_DEFINE_SIMPLE_GET(
|
struct mie_name_map_entry, e_node, e_hash, put_entry);
|
||||||
struct mie_name_map_entry, uint64_t, e_node, e_hash, get_entry)
|
static 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)
|
static struct mie_name_bucket *create_bucket(void)
|
||||||
{
|
{
|
||||||
@@ -36,7 +37,7 @@ static void destroy_bucket(struct mie_name_bucket *bucket)
|
|||||||
free(bucket);
|
free(bucket);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mie_name_map *mie_name_map_create(void)
|
struct mie_name_map *mie_name_map_create(const struct mie_name_map *parent)
|
||||||
{
|
{
|
||||||
struct mie_name_map *out = malloc(sizeof *out);
|
struct mie_name_map *out = malloc(sizeof *out);
|
||||||
if (!out) {
|
if (!out) {
|
||||||
@@ -44,6 +45,8 @@ struct mie_name_map *mie_name_map_create(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(out, 0x0, sizeof *out);
|
memset(out, 0x0, sizeof *out);
|
||||||
|
out->m_parent = parent;
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,6 +130,80 @@ static b_status put_name(struct mie_name_map *map, struct mie_name *name)
|
|||||||
return B_SUCCESS;
|
return B_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool check_name(const struct mie_name *name, const char *s, uint64_t hash)
|
||||||
|
{
|
||||||
|
return name->n_base.e_hash == hash && !strcmp(name->n_str, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct mie_name *find_name_in_bucket(
|
||||||
|
const struct mie_name_bucket *bucket, const char *s, uint64_t hash)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_first(&bucket->b_names);
|
||||||
|
while (entry) {
|
||||||
|
struct mie_name_map_entry *map_entry
|
||||||
|
= b_unbox(struct mie_name_map_entry, entry, e_entry);
|
||||||
|
struct mie_name *name = (struct mie_name *)map_entry;
|
||||||
|
if (check_name(name, s, hash)) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = b_queue_next(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct mie_name *name_map_get(
|
||||||
|
const struct mie_name_map *map, const char *name, uint64_t name_hash)
|
||||||
|
{
|
||||||
|
const struct mie_name_map_entry *entry
|
||||||
|
= get_entry(&map->m_entries, name_hash);
|
||||||
|
if (!entry) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct mie_name *name_entry = NULL;
|
||||||
|
struct mie_name_bucket *bucket = NULL;
|
||||||
|
|
||||||
|
switch (entry->e_type) {
|
||||||
|
case MIE_NAME_MAP_E_NAME:
|
||||||
|
name_entry = (struct mie_name *)entry;
|
||||||
|
if (check_name(name_entry, name, name_hash)) {
|
||||||
|
return name_entry;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MIE_NAME_MAP_E_BUCKET:
|
||||||
|
bucket = (struct mie_name_bucket *)entry;
|
||||||
|
name_entry = find_name_in_bucket(bucket, name, name_hash);
|
||||||
|
if (name_entry) {
|
||||||
|
return name_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct mie_name *mie_name_map_get(
|
||||||
|
const struct mie_name_map *map, const char *name,
|
||||||
|
enum mie_name_map_flags flags)
|
||||||
|
{
|
||||||
|
uint64_t name_hash = b_hash_cstr(name);
|
||||||
|
while (map) {
|
||||||
|
const struct mie_name *result = name_map_get(map, name, name_hash);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
map = (flags & MIE_NAME_MAP_F_RECURSIVE) ? map->m_parent : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct mie_name *mie_name_map_put(
|
struct mie_name *mie_name_map_put(
|
||||||
struct mie_name_map *map, struct mie_name *entry, const char *hint,
|
struct mie_name_map *map, struct mie_name *entry, const char *hint,
|
||||||
enum mie_name_map_flags flags)
|
enum mie_name_map_flags flags)
|
||||||
@@ -156,7 +233,7 @@ struct mie_name *mie_name_map_put(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & MIE_NAME_MAP_STRICT) {
|
if (flags & MIE_NAME_MAP_F_STRICT) {
|
||||||
/* the caller insists that `hint` be used as the name.
|
/* the caller insists that `hint` be used as the name.
|
||||||
* such a name already exists, so we can't help them */
|
* such a name already exists, so we can't help them */
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
Reference in New Issue
Block a user