diff --git a/docs/allocator/cf_destroy_memory_pool.md b/docs/allocator/cf_destroy_memory_pool.md index 1abfa7a84..02a73c1f0 100644 --- a/docs/allocator/cf_destroy_memory_pool.md +++ b/docs/allocator/cf_destroy_memory_pool.md @@ -19,13 +19,8 @@ Parameters | Description --- | --- pool | The pool to destroy. -## Remarks - -Does not clean up any allocations that overflowed to `malloc` backup. See [cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md) for more details. - ## Related Pages [cf_make_memory_pool](/allocator/cf_make_memory_pool.md) [cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md) -[cf_memory_pool_try_alloc](/allocator/cf_memory_pool_try_alloc.md) [cf_memory_pool_free](/allocator/cf_memory_pool_free.md) diff --git a/docs/allocator/cf_make_memory_pool.md b/docs/allocator/cf_make_memory_pool.md index 38c25d6f0..90415b722 100644 --- a/docs/allocator/cf_make_memory_pool.md +++ b/docs/allocator/cf_make_memory_pool.md @@ -29,5 +29,4 @@ Returns a memory pool pointer. [cf_destroy_memory_pool](/allocator/cf_destroy_memory_pool.md) [cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md) -[cf_memory_pool_try_alloc](/allocator/cf_memory_pool_try_alloc.md) [cf_memory_pool_free](/allocator/cf_memory_pool_free.md) diff --git a/docs/allocator/cf_memory_pool_alloc.md b/docs/allocator/cf_memory_pool_alloc.md index 219135799..1bd447bef 100644 --- a/docs/allocator/cf_memory_pool_alloc.md +++ b/docs/allocator/cf_memory_pool_alloc.md @@ -23,15 +23,8 @@ pool | The pool. Returns an aligned pointer of `size` bytes. -## Remarks - -Attempts to allocate from the internal pool. If the pool is empty a call to `malloc` is made as a backup. All -backup allocations are not tracked anywhere, so you must call [cf_memory_pool_free](/allocator/cf_memory_pool_free.md) on each allocation to be -sure they all properly cleaned up. - ## Related Pages [cf_make_memory_pool](/allocator/cf_make_memory_pool.md) [cf_destroy_memory_pool](/allocator/cf_destroy_memory_pool.md) -[cf_memory_pool_try_alloc](/allocator/cf_memory_pool_try_alloc.md) [cf_memory_pool_free](/allocator/cf_memory_pool_free.md) diff --git a/docs/allocator/cf_memory_pool_free.md b/docs/allocator/cf_memory_pool_free.md index 2a2fd98b0..ec153f339 100644 --- a/docs/allocator/cf_memory_pool_free.md +++ b/docs/allocator/cf_memory_pool_free.md @@ -9,7 +9,7 @@ Category: [allocator](/api_reference?id=allocator) GitHub: [cute_alloc.h](https://github.com/RandyGaul/cute_framework/blob/master/include/cute_alloc.h) --- -Frees an allocation made by [cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md) or [cf_memory_pool_try_alloc](/allocator/cf_memory_pool_try_alloc.md). +Frees an allocation made by [cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md). ```cpp void cf_memory_pool_free(CF_MemoryPool* pool, void* element); @@ -25,4 +25,3 @@ element | The pointer to deallocate. [cf_make_memory_pool](/allocator/cf_make_memory_pool.md) [cf_destroy_memory_pool](/allocator/cf_destroy_memory_pool.md) [cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md) -[cf_memory_pool_try_alloc](/allocator/cf_memory_pool_try_alloc.md) diff --git a/docs/allocator/cf_memory_pool_try_alloc.md b/docs/allocator/cf_memory_pool_try_alloc.md deleted file mode 100644 index 6db105a27..000000000 --- a/docs/allocator/cf_memory_pool_try_alloc.md +++ /dev/null @@ -1,36 +0,0 @@ -[//]: # (This file is automatically generated by Cute Framework's docs parser.) -[//]: # (Do not edit this file by hand!) -[//]: # (See: https://github.com/RandyGaul/cute_framework/blob/master/samples/docs_parser.cpp) -[](../header.md ':include') - -# cf_memory_pool_try_alloc - -Category: [allocator](/api_reference?id=allocator) -GitHub: [cute_alloc.h](https://github.com/RandyGaul/cute_framework/blob/master/include/cute_alloc.h) ---- - -Allocates a chunk of memory from the pool. The allocation size was determined by `element_size` in [cf_make_memory_pool](/allocator/cf_make_memory_pool.md). - -```cpp -void* cf_memory_pool_try_alloc(CF_MemoryPool* pool); -``` - -Parameters | Description ---- | --- -pool | The pool. - -## Return Value - -Returns an aligned pointer of `size` bytes. - -## Remarks - -Does not return an allocation if the internal pool is full, and will instead return `NULL` in this case. See -[cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md) for more details about overflowing the pool to use `malloc` as a backup. - -## Related Pages - -[cf_make_memory_pool](/allocator/cf_make_memory_pool.md) -[cf_destroy_memory_pool](/allocator/cf_destroy_memory_pool.md) -[cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md) -[cf_memory_pool_free](/allocator/cf_memory_pool_free.md) diff --git a/docs/api_reference.md b/docs/api_reference.md index 504772c76..6219f1027 100644 --- a/docs/api_reference.md +++ b/docs/api_reference.md @@ -25,7 +25,6 @@ This is a list of all functions in Cute Framework organized by categories. This - [cf_make_memory_pool](/allocator/cf_make_memory_pool.md) - [cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md) - [cf_memory_pool_free](/allocator/cf_memory_pool_free.md) -- [cf_memory_pool_try_alloc](/allocator/cf_memory_pool_try_alloc.md) - [cf_realloc](/allocator/cf_realloc.md) diff --git a/include/cute_alloc.h b/include/cute_alloc.h index 2aaec11f2..dd95fa24c 100644 --- a/include/cute_alloc.h +++ b/include/cute_alloc.h @@ -203,7 +203,7 @@ typedef struct CF_MemoryPool CF_MemoryPool; * @param element_count The number of elements in the internal pool. * @param alignment An alignment boundary, must be a power of two. * @return Returns a memory pool pointer. - * @related cf_destroy_memory_pool cf_memory_pool_alloc cf_memory_pool_try_alloc cf_memory_pool_free + * @related cf_destroy_memory_pool cf_memory_pool_alloc cf_memory_pool_free */ CF_API CF_MemoryPool* CF_CALL cf_make_memory_pool(int element_size, int element_count, int alignment); @@ -212,8 +212,7 @@ CF_API CF_MemoryPool* CF_CALL cf_make_memory_pool(int element_size, int element_ * @category allocator * @brief Destroys a memory pool. * @param pool The pool to destroy. - * @remarks Does not clean up any allocations that overflowed to `malloc` backup. See `cf_memory_pool_alloc` for more details. - * @related cf_make_memory_pool cf_memory_pool_alloc cf_memory_pool_try_alloc cf_memory_pool_free + * @related cf_make_memory_pool cf_memory_pool_alloc cf_memory_pool_free */ CF_API void CF_CALL cf_destroy_memory_pool(CF_MemoryPool* pool); @@ -223,32 +222,17 @@ CF_API void CF_CALL cf_destroy_memory_pool(CF_MemoryPool* pool); * @brief Allocates a chunk of memory from the pool. The allocation size was determined by `element_size` in `cf_make_memory_pool`. * @param pool The pool. * @return Returns an aligned pointer of `size` bytes. - * @remarks Attempts to allocate from the internal pool. If the pool is empty a call to `malloc` is made as a backup. All - * backup allocations are not tracked anywhere, so you must call `cf_memory_pool_free` on each allocation to be - * sure they all properly cleaned up. - * @related cf_make_memory_pool cf_destroy_memory_pool cf_memory_pool_try_alloc cf_memory_pool_free + * @related cf_make_memory_pool cf_destroy_memory_pool cf_memory_pool_free */ CF_API void* CF_CALL cf_memory_pool_alloc(CF_MemoryPool* pool); -/** - * @function cf_memory_pool_try_alloc - * @category allocator - * @brief Allocates a chunk of memory from the pool. The allocation size was determined by `element_size` in `cf_make_memory_pool`. - * @param pool The pool. - * @return Returns an aligned pointer of `size` bytes. - * @remarks Does not return an allocation if the internal pool is full, and will instead return `NULL` in this case. See - * `cf_memory_pool_alloc` for more details about overflowing the pool to use `malloc` as a backup. - * @related cf_make_memory_pool cf_destroy_memory_pool cf_memory_pool_alloc cf_memory_pool_free - */ -CF_API void* CF_CALL cf_memory_pool_try_alloc(CF_MemoryPool* pool); - /** * @function cf_memory_pool_free * @category allocator - * @brief Frees an allocation made by `cf_memory_pool_alloc` or `cf_memory_pool_try_alloc`. + * @brief Frees an allocation made by `cf_memory_pool_alloc`. * @param pool The pool. * @param element The pointer to deallocate. - * @related cf_make_memory_pool cf_destroy_memory_pool cf_memory_pool_alloc cf_memory_pool_try_alloc + * @related cf_make_memory_pool cf_destroy_memory_pool cf_memory_pool_alloc */ CF_API void CF_CALL cf_memory_pool_free(CF_MemoryPool* pool, void* element); @@ -274,7 +258,6 @@ CF_INLINE void arena_reset(CF_Arena* arena) { return cf_arena_reset(arena); } CF_INLINE CF_MemoryPool* make_memory_pool(int element_size, int element_count, int alignment) { return cf_make_memory_pool(element_size, element_count, alignment); } CF_INLINE void destroy_memory_pool(CF_MemoryPool* pool) { cf_destroy_memory_pool(pool); } CF_INLINE void* memory_pool_alloc(CF_MemoryPool* pool) { return cf_memory_pool_alloc(pool); } -CF_INLINE void* memory_pool_try_alloc(CF_MemoryPool* pool) { return cf_memory_pool_try_alloc(pool); } CF_INLINE void memory_pool_free(CF_MemoryPool* pool, void* element) { return cf_memory_pool_free(pool, element); } } diff --git a/src/cute_alloc.cpp b/src/cute_alloc.cpp index f97059a41..4bb09d479 100644 --- a/src/cute_alloc.cpp +++ b/src/cute_alloc.cpp @@ -142,39 +142,47 @@ void cf_arena_reset(CF_Arena* arena) //-------------------------------------------------------------------------------------------------- +struct CF_MemoryBlock +{ + uint8_t* memory; + CF_MemoryBlock* next; +}; + struct CF_MemoryPool { - int unaligned_element_size; int element_size; - size_t arena_size; + size_t block_size; int alignment; - uint8_t* arena; void* free_list; - int overflow_count; + CF_MemoryBlock* blocks; + int element_count_per_block; }; CF_MemoryPool* cf_make_memory_pool(int element_size, int element_count, int alignment) { element_size = element_size > sizeof(void*) ? element_size : sizeof(void*); - int unaligned_element_size = element_size; element_size = CF_ALIGN_FORWARD(element_size, alignment); - size_t header_size = CF_ALIGN_FORWARD(sizeof(CF_MemoryPool), alignment); - CF_MemoryPool* pool = (CF_MemoryPool*)cf_aligned_alloc(header_size + element_size * element_count, alignment); + size_t block_size = element_size * element_count; - pool->unaligned_element_size = unaligned_element_size; + CF_MemoryPool* pool = (CF_MemoryPool*)cf_aligned_alloc(sizeof(CF_MemoryPool), alignment); pool->element_size = element_size; - pool->arena_size = (size_t)element_size * element_count; - pool->arena = (uint8_t*)((uintptr_t)pool + header_size); - pool->free_list = pool->arena; - pool->overflow_count = 0; - + pool->block_size = block_size; + pool->alignment = alignment; + pool->free_list = NULL; + pool->element_count_per_block = element_count; + + // Allocate the first block and initialize the free list. + CF_MemoryBlock* block = (CF_MemoryBlock*)cf_aligned_alloc(sizeof(CF_MemoryBlock), alignment); + block->memory = (uint8_t*)cf_aligned_alloc(block_size, alignment); + block->next = NULL; + pool->blocks = block; + pool->free_list = block->memory; for (int i = 0; i < element_count - 1; ++i) { - void** element = (void**)(pool->arena + element_size * i); - void* next = (void*)(pool->arena + element_size * (i + 1)); + void** element = (void**)(block->memory + element_size * i); + void* next = (void*)(block->memory + element_size * (i + 1)); *element = next; - }; - - void** last_element = (void**)(pool->arena + element_size * (element_count - 1)); + } + void** last_element = (void**)(block->memory + element_size * (element_count - 1)); *last_element = NULL; return pool; @@ -182,48 +190,44 @@ CF_MemoryPool* cf_make_memory_pool(int element_size, int element_count, int alig void cf_destroy_memory_pool(CF_MemoryPool* pool) { - if (pool->overflow_count) { - // Attempted to destroy pool without freeing all overflow allocations. - CF_ASSERT(pool->overflow_count == 0); + CF_MemoryBlock* block = pool->blocks; + while (block) { + CF_MemoryBlock* next = block->next; + cf_aligned_free(block->memory); + cf_aligned_free(block); + block = next; } cf_aligned_free(pool); } void* cf_memory_pool_alloc(CF_MemoryPool* pool) { - void *mem = cf_memory_pool_try_alloc(pool); - if (!mem) { - mem = cf_aligned_alloc(pool->unaligned_element_size, pool->alignment); - if (mem) { - pool->overflow_count++; - } - } - return mem; -} - -void* cf_memory_pool_try_alloc(CF_MemoryPool* pool) -{ + // Try to allocate from the free list first. if (pool->free_list) { - void *mem = pool->free_list; - pool->free_list = *((void**)pool->free_list); + void* mem = pool->free_list; + pool->free_list = *(void**)pool->free_list; return mem; - } else { - return NULL; } + + // If no free elements, allocate a new block and initialize its free list. + CF_MemoryBlock* new_block = (CF_MemoryBlock*)cf_aligned_alloc(sizeof(CF_MemoryBlock), pool->alignment); + new_block->memory = (uint8_t*)cf_aligned_alloc(pool->block_size, pool->alignment); + new_block->next = pool->blocks; + pool->blocks = new_block; + pool->free_list = new_block->memory; + for (int i = 0; i < pool->element_count_per_block - 1; ++i) { + void** element = (void**)(new_block->memory + pool->element_size * i); + void* next = (void*)(new_block->memory + pool->element_size * (i + 1)); + *element = next; + } + void** last_element = (void**)(new_block->memory + pool->element_size * (pool->element_count_per_block - 1)); + *last_element = NULL; + + return cf_memory_pool_alloc(pool); } void cf_memory_pool_free(CF_MemoryPool* pool, void* element) { - int difference = (int)((uint8_t*)element - pool->arena); - bool in_bounds = (void*)element >= pool->arena && difference <= (pool->arena_size - pool->element_size); - if (pool->overflow_count && !in_bounds) { - cf_aligned_free(element); - pool->overflow_count--; - } else if (in_bounds) { - *(void**)element = pool->free_list; - pool->free_list = element; - } else { - // Tried to free something that definitely didn't come from this pool. - CF_ASSERT(false); - } -} + *(void**)element = pool->free_list; + pool->free_list = element; +} \ No newline at end of file diff --git a/src/cute_array.cpp b/src/cute_array.cpp index d897d9ed6..b5cd43e69 100644 --- a/src/cute_array.cpp +++ b/src/cute_array.cpp @@ -70,7 +70,8 @@ void* cf_aset(const void* a, const void* b, size_t element_size) a = cf_agrow(a, asize(b), element_size); } CF_MEMCPY((void*)a, b, asize(b) * element_size); - alen(a) = asize(b); + if (a) alen(a) = asize(b); + else CF_ASSERT(!asize(b)); return (void*)a; }