#ifndef MEMPOOL_H #define MEMPOOL_H /* To generate use MEMPOOL_GENERATE(id, type, cap), where functions * _mempool_allocate() and _mempool_free(type *obj) will be prefixed with * and can be used to allocate objects of type with objects in * each block */ #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, type, cap) \ \ struct id##_block { \ union id##_chunk { \ type obj; \ union id##_chunk *next; \ } chunks[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 < cap; i++) \ b->chunks[i].next = &b->chunks[i+1]; \ b->chunks[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