Sat, 08 Feb 2025 14:13:59 +0100
add documentation for allocator.h
relates to #451
--- a/docs/Writerside/topics/allocator.h.md Fri Feb 07 17:55:28 2025 +0100 +++ b/docs/Writerside/topics/allocator.h.md Sat Feb 08 14:13:59 2025 +0100 @@ -1,51 +1,114 @@ # Allocator -<warning> -Outdated - Rewrite! -</warning> +The allocator interface provides a mechanism to implement own custom allocators +that can also be used in many other function in UCX. + +A default allocator implementation using the stdlib functions is +available via the global symbol `cxDefaultAllocator` +and UCX also provides a [memory pool](mempool.h.md) implementation. +You are free to add additional own custom implementations. +A general sketch that illustrates how to do this can be found [below](#custom-allocator). + +## Overview + +```C +void *cxMalloc(const CxAllocator *allocator, size_t n); + +void *cxCalloc(const CxAllocator *allocator, + size_t nmemb, size_t size); + +void *cxRealloc(const CxAllocator *allocator, void *mem, size_t n); + +void *cxReallocArray(const CxAllocator *allocator, void *mem, + size_t nmemb, size_t size); + +int cxReallocate(const CxAllocator *allocator, void **mem, size_t n); + +int cxReallocateArray(const CxAllocator *allocator, void **mem, + size_t nmemb, size_t size); + +void cxFree(const CxAllocator *allocator, void *mem); + +int cx_reallocate(void **mem, size_t size); + +int cx_reallocatearray(void **mem, size_t nmemb, size_t size); + +// predefined allocator that uses stdlib functions +CxAllocator *cxDefaultAllocator; +``` -The UCX allocator provides an interface for implementing an own memory allocation mechanism. -Various function in UCX provide an additional alternative signature that takes an allocator as -argument. A default allocator implementation using the stdlib memory management functions is -available via the global symbol `cxDefaultAllocator`. +> All UCX functions that are not _explicitly_ designed for taking an allocator argument +> (recognizable by a `_a` suffix in the function's name) do support a `NULL` argument +> in which case the `cxDefaultAllocator` will be used. + +## Description + +The functions `cxMalloc()`, `cxCalloc()`, `cxRealloc()`, `cxReallocArray()`, and `cxFree()` +invoke the memory management functions specified in the `allocator` and should behave like +their respective stdlibc pendants. +Implementations of the allocator interface are strongly encouraged to guarantee this behavior, +most prominently that invocations of `cxFree()` with a `NULL`-pointer for `mem` are ignored +instead of causing segfault error. + +Additionally, UCX provides the functions `cxReallocate()` and `cxReallocateArray()`, as well as +their independent pendants `cx_reallocate()` and `cx_reallocatearray()`. +All those functions solve the problem that a possible reallocation might fail, +leading to a quite common programming mistake: + +```C +// common mistake - mem will be lost hen realloc() returns NULL +mem = realloc(mem, capacity + 32); +if (mem == NULL) // ... do error handling +``` + +The above code can be replaced with `cx_reallocate()` which keeps the pointer intact and returns an error code instead. + +```C +// when cx_reallocate() fails, mem will still point to the old memory +if (cx_reallocate(&mem, capacity + 32)) // ... do error handling +``` + +> Please pay special attention to always use `cxFree()` and the `cxRealloc()`-family of functions +> with the **same** allocator that was used to allocate the memory. +{style="warning"} + +## Custom Allocator If you want to define your own allocator, you need to initialize the `CxAllocator` structure with a pointer to an allocator class (containing function pointers for the memory management -functions) and an optional pointer to an arbitrary memory region that can be used to store -state information for the allocator. An example is shown below: +functions) and an optional pointer to custom data. An example is shown below: ```c + struct my_allocator_state { - size_t total; - size_t avail; - char mem[]; + // ... some internal state ... }; static cx_allocator_class my_allocator_class = { my_malloc_impl, - my_realloc_impl, // all these functions are somewhere defined + my_realloc_impl, // all these functions are somewhere defined my_calloc_impl, my_free_impl }; -CxAllocator create_my_allocator(size_t n) { +CxAllocator create_my_allocator(void) { CxAllocator alloc; alloc.cl = &my_allocator_class; - alloc.data = calloc(1, sizeof(struct my_allocator_state) + n); + struct my_allocator_state *state = malloc(sizeof(*state)); + // ... initialize state ... + alloc.data = state; return alloc; } + +void destroy_my_allocator(CxAllocator *al) { + struct my_allocator_state *state = al->state; + // ... destroy state -- + free(state); +} ``` -## Undocumented Symbols (TODO) - -### cxCalloc -### cx_default_allocator -### cxDefaultAllocator -### cxFree -### cxMalloc -### cxRealloc -### cxReallocArray -### cx_reallocate_ -### cxReallocate_ -### cx_reallocatearray_ -### cxReallocateArray_ +<seealso> +<category ref="apidoc"> +<a href="https://ucx.sourceforge.io/api/allocator_8h.html">allocator.h</a> +</category> +</seealso>
--- a/src/allocator.c Fri Feb 07 17:55:28 2025 +0100 +++ b/src/allocator.c Sat Feb 08 14:13:59 2025 +0100 @@ -47,10 +47,10 @@ static void *cx_calloc_stdlib( cx_attr_unused void *d, - size_t nelem, - size_t n + size_t nmemb, + size_t size ) { - return calloc(nelem, n); + return calloc(nmemb, size); } static void cx_free_stdlib( @@ -169,10 +169,10 @@ void *cxCalloc( const CxAllocator *allocator, - size_t nelem, - size_t n + size_t nmemb, + size_t size ) { - return allocator->cl->calloc(allocator->data, nelem, n); + return allocator->cl->calloc(allocator->data, nmemb, size); } void cxFree(
--- a/src/cx/allocator.h Fri Feb 07 17:55:28 2025 +0100 +++ b/src/cx/allocator.h Sat Feb 08 14:13:59 2025 +0100 @@ -65,8 +65,8 @@ */ void *(*calloc)( void *data, - size_t nelem, - size_t n + size_t nmemb, + size_t size ); /** @@ -386,11 +386,11 @@ cxReallocateArray_(allocator, (void**) (mem), nmemb, size) /** - * Allocate @p nelem elements of @p n bytes each, all initialized to zero. + * Allocate @p nmemb elements of @p n bytes each, all initialized to zero. * * @param allocator the allocator - * @param nelem the number of elements - * @param n the size of each element in bytes + * @param nmemb the number of elements + * @param size the size of each element in bytes * @return a pointer to the allocated memory */ cx_attr_nonnull_arg(1) @@ -400,8 +400,8 @@ cx_attr_allocsize(2, 3) void *cxCalloc( const CxAllocator *allocator, - size_t nelem, - size_t n + size_t nmemb, + size_t size ); #ifdef __cplusplus