BudgetAllocatorInit
Description
Initialize a BudgetAllocator over a caller-owned memory region. Carves buf into a [bitmap | pad | slots] layout: the bitmap is u64-aligned at the head; slots are sizeof(void *)-aligned and padded up to sizeof(void *). The bitmap region is zeroed in place as part of init.
Side-effect-free args only – buf, buf_bytes, and slot_size are each evaluated multiple times inside the layout arithmetic.
Parameters
| Name | Direction | Description |
|---|---|---|
buf |
in,out | Caller-owned memory region used as backing storage. |
buf_bytes |
in | Size of buf in bytes. |
slot_size |
in | Allocation size class served by this allocator. |
Success
Returns a fully-initialized BudgetAllocator value with bitmap zeroed.
Failure
Aborts via LOG_FATAL when buf is NULL, buf_bytes or slot_size is 0, or the buffer is too small for the bitmap word plus one padded slot. The fatal log points at the caller’s source line.
Usage example (Cross-references)
Usage examples (Cross-references)
- In
Budget.h:191:
///
#define BudgetAllocatorInitAligned(buf_ptr, total_bytes, slot_size_bytes, alignment_value) \
(ASSERT_OR_FATAL((buf_ptr) != NULL, "BudgetAllocatorInit: NULL buf"), \
ASSERT_OR_FATAL((total_bytes) > 0, "BudgetAllocatorInit: zero buf_bytes"), \
ASSERT_OR_FATAL((slot_size_bytes) > 0, "BudgetAllocatorInit: zero slot_size"), \- In
Budget.h:192:
#define BudgetAllocatorInitAligned(buf_ptr, total_bytes, slot_size_bytes, alignment_value) \
(ASSERT_OR_FATAL((buf_ptr) != NULL, "BudgetAllocatorInit: NULL buf"), \
ASSERT_OR_FATAL((total_bytes) > 0, "BudgetAllocatorInit: zero buf_bytes"), \
ASSERT_OR_FATAL((slot_size_bytes) > 0, "BudgetAllocatorInit: zero slot_size"), \
ASSERT_OR_FATAL( \- In
Budget.h:193:
(ASSERT_OR_FATAL((buf_ptr) != NULL, "BudgetAllocatorInit: NULL buf"), \
ASSERT_OR_FATAL((total_bytes) > 0, "BudgetAllocatorInit: zero buf_bytes"), \
ASSERT_OR_FATAL((slot_size_bytes) > 0, "BudgetAllocatorInit: zero slot_size"), \
ASSERT_OR_FATAL( \
(alignment_value) >= sizeof(void *) && ((alignment_value) & ((alignment_value) - 1)) == 0, \
- In
Budget.h:196:
ASSERT_OR_FATAL( \
(alignment_value) >= sizeof(void *) && ((alignment_value) & ((alignment_value) - 1)) == 0, \
"BudgetAllocatorInit: alignment must be a power of two >= sizeof(void *)" \
), \
ASSERT_OR_FATAL( \
- In
Budget.h:201:
(size)(total_bytes) >= (size)(ALIGN_UP_POW2((u64)(buf_ptr), 8u) - (u64)(buf_ptr)) + sizeof(u64) + \
ALIGN_UP_POW2((slot_size_bytes), (alignment_value)) + ((alignment_value) - 1), \
"BudgetAllocatorInit: buffer too small for bitmap + one padded slot" \
), \
MemSet( \
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); static bool test_zero_byte_alloc_returns_null(void) {
u8 buf[256] = {0};
BudgetAllocator bp = BudgetAllocatorInit(buf, sizeof(buf), sizeof(Node));
Allocator *alloc = ALLOCATOR_OF(&bp);
void *p = AllocatorAlloc(alloc, 0, false); static bool test_free_null_is_noop(void) {
u8 buf[256] = {0};
BudgetAllocator bp = BudgetAllocatorInit(buf, sizeof(buf), sizeof(Node));
Allocator *alloc = ALLOCATOR_OF(&bp);
AllocatorFree(alloc, NULL); static bool test_fails_when_empty(void) {
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_alloc_distinct_pointers(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); // line. A passing deadend is one where the abort fired.
u8 buf[4] = {0};
BudgetAllocator bp = BudgetAllocatorInit(buf, sizeof(buf), sizeof(Node));
BudgetAllocatorDeinit(&bp);
return false; u8 buf1[1024] = {0};
u8 buf2[1024] = {0};
BudgetAllocator bp1 = BudgetAllocatorInit(buf1, sizeof(buf1), sizeof(Node));
BudgetAllocator bp2 = BudgetAllocatorInit(buf2, sizeof(buf2), sizeof(Node));
Allocator *alloc1 = ALLOCATOR_OF(&bp1); u8 buf2[1024] = {0};
BudgetAllocator bp1 = BudgetAllocatorInit(buf1, sizeof(buf1), sizeof(Node));
BudgetAllocator bp2 = BudgetAllocatorInit(buf2, sizeof(buf2), sizeof(Node));
Allocator *alloc1 = ALLOCATOR_OF(&bp1);
Allocator *alloc2 = ALLOCATOR_OF(&bp2); // Pointer to bitmap region (front of buf) must be rejected as foreign.
u8 buf[1024] = {0};
BudgetAllocator bp = BudgetAllocatorInit(buf, sizeof(buf), sizeof(Node));
Allocator *alloc = ALLOCATOR_OF(&bp); static bool test_reject_misaligned_pointer(void) {
u8 buf[1024] = {0};
BudgetAllocator bp = BudgetAllocatorInit(buf, sizeof(buf), sizeof(Node));
Allocator *alloc = ALLOCATOR_OF(&bp);
char *p = (char *)AllocatorAlloc(alloc, sizeof(Node), false); static bool test_reject_double_free(void) {
u8 buf[1024] = {0};
BudgetAllocator bp = BudgetAllocatorInit(buf, sizeof(buf), sizeof(Node));
Allocator *alloc = ALLOCATOR_OF(&bp);
Node *p = (Node *)AllocatorAlloc(alloc, sizeof(Node), false); // is far too small for the string's backing buffer, so allocation fails.
u8 buf[64] = {0};
BudgetAllocator bp = BudgetAllocatorInit(buf, sizeof(buf), 8);
Str s = StrInit(&bp);
u8 buf[64] = {0};
BudgetAllocator bp = BudgetAllocatorInit(buf, sizeof(buf), 8);
Str s = StrInit(&bp);
u8 buf[512] = {0};
BudgetAllocator bp = BudgetAllocatorInit(buf, sizeof(buf), 8);
Str s = StrInit(&bp);
Last updated on