#ifndef MEMPOOL_H #define MEMPOOL_H #ifndef MEMPOOL_OBJ_TYPE #define MEMPOOL_OBJ_TYPE int #endif #ifndef MEMPOOL_CAP #define MEMPOOL_CAP (1 << 16) #endif #define for_each_block(id, b, head) \ for(struct id##_block *b = (head), *next = NULL; \ b && (next = b->next, 1); b = next) #define get_last_block(b) \ while((b)->next != NULL) (b) = (b)->next #define MEMPOOL_GENERATE(id) \ \ struct id##_block { \ union id##_chunk { \ MEMPOOL_OBJ_TYPE obj; \ union id##_chunk *next; \ } chunks[MEMPOOL_CAP]; \ \ struct id##_block *next; \ }; \ \ static union id##_chunk *id##_ap = NULL; \ static struct id##_block id##_block; \ static size_t id##_allocations = 0; \ \ static inline void *_##id##_mempool_init_block(struct id##_block *b) \ { \ b->next = NULL; \ for(size_t i = 0; i < MEMPOOL_CAP; i++) \ b->chunks[i].next = &b->chunks[i+1]; \ b->chunks[MEMPOOL_CAP-1].next = NULL; \ \ return b->chunks; \ } \ \ static inline void *id##_mempool_allocate(void) \ { \ if(!id##_ap) { \ struct id##_block *new_block = &(id##_block); \ if((id##_allocations) > 0) { \ new_block = malloc(sizeof(*new_block)); \ struct id##_block *last_block = &(id##_block); \ get_last_block(last_block); \ last_block->next = new_block; \ } \ id##_ap = _##id##_mempool_init_block(new_block); \ } \ \ id##_allocations++; \ \ void *ptr = &(id##_ap)->obj; \ id##_ap = (id##_ap)->next; \ return ptr; \ } \ \ static inline void id##_mempool_free(void *ptr) \ { \ ((union id##_chunk *)ptr)->next = id##_ap; \ id##_ap = (union id##_chunk *)ptr; \ \ if(--id##_allocations == 0) { \ for_each_block(id, b, (id##_block).next) \ free(b); \ id##_ap = id##_block.chunks; \ } \ } \ #endif