src/mempool.c

changeset 1281
45746a08c59e
parent 1065
6eb7b54975ee
child 1283
89935fea4b7c
--- a/src/mempool.c	Fri Apr 11 09:15:21 2025 +0200
+++ b/src/mempool.c	Fri Apr 11 13:20:07 2025 +0200
@@ -38,24 +38,34 @@
     char c[];
 };
 
+static int cx_mempool_ensure_capacity(
+        struct cx_mempool_s *pool,
+        size_t needed_capacity
+) {
+    if (needed_capacity <= pool->capacity) return 0;
+    size_t newcap = pool->capacity >= 1000 ?
+        pool->capacity + 1000 : pool->capacity * 2;
+    size_t newmsize;
+    if (pool->capacity > newcap || cx_szmul(newcap,
+            sizeof(struct cx_mempool_memory_s*), &newmsize)) {
+        errno = EOVERFLOW;
+        return 1;
+    }
+    struct cx_mempool_memory_s **newdata = realloc(pool->data, newmsize);
+    if (newdata == NULL) return 1;
+    pool->data = newdata;
+    pool->capacity = newcap;
+    return 0;
+}
+
 static void *cx_mempool_malloc(
         void *p,
         size_t n
 ) {
     struct cx_mempool_s *pool = p;
 
-    if (pool->size >= pool->capacity) {
-        size_t newcap = pool->capacity - (pool->capacity % 16) + 16;
-        size_t newmsize;
-        if (pool->capacity > newcap || cx_szmul(newcap,
-                sizeof(struct cx_mempool_memory_s*), &newmsize)) {
-            errno = EOVERFLOW;
-            return NULL;
-        }
-        struct cx_mempool_memory_s **newdata = realloc(pool->data, newmsize);
-        if (newdata == NULL) return NULL;
-        pool->data = newdata;
-        pool->capacity = newcap;
+    if (cx_mempool_ensure_capacity(pool, pool->size + 1)) {
+        return NULL;
     }
 
     struct cx_mempool_memory_s *mem = malloc(sizeof(cx_destructor_func) + n);
@@ -235,3 +245,41 @@
 
     return pool;
 }
+
+int cxMempoolTransfer(
+        CxMempool *source,
+        CxMempool *dest
+) {
+    // safety check
+    if (source == dest) return 1;
+
+    // ensure enough capacity in the destination pool
+    if (cx_mempool_ensure_capacity(dest, dest->size + source->size + 1)) {
+        return 1;
+    }
+
+    // allocate a replacement allocator for the source pool
+    CxAllocator *new_source_allocator = malloc(sizeof(CxAllocator));
+    if (new_source_allocator == NULL) { // LCOV_EXCL_START
+        return 1;
+    } // LCOV_EXCL_STOP
+    new_source_allocator->cl = &cx_mempool_allocator_class;
+    new_source_allocator->data = source;
+
+    // transfer all the data
+    memcpy(&dest->data[dest->size], source->data, sizeof(source->data[0])*source->size);
+    dest->size += source->size;
+
+    // register the old allocator with the new pool
+    // we have to remove const-ness for this, but that's okay here
+    CxAllocator *transferred_allocator = (CxAllocator*) source->allocator;
+    transferred_allocator->data = dest;
+    cxMempoolRegister(dest, transferred_allocator, free);
+
+    // prepare the source pool for re-use
+    source->allocator = new_source_allocator;
+    memset(source->data, 0, source->size * sizeof(source->data[0]));
+    source->size = 0;
+
+    return 0;
+}

mercurial