Initial garbage colletor implementation
This commit is contained in:
		| @ -4,6 +4,8 @@ | ||||
| #ifndef INCLUDED_REFCOUNT_ALLOCATOR_H | ||||
| #define INCLUDED_REFCOUNT_ALLOCATOR_H | ||||
|  | ||||
| #include <ht.h> | ||||
| #include <stdbool.h> | ||||
| #include <stddef.h> | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| @ -14,12 +16,27 @@ extern "C" { | ||||
|  * A set of the three main C standard allocators. Each member function should | ||||
|  * behave the same as its standard library counterpart. That is, for example, | ||||
|  * free should allow NULL as an input. | ||||
|  * | ||||
|  * To allow e.g. keeping track of allocations in different contexts, each | ||||
|  * function also takes a second user_data pointer argument. | ||||
|  */ | ||||
| typedef struct RefcountAllocator { | ||||
|     void *(*malloc)(size_t); //!< malloc implementation for the allocator. | ||||
|     void *(*realloc)(void *, | ||||
|                      size_t); //!< realloc implementation for the allocator. | ||||
|     void (*free)(void *); //!< free implementation for the allocator. | ||||
|     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. | ||||
|     }; | ||||
|     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. | ||||
|     }; | ||||
|     bool pass_data; | ||||
|     void *user_data; | ||||
| } RefcountAllocator; | ||||
|  | ||||
| extern const RefcountAllocator *refcount_global_allocator; | ||||
| @ -30,67 +47,29 @@ extern const RefcountAllocator *refcount_global_allocator; | ||||
|  * @param size The number of bytes to allocate | ||||
|  * @return The newly allocate pointer, or NULL if allocation failed | ||||
|  */ | ||||
| static inline void *refcount_allocator_malloc(const RefcountAllocator *alloc, | ||||
|                                               size_t size) { | ||||
| 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(size); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Reallocate memory using a #RefcountAllocator. | ||||
|  * @param alloc The allocator to use | ||||
|  * @param old_ptr The pointer to reallocate | ||||
|  * @param size The number of bytes to allocate | ||||
|  * @return The resized pointer, a newly allocated pointer, or NULL if | ||||
|  * allocation failed | ||||
|  */ | ||||
| static inline void *refcount_allocator_realloc(const RefcountAllocator *alloc, | ||||
|                                                void *old_ptr, size_t size) { | ||||
|     return alloc->realloc(old_ptr, size); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Free memory using a #RefcountAllocator. | ||||
|  * @param alloc The allocator to use | ||||
|  * @param ptr The pointer to free | ||||
|  */ | ||||
| static inline void refcount_allocator_free(const RefcountAllocator *alloc, | ||||
|                                            void *ptr) { | ||||
|     alloc->free(ptr); | ||||
| static inline void refcount_free(const RefcountAllocator *alloc, void *ptr) { | ||||
|     if (alloc->pass_data) { | ||||
|         alloc->free_with_data(ptr, alloc->user_data); | ||||
|     } else { | ||||
|         alloc->free(ptr); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Allocate memory using the global #RefcountAllocator. | ||||
|  * @param size The number of bytes to allocate | ||||
|  * @return The newly allocate pointer, or NULL if allocation failed | ||||
|  * | ||||
|  * @see refcount_allocator_malloc | ||||
|  */ | ||||
| static inline void *refcount_malloc(size_t size) { | ||||
|     return refcount_allocator_malloc(refcount_global_allocator, size); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Reallocate memory using the global #RefcountAllocator. | ||||
|  * @param old_ptr The pointer to reallocate | ||||
|  * @param size The number of bytes to allocate | ||||
|  * @return The resized pointer, a newly allocated pointer, or NULL if | ||||
|  * allocation failed | ||||
|  * | ||||
|  * @see refcount_allocator_realloc | ||||
|  */ | ||||
| static inline void *refcount_realloc(void *old_ptr, size_t size) { | ||||
|     return refcount_allocator_realloc(refcount_global_allocator, old_ptr, size); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Free memory using the global #RefcountAllocator. | ||||
|  * @param ptr The pointer to free | ||||
|  * | ||||
|  * @see refcount_allocator_free | ||||
|  */ | ||||
| static inline void refcount_free(void *ptr) { | ||||
|     refcount_allocator_free(refcount_global_allocator, ptr); | ||||
| } | ||||
| void refcount_allocator_to_ht_allocator(const RefcountAllocator *src, | ||||
|                                         HTAllocator *dest); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #define INCLUDED_REFCOUNT_LIST_H | ||||
|  | ||||
| #include <refcount/allocator.h> | ||||
| #include <stdarg.h> | ||||
| #include <stddef.h> // for NULL | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| @ -24,42 +25,130 @@ typedef struct RefcountList { | ||||
|  | ||||
| /** | ||||
|  * Callback to used to free list elements. | ||||
|  * @param ptr The pointer to free | ||||
|  * @see refcount_list_free | ||||
|  */ | ||||
| typedef void (*refcount_list_destroy_callback_t)(void *); | ||||
| typedef void (*refcount_list_destroy_callback_t)(void *ptr); | ||||
| /** | ||||
|  * Callback to used when looping over the list with extra data. | ||||
|  * @see refcount_list_free_with_data | ||||
|  * Callback to used to free list elements. | ||||
|  * @param ptr The pointer to free | ||||
|  * @param user_data Arbitrary user specified data | ||||
|  * @see refcount_list_free | ||||
|  */ | ||||
| typedef void (*refcount_list_foreach_callback_t)(void *, void *); | ||||
| typedef void (*refcount_list_destroy_with_data_callback_t)(void *ptr, | ||||
|                                                            void *user_data); | ||||
| /** | ||||
|  * Callback used when copying elements from one list to another. | ||||
|  * @param ptr The element to copy | ||||
|  * @param user_data Arbitrary user specified data | ||||
|  * @return The new copy, or NULL if an error occurred | ||||
|  * @see refcount_list_copy | ||||
|  */ | ||||
| typedef void *(*refcount_list_copy_callback_t)(void *); | ||||
| typedef void *(*refcount_list_copy_callback_t)(const void *ptr, | ||||
|                                                void *user_data); | ||||
|  | ||||
| RefcountList *refcount_list_build(int count, ...); | ||||
| RefcountList *refcount_list_build_full_va(int count, | ||||
|                                           const RefcountAllocator *alloc, | ||||
|                                           va_list args); | ||||
|  | ||||
| RefcountList *refcount_list_copy(RefcountList *list, | ||||
|                                  refcount_list_copy_callback_t callback); | ||||
| /** | ||||
|  * Like #refcount_list_build, but lets you specify the allocator to use. | ||||
|  * @param count The number of elements given | ||||
|  * @param alloc The allocator to use | ||||
|  * @param ... The elements from which to build the list | ||||
|  * @return The built list, or NULL if a memory allocation error occurred | ||||
|  */ | ||||
| static inline RefcountList * | ||||
| refcount_list_build_full(int count, const RefcountAllocator *alloc, ...) { | ||||
|     va_list args; | ||||
|     va_start(args, alloc); | ||||
|     RefcountList *retval = refcount_list_build_full_va(count, alloc, args); | ||||
|     va_end(args); | ||||
|     return retval; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Build a #RefcountList from a number of elements. | ||||
|  * | ||||
|  * > that this will return NULL if count is 0 or if a memory allocation error | ||||
|  * > occurred. However, as no allocation is preformed is count is 0, these | ||||
|  * > errors should be mutually exclusive. | ||||
|  * | ||||
|  * @param count The number of elements given | ||||
|  * @param ... The elements from which to build the list | ||||
|  * @return The built list, or NULL if a memory allocation error occurred | ||||
|  */ | ||||
| static inline RefcountList *refcount_list_build(int count, ...) { | ||||
|     va_list args; | ||||
|     va_start(args, count); | ||||
|     RefcountList *retval = | ||||
|         refcount_list_build_full_va(count, refcount_global_allocator, args); | ||||
|     va_end(args); | ||||
|     return retval; | ||||
| } | ||||
|  | ||||
| RefcountList *refcount_list_copy_full(const RefcountList *list, | ||||
|                                       refcount_list_copy_callback_t callback, | ||||
|                                       void *user_data, | ||||
|                                       const RefcountAllocator *alloc); | ||||
|  | ||||
| /** | ||||
|  * Return a new #RefcountList that is a copy of list. This does no allocation if | ||||
|  * the input list is NULL. | ||||
|  * @param list The list to copy | ||||
|  * @param callback The function to copy each element of the list, or NULL | ||||
|  * @param user_data Extra data to be passed to the copy callback | ||||
|  * @return The copy, or NULL if an allocation error occurred | ||||
|  */ | ||||
| static inline RefcountList * | ||||
| refcount_list_copy(const RefcountList *list, | ||||
|                    refcount_list_copy_callback_t callback, void *user_data) { | ||||
|     return refcount_list_copy_full(list, callback, user_data, | ||||
|                                    refcount_global_allocator); | ||||
| } | ||||
|  | ||||
| RefcountList *refcount_list_reverse(RefcountList *list); | ||||
|  | ||||
| void refcount_list_free(RefcountList *list, | ||||
|                         refcount_list_destroy_callback_t callback); | ||||
| void refcount_list_free_full(RefcountList *list, | ||||
|                              refcount_list_destroy_callback_t callback, | ||||
|                              const RefcountAllocator *alloc); | ||||
|  | ||||
| void refcount_list_free_with_data(RefcountList *list, | ||||
|                                   refcount_list_foreach_callback_t callback, | ||||
|                                   void *data); | ||||
| /** | ||||
|  * Free a #RefcountList. | ||||
|  * @param list The list to free | ||||
|  * @param callback The function to call to free each member, or NULL | ||||
|  */ | ||||
| static inline void | ||||
| refcount_list_free(RefcountList *list, | ||||
|                    refcount_list_destroy_callback_t callback) { | ||||
|     refcount_list_free_full(list, callback, refcount_global_allocator); | ||||
| } | ||||
|  | ||||
| size_t refcount_list_length(RefcountList *list); | ||||
| void refcount_list_free_with_data_full( | ||||
|     RefcountList *list, refcount_list_destroy_with_data_callback_t callback, | ||||
|     void *data, const RefcountAllocator *alloc); | ||||
|  | ||||
| /** | ||||
|  * Free a #RefcountList. | ||||
|  * @param list The list to free | ||||
|  * @param callback The function to call to free each member, or NULL | ||||
|  * @param data Extra data to pass to the second argument of the callback | ||||
|  */ | ||||
| static inline void refcount_list_free_with_data( | ||||
|     RefcountList *list, refcount_list_destroy_with_data_callback_t callback, | ||||
|     void *data) { | ||||
|     refcount_list_free_with_data_full(list, callback, data, | ||||
|                                       refcount_global_allocator); | ||||
| } | ||||
|  | ||||
| size_t refcount_list_length(const RefcountList *list); | ||||
|  | ||||
| /** | ||||
|  * Return the first element in a #RefcountList. | ||||
|  * @param list The list | ||||
|  * @return The first object in the list | ||||
|  */ | ||||
| static inline void *refcount_list_peek(RefcountList *list) { | ||||
| static inline void *refcount_list_peek(const RefcountList *list) { | ||||
|     if (!list) { | ||||
|         return NULL; | ||||
|     } | ||||
| @ -68,21 +157,171 @@ static inline void *refcount_list_peek(RefcountList *list) { | ||||
|  | ||||
| RefcountList *refcount_list_drop(RefcountList *list, size_t n); | ||||
|  | ||||
| void *refcount_list_nth(RefcountList *list, size_t n); | ||||
| void *refcount_list_nth(const RefcountList *list, size_t n); | ||||
|  | ||||
| RefcountList *refcount_list_pop(RefcountList *list, | ||||
|                                 refcount_list_destroy_callback_t callback); | ||||
| RefcountList * | ||||
| refcount_list_remove_full(RefcountList *list, RefcountList *link, | ||||
|                           refcount_list_destroy_callback_t callback, | ||||
|                           const RefcountAllocator *alloc); | ||||
|  | ||||
| RefcountList *refcount_list_remove(RefcountList *list, RefcountList *link, | ||||
|                                    refcount_list_destroy_callback_t callback); | ||||
| /** | ||||
|  * Remove a link from a #RefcountList. Note that you must save the return | ||||
|  * value as it is the new value of the list. | ||||
|  * | ||||
|  * If the given list or link is NULL, this does nothing. It is undefined | ||||
|  * behavior if link is not in list. | ||||
|  * | ||||
|  * @param list The list | ||||
|  * @param link The link to remove, or NULL | ||||
|  * @param callback The function to call to free the member, or NULL | ||||
|  * @return The new value of the list | ||||
|  */ | ||||
| static inline RefcountList * | ||||
| refcount_list_remove(RefcountList *list, RefcountList *link, | ||||
|                      refcount_list_destroy_callback_t callback) { | ||||
|     return refcount_list_remove_full(list, link, callback, | ||||
|                                      refcount_global_allocator); | ||||
| } | ||||
|  | ||||
| RefcountList *refcount_list_push(RefcountList *list, void *element); | ||||
| /** | ||||
|  * Same as #refcount_list_remove_with_data, but lets you specify the allocator | ||||
|  * to use. | ||||
|  * @param list The list | ||||
|  * @param callback The function to call to free the member, or NULL | ||||
|  * @param link The link to remove, or NULL | ||||
|  * @param user_data Extra data to pass to the callback | ||||
|  * @param alloc The allocator to use | ||||
|  * @return The new value of the list | ||||
|  */ | ||||
| static inline RefcountList *refcount_list_remove_with_data_full( | ||||
|     RefcountList *list, RefcountList *link, | ||||
|     refcount_list_destroy_with_data_callback_t callback, void *user_data, | ||||
|     const RefcountAllocator *alloc) { | ||||
|     if (list && link && callback) { | ||||
|         callback(link->data, user_data); | ||||
|     } | ||||
|     return refcount_list_remove_full(list, link, NULL, alloc); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Same as #refcount_list_remove except that the callback takes an additional | ||||
|  * argument. This also does nothing if either of list or link is NULL. | ||||
|  * @param list The list | ||||
|  * @param callback The function to call to free the member, or NULL | ||||
|  * @param link The link to remove, or NULL | ||||
|  * @param user_data Extra data to pass to the callback | ||||
|  * @return The new value of the list | ||||
|  */ | ||||
| static inline RefcountList *refcount_list_remove_with_data( | ||||
|     RefcountList *list, RefcountList *link, | ||||
|     refcount_list_destroy_with_data_callback_t callback, void *user_data) { | ||||
|     return refcount_list_remove_with_data_full(list, link, callback, user_data, | ||||
|                                                refcount_global_allocator); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Same as #refcount_list_pop, but lets you specify the allocator to use. | ||||
|  * | ||||
|  * @param list The list | ||||
|  * @param callback The function to call to free the removed, or NULL | ||||
|  * @param alloc The allocator to use | ||||
|  * @return The new value of the list | ||||
|  * | ||||
|  * @see refcount_list_remove | ||||
|  */ | ||||
| static inline RefcountList * | ||||
| refcount_list_pop_full(RefcountList *list, | ||||
|                        refcount_list_destroy_callback_t callback, | ||||
|                        const RefcountAllocator *alloc) { | ||||
|     return refcount_list_remove_full(list, list, callback, alloc); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Remove the first element from a #RefcountList. Note that you must save the | ||||
|  * return value as it is the new value of the list. If the list is a sub-list, | ||||
|  * the state of the larger list is undefined after this call. | ||||
|  * | ||||
|  * @param list The list | ||||
|  * @param callback The function to call to free the removed, or NULL | ||||
|  * @return The new value of the list | ||||
|  * | ||||
|  * @see refcount_list_remove | ||||
|  */ | ||||
| static inline RefcountList * | ||||
| refcount_list_pop(RefcountList *list, | ||||
|                   refcount_list_destroy_callback_t callback) { | ||||
|     return refcount_list_pop_full(list, callback, refcount_global_allocator); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Same as #refcount_list_pop_with_data, but lets specify the allocator to use. | ||||
|  * @param list The list | ||||
|  * @param callback The function to call to free the member, or NULL | ||||
|  * @param user_data Extra data to pass to the callback | ||||
|  * @param alloc The allocator to use | ||||
|  * @return The new value of the list | ||||
|  */ | ||||
| static inline RefcountList *refcount_list_pop_with_data_full( | ||||
|     RefcountList *list, refcount_list_destroy_with_data_callback_t callback, | ||||
|     void *user_data, const RefcountAllocator *alloc) { | ||||
|     if (list && callback) { | ||||
|         callback(list->data, user_data); | ||||
|     } | ||||
|     return refcount_list_pop_full(list, NULL, alloc); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Same as #refcount_list_pop except that the callback takes an additional | ||||
|  * argument. | ||||
|  * @param list The list | ||||
|  * @param callback The function to call to free the member, or NULL | ||||
|  * @param user_data Extra data to pass to the callback | ||||
|  * @return The new value of the list | ||||
|  */ | ||||
| static inline RefcountList * | ||||
| refcount_list_pop_with_data(RefcountList *list, | ||||
|                             refcount_list_destroy_with_data_callback_t callback, | ||||
|                             void *user_data) { | ||||
|     return refcount_list_pop_with_data_full(list, callback, user_data, | ||||
|                                             refcount_global_allocator); | ||||
| } | ||||
|  | ||||
| RefcountList *refcount_list_push_full(RefcountList *list, void *element, | ||||
|                                       const RefcountAllocator *alloc); | ||||
|  | ||||
| /** | ||||
|  * Add an element to the start of a #RefcountList. Note that you must save the | ||||
|  * return value as it is the new value of the list. | ||||
|  * @param list The list | ||||
|  * @param element The element to add | ||||
|  * @return The new value of the list, or NULL if allocation of the new node | ||||
|  * failed | ||||
|  */ | ||||
| static inline RefcountList *refcount_list_push(RefcountList *list, | ||||
|                                                void *element) { | ||||
|     return refcount_list_push_full(list, element, refcount_global_allocator); | ||||
| } | ||||
|  | ||||
| RefcountList *refcount_list_tail(RefcountList *list); | ||||
|  | ||||
| RefcountList *refcount_list_join(RefcountList *list1, RefcountList *list2); | ||||
|  | ||||
| RefcountList *refcount_list_push_back(RefcountList *list, void *element); | ||||
| RefcountList *refcount_list_push_back_full(RefcountList *list, void *element, | ||||
|                                            const RefcountAllocator *alloc); | ||||
|  | ||||
| /** | ||||
|  * Add an element to the end of a #RefcountList. Note that you must save the | ||||
|  * return value as it is the new value of the list. | ||||
|  * @param list The list | ||||
|  * @param element The element to add | ||||
|  * @return The new value of the list, or NULL if allocation of the new node | ||||
|  * failed | ||||
|  */ | ||||
| static inline RefcountList *refcount_list_push_back(RefcountList *list, | ||||
|                                                     void *element) { | ||||
|     return refcount_list_push_back_full(list, element, | ||||
|                                         refcount_global_allocator); | ||||
| } | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| #ifndef INCLUDED_REFCOUNT_REFCOUNT_H | ||||
| #define INCLUDED_REFCOUNT_REFCOUNT_H | ||||
|  | ||||
| #include <ht.h> | ||||
| #include <refcount/list.h> | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| @ -14,15 +15,29 @@ extern "C" { | ||||
|  | ||||
| /** | ||||
|  * Callback for listing all references held by the passed object. The function | ||||
|  * should take an objects and return a #RefcountList of references held by that | ||||
|  * object. | ||||
|  * should take an object and return a #RefcountList of references held by that | ||||
|  * object. The second parameter is user supplied data. | ||||
|  * | ||||
|  * > The list in the refs parameter will probably not be empty, so it is | ||||
|  * > important that you update it, not replace it. If an errors occurs, you | ||||
|  * > mustn't free anything that you did not add to the list yourself. | ||||
|  * | ||||
|  * @param obj The object | ||||
|  * @param refs A pointer to a #RefcountList that should be updated with the held | ||||
|  * references. | ||||
|  * @param user_data User supplied data pointer | ||||
|  * @return True if the operation was successful, false otherwise | ||||
|  */ | ||||
| typedef RefcountList *(*refcount_held_refs_callback_t)(void *); | ||||
| typedef bool (*refcount_held_refs_callback_t)(void *obj, RefcountList **refs, | ||||
|                                               void *user_data); | ||||
| /** | ||||
|  * Callback for freeing an object after its reference count drops to 0. It is | ||||
|  * safe the free the object from this callback. | ||||
|  * safe the free the object from this callback. The second parameter is user | ||||
|  * supplied data. | ||||
|  * @param obj The object to free | ||||
|  * @param user_data User supplied data pointer | ||||
|  */ | ||||
| typedef void (*refcount_destroy_callback_t)(void *); | ||||
| typedef void (*refcount_destroy_callback_t)(void *obj, void *user_data); | ||||
|  | ||||
| /** | ||||
|  * Context for reference counting a specific type of object. This should be | ||||
| @ -33,9 +48,11 @@ typedef struct RefcountContext { | ||||
|     refcount_held_refs_callback_t | ||||
|         held_refs_callback; //!< Callback to list an object's held references. | ||||
|     refcount_destroy_callback_t | ||||
|         destroy_callback; //!< Callback to free an object | ||||
|                           //!< after its reference count | ||||
|                           //!< dropped to 0. | ||||
|         destroy_callback; //!< Callback to free an object after its reference | ||||
|                           //!< count drops to 0. | ||||
|     void *user_data; //<! User data to pass to other callbacks. | ||||
|     RefcountAllocator alloc; //<! Allocator to use for this context. | ||||
|     HTAllocator ht_alloc; //<! ht version of the context's allocator. | ||||
|  | ||||
|     RefcountList *static_objects; //!< List of static objects registered with | ||||
|                                   //!< this context. | ||||
| @ -47,7 +64,6 @@ typedef struct RefcountContext { | ||||
|  */ | ||||
| typedef enum { | ||||
|     REFCOUNT_OPER_DEINIT_STATIC, | ||||
|     REFCOUNT_OPER_UNREF, | ||||
|     REFCOUNT_OPER_FLOAT, | ||||
| } RefcountOperation; | ||||
|  | ||||
| @ -55,9 +71,12 @@ typedef enum { | ||||
|  * Type for a function to be called when some kind of error occurs. It should | ||||
|  * take a #RefcountOperation, a #RefcountContext pointer, and the object on | ||||
|  * which the error occurred. | ||||
|  * @param oper The operation that failed | ||||
|  * @param ctx The context the operation was performed on | ||||
|  * @param obj The object that caused the failure | ||||
|  */ | ||||
| typedef void (*refcount_debug_callback_t)(RefcountOperation, RefcountContext *, | ||||
|                                           void *); | ||||
| typedef void (*refcount_debug_callback_t)(RefcountOperation oper, | ||||
|                                           RefcountContext *ctx, void *obj); | ||||
|  | ||||
| extern refcount_debug_callback_t refcount_debug_breakpoint; | ||||
|  | ||||
| @ -66,7 +85,8 @@ extern RefcountContext *refcount_default_context; | ||||
| RefcountContext * | ||||
| refcount_make_context(size_t entry_offset, | ||||
|                       refcount_held_refs_callback_t held_refs_callback, | ||||
|                       refcount_destroy_callback_t destroy_callback); | ||||
|                       refcount_destroy_callback_t destroy_callback, | ||||
|                       void *user_data, const RefcountAllocator *alloc); | ||||
|  | ||||
| void refcount_context_destroy(RefcountContext *ctx); | ||||
|  | ||||
| @ -100,7 +120,7 @@ typedef struct RefcountEntry { | ||||
|  * @return A pointer to the objects #RefcountEntry | ||||
|  */ | ||||
| #define REFCOUNT_OBJECT_ENTRY(ctx, obj) \ | ||||
|     ((RefcountEntry *) (((void *) (obj)) + (ctx)->entry_offset)) | ||||
|     ((RefcountEntry *) (((char *) (obj)) + (ctx)->entry_offset)) | ||||
|  | ||||
| /** | ||||
|  * Test whether an object is static or not. The object must have been | ||||
| @ -128,9 +148,9 @@ static inline size_t refcount_context_num_refs(RefcountContext *ctx, | ||||
|  | ||||
| void refcount_context_init_obj(RefcountContext *ctx, void *obj); | ||||
|  | ||||
| void refcount_context_init_static(RefcountContext *ctx, void *obj); | ||||
| bool refcount_context_init_static(RefcountContext *ctx, void *obj); | ||||
|  | ||||
| void refcount_context_deinit_static(RefcountContext *ctx, void *obj); | ||||
| bool refcount_context_deinit_static(RefcountContext *ctx, void *obj); | ||||
|  | ||||
| /** | ||||
|  * Unregister a static object in a context. This is suitable to be passed as a | ||||
| @ -158,6 +178,8 @@ static inline void refcount_context_unref_as_callback(void *obj, void *ctx) { | ||||
| } | ||||
| void *refcount_context_float(RefcountContext *ctx, void *obj); | ||||
|  | ||||
| bool refcount_context_garbage_collect(RefcountContext *ctx); | ||||
|  | ||||
| /** | ||||
|  * Same as #refcount_context_is_static, but only operates on the global | ||||
|  * context. | ||||
| @ -242,6 +264,15 @@ static inline void *refcount_float(void *obj) { | ||||
|     return refcount_context_float(refcount_default_context, obj); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Same as #refcount_context_garbage_collect, but only operates on the globa | ||||
|  * context. | ||||
|  * @return False if an error occured, true otherwise | ||||
|  */ | ||||
| static inline bool refcount_garbage_collect(void) { | ||||
|     return refcount_context_garbage_collect(refcount_default_context); | ||||
| } | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
		Reference in New Issue
	
	Block a user