Files
libucore/include/ucore/slot_allocator.h
T
Nils O. Selåsdal d58e24f6a9 Minor cleanup
2026-04-21 23:01:22 +02:00

103 lines
2.9 KiB
C

#ifndef UC_SLOT_ALLOCATOR_H_
#define UC_SLOT_ALLOCATOR_H_
#include <stddef.h>
#include <stdint.h>
#include <assert.h>
//Free memory is reused to build a linked list of slots
typedef union UCSlot UCSlot;
union UCSlot {
UCSlot *next; // next free block (when not allocated)
uint8_t data[0]; // data when allocated
};
typedef struct UCSlotArena UCSlotArena;
struct UCSlotArena {
UCSlot *free_list;
uint8_t *memory_start;
size_t memory_len;
size_t n_slots;
size_t used_slots;
size_t slot_size;
};
/**
* Initialize a memory arena for dynamically allocating slots of memory.
* Each allocation returns memory slots of the same size
* Note: For max speed, align @memory and @slot_size to the size of a pointer
*
* @param arena arena to initialize
* @param memory start of the backing memory
* @param memory_len length of @memory
* @param slot_size size of each slot allocation
*/
static inline void uc_slot_arena_init(UCSlotArena *arena, void *memory, size_t memory_len, size_t slot_size)
{
// Optionally - align to a pointer
//slot_size = (slot_size + _Alignof(UCSlot) - 1) & (~(_Alignof(UCSlot) - 1));
assert(slot_size >= sizeof(UCSlot));
size_t n_slots = memory_len / slot_size;
arena->free_list = NULL;
uint8_t *start = (uint8_t *)memory;
// build free_list in ascending order, anticipating sequential allocation
// and sequential access as the common case
for (size_t slot = n_slots; slot > 0; slot--) {
size_t index = slot - 1;
UCSlot *free_slot = (UCSlot *)(start + index * slot_size);
free_slot->next = arena->free_list;
arena->free_list = free_slot;
}
arena->n_slots = n_slots;
arena->memory_start = (uint8_t*)memory;
arena->memory_len = memory_len;
arena->slot_size = slot_size;
}
/**
* Allocate a slot.
*
* @return pointer to a slot, NULL if all slots are already allocated
*/
static inline void *uc_slot_alloc(UCSlotArena *arena)
{
UCSlot *slot = arena->free_list;
if (slot != NULL) {
arena->free_list = slot->next;
arena->used_slots++;
#ifdef DEBUG
memset(slot, 0xCB, arena->slot_size);
#endif
}
return &slot->data[0];
}
/**
* Free a slot.
*
* @param mem pointer to a slot that previously was allocated with uc_slot_alloc
*/
static inline void uc_slot_free(UCSlotArena *arena, void *memory)
{
if (memory != NULL) {
#ifdef DEBUG
for (const UCSlot *slot = arena->free_list ; slot = slot->next) {
if (slot == mem) {
assert(0 && "Double free detected");
}
}
#endif
assert((uint8_t *)memory >= arena->memory_start);
assert((uint8_t *)memory < arena->memory_start + arena->memory_len);
assert(arena->used_slots > 0);
UCSlot *slot = (UCSlot *)memory;
slot->next = arena->free_list;
arena->free_list = slot;
arena->used_slots--;
}
}
#endif