From f78ed0359185b3b97d32cb55ffdc067fc5d21351 Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Fri, 30 Jan 2026 12:26:23 +0800 Subject: [PATCH] - 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 --- include/rtti.h | 1 - include/rtti/typeinfo.h | 70 +++++++++++++++++++++++++----------- include/rtti/utils.h | 30 ---------------- src/create.c | 58 ++++++++++++++++++------------ src/hash.c | 22 ++++++++++++ src/iter.c | 46 ++++++++++++++++-------- src/length.c | 23 ++++++++++++ src/lock.c | 20 ++++++++--- src/meson.build | 3 +- src/ref.c | 20 ++++++++--- src/str.c | 11 ++++-- testsuite/meson.build | 1 + testsuite/test.c | 7 ++-- testsuite/test_invalid_obj.c | 26 ++++++++++++++ testsuite/test_iter.c | 28 ++++++++------- 15 files changed, 252 insertions(+), 114 deletions(-) delete mode 100644 include/rtti/utils.h create mode 100644 src/hash.c create mode 100644 src/length.c create mode 100644 testsuite/test_invalid_obj.c diff --git a/include/rtti.h b/include/rtti.h index cbf678f..aa937f9 100644 --- a/include/rtti.h +++ b/include/rtti.h @@ -3,6 +3,5 @@ #define _LIBRTTI_RTTI_H_ 1 #include "rtti/typeinfo.h" -#include "rtti/utils.h" #endif diff --git a/include/rtti/typeinfo.h b/include/rtti/typeinfo.h index acaf015..9144977 100644 --- a/include/rtti/typeinfo.h +++ b/include/rtti/typeinfo.h @@ -9,12 +9,14 @@ #include #include +#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; - var data; + 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, ...); diff --git a/include/rtti/utils.h b/include/rtti/utils.h deleted file mode 100644 index 7511262..0000000 --- a/include/rtti/utils.h +++ /dev/null @@ -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 diff --git a/src/create.c b/src/create.c index 2ae896e..8475435 100644 --- a/src/create.c +++ b/src/create.c @@ -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; @@ -16,18 +16,21 @@ static void* objAlloc(typeinfo_t* type, size_t sz) return NULL; } - obj = (meta_obj_t*)(p + privateSize); - obj->type = type; + 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; - int rc = 0; + va_list ap; + va_list ap1; + meta_obj_t* obj; + int rc = 0; if ((type == NULL) || (type->init == NULL) || (type->dataSize == NULL)) { errno = EINVAL; @@ -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; +} diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..57c8373 --- /dev/null +++ b/src/hash.c @@ -0,0 +1,22 @@ +#include +#include +#include + +#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); +} diff --git a/src/iter.c b/src/iter.c index 37fa4f4..2a5b69b 100644 --- a/src/iter.c +++ b/src/iter.c @@ -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; - return method(it, v); + memset(it, 0x0, sizeof(*it)); + it->obj = obj; + + 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,16 +73,20 @@ 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; } method(it); - + return; } diff --git a/src/length.c b/src/length.c new file mode 100644 index 0000000..fed03cc --- /dev/null +++ b/src/length.c @@ -0,0 +1,23 @@ +#include +#include +#include + +#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); +} diff --git a/src/lock.c b/src/lock.c index 6b31408..34f4e5b 100644 --- a/src/lock.c +++ b/src/lock.c @@ -5,21 +5,33 @@ 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) { 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; } diff --git a/src/meson.build b/src/meson.build index db6278b..5f083eb 100644 --- a/src/meson.build +++ b/src/meson.build @@ -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 = [ diff --git a/src/ref.c b/src/ref.c index 7535e60..d0f03db 100644 --- a/src/ref.c +++ b/src/ref.c @@ -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; diff --git a/src/str.c b/src/str.c index 1d3f112..3d85bc6 100644 --- a/src/str.c +++ b/src/str.c @@ -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; } diff --git a/testsuite/meson.build b/testsuite/meson.build index ab6519d..fe744b7 100644 --- a/testsuite/meson.build +++ b/testsuite/meson.build @@ -1,6 +1,7 @@ librtti_test_srcs = [ 'test.c', 'test_iter.c', + 'test_invalid_obj.c', ] unity_dep = dependency('unity') diff --git a/testsuite/test.c b/testsuite/test.c index b7465ed..83b1eed 100644 --- a/testsuite/test.c +++ b/testsuite/test.c @@ -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(); } diff --git a/testsuite/test_invalid_obj.c b/testsuite/test_invalid_obj.c new file mode 100644 index 0000000..a71d0f8 --- /dev/null +++ b/testsuite/test_invalid_obj.c @@ -0,0 +1,26 @@ +#include +#include +#include + +#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); +} diff --git a/testsuite/test_iter.c b/testsuite/test_iter.c index f08a2f1..f754403 100644 --- a/testsuite/test_iter.c +++ b/testsuite/test_iter.c @@ -11,10 +11,11 @@ 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) { - int count; - int i; + myArray_t* a = RTTI_OBJ_TO_DATA(myArray_t, obj); + int count; + int i; count = va_arg(ap, int); if (count <= 0) { @@ -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; }