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
|
#ifndef _AL_LIST_H
#define _AL_LIST_H
#include "lib.h"
#define AL_LIST_DEFINE(type, name) \
AL_UNUSED_FUNCTION_PUSH \
typedef struct list_##name list_##name; \
struct list_##name { \
type value; \
list_##name *next; \
list_##name *prev; \
}; \
static inline list_##name *list_new_node_##name(type value) \
{ \
list_##name *node = (list_##name *)al_malloc(sizeof(list_##name)); \
node->value = value; \
return node; \
} \
static inline void list_free_node_##name(list_##name *l) \
{ \
free(l); \
} \
static inline list_##name *list_last_##name(list_##name *l) \
{ \
if (l) while (l->next) l = l->next; \
return l; \
} \
static inline list_##name *list_nth_##name(list_##name *l, u32 n) \
{ \
while (n-- > 0 && l) l = l->next; \
return l; \
} \
static inline list_##name *list_append_##name(list_##name *l, type value) \
{ \
list_##name *node = list_new_node_##name(value); \
node->next = NULL; \
if (l) { \
list_##name *last = list_last_##name(l); \
node->prev = last; \
last->next = node; \
return l; \
} else { \
node->prev = NULL; \
return node; \
} \
} \
static inline list_##name *list_prepend_##name(list_##name *l, type value) \
{ \
list_##name *node = list_new_node_##name(value); \
node->next = l; \
node->prev = NULL; \
if (l) l->prev = node; \
return node; \
} \
static inline list_##name *list_insert_after_##name(list_##name *l, list_##name *s, type value) \
{ \
if (!l) { \
list_##name *node = list_new_node_##name(value); \
node->next = NULL; \
node->prev = NULL; \
return node; \
} else if (!s || !s->next) { \
return list_append_##name(l, value); \
} else { \
list_##name *node = list_new_node_##name(value); \
s->next->prev = node; \
node->next = s->next; \
node->prev = s; \
s->next = node; \
return l; \
} \
} \
static inline list_##name *list_insert_before_##name(list_##name *l, list_##name *s, type value) \
{ \
if (!l) { \
list_##name *node = list_new_node_##name(value); \
node->next = NULL; \
node->prev = NULL; \
return node; \
} else if (!s) { \
return list_append_##name(l, value); \
} else if (s == l) { \
return list_prepend_##name(l, value); \
} else { \
list_##name *node = list_new_node_##name(value); \
s->prev->next = node; \
node->prev = s->prev; \
node->next = s; \
s->prev = node; \
return l; \
} \
} \
static inline list_##name *list_remove_##name(list_##name *l, list_##name *n) \
{ \
if (!l) { \
return l; \
} else if (l == n) { \
if (n->next) { \
n->next->prev = NULL; \
} \
l = n->next; \
list_free_node_##name(n); \
} else { \
n->prev->next = n->next; \
if (n->next) { \
n->next->prev = n->prev; \
} \
list_free_node_##name(n); \
} \
return l; \
} \
AL_UNUSED_FUNCTION_POP
#define list(name) list_##name
#define al_list_nth(name, list, n) list_nth_##name(list, n)
#define al_list_last(name, list) list_last_##name(list)
// If list is NULL, a new list is created.
#define al_list_append(name, list, value) list_append_##name(list, value)
#define al_list_prepend(name, list, value) list_prepend_##name(list, value)
// If sibiling->next is NULL (or just sibiling for before) append the value to the end of the list.
#define al_list_insert_after(name, list, sibling, value) list_insert_after_##name(list, sibling, value)
#define al_list_insert_before(name, list, sibling, value) list_insert_before_##name(list, sibling, value)
#define al_list_remove(name, list, node) list_remove_##name(list, node)
#define al_list_foreach(name, list, node) \
for (list_##name *node = list; node; node = node->next)
#endif // _AL_LIST_H
|