diff -r 0f70bb04f7ba -r b0300de92b72 docs/Writerside/topics/mempool.h.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/Writerside/topics/mempool.h.md Tue Feb 11 19:55:32 2025 +0100 @@ -0,0 +1,153 @@ +# 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](allocator.h.md). +For example, the UCX [string](string.h.md) functions provide several variants suffixed with `_a` for that purpose. + +## Overview + +```C +#include + +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: + +1. In any order, for each object in 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 + +## Example + +The following code illustrates how the contents of a CSV file are read into pooled memory. +```C +#include +#include +#include +#include +#include +#include + +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; +} +``` + + + +mempool.h + +