- improve the interface of rtti to pass meta_obj_t* as parameter of type function to easy to access private/data

- rename some macro with RTTI
- add RTTI_MAGIC in object header
- add new rtti api
This commit is contained in:
Rongsong Shen 2026-01-30 12:26:23 +08:00
parent c8c1749347
commit f78ed03591
15 changed files with 252 additions and 114 deletions

View file

@ -3,6 +3,5 @@
#define _LIBRTTI_RTTI_H_ 1
#include "rtti/typeinfo.h"
#include "rtti/utils.h"
#endif

View file

@ -9,12 +9,14 @@
#include <stdlib.h>
#include <sys/types.h>
#define RTTI_MAGIC (0x5254544949545452)
#define var void*
#define SIZE_ROUNDUP(sz) \
#define RTTI_SIZE_ROUNDUP(sz) \
((((sz + sizeof(void*) - 1)) / (sizeof(void*))) * sizeof(void*))
#define OBJ_HEADER_SIZE SIZE_ROUNDUP(sizeof(meta_obj_t))
#define RTTI_OBJ_HEADER_SIZE RTTI_SIZE_ROUNDUP(sizeof(meta_obj_t))
/** Object format
**
@ -23,10 +25,34 @@
** +=====================+===================+===================+
**
**/
#define OBJ_TO_DATA(T, obj) ((T*)(((char*)obj) + OBJ_HEADER_SIZE))
#define DATA_TO_OBJ(v) ((meta_obj_t*)(((char*)v) - OBJ_HEADER_SIZE))
#define OBJ_TO_PRIV(obj) \
((void*)(((char*)obj) - SIZE_ROUNDUP((obj)->type->privateSize)))
#define RTTI_OBJ_TO_DATA(T, obj) ((T*)((obj)->data))
#define RTTI_DATA_TO_OBJ(v) \
(((v) == NULL) ? NULL : ((meta_obj_t*)(((char*)v) - RTTI_OBJ_HEADER_SIZE)))
#define RTTI_OBJ_TO_PRIV(obj) ((obj)->privdata)
#define RTTI_GET_METHOD(result, obj, intf, method) \
do { \
typeinfo_t* type_ = NULL; \
\
(result) = NULL; \
\
if ((obj) == NULL) { \
break; \
} \
\
type_ = obj->type; \
if (type_ == NULL) { \
break; \
} \
\
if (type_->interfaces.intf == NULL) { \
break; \
} \
\
(result) = type_->interfaces.intf->method; \
} while (0)
#define RTTI_OBJ_INVALID(obj) (((obj) == NULL) || ((obj)->magic != RTTI_MAGIC))
struct meta_obj_;
struct typeinfo_;
@ -38,12 +64,12 @@ typedef struct typeinfo_ typeinfo_t;
typedef size_t (*datasize_fn_t)(va_list);
/* object life cycle */
typedef int (*obj_init_fn_t)(typeinfo_t*, va_list);
typedef void (*obj_destroy_fn_t)(var);
typedef int (*obj_init_fn_t)(meta_obj_t*, va_list);
typedef void (*obj_destroy_fn_t)(meta_obj_t*);
/* lock/unlock */
typedef int (*lock_fn_t)(var, uint64_t);
typedef void (*unlock_fn_t)(var);
typedef int (*lock_fn_t)(meta_obj_t*, uint64_t);
typedef void (*unlock_fn_t)(meta_obj_t*);
typedef struct {
lock_fn_t lock;
@ -51,7 +77,7 @@ typedef struct {
} intf_lock_t;
/* convert to string */
typedef char* (*to_string_fn_t)(var, va_list);
typedef char* (*to_string_fn_t)(meta_obj_t*, va_list);
typedef struct {
to_string_fn_t toString;
@ -59,15 +85,15 @@ typedef struct {
/* iterator function */
#define ITER_NO_DATA (0)
#define ITER_OK (1)
#define RTTI_ITER_NO_DATA (0)
#define RTTI_ITER_OK (1)
typedef struct {
var v;
meta_obj_t* obj;
var data;
} iterator_t;
typedef int (*iter_make_fn_t)(iterator_t*, var);
typedef int (*iter_make_fn_t)(iterator_t*);
typedef int (*iter_next_fn_t)(iterator_t*, void**);
typedef int (*iter_reset_fn_t)(iterator_t*);
typedef void (*iter_destroy_fn_t)(iterator_t*);
@ -80,8 +106,8 @@ typedef struct {
} intf_iterator_t;
/* reference and deref */
typedef int32_t (*reference_fn_t)(var);
typedef void (*dereference_fn_t)(var);
typedef int32_t (*reference_fn_t)(meta_obj_t*);
typedef void (*dereference_fn_t)(meta_obj_t*);
typedef struct {
reference_fn_t reference;
@ -90,14 +116,14 @@ typedef struct {
/* hash */
typedef int32_t (*hash_fn_t)(var);
typedef int32_t (*hash_fn_t)(meta_obj_t*);
typedef struct {
hash_fn_t hash;
} intf_hash_t;
/* length */
typedef int64_t (*length_fn_t)(var);
typedef int64_t (*length_fn_t)(meta_obj_t*);
typedef struct {
length_fn_t length;
@ -122,11 +148,15 @@ struct typeinfo_ {
};
struct meta_obj_ {
uint64_t magic;
typeinfo_t* type;
void* privdata;
void* data;
};
extern var makeInstance(typeinfo_t*, ...);
extern void destroy(var);
extern int is_rtti_obj(var);
extern int lock(var, uint64_t);
extern void unlock(var);
extern char* toString(var, ...);

View file

@ -1,30 +0,0 @@
#if !defined(_RTTI_UTILS_H_)
#define _RTTI_UTILS_H_ 1
#define RTTI_GET_METHOD(result, obj, intf, method) \
do { \
typeinfo_t* type_ = NULL; \
meta_obj_t* obj_ = NULL; \
\
(result) = NULL; \
\
if ((obj) == NULL) { \
break; \
} \
\
obj_ = DATA_TO_OBJ(obj); \
\
type_ = obj_->type; \
if (type_ == NULL) { \
break; \
} \
\
if (type_->interfaces.intf == NULL) { \
break; \
} \
\
(result) = type_->interfaces.intf->method; \
} while (0)
#endif

View file

@ -3,10 +3,10 @@
#include "rtti.h"
static void* objAlloc(typeinfo_t* type, size_t sz)
static meta_obj_t* objAlloc(typeinfo_t* type, size_t sz)
{
size_t privateSize = SIZE_ROUNDUP(type->privateSize);
size_t headerSize = OBJ_HEADER_SIZE;
size_t privateSize = RTTI_SIZE_ROUNDUP(type->privateSize);
size_t headerSize = RTTI_OBJ_HEADER_SIZE;
char* p = NULL;
meta_obj_t* obj = NULL;
size_t total = privateSize + headerSize + sz;
@ -18,15 +18,18 @@ static void* objAlloc(typeinfo_t* type, size_t sz)
obj = (meta_obj_t*)(p + privateSize);
obj->type = type;
obj->magic = RTTI_MAGIC;
obj->privdata = p;
obj->data = (void*)(p + privateSize + headerSize);
return (void*)(p + privateSize + headerSize);
return obj;
}
var makeInstance(typeinfo_t* type, ...)
{
va_list ap;
va_list ap1;
var v = NULL;
meta_obj_t* obj;
int rc = 0;
if ((type == NULL) || (type->init == NULL) || (type->dataSize == NULL)) {
@ -36,46 +39,57 @@ var makeInstance(typeinfo_t* type, ...)
va_start(ap, type);
va_copy(ap1, ap);
v = objAlloc(type, type->dataSize(ap1));
obj = objAlloc(type, type->dataSize(ap1));
va_end(ap1);
if (v != NULL) {
rc = type->init(v, ap);
if (obj != NULL) {
rc = type->init(obj, ap);
}
va_end(ap);
if (rc < 0) {
destroy(v);
v = NULL;
destroy(obj);
return NULL;
}
return v;
return obj->data;
}
void destroy(var v)
{
typeinfo_t* type = NULL;
meta_obj_t* obj = NULL;
void* p = NULL;
meta_obj_t* obj = NULL;
if (v == NULL) {
obj = RTTI_DATA_TO_OBJ(v);
if (RTTI_OBJ_INVALID(obj)) {
return;
}
obj = DATA_TO_OBJ(v);
type = obj->type;
if (type == NULL) {
return;
}
if (type->destroy != NULL) {
type->destroy(v);
type->destroy(obj);
}
p = OBJ_TO_PRIV(obj);
p = RTTI_OBJ_TO_PRIV(obj);
free(p);
return;
}
int is_rtti_obj(var v)
{
meta_obj_t* obj = NULL;
obj = RTTI_DATA_TO_OBJ(v);
if (RTTI_OBJ_INVALID(obj)) {
return 0;
}
return 1;
}

22
src/hash.c Normal file
View file

@ -0,0 +1,22 @@
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include "rtti.h"
int32_t hash(var v) {
meta_obj_t* obj = NULL;
hash_fn_t method = NULL;
obj = RTTI_DATA_TO_OBJ(v);
if (RTTI_OBJ_INVALID(obj)) {
return -EINVAL;
}
RTTI_GET_METHOD(method, obj, hash, hash);
if (method == NULL) {
return -EINVAL;
}
return method(obj);
}

View file

@ -6,32 +6,42 @@
int iter_make(iterator_t* it, var v)
{
meta_obj_t* obj = NULL;
iter_make_fn_t method = NULL;
if (it == NULL) {
return -EINVAL;
}
RTTI_GET_METHOD(method, v, iter, make);
obj = RTTI_DATA_TO_OBJ(v);
if (RTTI_OBJ_INVALID(obj)) {
return -EINVAL;
}
RTTI_GET_METHOD(method, obj, iter, make);
if (method == NULL) {
return -EINVAL;
}
memset(it, 0x0, sizeof(*it));
it->v = v;
it->obj = obj;
return method(it, v);
return method(it);
}
int iter_next(iterator_t* it, void** data)
{
iter_next_fn_t method = NULL;
if ((it == NULL) || (data == NULL) || (it->v == NULL)) {
if ((it == NULL) || (data == NULL)) {
return -EINVAL;
}
RTTI_GET_METHOD(method, it->v, iter, next);
if (RTTI_OBJ_INVALID(it->obj)) {
return -EINVAL;
}
RTTI_GET_METHOD(method, it->obj, iter, next);
if (method == NULL) {
return -EINVAL;
}
@ -43,11 +53,15 @@ int iter_reset(iterator_t* it)
{
iter_reset_fn_t method = NULL;
if ((it == NULL) || (it->v == NULL)) {
if (it == NULL) {
return -EINVAL;
}
RTTI_GET_METHOD(method, it->v, iter, reset);
if (RTTI_OBJ_INVALID(it->obj)) {
return -EINVAL;
}
RTTI_GET_METHOD(method, it->obj, iter, reset);
if (method == NULL) {
return -EINVAL;
}
@ -59,11 +73,15 @@ void iter_destroy(iterator_t* it)
{
iter_destroy_fn_t method = NULL;
if ((it == NULL) || (it->v == NULL)) {
if (it == NULL) {
return;
}
RTTI_GET_METHOD(method, it->v, iter, destroy);
if (RTTI_OBJ_INVALID(it->obj)) {
return;
}
RTTI_GET_METHOD(method, it->obj, iter, destroy);
if (method == NULL) {
return;
}

23
src/length.c Normal file
View file

@ -0,0 +1,23 @@
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include "rtti.h"
int64_t length(var v)
{
meta_obj_t* obj = NULL;
length_fn_t method = NULL;
obj = RTTI_DATA_TO_OBJ(v);
if (RTTI_OBJ_INVALID(obj)) {
return -EINVAL;
}
RTTI_GET_METHOD(method, obj, length, length);
if (method == NULL) {
return -EINVAL;
}
return method(obj);
}

View file

@ -5,21 +5,33 @@
int lock(var v, uint64_t option)
{
meta_obj_t* obj = NULL;
lock_fn_t method = NULL;
RTTI_GET_METHOD(method, v, lock, lock);
obj = RTTI_DATA_TO_OBJ(v);
if (RTTI_OBJ_INVALID(obj)) {
return -EINVAL;
}
RTTI_GET_METHOD(method, obj, lock, lock);
if (method == NULL) {
return -EINVAL;
}
return method(v, option);
return method(obj, option);
}
void unlock(var v)
{
meta_obj_t* obj = NULL;
unlock_fn_t method = NULL;
RTTI_GET_METHOD(method, v, lock, unlock);
obj = RTTI_DATA_TO_OBJ(v);
if (RTTI_OBJ_INVALID(obj)) {
return;
}
RTTI_GET_METHOD(method, obj, lock, unlock);
if (method == NULL) {
return;
}

View file

@ -6,6 +6,8 @@ librtti_c_srcs=[
'iter.c',
'ref.c',
'str.c',
'hash.c',
'length.c',
]
@ -19,7 +21,6 @@ rtti_top_headers = [
rtti_headers = [
'../include/rtti/typeinfo.h',
'../include/rtti/utils.h',
]
librtti_deps = [

View file

@ -6,23 +6,35 @@
int32_t reference(var v)
{
meta_obj_t* obj = NULL;
reference_fn_t method = NULL;
RTTI_GET_METHOD(method, v, reference, reference);
obj = RTTI_DATA_TO_OBJ(v);
if (RTTI_OBJ_INVALID(obj)) {
return -EINVAL;
}
RTTI_GET_METHOD(method, obj, reference, reference);
if (method == NULL) {
return -EINVAL;
}
return method(v);
return method(obj);
}
void dereference(var v)
{
meta_obj_t* obj = NULL;
dereference_fn_t method = NULL;
RTTI_GET_METHOD(method,v, reference, dereference);
obj = RTTI_DATA_TO_OBJ(v);
if (RTTI_OBJ_INVALID(obj)) {
return;
}
RTTI_GET_METHOD(method, obj, reference, dereference);
if (method != NULL) {
method(v);
method(obj);
}
return;

View file

@ -5,13 +5,20 @@
char* toString(var v, ...)
{
meta_obj_t* obj = NULL;
to_string_fn_t method = NULL;
va_list ap;
char* s = NULL;
RTTI_GET_METHOD(method, v, toString, toString);
obj = RTTI_DATA_TO_OBJ(v);
if (RTTI_OBJ_INVALID(obj)) {
errno = EINVAL;
return NULL;
}
RTTI_GET_METHOD(method, obj, toString, toString);
if (method == NULL) {
errno = -EINVAL;
errno = EINVAL;
return NULL;
}

View file

@ -1,6 +1,7 @@
librtti_test_srcs = [
'test.c',
'test_iter.c',
'test_invalid_obj.c',
]
unity_dep = dependency('unity')

View file

@ -5,17 +5,17 @@
void setUp(void)
{
printf("\n");
return;
}
void tearDown(void)
{
printf("\n");
printf(">>");
return;
}
extern void test_iter(void);
extern void test_invalid(void);
#define TEST(x) x()
@ -24,6 +24,7 @@ int main(int argc, char* argv[])
UNITY_BEGIN();
TEST(test_iter);
TEST(test_invalid);
return UNITY_END();
}

View file

@ -0,0 +1,26 @@
#include <errno.h>
#include <stdarg.h>
#include <unity/unity.h>
#include "rtti.h"
static void test_c_str_invalid(void)
{
char* hello = "Hello, world";
TEST_ASSERT_TRUE(is_rtti_obj(hello) == 0);
}
static void test_intptr_invalid(void) {
int x = 20;
TEST_ASSERT_TRUE(is_rtti_obj(&x) == 0);
}
void test_invalid(void)
{
printf("\n invalid object\n\n");
RUN_TEST(test_c_str_invalid);
RUN_TEST(test_intptr_invalid);
}

View file

@ -11,8 +11,9 @@ typedef struct {
static size_t my_array_datasize(va_list ap) { return sizeof(myArray_t); }
static int my_array_init(myArray_t* a, va_list ap)
static int my_array_init(meta_obj_t* obj, va_list ap)
{
myArray_t* a = RTTI_OBJ_TO_DATA(myArray_t, obj);
int count;
int i;
@ -34,42 +35,43 @@ static int my_array_init(myArray_t* a, va_list ap)
return 1;
}
static void my_array_destroy(myArray_t* a)
static void my_array_destroy(meta_obj_t* obj)
{
myArray_t* a = RTTI_OBJ_TO_DATA(myArray_t, obj);
if (a->data != NULL) {
free(a->data);
a->data = NULL;
}
}
static int my_array_make_iter(iterator_t* iter, var obj)
static int my_array_make_iter(iterator_t* iter)
{
iter->data = (void*)(long)0;
return ITER_OK;
return RTTI_ITER_OK;
}
static int my_array_iter_next(iterator_t* iter, void** data)
{
myArray_t* a = iter->v;
myArray_t* a = RTTI_OBJ_TO_DATA(myArray_t, iter->obj);
int idx = (int)(long)iter->data;
if (idx >= a->count) {
/* no data */
return ITER_NO_DATA;
return RTTI_ITER_NO_DATA;
}
*data = (void*)(long)a->data[idx];
iter->data = (void*)(long)(idx + 1);
return ITER_OK;
return RTTI_ITER_OK;
}
static int my_array_iter_reset(iterator_t* iter)
{
iter->data = (void*)(long)0;
return ITER_OK;
return RTTI_ITER_OK;
}
static void my_array_iter_destroy(iterator_t* iter) { return; }
@ -95,7 +97,7 @@ static void test_array_iter(void)
void* data;
TEST_ASSERT_TRUE(array != NULL);
TEST_ASSERT_TRUE(is_rtti_obj(array) == 1);
rc = iter_make(&it, array);
TEST_ASSERT_TRUE(rc == 1);
@ -120,7 +122,7 @@ static void test_array_iter(void)
TEST_ASSERT_TRUE((int)(long)data == 4);
rc = iter_next(&it, (void**)&data);
TEST_ASSERT_TRUE(rc == ITER_NO_DATA);
TEST_ASSERT_TRUE(rc == RTTI_ITER_NO_DATA);
sum = 0;
rc = iter_reset(&it);
@ -129,7 +131,7 @@ static void test_array_iter(void)
for (;;) {
rc = iter_next(&it, &data);
TEST_ASSERT_TRUE(rc >= 0);
if (rc == ITER_NO_DATA) {
if (rc == RTTI_ITER_NO_DATA) {
break;
}