#ifndef UC_SLOT_ALLOCATOR_H_ #define UC_SLOT_ALLOCATOR_H_ #include #include #include // Repurpose free memory to eep a linked list of free slots typedef struct UCSlot UCSlot; struct UCSlot { UCSlot *next; }; 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++; } return slot; } /** * 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("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