docs/Writerside/topics/mempool.h.md

changeset 1188
b0300de92b72
parent 1174
ee473780cc0d
--- /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 <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:
+
+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 <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;
+} 
+```
+
+<seealso>
+<category ref="apidoc">
+<a href="https://ucx.sourceforge.io/api/mempool_8h.html">mempool.h</a>
+</category>
+</seealso>

mercurial