Change to C99 and add weak references
This commit is contained in:
@ -22,19 +22,19 @@ extern "C" {
|
||||
*/
|
||||
typedef struct RefcountAllocator {
|
||||
union {
|
||||
void *(*malloc)(size_t size); //!< malloc implementation which takes no
|
||||
//!< data.
|
||||
void *(*malloc_with_data)(
|
||||
size_t size,
|
||||
void *user_data); //!< malloc implementation that takes a data
|
||||
//!< argument.
|
||||
};
|
||||
void *(*no_data)(size_t size); //!< malloc implementation which takes no
|
||||
//!< data.
|
||||
void *(*with_data)(size_t size,
|
||||
void *user_data); //!< malloc implementation that
|
||||
//!< takes a data argument.
|
||||
} malloc;
|
||||
union {
|
||||
void (*free)(void *ptr); //!< free implementation which takes no data.
|
||||
void (*free_with_data)(void *ptr,
|
||||
void *user_data); //!< free implementation that
|
||||
//!< takes a data argument.
|
||||
};
|
||||
void (*no_data)(
|
||||
void *ptr); //!< free implementation which takes no data.
|
||||
void (*with_data)(void *ptr,
|
||||
void *user_data); //!< free implementation that
|
||||
//!< takes a data argument.
|
||||
} free;
|
||||
bool pass_data;
|
||||
void *user_data;
|
||||
} RefcountAllocator;
|
||||
@ -50,9 +50,9 @@ extern const RefcountAllocator *refcount_global_allocator;
|
||||
static inline void *refcount_malloc(const RefcountAllocator *alloc,
|
||||
size_t size) {
|
||||
if (alloc->pass_data) {
|
||||
return alloc->malloc_with_data(size, alloc->user_data);
|
||||
return alloc->malloc.with_data(size, alloc->user_data);
|
||||
}
|
||||
return alloc->malloc(size);
|
||||
return alloc->malloc.no_data(size);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,9 +62,9 @@ static inline void *refcount_malloc(const RefcountAllocator *alloc,
|
||||
*/
|
||||
static inline void refcount_free(const RefcountAllocator *alloc, void *ptr) {
|
||||
if (alloc->pass_data) {
|
||||
alloc->free_with_data(ptr, alloc->user_data);
|
||||
alloc->free.with_data(ptr, alloc->user_data);
|
||||
} else {
|
||||
alloc->free(ptr);
|
||||
alloc->free.no_data(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <refcount/list.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <threads.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -103,16 +104,28 @@ void refcount_context_destroy(RefcountContext *ctx);
|
||||
*/
|
||||
typedef struct RefcountEntry {
|
||||
bool is_static; //!< Whether the object is static.
|
||||
RefcountList *weak_refs; //<! List of #RefcountWeakref structures for
|
||||
//<! holding thread safe weak references.
|
||||
union {
|
||||
struct {
|
||||
uint64_t ref_count; //!< The object's reference count.
|
||||
RefcountList *gc_root; //!< The object's GC root, or NULL.
|
||||
};
|
||||
} counted;
|
||||
RefcountList *static_entry; //!< The object's static list entry, never
|
||||
//!< NULL for registed statics.
|
||||
};
|
||||
//!< NULL for registered statics.
|
||||
} impl;
|
||||
} RefcountEntry;
|
||||
|
||||
/**
|
||||
* Structure holding the required information for a weak reference. That is, a
|
||||
* reference that does not prevent an object from being de-allocated.
|
||||
*/
|
||||
typedef struct RefcountWeakref {
|
||||
RefcountList *entry; //!< Link in the #RefcountEntry list of the object this
|
||||
//!< references that points to this reference.
|
||||
void *data; //<! The object this weak ref references (not the entry).
|
||||
} RefcountWeakref;
|
||||
|
||||
/**
|
||||
* Return a pointer to the entry associated with an object.
|
||||
* @param ctx The #RefcountContext
|
||||
@ -129,7 +142,8 @@ typedef struct RefcountEntry {
|
||||
* @param obj The object to test
|
||||
* @return Whether or not the object is static
|
||||
*/
|
||||
static inline bool refcount_context_is_static(RefcountContext *ctx, void *obj) {
|
||||
static inline bool refcount_context_is_static(const RefcountContext *ctx,
|
||||
void *obj) {
|
||||
return REFCOUNT_OBJECT_ENTRY(ctx, obj)->is_static;
|
||||
}
|
||||
|
||||
@ -141,12 +155,12 @@ static inline bool refcount_context_is_static(RefcountContext *ctx, void *obj) {
|
||||
* @param obj The object
|
||||
* @return The number of references the object has
|
||||
*/
|
||||
static inline size_t refcount_context_num_refs(RefcountContext *ctx,
|
||||
static inline size_t refcount_context_num_refs(const RefcountContext *ctx,
|
||||
void *obj) {
|
||||
return REFCOUNT_OBJECT_ENTRY(ctx, obj)->ref_count;
|
||||
return REFCOUNT_OBJECT_ENTRY(ctx, obj)->impl.counted.ref_count;
|
||||
}
|
||||
|
||||
void refcount_context_init_obj(RefcountContext *ctx, void *obj);
|
||||
void refcount_context_init_obj(const RefcountContext *ctx, void *obj);
|
||||
|
||||
bool refcount_context_init_static(RefcountContext *ctx, void *obj);
|
||||
|
||||
@ -163,7 +177,7 @@ static inline void refcount_context_deinit_static_as_callback(void *obj,
|
||||
refcount_context_deinit_static(ctx, obj);
|
||||
}
|
||||
|
||||
void *refcount_context_ref(RefcountContext *ctx, void *obj);
|
||||
void *refcount_context_ref(const RefcountContext *ctx, void *obj);
|
||||
|
||||
void *refcount_context_unref(RefcountContext *ctx, void *obj);
|
||||
|
||||
@ -180,6 +194,58 @@ void *refcount_context_float(RefcountContext *ctx, void *obj);
|
||||
|
||||
ptrdiff_t refcount_context_garbage_collect(RefcountContext *ctx);
|
||||
|
||||
RefcountWeakref *refcount_context_make_weakref(const RefcountContext *ctx,
|
||||
void *obj);
|
||||
|
||||
void refcount_context_destroy_weakref(const RefcountContext *ctx,
|
||||
RefcountWeakref *wr);
|
||||
|
||||
/**
|
||||
* Return weather the object referenced by a weak reference still exists.
|
||||
* @param ctx The #RefcountContext
|
||||
* @param wr The weak reference
|
||||
* @return Weather the reference is still valid
|
||||
*/
|
||||
static inline bool refcount_context_weakref_is_valid(const RefcountContext *ctx,
|
||||
RefcountWeakref *wr) {
|
||||
return wr->data;
|
||||
}
|
||||
|
||||
void *refcount_context_ref_weakref(const RefcountContext *ctx,
|
||||
const RefcountWeakref *wr);
|
||||
|
||||
/**
|
||||
* Convenience function that calls #refcount_context_ref_weakref followed by
|
||||
* #refcount_context_destroy_weakref.
|
||||
* @param ctx The #RefcountContext
|
||||
* @param wr The weak reference
|
||||
* @return The newly referenced object, or NULL if the object no longer exists
|
||||
*/
|
||||
static inline void *refcount_context_strengthen(const RefcountContext *ctx,
|
||||
RefcountWeakref *wr) {
|
||||
void *obj = refcount_context_ref_weakref(ctx, wr);
|
||||
refcount_context_destroy_weakref(ctx, wr);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a weak reference for an object and then unref it. This is the same as
|
||||
* calling #refcount_context_make_weakref followed by #refcount_context_unref.
|
||||
* @param ctx The #RefcountContext
|
||||
* @param obj The object to create a weak reference for then unref
|
||||
* @return The newly created weak reference, or NULL if an allocation error
|
||||
* occurred. In this case the object is not unrefed.
|
||||
*/
|
||||
static inline RefcountWeakref *refcount_context_weaken(RefcountContext *ctx,
|
||||
void *obj) {
|
||||
RefcountWeakref *wr = refcount_context_make_weakref(ctx, obj);
|
||||
if (!wr) {
|
||||
return NULL;
|
||||
}
|
||||
refcount_context_unref(ctx, obj);
|
||||
return wr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as #refcount_context_is_static, but only operates on the global
|
||||
* context.
|
||||
@ -273,6 +339,63 @@ static inline ptrdiff_t refcount_garbage_collect(void) {
|
||||
return refcount_context_garbage_collect(refcount_default_context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as #refcount_context_make_weakref, but operates on the global context.
|
||||
* @param obj The object to reference
|
||||
* @return The new weak reference, or NULL if an allocation error occurred
|
||||
*/
|
||||
static inline RefcountWeakref *refcount_make_weakref(void *obj) {
|
||||
return refcount_context_make_weakref(refcount_default_context, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as #refcount_context_destroy_weakref, but operates on the global
|
||||
* context.
|
||||
* @param wr The weak reference
|
||||
*/
|
||||
static inline void refcount_destroy_weakref(RefcountWeakref *wr) {
|
||||
refcount_context_destroy_weakref(refcount_default_context, wr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as #refcount_context_ref_weakref, but operates on the global context.
|
||||
* @param wr The weak reference
|
||||
* @return The newly referenced object, or NULL if the object no longer exists
|
||||
*/
|
||||
static inline void *refcount_ref_weakref(RefcountWeakref *wr) {
|
||||
return refcount_context_ref_weakref(refcount_default_context, wr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as #refcount_context_weakref_is_valid, but operates on the global
|
||||
* context.
|
||||
* @param wr The weak reference
|
||||
* @return Weather the reference is still valid
|
||||
*/
|
||||
static inline bool refcount_weakref_is_valid(RefcountWeakref *wr) {
|
||||
return refcount_context_weakref_is_valid(refcount_default_context, wr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as #refcount_context_strengthen, but operates on the global context.
|
||||
* @param wr The weak reference
|
||||
* @return The newly referenced object, or NULL if the object no longer
|
||||
* exists
|
||||
*/
|
||||
static inline void *refcount_strengthen(RefcountWeakref *wr) {
|
||||
return refcount_context_strengthen(refcount_default_context, wr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as #refcount_context_weaken, but operates ojn the global context.
|
||||
* @param obj The object to create a weak reference for then unref
|
||||
* @return The newly created weak reference, or NULL if an allocation error
|
||||
* occurred. In this case the object is not unrefed.
|
||||
*/
|
||||
static inline RefcountWeakref *refcount_weaken(void *obj) {
|
||||
return refcount_context_weaken(refcount_default_context, obj);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user