# HG changeset patch # User Mike Becker # Date 1748001624 -7200 # Node ID 343eac5ac8245e2abcc65adafe851926dc361978 # Parent 2cf66dee40b888e9cc114a02cf8b19be4eb686ab add base allocator to mempool otherwise, mempools could not be used as new default allocators diff -r 2cf66dee40b8 -r 343eac5ac824 docs/Writerside/topics/mempool.h.md --- a/docs/Writerside/topics/mempool.h.md Fri May 23 13:36:11 2025 +0200 +++ b/docs/Writerside/topics/mempool.h.md Fri May 23 14:00:24 2025 +0200 @@ -125,9 +125,13 @@ In contrast to transferring an entire pool, if `obj` has a reference to `source->allocator`, it must be updated to `dest->allocator` manually. It is also possible to transfer registered memory from one pool to another, this way. -The functions returns zero when the transfer was successful and non-zero if a necessary memory allocation was not possible, -the `source` and `dest` pointers point to the same pool, or the pools have different type (simple, advanced, pure). -In case of an error, no memory is transferred and both pools are in a valid state. +The functions return zero when the transfer was successful, and non-zero under one of the following error conditions: +- a necessary memory allocation was not possible +- the `source` and `dest` pointers point to the same pool +- the pools have a different type (simple, advanced, pure) +- the pools have different base allocators (i.e. `cxDefaultAllocator` changed between creation of the pools) + +In case of an error, no memory is transferred and both pools remain unchanged and are in a valid state. ## Example diff -r 2cf66dee40b8 -r 343eac5ac824 src/cx/mempool.h --- a/src/cx/mempool.h Fri May 23 13:36:11 2025 +0200 +++ b/src/cx/mempool.h Fri May 23 14:00:24 2025 +0200 @@ -98,6 +98,9 @@ * Should be the first member of an actual memory pool implementation. */ struct cx_mempool_s { + /** The used allocator, initialized with the cxDefaultAllocator. */ + const CxAllocator * const base_allocator; + /** The provided allocator. */ const CxAllocator *allocator; diff -r 2cf66dee40b8 -r 343eac5ac824 src/mempool.c --- a/src/mempool.c Fri May 23 13:36:11 2025 +0200 +++ b/src/mempool.c Fri May 23 14:00:24 2025 +0200 @@ -45,7 +45,7 @@ errno = EOVERFLOW; return 1; } // LCOV_EXCL_STOP - void **newdata = cxReallocDefault(pool->data, newmsize); + void **newdata = cxRealloc(pool->base_allocator, pool->data, newmsize); if (newdata == NULL) return 1; pool->data = newdata; pool->capacity = newcap; @@ -66,7 +66,7 @@ errno = EOVERFLOW; return 1; } // LCOV_EXCL_STOP - void *newdata = cxReallocDefault(pool->registered, newmsize); + void *newdata = cxRealloc(pool->base_allocator, pool->registered, newmsize); if (newdata == NULL) return 1; pool->registered = newdata; pool->registered_capacity = newcap; @@ -84,7 +84,7 @@ } struct cx_mempool_memory_s *mem = - cxMallocDefault(sizeof(struct cx_mempool_memory_s) + n); + cxMalloc(pool->base_allocator, sizeof(struct cx_mempool_memory_s) + n); if (mem == NULL) return NULL; mem->destructor = NULL; pool->data[pool->size] = mem; @@ -130,7 +130,7 @@ if (pool->destr2) { pool->destr2(pool->destr2_data, mem->c); } - cxFreeDefault(mem); + cxFree(pool->base_allocator, mem); size_t last_index = pool->size - 1; if (i != last_index) { pool->data[i] = pool->data[last_index]; @@ -161,7 +161,7 @@ struct cx_mempool_memory_s *mem = (void *) (((char *) ptr) - overhead); struct cx_mempool_memory_s *newm = - cxReallocDefault(mem, n + overhead); + cxRealloc(pool->base_allocator, mem, n + overhead); if (newm == NULL) return NULL; if (mem != newm) { @@ -192,7 +192,7 @@ if (has_destr2) { pool->destr2(pool->destr2_data, mem->c); } - cxFreeDefault(mem); + cxFree(pool->base_allocator, mem); } } @@ -214,7 +214,7 @@ } struct cx_mempool_memory2_s *mem = - cxMallocDefault(sizeof(struct cx_mempool_memory2_s) + n); + cxMalloc(pool->base_allocator, sizeof(struct cx_mempool_memory2_s) + n); if (mem == NULL) return NULL; mem->destructor = NULL; mem->data = NULL; @@ -261,7 +261,7 @@ if (pool->destr2) { pool->destr2(pool->destr2_data, mem->c); } - cxFreeDefault(mem); + cxFree(pool->base_allocator, mem); size_t last_index = pool->size - 1; if (i != last_index) { pool->data[i] = pool->data[last_index]; @@ -292,7 +292,7 @@ struct cx_mempool_memory2_s *mem = (void *) (((char *) ptr) - overhead); struct cx_mempool_memory2_s *newm = - cxReallocDefault(mem, n + overhead); + cxRealloc(pool->base_allocator, mem, n + overhead); if (newm == NULL) return NULL; if (mem != newm) { @@ -323,7 +323,7 @@ if (has_destr2) { pool->destr2(pool->destr2_data, mem->c); } - cxFreeDefault(mem); + cxFree(pool->base_allocator, mem); } } @@ -345,7 +345,7 @@ return NULL; // LCOV_EXCL_LINE } - void *mem = cxMallocDefault(n); + void *mem = cxMalloc(pool->base_allocator, n); if (mem == NULL) return NULL; pool->data[pool->size] = mem; pool->size++; @@ -384,7 +384,7 @@ if (pool->destr2) { pool->destr2(pool->destr2_data, ptr); } - cxFreeDefault(ptr); + cxFree(pool->base_allocator, ptr); size_t last_index = pool->size - 1; if (i != last_index) { pool->data[i] = pool->data[last_index]; @@ -410,7 +410,7 @@ return NULL; } struct cx_mempool_s *pool = p; - void *newm = cxReallocDefault(ptr, n); + void *newm = cxRealloc(pool->base_allocator, ptr, n); if (newm == NULL) return NULL; if (ptr != newm) { for (size_t i = 0; i < pool->size; i++) { @@ -437,7 +437,7 @@ if (has_destr2) { pool->destr2(pool->destr2_data, mem); } - cxFreeDefault(mem); + cxFree(pool->base_allocator, mem); } } @@ -471,10 +471,10 @@ cx_mempool_free_all_pure(pool); } cx_mempool_free_foreign(pool); - cxFreeDefault(pool->data); - cxFreeDefault(pool->registered); - cxFreeDefault((void*) pool->allocator); - cxFreeDefault(pool); + cxFree(pool->base_allocator, pool->data); + cxFree(pool->base_allocator, pool->registered); + cxFree(pool->base_allocator, (void*) pool->allocator); + cxFree(pool->base_allocator, pool); } void cxMempoolSetDestructor( @@ -569,6 +569,7 @@ } // LCOV_EXCL_STOP provided_allocator->data = pool; + *((const CxAllocator**)&pool->base_allocator) = cxDefaultAllocator; pool->allocator = provided_allocator; if (type == CX_MEMPOOL_TYPE_SIMPLE) { provided_allocator->cl = &cx_mempool_simple_allocator_class; @@ -600,8 +601,8 @@ pool->destr2_data = data; } -static void cx_mempool_free_transferred_allocator(void *al) { - cxFreeDefault(al); +static void cx_mempool_free_transferred_allocator(void *base_al, void *al) { + cxFree(base_al, al); } int cxMempoolTransfer( @@ -611,6 +612,7 @@ // safety checks if (source == dest) return 1; if (source->allocator->cl != dest->allocator->cl) return 1; + if (source->base_allocator->cl != dest->base_allocator->cl) return 1; // ensure enough capacity in the destination pool if (cx_mempool_ensure_capacity(dest, dest->size + source->size)) { @@ -622,7 +624,8 @@ } // allocate a replacement allocator for the source pool - CxAllocator *new_source_allocator = cxMallocDefault(sizeof(CxAllocator)); + CxAllocator *new_source_allocator = + cxMalloc(source->base_allocator, sizeof(CxAllocator)); if (new_source_allocator == NULL) { // LCOV_EXCL_START return 1; } // LCOV_EXCL_STOP @@ -640,10 +643,11 @@ // register the old allocator with the new pool // we have to remove const-ness for this, but that's okay here + // also register the base allocator, s.t. the pool knows how to free it CxAllocator *transferred_allocator = (CxAllocator*) source->allocator; transferred_allocator->data = dest; - cxMempoolRegister(dest, transferred_allocator, - cx_mempool_free_transferred_allocator); + cxMempoolRegister2(dest, transferred_allocator, + cx_mempool_free_transferred_allocator, (void*)source->base_allocator); // prepare the source pool for re-use source->allocator = new_source_allocator; @@ -661,8 +665,10 @@ CxMempool *dest, const void *obj ) { - // safety check + // safety checks if (source == dest) return 1; + if (source->allocator->cl != dest->allocator->cl) return 1; + if (source->base_allocator->cl != dest->base_allocator->cl) return 1; // search for the object for (size_t i = 0; i < source->size; i++) {