Files
mie/mie/trait/trait-table.c

272 lines
6.7 KiB
C

#include <mie/dialect/dialect.h>
#include <mie/trait/trait-definition.h>
#include <mie/trait/trait-table.h>
#include <mie/trait/trait.h>
#define UNIQUE_TRAIT_NS_ID \
MIE_ID(0xd6, 0xb6, 0x72, 0xae, 0xef, 0x65, 0x40, 0x24, 0xaa, 0x6d, \
0xef, 0xfc, 0x37, 0xda, 0x5c, 0x88)
#define GENERIC_TRAIT_NS_ID \
MIE_ID(0x1a, 0x60, 0xbe, 0x20, 0xa6, 0xa0, 0x43, 0x3a, 0xb1, 0x2c, \
0x33, 0x9a, 0xac, 0x52, 0xa0, 0xca)
struct unique_trait {
mie_id u_id;
const struct mie_trait *u_trait;
};
struct generic_trait {
/* generic trait ID. */
mie_id g_id;
/* list of struct unique_trait */
b_queue g_traits;
};
static struct unique_trait *unique_trait_create(const struct mie_trait *trait)
{
struct unique_trait *out = malloc(sizeof *out);
if (!out) {
return NULL;
}
memset(out, 0x0, sizeof *out);
out->u_trait = trait;
return out;
}
static void unique_trait_destroy(struct unique_trait *trait)
{
free(trait);
}
static struct generic_trait *generic_trait_create(const struct mie_trait *trait)
{
struct generic_trait *out = malloc(sizeof *out);
if (!out) {
return NULL;
}
memset(out, 0x0, sizeof *out);
struct unique_trait *entry = unique_trait_create(trait);
if (!entry) {
free(out);
return NULL;
}
b_queue_push_back(&out->g_traits, &entry->u_id.e_entry);
return out;
}
static void generic_trait_destroy(struct generic_trait *trait)
{
b_queue_entry *cur = b_queue_first(&trait->g_traits);
while (cur) {
b_queue_entry *next = b_queue_next(cur);
b_queue_delete(&trait->g_traits, cur);
struct unique_trait *u
= b_unbox(struct unique_trait, cur, u_id.e_entry);
unique_trait_destroy(u);
cur = next;
}
free(trait);
}
void mie_trait_table_init(struct mie_trait_table *out)
{
memset(out, 0x0, sizeof *out);
mie_id unique_ns = UNIQUE_TRAIT_NS_ID;
mie_id_map_init(&out->tr_unique, &unique_ns);
mie_id generic_ns = GENERIC_TRAIT_NS_ID;
mie_id_map_init(&out->tr_generic, &generic_ns);
}
void mie_trait_table_cleanup(struct mie_trait_table *table)
{
/* TODO */
}
const struct mie_trait *mie_trait_table_get_unique(
const struct mie_trait_table *table, const char *dialect_name,
const char *trait_name)
{
mie_id id;
struct mie_id_builder id_ctx;
mie_id_builder_begin(&id_ctx, mie_id_map_get_ns(&table->tr_unique));
mie_id_builder_add_cstr(&id_ctx, dialect_name);
mie_id_builder_add_char(&id_ctx, '.');
mie_id_builder_add_cstr(&id_ctx, trait_name);
mie_id_builder_end(&id_ctx, &id);
const mie_id *result = mie_id_map_get(&table->tr_unique, &id);
const struct unique_trait *entry
= b_unbox(struct unique_trait, result, u_id);
return entry ? entry->u_trait : NULL;
}
static enum mie_status put_unique_trait(
struct mie_trait_table *table, const struct mie_trait *trait)
{
struct unique_trait *unique = unique_trait_create(trait);
if (!unique) {
return MIE_ERR_NO_MEMORY;
}
struct mie_id_builder id_ctx;
mie_id_builder_begin(&id_ctx, mie_id_map_get_ns(&table->tr_unique));
mie_id_builder_add_cstr(&id_ctx, trait->tr_def->tr_parent->d_name);
mie_id_builder_add_char(&id_ctx, '.');
mie_id_builder_add_cstr(&id_ctx, trait->tr_def->tr_name);
mie_id_builder_end(&id_ctx, &unique->u_id);
mie_id_map_put_id(&table->tr_unique, &unique->u_id);
return MIE_SUCCESS;
}
static enum mie_status put_generic_trait(
struct mie_trait_table *table, const struct mie_trait *trait)
{
mie_id id;
struct mie_id_builder id_ctx;
mie_id_builder_begin(&id_ctx, mie_id_map_get_ns(&table->tr_generic));
mie_id_builder_add_cstr(&id_ctx, trait->tr_def->tr_parent->d_name);
mie_id_builder_add_char(&id_ctx, '.');
mie_id_builder_add_cstr(&id_ctx, trait->tr_def->tr_name);
mie_id_builder_end(&id_ctx, &id);
mie_id *target = mie_id_map_get(&table->tr_generic, &id);
struct generic_trait *generic
= b_unbox(struct generic_trait, target, g_id);
if (!generic) {
generic = generic_trait_create(trait);
if (!generic) {
return MIE_ERR_NO_MEMORY;
}
generic->g_id = id;
mie_id_map_put_id(&table->tr_generic, &generic->g_id);
}
struct unique_trait *unique = unique_trait_create(trait);
if (!unique) {
return MIE_ERR_NO_MEMORY;
}
b_queue_push_back(&generic->g_traits, &unique->u_id.e_entry);
return MIE_SUCCESS;
}
enum mie_status mie_trait_table_put(
struct mie_trait_table *table, const struct mie_trait *trait)
{
if (trait->tr_def->tr_flags & MIE_TRAIT_F_PARAMETISED) {
return put_generic_trait(table, trait);
}
return put_unique_trait(table, trait);
}
enum mie_status mie_trait_table_get_generic(
const struct mie_trait_table *table, const char *dialect_name,
const char *trait_name, struct mie_trait_table_iterator *it)
{
mie_id id;
struct mie_id_builder id_ctx;
mie_id_builder_begin(&id_ctx, mie_id_map_get_ns(&table->tr_unique));
mie_id_builder_add_cstr(&id_ctx, dialect_name);
mie_id_builder_add_char(&id_ctx, '.');
mie_id_builder_add_cstr(&id_ctx, trait_name);
mie_id_builder_end(&id_ctx, &id);
const mie_id *result = mie_id_map_get(&table->tr_unique, &id);
const struct generic_trait *entry
= b_unbox(struct generic_trait, entry, g_id);
if (!entry || b_queue_empty(&entry->g_traits)) {
return MIE_ERR_NO_ENTRY;
}
memset(it, 0x0, sizeof *it);
it->_e = b_queue_first(&entry->g_traits);
struct unique_trait *trait
= b_unbox(struct unique_trait, it->_e, u_id.e_entry);
it->it_trait = trait->u_trait;
return MIE_SUCCESS;
}
enum mie_status mie_trait_table_iterate(
const struct mie_trait_table *table,
int (*func)(const struct mie_trait *, void *), void *arg)
{
struct mie_id_map_iterator it = {0};
mie_id_map_iterator_begin(&it, &table->tr_unique);
int ret = 0;
while (it.it_id) {
const struct unique_trait *trait
= b_unbox(struct unique_trait, it.it_id, u_id);
ret = func(trait->u_trait, arg);
if (ret != 0) {
return MIE_SUCCESS;
}
mie_id_map_iterator_move_next(&it);
}
mie_id_map_iterator_begin(&it, &table->tr_generic);
while (it.it_id) {
const struct generic_trait *trait_group
= b_unbox(struct generic_trait, it.it_id, g_id);
const b_queue_entry *cur = b_queue_first(&trait_group->g_traits);
while (cur) {
const struct unique_trait *trait
= b_unbox(struct unique_trait, cur, u_id.e_entry);
ret = func(trait->u_trait, arg);
if (ret != 0) {
return MIE_SUCCESS;
}
cur = b_queue_next(cur);
}
mie_id_map_iterator_move_next(&it);
}
return MIE_SUCCESS;
}
enum mie_status mie_trait_table_iterator_move_next(
struct mie_trait_table_iterator *it)
{
if (!it->_e) {
return MIE_ERR_NO_ENTRY;
}
it->_e = b_queue_next(it->_e);
if (!it->_e) {
return MIE_ERR_NO_ENTRY;
}
struct unique_trait *trait
= b_unbox(struct unique_trait, it->_e, u_id.e_entry);
it->it_trait = trait->u_trait;
return MIE_SUCCESS;
}