From c65541ac628f69ee6b26912dd09c6716b263f378 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sat, 16 Aug 2025 16:03:55 +0100 Subject: [PATCH] core: add new enhanced object module --- CMakeLists.txt | 2 +- object/CMakeLists.txt | 3 + object/class.c | 49 ++ object/class.h | 18 + object/include/blue/object.h | 0 object/include/blue/object/class.h | 17 + object/include/blue/object/macros.h | 130 +++++ object/include/blue/object/object.h | 41 ++ object/include/blue/object/string.h | 78 +++ object/include/blue/object/type.h | 61 +++ object/object.c | 146 ++++++ object/object.h | 19 + object/string.c | 773 ++++++++++++++++++++++++++++ object/type.c | 309 +++++++++++ object/type.h | 39 ++ 15 files changed, 1684 insertions(+), 1 deletion(-) create mode 100644 object/CMakeLists.txt create mode 100644 object/class.c create mode 100644 object/class.h create mode 100644 object/include/blue/object.h create mode 100644 object/include/blue/object/class.h create mode 100644 object/include/blue/object/macros.h create mode 100644 object/include/blue/object/object.h create mode 100644 object/include/blue/object/string.h create mode 100644 object/include/blue/object/type.h create mode 100644 object/object.c create mode 100644 object/object.h create mode 100644 object/string.c create mode 100644 object/type.c create mode 100644 object/type.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3964bc3..ae39d02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ set(CMAKE_C_EXTENSIONS OFF) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) set_property(GLOBAL PROPERTY USE_FOLDERS ON) -set(b_modules core ds serial term cmd io compress) +set(b_modules core ds object serial term cmd io compress) set(b_system_name ${CMAKE_SYSTEM_NAME}) string(TOLOWER ${b_system_name} b_system_name) diff --git a/object/CMakeLists.txt b/object/CMakeLists.txt new file mode 100644 index 0000000..905e9c0 --- /dev/null +++ b/object/CMakeLists.txt @@ -0,0 +1,3 @@ +include(../cmake/Templates.cmake) + +add_bluelib_module(NAME object DEPENDENCIES core) diff --git a/object/class.c b/object/class.c new file mode 100644 index 0000000..b5449cc --- /dev/null +++ b/object/class.c @@ -0,0 +1,49 @@ +#include "class.h" + +#include "type.h" + +#include +#include +#include + +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; +} diff --git a/object/class.h b/object/class.h new file mode 100644 index 0000000..252ffd9 --- /dev/null +++ b/object/class.h @@ -0,0 +1,18 @@ +#ifndef _CLASS_H_ +#define _CLASS_H_ + +#include +#include +#include + +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 diff --git a/object/include/blue/object.h b/object/include/blue/object.h new file mode 100644 index 0000000..e69de29 diff --git a/object/include/blue/object/class.h b/object/include/blue/object/class.h new file mode 100644 index 0000000..d6a0ce2 --- /dev/null +++ b/object/include/blue/object/class.h @@ -0,0 +1,17 @@ +#ifndef BLUE_OBJECT_CLASS_H_ +#define BLUE_OBJECT_CLASS_H_ + +#include + +#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 diff --git a/object/include/blue/object/macros.h b/object/include/blue/object/macros.h new file mode 100644 index 0000000..69a96b7 --- /dev/null +++ b/object/include/blue/object/macros.h @@ -0,0 +1,130 @@ +#ifndef BLUE_OBJECT_MACROS_H_ +#define BLUE_OBJECT_MACROS_H_ + +#include +#include +#include +#include +#include + +#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 diff --git a/object/include/blue/object/object.h b/object/include/blue/object/object.h new file mode 100644 index 0000000..b1c18db --- /dev/null +++ b/object/include/blue/object/object.h @@ -0,0 +1,41 @@ +#ifndef BLUE_OBJECT_OBJECT_H_ +#define BLUE_OBJECT_OBJECT_H_ + +#include +#include +#include + +#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 diff --git a/object/include/blue/object/string.h b/object/include/blue/object/string.h new file mode 100644 index 0000000..45ddf9c --- /dev/null +++ b/object/include/blue/object/string.h @@ -0,0 +1,78 @@ +#ifndef BLUE_OBJECT_STRING_H_ +#define BLUE_OBJECT_STRING_H_ + +#include +#include +#include + +typedef enum b_strlen_flags { + B_STRLEN_NORMAL = 0, + B_STRLEN_IGNORE_ESC = 0x01u, + B_STRLEN_IGNORE_MOD = 0x02u, +} b_strlen_flags; + +#define B_TYPE_STRING (b_string_get_type()) +#define B_CSTR(s) (b_string_create_from_cstr(s)) +#define B_STR_PTR(s) (b_string_ptr(s)) + +B_DECLARE_TYPE(b_string) + +B_TYPE_CLASS_DECLARATION_BEGIN(b_string) +B_TYPE_CLASS_DECLARATION_END(b_string) + +BLUE_API b_type b_string_get_type(void); + +B_TYPE_DEFAULT_CONSTRUCTOR(b_string, B_TYPE_STRING); +B_TYPE_DEFAULT_DESTRUCTOR(b_string); + +BLUE_API b_string *b_string_create_from_cstr(const char *s); +BLUE_API b_string *b_string_create_from_c(char c, size_t count); +BLUE_API b_string *b_string_duplicate(const b_string *str); + +BLUE_API char *b_string_steal(b_string *str); +BLUE_API b_status b_string_reserve(b_string *str, size_t capacity); +BLUE_API b_status b_string_replace( + b_string *str, size_t start, size_t length, const char *new_data); +BLUE_API b_status b_string_replace_all(b_string *str, const char *new_data); +BLUE_API b_status b_string_remove(b_string *str, size_t start, size_t length); +BLUE_API b_status b_string_transform(b_string *str, int (*transformer)(int)); +static inline b_status b_string_toupper(b_string *str) +{ + return b_string_transform(str, toupper); +} +static inline b_status b_string_tolower(b_string *str) +{ + return b_string_transform(str, tolower); +} +BLUE_API b_status b_string_open_stream(b_string *str, struct b_stream **out); + +BLUE_API void b_string_append_s(b_string *dest, const b_string *src); +BLUE_API void b_string_append_cstr(b_string *dest, const char *src); +BLUE_API void b_string_append_cstrf(b_string *dest, const char *format, ...); +BLUE_API void b_string_prepend_cstr(b_string *dest, const char *src); +BLUE_API void b_string_prepend_cstrf(b_string *dest, const char *format, ...); +BLUE_API void b_string_insert_s(b_string *dest, const b_string *src, size_t at); +BLUE_API void b_string_insert_cstr(b_string *dest, const char *src, size_t at); +BLUE_API void b_string_insert_cstrn( + b_string *dest, const char *src, size_t len, size_t at); +BLUE_API void b_string_insert_cstrf( + b_string *dest, size_t at, const char *format, ...); +BLUE_API void b_string_clear(b_string *str); + +BLUE_API size_t b_string_get_size(const b_string *str, b_strlen_flags flags); +BLUE_API size_t b_string_get_capacity(const b_string *str); + +BLUE_API char b_string_front(const b_string *str); +BLUE_API char b_string_back(const b_string *str); + +BLUE_API void b_string_pop_back(b_string *str); + +BLUE_API const char *b_string_ptr(const b_string *str); +BLUE_API b_string *b_string_substr(const b_string *str, size_t start, size_t len); + +BLUE_API char *b_strdup(const char *s); +BLUE_API size_t b_strlen(const char *s, b_strlen_flags flags); + +BLUE_API uint64_t b_cstr_hash(const char *s); + +#endif diff --git a/object/include/blue/object/type.h b/object/include/blue/object/type.h new file mode 100644 index 0000000..6ce6c63 --- /dev/null +++ b/object/include/blue/object/type.h @@ -0,0 +1,61 @@ +#ifndef BLUE_OBJECT_TYPE_H_ +#define BLUE_OBJECT_TYPE_H_ + +#include +#include +#include +#include +#include + +#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 diff --git a/object/object.c b/object/object.c new file mode 100644 index 0000000..7492db4 --- /dev/null +++ b/object/object.c @@ -0,0 +1,146 @@ +#include "object.h" + +#include "type.h" + +#include +#include +#include +#include + +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); +} diff --git a/object/object.h b/object/object.h new file mode 100644 index 0000000..ba7d6ba --- /dev/null +++ b/object/object.h @@ -0,0 +1,19 @@ +#ifndef _OBJECT_H_ +#define _OBJECT_H_ + +#include +#include +#include + +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 diff --git a/object/string.c b/object/string.c new file mode 100644 index 0000000..b9c148e --- /dev/null +++ b/object/string.c @@ -0,0 +1,773 @@ +#include +#include +#include + +#define STRING_INLINE_CAPACITY 15 + +struct b_string_p { + /* length of string, not including null-terminator */ + unsigned int s_len; + /* maximum length of string storable in the currently-allocated buffer, not including null terminator */ + unsigned int s_max; + union { + char d_inline[STRING_INLINE_CAPACITY + 1]; + char *d_external; + } s_data; +}; + +static void string_init(b_string *p, void *priv) +{ + struct b_string_p *str = priv; + + str->s_len = 0; + str->s_max = STRING_INLINE_CAPACITY; +} + +static bool string_is_inline(const struct b_string_p *str) +{ + /* strings cannot go below STRING_INLINE_CAPACITY capacity */ + return str->s_max == STRING_INLINE_CAPACITY; +} + +static char *string_ptr(struct b_string_p *str) +{ + if (string_is_inline(str)) { + return str->s_data.d_inline; + } + + return str->s_data.d_external; +} + +static int string_make_inline(struct b_string_p *str) +{ + char *buffer = string_ptr(str); + memcpy(str->s_data.d_inline, buffer, sizeof str->s_data.d_inline); + str->s_data.d_inline[sizeof str->s_data.d_inline - 1] = '\0'; + + str->s_max = STRING_INLINE_CAPACITY; + + if (str->s_len >= str->s_max) { + str->s_len = str->s_max; + } + + free(buffer); + return 0; +} + +static int string_resize_large(struct b_string_p *str, size_t capacity) +{ + char *buffer = string_ptr(str); + char *new_buffer = realloc(buffer, capacity + 1); + if (!new_buffer) { + return -1; + } + + str->s_max = capacity; + str->s_data.d_external = new_buffer; + return 0; +} + +static int string_make_large(struct b_string_p *str, size_t capacity) +{ + const char *old_buffer = string_ptr(str); + char *buffer = malloc(capacity + 1); + if (!buffer) { + return -1; + } + + memcpy(buffer, old_buffer, sizeof str->s_data.d_inline); + buffer[str->s_len] = '\0'; + + str->s_max = capacity; + str->s_data.d_external = buffer; + return 0; +} + +static int string_change_capacity(struct b_string_p *str, size_t capacity) +{ + size_t old_capacity = str->s_max; + + if (capacity < STRING_INLINE_CAPACITY) { + capacity = STRING_INLINE_CAPACITY; + } + + bool was_inline = string_is_inline(str); + bool is_now_inline = capacity == STRING_INLINE_CAPACITY; + + if (capacity == old_capacity) { + /* this also handles the case where the old and new capacity both fit into the inline buffer. */ + return 0; + } + + if (!was_inline && is_now_inline) { + /* string was large, is now small enough to fit inline. */ + return string_make_inline(str); + } + + if (!was_inline) { + /* string was large, and is still large. */ + return string_resize_large(str, capacity); + } + + if (!is_now_inline) { + /* string was inline, and now large enough to require a buffer. */ + return string_make_large(str, capacity); + } + + /* nothing to do */ + return 0; +} + +b_string *b_string_create_from_cstr(const char *s) +{ + b_string *p = b_string_create(); + if (!p) { + return NULL; + } + + if (!s) { + return p; + } + + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + str->s_len = strlen(s); + string_change_capacity(str, str->s_len); + + char *dest = string_ptr(str); + memcpy(dest, s, str->s_len); + dest[str->s_len] = 0; + + return p; +} + +b_string *b_string_create_from_c(char c, size_t count) +{ + b_string *p = b_string_create(); + if (!p) { + return NULL; + } + + if (!count || !c) { + return p; + } + + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + string_change_capacity(str, count); + char *s = string_ptr(str); + for (size_t i = 0; i < count; i++) { + s[i] = c; + } + + str->s_len = count; + return p; +} + +b_string *b_string_duplicate(const b_string *p) +{ + b_string *q = b_string_create(); + if (!q) { + return NULL; + } + + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + struct b_string_p *new_str + = b_object_get_private(q, struct b_string_p, B_TYPE_STRING); + + string_change_capacity(new_str, str->s_len); + const char *src = string_ptr(str); + char *dst = string_ptr(new_str); + + memcpy(dst, src, str->s_len); + new_str->s_len = str->s_len; + + return q; +} + +char *b_string_steal(b_string *p) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + char *dest = NULL; + char *src = string_ptr(str); + + if (string_is_inline(str)) { + dest = b_strdup(src); + src[0] = 0; + } else { + dest = src; + str->s_data.d_external = NULL; + str->s_max = STRING_INLINE_CAPACITY; + } + + str->s_len = 0; + return dest; +} + +static b_status string_reserve(struct b_string_p *str, size_t capacity) +{ + if (str->s_max >= capacity) { + return B_SUCCESS; + } + + int err = string_change_capacity(str, capacity); + + return err == 0 ? B_SUCCESS : B_ERR_NO_MEMORY; +} + +b_status b_string_reserve(b_string *p, size_t capacity) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + return string_reserve(str, capacity); +} + +b_status b_string_replace( + b_string *p, size_t start, size_t length, const char *new_data) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + b_status status = B_SUCCESS; + size_t new_data_len = strlen(new_data); + + if (start >= str->s_len) { + return B_ERR_INVALID_ARGUMENT; + } + + if (start + length >= str->s_len) { + length = str->s_len - start; + } + + size_t new_str_len = str->s_len - length + new_data_len; + if (new_str_len > str->s_max) { + status = string_reserve(str, new_str_len); + } + + if (!B_OK(status)) { + return status; + } + + char *s = string_ptr(str); + + char *substitution_start = s + start; + char *excess_src = s + start + length; + size_t excess_length = str->s_len - start - length; + char *excess_dest = substitution_start + new_data_len; + + memmove(excess_dest, excess_src, excess_length); + memmove(substitution_start, new_data, new_data_len); + s[new_str_len] = '\0'; + + str->s_len = new_str_len; + + return B_SUCCESS; +} + +b_status b_string_replace_all(b_string *p, const char *new_data) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + size_t new_len = strlen(new_data); + string_reserve(str, new_len); + char *dest = string_ptr(str); + memcpy(dest, new_data, new_len); + dest[new_len] = '\0'; + str->s_len = new_len; + + return B_SUCCESS; +} + +b_status b_string_remove(b_string *p, size_t start, size_t length) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + b_status status = B_SUCCESS; + + if (start >= str->s_len) { + return B_ERR_INVALID_ARGUMENT; + } + + if (start + length >= str->s_len) { + length = str->s_len - start; + } + + size_t new_str_len = str->s_len - length; + + char *s = string_ptr(str); + + char *removal_start = s + start; + char *excess_src = s + start + length; + size_t excess_length = str->s_len - start - length; + + memmove(removal_start, excess_src, excess_length); + s[new_str_len] = '\0'; + + str->s_len = new_str_len; + + return B_SUCCESS; +} + +b_status b_string_transform(b_string *p, int (*transformer)(int)) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + char *s = string_ptr(str); + for (size_t i = 0; i < str->s_len; i++) { + int c = transformer(s[i]); + + if (c != 0) { + s[i] = c; + } + } + + return B_SUCCESS; +} + +static enum b_status stream_close(struct b_stream *stream) +{ + b_string *str = stream->s_ptr; + b_release(str); + + return B_SUCCESS; +} + +static enum b_status stream_getc(struct b_stream *stream, int *out) +{ + b_string *p = stream->s_ptr; + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + if (stream->s_cursor >= str->s_len) { + return B_ERR_NO_DATA; + } + + char *s = string_ptr(str); + *out = s[stream->s_cursor]; + stream->s_cursor++; + + return B_SUCCESS; +} + +static enum b_status stream_read( + struct b_stream *stream, unsigned char *buf, size_t count, size_t *nr_read) +{ + b_string *p = stream->s_ptr; + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + if (stream->s_cursor >= str->s_len) { + *nr_read = 0; + return B_SUCCESS; + } + + size_t available = str->s_len - stream->s_cursor; + size_t to_read = b_min(size_t, count, available); + + char *s = string_ptr(str) + stream->s_cursor; + + memcpy(buf, s, to_read); + + *nr_read = to_read; + + return B_SUCCESS; +} + +static enum b_status stream_write( + struct b_stream *stream, const unsigned char *buf, size_t count, + size_t *nr_written) +{ + b_string *p = stream->s_ptr; + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + enum b_status status = B_SUCCESS; + + if (stream->s_cursor + count > str->s_max) { + status = string_reserve(str, stream->s_cursor + count); + } + + if (!B_OK(status)) { + return status; + } + + char *s = string_ptr(str) + stream->s_cursor; + memcpy(s, buf, count); + s[str->s_max] = '\0'; + stream->s_cursor += count; + str->s_len = b_max(size_t, str->s_len, stream->s_cursor + count); + + *nr_written = count; + + return B_SUCCESS; +} + +static enum b_status stream_seek( + struct b_stream *stream, long long offset, b_stream_seek_origin origin) +{ + b_string *p = stream->s_ptr; + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + size_t abs_offset; + switch (origin) { + case B_STREAM_SEEK_START: + abs_offset = offset; + break; + case B_STREAM_SEEK_CURRENT: + abs_offset = stream->s_cursor + offset; + break; + case B_STREAM_SEEK_END: + abs_offset = str->s_len + offset; + break; + default: + return B_ERR_INVALID_ARGUMENT; + } + + stream->s_cursor = abs_offset; + + return B_SUCCESS; +} + +static enum b_status stream_reserve(struct b_stream *stream, size_t len) +{ + b_string *p = stream->s_ptr; + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + size_t new_capacity = str->s_len + len; + return string_reserve(str, new_capacity); +} + +enum b_status b_string_open_stream(b_string *str, struct b_stream **out) +{ + struct b_stream *stream = malloc(sizeof *stream); + if (!stream) { + return B_ERR_NO_MEMORY; + } + + memset(stream, 0x0, sizeof *stream); + + stream->s_mode |= B_STREAM_READ | B_STREAM_WRITE; + + stream->s_ptr = b_retain(str); + stream->s_close = stream_close; + stream->s_getc = stream_getc; + stream->s_read = stream_read; + stream->s_write = stream_write; + stream->s_seek = stream_seek; + stream->s_reserve = stream_reserve; + + *out = stream; + + return B_SUCCESS; +} + +static void string_insert( + struct b_string_p *dest, const char *src, size_t len, size_t at) +{ + if (at >= dest->s_len) { + at = dest->s_len; + } + + size_t new_size = dest->s_len + len; + if (dest->s_max < new_size) { + string_change_capacity(dest, new_size); + } + + char *dest_buf = string_ptr(dest); + char *from = dest_buf + at; + char *to = dest_buf + at + len; + + memmove(to, from, dest->s_len - at); + memcpy(from, src, len); + dest_buf[new_size] = '\0'; + + dest->s_len = new_size; +} + +static void string_insertf( + struct b_string_p *dest, size_t at, const char *format, va_list arg) +{ + char buf[1024]; + size_t len = vsnprintf(buf, sizeof buf, format, arg); + string_insert(dest, buf, len, at); +} + +void b_string_insert_s(b_string *dest, const b_string *src, size_t at) +{ + struct b_string_p *dest_str + = b_object_get_private(dest, struct b_string_p, B_TYPE_STRING); + struct b_string_p *src_str + = b_object_get_private(src, struct b_string_p, B_TYPE_STRING); + string_insert(dest_str, string_ptr(src_str), src_str->s_len, at); +} + +void b_string_insert_cstr(b_string *dest, const char *src, size_t at) +{ + struct b_string_p *dest_str + = b_object_get_private(dest, struct b_string_p, B_TYPE_STRING); + string_insert(dest_str, src, strlen(src), at); +} + +void b_string_insert_cstrf(b_string *dest, size_t at, const char *format, ...) +{ + struct b_string_p *dest_str + = b_object_get_private(dest, struct b_string_p, B_TYPE_STRING); + + va_list arg; + va_start(arg, format); + string_insertf(dest_str, at, format, arg); + va_end(arg); +} + +void b_string_insert_cstrn(b_string *dest, const char *src, size_t len, size_t at) +{ + struct b_string_p *dest_str + = b_object_get_private(dest, struct b_string_p, B_TYPE_STRING); + + string_insert(dest_str, src, len, at); +} + +void b_string_append_s(b_string *dest, const b_string *src) +{ + b_string_insert_s(dest, src, SIZE_MAX); +} + +void b_string_append_cstr(b_string *dest, const char *src) +{ + b_string_insert_cstr(dest, src, SIZE_MAX); +} + +void b_string_append_cstrf(b_string *dest, const char *format, ...) +{ + struct b_string_p *dest_str + = b_object_get_private(dest, struct b_string_p, B_TYPE_STRING); + + va_list arg; + va_start(arg, format); + string_insertf(dest_str, SIZE_MAX, format, arg); + va_end(arg); +} + +void b_string_prepend_s(b_string *dest, const b_string *src) +{ + b_string_insert_s(dest, src, 0); +} + +void b_string_prepend_cstr(b_string *dest, const char *src) +{ + b_string_insert_cstr(dest, src, 0); +} + +void b_string_prepend_cstrf(b_string *dest, const char *format, ...) +{ + struct b_string_p *dest_str + = b_object_get_private(dest, struct b_string_p, B_TYPE_STRING); + + va_list arg; + va_start(arg, format); + string_insertf(dest_str, 0, format, arg); + va_end(arg); +} + +void b_string_clear(b_string *p) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + if (str->s_len == 0) { + return; + } + + char *s = string_ptr(str); + *s = '\0'; + str->s_len = 0; +} + +size_t b_string_get_size(const b_string *p, b_strlen_flags flags) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + if (flags != B_STRLEN_NORMAL) { + return b_strlen(string_ptr(str), flags); + } + + return str->s_len; +} + +size_t b_string_get_capacity(const b_string *p) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + return str->s_max; +} + +char b_string_front(const b_string *p) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + if (str->s_len == 0) { + return 0; + } + + const char *s = string_ptr(str); + return s[0]; +} + +char b_string_back(const b_string *p) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + if (str->s_len == 0) { + return 0; + } + + const char *s = string_ptr(str); + return s[str->s_len - 1]; +} + +void b_string_pop_back(b_string *p) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + if (str->s_len == 0) { + return; + } + + char *s = string_ptr(str); + + s[str->s_len - 1] = '\0'; + str->s_len--; +} + +const char *b_string_ptr(const b_string *p) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + if (string_is_inline(str)) { + return str->s_data.d_inline; + } + + return str->s_data.d_external; +} + +b_string *b_string_substr(const b_string *p, size_t start, size_t len) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + + if (start > str->s_len) { + return NULL; + } + + if (start + len > str->s_len) { + len = str->s_len - start; + } + + b_string *new_str = b_string_create(); + struct b_string_p *new_str_p + = b_object_get_private(new_str, struct b_string_p, B_TYPE_STRING); + string_reserve(new_str_p, len); + + const char *src = string_ptr(str) + start; + char *dest = string_ptr(new_str_p); + + memcpy(dest, src, len); + new_str_p->s_len = len; + + return new_str; +} + +static void string_fini(b_string *p, void *priv) +{ + struct b_string_p *str = priv; + if (!string_is_inline(str)) { + free(string_ptr(str)); + } +} + +static void string_to_string(b_string *p, struct b_stream *out) +{ + struct b_string_p *str + = b_object_get_private(p, struct b_string_p, B_TYPE_STRING); + b_stream_write_string(out, string_ptr(str), NULL); +} + +char *b_strdup(const char *s) +{ + size_t len = strlen(s); + char *p = malloc(len + 1); + if (!p) { + return NULL; + } + + memcpy(p, s, len); + p[len] = '\0'; + + return p; +} + +size_t b_strlen(const char *s, b_strlen_flags flags) +{ + if (!(flags & (B_STRLEN_IGNORE_ESC | B_STRLEN_IGNORE_MOD))) { + return strlen(s); + } + + size_t out = 0; + for (size_t i = 0; s[i]; i++) { + if (s[i] == '\033' && (flags & B_STRLEN_IGNORE_ESC)) { + while (!isalpha(s[i]) && s[i]) { + i++; + } + + continue; + } + + if (s[i] == '[' && (flags & B_STRLEN_IGNORE_MOD)) { + i++; + if (s[i] == '[') { + out++; + continue; + } + + while (s[i] != ']' && s[i]) { + i++; + } + + continue; + } + + out++; + } + + return out; +} + +B_TYPE_CLASS_DEFINITION_BEGIN(b_string) + B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT) + B_INTERFACE_ENTRY(to_string) = string_to_string; + B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT) +B_TYPE_CLASS_DEFINITION_END(b_string) + +B_TYPE_DEFINITION_BEGIN(b_string) + B_TYPE_ID(0xc986dd64, 0x7bfe, 0x4151, 0x8ffb, 0x251f4651fd35); + B_TYPE_CLASS(b_string_class); + B_TYPE_EXTENDS(B_TYPE_OBJECT); + B_TYPE_INSTANCE_PRIVATE(struct b_string_p); + B_TYPE_INSTANCE_INIT(string_init); +B_TYPE_DEFINITION_END(b_string) diff --git a/object/type.c b/object/type.c new file mode 100644 index 0000000..1d272f1 --- /dev/null +++ b/object/type.c @@ -0,0 +1,309 @@ +#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); +} diff --git a/object/type.h b/object/type.h new file mode 100644 index 0000000..e8f347b --- /dev/null +++ b/object/type.h @@ -0,0 +1,39 @@ +#ifndef _TYPE_H_ +#define _TYPE_H_ + +#include +#include +#include + +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