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); | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -103,16 +103,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 +141,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 +154,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 +176,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 +193,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 +338,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