103 lines
2.9 KiB
C
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
|