1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
#pragma once
#include "common/attributes.h"
#include <stdbool.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>
#define FF_LIST_DEFAULT_ALLOC 16
typedef struct FFlist {
uint8_t* data;
uint32_t length;
uint32_t capacity;
} FFlist;
void* ffListAdd(FFlist* list, uint32_t elementSize);
// Removes the first element, and copy its value to `*result`
bool ffListShift(FFlist* list, uint32_t elementSize, void* __restrict result);
// Removes the last element, and copy its value to `*result`
bool ffListPop(FFlist* list, uint32_t elementSize, void* __restrict result);
static inline void ffListInit(FFlist* list) {
list->capacity = 0;
list->length = 0;
list->data = NULL;
}
static inline void ffListInitA(FFlist* list, uint32_t elementSize, uint32_t capacity) {
ffListInit(list);
list->capacity = capacity;
list->data = __builtin_expect(capacity == 0, 0) ? NULL : (uint8_t*) malloc((size_t) capacity * elementSize);
}
FF_A_NODISCARD static inline FFlist ffListCreate() {
FFlist result;
ffListInit(&result);
return result;
}
FF_A_NODISCARD static inline FFlist ffListCreateA(uint32_t elementSize, uint32_t capacity) {
FFlist result;
ffListInitA(&result, elementSize, capacity);
return result;
}
FF_A_NODISCARD static inline void* ffListGet(const FFlist* list, uint32_t elementSize, uint32_t index) {
assert(list->capacity > index);
return list->data + (index * elementSize);
}
FF_A_NODISCARD static inline uint32_t ffListFirstIndexComp(const FFlist* list, uint32_t elementSize, void* compElement, bool (*compFunc)(const void*, const void*)) {
for (uint32_t i = 0; i < list->length; i++) {
if (compFunc(ffListGet(list, elementSize, i), compElement)) {
return i;
}
}
return list->length;
}
FF_A_NODISCARD static inline bool ffListContains(const FFlist* list, uint32_t elementSize, void* compElement, bool (*compFunc)(const void*, const void*)) {
return ffListFirstIndexComp(list, elementSize, compElement, compFunc) != list->length;
}
static inline void ffListSort(FFlist* list, uint32_t elementSize, int (*compar)(const void*, const void*)) {
qsort(list->data, list->length, elementSize, compar);
}
// Move the contents of `src` into `list`, and left `src` empty
static inline void ffListInitMove(FFlist* list, FFlist* src) {
if (src) {
list->capacity = src->capacity;
list->length = src->length;
list->data = src->data;
ffListInit(src);
} else {
ffListInit(list);
}
}
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;
}
static inline void ffListClear(FFlist* list) {
list->length = 0;
}
static inline void ffListReserve(FFlist* list, uint32_t elementSize, uint32_t newCapacity) {
if (__builtin_expect(newCapacity <= list->capacity, false)) {
return;
}
list->data = (uint8_t*) realloc(list->data, (size_t) newCapacity * elementSize);
list->capacity = newCapacity;
}
#define FF_LIST_FOR_EACH(itemType, itemVarName, listVar) \
for (itemType* itemVarName = (itemType*) (listVar).data; \
itemVarName - (itemType*) (listVar).data < (intptr_t) (listVar).length; \
++itemVarName)
#define FF_LIST_AUTO_DESTROY FFlist FF_A_CLEANUP(ffListDestroy)
#define FF_LIST_GET(itemType, listVar, index) \
({ \
assert((listVar).capacity > (index)); \
(itemType*) (listVar).data + (index); \
})
#define FF_LIST_ADD(itemType, listVar) (itemType*) ffListAdd(&(listVar), (uint32_t) sizeof(itemType))
#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)); \
})
#define FF_LIST_CONTAINS(listVar, pCompElement, compFunc) \
({ \
typedef __typeof__(*(pCompElement)) compElementType; \
typedef bool compFuncType(const compElementType*, const compElementType*); \
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); \
})
#define FF_LIST_SHIFT(listVar, pResult) \
ffListShift(&(listVar), (uint32_t) sizeof(*(pResult)), (pResult))
#define FF_LIST_POP(listVar, pResult) \
ffListPop(&(listVar), (uint32_t) sizeof(*(pResult)), (pResult))
|