Files
fx/fx/type.c
T

435 lines
9.9 KiB
C

#include "type.h"
#include "class.h"
#include "object.h"
#include <fx/bst.h>
#include <fx/endian.h>
#include <fx/int.h>
#include <fx/object.h>
#include <fx/reflection/function.h>
#include <fx/reflection/property.h>
#include <fx/type.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct fx_bst type_idmap = FX_BST_INIT;
static struct fx_namemap type_namemap = FX_NAMEMAP_INIT;
static union fx_type_id zero_id = {0};
struct type_init_ctx {
size_t ctx_class_offset;
size_t ctx_instance_offset;
};
static inline int type_info_compare(
const struct fx_type_info *a,
const struct fx_type_info *b)
{
return fx_type_id_compare(&a->ty_id, &b->ty_id);
}
static inline int component_compare(
const struct fx_type_component *a,
const struct fx_type_component *b)
{
return fx_type_id_compare(&a->c_type->ty_id, &b->c_type->ty_id);
}
FX_BST_DEFINE_INSERT(
struct fx_type_info,
ty_idmap_node,
ty_id,
put_type,
type_info_compare)
FX_BST_DEFINE_INSERT(
struct fx_type_component,
c_node,
&c_type->r_info->t_id,
put_type_component,
component_compare)
static struct fx_type_info *get_type(
const fx_bst *tree,
const union fx_type_id *key)
{
fx_bst_node *cur = tree->bst_root;
while (cur) {
struct fx_type_info *cur_node = fx_unbox(
struct fx_type_info,
cur,
ty_idmap_node);
int cmp = fx_type_id_compare(key, &cur_node->ty_id);
if (cmp > 0) {
cur = fx_bst_right(cur);
} else if (cmp < 0) {
cur = fx_bst_left(cur);
} else {
return cur_node;
}
}
return NULL;
}
struct fx_type_component *fx_type_get_component(
const fx_bst *tree,
const union fx_type_id *key)
{
fx_bst_node *cur = tree->bst_root;
while (cur) {
struct fx_type_component *cur_node = fx_unbox(
struct fx_type_component,
cur,
c_node);
int cmp = fx_type_id_compare(key, &cur_node->c_type->ty_id);
if (cmp > 0) {
cur = fx_bst_right(cur);
} else if (cmp < 0) {
cur = fx_bst_left(cur);
} else {
return cur_node;
}
}
return NULL;
}
static struct fx_type_component *create_type_component(
const struct fx_type_info *type_reg)
{
struct fx_type_component *c = malloc(sizeof *c);
if (!c) {
return NULL;
}
memset(c, 0x0, sizeof *c);
c->c_type = type_reg;
return c;
}
void fx_type_id_init(union fx_type_id *out, u32 a, u16 b, u16 c, u16 d, u64 e)
{
a = fx_u32_htob(a);
b = fx_u16_htob(b);
c = fx_u16_htob(c);
d = fx_u16_htob(d);
e = fx_u64_htob(e);
memcpy(&out->b[0], &a, sizeof a);
memcpy(&out->b[4], &b, sizeof b);
memcpy(&out->b[6], &c, sizeof c);
memcpy(&out->b[8], &d, sizeof d);
memcpy(&out->b[10], (byte *)&e + 2, sizeof e - 2);
}
static void initialise_type_component(
struct fx_type_component *comp,
const struct fx_type_info *info,
struct type_init_ctx *init_ctx)
{
comp->c_class_data_offset = init_ctx->ctx_class_offset;
comp->c_class_data_size = info->ty_class_private_size;
init_ctx->ctx_class_offset += comp->c_class_data_size;
comp->c_instance_private_data_offset = init_ctx->ctx_instance_offset;
comp->c_instance_private_data_size = info->ty_instance_private_size;
init_ctx->ctx_instance_offset += comp->c_instance_private_data_size;
comp->c_instance_protected_data_offset = init_ctx->ctx_instance_offset;
comp->c_instance_protected_data_size = info->ty_instance_protected_size;
init_ctx->ctx_instance_offset += comp->c_instance_protected_data_size;
}
static fx_result locate_interface(
fx_type_id interface_id,
struct fx_type_info *dest,
struct type_init_ctx *init_ctx)
{
struct fx_type_component *interface_comp = fx_type_get_component(
&dest->ty_components,
interface_id);
if (interface_comp) {
return FX_RESULT_SUCCESS;
}
struct fx_type_info *interface_reg = get_type(
&type_idmap,
interface_id);
if (!interface_reg) {
return FX_RESULT_ERR(NO_ENTRY);
}
interface_comp = create_type_component(interface_reg);
if (!interface_comp) {
return FX_RESULT_ERR(NO_MEMORY);
}
initialise_type_component(interface_comp, interface_reg, init_ctx);
put_type_component(&dest->ty_components, interface_comp);
return FX_RESULT_SUCCESS;
}
static fx_result locate_interfaces(
const union fx_type_id *interfaces,
size_t nr_interfaces,
struct fx_type_info *dest,
struct type_init_ctx *init_ctx)
{
fx_result result = FX_RESULT_SUCCESS;
for (size_t i = 0; i < nr_interfaces; i++) {
fx_type_id interface_id = &interfaces[i];
result = locate_interface(interface_id, dest, init_ctx);
if (fx_result_is_error(result)) {
break;
}
}
return result;
}
static fx_result find_type_components(struct fx_type_info *type)
{
const struct fx_type_info *current = type;
struct fx_type_component *comp = create_type_component(current);
if (!comp) {
return FX_RESULT_ERR(NO_MEMORY);
}
struct type_init_ctx init_ctx = {
.ctx_instance_offset = sizeof(struct _fx_object),
.ctx_class_offset = sizeof(struct _fx_class),
};
put_type_component(&type->ty_components, comp);
fx_queue_push_front(&type->ty_class_hierarchy, &comp->c_entry);
fx_result result = locate_interfaces(
current->ty_interfaces,
current->ty_nr_interfaces,
type,
&init_ctx);
if (fx_result_is_error(result)) {
return result;
}
fx_type_id current_id = &current->ty_parent_id;
if (!current_id || fx_type_id_compare(current_id, &zero_id) == 0) {
goto skip_class_hierarchy;
}
while (1) {
struct fx_type_info *dep_class = get_type(
&type_idmap,
current_id);
if (!dep_class) {
return FX_RESULT_ERR(NO_ENTRY);
}
comp = fx_type_get_component(&type->ty_components, current_id);
if (comp) {
/* circular class dependency */
// result = FX_RESULT_ERR(INVALID_ARGUMENT);
// break;
current_id = &dep_class->ty_parent_id;
continue;
}
comp = create_type_component(dep_class);
result = locate_interfaces(
dep_class->ty_interfaces,
dep_class->ty_nr_interfaces,
type,
&init_ctx);
if (fx_result_is_error(result)) {
break;
}
put_type_component(&type->ty_components, comp);
fx_queue_push_front(&type->ty_class_hierarchy, &comp->c_entry);
if (fx_type_id_compare(current_id, FX_TYPE_OBJECT) == 0) {
break;
}
current_id = &dep_class->ty_parent_id;
}
fx_queue_entry *entry = fx_queue_first(&type->ty_class_hierarchy);
while (entry) {
comp = fx_unbox(struct fx_type_component, entry, c_entry);
initialise_type_component(comp, comp->c_type, &init_ctx);
entry = fx_queue_next(entry);
}
fx_bst_node *node = fx_bst_first(&type->ty_components);
while (node) {
comp = fx_unbox(struct fx_type_component, node, c_node);
if (comp->c_type->ty_category == FX_TYPE_CLASS) {
/* this component was already initialised above */
node = fx_bst_next(node);
continue;
}
initialise_type_component(comp, comp->c_type, &init_ctx);
node = fx_bst_next(node);
}
skip_class_hierarchy:
type->ty_instance_size = init_ctx.ctx_instance_offset;
type->ty_class_size = init_ctx.ctx_class_offset;
return result;
}
static bool type_has_base_class(struct fx_type_info *info)
{
if (fx_type_id_compare(&info->ty_id, FX_TYPE_OBJECT) == 0) {
return true;
}
return fx_type_id_compare(&info->ty_parent_id, &zero_id) != 0;
}
fx_result fx_type_register(struct fx_type_info *info)
{
if (!type_has_base_class(info)) {
fx_type_id_copy(FX_TYPE_OBJECT, &info->ty_parent_id);
}
if (get_type(&type_idmap, &info->ty_id)) {
return FX_RESULT_ERR(NAME_EXISTS);
}
if (fx_namemap_get(&type_namemap, info->ty_name)) {
return FX_RESULT_ERR(NAME_EXISTS);
}
info->ty_category = FX_TYPE_CLASS;
union fx_type_id metatype = {0};
fx_result result = find_type_components(info);
if (fx_result_is_error(result)) {
return fx_result_propagate(result);
}
result = fx_class_instantiate(info, &info->ty_class);
if (!info->ty_class) {
return fx_error_with_msg_template_caused_by_error(
FX_ERRORS_BUILTIN,
FX_ERR_TYPE_REGISTRATION_FAILURE,
result,
FX_MSG_TYPE_REGISTRATION_FAILURE,
FX_ERROR_PARAM("typename", info->ty_name));
}
put_type(&type_idmap, info);
fx_namemap_put(&type_namemap, info->ty_name, &info->ty_namemap_entry);
info->ty_metatype = __fx_type_create(info);
return FX_RESULT_SUCCESS;
}
fx_result fx_type_add_function(fx_type_info *info, struct _fx_object *func)
{
const char *name = fx_function_get_name(func);
struct fx_namemap_entry *entry = fx_namemap_get(
&info->ty_functions,
name);
if (entry) {
return FX_RESULT_ERR(NAME_EXISTS);
}
struct fx_type_function *ty_func = malloc(sizeof *ty_func);
if (!ty_func) {
return FX_RESULT_ERR(NO_MEMORY);
}
memset(ty_func, 0x0, sizeof *ty_func);
ty_func->f_func = func;
fx_namemap_put(&info->ty_functions, name, &ty_func->f_entry);
return FX_RESULT_SUCCESS;
}
fx_result fx_type_add_property(fx_type_info *info, struct _fx_object *prop)
{
const char *name = fx_property_get_name(prop);
struct fx_namemap_entry *entry = fx_namemap_get(
&info->ty_functions,
name);
if (entry) {
return FX_RESULT_ERR(NAME_EXISTS);
}
struct fx_type_property *ty_prop = malloc(sizeof *ty_prop);
if (!ty_prop) {
return FX_RESULT_ERR(NO_MEMORY);
}
memset(ty_prop, 0x0, sizeof *ty_prop);
ty_prop->p_prop = prop;
fx_namemap_put(&info->ty_properties, name, &ty_prop->p_entry);
return FX_RESULT_SUCCESS;
}
struct fx_type_info *fx_type_info_get_by_id(const union fx_type_id *key)
{
return get_type(&type_idmap, key);
}
struct fx_type_info *fx_type_info_get_by_name(const char *name)
{
fx_namemap_entry *entry = fx_namemap_get(&type_namemap, name);
if (!entry) {
return NULL;
}
return fx_unbox(struct fx_type_info, entry, ty_namemap_entry);
}
fx_function *fx_type_info_get_function_by_name(
const struct fx_type_info *ty,
const char *name)
{
fx_namemap_entry *entry = fx_namemap_get(&ty->ty_functions, name);
if (!entry) {
return NULL;
}
struct fx_type_function *func = fx_unbox(
struct fx_type_function,
entry,
f_entry);
return func->f_func;
}
fx_function *fx_type_info_get_property_by_name(
const struct fx_type_info *ty,
const char *name)
{
fx_namemap_entry *entry = fx_namemap_get(&ty->ty_properties, name);
if (!entry) {
return NULL;
}
struct fx_type_property *prop = fx_unbox(
struct fx_type_property,
entry,
p_entry);
return prop->p_prop;
}