Add destructors

This commit is contained in:
2025-09-07 05:16:23 -07:00
parent 97d1b4a701
commit d088bc11d6
4 changed files with 230 additions and 12 deletions

View File

@ -80,8 +80,8 @@ refcount_make_context(size_t entry_offset,
void refcount_context_destroy(RefcountContext *ctx);
/**
* Structure holding the required information for a weak reference. That is, a
* reference that does not prevent an object from being de-allocated.
* Opaque 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 {
#ifdef REFCOUNT_HAS_THREADS
@ -94,8 +94,18 @@ typedef struct RefcountWeakref {
} RefcountWeakref;
/**
* Opaque struct holding reference data for an object. This should be included
* as a non-pointer member of the struct you are trying to track, e.g.
* Destructor callback type. Called before and object is freed after having its
* reference count drop to zero. This function can prevent the given object
* from being freed by increasing its reference count.
* @param obj The object being destroyed
* @param user_data Arbitrary user_provided data
*/
typedef void (*refcount_destructor_callback_t)(void *obj, void *user_data);
/**
* Opaque struct holding reference data for an object. This should be
* included as a non-pointer member of the struct you are trying to track,
* e.g.
* @code
* struct A {
* int my_num;
@ -106,7 +116,8 @@ typedef struct RefcountWeakref {
*/
typedef struct RefcountEntry {
bool is_static; //!< Whether the object is static.
RefcountWeakref *weak_ref; //<! Weakref for this entry.
RefcountWeakref *weak_ref; //!< Weakref for this entry.
HTTable *destructors; //!< Hash table of object destructors.
union {
struct {
uint64_t ref_count; //!< The object's reference count.
@ -226,6 +237,14 @@ static inline RefcountWeakref *refcount_context_weaken(RefcountContext *ctx,
return wr;
}
bool refcount_context_add_destructor(const RefcountContext *ctx, void *obj,
void *key,
refcount_destructor_callback_t callback,
void *user_data);
bool refcount_context_remove_destructor(const RefcountContext *ctx, void *obj,
void *key);
/**
* Same as #refcount_context_is_static, but only operates on the global
* context.
@ -367,7 +386,7 @@ static inline void *refcount_strengthen(RefcountWeakref *wr) {
}
/**
* Same as #refcount_context_weaken, but operates ojn the global context.
* Same as #refcount_context_weaken, but operates on 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.
@ -376,6 +395,35 @@ static inline RefcountWeakref *refcount_weaken(void *obj) {
return refcount_context_weaken(refcount_default_context, obj);
}
/**
* Same as #refcount_context_add_destructor, but operates on the global context.
* @param obj The object onto which to register the destructor
* @param key An arbitrary value that can be later used to unregister the
* destructor
* @param callback The destructor itself
* @param user_data Extra data to pass to the destructor
* @return True on success, false on failure. On failure, nothing is registered.
*/
static inline bool
refcount_add_destructor(void *obj, void *key,
refcount_destructor_callback_t callback,
void *user_data) {
return refcount_context_add_destructor(refcount_default_context, obj, key,
callback, user_data);
}
/**
* Same as #refcount_context_remove_destructor, but operates on the global
* context.
* @param obj The object for which to unregister the destructor
* @param key The destructors key
* @return True on success, false on error. On error, nothing is unregistered.
*/
static inline bool refcount_remove_destructor(void *obj, void *key) {
return refcount_context_remove_destructor(refcount_default_context, obj,
key);
}
#ifdef __cplusplus
}
#endif