272 lines
6.7 KiB
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;
|
|
}
|