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 |