docs/Writerside/topics/allocator.h.md

changeset 1188
b0300de92b72
parent 1174
ee473780cc0d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/Writerside/topics/allocator.h.md	Tue Feb 11 19:55:32 2025 +0100
@@ -0,0 +1,147 @@
+# Allocator
+
+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
+#include <cx/allocator.h>
+
+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;
+```
+
+> 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 custom data. An example is shown below:
+
+```c
+
+struct my_allocator_state {
+    // ... some internal state ...
+};
+
+static cx_allocator_class my_allocator_class = {
+        my_malloc_impl,
+        my_realloc_impl, // all these functions are somewhere defined
+        my_calloc_impl,
+        my_free_impl
+};
+
+CxAllocator create_my_allocator(void) {
+    CxAllocator alloc;
+    alloc.cl = &my_allocator_class;
+    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);
+}
+```
+
+When you are implementing 
+
+## Destructor Functions
+
+The `allocator.h` header also declares two function pointers for destructor functions.
+
+```C
+typedef void (*cx_destructor_func)(void *memory);
+typedef void (*cx_destructor_func2)(void *data, void *memory);
+```
+
+The first one is called _simple_ destructor (e.g. in the context of [collections](collection.h.md)),
+and the second one is called _advanced_ destructor.
+The only difference is that you can pass additional custom `data` to an advanced destructor function.
+
+Destructor functions play a vital role in deep de-allocations.
+Another scenarios, besides destroying elements in a collection, are the de-allocation of objects
+stored in a [memory pool](mempool.h.md) or de-allocations of deeply nested [JSON](json.h.md) objects.
+
+> Destructor functions are not to be confused with `free()`-like functions.
+> The fundamental differences are that 
+> * it is not safe to pass `NULL` to a destructor function
+> * a destructor may only de-allocate the contents inside an object but not the object itself, depending on context
+>
+{style="note"}
+
+> For example, when you are using a [list](list.h.md) that stores elements directly, a destructor function
+> assigned to that collection may only destroy the element's contents but must not deallocate the element's memory.
+> On the other hand, when the list is storing just pointers to the elements, you _may_ want the destructor
+> function to also de-allocate the element's memory when the element is removed from that list.
+
+<seealso>
+<category ref="apidoc">
+<a href="https://ucx.sourceforge.io/api/allocator_8h.html">allocator.h</a>
+</category>
+</seealso>

mercurial