--- a/docs/Writerside/topics/mempool.h.md Thu May 22 21:00:33 2025 +0200 +++ b/docs/Writerside/topics/mempool.h.md Thu May 22 22:22:14 2025 +0200 @@ -15,46 +15,93 @@ ```C #include <cx/mempool.h> -CxMempool *cxMempoolCreate(size_t capacity, cx_destructor_func fnc); +enum cx_mempool_type { + CX_MEMPOOL_TYPE_SIMPLE, + CX_MEMPOOL_TYPE_ADVANCED, + CX_MEMPOOL_TYPE_PURE, +}; + +CxMempool *cxMempoolCreate(size_t capacity, + enum cx_mempool_type type); CxMempool *cxMempoolCreateSimple(size_t capacity); +CxMempool *cxMempoolCreateAdvanced(size_t capacity); +CxMempool *cxMempoolCreatePure(size_t capacity); void cxMempoolFree(CxMempool *pool); -void cxMempoolSetDestructor(void *memory, cx_destructor_func fnc); +void cxMempoolGlobalDestructor(CxMempool *pool, + cx_destructor_func fnc); + +void cxMempoolGlobalDestructor2(CxMempool *pool, + cx_destructor_func2 fnc, void *data); + +void cxMempoolSetDestructor(void *memory, + cx_destructor_func fnc); + +void cxMempoolSetDestructor2(void *memory, + cx_destructor_func fnc, void *data); void cxMempoolRemoveDestructor(void *memory); +void cxMempoolRemoveDestructor2(void *memory); + int cxMempoolRegister(CxMempool *pool, void *memory, - cx_destructor_func fnc); + cx_destructor_func fnc); + +int cxMempoolRegister2(CxMempool *pool, void *memory, + cx_destructor_func fnc, void *data); ``` -A memory pool is created with the `cxMempoolCreate()` function with a default `capacity` -and an optional default destructor function `fnc`. -If specified, the default destructor function is registered for all freshly allocated memory within the pool, -as if `cxMempoolSetDestructor()` was called immediately after allocation. -When you set `fnc` is to `NULL` during pool creation, or use `cxMempoolCreateSimple`, no default destructor is registered. +A memory pool is created with the `cxMempoolCreate()` family of functions with a default `capacity`. +If `capacity` is set to zero, an implementation default is used. -After creating a memory pool `CxMempool *mpool`, you can access the provided allocator via `mpool->allocator`. +The `type` specifies how much additional data is allocated for each pooled memory block. +A simple pool reserves memory for an optional `cx_destructor_func`. +An advanced pool reserves memory for an optional `cx_destructor_func2` +and an additional `data` pointer that will be passed to that destructor. +A pure pool does not reserve any additional data and therefore does not support registering +custom destructors with the allocated memory. + +> After creating a memory pool `CxMempool *mpool`, you can access the provided allocator via `mpool->allocator`. +>{style="note"} + +The functions `cxMempoolGlobalDestructor()` and `cxMempoolGlobalDestructor2()` can be used to specify destructor functions +that shall be invoked for _all_ objects allocated by the pool when they are freed (see [](#order-of-destruction)). +This is usually only useful for pools that will only contain objects of the same type. -The functions `cxMempoolSetDestructor()` and `cxMempoolRemoveDestructor()` can be used to assign a specific destructor -function to an allocated object or remove any assigned destructor function, respectively. +In _simple_ memory pools, the two functions `cxMempoolSetDestructor()` and `cxMempoolRemoveDestructor()` can be used to assign a specific destructor +function to an allocated object or remove an assigned destructor function, respectively. The `memory` pointer points to the allocated object, which must have been allocated by any `CxMempool`'s provided allocator. +For _advanced_ pools, the functions `cxMempoolSetDestructor2()` and `cxMempoolRemoveDestructor2()` do the same. +It is disallowed to use the functions with a pool of the wrong type and will most likely cause undefined behavior. +Pure pools do not allow setting destructors for individual memory blocks at all. -The `cxMempoolRegister()` function allocates a new wrapper object for `memory` with `pool`'s allocator that -will call the specified destructor function when destroyed. -Usually this function returns zero except for platforms where memory allocations are likely to fail, +The `cxMempoolRegister()` function allocates a new wrapper object for `memory` +and makes the specified destructor function being called when the pool gets destroyed. +Alternatively, the `cxMempoolRegister2()` function can be used to register an advanced destructor and a pointer to custom data. +Be aware that the memory pointed to by the additional data pointer must remain valid until the pool gets destroyed! +Usually these functions return zero except for platforms where memory allocations are likely to fail, in which case a non-zero value is returned. +> When you register foreign memory with a pool, you can decide which destructor type you want to use, +> regardless of the pool's type. +> That means, for example, you can use `cxMempoolReigster2()` for simple pools, `cxMempoolRegister()` for pure pools, etc. +> +> When you use `cxMempoolReigster2()` the `data` pointer must not be `NULL` or the behavior will be undefined when the pool gets destroyed. + ### Order of Destruction When you call `cxMempoolFree()` the following actions are performed: -1. In any order, for each object in the pool +1. In any order, for each object allocated by the pool 1. the destructor function assigned to that object is called - 2. the object's memory is deallocated -2. The pool memory is deallocated -3. The pool structure is deallocated + 2. the pool's global simple destructor is called + 3. the pool's global advanced destructor is called + 4. the object's memory is deallocated +2. In any order, for each registered foreign object the destructor is called +3. The pool memory is deallocated +4. The pool structure is deallocated ## Transfer Memory @@ -75,11 +122,11 @@ The transferred allocator will be destroyed when the `dest` pool gets destroyed. The function `cxMempoolTransferObject()` transfers a _single_ object managed by the `source` pool to the `dest` pool. -Memory that was registered with `cxMempoolRegister()` cannot be transferred this way. -Also, if `obj` has a reference to `source->allocator`, it must be updated to `dest->allocator` manually. +In contrast to transferring an entire pool, if `obj` has a reference to `source->allocator`, it must be updated to `dest->allocator` manually. +It is also possible to transfer registered memory from one pool to another, this way. The functions returns zero when the transfer was successful and non-zero if a necessary memory allocation was not possible, -or the `source` and `dest` pointers point to the same pool. +the `source` and `dest` pointers point to the same pool, or the pools have different type (simple, advanced, pure). In case of an error, no memory is transferred and both pools are in a valid state.