From 2af56232a4e14d8d02b30f9f848d2b85500faf3d Mon Sep 17 00:00:00 2001 From: Carter Li Date: Tue, 4 Aug 2026 15:08:38 +0800 Subject: [PATCH] FFlist: adds `FF_LIST_INSERT_AT` and `FF_LIST_REMOVE_AT` --- src/common/FFlist.h | 24 +++++++++++++-- tests/list.c | 73 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/common/FFlist.h b/src/common/FFlist.h index cf1377b27..630b0734b 100644 --- a/src/common/FFlist.h +++ b/src/common/FFlist.h @@ -4,6 +4,7 @@ #include #include #include +#include #define FF_LIST_DEFAULT_ALLOC 16 @@ -110,6 +111,19 @@ static inline void* ffListAdd(FFlist* list, uint32_t elementSize) { return ffListGet(list, elementSize, list->length - 1); } +static inline void ffListRemoveAt(FFlist* list, uint32_t elementSize, uint32_t index) { + assert(list->length > index); + memmove(list->data + (index * elementSize), list->data + ((index + 1) * elementSize), (size_t) (list->length - index - 1) * elementSize); + --list->length; +} + +static inline void ffListInsertAt(FFlist* list, uint32_t elementSize, uint32_t index, const void* element) { + assert(list->length >= index); + ffListAdd(list, elementSize); + memmove(list->data + ((index + 1) * elementSize), list->data + (index * elementSize), (size_t) (list->length - index - 1) * elementSize); + memcpy(list->data + (index * elementSize), element, elementSize); +} + #define FF_LIST_FOR_EACH(itemType, itemVarName, listVar) \ for (itemType* itemVarName = (itemType*) (listVar).data; \ itemVarName - (itemType*) (listVar).data < (intptr_t) (listVar).length; \ @@ -125,6 +139,12 @@ static inline void* ffListAdd(FFlist* list, uint32_t elementSize) { #define FF_LIST_ADD(itemType, listVar) (itemType*) ffListAdd(&(listVar), (uint32_t) sizeof(itemType)) +#define FF_LIST_REMOVE_AT(itemType, listVar, index) \ + ffListRemoveAt(&(listVar), (uint32_t) sizeof(itemType), (index)) + +#define FF_LIST_INSERT_AT(itemType, listVar, index, pElement) \ + ffListInsertAt(&(listVar), (uint32_t) sizeof(itemType), (index), (pElement)) + #define FF_LIST_FIRST(itemType, listVar) FF_LIST_GET(itemType, listVar, 0) #define FF_LIST_LAST(itemType, listVar) \ ({ \ @@ -134,9 +154,9 @@ static inline void* ffListAdd(FFlist* list, uint32_t elementSize) { #define FF_LIST_CONTAINS(listVar, pCompElement, compFunc) \ ({ \ - typedef typeof(*(pCompElement)) compElementType; \ + typedef typeof(*(pCompElement)) compElementType; \ typedef bool compFuncType(const compElementType*, const compElementType*); \ - static_assert(__builtin_types_compatible_p(typeof(compFunc), compFuncType), "Incompatible callback function"); \ + static_assert(__builtin_types_compatible_p(typeof(compFunc), compFuncType), "Incompatible callback function"); \ ffListContains(&(listVar), (uint32_t) sizeof(*(pCompElement)), (pCompElement), (bool (*)(const void*, const void*)) compFunc); \ }) diff --git a/tests/list.c b/tests/list.c index 2184dd79c..a42d08878 100644 --- a/tests/list.c +++ b/tests/list.c @@ -100,6 +100,79 @@ int main(void) { VERIFY(*FF_LIST_GET(uint32_t, list, 0) == 2); VERIFY(*FF_LIST_GET(uint32_t, list, list.length - 1) == FF_LIST_DEFAULT_ALLOC); + // insertAt + ffListClear(&list); + for (uint32_t i = 1; i <= 5; ++i) { + *FF_LIST_ADD(uint32_t, list) = i; + } + // list = [1,2,3,4,5] + + { + uint32_t v = 0; + FF_LIST_INSERT_AT(uint32_t, list, 0, &v); // insert at head + } + VERIFY(list.length == 6); + VERIFY(*FF_LIST_GET(uint32_t, list, 0) == 0); + VERIFY(*FF_LIST_GET(uint32_t, list, 1) == 1); + VERIFY(*FF_LIST_GET(uint32_t, list, 5) == 5); + // list = [0,1,2,3,4,5] + + { + uint32_t v = 99; + FF_LIST_INSERT_AT(uint32_t, list, 3, &v); // insert in the middle + } + VERIFY(list.length == 7); + VERIFY(*FF_LIST_GET(uint32_t, list, 2) == 2); + VERIFY(*FF_LIST_GET(uint32_t, list, 3) == 99); + VERIFY(*FF_LIST_GET(uint32_t, list, 4) == 3); + VERIFY(*FF_LIST_GET(uint32_t, list, 6) == 5); + // list = [0,1,2,99,3,4,5] + + { + uint32_t v = 6; + FF_LIST_INSERT_AT(uint32_t, list, list.length, &v); // insert at tail + } + VERIFY(list.length == 8); + VERIFY(*FF_LIST_GET(uint32_t, list, 3) == 99); + VERIFY(*FF_LIST_GET(uint32_t, list, 7) == 6); + // list = [0,1,2,99,3,4,5,6] + + ffListClear(&list); + { + uint32_t v = 42; + FF_LIST_INSERT_AT(uint32_t, list, 0, &v); // insert into empty list + } + VERIFY(list.length == 1); + VERIFY(*FF_LIST_GET(uint32_t, list, 0) == 42); + + // removeAt + FF_LIST_REMOVE_AT(uint32_t, list, 0); // remove the only element + VERIFY(list.length == 0); + + for (uint32_t i = 1; i <= 5; ++i) { + *FF_LIST_ADD(uint32_t, list) = i; + } + // list = [1,2,3,4,5] + + FF_LIST_REMOVE_AT(uint32_t, list, 0); // remove head + VERIFY(list.length == 4); + VERIFY(*FF_LIST_GET(uint32_t, list, 0) == 2); + VERIFY(*FF_LIST_GET(uint32_t, list, list.length - 1) == 5); + // list = [2,3,4,5] + + FF_LIST_REMOVE_AT(uint32_t, list, 1); // remove in the middle + VERIFY(list.length == 3); + VERIFY(*FF_LIST_GET(uint32_t, list, 0) == 2); + VERIFY(*FF_LIST_GET(uint32_t, list, 1) == 4); + VERIFY(*FF_LIST_GET(uint32_t, list, 2) == 5); + // list = [2,4,5] + + FF_LIST_REMOVE_AT(uint32_t, list, list.length - 1); // remove tail + VERIFY(list.length == 2); + VERIFY(*FF_LIST_GET(uint32_t, list, 0) == 2); + VERIFY(*FF_LIST_GET(uint32_t, list, 1) == 4); + // list = [2,4] + // Destroy ffListDestroy(&list);