FFlist: adds FF_LIST_INSERT_AT and FF_LIST_REMOVE_AT

This commit is contained in:
Carter Li
2026-08-04 15:08:38 +08:00
parent 3196f5efaa
commit 2af56232a4
2 changed files with 95 additions and 2 deletions
+22 -2
View File
@@ -4,6 +4,7 @@
#include <stdint.h> #include <stdint.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#define FF_LIST_DEFAULT_ALLOC 16 #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); 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) \ #define FF_LIST_FOR_EACH(itemType, itemVarName, listVar) \
for (itemType* itemVarName = (itemType*) (listVar).data; \ for (itemType* itemVarName = (itemType*) (listVar).data; \
itemVarName - (itemType*) (listVar).data < (intptr_t) (listVar).length; \ 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_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_FIRST(itemType, listVar) FF_LIST_GET(itemType, listVar, 0)
#define FF_LIST_LAST(itemType, listVar) \ #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) \ #define FF_LIST_CONTAINS(listVar, pCompElement, compFunc) \
({ \ ({ \
typedef typeof(*(pCompElement)) compElementType; \ typedef typeof(*(pCompElement)) compElementType; \
typedef bool compFuncType(const compElementType*, const 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); \ ffListContains(&(listVar), (uint32_t) sizeof(*(pCompElement)), (pCompElement), (bool (*)(const void*, const void*)) compFunc); \
}) })
+73
View File
@@ -100,6 +100,79 @@ int main(void) {
VERIFY(*FF_LIST_GET(uint32_t, list, 0) == 2); VERIFY(*FF_LIST_GET(uint32_t, list, 0) == 2);
VERIFY(*FF_LIST_GET(uint32_t, list, list.length - 1) == FF_LIST_DEFAULT_ALLOC); 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 // Destroy
ffListDestroy(&list); ffListDestroy(&list);