#include #include #include #include "c_Alignment.h" /* ------------------------------------------------------------------------------------------------------------------ */ /* */ #define FREE(x) do{ \ if(x){ \ free(x); \ (x) = NULL; \ } \ }while(0) #define ALLOC(x) malloc(x) #define NEW(p) (p)=ALLOC(sizeof(*(p))) #define DEFAULT_CHUNK_SIZE 10 /* ------------------------------------------------------------------------------------------------------------------ */ /* */ typedef struct c_PoolBlockLink_t { void* block; struct c_PoolBlockLink_t* next; }c_PoolBlockLink_t; struct c_PoolBlockList_t{ c_PoolBlockLink_t* list; }; /* ------------------------------------------------------------------------------------------------------------------ */ /* */ C_STATIC_FORCE_INLINE void c_PoolBlockLink_Init(c_PoolBlockLink_t* self, void* p, c_PoolBlockLink_t* next) { self->block = p; self->next = next; } C_STATIC_FORCE_INLINE void c_PoolBlockList_Init(c_PoolBlockList_t* self) { self->list = NULL; } C_STATIC_FORCE_INLINE void c_PoolBlockList_Destroy(c_PoolBlockList_t* self) { if (!self) return; while (self->list){ c_PoolBlockLink_t* q = self->list; self->list = q->next; FREE(q); } } C_STATIC_FORCE_INLINE void* c_PoolBlockList_Alloc(c_PoolBlockList_t* self, c_size_t bytes) { c_size_t block_size = bytes + sizeof(c_PoolBlockLink_t); block_size = C_ALIGN_UPB(block_size, C_ALIGN_SIZE); c_PoolBlockLink_t* p = ALLOC(block_size); if (!p) { return NULL; } c_PoolBlockLink_Init(p, p+1, self->list); self->list = p; return p->block; } C_STATIC_FORCE_INLINE c_err_t c_Pool_Replenish(c_Pool_t* self) { c_size_t size = self->chunkSize * self->objSize; uint8_t* start = (uint8_t*)c_PoolBlockList_Alloc(self->blockAllocator, size); if (!start) return C_ERR_NOMEM; uint8_t* last = &start[(self->chunkSize - 1) * self->objSize]; for (uint8_t* p = start; pobjSize) { ((struct c_PoolLink_t*)p)->next = (struct c_PoolLink_t*)(p + self->objSize); } ((struct c_PoolLink_t*)last)->next = NULL; self->freelist = (struct c_PoolLink_t*)start; return C_ERR_SUCCESS; } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ c_err_t c_Pool_Init(c_Pool_t* self, int objSize, int chunkSize) { self->freelist = 0; self->objSize = objSize>=sizeof(struct c_PoolLink_t)?objSize:sizeof(struct c_PoolLink_t); self->chunkSize = (chunkSize > 0)?chunkSize:DEFAULT_CHUNK_SIZE; self->instanceCount = 0; NEW(self->blockAllocator); if (!self->blockAllocator) { return C_ERR_NOMEM; } c_PoolBlockList_Init(self->blockAllocator); return C_ERR_SUCCESS; } void c_Pool_Destroy(c_Pool_t* self) { if (0==self->instanceCount) { c_PoolBlockList_Destroy(self->blockAllocator); FREE(self->blockAllocator); self->freelist = NULL; } assert(0==self->instanceCount); } void* c_Pool_Alloc(c_Pool_t* self) { if (!self->freelist) { if (c_Pool_Replenish(self)!=C_ERR_SUCCESS) { return NULL; } } struct c_PoolLink_t* p = self->freelist; self->freelist = p->next; ++self->instanceCount; return p; } void c_Pool_Free(c_Pool_t* self, void* ptr) { if (!self || !ptr) { return; } struct c_PoolLink_t* p = (struct c_PoolLink_t*)ptr; p->next = self->freelist; self->freelist = p; --self->instanceCount; } void c_Pool_DryUp(c_Pool_t* self) { c_PoolBlockList_Destroy(self->blockAllocator); FREE(self->blockAllocator); self->instanceCount = 0; }