0
0
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:
Philipp Schafft 2019-07-07 16:01:06 +00:00
parent f9badfd502
commit d1e2abbddd
3 changed files with 352 additions and 7 deletions

View File

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

View File

@ -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
View File

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