1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-12-04 14:46:30 -05:00

Merge branch 'ph3-update-refobject'

This commit is contained in:
Philipp Schafft 2018-10-11 09:37:19 +00:00
commit ed78741e3d
18 changed files with 401 additions and 128 deletions

View File

@ -37,16 +37,18 @@ static void __free(refobject_t self, void **userdata)
free(buffer->buffer); free(buffer->buffer);
} }
REFOBJECT_DEFINE_TYPE(buffer_t,
REFOBJECT_DEFINE_TYPE_FREE(__free),
REFOBJECT_DEFINE_TYPE_NEW_NOOP()
);
buffer_t * buffer_new(ssize_t preallocation, void *userdata, const char *name, refobject_t associated) buffer_t * buffer_new(ssize_t preallocation, void *userdata, const char *name, refobject_t associated)
{ {
buffer_t *buffer = NULL; buffer_t *buffer = refobject_new_ext(buffer_t, userdata, name, associated);
refobject_t refobject = refobject_new(sizeof(*buffer), __free, userdata, name, associated);
if (REFOBJECT_IS_NULL(refobject)) if (!buffer)
return NULL; return NULL;
buffer = REFOBJECT_TO_TYPE(refobject, buffer_t *);
if (preallocation > 0) if (preallocation > 0)
buffer_preallocate(buffer, preallocation); buffer_preallocate(buffer, preallocation);
@ -55,7 +57,7 @@ buffer_t * buffer_new(ssize_t preallocation, void *userdata, const char *name,
buffer_t * buffer_new_simple(void) buffer_t * buffer_new_simple(void)
{ {
return buffer_new(-1, NULL, NULL, REFOBJECT_NULL); return refobject_new(buffer_t);
} }
void buffer_preallocate(buffer_t *buffer, size_t request) void buffer_preallocate(buffer_t *buffer, size_t request)

View File

@ -28,6 +28,8 @@
* This set of functions is intentinally not thread safe. * This set of functions is intentinally not thread safe.
*/ */
REFOBJECT_FORWARD_TYPE(buffer_t);
/* This creates a new buffer object. /* This creates a new buffer object.
* Parameters: * Parameters:
* preallocation * preallocation
@ -37,7 +39,9 @@
*/ */
buffer_t * buffer_new(ssize_t preallocation, void *userdata, const char *name, refobject_t associated); buffer_t * buffer_new(ssize_t preallocation, void *userdata, const char *name, refobject_t associated);
/* This creates a new buffer with defaults. /* Depreciated: This creates a new buffer with defaults.
* Do NOT use this. Use refobject_new(buffer_t)
*
* This is the same as: * This is the same as:
* buffer_new(-1, NULL, NULL, REFOBJECT_NULL) * buffer_new(-1, NULL, NULL, REFOBJECT_NULL)
*/ */

View File

@ -232,7 +232,7 @@ void config_init_configuration(ice_config_t *configuration)
{ {
memset(configuration, 0, sizeof(ice_config_t)); memset(configuration, 0, sizeof(ice_config_t));
_set_defaults(configuration); _set_defaults(configuration);
configuration->reportxml_db = reportxml_database_new(); configuration->reportxml_db = refobject_new(reportxml_database_t);
} }
static inline void __read_int(xmlDocPtr doc, xmlNodePtr node, int *val, const char *warning) static inline void __read_int(xmlDocPtr doc, xmlNodePtr node, int *val, const char *warning)

View File

@ -661,7 +661,7 @@ reportxml_t *client_get_reportxml(const char *state_definition, const char *stat
if (!report) { if (!report) {
reportxml_node_t *rootnode, *incidentnode, *statenode; reportxml_node_t *rootnode, *incidentnode, *statenode;
report = reportxml_new(); report = refobject_new(reportxml_t);
rootnode = reportxml_get_root_node(report); rootnode = reportxml_get_root_node(report);
incidentnode = reportxml_node_new(REPORTXML_NODE_TYPE_INCIDENT, NULL, NULL, NULL); incidentnode = reportxml_node_new(REPORTXML_NODE_TYPE_INCIDENT, NULL, NULL, NULL);
statenode = reportxml_node_new(REPORTXML_NODE_TYPE_STATE, NULL, state_definition, state_akindof); statenode = reportxml_node_new(REPORTXML_NODE_TYPE_STATE, NULL, state_definition, state_akindof);

View File

@ -1703,7 +1703,7 @@ void connection_setup_sockets (ice_config_t *config)
allowed_ip = matchfile_new(config->allowfile); allowed_ip = matchfile_new(config->allowfile);
} }
global.listensockets = listensocket_container_new(); global.listensockets = refobject_new(listensocket_container_t);
listensocket_container_configure(global.listensockets, config); listensocket_container_configure(global.listensockets, config);
global_unlock(); global_unlock();

View File

@ -26,19 +26,19 @@
#ifdef FASTEVENT_ENABLED #ifdef FASTEVENT_ENABLED
struct registration { typedef struct {
refobject_base_t __base; refobject_base_t __base;
fastevent_type_t type; fastevent_type_t type;
fastevent_cb_t cb; fastevent_cb_t cb;
fastevent_freecb_t freecb; fastevent_freecb_t freecb;
void *userdata; void *userdata;
}; } fastevent_registration_t;
struct eventrow { struct eventrow {
size_t length; size_t length;
size_t used; size_t used;
struct registration **registrations; fastevent_registration_t **registrations;
}; };
static struct eventrow fastevent_registrations[FASTEVENT_TYPE__END]; static struct eventrow fastevent_registrations[FASTEVENT_TYPE__END];
@ -54,9 +54,9 @@ static inline struct eventrow * __get_row(fastevent_type_t type)
return &(fastevent_registrations[idx]); return &(fastevent_registrations[idx]);
} }
static int __add_to_row(struct eventrow * row, struct registration *registration) static int __add_to_row(struct eventrow * row, fastevent_registration_t *registration)
{ {
struct registration **n; fastevent_registration_t **n;
if (row == NULL) if (row == NULL)
return -1; return -1;
@ -77,7 +77,7 @@ static int __add_to_row(struct eventrow * row, struct registration *registration
return 0; return 0;
} }
static int __remove_from_row(struct eventrow * row, struct registration *registration) static int __remove_from_row(struct eventrow * row, fastevent_registration_t *registration)
{ {
size_t i; size_t i;
@ -98,7 +98,7 @@ static int __remove_from_row(struct eventrow * row, struct registration *registr
static void __unregister(refobject_t self, void **userdata) static void __unregister(refobject_t self, void **userdata)
{ {
struct registration *registration = REFOBJECT_TO_TYPE(self, struct registration *); fastevent_registration_t *registration = REFOBJECT_TO_TYPE(self, fastevent_registration_t *);
struct eventrow * row; struct eventrow * row;
(void)userdata; (void)userdata;
@ -143,11 +143,14 @@ int fastevent_shutdown(void)
return 0; return 0;
} }
REFOBJECT_DEFINE_PRIVATE_TYPE(fastevent_registration_t,
REFOBJECT_DEFINE_TYPE_FREE(__unregister)
);
refobject_t fastevent_register(fastevent_type_t type, fastevent_cb_t cb, fastevent_freecb_t freecb, void *userdata) refobject_t fastevent_register(fastevent_type_t type, fastevent_cb_t cb, fastevent_freecb_t freecb, void *userdata)
{ {
struct eventrow * row; struct eventrow * row;
struct registration *registration; fastevent_registration_t *registration;
refobject_t ret;
if (cb == NULL) if (cb == NULL)
return REFOBJECT_NULL; return REFOBJECT_NULL;
@ -160,15 +163,13 @@ refobject_t fastevent_register(fastevent_type_t type, fastevent_cb_t cb, fasteve
return REFOBJECT_NULL; return REFOBJECT_NULL;
} }
ret = refobject_new(sizeof(struct registration), __unregister, NULL, NULL, NULL); registration = refobject_new__new(fastevent_registration_t, NULL, NULL, NULL);
if (REFOBJECT_IS_NULL(ret)) { if (!registration) {
thread_rwlock_unlock(&fastevent_lock); thread_rwlock_unlock(&fastevent_lock);
return REFOBJECT_NULL; return REFOBJECT_NULL;
} }
registration = REFOBJECT_TO_TYPE(ret, struct registration *);
registration->type = type; registration->type = type;
registration->cb = cb; registration->cb = cb;
registration->freecb = freecb; registration->freecb = freecb;
@ -176,12 +177,12 @@ refobject_t fastevent_register(fastevent_type_t type, fastevent_cb_t cb, fasteve
if (__add_to_row(row, registration) != 0) { if (__add_to_row(row, registration) != 0) {
thread_rwlock_unlock(&fastevent_lock); thread_rwlock_unlock(&fastevent_lock);
refobject_unref(ret); refobject_unref(REFOBJECT_FROM_TYPE(registration));
return REFOBJECT_NULL; return REFOBJECT_NULL;
} }
thread_rwlock_unlock(&fastevent_lock); thread_rwlock_unlock(&fastevent_lock);
return ret; return REFOBJECT_FROM_TYPE(registration);
} }
void fastevent_emit(fastevent_type_t type, fastevent_flag_t flags, fastevent_datatype_t datatype, ...) void fastevent_emit(fastevent_type_t type, fastevent_flag_t flags, fastevent_datatype_t datatype, ...)

View File

@ -15,7 +15,7 @@
#endif #endif
#include <stdarg.h> #include <stdarg.h>
#include <refobject.h> #include "refobject.h"
typedef enum { typedef enum {
FASTEVENT_TYPE_SLOWEVENT = 0, FASTEVENT_TYPE_SLOWEVENT = 0,

View File

@ -38,7 +38,7 @@ void global_initialize(void)
global.clients = 0; global.clients = 0;
global.sources = 0; global.sources = 0;
global.source_tree = avl_tree_new(source_compare_sources, NULL); global.source_tree = avl_tree_new(source_compare_sources, NULL);
global.modulecontainer = module_container_new(); global.modulecontainer = refobject_new(module_container_t);
thread_mutex_create(&_global_mutex); thread_mutex_create(&_global_mutex);
} }

View File

@ -150,22 +150,25 @@ static void __listensocket_container_free(refobject_t self, void **userdata)
thread_mutex_destroy(&container->lock); thread_mutex_destroy(&container->lock);
} }
listensocket_container_t * listensocket_container_new(void) int __listensocket_container_new(refobject_t self, const refobject_type_t *type, va_list ap)
{ {
listensocket_container_t *self = REFOBJECT_TO_TYPE(refobject_new(sizeof(listensocket_container_t), __listensocket_container_free, NULL, NULL, NULL), listensocket_container_t *); listensocket_container_t *ret = REFOBJECT_TO_TYPE(self, listensocket_container_t*);
if (!self)
return NULL;
self->sock = NULL; ret->sock = NULL;
self->sock_len = 0; ret->sock_len = 0;
self->sockcount_cb = NULL; ret->sockcount_cb = NULL;
self->sockcount_userdata = NULL; ret->sockcount_userdata = NULL;
thread_mutex_create(&self->lock); thread_mutex_create(&ret->lock);
return self; return 0;
} }
REFOBJECT_DEFINE_TYPE(listensocket_container_t,
REFOBJECT_DEFINE_TYPE_FREE(__listensocket_container_free),
REFOBJECT_DEFINE_TYPE_NEW(__listensocket_container_new)
);
static inline void __find_matching_entry(listensocket_container_t *self, const listener_t *listener, listensocket_t ***found, int **ref) static inline void __find_matching_entry(listensocket_container_t *self, const listener_t *listener, listensocket_t ***found, int **ref)
{ {
const listener_t *b; const listener_t *b;
@ -527,13 +530,17 @@ static void __listensocket_free(refobject_t self, void **userdata)
thread_mutex_destroy(&listensocket->lock); thread_mutex_destroy(&listensocket->lock);
} }
REFOBJECT_DEFINE_TYPE(listensocket_t,
REFOBJECT_DEFINE_TYPE_FREE(__listensocket_free)
);
static listensocket_t * listensocket_new(const listener_t *listener) { static listensocket_t * listensocket_new(const listener_t *listener) {
listensocket_t *self; listensocket_t *self;
if (listener == NULL) if (listener == NULL)
return NULL; return NULL;
self = REFOBJECT_TO_TYPE(refobject_new(sizeof(listensocket_t), __listensocket_free, NULL, NULL, NULL), listensocket_t *); self = refobject_new__new(listensocket_t, NULL, NULL, NULL);
if (!self) if (!self)
return NULL; return NULL;

View File

@ -10,8 +10,11 @@
#define __LISTENSOCKET_H__ #define __LISTENSOCKET_H__
#include "icecasttypes.h" #include "icecasttypes.h"
#include "refobject.h"
#include "cfgfile.h" #include "cfgfile.h"
REFOBJECT_FORWARD_TYPE(listensocket_container_t);
listensocket_container_t * listensocket_container_new(void); listensocket_container_t * listensocket_container_new(void);
int listensocket_container_configure(listensocket_container_t *self, const ice_config_t *config); int listensocket_container_configure(listensocket_container_t *self, const ice_config_t *config);
int listensocket_container_configure_and_setup(listensocket_container_t *self, const ice_config_t *config); int listensocket_container_configure_and_setup(listensocket_container_t *self, const ice_config_t *config);
@ -20,6 +23,8 @@ connection_t * listensocket_container_accept(listensocket_container
int listensocket_container_set_sockcount_cb(listensocket_container_t *self, void (*cb)(size_t count, void *userdata), void *userdata); int listensocket_container_set_sockcount_cb(listensocket_container_t *self, void (*cb)(size_t count, void *userdata), void *userdata);
ssize_t listensocket_container_sockcount(listensocket_container_t *self); ssize_t listensocket_container_sockcount(listensocket_container_t *self);
REFOBJECT_FORWARD_TYPE(listensocket_t);
int listensocket_refsock(listensocket_t *self); int listensocket_refsock(listensocket_t *self);
int listensocket_unrefsock(listensocket_t *self); int listensocket_unrefsock(listensocket_t *self);
connection_t * listensocket_accept(listensocket_t *self, listensocket_container_t *container); connection_t * listensocket_accept(listensocket_t *self, listensocket_container_t *container);

View File

@ -50,20 +50,22 @@ static void __module_container_free(refobject_t self, void **userdata)
avl_tree_free(cont->module, (avl_free_key_fun_type)refobject_unref); avl_tree_free(cont->module, (avl_free_key_fun_type)refobject_unref);
} }
module_container_t * module_container_new(void) int __module_container_new(refobject_t self, const refobject_type_t *type, va_list ap)
{ {
module_container_t *ret = REFOBJECT_TO_TYPE(refobject_new(sizeof(module_container_t), __module_container_free, NULL, NULL, NULL), module_container_t *); module_container_t *ret = REFOBJECT_TO_TYPE(self, module_container_t*);
if (!ret)
return NULL;
thread_mutex_create(&(ret->lock)); thread_mutex_create(&(ret->lock));
ret->module = avl_tree_new(compare_refobject_t_name, NULL); ret->module = avl_tree_new(compare_refobject_t_name, NULL);
return ret; return 0;
} }
REFOBJECT_DEFINE_TYPE(module_container_t,
REFOBJECT_DEFINE_TYPE_FREE(__module_container_free),
REFOBJECT_DEFINE_TYPE_NEW(__module_container_new)
);
int module_container_add_module(module_container_t *self, module_t *module) int module_container_add_module(module_container_t *self, module_t *module)
{ {
if (!self) if (!self)
@ -101,13 +103,13 @@ int module_container_delete_module(module_container_t *self,
module_t * module_container_get_module(module_container_t *self, const char *name) module_t * module_container_get_module(module_container_t *self, const char *name)
{ {
refobject_t search; refobject_base_t *search;
module_t *ret; module_t *ret;
if (!self || !name) if (!self || !name)
return NULL; return NULL;
search = refobject_new(sizeof(refobject_base_t), NULL, NULL, name, NULL); search = refobject_new__new(refobject_base_t, NULL, name, NULL);
thread_mutex_lock(&(self->lock)); thread_mutex_lock(&(self->lock));
if (avl_get_by_key(self->module, REFOBJECT_TO_TYPE(search, void *), (void**)&ret) != 0) { if (avl_get_by_key(self->module, REFOBJECT_TO_TYPE(search, void *), (void**)&ret) != 0) {
@ -168,9 +170,13 @@ static void __module_free(refobject_t self, void **userdata)
thread_mutex_destroy(&(mod->lock)); thread_mutex_destroy(&(mod->lock));
} }
REFOBJECT_DEFINE_TYPE(module_t,
REFOBJECT_DEFINE_TYPE_FREE(__module_free)
);
module_t * module_new(const char *name, module_setup_handler_t newcb, module_setup_handler_t freecb, void *userdata) module_t * module_new(const char *name, module_setup_handler_t newcb, module_setup_handler_t freecb, void *userdata)
{ {
module_t *ret = REFOBJECT_TO_TYPE(refobject_new(sizeof(module_t), __module_free, NULL, name, NULL), module_t *); module_t *ret = refobject_new__new(module_t, NULL, name, NULL);
if (!ret) if (!ret)
return NULL; return NULL;

View File

@ -12,6 +12,7 @@
#include <libxml/tree.h> #include <libxml/tree.h>
#include "icecasttypes.h" #include "icecasttypes.h"
#include "refobject.h"
typedef void (*module_client_handler_function_t)(module_t *self, client_t *client); typedef void (*module_client_handler_function_t)(module_t *self, client_t *client);
typedef int (*module_setup_handler_t)(module_t *self, void **userdata); typedef int (*module_setup_handler_t)(module_t *self, void **userdata);
@ -21,7 +22,9 @@ typedef struct {
module_client_handler_function_t cb; module_client_handler_function_t cb;
} module_client_handler_t; } module_client_handler_t;
module_container_t * module_container_new(void); REFOBJECT_FORWARD_TYPE(module_container_t);
REFOBJECT_FORWARD_TYPE(module_t);
int module_container_add_module(module_container_t *self, module_t *module); int module_container_add_module(module_container_t *self, module_t *module);
int module_container_delete_module(module_container_t *self, const char *name); int module_container_delete_module(module_container_t *self, const char *name);
module_t * module_container_get_module(module_container_t *self, const char *name); module_t * module_container_get_module(module_container_t *self, const char *name);

View File

@ -19,19 +19,35 @@
#define TO_BASE(x) REFOBJECT_TO_TYPE((x), refobject_base_t *) #define TO_BASE(x) REFOBJECT_TO_TYPE((x), refobject_base_t *)
refobject_t refobject_new(size_t len, refobject_free_t freecb, void *userdata, const char *name, refobject_t associated) int refobject_new__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_NOOP()
);
static inline int check_type(const refobject_type_t *type)
{
return type->control_length == sizeof(refobject_type_t) && type->control_version == REFOBJECT_CONTROL_VERSION &&
type->type_length >= sizeof(refobject_base_t);
}
refobject_t refobject_new__real(const refobject_type_t *type, void *userdata, const char *name, refobject_t associated)
{ {
refobject_base_t *ret = NULL; refobject_base_t *ret = NULL;
if (len < sizeof(refobject_base_t)) if (!check_type(type))
return (refobject_t)ret; return (refobject_t)ret;
ret = calloc(1, len); ret = calloc(1, type->type_length);
if (ret == NULL) if (ret == NULL)
return (refobject_t)ret; return (refobject_t)ret;
ret->type = type;
ret->refc = 1; ret->refc = 1;
ret->freecb = freecb;
ret->userdata = userdata; ret->userdata = userdata;
thread_mutex_create(&(ret->lock)); thread_mutex_create(&(ret->lock));
@ -56,6 +72,34 @@ refobject_t refobject_new(size_t len, refobject_free_t freecb, void *userdat
return (refobject_t)ret; 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) int refobject_ref(refobject_t self)
{ {
if (REFOBJECT_IS_NULL(self)) if (REFOBJECT_IS_NULL(self))
@ -82,8 +126,8 @@ int refobject_unref(refobject_t self)
return 0; return 0;
} }
if (base->freecb) if (base->type->type_freecb)
base->freecb(self, &(base->userdata)); base->type->type_freecb(self, &(base->userdata));
if (base->userdata) if (base->userdata)
free(base->userdata); free(base->userdata);

View File

@ -17,6 +17,8 @@
#include <config.h> #include <config.h>
#endif #endif
#include <stdarg.h>
#include "common/thread/thread.h" #include "common/thread/thread.h"
#include "icecasttypes.h" #include "icecasttypes.h"
@ -35,17 +37,82 @@
* as the operation is only defined for it's members. * as the operation is only defined for it's members.
* REFOBJECT_TO_TYPE(type,x) * REFOBJECT_TO_TYPE(type,x)
* This casts the refobject (x) to the type (type). * This casts the refobject (x) to the type (type).
* REFOBJECT_FROM_TYPE(x)
* Converts an object to a (refobject_t). This is the inverse of REFOBJECT_TO_TYPE().
* REFOBJECT_GET_TYPENAME(x)
* Get the name of the type of the object.
* REFOBJECT_IS_VALID(x,type)
* This returns true if x is not NULL and of type type.
* REFOBJECT_GET_BASE(x)
* REFOBJECT_GET_TYPE(x)
* Not to be used by the user.
*/ */
#ifdef HAVE_TYPE_ATTRIBUTE_TRANSPARENT_UNION #ifdef HAVE_TYPE_ATTRIBUTE_TRANSPARENT_UNION
#define REFOBJECT_NULL ((refobject_t)(refobject_base_t*)NULL) #define REFOBJECT_NULL ((refobject_t)(refobject_base_t*)NULL)
#define REFOBJECT_GET_BASE(x) (((refobject_t)(x)).refobject_base)
#define REFOBJECT_IS_NULL(x) (((refobject_t)(x)).refobject_base == NULL) #define REFOBJECT_IS_NULL(x) (((refobject_t)(x)).refobject_base == NULL)
#define REFOBJECT_TO_TYPE(x,y) ((y)(((refobject_t)(x)).refobject_base)) #define REFOBJECT_TO_TYPE(x,y) ((y)(((refobject_t)(x)).refobject_base))
#else #else
#define REFOBJECT_NULL NULL #define REFOBJECT_NULL NULL
#define REFOBJECT_GET_BASE(x) ((refobject_base_t)(x))
#define REFOBJECT_IS_NULL(x) ((x) == NULL) #define REFOBJECT_IS_NULL(x) ((x) == NULL)
#define REFOBJECT_TO_TYPE(x,y) ((y)(x)) #define REFOBJECT_TO_TYPE(x,y) ((y)(x))
#endif #endif
#define REFOBJECT_FROM_TYPE(x) ((refobject_t)(refobject_base_t*)(x))
#define REFOBJECT_GET_TYPE(x) (REFOBJECT_GET_BASE((x)) == NULL ? NULL : REFOBJECT_GET_BASE((x))->type)
#define REFOBJECT_GET_TYPENAME(x) (REFOBJECT_GET_TYPE((x)) == NULL ? NULL : REFOBJECT_GET_TYPE((x))->type_name)
#define REFOBJECT_IS_VALID(x,type) (!REFOBJECT_IS_NULL((x)) && REFOBJECT_GET_TYPE((x)) == (refobject_type__ ## type))
/* The following macros are used to define types.
*
* REFOBJECT_FORWARD_TYPE(type)
* Adds a forward decleration for the type. This is useful for non private types.
* REFOBJECT_DEFINE_TYPE(type,extras...)
* This defines a public type. One or more of the EXTRA macros be used.
* REFOBJECT_DEFINE_PRIVATE_TYPE(type,extras...)
* Same as REFOBJECT_DEFINE_TYPE() but defines private type.
*
* EXTRA Marcos:
* REFOBJECT_DEFINE_TYPE_FREE(cb)
* This defines a callback to be called when the object is freed.
* cb must be of type refobject_free_t.
* REFOBJECT_DEFINE_TYPE_NEW(cb)
* This defines a callback to be called when a new object is created.
* cb must be of type refobject_new_t.
* REFOBJECT_DEFINE_TYPE_NEW_NOOP()
* This installs a dummy callback for creation. This allows the type
* to be created using refobject_new(type) as with REFOBJECT_DEFINE_TYPE_NEW().
* This is useful for types that do not need to be initialized more than what
* refobject_new() already does.
*
* Other Macros:
* REFOBJECT_CONTROL_VERSION
* REFOBJECT_DEFINE_TYPE__RAW()
* Not to be used by the user.
*/
#define REFOBJECT_CONTROL_VERSION 1
#define REFOBJECT_FORWARD_TYPE(type) extern const refobject_type_t * refobject_type__ ## type;
#define REFOBJECT_DEFINE_TYPE__RAW(type, ...) \
static const refobject_type_t refobject_typedef__ ## type = \
{ \
.control_length = sizeof(refobject_type_t), \
.control_version = REFOBJECT_CONTROL_VERSION, \
.type_length = sizeof(type), \
.type_name = # type \
, ## __VA_ARGS__ \
}
#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)
#define REFOBJECT_DEFINE_TYPE_NEW_NOOP() .type_newcb = refobject_new__return_zero
typedef struct refobject_type_tag refobject_type_t;
int refobject_new__return_zero(refobject_t self, const refobject_type_t *type, va_list ap);
/* Type used for callback called then the object is actually freed /* Type used for callback called then the object is actually freed
* That is once all references to it are gone. * That is once all references to it are gone.
* *
@ -56,18 +123,52 @@
*/ */
typedef void (*refobject_free_t)(refobject_t self, void **userdata); 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!
*/
struct refobject_type_tag {
/* Size of this control structure */
size_t control_length;
/* ABI version of this structure */
int control_version;
/* Total length of the objects to be created */
size_t type_length;
/* Name of type */
const char * type_name;
/* Callback to be called on final free() */
refobject_free_t type_freecb;
/* Callback to be callback by refobject_new() */
refobject_new_t type_newcb;
};
/* Only defined here as the size must be publically known. /* Only defined here as the size must be publically known.
* DO NOT use any of the members in here directly! * DO NOT use any of the members in here directly!
*/ */
struct refobject_base_tag { struct refobject_base_tag {
const refobject_type_t* type;
size_t refc; size_t refc;
mutex_t lock; mutex_t lock;
void *userdata; void *userdata;
refobject_free_t freecb;
char *name; char *name;
refobject_t associated; refobject_t associated;
}; };
REFOBJECT_FORWARD_TYPE(refobject_base_t);
/* Create a new refobject /* Create a new refobject
* The total length of the new object is given by len (see malloc(3)), * The total length of the new object is given by len (see malloc(3)),
* the callback called on free is given by freecb (see refobject_free_t above), * the callback called on free is given by freecb (see refobject_free_t above),
@ -78,7 +179,11 @@ struct refobject_base_tag {
* All parameters beside len are optional and can be NULL/REFOBJECT_NULL. * All parameters beside len are optional and can be NULL/REFOBJECT_NULL.
* If no freecb is given the userdata is freed (see refobject_free_t above). * If no freecb is given the userdata is freed (see refobject_free_t above).
*/ */
refobject_t refobject_new(size_t len, refobject_free_t freecb, void *userdata, const char *name, refobject_t associated); #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 */ /* This increases the reference counter of the object */
int refobject_ref(refobject_t self); int refobject_ref(refobject_t self);

View File

@ -236,6 +236,24 @@ static void __report_free(refobject_t self, void **userdata)
refobject_unref(report->root); refobject_unref(report->root);
} }
static int __report_new(refobject_t self, const refobject_type_t *type, va_list ap)
{
reportxml_t *ret = REFOBJECT_TO_TYPE(self, reportxml_t*);
reportxml_node_t *root = reportxml_node_new(REPORTXML_NODE_TYPE_REPORT, NULL, NULL, NULL);
if (!root)
return -1;
ret->root = root;
return 0;
}
REFOBJECT_DEFINE_TYPE(reportxml_t,
REFOBJECT_DEFINE_TYPE_FREE(__report_free),
REFOBJECT_DEFINE_TYPE_NEW(__report_new)
);
static reportxml_t * reportxml_new_with_root(reportxml_node_t *root) static reportxml_t * reportxml_new_with_root(reportxml_node_t *root)
{ {
reportxml_t *ret; reportxml_t *ret;
@ -243,7 +261,7 @@ static reportxml_t * reportxml_new_with_root(reportxml_node_t *root)
if (!root) if (!root)
return NULL; return NULL;
ret = REFOBJECT_TO_TYPE(refobject_new(sizeof(reportxml_t), __report_free, NULL, NULL, NULL), reportxml_t *); ret = refobject_new__new(reportxml_t, NULL, NULL, NULL);
ret->root = root; ret->root = root;
return ret; return ret;
@ -251,20 +269,7 @@ static reportxml_t * reportxml_new_with_root(reportxml_node_t *root)
reportxml_t * reportxml_new(void) reportxml_t * reportxml_new(void)
{ {
reportxml_node_t *root = reportxml_node_new(REPORTXML_NODE_TYPE_REPORT, NULL, NULL, NULL); return refobject_new(reportxml_t);
reportxml_t *ret;
if (!root)
return NULL;
ret = reportxml_new_with_root(root);
if (!ret) {
refobject_unref(root);
return NULL;
}
return ret;
} }
reportxml_node_t * reportxml_get_root_node(reportxml_t *report) reportxml_node_t * reportxml_get_root_node(reportxml_t *report)
@ -368,6 +373,10 @@ static void __report_node_free(refobject_t self, void **userdata)
free(node->xml_childs); free(node->xml_childs);
} }
REFOBJECT_DEFINE_TYPE(reportxml_node_t,
REFOBJECT_DEFINE_TYPE_FREE(__report_node_free)
);
reportxml_node_t * reportxml_node_new(reportxml_node_type_t type, const char *id, const char *definition, const char *akindof) reportxml_node_t * reportxml_node_new(reportxml_node_type_t type, const char *id, const char *definition, const char *akindof)
{ {
reportxml_node_t *ret; reportxml_node_t *ret;
@ -377,7 +386,7 @@ reportxml_node_t * reportxml_node_new(reportxml_node_type_t type, const cha
if (!nodedef) if (!nodedef)
return NULL; return NULL;
ret = REFOBJECT_TO_TYPE(refobject_new(sizeof(reportxml_node_t), __report_node_free, NULL, NULL, NULL), reportxml_node_t *); ret = refobject_new__new(reportxml_node_t, NULL, NULL, NULL);
if (ret == NULL) if (ret == NULL)
return NULL; return NULL;
@ -975,22 +984,27 @@ static int __compare_definitions(void *arg, void *a, void *b)
return ret; return ret;
} }
reportxml_database_t * reportxml_database_new(void) static int __database_new(refobject_t self, const refobject_type_t *type, va_list ap)
{ {
reportxml_database_t *ret = REFOBJECT_TO_TYPE(refobject_new(sizeof(reportxml_database_t), __database_free, NULL, NULL, NULL), reportxml_database_t *); reportxml_database_t *ret = REFOBJECT_TO_TYPE(self, reportxml_database_t*);
if (!ret)
return NULL;
ret->definitions = avl_tree_new(__compare_definitions, NULL);
if (!ret->definitions) {
refobject_unref(ret);
return NULL;
}
thread_mutex_create(&(ret->lock)); thread_mutex_create(&(ret->lock));
return ret; ret->definitions = avl_tree_new(__compare_definitions, NULL);
if (!ret->definitions)
return -1;
return 0;
}
REFOBJECT_DEFINE_TYPE(reportxml_database_t,
REFOBJECT_DEFINE_TYPE_FREE(__database_free),
REFOBJECT_DEFINE_TYPE_NEW(__database_new)
);
reportxml_database_t * reportxml_database_new(void)
{
return refobject_new(reportxml_database_t);
} }
int reportxml_database_add_report(reportxml_database_t *db, reportxml_t *report) int reportxml_database_add_report(reportxml_database_t *db, reportxml_t *report)
@ -1293,7 +1307,7 @@ reportxml_t * reportxml_database_build_report(reportxml_database_t *db
/* Empty definition? Not exactly an exciting report... */ /* Empty definition? Not exactly an exciting report... */
ICECAST_LOG_WARN("Empty definition for \"%H\". Returning empty report. This is likely an error.", id); ICECAST_LOG_WARN("Empty definition for \"%H\". Returning empty report. This is likely an error.", id);
refobject_unref(definition); refobject_unref(definition);
return reportxml_new(); return refobject_new(reportxml_t);
} }
if (type == REPORTXML_NODE_TYPE__ERROR) { if (type == REPORTXML_NODE_TYPE__ERROR) {
@ -1321,7 +1335,7 @@ reportxml_t * reportxml_database_build_report(reportxml_database_t *db
break; break;
} }
ret = reportxml_new(); ret = refobject_new(reportxml_t);
if (!ret) { if (!ret) {
refobject_unref(definition); refobject_unref(definition);
ICECAST_LOG_ERROR("Can not allocate new report. BAD."); ICECAST_LOG_ERROR("Can not allocate new report. BAD.");

View File

@ -15,6 +15,7 @@
#include "icecasttypes.h" #include "icecasttypes.h"
#include "compat.h" #include "compat.h"
#include "refobject.h"
/* XML Tag Types /* XML Tag Types
* While a hint of what the nodes are used for is given, see the specification for more details. * While a hint of what the nodes are used for is given, see the specification for more details.
@ -60,12 +61,16 @@ typedef enum {
REPORTXML_NODE_TYPE_EXTENSION REPORTXML_NODE_TYPE_EXTENSION
} reportxml_node_type_t; } reportxml_node_type_t;
REFOBJECT_FORWARD_TYPE(reportxml_t);
REFOBJECT_FORWARD_TYPE(reportxml_node_t);
REFOBJECT_FORWARD_TYPE(reportxml_database_t);
/* ---[ Document level ]--- */ /* ---[ Document level ]--- */
/* The document object is NOT thread safe. */ /* The document object is NOT thread safe. */
/* Depreciated: This creates a new, empty report XML document
/* This creates a new, empty report XML document */ * Do NOT use this. Use refobject_new(reportxml_t)
*/
reportxml_t * reportxml_new(void); reportxml_t * reportxml_new(void);
/* This gets the root node of a report XML document */ /* This gets the root node of a report XML document */
reportxml_node_t * reportxml_get_root_node(reportxml_t *report); reportxml_node_t * reportxml_get_root_node(reportxml_t *report);
@ -125,7 +130,9 @@ xmlNodePtr reportxml_node_get_xml_child(reportxml_node_t *node, siz
/* The database object is thread safe. */ /* The database object is thread safe. */
/* Create a new database object */ /* Depreciated: Create a new database object
* Do NOT use this. Use refobject_new(reportxml_database_t)
*/
reportxml_database_t * reportxml_database_new(void); reportxml_database_t * reportxml_database_new(void);
/* Add an report to the database */ /* Add an report to the database */
int reportxml_database_add_report(reportxml_database_t *db, reportxml_t *report); int reportxml_database_add_report(reportxml_database_t *db, reportxml_t *report);

View File

@ -25,7 +25,7 @@ static void test_create_ref_unref(void)
ctest_test("buffer created", a != NULL); ctest_test("buffer created", a != NULL);
ctest_test("un-referenced", refobject_unref(a) == 0); ctest_test("un-referenced", refobject_unref(a) == 0);
a = buffer_new_simple(); a = refobject_new(buffer_t);
ctest_test("buffer created", a != NULL); ctest_test("buffer created", a != NULL);
ctest_test("un-referenced", refobject_unref(a) == 0); ctest_test("un-referenced", refobject_unref(a) == 0);
@ -80,10 +80,10 @@ static void test_userdata(void)
static void test_associated(void) static void test_associated(void)
{ {
refobject_t a; refobject_base_t *a;
buffer_t *b; buffer_t *b;
a = refobject_new(sizeof(refobject_base_t), NULL, NULL, NULL, REFOBJECT_NULL); a = refobject_new(refobject_base_t);
ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ctest_test("refobject created", !REFOBJECT_IS_NULL(a));
@ -102,7 +102,7 @@ static void test_empty(void)
const char *string; const char *string;
int ret; int ret;
a = buffer_new_simple(); a = refobject_new(buffer_t);
ctest_test("buffer created", a != NULL); ctest_test("buffer created", a != NULL);
ret = buffer_get_data(a, &data, &length); ret = buffer_get_data(a, &data, &length);
@ -147,7 +147,7 @@ static void test_string(void)
const char *string = NULL; const char *string = NULL;
int ret; int ret;
a = buffer_new_simple(); a = refobject_new(buffer_t);
ctest_test("buffer created", a != NULL); ctest_test("buffer created", a != NULL);
ctest_test("pushed string", buffer_push_string(a, hw) == 0); ctest_test("pushed string", buffer_push_string(a, hw) == 0);
ret = buffer_get_string(a, &string); ret = buffer_get_string(a, &string);
@ -182,7 +182,7 @@ static void test_binary(void)
size_t length; size_t length;
const void *data; const void *data;
a = buffer_new_simple(); a = refobject_new(buffer_t);
ctest_test("buffer created", a != NULL); ctest_test("buffer created", a != NULL);
ctest_test("pushed data pattern a", buffer_push_data(a, pattern_a, sizeof(pattern_a)) == 0); ctest_test("pushed data pattern a", buffer_push_data(a, pattern_a, sizeof(pattern_a)) == 0);
@ -238,7 +238,7 @@ static void test_shift(void)
buffer_t *a; buffer_t *a;
const char *pattern = "AABBBCC"; const char *pattern = "AABBBCC";
a = buffer_new_simple(); a = refobject_new(buffer_t);
ctest_test("buffer created", a != NULL); ctest_test("buffer created", a != NULL);
ctest_test("pushed string", buffer_push_string(a, pattern) == 0); ctest_test("pushed string", buffer_push_string(a, pattern) == 0);
@ -264,7 +264,7 @@ static void test_length(void)
const char *match_b = "AABB"; const char *match_b = "AABB";
const char *match_c = ""; const char *match_c = "";
a = buffer_new_simple(); a = refobject_new(buffer_t);
ctest_test("buffer created", a != NULL); ctest_test("buffer created", a != NULL);
ctest_test("pushed string", buffer_push_string(a, pattern) == 0); ctest_test("pushed string", buffer_push_string(a, pattern) == 0);
@ -290,7 +290,7 @@ static void test_printf(void)
const char *match_b = ":Hello World!:<-127 >"; const char *match_b = ":Hello World!:<-127 >";
const char *match_c = ":Hello World!:<-127 >? +127?"; const char *match_c = ":Hello World!:<-127 >? +127?";
a = buffer_new_simple(); a = refobject_new(buffer_t);
ctest_test("buffer created", a != NULL); ctest_test("buffer created", a != NULL);
ctest_test("Set length to match pattern a", buffer_push_printf(a, ":%s:", str) == 0); ctest_test("Set length to match pattern a", buffer_push_printf(a, ":%s:", str) == 0);
@ -310,9 +310,9 @@ static void test_push_buffer(void)
const char *pattern = "AABBBCC"; const char *pattern = "AABBBCC";
const char *match_a = "AABBBCCAABBBCC"; const char *match_a = "AABBBCCAABBBCC";
a = buffer_new_simple(); a = refobject_new(buffer_t);
ctest_test("buffer a created", a != NULL); ctest_test("buffer a created", a != NULL);
b = buffer_new_simple(); b = refobject_new(buffer_t);
ctest_test("buffer b created", b != NULL); ctest_test("buffer b created", b != NULL);
ctest_test("pushed string", buffer_push_string(a, pattern) == 0); ctest_test("pushed string", buffer_push_string(a, pattern) == 0);

View File

@ -29,9 +29,9 @@ static void test_ptr(void)
static void test_create_ref_unref(void) static void test_create_ref_unref(void)
{ {
refobject_t a; refobject_base_t *a;
a = refobject_new(sizeof(refobject_base_t), NULL, NULL, NULL, REFOBJECT_NULL); a = refobject_new(refobject_base_t);
ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ctest_test("refobject created", !REFOBJECT_IS_NULL(a));
ctest_test("referenced", refobject_ref(a) == 0); ctest_test("referenced", refobject_ref(a) == 0);
@ -39,27 +39,91 @@ static void test_create_ref_unref(void)
ctest_test("un-referenced (2 of 2)", refobject_unref(a) == 0); ctest_test("un-referenced (2 of 2)", refobject_unref(a) == 0);
} }
static void test_typename(void)
{
refobject_base_t *a;
const char *typename;
a = refobject_new(refobject_base_t);
ctest_test("refobject created", !REFOBJECT_IS_NULL(a));
typename = REFOBJECT_GET_TYPENAME(a);
ctest_test("got typename", typename != NULL);
ctest_test("typename matches", strcmp(typename, "refobject_base_t") == 0);
ctest_test("un-referenced", refobject_unref(a) == 0);
}
static void test_valid(void)
{
refobject_base_t *a;
typedef struct {
refobject_base_t __base;
} ctest_test_type_t;
REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_t);
ctest_test("NULL is not valid", !REFOBJECT_IS_VALID(REFOBJECT_NULL, refobject_base_t));
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));
ctest_test("is valid as diffrent type", !REFOBJECT_IS_VALID(a, ctest_test_type_t));
ctest_test("un-referenced", refobject_unref(a) == 0);
}
static void test_sizes(void) static void test_sizes(void)
{ {
refobject_t a; refobject_t a;
a = refobject_new(sizeof(refobject_base_t) + 1024, NULL, NULL, NULL, REFOBJECT_NULL); typedef struct {
refobject_base_t __base;
char padding[1024];
} ctest_test_type_a_t;
REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_a_t,
REFOBJECT_DEFINE_TYPE_NEW_NOOP()
);
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_TYPE_NEW_NOOP()
);
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_TYPE_NEW_NOOP()
);
typedef struct {
char padding[0];
} ctest_test_type_d_t;
REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_d_t,
REFOBJECT_DEFINE_TYPE_NEW_NOOP()
);
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("refobject created with size=sizeof(refobject_base_t) + 1024", !REFOBJECT_IS_NULL(a));
ctest_test("un-referenced", refobject_unref(a) == 0); ctest_test("un-referenced", refobject_unref(a) == 0);
a = refobject_new(sizeof(refobject_base_t) + 131072, NULL, 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("refobject created with size=sizeof(refobject_base_t) + 131072", !REFOBJECT_IS_NULL(a));
ctest_test("un-referenced", refobject_unref(a) == 0); ctest_test("un-referenced", refobject_unref(a) == 0);
if (sizeof(refobject_base_t) >= 1) { a = REFOBJECT_FROM_TYPE(refobject_new(ctest_test_type_c_t));
a = refobject_new(sizeof(refobject_base_t) - 1, NULL, NULL, NULL, REFOBJECT_NULL);
ctest_test("refobject created with size=sizeof(refobject_base_t) - 1", REFOBJECT_IS_NULL(a)); ctest_test("refobject created with size=sizeof(refobject_base_t) - 1", REFOBJECT_IS_NULL(a));
if (!REFOBJECT_IS_NULL(a)) { if (!REFOBJECT_IS_NULL(a)) {
ctest_test("un-referenced", refobject_unref(a) == 0); ctest_test("un-referenced", refobject_unref(a) == 0);
} }
}
a = refobject_new(0, NULL, 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)); ctest_test("refobject created with size=0", REFOBJECT_IS_NULL(a));
if (!REFOBJECT_IS_NULL(a)) { if (!REFOBJECT_IS_NULL(a)) {
ctest_test("un-referenced", refobject_unref(a) == 0); ctest_test("un-referenced", refobject_unref(a) == 0);
@ -68,11 +132,11 @@ static void test_sizes(void)
static void test_name(void) static void test_name(void)
{ {
refobject_t a; refobject_base_t *a;
const char *name = "test object name"; const char *name = "test object name";
const char *ret; const char *ret;
a = refobject_new(sizeof(refobject_base_t), NULL, NULL, name, REFOBJECT_NULL); a = refobject_new_ext(refobject_base_t, NULL, name, REFOBJECT_NULL);
ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ctest_test("refobject created", !REFOBJECT_IS_NULL(a));
ret = refobject_get_name(a); ret = refobject_get_name(a);
@ -84,12 +148,12 @@ static void test_name(void)
static void test_userdata(void) static void test_userdata(void)
{ {
refobject_t a; refobject_base_t *a;
int tmp = 0; int tmp = 0;
void *userdata = &tmp; void *userdata = &tmp;
void *ret; void *ret;
a = refobject_new(sizeof(refobject_base_t), NULL, NULL, NULL, REFOBJECT_NULL); a = refobject_new(refobject_base_t);
ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ctest_test("refobject created", !REFOBJECT_IS_NULL(a));
ret = refobject_get_userdata(a); ret = refobject_get_userdata(a);
@ -103,7 +167,7 @@ static void test_userdata(void)
ctest_test("un-referenced", refobject_unref(a) == 0); ctest_test("un-referenced", refobject_unref(a) == 0);
a = refobject_new(sizeof(refobject_base_t), NULL, userdata, NULL, REFOBJECT_NULL); a = refobject_new_ext(refobject_base_t, userdata, NULL, REFOBJECT_NULL);
ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ctest_test("refobject created", !REFOBJECT_IS_NULL(a));
ret = refobject_get_userdata(a); ret = refobject_get_userdata(a);
ctest_test("get userdata", ret == userdata); ctest_test("get userdata", ret == userdata);
@ -115,12 +179,12 @@ static void test_userdata(void)
static void test_associated(void) static void test_associated(void)
{ {
refobject_t a, b; refobject_base_t *a, *b;
a = refobject_new(sizeof(refobject_base_t), NULL, NULL, NULL, REFOBJECT_NULL); a = refobject_new(refobject_base_t);
ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ctest_test("refobject created", !REFOBJECT_IS_NULL(a));
b = refobject_new(sizeof(refobject_base_t), NULL, 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("refobject created with associated", !REFOBJECT_IS_NULL(b));
ctest_test("un-referenced (1 of 2)", refobject_unref(b) == 0); ctest_test("un-referenced (1 of 2)", refobject_unref(b) == 0);
@ -135,22 +199,30 @@ static void test_freecb__freecb(refobject_t self, void **userdata)
static void test_freecb(void) static void test_freecb(void)
{ {
refobject_t a; typedef struct {
refobject_base_t __base;
} ctest_test_type_t;
ctest_test_type_t *a;
REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_t,
REFOBJECT_DEFINE_TYPE_FREE(test_freecb__freecb),
REFOBJECT_DEFINE_TYPE_NEW_NOOP()
);
test_freecb__called = 0; test_freecb__called = 0;
a = refobject_new(sizeof(refobject_base_t), test_freecb__freecb, NULL, NULL, REFOBJECT_NULL); a = refobject_new(ctest_test_type_t);
ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ctest_test("refobject created", a != NULL);
ctest_test("un-referenced", refobject_unref(a) == 0); ctest_test("un-referenced", refobject_unref(REFOBJECT_FROM_TYPE(a)) == 0);
ctest_test("freecb called", test_freecb__called == 1); ctest_test("freecb called", test_freecb__called == 1);
test_freecb__called = 0; test_freecb__called = 0;
a = refobject_new(sizeof(refobject_base_t), test_freecb__freecb, NULL, NULL, REFOBJECT_NULL); a = refobject_new(ctest_test_type_t);
ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ctest_test("refobject created", a != NULL);
ctest_test("referenced", refobject_ref(a) == 0); ctest_test("referenced", refobject_ref(REFOBJECT_FROM_TYPE(a)) == 0);
ctest_test("freecb uncalled", test_freecb__called == 0); ctest_test("freecb uncalled", test_freecb__called == 0);
ctest_test("un-referenced (1 of 2)", refobject_unref(a) == 0); ctest_test("un-referenced (1 of 2)", refobject_unref(REFOBJECT_FROM_TYPE(a)) == 0);
ctest_test("freecb uncalled", test_freecb__called == 0); ctest_test("freecb uncalled", test_freecb__called == 0);
ctest_test("un-referenced (2 of 2)", refobject_unref(a) == 0); ctest_test("un-referenced (2 of 2)", refobject_unref(REFOBJECT_FROM_TYPE(a)) == 0);
ctest_test("freecb called", test_freecb__called == 1); ctest_test("freecb called", test_freecb__called == 1);
} }
@ -167,6 +239,9 @@ int main (void)
test_create_ref_unref(); test_create_ref_unref();
test_typename();
test_valid();
test_sizes(); test_sizes();
test_name(); test_name();