src/mempool.c

changeset 1281
45746a08c59e
parent 1065
6eb7b54975ee
child 1283
89935fea4b7c
equal deleted inserted replaced
1280:60123b3db06e 1281:45746a08c59e
36 cx_destructor_func destructor; 36 cx_destructor_func destructor;
37 /** The actual memory. */ 37 /** The actual memory. */
38 char c[]; 38 char c[];
39 }; 39 };
40 40
41 static int cx_mempool_ensure_capacity(
42 struct cx_mempool_s *pool,
43 size_t needed_capacity
44 ) {
45 if (needed_capacity <= pool->capacity) return 0;
46 size_t newcap = pool->capacity >= 1000 ?
47 pool->capacity + 1000 : pool->capacity * 2;
48 size_t newmsize;
49 if (pool->capacity > newcap || cx_szmul(newcap,
50 sizeof(struct cx_mempool_memory_s*), &newmsize)) {
51 errno = EOVERFLOW;
52 return 1;
53 }
54 struct cx_mempool_memory_s **newdata = realloc(pool->data, newmsize);
55 if (newdata == NULL) return 1;
56 pool->data = newdata;
57 pool->capacity = newcap;
58 return 0;
59 }
60
41 static void *cx_mempool_malloc( 61 static void *cx_mempool_malloc(
42 void *p, 62 void *p,
43 size_t n 63 size_t n
44 ) { 64 ) {
45 struct cx_mempool_s *pool = p; 65 struct cx_mempool_s *pool = p;
46 66
47 if (pool->size >= pool->capacity) { 67 if (cx_mempool_ensure_capacity(pool, pool->size + 1)) {
48 size_t newcap = pool->capacity - (pool->capacity % 16) + 16; 68 return NULL;
49 size_t newmsize;
50 if (pool->capacity > newcap || cx_szmul(newcap,
51 sizeof(struct cx_mempool_memory_s*), &newmsize)) {
52 errno = EOVERFLOW;
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 } 69 }
60 70
61 struct cx_mempool_memory_s *mem = malloc(sizeof(cx_destructor_func) + n); 71 struct cx_mempool_memory_s *mem = malloc(sizeof(cx_destructor_func) + n);
62 if (mem == NULL) return NULL; 72 if (mem == NULL) return NULL;
63 73
233 pool->capacity = capacity; 243 pool->capacity = capacity;
234 pool->auto_destr = destr; 244 pool->auto_destr = destr;
235 245
236 return pool; 246 return pool;
237 } 247 }
248
249 int cxMempoolTransfer(
250 CxMempool *source,
251 CxMempool *dest
252 ) {
253 // safety check
254 if (source == dest) return 1;
255
256 // ensure enough capacity in the destination pool
257 if (cx_mempool_ensure_capacity(dest, dest->size + source->size + 1)) {
258 return 1;
259 }
260
261 // allocate a replacement allocator for the source pool
262 CxAllocator *new_source_allocator = malloc(sizeof(CxAllocator));
263 if (new_source_allocator == NULL) { // LCOV_EXCL_START
264 return 1;
265 } // LCOV_EXCL_STOP
266 new_source_allocator->cl = &cx_mempool_allocator_class;
267 new_source_allocator->data = source;
268
269 // transfer all the data
270 memcpy(&dest->data[dest->size], source->data, sizeof(source->data[0])*source->size);
271 dest->size += source->size;
272
273 // register the old allocator with the new pool
274 // we have to remove const-ness for this, but that's okay here
275 CxAllocator *transferred_allocator = (CxAllocator*) source->allocator;
276 transferred_allocator->data = dest;
277 cxMempoolRegister(dest, transferred_allocator, free);
278
279 // prepare the source pool for re-use
280 source->allocator = new_source_allocator;
281 memset(source->data, 0, source->size * sizeof(source->data[0]));
282 source->size = 0;
283
284 return 0;
285 }

mercurial