--- a/src/mempool.c Thu May 22 16:25:32 2025 +0200 +++ b/src/mempool.c Thu May 22 21:00:33 2025 +0200 @@ -186,6 +186,242 @@ } } +static cx_allocator_class cx_mempool_simple_allocator_class = { + cx_mempool_malloc_simple, + cx_mempool_realloc_simple, + cx_mempool_calloc_simple, + cx_mempool_free_simple +}; + +static void *cx_mempool_malloc_advanced( + void *p, + size_t n +) { + struct cx_mempool_s *pool = p; + + if (cx_mempool_ensure_capacity(pool, pool->size + 1)) { + return NULL; + } + + struct cx_mempool_memory2_s *mem = + cxMallocDefault(sizeof(struct cx_mempool_memory_s) + n); + if (mem == NULL) return NULL; + mem->destructor = NULL; + mem->data = NULL; + pool->data[pool->size] = mem; + pool->size++; + + return mem->c; +} + +static void *cx_mempool_calloc_advanced( + void *p, + size_t nelem, + size_t elsize +) { + size_t msz; + if (cx_szmul(nelem, elsize, &msz)) { + errno = EOVERFLOW; + return NULL; + } + void *ptr = cx_mempool_malloc_advanced(p, msz); + if (ptr == NULL) return NULL; + memset(ptr, 0, nelem * elsize); + return ptr; +} + +static void *cx_mempool_realloc_advanced( + void *p, + void *ptr, + size_t n +) { + struct cx_mempool_s *pool = p; + + const unsigned overhead = sizeof(struct cx_mempool_memory2_s); + struct cx_mempool_memory2_s *mem = + (void *) (((char *) ptr) - overhead); + struct cx_mempool_memory2_s *newm = + cxReallocDefault(mem, n + overhead); + + if (newm == NULL) return NULL; + if (mem != newm) { + for (size_t i = 0; i < pool->size; i++) { + if (pool->data[i] == mem) { + pool->data[i] = newm; + return ((char*)newm) + overhead; + } + } + abort(); // LCOV_EXCL_LINE + } else { + return ptr; + } +} + +static void cx_mempool_free_advanced( + void *p, + void *ptr +) { + if (!ptr) return; + struct cx_mempool_s *pool = p; + + struct cx_mempool_memory2_s *mem = + (void*) ((char *) ptr - sizeof(struct cx_mempool_memory2_s)); + + for (size_t i = 0; i < pool->size; i++) { + if (mem == pool->data[i]) { + if (mem->destructor) { + mem->destructor(mem->data, mem->c); + } + if (pool->destr) { + pool->destr(mem->c); + } + if (pool->destr2) { + pool->destr2(pool->destr2_data, mem->c); + } + cxFreeDefault(mem); + size_t last_index = pool->size - 1; + if (i != last_index) { + pool->data[i] = pool->data[last_index]; + pool->data[last_index] = NULL; + } + pool->size--; + return; + } + } + abort(); // LCOV_EXCL_LINE +} + +static void cx_mempool_free_all_advanced(const struct cx_mempool_s *pool) { + const bool has_destr = pool->destr; + const bool has_destr2 = pool->destr2; + for (size_t i = 0; i < pool->size; i++) { + struct cx_mempool_memory2_s *mem = pool->data[i]; + if (mem->destructor) { + mem->destructor(mem->data, mem->c); + } + if (has_destr) { + pool->destr(mem->c); + } + if (has_destr2) { + pool->destr2(pool->destr2_data, mem->c); + } + cxFreeDefault(mem); + } +} + +static cx_allocator_class cx_mempool_advanced_allocator_class = { + cx_mempool_malloc_advanced, + cx_mempool_realloc_advanced, + cx_mempool_calloc_advanced, + cx_mempool_free_advanced +}; + + +static void *cx_mempool_malloc_pure( + void *p, + size_t n +) { + struct cx_mempool_s *pool = p; + + if (cx_mempool_ensure_capacity(pool, pool->size + 1)) { + return NULL; + } + + void *mem = cxMallocDefault(n); + if (mem == NULL) return NULL; + pool->data[pool->size] = mem; + pool->size++; + + return mem; +} + +static void *cx_mempool_calloc_pure( + void *p, + size_t nelem, + size_t elsize +) { + size_t msz; + if (cx_szmul(nelem, elsize, &msz)) { + errno = EOVERFLOW; + return NULL; + } + void *ptr = cx_mempool_malloc_pure(p, msz); + if (ptr == NULL) return NULL; + memset(ptr, 0, nelem * elsize); + return ptr; +} + +static void *cx_mempool_realloc_pure( + void *p, + void *ptr, + size_t n +) { + struct cx_mempool_s *pool = p; + void *newm = cxReallocDefault(ptr, n); + if (newm == NULL) return NULL; + if (ptr != newm) { + for (size_t i = 0; i < pool->size; i++) { + if (pool->data[i] == ptr) { + pool->data[i] = newm; + return newm; + } + } + abort(); // LCOV_EXCL_LINE + } else { + return ptr; + } +} + +static void cx_mempool_free_pure( + void *p, + void *ptr +) { + if (!ptr) return; + struct cx_mempool_s *pool = p; + + for (size_t i = 0; i < pool->size; i++) { + if (ptr == pool->data[i]) { + if (pool->destr) { + pool->destr(ptr); + } + if (pool->destr2) { + pool->destr2(pool->destr2_data, ptr); + } + cxFreeDefault(ptr); + size_t last_index = pool->size - 1; + if (i != last_index) { + pool->data[i] = pool->data[last_index]; + pool->data[last_index] = NULL; + } + pool->size--; + return; + } + } + abort(); // LCOV_EXCL_LINE +} + +static void cx_mempool_free_all_pure(const struct cx_mempool_s *pool) { + const bool has_destr = pool->destr; + const bool has_destr2 = pool->destr2; + for (size_t i = 0; i < pool->size; i++) { + void *mem = pool->data[i]; + if (has_destr) { + pool->destr(mem); + } + if (has_destr2) { + pool->destr2(pool->destr2_data, mem); + } + cxFreeDefault(mem); + } +} + +static cx_allocator_class cx_mempool_pure_allocator_class = { + cx_mempool_malloc_pure, + cx_mempool_realloc_pure, + cx_mempool_calloc_pure, + cx_mempool_free_pure +}; + static void cx_mempool_free_foreign(const struct cx_mempool_s *pool) { for (size_t i = 0; i < pool->registered_size; i++) { struct cx_mempool_foreign_memory_s info = pool->registered[i]; @@ -199,19 +435,14 @@ } } -static cx_allocator_class cx_mempool_simple_allocator_class = { - cx_mempool_malloc_simple, - cx_mempool_realloc_simple, - cx_mempool_calloc_simple, - cx_mempool_free_simple -}; - void cxMempoolFree(CxMempool *pool) { if (pool == NULL) return; if (pool->allocator->cl == &cx_mempool_simple_allocator_class) { cx_mempool_free_all_simple(pool); + } else if (pool->allocator->cl == &cx_mempool_advanced_allocator_class) { + cx_mempool_free_all_advanced(pool); } else { - // TODO: implement + cx_mempool_free_all_pure(pool); } cx_mempool_free_foreign(pool); cxFreeDefault(pool->data); @@ -227,10 +458,28 @@ *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = func; } +void cxMempoolSetDestructor2( + void *ptr, + cx_destructor_func2 func, + void *data +) { + struct cx_mempool_memory2_s *info = + (void*)((char *) ptr - sizeof(struct cx_mempool_memory2_s)); + info->destructor = func; + info->data = data; +} + void cxMempoolRemoveDestructor(void *ptr) { *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = NULL; } +void cxMempoolRemoveDestructor2(void *ptr) { + struct cx_mempool_memory2_s *info = + (void*)((char *) ptr - sizeof(struct cx_mempool_memory2_s)); + info->destructor = NULL; + info->data = NULL; +} + int cxMempoolRegister( CxMempool *pool, void *memory, @@ -250,6 +499,26 @@ return 0; } +int cxMempoolRegister2( + CxMempool *pool, + void *memory, + cx_destructor_func2 destr, + void *data +) { + if (cx_mempool_ensure_registered_capacity(pool, pool->registered_size + 1)) { + return 1; // LCOV_EXCL_LINE + } + + pool->registered[pool->registered_size++] = + (struct cx_mempool_foreign_memory_s) { + .mem = memory, + .destr2 = destr, + .destr2_data = data + }; + + return 0; +} + CxMempool *cxMempoolCreate( size_t capacity, enum cx_mempool_type type @@ -277,9 +546,9 @@ if (type == CX_MEMPOOL_TYPE_SIMPLE) { provided_allocator->cl = &cx_mempool_simple_allocator_class; } else if (type == CX_MEMPOOL_TYPE_ADVANCED) { - // TODO: implement + provided_allocator->cl = &cx_mempool_advanced_allocator_class; } else { - // TODO: implement + provided_allocator->cl = &cx_mempool_pure_allocator_class; } pool->data = cxMallocDefault(poolsize);