ucx/mempool.c

branch
dav-2
changeset 886
da79af4baec8
parent 852
83fdf679df99
child 889
42cdbf9bbd49
equal deleted inserted replaced
885:591377a27fa3 886:da79af4baec8
29 #include "cx/mempool.h" 29 #include "cx/mempool.h"
30 30
31 #include <string.h> 31 #include <string.h>
32 #include <errno.h> 32 #include <errno.h>
33 33
34 struct cx_mempool_memory_s { 34 static int cx_mempool_ensure_capacity(
35 /** The destructor. */ 35 struct cx_mempool_s *pool,
36 cx_destructor_func destructor; 36 size_t needed_capacity
37 /** The actual memory. */ 37 ) {
38 char c[]; 38 if (needed_capacity <= pool->capacity) return 0;
39 }; 39 size_t newcap = pool->capacity >= 1000 ?
40 40 pool->capacity + 1000 : pool->capacity * 2;
41 static void *cx_mempool_malloc( 41 size_t newmsize;
42 // LCOV_EXCL_START
43 if (pool->capacity > newcap
44 || cx_szmul(newcap, sizeof(void*), &newmsize)) {
45 errno = EOVERFLOW;
46 return 1;
47 } // LCOV_EXCL_STOP
48 void **newdata = cxRealloc(pool->base_allocator, pool->data, newmsize);
49 if (newdata == NULL) return 1;
50 pool->data = newdata;
51 pool->capacity = newcap;
52 return 0;
53 }
54
55 static int cx_mempool_ensure_registered_capacity(
56 struct cx_mempool_s *pool,
57 size_t needed_capacity
58 ) {
59 if (needed_capacity <= pool->registered_capacity) return 0;
60 // we do not expect so many registrations
61 size_t newcap = pool->registered_capacity + 8;
62 size_t newmsize;
63 // LCOV_EXCL_START
64 if (pool->registered_capacity > newcap || cx_szmul(newcap,
65 sizeof(struct cx_mempool_foreign_memory_s), &newmsize)) {
66 errno = EOVERFLOW;
67 return 1;
68 } // LCOV_EXCL_STOP
69 void *newdata = cxRealloc(pool->base_allocator, pool->registered, newmsize);
70 if (newdata == NULL) return 1;
71 pool->registered = newdata;
72 pool->registered_capacity = newcap;
73 return 0;
74 }
75
76 static void *cx_mempool_malloc_simple(
42 void *p, 77 void *p,
43 size_t n 78 size_t n
44 ) { 79 ) {
45 struct cx_mempool_s *pool = p; 80 struct cx_mempool_s *pool = p;
46 81
47 if (pool->size >= pool->capacity) { 82 if (cx_mempool_ensure_capacity(pool, pool->size + 1)) {
48 size_t newcap = pool->capacity - (pool->capacity % 16) + 16; 83 return NULL; // LCOV_EXCL_LINE
49 size_t newmsize; 84 }
50 if (pool->capacity > newcap || cx_szmul(newcap, 85
51 sizeof(struct cx_mempool_memory_s*), &newmsize)) { 86 struct cx_mempool_memory_s *mem =
52 errno = EOVERFLOW; 87 cxMalloc(pool->base_allocator, sizeof(struct cx_mempool_memory_s) + n);
53 return NULL;
54 }
55 struct cx_mempool_memory_s **newdata = realloc(pool->data, newmsize);
56 if (newdata == NULL) return NULL;
57 pool->data = newdata;
58 pool->capacity = newcap;
59 }
60
61 struct cx_mempool_memory_s *mem = malloc(sizeof(cx_destructor_func) + n);
62 if (mem == NULL) return NULL; 88 if (mem == NULL) return NULL;
63 89 mem->destructor = NULL;
64 mem->destructor = pool->auto_destr;
65 pool->data[pool->size] = mem; 90 pool->data[pool->size] = mem;
66 pool->size++; 91 pool->size++;
67 92
68 return mem->c; 93 return mem->c;
69 } 94 }
70 95
71 static void *cx_mempool_calloc( 96 static void *cx_mempool_calloc_simple(
72 void *p, 97 void *p,
73 size_t nelem, 98 size_t nelem,
74 size_t elsize 99 size_t elsize
75 ) { 100 ) {
76 size_t msz; 101 size_t msz;
77 if (cx_szmul(nelem, elsize, &msz)) { 102 if (cx_szmul(nelem, elsize, &msz)) {
78 errno = EOVERFLOW; 103 errno = EOVERFLOW;
79 return NULL; 104 return NULL;
80 } 105 }
81 void *ptr = cx_mempool_malloc(p, msz); 106 void *ptr = cx_mempool_malloc_simple(p, msz);
82 if (ptr == NULL) return NULL; 107 if (ptr == NULL) return NULL;
83 memset(ptr, 0, nelem * elsize); 108 memset(ptr, 0, nelem * elsize);
84 return ptr; 109 return ptr;
85 } 110 }
86 111
87 static void *cx_mempool_realloc( 112 static void cx_mempool_free_simple(
113 void *p,
114 void *ptr
115 ) {
116 if (!ptr) return;
117 struct cx_mempool_s *pool = p;
118
119 struct cx_mempool_memory_s *mem =
120 (void*) ((char *) ptr - sizeof(struct cx_mempool_memory_s));
121
122 for (size_t i = 0; i < pool->size; i++) {
123 if (mem == pool->data[i]) {
124 if (mem->destructor) {
125 mem->destructor(mem->c);
126 }
127 if (pool->destr) {
128 pool->destr(mem->c);
129 }
130 if (pool->destr2) {
131 pool->destr2(pool->destr2_data, mem->c);
132 }
133 cxFree(pool->base_allocator, mem);
134 size_t last_index = pool->size - 1;
135 if (i != last_index) {
136 pool->data[i] = pool->data[last_index];
137 pool->data[last_index] = NULL;
138 }
139 pool->size--;
140 return;
141 }
142 }
143 abort(); // LCOV_EXCL_LINE
144 }
145
146 static void *cx_mempool_realloc_simple(
88 void *p, 147 void *p,
89 void *ptr, 148 void *ptr,
90 size_t n 149 size_t n
91 ) { 150 ) {
92 struct cx_mempool_s *pool = p; 151 if (ptr == NULL) {
93 152 return cx_mempool_malloc_simple(p, n);
94 struct cx_mempool_memory_s *mem, *newm; 153 }
95 mem = (struct cx_mempool_memory_s*)(((char *) ptr) - sizeof(cx_destructor_func)); 154 if (n == 0) {
96 newm = realloc(mem, n + sizeof(cx_destructor_func)); 155 cx_mempool_free_simple(p, ptr);
156 return NULL;
157 }
158 struct cx_mempool_s *pool = p;
159
160 const unsigned overhead = sizeof(struct cx_mempool_memory_s);
161 struct cx_mempool_memory_s *mem =
162 (void *) (((char *) ptr) - overhead);
163 struct cx_mempool_memory_s *newm =
164 cxRealloc(pool->base_allocator, mem, n + overhead);
97 165
98 if (newm == NULL) return NULL; 166 if (newm == NULL) return NULL;
99 if (mem != newm) { 167 if (mem != newm) {
100 for (size_t i = 0; i < pool->size; i++) { 168 for (size_t i = 0; i < pool->size; i++) {
101 if (pool->data[i] == mem) { 169 if (pool->data[i] == mem) {
102 pool->data[i] = newm; 170 pool->data[i] = newm;
103 return ((char*)newm) + sizeof(cx_destructor_func); 171 return ((char*)newm) + overhead;
104 } 172 }
105 } 173 }
106 abort(); // LCOV_EXCL_LINE 174 abort(); // LCOV_EXCL_LINE
107 } else { 175 } else {
108 return ptr; 176 // unfortunately glibc() realloc seems to always move
109 } 177 return ptr; // LCOV_EXCL_LINE
110 } 178 }
111 179 }
112 static void cx_mempool_free( 180
181 static void cx_mempool_free_all_simple(const struct cx_mempool_s *pool) {
182 const bool has_destr = pool->destr;
183 const bool has_destr2 = pool->destr2;
184 for (size_t i = 0; i < pool->size; i++) {
185 struct cx_mempool_memory_s *mem = pool->data[i];
186 if (mem->destructor) {
187 mem->destructor(mem->c);
188 }
189 if (has_destr) {
190 pool->destr(mem->c);
191 }
192 if (has_destr2) {
193 pool->destr2(pool->destr2_data, mem->c);
194 }
195 cxFree(pool->base_allocator, mem);
196 }
197 }
198
199 static cx_allocator_class cx_mempool_simple_allocator_class = {
200 cx_mempool_malloc_simple,
201 cx_mempool_realloc_simple,
202 cx_mempool_calloc_simple,
203 cx_mempool_free_simple
204 };
205
206 static void *cx_mempool_malloc_advanced(
207 void *p,
208 size_t n
209 ) {
210 struct cx_mempool_s *pool = p;
211
212 if (cx_mempool_ensure_capacity(pool, pool->size + 1)) {
213 return NULL; // LCOV_EXCL_LINE
214 }
215
216 struct cx_mempool_memory2_s *mem =
217 cxMalloc(pool->base_allocator, sizeof(struct cx_mempool_memory2_s) + n);
218 if (mem == NULL) return NULL;
219 mem->destructor = NULL;
220 mem->data = NULL;
221 pool->data[pool->size] = mem;
222 pool->size++;
223
224 return mem->c;
225 }
226
227 static void *cx_mempool_calloc_advanced(
228 void *p,
229 size_t nelem,
230 size_t elsize
231 ) {
232 size_t msz;
233 if (cx_szmul(nelem, elsize, &msz)) {
234 errno = EOVERFLOW;
235 return NULL;
236 }
237 void *ptr = cx_mempool_malloc_advanced(p, msz);
238 if (ptr == NULL) return NULL;
239 memset(ptr, 0, nelem * elsize);
240 return ptr;
241 }
242
243 static void cx_mempool_free_advanced(
113 void *p, 244 void *p,
114 void *ptr 245 void *ptr
115 ) { 246 ) {
116 if (!ptr) return; 247 if (!ptr) return;
117 struct cx_mempool_s *pool = p; 248 struct cx_mempool_s *pool = p;
118 249
119 struct cx_mempool_memory_s *mem = (struct cx_mempool_memory_s *) 250 struct cx_mempool_memory2_s *mem =
120 ((char *) ptr - sizeof(cx_destructor_func)); 251 (void*) ((char *) ptr - sizeof(struct cx_mempool_memory2_s));
121 252
122 for (size_t i = 0; i < pool->size; i++) { 253 for (size_t i = 0; i < pool->size; i++) {
123 if (mem == pool->data[i]) { 254 if (mem == pool->data[i]) {
124 if (mem->destructor) { 255 if (mem->destructor) {
125 mem->destructor(mem->c); 256 mem->destructor(mem->data, mem->c);
126 } 257 }
127 free(mem); 258 if (pool->destr) {
259 pool->destr(mem->c);
260 }
261 if (pool->destr2) {
262 pool->destr2(pool->destr2_data, mem->c);
263 }
264 cxFree(pool->base_allocator, mem);
128 size_t last_index = pool->size - 1; 265 size_t last_index = pool->size - 1;
129 if (i != last_index) { 266 if (i != last_index) {
130 pool->data[i] = pool->data[last_index]; 267 pool->data[i] = pool->data[last_index];
131 pool->data[last_index] = NULL; 268 pool->data[last_index] = NULL;
132 } 269 }
135 } 272 }
136 } 273 }
137 abort(); // LCOV_EXCL_LINE 274 abort(); // LCOV_EXCL_LINE
138 } 275 }
139 276
277 static void *cx_mempool_realloc_advanced(
278 void *p,
279 void *ptr,
280 size_t n
281 ) {
282 if (ptr == NULL) {
283 return cx_mempool_malloc_advanced(p, n);
284 }
285 if (n == 0) {
286 cx_mempool_free_advanced(p, ptr);
287 return NULL;
288 }
289 struct cx_mempool_s *pool = p;
290
291 const unsigned overhead = sizeof(struct cx_mempool_memory2_s);
292 struct cx_mempool_memory2_s *mem =
293 (void *) (((char *) ptr) - overhead);
294 struct cx_mempool_memory2_s *newm =
295 cxRealloc(pool->base_allocator, mem, n + overhead);
296
297 if (newm == NULL) return NULL;
298 if (mem != newm) {
299 for (size_t i = 0; i < pool->size; i++) {
300 if (pool->data[i] == mem) {
301 pool->data[i] = newm;
302 return ((char*)newm) + overhead;
303 }
304 }
305 abort(); // LCOV_EXCL_LINE
306 } else {
307 // unfortunately glibc() realloc seems to always move
308 return ptr; // LCOV_EXCL_LINE
309 }
310 }
311
312 static void cx_mempool_free_all_advanced(const struct cx_mempool_s *pool) {
313 const bool has_destr = pool->destr;
314 const bool has_destr2 = pool->destr2;
315 for (size_t i = 0; i < pool->size; i++) {
316 struct cx_mempool_memory2_s *mem = pool->data[i];
317 if (mem->destructor) {
318 mem->destructor(mem->data, mem->c);
319 }
320 if (has_destr) {
321 pool->destr(mem->c);
322 }
323 if (has_destr2) {
324 pool->destr2(pool->destr2_data, mem->c);
325 }
326 cxFree(pool->base_allocator, mem);
327 }
328 }
329
330 static cx_allocator_class cx_mempool_advanced_allocator_class = {
331 cx_mempool_malloc_advanced,
332 cx_mempool_realloc_advanced,
333 cx_mempool_calloc_advanced,
334 cx_mempool_free_advanced
335 };
336
337
338 static void *cx_mempool_malloc_pure(
339 void *p,
340 size_t n
341 ) {
342 struct cx_mempool_s *pool = p;
343
344 if (cx_mempool_ensure_capacity(pool, pool->size + 1)) {
345 return NULL; // LCOV_EXCL_LINE
346 }
347
348 void *mem = cxMalloc(pool->base_allocator, n);
349 if (mem == NULL) return NULL;
350 pool->data[pool->size] = mem;
351 pool->size++;
352
353 return mem;
354 }
355
356 static void *cx_mempool_calloc_pure(
357 void *p,
358 size_t nelem,
359 size_t elsize
360 ) {
361 size_t msz;
362 if (cx_szmul(nelem, elsize, &msz)) {
363 errno = EOVERFLOW;
364 return NULL;
365 }
366 void *ptr = cx_mempool_malloc_pure(p, msz);
367 if (ptr == NULL) return NULL;
368 memset(ptr, 0, nelem * elsize);
369 return ptr;
370 }
371
372 static void cx_mempool_free_pure(
373 void *p,
374 void *ptr
375 ) {
376 if (!ptr) return;
377 struct cx_mempool_s *pool = p;
378
379 for (size_t i = 0; i < pool->size; i++) {
380 if (ptr == pool->data[i]) {
381 if (pool->destr) {
382 pool->destr(ptr);
383 }
384 if (pool->destr2) {
385 pool->destr2(pool->destr2_data, ptr);
386 }
387 cxFree(pool->base_allocator, ptr);
388 size_t last_index = pool->size - 1;
389 if (i != last_index) {
390 pool->data[i] = pool->data[last_index];
391 pool->data[last_index] = NULL;
392 }
393 pool->size--;
394 return;
395 }
396 }
397 abort(); // LCOV_EXCL_LINE
398 }
399
400 static void *cx_mempool_realloc_pure(
401 void *p,
402 void *ptr,
403 size_t n
404 ) {
405 if (ptr == NULL) {
406 return cx_mempool_malloc_pure(p, n);
407 }
408 if (n == 0) {
409 cx_mempool_free_pure(p, ptr);
410 return NULL;
411 }
412 struct cx_mempool_s *pool = p;
413 void *newm = cxRealloc(pool->base_allocator, ptr, n);
414 if (newm == NULL) return NULL;
415 if (ptr != newm) {
416 for (size_t i = 0; i < pool->size; i++) {
417 if (pool->data[i] == ptr) {
418 pool->data[i] = newm;
419 return newm;
420 }
421 }
422 abort(); // LCOV_EXCL_LINE
423 } else {
424 // unfortunately glibc() realloc seems to always move
425 return ptr; // LCOV_EXCL_LINE
426 }
427 }
428
429 static void cx_mempool_free_all_pure(const struct cx_mempool_s *pool) {
430 const bool has_destr = pool->destr;
431 const bool has_destr2 = pool->destr2;
432 for (size_t i = 0; i < pool->size; i++) {
433 void *mem = pool->data[i];
434 if (has_destr) {
435 pool->destr(mem);
436 }
437 if (has_destr2) {
438 pool->destr2(pool->destr2_data, mem);
439 }
440 cxFree(pool->base_allocator, mem);
441 }
442 }
443
444 static cx_allocator_class cx_mempool_pure_allocator_class = {
445 cx_mempool_malloc_pure,
446 cx_mempool_realloc_pure,
447 cx_mempool_calloc_pure,
448 cx_mempool_free_pure
449 };
450
451 static void cx_mempool_free_foreign(const struct cx_mempool_s *pool) {
452 for (size_t i = 0; i < pool->registered_size; i++) {
453 struct cx_mempool_foreign_memory_s info = pool->registered[i];
454 if (info.destr2_data == NULL) {
455 if (info.destr) {
456 info.destr(info.mem);
457 }
458 } else {
459 info.destr2(info.destr2_data, info.mem);
460 }
461 }
462 }
463
140 void cxMempoolFree(CxMempool *pool) { 464 void cxMempoolFree(CxMempool *pool) {
141 if (pool == NULL) return; 465 if (pool == NULL) return;
142 struct cx_mempool_memory_s *mem; 466 if (pool->allocator->cl == &cx_mempool_simple_allocator_class) {
143 for (size_t i = 0; i < pool->size; i++) { 467 cx_mempool_free_all_simple(pool);
144 mem = pool->data[i]; 468 } else if (pool->allocator->cl == &cx_mempool_advanced_allocator_class) {
145 if (mem->destructor) { 469 cx_mempool_free_all_advanced(pool);
146 mem->destructor(mem->c); 470 } else {
147 } 471 cx_mempool_free_all_pure(pool);
148 free(mem); 472 }
149 } 473 cx_mempool_free_foreign(pool);
150 free(pool->data); 474 cxFree(pool->base_allocator, pool->data);
151 free((void*) pool->allocator); 475 cxFree(pool->base_allocator, pool->registered);
152 free(pool); 476 cxFree(pool->base_allocator, (void*) pool->allocator);
477 cxFree(pool->base_allocator, pool);
153 } 478 }
154 479
155 void cxMempoolSetDestructor( 480 void cxMempoolSetDestructor(
156 void *ptr, 481 void *ptr,
157 cx_destructor_func func 482 cx_destructor_func func
158 ) { 483 ) {
159 *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = func; 484 *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = func;
160 } 485 }
161 486
487 void cxMempoolSetDestructor2(
488 void *ptr,
489 cx_destructor_func2 func,
490 void *data
491 ) {
492 struct cx_mempool_memory2_s *info =
493 (void*)((char *) ptr - sizeof(struct cx_mempool_memory2_s));
494 info->destructor = func;
495 info->data = data;
496 }
497
162 void cxMempoolRemoveDestructor(void *ptr) { 498 void cxMempoolRemoveDestructor(void *ptr) {
163 *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = NULL; 499 *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = NULL;
164 } 500 }
165 501
166 struct cx_mempool_foreign_mem_s { 502 void cxMempoolRemoveDestructor2(void *ptr) {
167 cx_destructor_func destr; 503 struct cx_mempool_memory2_s *info =
168 void* mem; 504 (void*)((char *) ptr - sizeof(struct cx_mempool_memory2_s));
169 }; 505 info->destructor = NULL;
170 506 info->data = NULL;
171 static void cx_mempool_destr_foreign_mem(void* ptr) {
172 struct cx_mempool_foreign_mem_s *fm = ptr;
173 fm->destr(fm->mem);
174 } 507 }
175 508
176 int cxMempoolRegister( 509 int cxMempoolRegister(
177 CxMempool *pool, 510 CxMempool *pool,
178 void *memory, 511 void *memory,
179 cx_destructor_func destr 512 cx_destructor_func destr
180 ) { 513 ) {
181 struct cx_mempool_foreign_mem_s *fm = cx_mempool_malloc( 514 if (cx_mempool_ensure_registered_capacity(pool, pool->registered_size + 1)) {
182 pool, 515 return 1; // LCOV_EXCL_LINE
183 sizeof(struct cx_mempool_foreign_mem_s) 516 }
184 ); 517
185 if (fm == NULL) return 1; 518 pool->registered[pool->registered_size++] =
186 519 (struct cx_mempool_foreign_memory_s) {
187 fm->mem = memory; 520 .mem = memory,
188 fm->destr = destr; 521 .destr = destr,
189 *(cx_destructor_func *) ((char *) fm - sizeof(cx_destructor_func)) = cx_mempool_destr_foreign_mem; 522 .destr2_data = NULL
523 };
190 524
191 return 0; 525 return 0;
192 } 526 }
193 527
194 static cx_allocator_class cx_mempool_allocator_class = { 528 int cxMempoolRegister2(
195 cx_mempool_malloc, 529 CxMempool *pool,
196 cx_mempool_realloc, 530 void *memory,
197 cx_mempool_calloc, 531 cx_destructor_func2 destr,
198 cx_mempool_free 532 void *data
199 }; 533 ) {
534 if (cx_mempool_ensure_registered_capacity(pool, pool->registered_size + 1)) {
535 return 1; // LCOV_EXCL_LINE
536 }
537
538 pool->registered[pool->registered_size++] =
539 (struct cx_mempool_foreign_memory_s) {
540 .mem = memory,
541 .destr2 = destr,
542 .destr2_data = data
543 };
544
545 return 0;
546 }
200 547
201 CxMempool *cxMempoolCreate( 548 CxMempool *cxMempoolCreate(
202 size_t capacity, 549 size_t capacity,
203 cx_destructor_func destr 550 enum cx_mempool_type type
204 ) { 551 ) {
552 if (capacity == 0) capacity = 16;
205 size_t poolsize; 553 size_t poolsize;
206 if (cx_szmul(capacity, sizeof(struct cx_mempool_memory_s*), &poolsize)) { 554 if (cx_szmul(capacity, sizeof(void*), &poolsize)) {
555 // LCOV_EXCL_START
207 errno = EOVERFLOW; 556 errno = EOVERFLOW;
208 return NULL; 557 return NULL;
209 } 558 } // LCOV_EXCL_STOP
210 559
211 struct cx_mempool_s *pool = 560 CxAllocator *provided_allocator = cxMallocDefault(sizeof(CxAllocator));
212 malloc(sizeof(struct cx_mempool_s));
213 if (pool == NULL) return NULL;
214
215 CxAllocator *provided_allocator = malloc(sizeof(CxAllocator));
216 if (provided_allocator == NULL) { // LCOV_EXCL_START 561 if (provided_allocator == NULL) { // LCOV_EXCL_START
217 free(pool);
218 return NULL; 562 return NULL;
219 } // LCOV_EXCL_STOP 563 } // LCOV_EXCL_STOP
220 provided_allocator->cl = &cx_mempool_allocator_class; 564
565 CxMempool *pool = cxCallocDefault(1, sizeof(CxMempool));
566 if (pool == NULL) { // LCOV_EXCL_START
567 cxFreeDefault(provided_allocator);
568 return NULL;
569 } // LCOV_EXCL_STOP
570
221 provided_allocator->data = pool; 571 provided_allocator->data = pool;
222 572 *((const CxAllocator**)&pool->base_allocator) = cxDefaultAllocator;
223 pool->allocator = provided_allocator; 573 pool->allocator = provided_allocator;
224 574 if (type == CX_MEMPOOL_TYPE_SIMPLE) {
225 pool->data = malloc(poolsize); 575 provided_allocator->cl = &cx_mempool_simple_allocator_class;
576 } else if (type == CX_MEMPOOL_TYPE_ADVANCED) {
577 provided_allocator->cl = &cx_mempool_advanced_allocator_class;
578 } else {
579 provided_allocator->cl = &cx_mempool_pure_allocator_class;
580 }
581
582 pool->data = cxMallocDefault(poolsize);
226 if (pool->data == NULL) { // LCOV_EXCL_START 583 if (pool->data == NULL) { // LCOV_EXCL_START
227 free(provided_allocator); 584 cxFreeDefault(provided_allocator);
228 free(pool); 585 cxFreeDefault(pool);
229 return NULL; 586 return NULL;
230 } // LCOV_EXCL_STOP 587 } // LCOV_EXCL_STOP
231 588
232 pool->size = 0; 589 pool->size = 0;
233 pool->capacity = capacity; 590 pool->capacity = capacity;
234 pool->auto_destr = destr;
235 591
236 return pool; 592 return pool;
237 } 593 }
594
595 void cxMempoolGlobalDestructor(CxMempool *pool, cx_destructor_func fnc) {
596 pool->destr = fnc;
597 }
598
599 void cxMempoolGlobalDestructor2(CxMempool *pool, cx_destructor_func2 fnc, void *data) {
600 pool->destr2 = fnc;
601 pool->destr2_data = data;
602 }
603
604 static void cx_mempool_free_transferred_allocator(void *base_al, void *al) {
605 cxFree(base_al, al);
606 }
607
608 int cxMempoolTransfer(
609 CxMempool *source,
610 CxMempool *dest
611 ) {
612 // safety checks
613 if (source == dest) return 1;
614 if (source->allocator->cl != dest->allocator->cl) return 1;
615 if (source->base_allocator->cl != dest->base_allocator->cl) return 1;
616
617 // ensure enough capacity in the destination pool
618 if (cx_mempool_ensure_capacity(dest, dest->size + source->size)) {
619 return 1; // LCOV_EXCL_LINE
620 }
621 if (cx_mempool_ensure_registered_capacity(dest,
622 dest->registered_size + source->registered_size)) {
623 return 1; // LCOV_EXCL_LINE
624 }
625
626 // allocate a replacement allocator for the source pool
627 CxAllocator *new_source_allocator =
628 cxMalloc(source->base_allocator, sizeof(CxAllocator));
629 if (new_source_allocator == NULL) { // LCOV_EXCL_START
630 return 1;
631 } // LCOV_EXCL_STOP
632 new_source_allocator->cl = source->allocator->cl;
633 new_source_allocator->data = source;
634
635 // transfer all the data
636 if (source->size > 0) {
637 memcpy(&dest->data[dest->size], source->data,
638 sizeof(void*)*source->size);
639 dest->size += source->size;
640 }
641
642 // transfer all registered memory
643 if (source->registered_size > 0) {
644 memcpy(&dest->registered[dest->registered_size], source->registered,
645 sizeof(struct cx_mempool_foreign_memory_s)
646 * source->registered_size);
647 dest->registered_size += source->registered_size;
648 }
649
650 // register the old allocator with the new pool
651 // we have to remove const-ness for this, but that's okay here
652 // also register the base allocator, s.t. the pool knows how to free it
653 CxAllocator *transferred_allocator = (CxAllocator*) source->allocator;
654 transferred_allocator->data = dest;
655 cxMempoolRegister2(dest, transferred_allocator,
656 cx_mempool_free_transferred_allocator, (void*)source->base_allocator);
657
658 // prepare the source pool for re-use
659 source->allocator = new_source_allocator;
660 memset(source->data, 0, source->size * sizeof(void*));
661 memset(source->registered, 0,
662 source->registered_size * sizeof(struct cx_mempool_foreign_memory_s));
663 source->size = 0;
664 source->registered_size = 0;
665
666 return 0;
667 }
668
669 int cxMempoolTransferObject(
670 CxMempool *source,
671 CxMempool *dest,
672 const void *obj
673 ) {
674 // safety checks
675 if (source == dest) return 1;
676 if (source->allocator->cl != dest->allocator->cl) return 1;
677 if (source->base_allocator->cl != dest->base_allocator->cl) return 1;
678
679 // search for the object
680 for (size_t i = 0; i < source->size; i++) {
681 struct cx_mempool_memory_s *mem = source->data[i];
682 if (mem->c == obj) {
683 // first, make sure that the dest pool can take the object
684 if (cx_mempool_ensure_capacity(dest, dest->size + 1)) {
685 return 1; // LCOV_EXCL_LINE
686 }
687 // remove from the source pool
688 size_t last_index = source->size - 1;
689 if (i != last_index) {
690 source->data[i] = source->data[last_index];
691 source->data[last_index] = NULL;
692 }
693 source->size--;
694 // add to the target pool
695 dest->data[dest->size++] = mem;
696 return 0;
697 }
698 }
699 // search in the registered objects
700 for (size_t i = 0; i < source->registered_size; i++) {
701 struct cx_mempool_foreign_memory_s *mem = &source->registered[i];
702 if (mem->mem == obj) {
703 // first, make sure that the dest pool can take the object
704 if (cx_mempool_ensure_registered_capacity(dest,
705 dest->registered_size + 1)) {
706 return 1; // LCOV_EXCL_LINE
707 }
708 dest->registered[dest->registered_size++] = *mem;
709 // remove from the source pool
710 size_t last_index = source->registered_size - 1;
711 if (i != last_index) {
712 source->registered[i] = source->registered[last_index];
713 memset(&source->registered[last_index], 0,
714 sizeof(struct cx_mempool_foreign_memory_s));
715 }
716 source->registered_size--;
717 return 0;
718 }
719 }
720 // not found
721 return 1;
722 }

mercurial