Memory Pool
A memory pool is providing an allocator implementation that automatically deallocates the memory upon its destruction. It also allows you to register destructor functions for the allocated memory, which are automatically called before the memory is deallocated.
Additionally, you may also register independent destructor functions. This can be useful, for example, when some library allocates memory that you wish to destroy when the memory pool gets destroyed.
A memory pool can be used with all UCX features that support the use of an allocator. For example, the UCX string functions provide several variants suffixed with _a
for that purpose.
Overview
#include <cx/mempool.h>
CxMempool *cxMempoolCreate(size_t capacity, cx_destructor_func fnc);
CxMempool *cxMempoolCreateSimple(size_t capacity);
void cxMempoolFree(CxMempool *pool);
void cxMempoolSetDestructor(void *memory, cx_destructor_func fnc);
void cxMempoolRemoveDestructor(void *memory);
int cxMempoolRegister(CxMempool *pool, void *memory,
cx_destructor_func fnc);
Description
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.
After creating a memory pool CxMempool *mpool
, you can access the provided allocator via mpool->allocator
.
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. The memory
pointer points to the allocated object, which must have been allocated by any CxMempool
's provided allocator.
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, in which case a non-zero value is returned.
Order of Destruction
When you call cxMempoolFree()
the following actions are performed:
In any order, for each object in the pool
the destructor function assigned to that object is called
the object's memory is deallocated
The pool memory is deallocated
The pool structure is deallocated
Example
The following code illustrates how the contents of a CSV file are read into pooled memory.
#include <stdio.h>
#include <cx/mempool.h>
#include <cx/linked_list.h>
#include <cx/string.h>
#include <cx/buffer.h>
#include <cx/utils.h>
typedef struct {
cxstring column_a;
cxstring column_b;
cxstring column_c;
} CSVData;
int main(void) {
// create a simple pool for various different objects
CxMempool* pool = cxMempoolCreateSimple(128);
FILE *f = fopen("test.csv", "r");
if (f == NULL) {
perror("Cannot open file");
return 1;
}
// close the file automatically at pool destruction
cxMempoolRegister(pool, f, (cx_destructor_func) fclose);
// create a buffer using the memory pool for destruction
CxBuffer *content = cxBufferCreate(
NULL, 256, pool->allocator, CX_BUFFER_AUTO_EXTEND
);
// read the file into the buffer and turn it into a string
cx_stream_copy(
f, content, (cx_read_func) fread, cxBufferWriteFunc
);
fclose(f);
cxstring contentstr = cx_strn(content->space, content->size);
// split the string into lines
// use the memory pool to allocate the target array
cxstring* lines;
size_t lc = cx_strsplit_a(
pool->allocator, contentstr, cx_str("\n"), SIZE_MAX, &lines
);
// skip the header and parse the remaining data into a linked list
// the nodes of the list shall also be allocated by the pool
CxList* datalist = cxLinkedListCreate(
pool->allocator, NULL, sizeof(CSVData)
);
for (size_t i = 1 ; i < lc ; i++) {
if (lines[i].length == 0) continue;
cxstring fields[3];
size_t fc = cx_strsplit(lines[i], cx_str(";"), 3, fields);
if (fc != 3) {
fprintf(stderr, "Syntax error in line %zu.\n", i);
cxMempoolFree(pool);
return 1;
}
CSVData data;
data.column_a = fields[0];
data.column_b = fields[1];
data.column_c = fields[2];
cxListAdd(datalist, &data);
}
// iterate through the list and output the data
CxIterator iter = cxListIterator(datalist);
cx_foreach(CSVData*, data, iter) {
printf("Column A: %.*s | "
"Column B: %.*s | "
"Column C: %.*s\n",
(int)data->column_a.length, data->column_a.ptr,
(int)data->column_b.length, data->column_b.ptr,
(int)data->column_c.length, data->column_c.ptr
);
}
// cleanup everything, no manual free() needed
cxMempoolFree(pool);
return 0;
}
Last modified: 06 April 2025