memory/mempool: refactor to avoid storing object size and alignment in struct
Works similarly to DYNAMMIC_ARRAY(type)
This commit is contained in:
parent
05168ac2d7
commit
13ace0e5c0
8 changed files with 81 additions and 49 deletions
|
@ -165,7 +165,7 @@ static void *_delete_enemy(ListAnchor *enemies, List* enemy, void *arg) {
|
|||
|
||||
COEVENT_CANCEL_ARRAY(e->events);
|
||||
ent_unregister(&e->ent);
|
||||
mempool_release(&stage_object_pools.enemies, alist_unlink(enemies, enemy));
|
||||
mempool_release(&stage_object_pools.enemies, alist_unlink(enemies, e));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ void laserline_set_posdir(Laser *l, cmplx pos, cmplx dir) {
|
|||
static void *_delete_laser(ListAnchor *lasers, List *laser, void *arg) {
|
||||
Laser *l = (Laser*)laser;
|
||||
ent_unregister(&l->ent);
|
||||
mempool_release(&stage_object_pools.lasers, alist_unlink(lasers, laser));
|
||||
mempool_release(&stage_object_pools.lasers, alist_unlink(lasers, l));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,44 +8,37 @@
|
|||
|
||||
#include "mempool.h"
|
||||
|
||||
void mempool_init(
|
||||
void mempool_generic_init(
|
||||
MemPool *pool,
|
||||
const char *tag,
|
||||
MemArena *arena,
|
||||
size_t obj_size,
|
||||
size_t obj_align
|
||||
MemArena *arena
|
||||
) {
|
||||
*pool = (MemPool) {
|
||||
.arena = arena,
|
||||
.obj_size = obj_size,
|
||||
.obj_align = obj_align,
|
||||
.tag = tag,
|
||||
};
|
||||
}
|
||||
|
||||
void *mempool_acquire(MemPool *pool) {
|
||||
MemPoolObjectHeader *obj = pool->free_objects;
|
||||
void *mempool_generic_acquire(MemPool *pool, size_t size, size_t align) {
|
||||
MemPoolObjectHeader *obj = pool->free_objects.as_generic;
|
||||
|
||||
if(obj) {
|
||||
assert(pool->num_used < pool->num_allocated);
|
||||
pool->free_objects = obj->next;
|
||||
pool->free_objects.as_generic = obj->next;
|
||||
} else {
|
||||
assert(pool->num_used == pool->num_allocated);
|
||||
obj = marena_alloc_aligned(pool->arena, pool->obj_size, pool->obj_align);
|
||||
obj = marena_alloc_aligned(pool->arena, size, align);
|
||||
++pool->num_allocated;
|
||||
}
|
||||
|
||||
memset(obj, 0, pool->obj_size);
|
||||
++pool->num_used;
|
||||
|
||||
assert(pool->num_used <= pool->num_allocated);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void mempool_release(MemPool *pool, void *object) {
|
||||
void mempool_generic_release(MemPool *pool, void *object) {
|
||||
MemPoolObjectHeader *obj = object;
|
||||
obj->next = pool->free_objects;
|
||||
pool->free_objects = obj;
|
||||
obj->next = pool->free_objects.as_generic;
|
||||
pool->free_objects.as_generic = obj;
|
||||
|
||||
--pool->num_used;
|
||||
assert(pool->num_used >= 0);
|
||||
|
|
|
@ -11,32 +11,68 @@
|
|||
|
||||
#include "arena.h"
|
||||
|
||||
typedef struct MemPool MemPool;
|
||||
|
||||
typedef struct MemPoolObjectHeader {
|
||||
alignas(alignof(max_align_t)) struct MemPoolObjectHeader *next;
|
||||
} MemPoolObjectHeader;
|
||||
|
||||
struct MemPool {
|
||||
MemArena *arena;
|
||||
MemPoolObjectHeader *free_objects;
|
||||
const char *tag;
|
||||
size_t obj_size;
|
||||
size_t obj_align;
|
||||
int num_allocated;
|
||||
int num_used;
|
||||
};
|
||||
#define MEMPOOL_BASE(elem_type) struct { \
|
||||
MemArena *arena; \
|
||||
union { \
|
||||
MemPoolObjectHeader *as_generic; \
|
||||
elem_type *as_specific; \
|
||||
} free_objects; \
|
||||
uint num_allocated; \
|
||||
uint num_used; \
|
||||
} \
|
||||
|
||||
void mempool_init(
|
||||
MemPool *pool,
|
||||
const char *tag,
|
||||
MemArena *arena,
|
||||
size_t obj_size,
|
||||
size_t obj_align
|
||||
) attr_nonnull(1, 2, 3);
|
||||
typedef MEMPOOL_BASE(max_align_t) MemPool;
|
||||
|
||||
void *mempool_acquire(MemPool *pool)
|
||||
#define MEMPOOL(elem_type) union { \
|
||||
MEMPOOL_BASE(elem_type); \
|
||||
MemPool as_generic; \
|
||||
}
|
||||
|
||||
#define MEMPOOL_ASSERT_VALID(mpool) do { \
|
||||
static_assert( \
|
||||
__builtin_types_compatible_p(MemPool, __typeof__((mpool)->as_generic)), \
|
||||
"x->as_generic must be of MemPool type"); \
|
||||
static_assert( \
|
||||
__builtin_offsetof(__typeof__(*(mpool)), as_generic) == 0, \
|
||||
"x->as_generic must be the first member in struct"); \
|
||||
} while(0)
|
||||
|
||||
#define MEMPOOL_CAST_TO_BASE(mpool) ({ \
|
||||
MEMPOOL_ASSERT_VALID(mpool); \
|
||||
&NOT_NULL(mpool)->as_generic; \
|
||||
})
|
||||
|
||||
#define MEMPOOL_OBJTYPE(mpool) \
|
||||
typeof(*(mpool)->free_objects.as_specific)
|
||||
|
||||
void mempool_generic_init(MemPool *pool, MemArena *arena)
|
||||
attr_nonnull(1, 2);
|
||||
|
||||
void *mempool_generic_acquire(MemPool *pool, size_t size, size_t align)
|
||||
attr_returns_allocated attr_hot attr_nonnull(1);
|
||||
|
||||
void mempool_release(MemPool *pool, void *object)
|
||||
void mempool_generic_release(MemPool *pool, void *object)
|
||||
attr_hot attr_nonnull(1, 2);
|
||||
|
||||
#define mempool_init(mpool, arena) \
|
||||
mempool_generic_init(MEMPOOL_CAST_TO_BASE(mpool), (arena));
|
||||
|
||||
#define mempool_acquire(mpool) ({ \
|
||||
auto _mpool = mpool; \
|
||||
MEMPOOL_OBJTYPE(_mpool) *_obj = mempool_generic_acquire(\
|
||||
MEMPOOL_CAST_TO_BASE(_mpool), \
|
||||
sizeof(MEMPOOL_OBJTYPE(_mpool)), \
|
||||
alignof(MEMPOOL_OBJTYPE(_mpool))); \
|
||||
*_obj = (typeof(*_obj)) {} ; \
|
||||
_obj; \
|
||||
})
|
||||
|
||||
#define mempool_release(mpool, obj) ({ \
|
||||
static_assert( \
|
||||
__builtin_types_compatible_p(typeof(*(obj)), MEMPOOL_OBJTYPE(mpool))); \
|
||||
mempool_generic_release(MEMPOOL_CAST_TO_BASE(mpool), (obj)); \
|
||||
})
|
||||
|
|
|
@ -1197,12 +1197,20 @@ static void stage_draw_hud_objpool_stats(float x, float y, float width) {
|
|||
|
||||
y += lineskip * 1.5;
|
||||
|
||||
const char *const names[] = {
|
||||
#define OBJECT_POOL(t, n) #t,
|
||||
OBJECT_POOLS
|
||||
#undef OBJECT_POOL
|
||||
};
|
||||
|
||||
static_assert(ARRAY_SIZE(*objpools) == ARRAY_SIZE(names));
|
||||
|
||||
for(int i = 0; i < ARRAY_SIZE(*objpools); ++i) {
|
||||
MemPool *p = &(*objpools)[i];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%u | %7u", p->num_used, p->num_allocated);
|
||||
|
||||
text_draw(p->tag, &(TextParams) {
|
||||
text_draw(names[i], &(TextParams) {
|
||||
.pos = { x, y },
|
||||
.font_ptr = font,
|
||||
.align = ALIGN_LEFT,
|
||||
|
|
|
@ -24,14 +24,9 @@ void stage_objpools_init(void) {
|
|||
}
|
||||
|
||||
#define OBJECT_POOL(type, field) \
|
||||
mempool_init( \
|
||||
&stage_object_pools.field, \
|
||||
#type, \
|
||||
&stgobjs.arena, \
|
||||
sizeof(type), \
|
||||
alignof(type));
|
||||
mempool_init(&stage_object_pools.field, &stgobjs.arena);
|
||||
|
||||
OBJECT_POOLS
|
||||
OBJECT_POOLS
|
||||
#undef OBJECT_POOL
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
typedef struct StageObjectPools {
|
||||
#define OBJECT_POOL(type, field) \
|
||||
MemPool field;
|
||||
MEMPOOL(type) field;
|
||||
|
||||
OBJECT_POOLS
|
||||
#undef OBJECT_POOL
|
||||
|
|
|
@ -46,8 +46,8 @@ StageText* stagetext_add_numeric(int n, cmplx pos, Alignment align, Font *font,
|
|||
return t;
|
||||
}
|
||||
|
||||
static void* stagetext_delete(List **dest, List *txt, void *arg) {
|
||||
mempool_release(&stage_object_pools.stagetext, list_unlink(dest, txt));
|
||||
static void *stagetext_delete(List **dest, List *txt, void *arg) {
|
||||
mempool_release(&stage_object_pools.stagetext, list_unlink(dest, (StageText*)txt));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue