From c686c31ca034cce178e5808ffca2259fc50492b6 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Thu, 8 Jan 2026 19:21:17 +0000 Subject: [PATCH] mie: add data structures for registering and applying extensible traits --- mie/include/mie/trait/trait-table.h | 39 ++++++ mie/include/mie/trait/trait.h | 42 +++++++ mie/trait/trait-table.c | 183 ++++++++++++++++++++++++++++ 3 files changed, 264 insertions(+) create mode 100644 mie/include/mie/trait/trait-table.h create mode 100644 mie/include/mie/trait/trait.h create mode 100644 mie/trait/trait-table.c diff --git a/mie/include/mie/trait/trait-table.h b/mie/include/mie/trait/trait-table.h new file mode 100644 index 0000000..83c4da3 --- /dev/null +++ b/mie/include/mie/trait/trait-table.h @@ -0,0 +1,39 @@ +#ifndef MIE_TRAIT_TRAIT_TABLE_H_ +#define MIE_TRAIT_TRAIT_TABLE_H_ + +#include +#include +#include +#include + +/* for IR objects that support traits (ops, types, etc), this struct can be used + * to store and retrieve references to the traits that apply */ +struct mie_trait_table { + struct mie_id_map tr_unique; + struct mie_id_map tr_generic; +}; + +struct mie_trait_table_iterator { + const struct mie_trait *it_trait; + b_queue_entry *_e; +}; + +MIE_API void mie_trait_table_init(struct mie_trait_table *out); +MIE_API void mie_trait_table_cleanup(struct mie_trait_table *table); + +/* retrieve a trait based on its name. this function can only be used to + * retrieve non-parametised traits. to retrieve parametised traits, use + * mie_trait_table_get_generic. */ +MIE_API const struct mie_trait *mie_trait_table_get_unique( + const struct mie_trait_table *table, const char *dialect_name, + const char *trait_name); +MIE_API 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_API enum mie_status mie_trait_table_put( + struct mie_trait_table *table, const struct mie_trait *trait); + +MIE_API enum mie_status mie_trait_table_iterator_move_next( + struct mie_trait_table_iterator *it); + +#endif diff --git a/mie/include/mie/trait/trait.h b/mie/include/mie/trait/trait.h new file mode 100644 index 0000000..02b83b5 --- /dev/null +++ b/mie/include/mie/trait/trait.h @@ -0,0 +1,42 @@ +#ifndef MIE_TRAIT_TRAIT_H_ +#define MIE_TRAIT_TRAIT_H_ + +#include + +struct mie_trait; + +enum mie_trait_flags { + /* a trait user can only apply the trait once. this is assumed to be the + * case unless a trait is parametised, in which case this flag can be + * used to prevent more than one specialisation from being used. */ + MIE_TRAIT_F_UNIQUE = 0x01u, + MIE_TRAIT_F_PARAMETISED = 0x02u, +}; + +/* used to define a trait */ +struct mie_trait_definition { + /* ID for the generic trait */ + mie_id tr_id; + char *tr_name; + enum mie_trait_flags tr_flags; + + /* the size of any corresponding struct mie_trait instances */ + size_t tr_data_size; + + enum mie_status (*tr_build_id)( + const struct mie_trait_definition *, const struct mie_trait *, + struct mie_id_builder *); + enum mie_status (*tr_print)( + const struct mie_trait_definition *, const struct mie_trait *, + b_stream *); +}; + +/* used to link an op/type/etc to a trait. if the trait is parametised, this + * struct includes any parameter values. */ +struct mie_trait { + /* this is NOT the same as tr_def->tr_id */ + mie_id tr_id; + const struct mie_trait_definition *tr_def; +}; + +#endif diff --git a/mie/trait/trait-table.c b/mie/trait/trait-table.c new file mode 100644 index 0000000..cda592b --- /dev/null +++ b/mie/trait/trait-table.c @@ -0,0 +1,183 @@ +#include +#include + +#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_id = trait->tr_id; + 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); + out->g_id = trait->tr_def->tr_id; + + 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, entry, 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) +{ + return MIE_SUCCESS; +} + +static enum mie_status put_generic_trait( + struct mie_trait_table *table, const struct mie_trait *trait) +{ + 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_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; +}