| 13 ## Basic Memory Management |
13 ## Basic Memory Management |
| 14 |
14 |
| 15 ```C |
15 ```C |
| 16 #include <cx/mempool.h> |
16 #include <cx/mempool.h> |
| 17 |
17 |
| 18 CxMempool *cxMempoolCreate(size_t capacity, cx_destructor_func fnc); |
18 enum cx_mempool_type { |
| |
19 CX_MEMPOOL_TYPE_SIMPLE, |
| |
20 CX_MEMPOOL_TYPE_ADVANCED, |
| |
21 CX_MEMPOOL_TYPE_PURE, |
| |
22 }; |
| |
23 |
| |
24 CxMempool *cxMempoolCreate(size_t capacity, |
| |
25 enum cx_mempool_type type); |
| 19 |
26 |
| 20 CxMempool *cxMempoolCreateSimple(size_t capacity); |
27 CxMempool *cxMempoolCreateSimple(size_t capacity); |
| |
28 CxMempool *cxMempoolCreateAdvanced(size_t capacity); |
| |
29 CxMempool *cxMempoolCreatePure(size_t capacity); |
| 21 |
30 |
| 22 void cxMempoolFree(CxMempool *pool); |
31 void cxMempoolFree(CxMempool *pool); |
| 23 |
32 |
| 24 void cxMempoolSetDestructor(void *memory, cx_destructor_func fnc); |
33 void cxMempoolGlobalDestructor(CxMempool *pool, |
| |
34 cx_destructor_func fnc); |
| |
35 |
| |
36 void cxMempoolGlobalDestructor2(CxMempool *pool, |
| |
37 cx_destructor_func2 fnc, void *data); |
| |
38 |
| |
39 void cxMempoolSetDestructor(void *memory, |
| |
40 cx_destructor_func fnc); |
| |
41 |
| |
42 void cxMempoolSetDestructor2(void *memory, |
| |
43 cx_destructor_func fnc, void *data); |
| 25 |
44 |
| 26 void cxMempoolRemoveDestructor(void *memory); |
45 void cxMempoolRemoveDestructor(void *memory); |
| 27 |
46 |
| |
47 void cxMempoolRemoveDestructor2(void *memory); |
| |
48 |
| 28 int cxMempoolRegister(CxMempool *pool, void *memory, |
49 int cxMempoolRegister(CxMempool *pool, void *memory, |
| 29 cx_destructor_func fnc); |
50 cx_destructor_func fnc); |
| |
51 |
| |
52 int cxMempoolRegister2(CxMempool *pool, void *memory, |
| |
53 cx_destructor_func fnc, void *data); |
| 30 ``` |
54 ``` |
| 31 |
55 |
| 32 A memory pool is created with the `cxMempoolCreate()` function with a default `capacity` |
56 A memory pool is created with the `cxMempoolCreate()` family of functions with a default `capacity`. |
| 33 and an optional default destructor function `fnc`. |
57 If `capacity` is set to zero, an implementation default is used. |
| 34 If specified, the default destructor function is registered for all freshly allocated memory within the pool, |
58 |
| 35 as if `cxMempoolSetDestructor()` was called immediately after allocation. |
59 The `type` specifies how much additional data is allocated for each pooled memory block. |
| 36 When you set `fnc` is to `NULL` during pool creation, or use `cxMempoolCreateSimple`, no default destructor is registered. |
60 A simple pool reserves memory for an optional `cx_destructor_func`. |
| 37 |
61 An advanced pool reserves memory for an optional `cx_destructor_func2` |
| 38 After creating a memory pool `CxMempool *mpool`, you can access the provided allocator via `mpool->allocator`. |
62 and an additional `data` pointer that will be passed to that destructor. |
| 39 |
63 A pure pool does not reserve any additional data and therefore does not support registering |
| 40 The functions `cxMempoolSetDestructor()` and `cxMempoolRemoveDestructor()` can be used to assign a specific destructor |
64 custom destructors with the allocated memory. |
| 41 function to an allocated object or remove any assigned destructor function, respectively. |
65 |
| |
66 > After creating a memory pool `CxMempool *mpool`, you can access the provided allocator via `mpool->allocator`. |
| |
67 >{style="note"} |
| |
68 |
| |
69 The functions `cxMempoolGlobalDestructor()` and `cxMempoolGlobalDestructor2()` can be used to specify destructor functions |
| |
70 that shall be invoked for _all_ objects allocated by the pool when they are freed (see [](#order-of-destruction)). |
| |
71 This is usually only useful for pools that will only contain objects of the same type. |
| |
72 |
| |
73 In _simple_ memory pools, the two functions `cxMempoolSetDestructor()` and `cxMempoolRemoveDestructor()` can be used to assign a specific destructor |
| |
74 function to an allocated object or remove an assigned destructor function, respectively. |
| 42 The `memory` pointer points to the allocated object, which must have been allocated by any `CxMempool`'s provided allocator. |
75 The `memory` pointer points to the allocated object, which must have been allocated by any `CxMempool`'s provided allocator. |
| 43 |
76 For _advanced_ pools, the functions `cxMempoolSetDestructor2()` and `cxMempoolRemoveDestructor2()` do the same. |
| 44 The `cxMempoolRegister()` function allocates a new wrapper object for `memory` with `pool`'s allocator that |
77 It is disallowed to use the functions with a pool of the wrong type and will most likely cause undefined behavior. |
| 45 will call the specified destructor function when destroyed. |
78 Pure pools do not allow setting destructors for individual memory blocks at all. |
| 46 Usually this function returns zero except for platforms where memory allocations are likely to fail, |
79 |
| |
80 The `cxMempoolRegister()` function allocates a new wrapper object for `memory` |
| |
81 and makes the specified destructor function being called when the pool gets destroyed. |
| |
82 Alternatively, the `cxMempoolRegister2()` function can be used to register an advanced destructor and a pointer to custom data. |
| |
83 Be aware that the memory pointed to by the additional data pointer must remain valid until the pool gets destroyed! |
| |
84 Usually these functions return zero except for platforms where memory allocations are likely to fail, |
| 47 in which case a non-zero value is returned. |
85 in which case a non-zero value is returned. |
| 48 |
86 |
| |
87 > When you register foreign memory with a pool, you can decide which destructor type you want to use, |
| |
88 > regardless of the pool's type. |
| |
89 > That means, for example, you can use `cxMempoolReigster2()` for simple pools, `cxMempoolRegister()` for pure pools, etc. |
| |
90 > |
| |
91 > When you use `cxMempoolReigster2()` the `data` pointer must not be `NULL` or the behavior will be undefined when the pool gets destroyed. |
| |
92 |
| 49 ### Order of Destruction |
93 ### Order of Destruction |
| 50 |
94 |
| 51 When you call `cxMempoolFree()` the following actions are performed: |
95 When you call `cxMempoolFree()` the following actions are performed: |
| 52 |
96 |
| 53 1. In any order, for each object in the pool |
97 1. In any order, for each object allocated by the pool |
| 54 1. the destructor function assigned to that object is called |
98 1. the destructor function assigned to that object is called |
| 55 2. the object's memory is deallocated |
99 2. the pool's global simple destructor is called |
| 56 2. The pool memory is deallocated |
100 3. the pool's global advanced destructor is called |
| 57 3. The pool structure is deallocated |
101 4. the object's memory is deallocated |
| |
102 2. In any order, for each registered foreign object the destructor is called |
| |
103 3. The pool memory is deallocated |
| |
104 4. The pool structure is deallocated |
| 58 |
105 |
| 59 ## Transfer Memory |
106 ## Transfer Memory |
| 60 |
107 |
| 61 ```C |
108 ```C |
| 62 #include <cx/mempool.h> |
109 #include <cx/mempool.h> |
| 73 It also registers its allocator with the `dest` pool and creates a new allocator for the `source` pool. |
120 It also registers its allocator with the `dest` pool and creates a new allocator for the `source` pool. |
| 74 That means, that all references to the allocator of the `source` pool remain valid and continue to work with the `dest` pool. |
121 That means, that all references to the allocator of the `source` pool remain valid and continue to work with the `dest` pool. |
| 75 The transferred allocator will be destroyed when the `dest` pool gets destroyed. |
122 The transferred allocator will be destroyed when the `dest` pool gets destroyed. |
| 76 |
123 |
| 77 The function `cxMempoolTransferObject()` transfers a _single_ object managed by the `source` pool to the `dest` pool. |
124 The function `cxMempoolTransferObject()` transfers a _single_ object managed by the `source` pool to the `dest` pool. |
| 78 Memory that was registered with `cxMempoolRegister()` cannot be transferred this way. |
125 In contrast to transferring an entire pool, if `obj` has a reference to `source->allocator`, it must be updated to `dest->allocator` manually. |
| 79 Also, if `obj` has a reference to `source->allocator`, it must be updated to `dest->allocator` manually. |
126 It is also possible to transfer registered memory from one pool to another, this way. |
| 80 |
127 |
| 81 The functions returns zero when the transfer was successful and non-zero if a necessary memory allocation was not possible, |
128 The functions returns zero when the transfer was successful and non-zero if a necessary memory allocation was not possible, |
| 82 or the `source` and `dest` pointers point to the same pool. |
129 the `source` and `dest` pointers point to the same pool, or the pools have different type (simple, advanced, pure). |
| 83 In case of an error, no memory is transferred and both pools are in a valid state. |
130 In case of an error, no memory is transferred and both pools are in a valid state. |
| 84 |
131 |
| 85 |
132 |
| 86 ## Example |
133 ## Example |
| 87 |
134 |