| 49 if (pool->capacity > newcap || cx_szmul(newcap, |
49 if (pool->capacity > newcap || cx_szmul(newcap, |
| 50 sizeof(struct cx_mempool_memory_s*), &newmsize)) { |
50 sizeof(struct cx_mempool_memory_s*), &newmsize)) { |
| 51 errno = EOVERFLOW; |
51 errno = EOVERFLOW; |
| 52 return 1; |
52 return 1; |
| 53 } |
53 } |
| 54 struct cx_mempool_memory_s **newdata = realloc(pool->data, newmsize); |
54 struct cx_mempool_memory_s **newdata = cxRealloc( |
| |
55 cxDefaultAllocator, pool->data, newmsize); |
| 55 if (newdata == NULL) return 1; |
56 if (newdata == NULL) return 1; |
| 56 pool->data = newdata; |
57 pool->data = newdata; |
| 57 pool->capacity = newcap; |
58 pool->capacity = newcap; |
| 58 return 0; |
59 return 0; |
| 59 } |
60 } |
| 66 |
67 |
| 67 if (cx_mempool_ensure_capacity(pool, pool->size + 1)) { |
68 if (cx_mempool_ensure_capacity(pool, pool->size + 1)) { |
| 68 return NULL; |
69 return NULL; |
| 69 } |
70 } |
| 70 |
71 |
| 71 struct cx_mempool_memory_s *mem = malloc(sizeof(cx_destructor_func) + n); |
72 struct cx_mempool_memory_s *mem = cxMalloc( |
| |
73 cxDefaultAllocator, sizeof(cx_destructor_func) + n); |
| 72 if (mem == NULL) return NULL; |
74 if (mem == NULL) return NULL; |
| 73 |
75 |
| 74 mem->destructor = pool->auto_destr; |
76 mem->destructor = pool->auto_destr; |
| 75 pool->data[pool->size] = mem; |
77 pool->data[pool->size] = mem; |
| 76 pool->size++; |
78 pool->size++; |
| 101 ) { |
103 ) { |
| 102 struct cx_mempool_s *pool = p; |
104 struct cx_mempool_s *pool = p; |
| 103 |
105 |
| 104 struct cx_mempool_memory_s *mem, *newm; |
106 struct cx_mempool_memory_s *mem, *newm; |
| 105 mem = (struct cx_mempool_memory_s*)(((char *) ptr) - sizeof(cx_destructor_func)); |
107 mem = (struct cx_mempool_memory_s*)(((char *) ptr) - sizeof(cx_destructor_func)); |
| 106 newm = realloc(mem, n + sizeof(cx_destructor_func)); |
108 newm = cxRealloc(cxDefaultAllocator, mem, n + sizeof(cx_destructor_func)); |
| 107 |
109 |
| 108 if (newm == NULL) return NULL; |
110 if (newm == NULL) return NULL; |
| 109 if (mem != newm) { |
111 if (mem != newm) { |
| 110 for (size_t i = 0; i < pool->size; i++) { |
112 for (size_t i = 0; i < pool->size; i++) { |
| 111 if (pool->data[i] == mem) { |
113 if (pool->data[i] == mem) { |
| 132 for (size_t i = 0; i < pool->size; i++) { |
134 for (size_t i = 0; i < pool->size; i++) { |
| 133 if (mem == pool->data[i]) { |
135 if (mem == pool->data[i]) { |
| 134 if (mem->destructor) { |
136 if (mem->destructor) { |
| 135 mem->destructor(mem->c); |
137 mem->destructor(mem->c); |
| 136 } |
138 } |
| 137 free(mem); |
139 cxFree(cxDefaultAllocator, mem); |
| 138 size_t last_index = pool->size - 1; |
140 size_t last_index = pool->size - 1; |
| 139 if (i != last_index) { |
141 if (i != last_index) { |
| 140 pool->data[i] = pool->data[last_index]; |
142 pool->data[i] = pool->data[last_index]; |
| 141 pool->data[last_index] = NULL; |
143 pool->data[last_index] = NULL; |
| 142 } |
144 } |
| 153 for (size_t i = 0; i < pool->size; i++) { |
155 for (size_t i = 0; i < pool->size; i++) { |
| 154 mem = pool->data[i]; |
156 mem = pool->data[i]; |
| 155 if (mem->destructor) { |
157 if (mem->destructor) { |
| 156 mem->destructor(mem->c); |
158 mem->destructor(mem->c); |
| 157 } |
159 } |
| 158 free(mem); |
160 cxFree(cxDefaultAllocator, mem); |
| 159 } |
161 } |
| 160 free(pool->data); |
162 cxFree(cxDefaultAllocator, pool->data); |
| 161 free((void*) pool->allocator); |
163 cxFree(cxDefaultAllocator, (void*) pool->allocator); |
| 162 free(pool); |
164 cxFree(cxDefaultAllocator, pool); |
| 163 } |
165 } |
| 164 |
166 |
| 165 void cxMempoolSetDestructor( |
167 void cxMempoolSetDestructor( |
| 166 void *ptr, |
168 void *ptr, |
| 167 cx_destructor_func func |
169 cx_destructor_func func |
| 217 errno = EOVERFLOW; |
219 errno = EOVERFLOW; |
| 218 return NULL; |
220 return NULL; |
| 219 } |
221 } |
| 220 |
222 |
| 221 struct cx_mempool_s *pool = |
223 struct cx_mempool_s *pool = |
| 222 malloc(sizeof(struct cx_mempool_s)); |
224 cxMalloc(cxDefaultAllocator, sizeof(struct cx_mempool_s)); |
| 223 if (pool == NULL) return NULL; |
225 if (pool == NULL) return NULL; |
| 224 |
226 |
| 225 CxAllocator *provided_allocator = malloc(sizeof(CxAllocator)); |
227 CxAllocator *provided_allocator = cxMalloc(cxDefaultAllocator, sizeof(CxAllocator)); |
| 226 if (provided_allocator == NULL) { // LCOV_EXCL_START |
228 if (provided_allocator == NULL) { // LCOV_EXCL_START |
| 227 free(pool); |
229 cxFree(cxDefaultAllocator, pool); |
| 228 return NULL; |
230 return NULL; |
| 229 } // LCOV_EXCL_STOP |
231 } // LCOV_EXCL_STOP |
| 230 provided_allocator->cl = &cx_mempool_allocator_class; |
232 provided_allocator->cl = &cx_mempool_allocator_class; |
| 231 provided_allocator->data = pool; |
233 provided_allocator->data = pool; |
| 232 |
234 |
| 233 pool->allocator = provided_allocator; |
235 pool->allocator = provided_allocator; |
| 234 |
236 |
| 235 pool->data = malloc(poolsize); |
237 pool->data = cxMalloc(cxDefaultAllocator, poolsize); |
| 236 if (pool->data == NULL) { // LCOV_EXCL_START |
238 if (pool->data == NULL) { // LCOV_EXCL_START |
| 237 free(provided_allocator); |
239 cxFree(cxDefaultAllocator, provided_allocator); |
| 238 free(pool); |
240 cxFree(cxDefaultAllocator, pool); |
| 239 return NULL; |
241 return NULL; |
| 240 } // LCOV_EXCL_STOP |
242 } // LCOV_EXCL_STOP |
| 241 |
243 |
| 242 pool->size = 0; |
244 pool->size = 0; |
| 243 pool->capacity = capacity; |
245 pool->capacity = capacity; |
| 244 pool->auto_destr = destr; |
246 pool->auto_destr = destr; |
| 245 |
247 |
| 246 return pool; |
248 return pool; |
| 247 } |
249 } |
| 248 |
250 |
| |
251 static void cx_mempool_free_transferred_allocator(void *al) { |
| |
252 cxFree(cxDefaultAllocator, al); |
| |
253 } |
| |
254 |
| 249 int cxMempoolTransfer( |
255 int cxMempoolTransfer( |
| 250 CxMempool *source, |
256 CxMempool *source, |
| 251 CxMempool *dest |
257 CxMempool *dest |
| 252 ) { |
258 ) { |
| 253 // safety check |
259 // safety check |
| 257 if (cx_mempool_ensure_capacity(dest, dest->size + source->size + 1)) { |
263 if (cx_mempool_ensure_capacity(dest, dest->size + source->size + 1)) { |
| 258 return 1; // LCOV_EXCL_LINE |
264 return 1; // LCOV_EXCL_LINE |
| 259 } |
265 } |
| 260 |
266 |
| 261 // allocate a replacement allocator for the source pool |
267 // allocate a replacement allocator for the source pool |
| 262 CxAllocator *new_source_allocator = malloc(sizeof(CxAllocator)); |
268 CxAllocator *new_source_allocator = cxMalloc(cxDefaultAllocator, sizeof(CxAllocator)); |
| 263 if (new_source_allocator == NULL) { // LCOV_EXCL_START |
269 if (new_source_allocator == NULL) { // LCOV_EXCL_START |
| 264 return 1; |
270 return 1; |
| 265 } // LCOV_EXCL_STOP |
271 } // LCOV_EXCL_STOP |
| 266 new_source_allocator->cl = &cx_mempool_allocator_class; |
272 new_source_allocator->cl = &cx_mempool_allocator_class; |
| 267 new_source_allocator->data = source; |
273 new_source_allocator->data = source; |
| 272 |
278 |
| 273 // register the old allocator with the new pool |
279 // register the old allocator with the new pool |
| 274 // we have to remove const-ness for this, but that's okay here |
280 // we have to remove const-ness for this, but that's okay here |
| 275 CxAllocator *transferred_allocator = (CxAllocator*) source->allocator; |
281 CxAllocator *transferred_allocator = (CxAllocator*) source->allocator; |
| 276 transferred_allocator->data = dest; |
282 transferred_allocator->data = dest; |
| 277 cxMempoolRegister(dest, transferred_allocator, free); |
283 cxMempoolRegister(dest, transferred_allocator, cx_mempool_free_transferred_allocator); |
| 278 |
284 |
| 279 // prepare the source pool for re-use |
285 // prepare the source pool for re-use |
| 280 source->allocator = new_source_allocator; |
286 source->allocator = new_source_allocator; |
| 281 memset(source->data, 0, source->size * sizeof(source->data[0])); |
287 memset(source->data, 0, source->size * sizeof(source->data[0])); |
| 282 source->size = 0; |
288 source->size = 0; |