From f97505d8ba8deaf88b6925ea9b24025aa391e6d6 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Tue, 9 Sep 2025 10:06:03 +0200 Subject: [PATCH] Freelist now uses offsets instead of raw pointers instead of header --- freelist/freelist.c | 54 +++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/freelist/freelist.c b/freelist/freelist.c index 62bd1a3..7a31c38 100644 --- a/freelist/freelist.c +++ b/freelist/freelist.c @@ -7,7 +7,7 @@ #include struct __attribute__((packed)) FreeListBlock { - struct FreeListBlock *next; + uint16_t next_offset; }; /* Align to nearest multiple of align */ @@ -15,15 +15,31 @@ static inline size_t align_up_to(size_t n, size_t align) { return (n + align - 1) & ~(align - 1); } +// Convert pointer -> 1-based offset (0 means NULL) +static inline uint32_t ptr_to_offset(FreeList *fl, void *ptr) { + if (!ptr) + return 0; // NULL maps to 0 + uintptr_t diff = (uintptr_t)ptr - fl->start; + return (uint32_t)(diff / fl->size) + 1; +} + +// Convert 1-based offset -> pointer (0 means NULL) +static inline void *offset_to_ptr(FreeList *fl, uint32_t offset) { + if (offset == 0) + return NULL; // 0 = invalid/null + return (void *)(fl->start + (uintptr_t)(offset - 1) * fl->size); +} + /* Initialize the FreeList */ int fl_init(FreeList *fl, uintptr_t start, size_t size_bytes, size_t itemsize) { /* Fiddle around according to your need, (void *) alignment seems to be enough, * but MAX_ALIGN_T is also an option. Especially for allocator implementation. */ size_t size = align_up_to(itemsize, sizeof(void *)); - if (size < sizeof(FreeListBlock) || !fl) { + assert(sizeof(FreeListBlock) == 2); + + if (size < sizeof(FreeListBlock) || !fl) return 0; - } fl->start = start; fl->end = start + size_bytes; @@ -31,12 +47,13 @@ int fl_init(FreeList *fl, uintptr_t start, size_t size_bytes, size_t itemsize) { fl->allocated = 0; FreeListBlock *block = (FreeListBlock *)start; - for (size_t i = 0; i < fl_capacity(fl); i++) { - block->next = (FreeListBlock *)((void *)block + size); - block = block->next; + + for (size_t offset = 1; offset < fl_capacity(fl) + 1; offset++) { + block->next_offset = (int32_t)offset; + block = offset_to_ptr(fl, offset); } - block->next = NULL; /* Last block */ + block->next_offset = 0; /* Last block */ fl->free = (FreeListBlock *)start; return 1; @@ -49,7 +66,7 @@ void *fl_alloc(FreeList *fl) { FreeListBlock *m = fl->free; - fl->free = fl->free->next; /* May be null, which is fine */ + fl->free = offset_to_ptr(fl, fl->free->next_offset); /* May be null, which is fine */ fl->allocated++; memset((void *)m, 0, sizeof(FreeListBlock)); @@ -63,7 +80,7 @@ int fl_free(FreeList *fl, void *ptr) { FreeListBlock *block = (FreeListBlock *)ptr; - block->next = fl->free; /* May be null, which is fine */ + block->next_offset = ptr_to_offset(fl, fl->free); /* May be null, which is fine */ fl->free = block; fl->allocated--; @@ -106,17 +123,16 @@ size_t fl_check(FreeList *fl) { int avail = 0; FreeListBlock *cursor = fl->free; - while (cursor->next != NULL) { - cursor = cursor->next; - - if (!fl_is_managed(fl, cursor)) { - printf("Unused memory at: %zX\n", (size_t)cursor->next); - printf("Min memory at: %zX\n", (size_t)fl->start); - printf("Max memory at: %zX\n", (size_t)fl->end); - return 0; - } - + while (cursor) { avail++; + + if (!fl_is_managed(fl, cursor) || avail > fl_capacity(fl)) + return 0; + + if (cursor->next_offset == 0) + break; + + cursor = offset_to_ptr(fl, cursor->next_offset); } return avail;