#include #include #include /* See: https://8dcc.github.io/programming/pool-allocator.html */ /* See: https://github.com/8dcc/libpool */ #define CHUNK_SIZE 64 typedef union Chunk Chunk; union Chunk { Chunk *next; // When not null, it is used char arr[CHUNK_SIZE]; }; typedef struct LinkedPtr LinkedPtr; struct LinkedPtr { Chunk *ptr; LinkedPtr *next; }; typedef struct Pool Pool; struct Pool { Chunk *free_chunk; // Pointer to a linked list of free chunks LinkedPtr *array_starts; }; Pool *pool_new(size_t pool_size) { Pool *pool = malloc(sizeof(Pool)); if (pool == NULL) return NULL; Chunk *arr = pool->free_chunk = malloc(pool_size * sizeof(Chunk)); if (arr == NULL) { free(pool); return NULL; } for (size_t i = 0; i < pool_size - 1; i++) arr[i].next = &arr[i + 1]; arr[pool_size - 1].next = NULL; pool->array_starts = malloc(sizeof(LinkedPtr)); if (pool->array_starts == NULL) { /* Allocation failed */ free(arr); free(pool); return NULL; } pool->array_starts->next = NULL; pool->array_starts->ptr = arr; return pool; } void *pool_alloc(Pool *pool) { if (pool == NULL || pool->free_chunk == NULL) return NULL; // Pop a new one from the free list Chunk *result = pool->free_chunk; pool->free_chunk = pool->free_chunk->next; return result; } void pool_free(Pool *pool, void *ptr) { if (pool == NULL || ptr == NULL) return; // This can be done withuot an intermediate ptr Chunk *freed = ptr; freed->next = pool->free_chunk; pool->free_chunk = freed; } void pool_close(Pool *pool) { if (pool == NULL) return; LinkedPtr *lptr = pool->array_starts; while (lptr != NULL) { LinkedPtr *next = lptr->next; free(lptr->ptr); free(lptr); lptr = next; } free(pool); } bool pool_resize(Pool *pool, size_t extra_chunk_num) { if (pool == NULL || extra_chunk_num == 0) return false; // Allocate the array of extra chunks that we are trying to add to the pool. Chunk *extra_chunk_arr = malloc(extra_chunk_num * sizeof(Chunk)); if (extra_chunk_arr == NULL) return false; // Link the new chunks together, just like we did when creating the pool. for (size_t i = 0; i < extra_chunk_num - 1; i++) extra_chunk_arr[i].next = &extra_chunk_arr[i + 1]; // Prepend the array of extra chunks to the “free chunks” list, just like we // did when freeing chunks. extra_chunk_arr[extra_chunk_num - 1].next = pool->free_chunk; pool->free_chunk = extra_chunk_arr; // Allocate a new LinkedPtr structure, and store the start of the new chunk // array in it. LinkedPtr *array_start = malloc(sizeof(LinkedPtr)); if (array_start == NULL) { free(extra_chunk_arr); return false; } // Prepend this new LinkedPtr structure to the linked list of “array // starts”, stored inside the Pool structure. array_start->ptr = extra_chunk_arr; array_start->next = pool->array_starts; pool->array_starts = array_start; return true; }