1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-06-16 06:15:24 +00:00

Feature: Implemented simple API refobject_new() and refobject_new_ext()

This commit is contained in:
Philipp Schafft 2018-10-10 14:27:07 +00:00
parent 9f6d3c3018
commit 491c4ab2f4
4 changed files with 96 additions and 23 deletions

View File

@ -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))

View File

@ -17,6 +17,8 @@
#include <config.h>
#endif
#include <stdarg.h>
#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 <stdarg.h> 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);

View File

@ -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));

View File

@ -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);