apool: track total&free elements

This commit is contained in:
2026-09-14 19:55:23 +02:00
parent 9ed137abcb
commit 076b152555
3 changed files with 83 additions and 51 deletions
+26 -20
View File
@@ -1,33 +1,35 @@
#include "pool.h" #include "pool.h"
APool *apool_create_ex(Allocator *allocator, U32 n_elements, U32 element_size, U32 element_align) APool *apool_create_ex(Allocator *allocator, const APoolCreateOptions *options)
{ {
Assert(IsPow2(element_align)); Assert(IsPow2(options->element_align));
U32 align = element_align; U32 element_align = options->element_align;
if (element_align < alignof(APoolElement)) { if (element_align < alignof(APoolElement)) {
element_align = alignof(APoolElement); element_align = alignof(APoolElement);
} }
U32 size = AlignUp(element_size, element_align); U32 element_size = AlignUp(options->element_size, options->element_align);
APool *pool = allocator_push_type(allocator, APool); APool *pool = allocator_push_type(allocator, APool);
Assert(pool != NULL); Assert(pool != NULL);
pool->align = align; pool->element_align= element_align;
pool->element_size = size; pool->element_size = element_size;
pool->allocator = allocator; pool->allocator = allocator;
pool->n_elements = n_elements; pool->n_elements = 0;
pool->free_list = NULL; pool->n_free = 0;
pool->start = NULL; pool->free_list = NULL;
pool->flags = options->flags;
if (size != APOOL_AUTOGROW) { if (options->n_reserved != 0) {
Assert(n_elements <= U32_Max / size ); Assert(options->n_reserved <= U32_Max / element_size );
U32 total_size = n_elements * size; U32 total_size = options->n_reserved * element_size;
U8 * start = allocator_push(allocator, total_size, align); U8 *start = allocator_push(allocator, total_size, element_align);
for (U32 i = 0; i < total_size; i += size) { for (U32 i = 0; i < total_size; i += element_size) {
APoolElement *element = (APoolElement *)&start[i]; APoolElement *element = (APoolElement *)&start[i];
element->next = pool->free_list; element->next = pool->free_list;
pool->free_list = element; pool->free_list = element;
pool->n_elements++;
} }
pool->start = start; pool->n_free = pool->n_elements;
} }
return pool; return pool;
@@ -38,8 +40,12 @@ void *apool_alloc(APool *pool)
APoolElement *element = pool->free_list; APoolElement *element = pool->free_list;
if (element != NULL) { if (element != NULL) {
pool->free_list = element->next; pool->free_list = element->next;
} else if(pool->n_elements == APOOL_AUTOGROW) { pool->n_free--;
element = allocator_push(pool->allocator, pool->element_size, pool->align); } else if((pool->flags & APoolFlag_AutoGrow) != 0) {
element = allocator_push(pool->allocator, pool->element_size, pool->element_align);
if (element != NULL) {
pool->n_elements++;
}
} }
return element; return element;
@@ -48,10 +54,10 @@ void *apool_alloc(APool *pool)
void apool_free(APool *pool, void *ptr) void apool_free(APool *pool, void *ptr)
{ {
if (ptr != NULL) { if (ptr != NULL) {
Assert((U8 *)ptr >= pool->start);
APoolElement *element = (APoolElement *)ptr; APoolElement *element = (APoolElement *)ptr;
element->next = pool->free_list; element->next = pool->free_list;
pool->free_list = element; pool->free_list = element;
pool->n_free++;
} }
} }
+19 -9
View File
@@ -1,6 +1,10 @@
#pragma once #pragma once
#include "core.h" #include "core.h"
enum {
APoolFlag_AutoGrow = (1 << 0)
};
typedef U32 APoolFlags;
typedef union APoolElement APoolElement; typedef union APoolElement APoolElement;
union APoolElement { union APoolElement {
APoolElement *next; // offset from start to next free block (when not allocated) APoolElement *next; // offset from start to next free block (when not allocated)
@@ -11,16 +15,22 @@ struct APool {
APoolElement *free_list; // free list APoolElement *free_list; // free list
U8 *start; // start of user buffer U8 *start; // start of user buffer
Allocator *allocator; Allocator *allocator;
U32 element_size; // aligned size of each block APoolFlags flags;
U32 n_elements; // total number of blocks U32 element_size; // aligned size of each element
U32 align; // alignment U32 element_align; // alignment
}; U32 n_elements; // total elements in the pool
enum { U32 n_free; // number of free elements
APOOL_AUTOGROW = 0
}; };
typedef struct APoolCreateOptions APoolCreateOptions;
struct APoolCreateOptions {
U32 element_size; // aligned size of each element
U32 element_align; // alignment of elements
U32 n_reserved; // number of elements reserved
APoolFlags flags;
#define apool_create(arena, n_elements, type) \ };
apool_create_ex(arena, n_elements, sizeof(type), alignof(type)); #define apool_create(arena, n_reserved, type) \
APool *apool_create_ex(Allocator *allocator, U32 n_elements, U32 element_size, uint32_t element_align); apool_create_ex(arena, &(APoolCreateOptions){sizeof(type), alignof(type), n_reserved, 0})
APool *apool_create_ex(Allocator *allocator, const APoolCreateOptions *options);
void *apool_alloc(APool *pool); void *apool_alloc(APool *pool);
void apool_free(APool *pool, void *element); void apool_free(APool *pool, void *element);
+38 -22
View File
@@ -26,7 +26,7 @@ void arena_dump(const Arena *arena)
} }
static void arena_test_1(void) static void arena_test_1(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
ArenaOptions arena_params = {}; ArenaOptions arena_params = {};
U32 arena_size = MB(1) + MemoryBlock_Header_Size; U32 arena_size = MB(1) + MemoryBlock_Header_Size;
U32 commit_size = KB(8); U32 commit_size = KB(8);
@@ -53,7 +53,7 @@ static void arena_test_1(void)
static void arena_test_2(void) static void arena_test_2(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
ArenaOptions arena_params = {}; ArenaOptions arena_params = {};
U32 arena_size = MB(3) + MemoryBlock_Header_Size; U32 arena_size = MB(3) + MemoryBlock_Header_Size;
@@ -106,7 +106,7 @@ static void arena_test_2(void)
static void arena_test_3(void) static void arena_test_3(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
ArenaOptions arena_params = {}; ArenaOptions arena_params = {};
U32 arena_size = KB(97) + MemoryBlock_Header_Size; U32 arena_size = KB(97) + MemoryBlock_Header_Size;
@@ -134,7 +134,7 @@ static void arena_test_3(void)
// gap was not accounted for. After the fix this should allocate a larger block. // gap was not accounted for. After the fix this should allocate a larger block.
static void arena_test_4(void) static void arena_test_4(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
U32 page_size = platform_page_size(); U32 page_size = platform_page_size();
ArenaOptions arena_params = {}; ArenaOptions arena_params = {};
@@ -167,7 +167,7 @@ static void arena_test_4(void)
static void arena_test_allocator_interface(void) static void arena_test_allocator_interface(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
U32 page_size = platform_page_size(); U32 page_size = platform_page_size();
ArenaOptions arena_params = {}; ArenaOptions arena_params = {};
@@ -203,7 +203,7 @@ static void arena_test_allocator_interface(void)
static void arena_test_decommit(void) static void arena_test_decommit(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
U32 page_size = platform_page_size(); U32 page_size = platform_page_size();
ArenaOptions arena_params = {}; ArenaOptions arena_params = {};
@@ -230,7 +230,7 @@ static void arena_test_decommit(void)
void miniarena_test1(void) void miniarena_test1(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
#define arena_size 4096 #define arena_size 4096
MARENA_DEFINE(arena, arena_size, 8); MARENA_DEFINE(arena, arena_size, 8);
@@ -269,12 +269,18 @@ struct PoolTest{
void apool_test(void) void apool_test(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
Arena arena; Arena arena;
arena_init(&arena, &ArenaOptions_Default); arena_init(&arena, &ArenaOptions_Default);
Allocator allocator = arena_allocator(&arena); Allocator allocator = arena_allocator(&arena);
APool *pool = apool_create_ex(&allocator, 16, sizeof(PoolTest), alignof(PoolTest)); APoolCreateOptions opts = {
.n_reserved= 16,
.element_size = sizeof(PoolTest),
.element_align = alignof(PoolTest),
.flags = 0
};
APool *pool = apool_create_ex(&allocator, &opts);
PoolTest *list = NULL; PoolTest *list = NULL;
for (U32 i = 0; i < U32_Max; i++) { for (U32 i = 0; i < U32_Max; i++) {
PoolTest *pt = apool_alloc(pool); PoolTest *pt = apool_alloc(pool);
@@ -297,6 +303,7 @@ void apool_test(void)
printf("Pooltest freeing %u\n",p->n); printf("Pooltest freeing %u\n",p->n);
apool_free(pool, p); apool_free(pool, p);
} }
printf("Pooltest total: %u free %u\n", pool->n_elements, pool->n_free);
list = NULL; list = NULL;
for (U32 i = 0; i < U32_Max; i++) { for (U32 i = 0; i < U32_Max; i++) {
PoolTest *pt = apool_alloc(pool); PoolTest *pt = apool_alloc(pool);
@@ -316,13 +323,13 @@ void apool_test(void)
void apool_test_miniarena(void) void apool_test_miniarena(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
MArena arena; MArena arena;
U8 data[4096]; U8 data[4096];
marena_init(&arena, data, sizeof data); marena_init(&arena, data, sizeof data);
Allocator allocator = marena_allocator(&arena); Allocator allocator = marena_allocator(&arena);
APool *pool = apool_create_ex(&allocator, 16, sizeof(PoolTest), alignof(PoolTest)); APool *pool = apool_create(&allocator, 16, PoolTest);
PoolTest *list = NULL; PoolTest *list = NULL;
for (U32 i = 0; i < U32_Max; i++) { for (U32 i = 0; i < U32_Max; i++) {
PoolTest *pt = apool_alloc(pool); PoolTest *pt = apool_alloc(pool);
@@ -358,19 +365,26 @@ void apool_test_miniarena(void)
for (PoolTest *p = list; p; p = p->next){ for (PoolTest *p = list; p; p = p->next){
printf("Pooltest %u\n",p->n); printf("Pooltest %u\n",p->n);
} }
printf("Pooltest total: %u free %u\n", pool->n_elements, pool->n_free);
allocator_free_all(&allocator); allocator_free_all(&allocator);
} }
void apool_test_autogrow(void) void apool_test_autogrow(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
Arena arena; Arena arena;
arena_init(&arena, &ArenaOptions_Default); arena_init(&arena, &ArenaOptions_Default);
Allocator allocator = arena_allocator(&arena); Allocator allocator = arena_allocator(&arena);
APoolCreateOptions opts = {
APool *pool = apool_create(&allocator, APOOL_AUTOGROW, PoolTest); .n_reserved = 0,
.element_size = sizeof(PoolTest),
.element_align = alignof(PoolTest),
.flags = APoolFlag_AutoGrow
};
APool *pool = apool_create_ex(&allocator, &opts);
PoolTest *list = NULL; PoolTest *list = NULL;
for (U32 i = 0; i < 4; i++) { for (U32 i = 0; i < 4; i++) {
PoolTest *pt = apool_alloc(pool); PoolTest *pt = apool_alloc(pool);
@@ -384,6 +398,7 @@ void apool_test_autogrow(void)
for (PoolTest *p = list; p; p = p->next){ for (PoolTest *p = list; p; p = p->next){
printf("Pooltest %u\n",p->n); printf("Pooltest %u\n",p->n);
} }
printf("Pooltest total: %u free %u\n", pool->n_elements, pool->n_free);
PoolTest *next; PoolTest *next;
U32 count = 0; U32 count = 0;
@@ -406,6 +421,7 @@ void apool_test_autogrow(void)
for (PoolTest *p = list; p; p = p->next){ for (PoolTest *p = list; p; p = p->next){
printf("Pooltest %u\n",p->n); printf("Pooltest %u\n",p->n);
} }
printf("Pooltest total: %u free %u\n", pool->n_elements, pool->n_free);
allocator_free_all(&allocator); allocator_free_all(&allocator);
arena_free(&arena); arena_free(&arena);
@@ -414,7 +430,7 @@ void apool_test_autogrow(void)
void string_test_1(void) void string_test_1(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
Str str1 = S("Hello"); Str str1 = S("Hello");
printf("str1: %.*s len %d\n", str1.len, str1.str, str1.len); printf("str1: %.*s len %d\n", str1.len, str1.str, str1.len);
@@ -431,7 +447,7 @@ void string_test_1(void)
void string_split_test_1(void) void string_split_test_1(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
Str str1 = S("|a:bb|ccc|"); Str str1 = S("|a:bb|ccc|");
Str sep = S("|:"); Str sep = S("|:");
@@ -445,7 +461,7 @@ void string_split_test_1(void)
} }
void string_test_misc(void) void string_test_misc(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
Str str1 = S("Hello World"); Str str1 = S("Hello World");
bool prefix1 = str_starts_with(str1, S("He")); bool prefix1 = str_starts_with(str1, S("He"));
@@ -484,7 +500,7 @@ void string_test_misc(void)
} }
void string_test_join(void) void string_test_join(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
Arena arena; Arena arena;
arena_init(&arena, &ArenaOptions_Default); arena_init(&arena, &ArenaOptions_Default);
Allocator allocator = arena_allocator(&arena); Allocator allocator = arena_allocator(&arena);
@@ -515,7 +531,7 @@ void print_runes(Str str)
void string_test_utf8(void) void string_test_utf8(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
Str str1 = S("Test 1ø2 ☺"); Str str1 = S("Test 1ø2 ☺");
@@ -539,7 +555,7 @@ void string_test_utf8(void)
void string_test_hex(void) void string_test_hex(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
MArena arena; MArena arena;
U8 data[4096]; U8 data[4096];
@@ -577,7 +593,7 @@ struct StrSList {
void string_test_slist(void) void string_test_slist(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
Str str1 = S("one"); Str str1 = S("one");
Str str2 = S("two"); Str str2 = S("two");
@@ -625,7 +641,7 @@ struct StrDList {
void string_test_dlist(void) void string_test_dlist(void)
{ {
TRACEF("\n"); TRACEF("\n\n");
Str str1 = S("one"); Str str1 = S("one");
Str str2 = S("two"); Str str2 = S("two");