core: move new object system to core module
this will allow a wider range of data structures (e.g. b_error, b_stream, b_stringstream) to make use of the new object system, and other modules and library users can use the object system without depending on the blue-object or blue-ds modules. blue-ds will become a simple library of data structures (string, hashmap, etc), built on top of the core object system.
This commit is contained in:
49
core/class.c
Normal file
49
core/class.c
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "class.h"
|
||||
|
||||
#include "type.h"
|
||||
|
||||
#include <blue/core/class.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void *z__b_class_get_interface(struct _b_class *c, const union b_type *id)
|
||||
{
|
||||
const struct b_type_registration *type_reg = c->c_type;
|
||||
struct b_type_component *comp
|
||||
= b_type_get_component(&type_reg->r_components, id);
|
||||
|
||||
if (!comp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (char *)c + comp->c_class_data_offset;
|
||||
}
|
||||
|
||||
b_result b_class_instantiate(
|
||||
struct b_type_registration *type, struct _b_class **out_class)
|
||||
{
|
||||
struct _b_class *out = malloc(type->r_class_size);
|
||||
if (!out) {
|
||||
return B_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
memset(out, 0x0, type->r_class_size);
|
||||
|
||||
out->c_magic = B_CLASS_MAGIC;
|
||||
out->c_type = type;
|
||||
|
||||
b_queue_iterator q_it;
|
||||
b_queue_foreach (&q_it, &type->r_class_hierarchy) {
|
||||
struct b_type_component *comp
|
||||
= b_unbox(struct b_type_component, q_it.entry, c_entry);
|
||||
const struct b_type_info *class_info = comp->c_type->r_info;
|
||||
void *class_data = (char *)out + comp->c_class_data_offset;
|
||||
|
||||
if (class_info->t_class_init) {
|
||||
class_info->t_class_init(out, class_data);
|
||||
}
|
||||
}
|
||||
|
||||
*out_class = out;
|
||||
return B_RESULT_SUCCESS;
|
||||
}
|
||||
18
core/class.h
Normal file
18
core/class.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef _CLASS_H_
|
||||
#define _CLASS_H_
|
||||
|
||||
#include <blue/core/error.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct b_type_registration;
|
||||
|
||||
struct _b_class {
|
||||
uint64_t c_magic;
|
||||
const struct b_type_registration *c_type;
|
||||
};
|
||||
|
||||
extern b_result b_class_instantiate(
|
||||
struct b_type_registration *type, struct _b_class **out);
|
||||
|
||||
#endif
|
||||
17
core/include/blue/core/class.h
Normal file
17
core/include/blue/core/class.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef BLUE_OBJECT_CLASS_H_
|
||||
#define BLUE_OBJECT_CLASS_H_
|
||||
|
||||
#include <blue/core/type.h>
|
||||
|
||||
#define B_CLASS_MAGIC 0xDEADFACEDCAFEBEDULL
|
||||
#define B_CLASS(p) ((b_class *)(p))
|
||||
|
||||
typedef struct _b_class b_class;
|
||||
|
||||
#define b_class_get_interface(class, interface_struct, interface_id) \
|
||||
((interface_struct *)z__b_class_get_interface( \
|
||||
B_CLASS(class), interface_id));
|
||||
|
||||
BLUE_API void *z__b_class_get_interface(b_class *c, b_type id);
|
||||
|
||||
#endif
|
||||
130
core/include/blue/core/macros.h
Normal file
130
core/include/blue/core/macros.h
Normal file
@@ -0,0 +1,130 @@
|
||||
#ifndef BLUE_CORE_MACROS_H_
|
||||
#define BLUE_CORE_MACROS_H_
|
||||
|
||||
#include <blue/core/class.h>
|
||||
#include <blue/core/object.h>
|
||||
#include <blue/core/thread.h>
|
||||
#include <blue/core/type.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define __B_IFACE_I0(p, x) p##x
|
||||
#define __B_IFACE_I1(p, x) __B_IFACE_I0(p, x)
|
||||
|
||||
/* Type definitions macros (for use in .c source file) */
|
||||
|
||||
#define B_TYPE_CLASS_DEFINITION_BEGIN(type_name) \
|
||||
static void type_name##_class_init(b_class *p, void *d) \
|
||||
{
|
||||
#define B_TYPE_CLASS_DEFINITION_END(type_name) }
|
||||
|
||||
#define B_TYPE_CLASS_INTERFACE_BEGIN(interface_name, interface_id) \
|
||||
interface_name##_class *__B_IFACE_I1(iface, __LINE__) \
|
||||
= b_class_get_interface(p, interface_name##_class, interface_id); \
|
||||
if (__B_IFACE_I1(iface, __LINE__)) { \
|
||||
interface_name##_class *iface = __B_IFACE_I1(iface, __LINE__);
|
||||
#define B_TYPE_CLASS_INTERFACE_END(interface_name, interface_id) }
|
||||
#define B_INTERFACE_ENTRY(slot) iface->slot
|
||||
|
||||
#define B_TYPE_DEFINITION_BEGIN(name) \
|
||||
static b_type_info name##_type_info = {0}; \
|
||||
static void name##_class_init(b_class *, void *); \
|
||||
static void name##_type_init(void) \
|
||||
{ \
|
||||
b_type_info *type_info = &name##_type_info; \
|
||||
unsigned int nr_vtables = 0; \
|
||||
type_info->t_name = #name; \
|
||||
type_info->t_class_init = name##_class_init;
|
||||
#define B_TYPE_DEFINITION_END(name) \
|
||||
b_result result = b_type_register(type_info); \
|
||||
if (b_result_is_error(result)) { \
|
||||
b_throw_error_caused_by_error( \
|
||||
B_ERRORS_BUILTIN, B_ERR_TYPE_REGISTRATION_FAILURE, \
|
||||
result); \
|
||||
abort(); \
|
||||
} \
|
||||
} \
|
||||
b_type name##_get_type(void) \
|
||||
{ \
|
||||
static b_once static_type_init = B_ONCE_INIT; \
|
||||
\
|
||||
if (b_init_once(&static_type_init)) { \
|
||||
name##_type_init(); \
|
||||
} \
|
||||
\
|
||||
return &name##_type_info.t_id; \
|
||||
}
|
||||
|
||||
#define B_TYPE_ID(a, b, c, d, e) b_type_id_init(&type_info->t_id, a, b, c, d, e)
|
||||
#define B_TYPE_EXTENDS(parent_id) \
|
||||
b_type_id_copy(parent_id, &type_info->t_parent_id)
|
||||
#define B_TYPE_IMPLEMENTS(interface_id) \
|
||||
b_type_id_copy( \
|
||||
interface_id, \
|
||||
&type_info->t_interfaces[type_info->t_nr_interfaces++])
|
||||
#define B_TYPE_CLASS(class_struct) \
|
||||
type_info->t_class_size = sizeof(class_struct)
|
||||
#define B_TYPE_INSTANCE_INIT(func) type_info->t_instance_init = (func)
|
||||
#define B_TYPE_INSTANCE_FINI(func) type_info->t_instance_fini = (func)
|
||||
|
||||
#if 0
|
||||
#define B_TYPE_VTABLE_BEGIN(vtable_struct, interface_id) \
|
||||
vtable_struct __B_IFACE_I1(iface, __LINE__) = {0}; \
|
||||
{ \
|
||||
vtable_struct *iface = &__B_IFACE_I1(iface, __LINE__); \
|
||||
type_info->t_vtables[nr_vtables].v_vtable = iface; \
|
||||
type_info->t_vtables[nr_vtables].v_interface_id = interface_id; \
|
||||
nr_vtables++;
|
||||
#define B_TYPE_VTABLE_END(vtable_struct, interface_id) }
|
||||
#endif
|
||||
|
||||
#define B_TYPE_INSTANCE_PRIVATE(instance_struct) \
|
||||
type_info->t_instance_private_size = sizeof(instance_struct)
|
||||
#define B_TYPE_INSTANCE_PROTECTED(instance_struct) \
|
||||
type_info->t_instance_protected_size = sizeof(instance_struct)
|
||||
|
||||
/* Type declaration macros (for use in .h header file) */
|
||||
|
||||
#define B_DECLARE_TYPE(name) \
|
||||
typedef struct _b_object name; \
|
||||
typedef struct _##name##_class name##_class;
|
||||
|
||||
#define B_TYPE_CLASS_DECLARATION_BEGIN(name) struct _##name##_class {
|
||||
#define B_TYPE_CLASS_DECLARATION_END(name) \
|
||||
} \
|
||||
;
|
||||
|
||||
#define B_TYPE_VIRTUAL_METHOD(return_type, method_name) \
|
||||
return_type(*method_name)
|
||||
|
||||
#define B_TYPE_DEFAULT_CONSTRUCTOR(type_name, type_id) \
|
||||
static inline type_name *type_name##_create(void) \
|
||||
{ \
|
||||
return b_object_create(type_id); \
|
||||
}
|
||||
#define B_TYPE_DEFAULT_DESTRUCTOR(type_name) \
|
||||
static inline void type_name##_release(type_name *p) \
|
||||
{ \
|
||||
b_release(p); \
|
||||
}
|
||||
|
||||
/* Other macros */
|
||||
|
||||
#define B_CLASS_DISPATCH_VIRTUAL(type_name, type_id, object, func, ...) \
|
||||
do { \
|
||||
type_name##_class *iface = b_object_get_interface( \
|
||||
object, type_name##_class, type_id); \
|
||||
if (iface && iface->func) { \
|
||||
return iface->func(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#define B_CLASS_DISPATCH_VIRTUAL_V(type_name, type_id, object, func, ...) \
|
||||
do { \
|
||||
type_name##_class *iface = b_object_get_interface( \
|
||||
object, type_name##_class, type_id); \
|
||||
if (iface && iface->func) { \
|
||||
iface->func(__VA_ARGS__); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
41
core/include/blue/core/object.h
Normal file
41
core/include/blue/core/object.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef BLUE_CORE_OBJECT_H_
|
||||
#define BLUE_CORE_OBJECT_H_
|
||||
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/stringstream.h>
|
||||
#include <blue/core/type.h>
|
||||
|
||||
#define B_OBJECT_MAGIC 0xDECAFC0C0ABEEF13ULL
|
||||
|
||||
#define B_OBJECT(p) ((b_object *)(p))
|
||||
#define B_TYPE_OBJECT (b_object_get_type())
|
||||
|
||||
struct b_stream;
|
||||
|
||||
typedef struct _b_object b_object;
|
||||
|
||||
typedef struct _b_object_class {
|
||||
void (*to_string)(b_object *, struct b_stream *);
|
||||
} b_object_class;
|
||||
|
||||
#define b_object_get_private(object, private_struct, type_id) \
|
||||
((private_struct *)z__b_object_get_private(B_OBJECT(object), type_id));
|
||||
#define b_object_get_protected(object, protected_struct, type_id) \
|
||||
((protected_struct *)z__b_object_get_protected(B_OBJECT(object), type_id));
|
||||
#define b_object_get_interface(object, interface_struct, interface_id) \
|
||||
((interface_struct *)z__b_object_get_interface( \
|
||||
B_OBJECT(object), interface_id));
|
||||
|
||||
BLUE_API b_type b_object_get_type(void);
|
||||
|
||||
BLUE_API void *z__b_object_get_private(b_object *object, b_type type);
|
||||
BLUE_API void *z__b_object_get_protected(b_object *object, b_type type);
|
||||
BLUE_API void *z__b_object_get_interface(b_object *object, b_type type);
|
||||
|
||||
b_object *b_retain(b_object *p);
|
||||
BLUE_API void b_release(b_object *p);
|
||||
|
||||
BLUE_API b_object *b_object_create(b_type type);
|
||||
BLUE_API void b_object_to_string(b_object *p, struct b_stream *out);
|
||||
|
||||
#endif
|
||||
61
core/include/blue/core/type.h
Normal file
61
core/include/blue/core/type.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef BLUE_CORE_TYPE_H_
|
||||
#define BLUE_CORE_TYPE_H_
|
||||
|
||||
#include <blue/core/error.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define B_TYPE_MAX_INTERFACES 64
|
||||
|
||||
struct _b_class;
|
||||
struct _b_object;
|
||||
|
||||
typedef void (*b_class_init_function)(struct _b_class *, void *);
|
||||
typedef void (*b_instance_init_function)(struct _b_object *, void *);
|
||||
typedef void (*b_instance_fini_function)(struct _b_object *, void *);
|
||||
|
||||
typedef const union b_type {
|
||||
struct {
|
||||
uint64_t p00, p01;
|
||||
} a;
|
||||
|
||||
unsigned char b[16];
|
||||
} *b_type;
|
||||
|
||||
typedef struct b_type_info {
|
||||
union b_type t_id;
|
||||
union b_type t_parent_id;
|
||||
const char *t_name;
|
||||
union b_type t_interfaces[B_TYPE_MAX_INTERFACES];
|
||||
size_t t_nr_interfaces;
|
||||
size_t t_class_size;
|
||||
b_class_init_function t_class_init;
|
||||
size_t t_instance_private_size;
|
||||
size_t t_instance_protected_size;
|
||||
b_instance_init_function t_instance_init;
|
||||
b_instance_fini_function t_instance_fini;
|
||||
} b_type_info;
|
||||
|
||||
BLUE_API void b_type_id_init(
|
||||
union b_type *out, uint32_t a, uint16_t b, uint16_t c, uint16_t d,
|
||||
uint64_t e);
|
||||
static inline void b_type_id_copy(b_type src, union b_type *dest)
|
||||
{
|
||||
dest->a.p00 = src->a.p00;
|
||||
dest->a.p01 = src->a.p01;
|
||||
}
|
||||
|
||||
static inline int b_type_id_compare(b_type a, b_type b)
|
||||
{
|
||||
if (a == b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return memcmp(a, b, sizeof(union b_type));
|
||||
}
|
||||
|
||||
BLUE_API b_result b_type_register(b_type_info *info);
|
||||
|
||||
#endif
|
||||
146
core/object.c
Normal file
146
core/object.c
Normal file
@@ -0,0 +1,146 @@
|
||||
#include "object.h"
|
||||
|
||||
#include "type.h"
|
||||
|
||||
#include <blue/core/class.h>
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/object.h>
|
||||
#include <blue/core/thread.h>
|
||||
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_object)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_object)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_object)
|
||||
B_TYPE_ID(0x45f15a2c, 0x6831, 0x4bef, 0xb350, 0x15c650679211);
|
||||
B_TYPE_CLASS(b_object_class);
|
||||
B_TYPE_DEFINITION_END(b_object)
|
||||
|
||||
b_result b_object_instantiate(
|
||||
struct b_type_registration *type, struct _b_object **out_object)
|
||||
{
|
||||
struct _b_object *out = malloc(type->r_instance_size);
|
||||
if (!out) {
|
||||
return B_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
memset(out, 0x0, type->r_instance_size);
|
||||
|
||||
out->obj_magic = B_OBJECT_MAGIC;
|
||||
out->obj_type = type;
|
||||
out->obj_ref = 1;
|
||||
|
||||
b_queue_iterator q_it;
|
||||
b_queue_foreach (&q_it, &type->r_class_hierarchy) {
|
||||
struct b_type_component *comp
|
||||
= b_unbox(struct b_type_component, q_it.entry, c_entry);
|
||||
const struct b_type_info *class_info = comp->c_type->r_info;
|
||||
void *private_data
|
||||
= (char *)out + comp->c_instance_private_data_offset;
|
||||
|
||||
if (class_info->t_instance_init) {
|
||||
class_info->t_instance_init(out, private_data);
|
||||
}
|
||||
|
||||
if (comp->c_type == type) {
|
||||
out->obj_main_priv_offset
|
||||
= comp->c_instance_private_data_offset;
|
||||
}
|
||||
}
|
||||
|
||||
*out_object = out;
|
||||
return B_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
struct _b_object *b_object_create(b_type type)
|
||||
{
|
||||
struct b_type_registration *type_reg = b_type_get_registration(type);
|
||||
if (!type_reg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct _b_object *out = NULL;
|
||||
b_result result = b_object_instantiate(type_reg, &out);
|
||||
if (b_result_is_error(result)) {
|
||||
b_error_release(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void b_object_to_string(struct _b_object *p, struct b_stream *out)
|
||||
{
|
||||
B_CLASS_DISPATCH_VIRTUAL_V(b_object, B_TYPE_OBJECT, p, to_string, p, out);
|
||||
b_stream_write_fmt(out, NULL, "<%s@%p>", p->obj_type->r_info->t_name, p);
|
||||
}
|
||||
|
||||
void *z__b_object_get_private(struct _b_object *object, b_type type)
|
||||
{
|
||||
if (b_type_id_compare(&object->obj_type->r_info->t_id, type) == 0) {
|
||||
return (char *)object + object->obj_main_priv_offset;
|
||||
}
|
||||
|
||||
struct b_type_component *comp
|
||||
= b_type_get_component(&object->obj_type->r_components, type);
|
||||
if (!comp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (char *)object + comp->c_instance_private_data_offset;
|
||||
}
|
||||
|
||||
void *z__b_object_get_protected(struct _b_object *object, b_type type)
|
||||
{
|
||||
struct b_type_component *comp
|
||||
= b_type_get_component(&object->obj_type->r_components, type);
|
||||
if (!comp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (char *)object + comp->c_instance_protected_data_offset;
|
||||
}
|
||||
|
||||
void *z__b_object_get_interface(struct _b_object *object, b_type type)
|
||||
{
|
||||
return z__b_class_get_interface(object->obj_type->r_class, type);
|
||||
}
|
||||
|
||||
struct _b_object *b_retain(struct _b_object *p)
|
||||
{
|
||||
p->obj_ref++;
|
||||
return p;
|
||||
}
|
||||
|
||||
void b_release(struct _b_object *p)
|
||||
{
|
||||
if (p->obj_ref > 1) {
|
||||
p->obj_ref--;
|
||||
}
|
||||
|
||||
p->obj_ref = 0;
|
||||
const struct b_type_registration *type = p->obj_type;
|
||||
|
||||
struct b_queue_entry *cur = b_queue_last(&type->r_class_hierarchy);
|
||||
while (cur) {
|
||||
struct b_type_component *comp
|
||||
= b_unbox(struct b_type_component, cur, c_entry);
|
||||
|
||||
const struct b_type_info *class_info = comp->c_type->r_info;
|
||||
void *private_data
|
||||
= (char *)p + comp->c_instance_private_data_offset;
|
||||
|
||||
if (class_info->t_instance_fini) {
|
||||
class_info->t_instance_fini(p, private_data);
|
||||
}
|
||||
|
||||
cur = b_queue_prev(cur);
|
||||
}
|
||||
|
||||
p->obj_magic = 0;
|
||||
p->obj_type = NULL;
|
||||
|
||||
free(p);
|
||||
}
|
||||
19
core/object.h
Normal file
19
core/object.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef _OBJECT_H_
|
||||
#define _OBJECT_H_
|
||||
|
||||
#include <blue/core/error.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct b_type_registration;
|
||||
|
||||
struct _b_object {
|
||||
uint64_t obj_magic;
|
||||
const struct b_type_registration *obj_type;
|
||||
unsigned int obj_ref, obj_main_priv_offset;
|
||||
};
|
||||
|
||||
extern b_result b_object_instantiate(
|
||||
struct b_type_registration *type, struct _b_object **out);
|
||||
|
||||
#endif
|
||||
309
core/type.c
Normal file
309
core/type.c
Normal file
@@ -0,0 +1,309 @@
|
||||
#include "type.h"
|
||||
|
||||
#include "class.h"
|
||||
#include "object.h"
|
||||
|
||||
#include <blue/core/btree.h>
|
||||
#include <blue/core/endian.h>
|
||||
#include <blue/core/object.h>
|
||||
#include <blue/core/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(®->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);
|
||||
}
|
||||
39
core/type.h
Normal file
39
core/type.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef _TYPE_H_
|
||||
#define _TYPE_H_
|
||||
|
||||
#include <blue/core/btree.h>
|
||||
#include <blue/core/type.h>
|
||||
#include <stddef.h>
|
||||
|
||||
enum b_type_category {
|
||||
B_TYPE_NONE = 0,
|
||||
B_TYPE_CLASS,
|
||||
B_TYPE_INTERFACE,
|
||||
};
|
||||
|
||||
struct b_type_component {
|
||||
struct b_btree_node c_node;
|
||||
struct b_queue_entry c_entry;
|
||||
const struct b_type_registration *c_type;
|
||||
|
||||
size_t c_class_data_offset, c_class_data_size;
|
||||
size_t c_instance_private_data_offset, c_instance_private_data_size;
|
||||
size_t c_instance_protected_data_offset, c_instance_protected_data_size;
|
||||
};
|
||||
|
||||
struct b_type_registration {
|
||||
enum b_type_category r_category;
|
||||
struct b_btree_node r_node;
|
||||
const b_type_info *r_info;
|
||||
struct _b_class *r_class;
|
||||
struct b_btree r_components;
|
||||
struct b_queue r_class_hierarchy;
|
||||
|
||||
size_t r_instance_size, r_class_size;
|
||||
};
|
||||
|
||||
extern struct b_type_registration *b_type_get_registration(b_type id);
|
||||
extern struct b_type_component *b_type_get_component(
|
||||
const b_btree *tree, const union b_type *key);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user