GBAlatro
A Demake of Balatro for the GBA
Loading...
Searching...
No Matches
list.c
Go to the documentation of this file.
1
7#include "list.h"
8
9#include "pool.h"
10
11#include <stdbool.h>
12
23static void s_list_remove_node(List* list, ListNode* node);
24
37
39{
40 List list = LIST_DEFAULT;
41 return list;
42}
43
44void list_clear(List* list)
45{
46 if (list_is_empty(list))
47 return;
48
49 ListItr itr = list_itr_create(list);
50 ListNode* ln;
51
52 while ((ln = s_list_itr_node_next(&itr)))
53 {
54 POOL_FREE(ListNode, ln);
55 }
56
57 list->head = NULL;
58 list->tail = NULL;
59 list->len = 0;
60}
61
62bool list_is_empty(const List* list)
63{
64 return list->len == 0;
65}
66
67void list_push_front(List* list, void* data)
68{
69 ListNode* node = POOL_GET(ListNode);
70
71 node->data = data;
72 node->prev = NULL;
73 node->next = list->head;
74
75 if (list_is_empty(list))
76 {
77 list->tail = node;
78 }
79 else
80 {
81 list->head->prev = node;
82 }
83
84 list->head = node;
85
86 list->len++;
87}
88
89void list_push_back(List* list, void* data)
90{
91 ListNode* node = POOL_GET(ListNode);
92 node->data = data;
93 node->prev = list->tail;
94 node->next = NULL;
95
96 if (list_is_empty(list))
97 {
98 list->head = node;
99 }
100 else
101 {
102 list->tail->next = node;
103 }
104
105 list->tail = node;
106
107 list->len++;
108}
109
110void list_insert(List* list, void* data, unsigned int idx)
111{
112 if (idx >= list->len)
113 {
114 list_push_back(list, data);
115 return;
116 }
117
118 if (idx == 0)
119 {
120 list_push_front(list, data);
121 return;
122 }
123
124 // After the above two checks the index is guaranteed to be inbetween the
125 // `head` and `tail` of the `list`. This means the actual list doesn't need
126 // to modify it's head and tail, only it's length. Simplifying the code below:
127
128 unsigned int curr_idx = 0;
129 ListItr itr = list_itr_create(list);
130 ListNode* ln;
131
132 while ((ln = s_list_itr_node_next(&itr)))
133 {
134 if (idx == curr_idx++)
135 {
136 ListNode* node = POOL_GET(ListNode);
137 node->prev = ln->prev;
138 node->next = ln;
139 ln->prev->next = node;
140 ln->prev = node;
141 node->data = data;
142 list->len++;
143 return;
144 }
145 }
146}
147
148bool list_swap(List* list, unsigned int idx_a, unsigned int idx_b)
149{
150 if (idx_a >= list->len || idx_b >= list->len)
151 return false;
152 if (idx_a == idx_b)
153 return true; // swapping with yourself isn't technically an error
154
155 unsigned int curr_idx = 0;
156 unsigned int max_idx = idx_a > idx_b ? idx_a : idx_b;
157 ListNode* node_a = NULL;
158 ListNode* node_b = NULL;
159
160 ListItr itr = list_itr_create(list);
161 ListNode* ln;
162
163 do
164 {
165 ln = s_list_itr_node_next(&itr);
166 if (idx_a == curr_idx)
167 {
168 node_a = ln;
169 continue;
170 }
171 if (idx_b == curr_idx)
172 {
173 node_b = ln;
174 continue;
175 }
176 } while (max_idx != curr_idx++);
177
178 // Just swap the data pointers
179 void* tmp = node_a->data;
180 node_a->data = node_b->data;
181 node_b->data = tmp;
182
183 return true;
184}
185
186static void s_list_remove_node(List* list, ListNode* node)
187{
188 if (node->prev && !node->next) // end of list
189 {
190 node->prev->next = NULL;
191 list->tail = node->prev;
192 }
193 else if (node->prev && node->next) // somewhere in between
194 {
195 node->prev->next = node->next;
196 node->next->prev = node->prev;
197 }
198 else if (node->next && !node->prev) // beginning of list
199 {
200 node->next->prev = NULL;
201 list->head = node->next;
202 }
203 else if (!node->prev && !node->next) // only element in list
204 {
205 list->head = NULL;
206 list->tail = NULL;
207 }
208
209 POOL_FREE(ListNode, node);
210
211 list->len--;
212}
213
214int list_get_len(const List* list)
215{
216 return list->len;
217}
218
219void* list_get_at_idx(List* list, unsigned int idx)
220{
221 if (idx >= list_get_len(list))
222 return NULL;
223
224 int curr_idx = 0;
225 ListItr itr = list_itr_create(list);
226 void* data = NULL;
227
228 while ((data = list_itr_next(&itr)))
229 {
230 if (idx == curr_idx++)
231 return data;
232 }
233
234 return NULL;
235}
236
237bool list_remove_at_idx(List* list, unsigned int idx)
238{
239 if (idx >= list_get_len(list))
240 return false;
241
242 int len = 0;
243 ListItr itr = list_itr_create(list);
244 ListNode* ln;
245
246 while ((ln = s_list_itr_node_next(&itr)))
247 {
248 if (idx == len++)
249 {
250 s_list_remove_node(list, ln);
251 return true;
252 }
253 }
254 return false;
255}
256
258{
259 ListItr itr = {
260 .list = list,
261 .next_node = !list_is_empty(list) ? list->head : NULL,
262 .current_node = NULL,
263 .direction = LIST_ITR_FORWARD,
264 };
265
266 return itr;
267}
268
270{
271 ListItr itr = {
272 .list = list,
273 .next_node = !list_is_empty(list) ? list->tail : NULL,
274 .current_node = NULL,
275 .direction = LIST_ITR_REVERSE,
276 };
277
278 return itr;
279}
280
282{
284 return ln ? ln->data : NULL;
285}
286
288{
289 if (!itr->next_node)
290 return NULL;
291
292 itr->current_node = itr->next_node;
293
294 ListNode* ln = itr->next_node;
295 ListNode* next_itr_node = (itr->direction == LIST_ITR_FORWARD) ? ln->next : ln->prev;
296
297 if (next_itr_node)
298 {
299 itr->next_node = next_itr_node;
300 return ln;
301 }
302
303 itr->next_node = NULL;
304 return ln;
305}
306
308{
309 if (!itr || !itr->current_node)
310 return;
311 ListNode* tmp_prev = itr->current_node->prev;
313 itr->current_node = tmp_prev;
314}
315
316bool list_remove_data(List* list, void* data)
317{
318 ListItr itr = list_itr_create(list);
319 ListNode* ln;
320
321 while ((ln = s_list_itr_node_next(&itr)))
322 {
323 if (ln->data == data)
324 {
325 s_list_remove_node(list, ln);
326 return true;
327 }
328 }
329
330 return false;
331}
bool list_swap(List *list, unsigned int idx_a, unsigned int idx_b)
Definition list.c:148
bool list_is_empty(const List *list)
Definition list.c:62
List list_init(void)
Definition list.c:38
void * list_get_at_idx(List *list, unsigned int idx)
Definition list.c:219
void list_insert(List *list, void *data, unsigned int idx)
Definition list.c:110
static void s_list_remove_node(List *list, ListNode *node)
Definition list.c:186
int list_get_len(const List *list)
Definition list.c:214
static ListNode * s_list_itr_node_next(ListItr *itr)
Definition list.c:287
void list_push_front(List *list, void *data)
Definition list.c:67
ListItr rev_list_itr_create(List *list)
Definition list.c:269
void list_clear(List *list)
Definition list.c:44
void list_itr_remove_current_node(ListItr *itr)
Definition list.c:307
void * list_itr_next(ListItr *itr)
Definition list.c:281
bool list_remove_data(List *list, void *data)
Definition list.c:316
bool list_remove_at_idx(List *list, unsigned int idx)
Definition list.c:237
void list_push_back(List *list, void *data)
Definition list.c:89
ListItr list_itr_create(List *list)
Definition list.c:257
A doubly-linked list.
#define LIST_DEFAULT
Default list declaration for empty lists.
Definition list.h:30
An iterator into a list.
Definition list.h:91
ListNode * current_node
The current node in the list iterator.
Definition list.h:107
ListNode * next_node
The next node in the list.
Definition list.h:100
enum ListItrDirection direction
The direction of the iterator.
Definition list.h:112
List * list
A pointer to the List this is iterating through.
Definition list.h:95
A single entry in a List.
Definition list.h:39
void * data
Pointer to generic data stored in this node.
Definition list.h:54
ListNode * prev
The previous ListNode in the associated List, NULL if at the head of the list.
Definition list.h:44
ListNode * next
The next ListNode in the associated List, NULL if at the tail of the list.
Definition list.h:49
A doubly-linked list.
Definition list.h:61
ListNode * head
The first entry in the list.
Definition list.h:65
ListNode * tail
The last entry in the list.
Definition list.h:70
int len
Number of elements in list.
Definition list.h:75