2021-04-15 18:59:26 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
2022-09-16 14:03:14 +08:00
|
|
|
#include "FFcheckmacros.h"
|
|
|
|
|
|
2021-05-07 14:55:43 +02:00
|
|
|
#include <stdbool.h>
|
2021-04-15 18:59:26 +02:00
|
|
|
#include <stdint.h>
|
2022-09-24 19:22:33 +08:00
|
|
|
#include <assert.h>
|
2022-10-17 13:19:48 +02:00
|
|
|
#include <stdlib.h>
|
2021-04-15 18:59:26 +02:00
|
|
|
|
|
|
|
|
#define FF_LIST_DEFAULT_ALLOC 16
|
|
|
|
|
|
|
|
|
|
typedef struct FFlist
|
|
|
|
|
{
|
2025-04-01 16:25:08 +08:00
|
|
|
uint8_t* data;
|
2021-04-15 18:59:26 +02:00
|
|
|
uint32_t elementSize;
|
|
|
|
|
uint32_t length;
|
|
|
|
|
uint32_t capacity;
|
|
|
|
|
} FFlist;
|
|
|
|
|
|
|
|
|
|
void* ffListAdd(FFlist* list);
|
|
|
|
|
|
2023-01-13 19:03:09 +08:00
|
|
|
// Removes the first element, and copy its value to `*result`
|
|
|
|
|
bool ffListShift(FFlist* list, void* result);
|
|
|
|
|
// Removes the last element, and copy its value to `*result`
|
|
|
|
|
bool ffListPop(FFlist* list, void* result);
|
|
|
|
|
|
2022-09-24 19:22:33 +08:00
|
|
|
static inline void ffListInit(FFlist* list, uint32_t elementSize)
|
|
|
|
|
{
|
2022-09-24 23:17:38 +08:00
|
|
|
assert(elementSize > 0);
|
2023-04-21 22:41:32 +08:00
|
|
|
list->elementSize = elementSize;
|
|
|
|
|
list->capacity = 0;
|
|
|
|
|
list->length = 0;
|
|
|
|
|
list->data = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-25 14:48:11 +08:00
|
|
|
static inline void ffListInitA(FFlist* list, uint32_t elementSize, uint32_t capacity)
|
|
|
|
|
{
|
|
|
|
|
ffListInit(list, elementSize);
|
|
|
|
|
list->capacity = capacity;
|
2025-04-01 16:25:08 +08:00
|
|
|
list->data = __builtin_expect(capacity == 0, 0) ? NULL : (uint8_t*) malloc((size_t)list->capacity * list->elementSize);
|
2024-10-25 14:48:11 +08:00
|
|
|
}
|
|
|
|
|
|
2023-04-21 22:41:32 +08:00
|
|
|
static inline FFlist ffListCreate(uint32_t elementSize)
|
|
|
|
|
{
|
|
|
|
|
FFlist result;
|
|
|
|
|
ffListInit(&result, elementSize);
|
|
|
|
|
return result;
|
2022-09-24 19:22:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void* ffListGet(const FFlist* list, uint32_t index)
|
|
|
|
|
{
|
2022-09-24 23:17:38 +08:00
|
|
|
assert(list->capacity > index);
|
2022-09-24 19:22:33 +08:00
|
|
|
return list->data + (index * list->elementSize);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-25 14:48:11 +08:00
|
|
|
FF_C_NODISCARD static inline uint32_t ffListFirstIndexComp(const FFlist* list, void* compElement, bool(*compFunc)(const void*, const void*))
|
|
|
|
|
{
|
|
|
|
|
for(uint32_t i = 0; i < list->length; i++)
|
|
|
|
|
{
|
|
|
|
|
if(compFunc(ffListGet(list, i), compElement))
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return list->length;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-29 10:31:20 +08:00
|
|
|
static inline bool ffListContains(const FFlist* list, void* compElement, bool(*compFunc)(const void*, const void*))
|
|
|
|
|
{
|
|
|
|
|
return ffListFirstIndexComp(list, compElement, compFunc) != list->length;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-17 13:19:48 +02:00
|
|
|
static inline void ffListSort(FFlist* list, int(*compar)(const void*, const void*))
|
|
|
|
|
{
|
|
|
|
|
qsort(list->data, list->length, list->elementSize, compar);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-12 11:30:04 +08:00
|
|
|
// Move the contents of `src` into `list`, and left `src` empty
|
|
|
|
|
static inline void ffListInitMove(FFlist* list, FFlist* src)
|
|
|
|
|
{
|
|
|
|
|
if (src)
|
|
|
|
|
{
|
|
|
|
|
list->elementSize = src->elementSize;
|
|
|
|
|
list->capacity = src->capacity;
|
|
|
|
|
list->length = src->length;
|
2023-06-13 09:13:37 +08:00
|
|
|
list->data = src->data;
|
2023-06-12 11:30:04 +08:00
|
|
|
ffListInit(src, list->elementSize);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ffListInit(list, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-21 22:41:32 +08:00
|
|
|
static inline void ffListDestroy(FFlist* list)
|
|
|
|
|
{
|
|
|
|
|
if (!list->data) return;
|
|
|
|
|
|
|
|
|
|
//Avoid free-after-use. These 3 assignments are cheap so don't remove them
|
|
|
|
|
list->capacity = list->length = 0;
|
|
|
|
|
free(list->data);
|
|
|
|
|
list->data = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-10 16:00:23 +08:00
|
|
|
static inline void ffListClear(FFlist* list)
|
|
|
|
|
{
|
|
|
|
|
list->length = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-13 09:52:18 +08:00
|
|
|
static inline void ffListReserve(FFlist* list, uint32_t newCapacity)
|
|
|
|
|
{
|
|
|
|
|
if (__builtin_expect(newCapacity <= list->capacity, false))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
list->data = (uint8_t*) realloc(list->data, (size_t) newCapacity * list->elementSize);
|
|
|
|
|
list->capacity = newCapacity;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-02 16:51:11 +08:00
|
|
|
#define FF_LIST_FOR_EACH(itemType, itemVarName, listVar) \
|
|
|
|
|
assert(sizeof(itemType) == (listVar).elementSize); \
|
|
|
|
|
for(itemType* itemVarName = (itemType*)(listVar).data; \
|
2023-01-15 00:59:33 +08:00
|
|
|
itemVarName - (itemType*)(listVar).data < (intptr_t)(listVar).length; \
|
2023-01-02 16:51:11 +08:00
|
|
|
++itemVarName)
|
|
|
|
|
|
2023-01-11 13:55:06 +08:00
|
|
|
#define FF_LIST_AUTO_DESTROY FFlist __attribute__((__cleanup__(ffListDestroy)))
|
2022-11-13 00:04:34 +08:00
|
|
|
|
2023-10-27 11:52:14 +08:00
|
|
|
#define FF_LIST_GET(itemType, listVar, index) \
|
|
|
|
|
({ \
|
|
|
|
|
assert(sizeof(itemType) == (listVar).elementSize); \
|
|
|
|
|
assert((listVar).capacity > (index)); \
|
|
|
|
|
(itemType*)(listVar).data + (index); \
|
|
|
|
|
})
|
2025-08-15 13:29:22 +08:00
|
|
|
|
|
|
|
|
#define FF_LIST_ADD(itemType, listVar) \
|
|
|
|
|
({ \
|
|
|
|
|
assert(sizeof(itemType) == (listVar).elementSize); \
|
|
|
|
|
(itemType*) ffListAdd(&(listVar)); \
|
|
|
|
|
})
|
2026-01-09 16:18:25 +08:00
|
|
|
|
|
|
|
|
#define FF_LIST_FIRST(itemType, listVar) FF_LIST_GET(itemType, listVar, 0)
|
|
|
|
|
#define FF_LIST_LAST(itemType, listVar) \
|
|
|
|
|
({ \
|
|
|
|
|
assert((listVar).length > 0); \
|
|
|
|
|
FF_LIST_GET(itemType, listVar, ((listVar).length - 1)); \
|
|
|
|
|
})
|