#include "type.h" #include "class.h" #include "object.h" #include #include #include #include #include #include #include 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(®->r_components, comp); b_queue_push_front(®->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 = ¤t->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(®->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(®->r_components, comp); b_queue_push_front(®->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, ®->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, ®->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); }