- 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 #define _LIBRTTI_RTTI_H_ 1
#include "rtti/typeinfo.h" #include "rtti/typeinfo.h"
#include "rtti/utils.h"
#endif #endif

View file

@ -9,12 +9,14 @@
#include <stdlib.h> #include <stdlib.h>
#include <sys/types.h> #include <sys/types.h>
#define RTTI_MAGIC (0x5254544949545452)
#define var void* #define var void*
#define SIZE_ROUNDUP(sz) \ #define RTTI_SIZE_ROUNDUP(sz) \
((((sz + sizeof(void*) - 1)) / (sizeof(void*))) * sizeof(void*)) ((((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 /** Object format
** **
@ -23,10 +25,34 @@
** +=====================+===================+===================+ ** +=====================+===================+===================+
** **
**/ **/
#define OBJ_TO_DATA(T, obj) ((T*)(((char*)obj) + OBJ_HEADER_SIZE)) #define RTTI_OBJ_TO_DATA(T, obj) ((T*)((obj)->data))
#define DATA_TO_OBJ(v) ((meta_obj_t*)(((char*)v) - OBJ_HEADER_SIZE)) #define RTTI_DATA_TO_OBJ(v) \
#define OBJ_TO_PRIV(obj) \ (((v) == NULL) ? NULL : ((meta_obj_t*)(((char*)v) - RTTI_OBJ_HEADER_SIZE)))
((void*)(((char*)obj) - SIZE_ROUNDUP((obj)->type->privateSize))) #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 meta_obj_;
struct typeinfo_; struct typeinfo_;
@ -38,12 +64,12 @@ typedef struct typeinfo_ typeinfo_t;
typedef size_t (*datasize_fn_t)(va_list); typedef size_t (*datasize_fn_t)(va_list);
/* object life cycle */ /* object life cycle */
typedef int (*obj_init_fn_t)(typeinfo_t*, va_list); typedef int (*obj_init_fn_t)(meta_obj_t*, va_list);
typedef void (*obj_destroy_fn_t)(var); typedef void (*obj_destroy_fn_t)(meta_obj_t*);
/* lock/unlock */ /* lock/unlock */
typedef int (*lock_fn_t)(var, uint64_t); typedef int (*lock_fn_t)(meta_obj_t*, uint64_t);
typedef void (*unlock_fn_t)(var); typedef void (*unlock_fn_t)(meta_obj_t*);
typedef struct { typedef struct {
lock_fn_t lock; lock_fn_t lock;
@ -51,7 +77,7 @@ typedef struct {
} intf_lock_t; } intf_lock_t;
/* convert to string */ /* 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 { typedef struct {
to_string_fn_t toString; to_string_fn_t toString;
@ -59,15 +85,15 @@ typedef struct {
/* iterator function */ /* iterator function */
#define ITER_NO_DATA (0) #define RTTI_ITER_NO_DATA (0)
#define ITER_OK (1) #define RTTI_ITER_OK (1)
typedef struct { typedef struct {
var v; meta_obj_t* obj;
var data; var data;
} iterator_t; } 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_next_fn_t)(iterator_t*, void**);
typedef int (*iter_reset_fn_t)(iterator_t*); typedef int (*iter_reset_fn_t)(iterator_t*);
typedef void (*iter_destroy_fn_t)(iterator_t*); typedef void (*iter_destroy_fn_t)(iterator_t*);
@ -80,8 +106,8 @@ typedef struct {
} intf_iterator_t; } intf_iterator_t;
/* reference and deref */ /* reference and deref */
typedef int32_t (*reference_fn_t)(var); typedef int32_t (*reference_fn_t)(meta_obj_t*);
typedef void (*dereference_fn_t)(var); typedef void (*dereference_fn_t)(meta_obj_t*);
typedef struct { typedef struct {
reference_fn_t reference; reference_fn_t reference;
@ -90,14 +116,14 @@ typedef struct {
/* hash */ /* hash */
typedef int32_t (*hash_fn_t)(var); typedef int32_t (*hash_fn_t)(meta_obj_t*);
typedef struct { typedef struct {
hash_fn_t hash; hash_fn_t hash;
} intf_hash_t; } intf_hash_t;
/* length */ /* length */
typedef int64_t (*length_fn_t)(var); typedef int64_t (*length_fn_t)(meta_obj_t*);
typedef struct { typedef struct {
length_fn_t length; length_fn_t length;
@ -122,11 +148,15 @@ struct typeinfo_ {
}; };
struct meta_obj_ { struct meta_obj_ {
uint64_t magic;
typeinfo_t* type; typeinfo_t* type;
void* privdata;
void* data;
}; };
extern var makeInstance(typeinfo_t*, ...); extern var makeInstance(typeinfo_t*, ...);
extern void destroy(var); extern void destroy(var);
extern int is_rtti_obj(var);
extern int lock(var, uint64_t); extern int lock(var, uint64_t);
extern void unlock(var); extern void unlock(var);
extern char* toString(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" #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 privateSize = RTTI_SIZE_ROUNDUP(type->privateSize);
size_t headerSize = OBJ_HEADER_SIZE; size_t headerSize = RTTI_OBJ_HEADER_SIZE;
char* p = NULL; char* p = NULL;
meta_obj_t* obj = NULL; meta_obj_t* obj = NULL;
size_t total = privateSize + headerSize + sz; size_t total = privateSize + headerSize + sz;
@ -16,18 +16,21 @@ static void* objAlloc(typeinfo_t* type, size_t sz)
return NULL; return NULL;
} }
obj = (meta_obj_t*)(p + privateSize); obj = (meta_obj_t*)(p + privateSize);
obj->type = type; 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, ...) var makeInstance(typeinfo_t* type, ...)
{ {
va_list ap; va_list ap;
va_list ap1; va_list ap1;
var v = NULL; meta_obj_t* obj;
int rc = 0; int rc = 0;
if ((type == NULL) || (type->init == NULL) || (type->dataSize == NULL)) { if ((type == NULL) || (type->init == NULL) || (type->dataSize == NULL)) {
errno = EINVAL; errno = EINVAL;
@ -36,46 +39,57 @@ var makeInstance(typeinfo_t* type, ...)
va_start(ap, type); va_start(ap, type);
va_copy(ap1, ap); va_copy(ap1, ap);
v = objAlloc(type, type->dataSize(ap1)); obj = objAlloc(type, type->dataSize(ap1));
va_end(ap1); va_end(ap1);
if (v != NULL) { if (obj != NULL) {
rc = type->init(v, ap); rc = type->init(obj, ap);
} }
va_end(ap); va_end(ap);
if (rc < 0) { if (rc < 0) {
destroy(v); destroy(obj);
v = NULL; return NULL;
} }
return v; return obj->data;
} }
void destroy(var v) void destroy(var v)
{ {
typeinfo_t* type = NULL; typeinfo_t* type = NULL;
meta_obj_t* obj = NULL;
void* p = NULL; void* p = NULL;
meta_obj_t* obj = NULL;
if (v == NULL) { obj = RTTI_DATA_TO_OBJ(v);
if (RTTI_OBJ_INVALID(obj)) {
return; return;
} }
obj = DATA_TO_OBJ(v);
type = obj->type; type = obj->type;
if (type == NULL) { if (type == NULL) {
return; return;
} }
if (type->destroy != NULL) { if (type->destroy != NULL) {
type->destroy(v); type->destroy(obj);
} }
p = OBJ_TO_PRIV(obj); p = RTTI_OBJ_TO_PRIV(obj);
free(p); free(p);
return; 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) int iter_make(iterator_t* it, var v)
{ {
meta_obj_t* obj = NULL;
iter_make_fn_t method = NULL; iter_make_fn_t method = NULL;
if (it == NULL) { if (it == NULL) {
return -EINVAL; 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) { if (method == NULL) {
return -EINVAL; return -EINVAL;
} }
memset(it, 0x0, sizeof(*it)); 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) int iter_next(iterator_t* it, void** data)
{ {
iter_next_fn_t method = NULL; iter_next_fn_t method = NULL;
if ((it == NULL) || (data == NULL) || (it->v == NULL)) { if ((it == NULL) || (data == NULL)) {
return -EINVAL; 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) { if (method == NULL) {
return -EINVAL; return -EINVAL;
} }
@ -43,11 +53,15 @@ int iter_reset(iterator_t* it)
{ {
iter_reset_fn_t method = NULL; iter_reset_fn_t method = NULL;
if ((it == NULL) || (it->v == NULL)) { if (it == NULL) {
return -EINVAL; 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) { if (method == NULL) {
return -EINVAL; return -EINVAL;
} }
@ -59,11 +73,15 @@ void iter_destroy(iterator_t* it)
{ {
iter_destroy_fn_t method = NULL; iter_destroy_fn_t method = NULL;
if ((it == NULL) || (it->v == NULL)) { if (it == NULL) {
return; 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) { if (method == NULL) {
return; 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) int lock(var v, uint64_t option)
{ {
lock_fn_t method = NULL; 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) { if (method == NULL) {
return -EINVAL; return -EINVAL;
} }
return method(v, option); return method(obj, option);
} }
void unlock(var v) void unlock(var v)
{ {
meta_obj_t* obj = NULL;
unlock_fn_t method = 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) { if (method == NULL) {
return; return;
} }

View file

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

View file

@ -6,23 +6,35 @@
int32_t reference(var v) int32_t reference(var v)
{ {
meta_obj_t* obj = NULL;
reference_fn_t method = 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) { if (method == NULL) {
return -EINVAL; return -EINVAL;
} }
return method(v); return method(obj);
} }
void dereference(var v) void dereference(var v)
{ {
meta_obj_t* obj = NULL;
dereference_fn_t method = 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) { if (method != NULL) {
method(v); method(obj);
} }
return; return;

View file

@ -5,13 +5,20 @@
char* toString(var v, ...) char* toString(var v, ...)
{ {
meta_obj_t* obj = NULL;
to_string_fn_t method = NULL; to_string_fn_t method = NULL;
va_list ap; va_list ap;
char* s = NULL; 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) { if (method == NULL) {
errno = -EINVAL; errno = EINVAL;
return NULL; return NULL;
} }

View file

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

View file

@ -5,17 +5,17 @@
void setUp(void) void setUp(void)
{ {
printf("\n");
return; return;
} }
void tearDown(void) void tearDown(void)
{ {
printf("\n"); printf(">>");
return; return;
} }
extern void test_iter(void); extern void test_iter(void);
extern void test_invalid(void);
#define TEST(x) x() #define TEST(x) x()
@ -24,6 +24,7 @@ int main(int argc, char* argv[])
UNITY_BEGIN(); UNITY_BEGIN();
TEST(test_iter); TEST(test_iter);
TEST(test_invalid);
return UNITY_END(); 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,10 +11,11 @@ typedef struct {
static size_t my_array_datasize(va_list ap) { return sizeof(myArray_t); } 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)
{ {
int count; myArray_t* a = RTTI_OBJ_TO_DATA(myArray_t, obj);
int i; int count;
int i;
count = va_arg(ap, int); count = va_arg(ap, int);
if (count <= 0) { if (count <= 0) {
@ -34,42 +35,43 @@ static int my_array_init(myArray_t* a, va_list ap)
return 1; 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) { if (a->data != NULL) {
free(a->data); free(a->data);
a->data = NULL; 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; iter->data = (void*)(long)0;
return ITER_OK; return RTTI_ITER_OK;
} }
static int my_array_iter_next(iterator_t* iter, void** data) 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; int idx = (int)(long)iter->data;
if (idx >= a->count) { if (idx >= a->count) {
/* no data */ /* no data */
return ITER_NO_DATA; return RTTI_ITER_NO_DATA;
} }
*data = (void*)(long)a->data[idx]; *data = (void*)(long)a->data[idx];
iter->data = (void*)(long)(idx + 1); iter->data = (void*)(long)(idx + 1);
return ITER_OK; return RTTI_ITER_OK;
} }
static int my_array_iter_reset(iterator_t* iter) static int my_array_iter_reset(iterator_t* iter)
{ {
iter->data = (void*)(long)0; iter->data = (void*)(long)0;
return ITER_OK; return RTTI_ITER_OK;
} }
static void my_array_iter_destroy(iterator_t* iter) { return; } static void my_array_iter_destroy(iterator_t* iter) { return; }
@ -95,7 +97,7 @@ static void test_array_iter(void)
void* data; void* data;
TEST_ASSERT_TRUE(array != NULL); TEST_ASSERT_TRUE(array != NULL);
TEST_ASSERT_TRUE(is_rtti_obj(array) == 1);
rc = iter_make(&it, array); rc = iter_make(&it, array);
TEST_ASSERT_TRUE(rc == 1); TEST_ASSERT_TRUE(rc == 1);
@ -120,7 +122,7 @@ static void test_array_iter(void)
TEST_ASSERT_TRUE((int)(long)data == 4); TEST_ASSERT_TRUE((int)(long)data == 4);
rc = iter_next(&it, (void**)&data); rc = iter_next(&it, (void**)&data);
TEST_ASSERT_TRUE(rc == ITER_NO_DATA); TEST_ASSERT_TRUE(rc == RTTI_ITER_NO_DATA);
sum = 0; sum = 0;
rc = iter_reset(&it); rc = iter_reset(&it);
@ -129,7 +131,7 @@ static void test_array_iter(void)
for (;;) { for (;;) {
rc = iter_next(&it, &data); rc = iter_next(&it, &data);
TEST_ASSERT_TRUE(rc >= 0); TEST_ASSERT_TRUE(rc >= 0);
if (rc == ITER_NO_DATA) { if (rc == RTTI_ITER_NO_DATA) {
break; break;
} }