mirror of
https://gitlab.xiph.org/xiph/icecast-common.git
synced 2025-06-30 22:18:29 -04:00
Feature: Added additional functions to work with pure refobjects
This commit is contained in:
parent
f9badfd502
commit
d1e2abbddd
@ -24,6 +24,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <igloo/config.h>
|
||||
|
||||
#ifdef IGLOO_CTC_HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <igloo/config.h>
|
||||
@ -49,6 +54,106 @@ typedef void (*igloo_ro_free_t)(igloo_ro_t self);
|
||||
*/
|
||||
typedef int (*igloo_ro_new_t)(igloo_ro_t self, const igloo_ro_type_t *type, va_list ap);
|
||||
|
||||
/* Type used to store flags for clone operations.
|
||||
*/
|
||||
#ifdef IGLOO_CTC_HAVE_STDINT_H
|
||||
typedef uint_least32_t igloo_ro_cf_t;
|
||||
#else
|
||||
typedef unsigned long int igloo_ro_cf_t;
|
||||
#endif
|
||||
|
||||
/* No clone flags set. Usefull for variable initialization. */
|
||||
#define igloo_RO_CF_NONE ((igloo_ro_cf_t)0x0000)
|
||||
/* Make a shallow copy of the object */
|
||||
#define igloo_RO_CF_SHALLOW ((igloo_ro_cf_t)0x0001)
|
||||
/* Make a deep copy of the object */
|
||||
#define igloo_RO_CF_DEEP ((igloo_ro_cf_t)0x0002)
|
||||
/* Make a copy of the object that shares part of it's state with the original.
|
||||
* This is similar to using dup() on a POSIX filehandle.
|
||||
* This is useful when interacting with IO.
|
||||
*/
|
||||
#define igloo_RO_CF_DUP ((igloo_ro_cf_t)0x0004)
|
||||
/* Defaults to use if required and allowed is igloo_RO_CF_NONE */
|
||||
#define igloo_RO_CF_DEFAULT (igloo_RO_CF_SHALLOW|igloo_RO_CF_DEEP)
|
||||
|
||||
/* Type uses for callback called when the object should be cloned.
|
||||
*
|
||||
* A clone of the object must never have the same address of the object that was cloned.
|
||||
*
|
||||
* Parameters:
|
||||
* self
|
||||
* The object to clone.
|
||||
* required, allowed
|
||||
* See igloo_ro_clone().
|
||||
* name, associated
|
||||
* See igloo_ro_new().
|
||||
*/
|
||||
typedef igloo_ro_t (*igloo_ro_clone_t)(igloo_ro_t self, igloo_ro_cf_t required, igloo_ro_cf_t allowed, const char *name, igloo_ro_t associated);
|
||||
|
||||
/* Type used for callback called when the object needs to be converted to another type.
|
||||
*
|
||||
* This callback is not used when a object of the same type is requested.
|
||||
* On that case clone is requested.
|
||||
*
|
||||
* There are two cases that must be handled by the callback:
|
||||
* 0) The object self is of the same type as this callback is set for and type is pointing to different type.
|
||||
* 1) The object self is of any type and type is pointing to the type this callback was set to.
|
||||
*
|
||||
* If the callback can not convert it must return igloo_RO_NULL.
|
||||
*
|
||||
* Parameters:
|
||||
* self
|
||||
* The object to convert.
|
||||
* type
|
||||
* The type to convert to.
|
||||
* required, allowed
|
||||
* See igloo_ro_clone().
|
||||
* name, associated
|
||||
* See igloo_ro_new().
|
||||
*/
|
||||
typedef igloo_ro_t (*igloo_ro_convert_t)(igloo_ro_t self, const igloo_ro_type_t *type, igloo_ro_cf_t required, igloo_ro_cf_t allowed, const char *name, igloo_ro_t associated);
|
||||
|
||||
/* Type used for callback called when the object needs to be converted to a string.
|
||||
*
|
||||
* This is used mostly for debugging or preseting the object to the user.
|
||||
* The callback is not expected to return a string that can be used to reconstruct the object.
|
||||
*/
|
||||
typedef char * (*igloo_ro_stringify_t)(igloo_ro_t self);
|
||||
|
||||
/* Type used as a result of a compare between objects.
|
||||
*/
|
||||
typedef enum {
|
||||
/* The objects could not be compared.
|
||||
* Common cases may be that when one is NULL and the other is not NULL
|
||||
* or when both are of difference types that can not be compared to each other
|
||||
* (e.g. a IO handle and a buffer.)
|
||||
*/
|
||||
igloo_RO_CR__ERROR = -1,
|
||||
/* Both objects represent the same thing but are not the same object.
|
||||
* See also igloo_RO_CR_SAME.
|
||||
*/
|
||||
igloo_RO_CR_EQUAL = 0,
|
||||
/* Both objects are distinct and no other relation can be applied. */
|
||||
igloo_RO_CR_NOTEQUAL,
|
||||
/* Object A is less than object B. */
|
||||
igloo_RO_CR_ALESSTHANB,
|
||||
/* Object A is greather than object B. */
|
||||
igloo_RO_CR_AGREATERTHANB,
|
||||
/* Both objects are the same.
|
||||
* That is then they share the same address in memory.
|
||||
*/
|
||||
igloo_RO_CR_SAME
|
||||
} igloo_ro_cr_t;
|
||||
|
||||
/* Type used for callback called then two objects must be compared.
|
||||
*
|
||||
* Object a is always a object that belongs to the type this callback was set for.
|
||||
* Objects a, and b are not igloo_RO_NULL.
|
||||
* Objects a, and b may be of diffrent type.
|
||||
* Objects a, and b are not the same (See igloo_RO_CR_SAME).
|
||||
*/
|
||||
typedef igloo_ro_cr_t (*igloo_ro_compare_t)(igloo_ro_t a, igloo_ro_t b);
|
||||
|
||||
/* Meta type used to defined types.
|
||||
* DO NOT use any of the members in here directly!
|
||||
*/
|
||||
@ -60,18 +165,27 @@ typedef int (*igloo_ro_new_t)(igloo_ro_t self, const igloo_ro_type_t *type, va_l
|
||||
*/
|
||||
struct igloo_ro_type_tag {
|
||||
/* Size of this control structure */
|
||||
size_t control_length;
|
||||
size_t control_length;
|
||||
/* ABI version of this structure */
|
||||
int control_version;
|
||||
int control_version;
|
||||
|
||||
/* Total length of the objects to be created */
|
||||
size_t type_length;
|
||||
size_t type_length;
|
||||
/* Name of type */
|
||||
const char * type_name;
|
||||
const char * type_name;
|
||||
/* Callback to be called on final free() */
|
||||
igloo_ro_free_t type_freecb;
|
||||
/* Callback to be callback by igloo_ro_new() */
|
||||
igloo_ro_new_t type_newcb;
|
||||
igloo_ro_free_t type_freecb;
|
||||
/* Callback to be called by igloo_ro_new() */
|
||||
igloo_ro_new_t type_newcb;
|
||||
|
||||
/* Callback to be called by igloo_ro_clone() */
|
||||
igloo_ro_clone_t type_clonecb;
|
||||
/* Callback to be called by igloo_ro_convert() */
|
||||
igloo_ro_convert_t type_convertcb;
|
||||
/* Callback to be called by igloo_ro_stringify() */
|
||||
igloo_ro_stringify_t type_stringifycb;
|
||||
/* Callback to be called by igloo_ro_compare() */
|
||||
igloo_ro_compare_t type_comparecb;
|
||||
};
|
||||
struct igloo_ro_base_tag {
|
||||
/* Type of the object */
|
||||
@ -140,6 +254,70 @@ const char * igloo_ro_get_name(igloo_ro_t self);
|
||||
igloo_ro_t igloo_ro_get_associated(igloo_ro_t self);
|
||||
int igloo_ro_set_associated(igloo_ro_t self, igloo_ro_t associated);
|
||||
|
||||
/* Clone the given object returning a copy of it.
|
||||
*
|
||||
* This creates a copy of the passed object if possible.
|
||||
* The mode of copy is selected by the parameters required and allowed.
|
||||
* Both list flags of modes. Modes listed as required are adhered to.
|
||||
* However the application may select any additional mode from the allowed
|
||||
* flags.
|
||||
*
|
||||
* If both required and allowed are zero a set of default flags is applied
|
||||
* as allowed flags.
|
||||
*
|
||||
* Parameters:
|
||||
* self
|
||||
* The object to copy.
|
||||
* required
|
||||
* Flags that must be adhered to when coping.
|
||||
* allowed
|
||||
* Flags that are allowed to be used.
|
||||
* Flags that are listed as required are automatically added the list of allowed flags.
|
||||
* name, associated
|
||||
* See igloo_ro_new().
|
||||
*/
|
||||
igloo_ro_t igloo_ro_clone(igloo_ro_t self, igloo_ro_cf_t required, igloo_ro_cf_t allowed, const char *name, igloo_ro_t associated);
|
||||
|
||||
/* Make a copy of a object but converts it to another type as well.
|
||||
*
|
||||
* This makes makes a copy of the object that is also of a diffrent type.
|
||||
* If the type is the same as the type of self igloo_ro_clone() is called.
|
||||
*
|
||||
* Parameters:
|
||||
* self
|
||||
* The object to copy and convert.
|
||||
* type
|
||||
* The type to convert to.
|
||||
* required, allowed
|
||||
* See igloo_ro_clone().
|
||||
* name, associated
|
||||
* See igloo_ro_new().
|
||||
*/
|
||||
igloo_ro_t igloo_ro_convert(igloo_ro_t self, const igloo_ro_type_t *type, igloo_ro_cf_t required, igloo_ro_cf_t allowed, const char *name, igloo_ro_t associated);
|
||||
|
||||
/* Convert a object to a string.
|
||||
* This is used for debugging and presenting to the user.
|
||||
*
|
||||
* The resulting string can not be used to recreate the object.
|
||||
*
|
||||
* Parameters:
|
||||
* self
|
||||
* The object to convert to a string.
|
||||
* Returns:
|
||||
* A string as allocated using malloc(3). The caller must call free(3).
|
||||
*/
|
||||
char * igloo_ro_stringify(igloo_ro_t self);
|
||||
|
||||
/* Compare two objects.
|
||||
*
|
||||
* Parameters:
|
||||
* a, b
|
||||
* The objects to compare.
|
||||
* Returns:
|
||||
* Thre result of the compare. See igloo_ro_cr_t.
|
||||
*/
|
||||
igloo_ro_cr_t igloo_ro_compare(igloo_ro_t a, igloo_ro_t b);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -49,6 +49,10 @@ static const igloo_ro_type_t igloo_ro__typedef__ ## type = \
|
||||
#define igloo_RO_TYPEDECL_FREE(cb) .type_freecb = (cb)
|
||||
#define igloo_RO_TYPEDECL_NEW(cb) .type_newcb = (cb)
|
||||
#define igloo_RO_TYPEDECL_NEW_NOOP() .type_newcb = igloo_ro_new__return_zero
|
||||
#define igloo_RO_TYPEDECL_CLONE(cb) .type_clonecb = (cb)
|
||||
#define igloo_RO_TYPEDECL_CONVERT(cb) .type_convertcb = (cb)
|
||||
#define igloo_RO_TYPEDECL_STRINGIFY(cb) .type_stringifycb = (cb)
|
||||
#define igloo_RO_TYPEDECL_COMPARE(cb) .type_comparecb = (cb)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
163
src/ro.c
163
src/ro.c
@ -21,6 +21,7 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -309,3 +310,165 @@ int igloo_ro_set_associated(igloo_ro_t self, igloo_ro_t associated)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
igloo_ro_t igloo_ro_clone(igloo_ro_t self, igloo_ro_cf_t required, igloo_ro_cf_t allowed, const char *name, igloo_ro_t associated)
|
||||
{
|
||||
igloo_ro_base_t *base = igloo_RO__GETBASE(self);
|
||||
igloo_ro_t ret = igloo_RO_NULL;
|
||||
|
||||
if (!base)
|
||||
return igloo_RO_NULL;
|
||||
|
||||
allowed |= required;
|
||||
|
||||
if (!allowed)
|
||||
allowed = igloo_RO_CF_DEFAULT;
|
||||
|
||||
igloo_thread_mutex_lock(&(base->lock));
|
||||
if (!base->refc) {
|
||||
igloo_thread_mutex_unlock(&(base->lock));
|
||||
return igloo_RO_NULL;
|
||||
}
|
||||
|
||||
if (base->type->type_clonecb)
|
||||
ret = base->type->type_clonecb(self, required, allowed, name, associated);
|
||||
igloo_thread_mutex_unlock(&(base->lock));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
igloo_ro_t igloo_ro_convert(igloo_ro_t self, const igloo_ro_type_t *type, igloo_ro_cf_t required, igloo_ro_cf_t allowed, const char *name, igloo_ro_t associated)
|
||||
{
|
||||
igloo_ro_base_t *base = igloo_RO__GETBASE(self);
|
||||
igloo_ro_t ret = igloo_RO_NULL;
|
||||
|
||||
if (!base || !type)
|
||||
return igloo_RO_NULL;
|
||||
|
||||
igloo_thread_mutex_lock(&(base->lock));
|
||||
if (!base->refc) {
|
||||
igloo_thread_mutex_unlock(&(base->lock));
|
||||
return igloo_RO_NULL;
|
||||
}
|
||||
|
||||
if (base->type == type) {
|
||||
igloo_thread_mutex_unlock(&(base->lock));
|
||||
return igloo_ro_clone(self, required, allowed, name, associated);
|
||||
}
|
||||
|
||||
allowed |= required;
|
||||
|
||||
if (!allowed)
|
||||
allowed = igloo_RO_CF_DEFAULT;
|
||||
|
||||
if (base->type->type_convertcb)
|
||||
ret = base->type->type_convertcb(self, type, required, allowed, name, associated);
|
||||
|
||||
if (igloo_RO_IS_NULL(ret))
|
||||
if (type->type_convertcb)
|
||||
ret = type->type_convertcb(self, type, required, allowed, name, associated);
|
||||
igloo_thread_mutex_unlock(&(base->lock));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char * igloo_ro_stringify(igloo_ro_t self)
|
||||
{
|
||||
igloo_ro_base_t *base = igloo_RO__GETBASE(self);
|
||||
char *ret = NULL;
|
||||
|
||||
if (!base)
|
||||
return strdup("{igloo_RO_NULL}");
|
||||
|
||||
igloo_thread_mutex_lock(&(base->lock));
|
||||
if (!base->refc) {
|
||||
int len;
|
||||
char buf;
|
||||
|
||||
#define STRINGIFY_FORMAT_WEAK "{%s@%p, weak}", base->type->type_name, base
|
||||
len = snprintf(&buf, 1, STRINGIFY_FORMAT_WEAK);
|
||||
if (len > 2) {
|
||||
/* We add 2 bytes just to make sure no buggy interpretation of \0 inclusion could bite us. */
|
||||
ret = calloc(1, len + 2);
|
||||
if (ret) {
|
||||
snprintf(ret, len + 1, STRINGIFY_FORMAT_WEAK);
|
||||
}
|
||||
}
|
||||
|
||||
igloo_thread_mutex_unlock(&(base->lock));
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (base->type->type_stringifycb) {
|
||||
ret = base->type->type_stringifycb(self);
|
||||
} else {
|
||||
int len;
|
||||
char buf;
|
||||
|
||||
#define STRINGIFY_FORMAT_FULL "{%s@%p, strong, name=\"%s\", associated=%p}", base->type->type_name, base, base->name, igloo_RO__GETBASE(base->associated)
|
||||
len = snprintf(&buf, 1, STRINGIFY_FORMAT_FULL);
|
||||
if (len > 2) {
|
||||
/* We add 2 bytes just to make sure no buggy interpretation of \0 inclusion could bite us. */
|
||||
ret = calloc(1, len + 2);
|
||||
if (ret) {
|
||||
snprintf(ret, len + 1, STRINGIFY_FORMAT_FULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
igloo_thread_mutex_unlock(&(base->lock));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
igloo_ro_cr_t igloo_ro_compare(igloo_ro_t a, igloo_ro_t b)
|
||||
{
|
||||
igloo_ro_base_t *base_a = igloo_RO__GETBASE(a);
|
||||
igloo_ro_base_t *base_b = igloo_RO__GETBASE(b);
|
||||
igloo_ro_cr_t ret = igloo_RO_CR__ERROR;
|
||||
|
||||
if (base_a == base_b)
|
||||
return igloo_RO_CR_SAME;
|
||||
|
||||
if (!base_a || !base_b)
|
||||
return igloo_RO_CR__ERROR;
|
||||
|
||||
igloo_thread_mutex_lock(&(base_a->lock));
|
||||
igloo_thread_mutex_lock(&(base_b->lock));
|
||||
|
||||
if (!base_a->refc || !base_b->refc) {
|
||||
igloo_thread_mutex_unlock(&(base_b->lock));
|
||||
igloo_thread_mutex_unlock(&(base_a->lock));
|
||||
return igloo_RO_CR__ERROR;
|
||||
}
|
||||
|
||||
if (base_a->type->type_comparecb)
|
||||
ret = base_a->type->type_comparecb(a, b);
|
||||
|
||||
if (ret == igloo_RO_CR__ERROR) {
|
||||
ret = base_b->type->type_comparecb(b, a);
|
||||
|
||||
/* we switched arguments here, so we need to reverse the result */
|
||||
switch (ret) {
|
||||
case igloo_RO_CR__ERROR:
|
||||
case igloo_RO_CR_EQUAL:
|
||||
case igloo_RO_CR_NOTEQUAL:
|
||||
/* those are the same in both directions */
|
||||
break;
|
||||
case igloo_RO_CR_ALESSTHANB:
|
||||
ret = igloo_RO_CR_AGREATERTHANB;
|
||||
break;
|
||||
case igloo_RO_CR_AGREATERTHANB:
|
||||
ret = igloo_RO_CR_ALESSTHANB;
|
||||
break;
|
||||
default:
|
||||
/* Cases we do not yet handle or that are not a valid result. */
|
||||
ret = igloo_RO_CR__ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
igloo_thread_mutex_unlock(&(base_b->lock));
|
||||
igloo_thread_mutex_unlock(&(base_a->lock));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user