From 491c4ab2f4641f432f22672786304ab6b6bc2397 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 10 Oct 2018 14:27:07 +0000 Subject: [PATCH] Feature: Implemented simple API refobject_new() and refobject_new_ext() --- src/refobject.c | 38 +++++++++++++++++++++++++- src/refobject.h | 26 ++++++++++++++++-- src/tests/ctest_buffer.c | 2 +- src/tests/ctest_refobject.c | 53 ++++++++++++++++++++++++------------- 4 files changed, 96 insertions(+), 23 deletions(-) diff --git a/src/refobject.c b/src/refobject.c index e232553d..d2abed2e 100644 --- a/src/refobject.c +++ b/src/refobject.c @@ -19,7 +19,15 @@ #define TO_BASE(x) REFOBJECT_TO_TYPE((x), refobject_base_t *) -REFOBJECT_DEFINE_TYPE(refobject_base_t); +static int return_zero(refobject_t self, const refobject_type_t *type, va_list ap) +{ + (void)self, (void)type, (void)ap; + return 0; +} + +REFOBJECT_DEFINE_TYPE(refobject_base_t, + REFOBJECT_DEFINE_TYPE_NEW(return_zero) + ); static inline int check_type(const refobject_type_t *type) { @@ -64,6 +72,34 @@ refobject_t refobject_new__real(const refobject_type_t *type, void *userdata return (refobject_t)ret; } +refobject_t refobject_new__simple(const refobject_type_t *type, void *userdata, const char *name, refobject_t associated, ...) +{ + refobject_t ret; + int res; + va_list ap; + + if (!check_type(type)) + return REFOBJECT_NULL; + + if (!type->type_newcb) + return REFOBJECT_NULL; + + ret = refobject_new__real(type, userdata, name, associated); + if (REFOBJECT_IS_NULL(ret)) + return REFOBJECT_NULL; + + va_start(ap, associated); + res = type->type_newcb(ret, type, ap); + va_end(ap); + + if (res != 0) { + refobject_unref(ret); + return REFOBJECT_NULL; + } + + return ret; +} + int refobject_ref(refobject_t self) { if (REFOBJECT_IS_NULL(self)) diff --git a/src/refobject.h b/src/refobject.h index 7e375e4c..946a78a5 100644 --- a/src/refobject.h +++ b/src/refobject.h @@ -17,6 +17,8 @@ #include #endif +#include + #include "common/thread/thread.h" #include "icecasttypes.h" @@ -69,6 +71,9 @@ static const refobject_type_t refobject_typedef__ ## type = \ #define REFOBJECT_DEFINE_TYPE(type, ...) REFOBJECT_DEFINE_TYPE__RAW(type, ## __VA_ARGS__); const refobject_type_t * refobject_type__ ## type = &refobject_typedef__ ## type #define REFOBJECT_DEFINE_PRIVATE_TYPE(type, ...) REFOBJECT_DEFINE_TYPE__RAW(type, ## __VA_ARGS__); static const refobject_type_t * refobject_type__ ## type = &refobject_typedef__ ## type #define REFOBJECT_DEFINE_TYPE_FREE(cb) .type_freecb = (cb) +#define REFOBJECT_DEFINE_TYPE_NEW(cb) .type_newcb = (cb) + +typedef struct refobject_type_tag refobject_type_t; /* Type used for callback called then the object is actually freed * That is once all references to it are gone. @@ -80,11 +85,23 @@ static const refobject_type_t refobject_typedef__ ## type = \ */ typedef void (*refobject_free_t)(refobject_t self, void **userdata); +/* Type used for callback called then the object is created + * using the generic refobject_new(). + * + * Additional parameters passed to refobject_new() are passed + * in the list ap. All limitations of apply. + * + * This function must return zero in case of success and + * non-zero in case of error. In case of error refobject_unref() + * is called internally to clear the object. + */ +typedef int (*refobject_new_t)(refobject_t self, const refobject_type_t *type, va_list ap); + /* Meta type used to defined types. * DO NOT use any of the members in here directly! */ -typedef struct { +struct refobject_type_tag { /* Size of this control structure */ size_t control_length; /* ABI version of this structure */ @@ -96,7 +113,9 @@ typedef struct { const char * type_name; /* Callback to be called on final free() */ refobject_free_t type_freecb; -} refobject_type_t; + /* Callback to be callback by refobject_new() */ + refobject_new_t type_newcb; +}; /* Only defined here as the size must be publically known. * DO NOT use any of the members in here directly! @@ -124,6 +143,9 @@ REFOBJECT_FORWARD_TYPE(refobject_base_t); */ #define refobject_new__new(type, userdata, name, associated) REFOBJECT_TO_TYPE(refobject_new__real((refobject_type__ ## type), (userdata), (name), (associated)), type*) refobject_t refobject_new__real(const refobject_type_t *type, void *userdata, const char *name, refobject_t associated); +#define refobject_new(type, ...) REFOBJECT_TO_TYPE(refobject_new__simple((refobject_type__ ## type), NULL, NULL, REFOBJECT_NULL, ## __VA_ARGS__), type*) +#define refobject_new_ext(type, userdata, name, associated, ...) REFOBJECT_TO_TYPE(refobject_new__simple((refobject_type__ ## type), (userdata), (name), (associated), ## __VA_ARGS__), type*) +refobject_t refobject_new__simple(const refobject_type_t *type, void *userdata, const char *name, refobject_t associated, ...); /* This increases the reference counter of the object */ int refobject_ref(refobject_t self); diff --git a/src/tests/ctest_buffer.c b/src/tests/ctest_buffer.c index d8158e08..feec0384 100644 --- a/src/tests/ctest_buffer.c +++ b/src/tests/ctest_buffer.c @@ -83,7 +83,7 @@ static void test_associated(void) refobject_base_t *a; buffer_t *b; - a = refobject_new__new(refobject_base_t, NULL, NULL, REFOBJECT_NULL); + a = refobject_new(refobject_base_t); ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); diff --git a/src/tests/ctest_refobject.c b/src/tests/ctest_refobject.c index 734454aa..fbea21f0 100644 --- a/src/tests/ctest_refobject.c +++ b/src/tests/ctest_refobject.c @@ -16,6 +16,12 @@ #include "../refobject.h" +static int return_zero(refobject_t self, const refobject_type_t *type, va_list ap) +{ + (void)self, (void)type, (void)ap; + return 0; +} + static void test_ptr(void) { refobject_t a; @@ -31,7 +37,7 @@ static void test_create_ref_unref(void) { refobject_base_t *a; - a = refobject_new__new(refobject_base_t, NULL, NULL, REFOBJECT_NULL); + a = refobject_new(refobject_base_t); ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ctest_test("referenced", refobject_ref(a) == 0); @@ -44,7 +50,7 @@ static void test_typename(void) refobject_base_t *a; const char *typename; - a = refobject_new__new(refobject_base_t, NULL, NULL, REFOBJECT_NULL); + a = refobject_new(refobject_base_t); ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); typename = REFOBJECT_GET_TYPENAME(a); @@ -66,7 +72,7 @@ static void test_valid(void) ctest_test("NULL is not valid", !REFOBJECT_IS_VALID(REFOBJECT_NULL, refobject_base_t)); - a = refobject_new__new(refobject_base_t, NULL, NULL, REFOBJECT_NULL); + a = refobject_new(refobject_base_t); ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ctest_test("is valid", REFOBJECT_IS_VALID(a, refobject_base_t)); @@ -83,39 +89,47 @@ static void test_sizes(void) refobject_base_t __base; char padding[1024]; } ctest_test_type_a_t; - REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_a_t); + REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_a_t, + REFOBJECT_DEFINE_TYPE_NEW(return_zero) + ); typedef struct { refobject_base_t __base; char padding[131072]; } ctest_test_type_b_t; - REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_b_t); + REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_b_t, + REFOBJECT_DEFINE_TYPE_NEW(return_zero) + ); typedef struct { char padding[sizeof(refobject_base_t) - 1]; } ctest_test_type_c_t; - REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_c_t); + REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_c_t, + REFOBJECT_DEFINE_TYPE_NEW(return_zero) + ); typedef struct { char padding[0]; } ctest_test_type_d_t; - REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_d_t); + REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_d_t, + REFOBJECT_DEFINE_TYPE_NEW(return_zero) + ); - a = REFOBJECT_FROM_TYPE(refobject_new__new(ctest_test_type_a_t, NULL, NULL, REFOBJECT_NULL)); + a = REFOBJECT_FROM_TYPE(refobject_new(ctest_test_type_a_t)); ctest_test("refobject created with size=sizeof(refobject_base_t) + 1024", !REFOBJECT_IS_NULL(a)); ctest_test("un-referenced", refobject_unref(a) == 0); - a = REFOBJECT_FROM_TYPE(refobject_new__new(ctest_test_type_b_t, NULL, NULL, REFOBJECT_NULL)); + a = REFOBJECT_FROM_TYPE(refobject_new(ctest_test_type_b_t)); ctest_test("refobject created with size=sizeof(refobject_base_t) + 131072", !REFOBJECT_IS_NULL(a)); ctest_test("un-referenced", refobject_unref(a) == 0); - a = REFOBJECT_FROM_TYPE(refobject_new__new(ctest_test_type_c_t, NULL, NULL, REFOBJECT_NULL)); + a = REFOBJECT_FROM_TYPE(refobject_new(ctest_test_type_c_t)); ctest_test("refobject created with size=sizeof(refobject_base_t) - 1", REFOBJECT_IS_NULL(a)); if (!REFOBJECT_IS_NULL(a)) { ctest_test("un-referenced", refobject_unref(a) == 0); } - a = REFOBJECT_FROM_TYPE(refobject_new__new(ctest_test_type_d_t, NULL, NULL, REFOBJECT_NULL)); + a = REFOBJECT_FROM_TYPE(refobject_new(ctest_test_type_d_t)); ctest_test("refobject created with size=0", REFOBJECT_IS_NULL(a)); if (!REFOBJECT_IS_NULL(a)) { ctest_test("un-referenced", refobject_unref(a) == 0); @@ -128,7 +142,7 @@ static void test_name(void) const char *name = "test object name"; const char *ret; - a = refobject_new__new(refobject_base_t, NULL, name, REFOBJECT_NULL); + a = refobject_new_ext(refobject_base_t, NULL, name, REFOBJECT_NULL); ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ret = refobject_get_name(a); @@ -145,7 +159,7 @@ static void test_userdata(void) void *userdata = &tmp; void *ret; - a = refobject_new__new(refobject_base_t, NULL, NULL, REFOBJECT_NULL); + a = refobject_new(refobject_base_t); ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ret = refobject_get_userdata(a); @@ -159,7 +173,7 @@ static void test_userdata(void) ctest_test("un-referenced", refobject_unref(a) == 0); - a = refobject_new__new(refobject_base_t, userdata, NULL, REFOBJECT_NULL); + a = refobject_new_ext(refobject_base_t, userdata, NULL, REFOBJECT_NULL); ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ret = refobject_get_userdata(a); ctest_test("get userdata", ret == userdata); @@ -173,10 +187,10 @@ static void test_associated(void) { refobject_base_t *a, *b; - a = refobject_new__new(refobject_base_t, NULL, NULL, REFOBJECT_NULL); + a = refobject_new(refobject_base_t); ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); - b = refobject_new__new(refobject_base_t, NULL, NULL, a); + b = refobject_new_ext(refobject_base_t, NULL, NULL, a); ctest_test("refobject created with associated", !REFOBJECT_IS_NULL(b)); ctest_test("un-referenced (1 of 2)", refobject_unref(b) == 0); @@ -197,17 +211,18 @@ static void test_freecb(void) ctest_test_type_t *a; REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_t, - REFOBJECT_DEFINE_TYPE_FREE(test_freecb__freecb) + REFOBJECT_DEFINE_TYPE_FREE(test_freecb__freecb), + REFOBJECT_DEFINE_TYPE_NEW(return_zero) ); test_freecb__called = 0; - a = refobject_new__new(ctest_test_type_t, NULL, NULL, REFOBJECT_NULL); + a = refobject_new(ctest_test_type_t); ctest_test("refobject created", a != NULL); ctest_test("un-referenced", refobject_unref(REFOBJECT_FROM_TYPE(a)) == 0); ctest_test("freecb called", test_freecb__called == 1); test_freecb__called = 0; - a = refobject_new__new(ctest_test_type_t, NULL, NULL, REFOBJECT_NULL); + a = refobject_new(ctest_test_type_t); ctest_test("refobject created", a != NULL); ctest_test("referenced", refobject_ref(REFOBJECT_FROM_TYPE(a)) == 0); ctest_test("freecb uncalled", test_freecb__called == 0);