#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef __cplusplus
#define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>
#include "mempool.h"
typedef struct {
ucx_destructor destructor;
char c;
} ucx_memchunk;
typedef struct {
ucx_destructor destructor;
void *ptr;
} ucx_regdestr;
UCX_EXTERN void ucx_mempool_shared_destr(
void* ptr) {
ucx_regdestr *rd = (ucx_regdestr*)ptr;
rd->destructor(rd->ptr);
}
UcxMempool *ucx_mempool_new(
size_t n) {
UcxMempool *pool = (UcxMempool*)malloc(
sizeof(UcxMempool));
if (!pool) {
return NULL;
}
pool->data = (
void**) malloc(n *
sizeof(
void*));
if (pool->data ==
NULL) {
free(pool);
return NULL;
}
pool->ndata =
0;
pool->size = n;
UcxAllocator *allocator = (UcxAllocator*)malloc(
sizeof(UcxAllocator));
if(!allocator) {
free(pool->data);
free(pool);
return NULL;
}
allocator->malloc = (ucx_allocator_malloc)ucx_mempool_malloc;
allocator->calloc = (ucx_allocator_calloc)ucx_mempool_calloc;
allocator->realloc = (ucx_allocator_realloc)ucx_mempool_realloc;
allocator->free = (ucx_allocator_free)ucx_mempool_free;
allocator->pool = pool;
pool->allocator = allocator;
return pool;
}
int ucx_mempool_chcap(UcxMempool *pool,
size_t newcap) {
void **data = (
void**) realloc(pool->data, newcap*
sizeof(
void*));
if (data) {
pool->data = data;
pool->size = newcap;
return EXIT_SUCCESS;
}
else {
return EXIT_FAILURE;
}
}
void *ucx_mempool_malloc(UcxMempool *pool,
size_t n) {
if (pool->ndata >= pool->size) {
if (ucx_mempool_chcap(pool, pool->size +
16) ==
EXIT_FAILURE) {
return NULL;
}
}
ucx_memchunk *mem = (ucx_memchunk*)malloc(
sizeof(ucx_destructor) + n);
if (!mem) {
return NULL;
}
mem->destructor =
NULL;
pool->data[pool->ndata] = mem;
pool->ndata++;
return &(mem->c);
}
void *ucx_mempool_calloc(UcxMempool *pool,
size_t nelem,
size_t elsize) {
void *ptr = ucx_mempool_malloc(pool, nelem*elsize);
if (!ptr) {
return NULL;
}
memset(ptr,
0, nelem * elsize);
return ptr;
}
void *ucx_mempool_realloc(UcxMempool *pool,
void *ptr,
size_t n) {
char *mem = ((
char*)ptr) -
sizeof(ucx_destructor);
char *newm = (
char*) realloc(mem, n +
sizeof(ucx_destructor));
if (!newm) {
return NULL;
}
if (mem != newm) {
for(
size_t i=
0 ; i < pool->ndata ; i++) {
if(pool->data[i] == mem) {
pool->data[i] = newm;
return newm +
sizeof(ucx_destructor);
}
}
fprintf(stderr,
"FATAL: 0x%08" " not in mpool 0x%08"PRIxPTR
"\n"PRIxPTR,
(
intptr_t)ptr, (
intptr_t)pool);
exit(
EXIT_FAILURE);
}
else {
return newm +
sizeof(ucx_destructor);
}
}
void ucx_mempool_free(UcxMempool *pool,
void *ptr) {
ucx_memchunk *chunk = (ucx_memchunk*)((
char*)ptr-
sizeof(ucx_destructor));
for(
size_t i=
0 ; i<pool->ndata ; i++) {
if(chunk == pool->data[i]) {
if(chunk->destructor !=
NULL) {
chunk->destructor(&(chunk->c));
}
free(chunk);
size_t last_index = pool->ndata -
1;
if(i != last_index) {
pool->data[i] = pool->data[last_index];
pool->data[last_index] =
NULL;
}
pool->ndata--;
return;
}
}
fprintf(stderr,
"FATAL: 0x%08" " not in mpool 0x%08"PRIxPTR
"\n"PRIxPTR,
(
intptr_t)ptr, (
intptr_t)pool);
exit(
EXIT_FAILURE);
}
void ucx_mempool_destroy(UcxMempool *pool) {
ucx_memchunk *chunk;
for(
size_t i=
0 ; i<pool->ndata ; i++) {
chunk = (ucx_memchunk*) pool->data[i];
if(chunk) {
if(chunk->destructor) {
chunk->destructor(&(chunk->c));
}
free(chunk);
}
}
free(pool->data);
free(pool->allocator);
free(pool);
}
void ucx_mempool_set_destr(
void *ptr, ucx_destructor func) {
*(ucx_destructor*)((
char*)ptr-
sizeof(ucx_destructor)) = func;
}
void ucx_mempool_reg_destr(UcxMempool *pool,
void *ptr, ucx_destructor destr) {
ucx_regdestr *rd = (ucx_regdestr*)ucx_mempool_malloc(
pool,
sizeof(ucx_regdestr));
rd->destructor = destr;
rd->ptr = ptr;
ucx_mempool_set_destr(rd, ucx_mempool_shared_destr);
}