Add page support to object pool

This commit is contained in:
2023-12-13 09:31:08 +01:00
parent 72b32b1a26
commit a2c19cf65d
5 changed files with 129 additions and 48 deletions

View File

@@ -2,13 +2,65 @@
#include "../memory/memory.h"
typedef union BzObjectIdx {
struct {
u16 idx;
u16 page;
};
u32 value;
} BzObjectIdx;
#define INVALID_OBJECT_IDX (UINT32_MAX)
static_assert(sizeof(BzObjectIdx) == 4, "");
typedef struct BzObjectPool {
void *objects;
void **pages;
size_t pageCapacity;
size_t pageSize;
size_t objectsPerPage;
size_t stride;
size_t numObjects;
i32 firstFree;
size_t numFree;
BzObjectIdx firstFree;
BzObjectPoolFunc constructor;
BzObjectPoolFunc destructor;
} BzObjectPool;
static void initializePage(BzObjectPool *pool, u16 pageIdx) {
BZ_ASSERT(pageIdx < UINT8_MAX);
// Link free list
for (size_t i = 0; i < pool->objectsPerPage - 1; i++) {
BzObjectIdx idx = {.page = pageIdx, .idx = i};
BzObjectIdx *obj = bzObjectPoolGetObject(pool, idx.value);
BzObjectIdx nextIdx = {.page = pageIdx, .idx = i + 1};
obj->value = nextIdx.value;
}
BzObjectIdx lastIdx = {.page = pageIdx, .idx = pool->objectsPerPage - 1};
BzObjectIdx *lastObj = bzObjectPoolGetObject(pool, lastIdx.value);
lastObj->value = pool->firstFree.value;
pool->firstFree = (BzObjectIdx) {.page = pageIdx, .idx = 0};
pool->numFree += pool->objectsPerPage;
}
static void addNewPage(BzObjectPool *pool) {
if (pool->pageSize >= pool->pageCapacity) {
size_t newCapacity = pool->pageCapacity << 1;
void **newPages = bzResize(pool->pages, sizeof(*newPages) * newCapacity);
BZ_ASSERT(newPages);
pool->pages = newPages;
pool->pageCapacity = newCapacity;
}
void *newPage = bzAlloc(pool->stride * pool->objectsPerPage);
BZ_ASSERT(newPage);
size_t pageIdx = pool->pageSize;
pool->pages[pageIdx] = newPage;
pool->pageSize++;
initializePage(pool, pageIdx);
}
BzObjectPool *bzObjectPoolCreate(const BzObjectPoolDesc *desc) {
BZ_ASSERT(desc->objectSize > 0);
@@ -18,58 +70,83 @@ BzObjectPool *bzObjectPoolCreate(const BzObjectPoolDesc *desc) {
if (stride < sizeof(i32)) {
stride = sizeof(i32);
}
BZ_ASSERT(desc->objectsPerPage > 0);
BZ_ASSERT(desc->objectsPerPage < (2 << 23));
size_t numBytes = sizeof(BzObjectPool) + desc->numObjects * stride;
BzObjectPool *pool = bzAlloc(numBytes);
size_t objectsPerPage = desc->objectsPerPage;
void *firstPage = bzAlloc(stride * objectsPerPage);
BZ_ASSERT(firstPage);
size_t pageCapacity = 8;
void **pages = bzAlloc(sizeof(*pages) * pageCapacity);
BZ_ASSERT(pages);
pages[0] = firstPage;
BzObjectPool *pool = bzAlloc(sizeof(*pool));
*pool = (BzObjectPool) {
.objects=pool + 1,
.stride=stride,
.numObjects=desc->numObjects,
.firstFree=0,
.pages = pages,
.pageSize = 0,
.pageCapacity = pageCapacity,
.objectsPerPage = objectsPerPage,
.stride = stride,
};
pool->firstFree.value = INVALID_OBJECT_IDX;
// Link free list
for (size_t i = 0; i < pool->numObjects - 1; i++) {
i32 *object = bzObjectPoolGetObject(pool, i);
*object = (i32) (i + 1);
}
i32 *lastObject = bzObjectPoolGetObject(pool, pool->numObjects - 1);
*lastObject = -1;
addNewPage(pool);
return pool;
}
void bzObjectPoolDestroy(BzObjectPool *pool) {
bzFree(pool);
}
size_t bzObjectPoolCalcNumFree(BzObjectPool *pool) {
size_t count = 0;
i32 idx = pool->firstFree;
while (idx != -1) {
count++;
i32 *object = bzObjectPoolGetObject(pool, idx);
idx = *object;
}
return count;
size_t bzObjectPoolGetNumFree(BzObjectPool *pool) {
return pool->numFree;
}
void *bzObjectPool(BzObjectPool *pool) {
if (pool->firstFree == -1)
return NULL;
i32 *object = bzObjectPoolGetObject(pool, pool->firstFree);
pool->firstFree = *object;
if (pool->firstFree.value == INVALID_OBJECT_IDX) {
addNewPage(pool);
BZ_ASSERT(pool->firstFree.value != INVALID_OBJECT_IDX);
}
BzObjectIdx *object = (BzObjectIdx *) bzObjectPoolGetObject(pool, pool->firstFree.value);
pool->firstFree = *object;
BZ_ASSERT(pool->numFree > 0);
pool->numFree--;
return object;
}
void *bzObjectPoolGetObject(BzObjectPool *pool, i32 idx) {
BZ_ASSERT(idx >= 0 && (size_t) idx < pool->numObjects);
return (void *) ((u8 *) pool->objects + idx * pool->stride);
void *bzObjectPoolGetObject(BzObjectPool *pool, u32 idx) {
BzObjectIdx objectIdx = {.value = idx};
BZ_ASSERT(objectIdx.page >= 0 && objectIdx.page < pool->pageSize);
BZ_ASSERT(objectIdx.idx >= 0 && objectIdx.idx < pool->objectsPerPage);
void *page = pool->pages[objectIdx.page];
return (void *) ((u8 *) page + objectIdx.idx * pool->stride);
}
i32 bzObjectPoolGetIdx(BzObjectPool *pool, void *object) {
size_t objectIdx = (size_t) object - (size_t) pool->objects;
return (i32) (objectIdx / pool->stride);
u32 bzObjectPoolGetIdx(BzObjectPool *pool, void *object) {
u16 pageIdx = pool->pageSize;
u16 idx = 0;
for (size_t i = 0; i < pool->pageSize; i++) {
void *start = pool->pages[i];
void *end = (u8 *) start + pool->objectsPerPage * pool->stride;
if (object >= start && object < end) {
pageIdx = i;
idx = (size_t) object - (size_t) start;
idx = idx / pool->stride;
break;
}
}
BZ_ASSERT(pageIdx < pool->pageSize);
BzObjectIdx objectIdx = {.page = pageIdx, .idx = idx};
return objectIdx.value;
}
void bzObjectPoolRelease(BzObjectPool *pool, void *object) {
size_t objectIdx = bzObjectPoolGetIdx(pool, object);
BZ_ASSERT(objectIdx < pool->numObjects);
*(i32 *) ((u8 *) pool->objects + objectIdx * pool->stride) = pool->firstFree;
pool->firstFree = (i32) objectIdx;
BzObjectIdx objectIdx = {.value = bzObjectPoolGetIdx(pool, object)};
void *page = pool->pages[objectIdx.page];
*(BzObjectIdx *) ((u8 *) page + objectIdx.idx * pool->stride) = pool->firstFree;
pool->firstFree = objectIdx;
pool->numFree++;
}

View File

@@ -5,18 +5,22 @@
typedef struct BzObjectPool BzObjectPool;
typedef void (*BzObjectPoolFunc)(void *object);
typedef struct BzObjectPoolDesc {
size_t objectSize;
size_t numObjects;
size_t objectsPerPage;
BzObjectPoolFunc constructor;
BzObjectPoolFunc destructor;
} BzObjectPoolDesc;
BzObjectPool *bzObjectPoolCreate(const BzObjectPoolDesc *desc);
void bzObjectPoolDestroy(BzObjectPool *pool);
size_t bzObjectPoolCalcNumFree(BzObjectPool *pool);
size_t bzObjectPoolGetNumFree(BzObjectPool *pool);
void *bzObjectPool(BzObjectPool *pool);
void *bzObjectPoolGetObject(BzObjectPool *pool, i32 idx);
i32 bzObjectPoolGetIdx(BzObjectPool *pool, void *object);
void *bzObjectPoolGetObject(BzObjectPool *pool, u32 idx);
u32 bzObjectPoolGetIdx(BzObjectPool *pool, void *object);
void bzObjectPoolRelease(BzObjectPool *pool, void *object);
#endif //BREEZE_OBJECT_POOL_H

View File

@@ -42,7 +42,7 @@ BzSpatialGrid *bzSpatialGridCreate(const BzSpatialGridDesc *desc) {
}
grid->entriesPool = bzObjectPoolCreate(&(BzObjectPoolDesc) {
.objectSize=sizeof(BzSpatialGridEntry) + desc->userDataSize,
.numObjects=1024,
.objectsPerPage=1024,
});
return grid;
}

View File

@@ -79,7 +79,7 @@ bool init(void *userData) {
// init pools
game->pools.pathData = bzObjectPoolCreate(&(BzObjectPoolDesc) {
.objectSize=sizeof(PathData),
.numObjects=512
.objectsPerPage=512
});
@@ -241,7 +241,7 @@ void imguiRender(float dt, void *userData) {
createWorker((Position) {1100, 400}, (Size) {10, 10}, game->entityGrid,
&game->map.tilesets[2], 1322);
}
igText("Num paths from pool available: %llu", bzObjectPoolCalcNumFree(game->pools.pathData));
igText("Num paths from pool available: %llu", bzObjectPoolGetNumFree(game->pools.pathData));
const char *inputState = "NONE";
switch (input->state) {
case INPUT_NONE:

View File

@@ -107,7 +107,7 @@ bool initTreesLayer(BzTileMap *map, BzTileLayer *layer) {
f32 posX = layer->offsetX + x * sizeX;
f32 posY = layer->offsetY + y * sizeY;
ecs_entity_t e = ecs_new_id(ECS);
//bzSpatialGridInsert(game->entityGrid, &e, posX, posY, sizeX, sizeY);;
bzSpatialGridInsert(game->entityGrid, &e, posX, posY, sizeX, sizeY);
posX += sizeX * 0.5f;
posY += sizeY * 0.5f;
ecs_add(ECS, e, TextureTerrain);