Skip to content
BudgetAllocator

BudgetAllocator

Description

Caller-buffer fixed-budget allocator. Carries Allocator base at offset 0 so (Allocator *)&bp is well-defined.

Fields

Name Description
base Generic allocator base (function pointers, alignment, …).
buf Pointer to the caller-owned memory region.
buf_bytes Size of buf in bytes.
slot_size Slot size in bytes (rounded up to base.alignment).
slot_count Number of slots carved out of buf.
free_head Head of the intrusive free list.

Usage example (Cross-references)

Usage examples (Cross-references)
    static bool test_basic_alloc_and_free(void) {
        u8              buf[1024] = {0};
        BudgetAllocator bp        = BudgetAllocatorInit(buf, sizeof(buf), sizeof(Node));
        Allocator      *alloc     = ALLOCATOR_OF(&bp);
        Node           *a         = (Node *)AllocatorAlloc(alloc, sizeof(Node), true);
        // 256 bytes / padded(sizeof(Node)) = a few slots, exhaust them.
        u8              buf[256] = {0};
        BudgetAllocator bp       = BudgetAllocatorInit(buf, sizeof(buf), sizeof(Node));
        Allocator      *alloc    = ALLOCATOR_OF(&bp);
    static bool test_free_then_alloc_recycles(void) {
        u8              buf[1024] = {0};
        BudgetAllocator bp        = BudgetAllocatorInit(buf, sizeof(buf), sizeof(Node));
        Allocator      *alloc     = ALLOCATOR_OF(&bp);
    static bool test_oversized_request_fails(void) {
        u8              buf[256] = {0};
        BudgetAllocator bp       = BudgetAllocatorInit(buf, sizeof(buf), sizeof(int));
        Allocator      *alloc    = ALLOCATOR_OF(&bp);
        void           *big      = AllocatorAlloc(alloc, 4096, true);
        static u8 buf[1024];
        MemSet(buf, 0, sizeof(buf));
        BudgetAllocator bp    = BudgetAllocatorInitAligned(buf, sizeof(buf), sizeof(int), 64);
        Allocator      *alloc = ALLOCATOR_OF(&bp);
        int            *p1    = (int *)AllocatorAlloc(alloc, sizeof(int), true);
        // alloc must therefore return NULL on the very first call.
        u8              buf[4] = {0};
        BudgetAllocator bp     = BudgetAllocatorInit(buf, sizeof(buf), sizeof(Node));
        bool            ok     = (bp.slot_count == 0);
    static void budget_validate_self(const Allocator *self) {
        if (!self || self->__magic != MISRA_BUDGET_ALLOCATOR_MAGIC) {
            LOG_FATAL("type-confusion: allocator passed to budget_allocator_* is not a BudgetAllocator");
        }
    }
    void *budget_allocator_allocate(Allocator *self, size bytes, i8 zeroed) {
        budget_validate_self(self);
        BudgetAllocator *bp = (BudgetAllocator *)self;
        if (bytes > bp->slot_size) {
            return NULL;
    void *budget_allocator_reallocate(Allocator *self, void *ptr, size old_size, size new_size) {
        budget_validate_self(self);
        BudgetAllocator *bp = (BudgetAllocator *)self;
        (void)old_size;
    void budget_allocator_deallocate(Allocator *self, void *ptr, size bytes) {
        budget_validate_self(self);
        BudgetAllocator *bp = (BudgetAllocator *)self;
        (void)bytes;
        if (!ptr) {
    }
    
    static BudgetAllocator budget_build(void *buf, size buf_bytes, size slot_size, size alignment) {
        BudgetAllocator empty = {0};
        if (!buf || !slot_size) {
    
    static BudgetAllocator budget_build(void *buf, size buf_bytes, size slot_size, size alignment) {
        BudgetAllocator empty = {0};
        if (!buf || !slot_size) {
            return empty;
        }
    
        BudgetAllocator bp = {
            .base =
                {.allocate    = budget_allocator_allocate,
    }
    
    BudgetAllocator BudgetAllocatorInit(void *buf, size buf_bytes, size slot_size) {
        return budget_build(buf, buf_bytes, slot_size, sizeof(void *));
    }
    }
    
    BudgetAllocator BudgetAllocatorInitAligned(void *buf, size buf_bytes, size slot_size, size alignment) {
        return budget_build(buf, buf_bytes, slot_size, alignment);
    }
    }
    
    void BudgetAllocatorDeinit(BudgetAllocator *self) {
        if (!self) {
            return;
        typedef struct ArenaAllocator  ArenaAllocator;
        typedef struct SlabAllocator   SlabAllocator;
        typedef struct BudgetAllocator BudgetAllocator;
    
        // `zeroed` uses `i8` (signed char) directly instead of `bool` to
            ArenaAllocator *: (Allocator *)(allocator_ptr),                                                                \
            SlabAllocator *: (Allocator *)(allocator_ptr),                                                                 \
            BudgetAllocator *: (Allocator *)(allocator_ptr)                                                                \
        )
            size            slot_count;
            BudgetFreeSlot *free_head;
        } BudgetAllocator;
    
        void *budget_allocator_allocate(Allocator *self, size bytes, i8 zeroed);
        /// TAGS: Allocator, Budget, Init
        ///
        BudgetAllocator BudgetAllocatorInit(void *buf, size buf_bytes, size slot_size);
    
        ///
        /// TAGS: Allocator, Budget, Init, Alignment
        ///
        BudgetAllocator BudgetAllocatorInitAligned(void *buf, size buf_bytes, size slot_size, size alignment);
    
        ///
        /// TAGS: Allocator, Budget, Cleanup
        ///
        void BudgetAllocatorDeinit(BudgetAllocator *self);
    
    #ifdef __cplusplus
Last updated on