# Allocator
The allocator interface provides a mechanism to implement own custom allocators
that can also be used in many other functions in UCX.
A default allocator implementation using the stdlib functions is
available via the global symbol `cxStdlibAllocator`,
and UCX also provides a [memory pool](mempool.h.md) implementation.
You are free to add your additional, own custom implementations.
A general sketch that illustrates how to do this can be found [below](#custom-allocator).
## Default Allocator
The global default allocator which is used by UCX
when no specific allocator is specified
can be configured via the `cxDefaultAllocator`.
It is by default set to the `cxStdlibAllocator`.
## Overview
```C
#include <cx/allocator.h>
void *cxMalloc(const CxAllocator *allocator, size_t n);
void *cxZalloc(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);
void cx_system_page_size(void);
void *cx_zalloc(size_t n);
int cx_reallocate(void **mem, size_t n);
int cx_reallocatearray(void **mem, size_t nmemb, size_t size);
// predefined allocator that uses stdlib functions
CxAllocator * const cxStdlibAllocator;
// default allocator that can be changed
CxAllocator *cxDefaultAllocator = cxStdlibAllocator;
// convenience macros that invoke the above with cxDefaultAllocator
#define cxMallocDefault(...)
#define cxZallocDefault(...)
#define cxCallocDefault(...)
#define cxReallocDefault(...)
#define cxReallocateDefault(...)
#define cxReallocateArrayDefault(...)
#define cxReallocArrayDefault(...)
#define cxFreeDefault(...)
```
> 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.
>
> You may change the default allocator at any time, but it is strongly recommended to
> do it only once at program start to avoid accidentally freeing memory that was
> allocated by a different allocator.
## 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.
The functions `cxZalloc()` and `cx_zalloc()` allocate memory and set every allocated byte to zero.
The latter is merely a macro for stdlibc `calloc(1,n)`.
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"}
The function `cx_system_page_size()` offers a cross-platform way to retrieve the memory page size in bytes.
If, for some reason, the page size cannot be determined, a default of 4096 bytes is returned.
## 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
#include <cx/allocator.h>
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 deallocations.
Another scenario, besides destroying elements in a collection, is the deallocation of objects
stored in a [memory pool](mempool.h.md) or deallocations 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 deallocate 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 deallocate the element's memory when the element is removed from that list.
## Clone Function
```C
#include <cx/allocator.h>
typedef void*(cx_clone_func)(
void *target, const void *source,
const CxAllocator *allocator,
void *data);
```
A clone function is a callback invoked when a deep copy of an object is supposed to be made.
If `target` is not `NULL`, memory for the first level was already allocated, and only the deeper levels need to
be allocated by the clone function.
If `target` is `NULL`, the clone function must allocate all memory.
The `source` pointer is never `NULL` and points to the source object.
The optional `data` pointer can be used to pass additional state.
All allocations should be performed by the specified allocator, which is guaranteed to be not `NULL`.
A very basic clone function that performs a deep copy of a struct with two strings is shown below.
```C
#include <cx/string.h>
#include <cx/allocator.h>
struct kv_pair {
cxmutstr key;
cxmutstr value;
};
void *clone_kv_pair(
void *target, const void *source,
const CxAllocator *allocator,
[[maybe_unused]] void *data) {
const struct kv_pair *src = source;
struct kv_pair *dst;
if (target == NULL) {
dst = cxMalloc(allocator, sizeof(struct kv_pair));
} else {
dst = target;
}
dst->key = cx_strdup_a(allocator, src->key);
dst->value = cx_strdup_a(allocator, src->value);
return dst;
}
```
Clone functions are, for example, used by the functions to clone [lists](list.h.md#clone) or [maps](map.h.md#clone).
<seealso>
<category ref="apidoc">
<a href="https://ucx.sourceforge.io/api/allocator_8h.html">allocator.h</a>
</category>
</seealso>