Files
bluelib/object/type.c

310 lines
7.7 KiB
C

#include "type.h"
#include "class.h"
#include "object.h"
#include <blue/core/btree.h>
#include <blue/core/endian.h>
#include <blue/object/object.h>
#include <blue/object/type.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct b_btree type_list = B_BTREE_INIT;
static union b_type zero_id = {0};
struct type_init_ctx {
size_t ctx_class_offset;
size_t ctx_instance_offset;
};
static inline int registration_compare(
const struct b_type_registration *a, const struct b_type_registration *b)
{
return b_type_id_compare(&a->r_info->t_id, &b->r_info->t_id);
}
static inline int component_compare(
const struct b_type_component *a, const struct b_type_component *b)
{
return b_type_id_compare(&a->c_type->r_info->t_id, &b->c_type->r_info->t_id);
}
B_BTREE_DEFINE_INSERT(
struct b_type_registration, r_node, r_info->r_id, put_type,
registration_compare)
B_BTREE_DEFINE_INSERT(
struct b_type_component, c_node, &c_type->r_info->t_id,
put_type_component, component_compare)
struct b_type_registration *get_type(const b_btree *tree, const union b_type *key)
{
b_btree_node *cur = tree->b_root;
while (cur) {
struct b_type_registration *cur_node
= b_unbox(struct b_type_registration, cur, r_node);
int cmp = b_type_id_compare(key, &cur_node->r_info->t_id);
if (cmp > 0) {
cur = b_btree_right(cur);
} else if (cmp < 0) {
cur = b_btree_left(cur);
} else {
return cur_node;
}
}
return NULL;
}
struct b_type_component *b_type_get_component(
const b_btree *tree, const union b_type *key)
{
b_btree_node *cur = tree->b_root;
while (cur) {
struct b_type_component *cur_node
= b_unbox(struct b_type_component, cur, c_node);
int cmp = b_type_id_compare(key, &cur_node->c_type->r_info->t_id);
if (cmp > 0) {
cur = b_btree_right(cur);
} else if (cmp < 0) {
cur = b_btree_left(cur);
} else {
return cur_node;
}
}
return NULL;
}
static struct b_type_component *create_type_component(
const struct b_type_registration *type_reg)
{
struct b_type_component *c = malloc(sizeof *c);
if (!c) {
return NULL;
}
memset(c, 0x0, sizeof *c);
c->c_type = type_reg;
return c;
}
void b_type_id_init(
union b_type *out, uint32_t a, uint16_t b, uint16_t c, uint16_t d,
uint64_t e)
{
b_i32 x_a = b_i32_htob(a);
b_i16 x_b = b_i16_htob(b);
b_i16 x_c = b_i16_htob(c);
b_i16 x_d = b_i16_htob(d);
b_i64 x_e = b_i64_htob(e);
memcpy(&out->b[0], x_a.i_bytes, sizeof x_a.i_bytes);
memcpy(&out->b[4], x_b.i_bytes, sizeof x_b.i_bytes);
memcpy(&out->b[6], x_c.i_bytes, sizeof x_c.i_bytes);
memcpy(&out->b[8], x_d.i_bytes, sizeof x_d.i_bytes);
memcpy(&out->b[10], &x_e.i_bytes[2], sizeof x_e.i_bytes - 2);
}
static void initialise_type_component(
struct b_type_component *comp, const struct b_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->t_class_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->t_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->t_instance_protected_size;
init_ctx->ctx_instance_offset += comp->c_instance_protected_data_size;
}
static b_result locate_interface(
b_type interface_id, struct b_type_registration *dest,
struct type_init_ctx *init_ctx)
{
struct b_type_component *interface_comp
= b_type_get_component(&dest->r_components, interface_id);
if (interface_comp) {
return B_RESULT_SUCCESS;
}
struct b_type_registration *interface_reg
= get_type(&type_list, interface_id);
if (!interface_reg) {
return B_RESULT_ERR(NO_MEMORY);
}
interface_comp = create_type_component(interface_reg);
if (!interface_comp) {
return B_RESULT_ERR(NO_MEMORY);
}
put_type_component(&dest->r_components, interface_comp);
return B_RESULT_SUCCESS;
}
static b_result locate_interfaces(
const union b_type *interfaces, size_t nr_interfaces,
struct b_type_registration *dest, struct type_init_ctx *init_ctx)
{
b_result result = B_RESULT_SUCCESS;
for (size_t i = 0; i < nr_interfaces; i++) {
b_type interface_id = &interfaces[i];
result = locate_interface(interface_id, dest, init_ctx);
if (b_result_is_error(result)) {
break;
}
}
return result;
}
static b_result find_type_components(struct b_type_registration *reg)
{
const struct b_type_info *current = reg->r_info;
struct b_type_component *comp = create_type_component(reg);
if (!comp) {
return B_RESULT_ERR(NO_MEMORY);
}
struct type_init_ctx init_ctx = {
.ctx_instance_offset = sizeof(struct _b_object),
.ctx_class_offset = sizeof(struct _b_class),
};
put_type_component(&reg->r_components, comp);
b_queue_push_front(&reg->r_class_hierarchy, &comp->c_entry);
b_result result = locate_interfaces(
current->t_interfaces, current->t_nr_interfaces, reg, &init_ctx);
if (b_result_is_error(result)) {
return result;
}
b_type current_id = &current->t_parent_id;
if (!current_id || b_type_id_compare(current_id, &zero_id) == 0) {
goto skip_class_hierarchy;
}
while (1) {
struct b_type_registration *dep_class
= get_type(&type_list, current_id);
if (!dep_class) {
return B_RESULT_ERR(NO_ENTRY);
}
comp = b_type_get_component(&reg->r_components, current_id);
if (comp) {
/* circular class dependency */
result = B_RESULT_ERR(INVALID_ARGUMENT);
break;
}
comp = create_type_component(dep_class);
result = locate_interfaces(
dep_class->r_info->t_interfaces,
dep_class->r_info->t_nr_interfaces, reg, &init_ctx);
if (b_result_is_error(result)) {
break;
}
put_type_component(&reg->r_components, comp);
b_queue_push_front(&reg->r_class_hierarchy, &comp->c_entry);
if (b_type_id_compare(current_id, B_TYPE_OBJECT) == 0) {
break;
}
}
b_queue_iterator q_it;
b_queue_foreach (&q_it, &reg->r_class_hierarchy) {
comp = b_unbox(struct b_type_component, q_it.entry, c_entry);
initialise_type_component(comp, comp->c_type->r_info, &init_ctx);
}
b_btree_iterator t_it;
b_btree_foreach (&t_it, &reg->r_components) {
comp = b_unbox(struct b_type_component, t_it.node, c_node);
if (comp->c_type->r_category == B_TYPE_CLASS) {
/* this component was already initialised above */
continue;
}
initialise_type_component(comp, comp->c_type->r_info, &init_ctx);
}
skip_class_hierarchy:
reg->r_instance_size = init_ctx.ctx_instance_offset;
reg->r_class_size = init_ctx.ctx_class_offset;
return result;
}
static bool type_has_base_class(struct b_type_info *info)
{
if (b_type_id_compare(&info->t_id, B_TYPE_OBJECT) == 0) {
return true;
}
return b_type_id_compare(&info->t_parent_id, &zero_id) != 0;
}
b_result b_type_register(struct b_type_info *info)
{
if (!type_has_base_class(info)) {
b_type_id_copy(B_TYPE_OBJECT, &info->t_parent_id);
}
struct b_type_registration *r = get_type(&type_list, &info->t_id);
if (r) {
return B_RESULT_ERR(NAME_EXISTS);
}
r = malloc(sizeof *r);
if (!r) {
return B_RESULT_ERR(NO_MEMORY);
}
memset(r, 0x0, sizeof *r);
r->r_category = B_TYPE_CLASS;
r->r_info = info;
b_result result = find_type_components(r);
if (b_result_is_error(result)) {
free(r);
return b_result_propagate(result);
}
result = b_class_instantiate(r, &r->r_class);
if (!r->r_class) {
free(r);
return b_error_with_msg_template_caused_by_error(
B_ERRORS_BUILTIN, B_ERR_TYPE_REGISTRATION_FAILURE,
result, B_MSG_TYPE_REGISTRATION_FAILURE,
B_ERROR_PARAM("typename", info->t_name));
}
put_type(&type_list, r);
return B_RESULT_SUCCESS;
}
struct b_type_registration *b_type_get_registration(b_type id)
{
return get_type(&type_list, id);
}