1 /**
2 * @file lv_ll.c
3 * Handle linked lists.
4 * The nodes are dynamically allocated by the 'lv_mem' module,
5 */
6
7 /*********************
8 * INCLUDES
9 *********************/
10 #include <stdint.h>
11 #include <string.h>
12
13 #include "lv_ll.h"
14 #include "lv_mem.h"
15
16 /*********************
17 * DEFINES
18 *********************/
19 #define LL_NODE_META_SIZE (sizeof(lv_ll_node_t *) + sizeof(lv_ll_node_t *))
20 #define LL_PREV_P_OFFSET(ll_p) (ll_p->n_size)
21 #define LL_NEXT_P_OFFSET(ll_p) (ll_p->n_size + sizeof(lv_ll_node_t *))
22
23 /**********************
24 * TYPEDEFS
25 **********************/
26
27 /**********************
28 * STATIC PROTOTYPES
29 **********************/
30 static void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * prev);
31 static void node_set_next(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * next);
32
33 /**********************
34 * STATIC VARIABLES
35 **********************/
36
37 /**********************
38 * MACROS
39 **********************/
40
41 /**********************
42 * GLOBAL FUNCTIONS
43 **********************/
44
45 /**
46 * Initialize linked list
47 * @param ll_dsc pointer to ll_dsc variable
48 * @param node_size the size of 1 node in bytes
49 */
lv_ll_init(lv_ll_t * ll_p,uint32_t node_size)50 void lv_ll_init(lv_ll_t * ll_p, uint32_t node_size)
51 {
52 ll_p->head = NULL;
53 ll_p->tail = NULL;
54 #ifdef LV_MEM_ENV64
55 /*Round the size up to 8*/
56 if(node_size & 0x7) {
57 node_size = node_size & (~0x7);
58 node_size += 8;
59 }
60 #else
61 /*Round the size up to 4*/
62 if(node_size & 0x3) {
63 node_size = node_size & (~0x3);
64 node_size += 4;
65 }
66 #endif
67
68 ll_p->n_size = node_size;
69 }
70
71 /**
72 * Add a new head to a linked list
73 * @param ll_p pointer to linked list
74 * @return pointer to the new head
75 */
lv_ll_ins_head(lv_ll_t * ll_p)76 void * lv_ll_ins_head(lv_ll_t * ll_p)
77 {
78 lv_ll_node_t * n_new;
79
80 n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);
81
82 if(n_new != NULL) {
83 node_set_prev(ll_p, n_new, NULL); /*No prev. before the new head*/
84 node_set_next(ll_p, n_new, ll_p->head); /*After new comes the old head*/
85
86 if(ll_p->head != NULL) { /*If there is old head then before it goes the new*/
87 node_set_prev(ll_p, ll_p->head, n_new);
88 }
89
90 ll_p->head = n_new; /*Set the new head in the dsc.*/
91 if(ll_p->tail == NULL) { /*If there is no tail (1. node) set the tail too*/
92 ll_p->tail = n_new;
93 }
94 }
95
96 return n_new;
97 }
98
99 /**
100 * Insert a new node in front of the n_act node
101 * @param ll_p pointer to linked list
102 * @param n_act pointer a node
103 * @return pointer to the new head
104 */
lv_ll_ins_prev(lv_ll_t * ll_p,void * n_act)105 void * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act)
106 {
107 lv_ll_node_t * n_new;
108 lv_ll_node_t * n_prev;
109
110 if(NULL == ll_p || NULL == n_act) return NULL;
111
112 if(lv_ll_get_head(ll_p) == n_act) {
113 n_new = lv_ll_ins_head(ll_p);
114 if(n_new == NULL) return NULL;
115 } else {
116 n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);
117 if(n_new == NULL) return NULL;
118
119 n_prev = lv_ll_get_prev(ll_p, n_act);
120 node_set_next(ll_p, n_prev, n_new);
121 node_set_prev(ll_p, n_new, n_prev);
122 node_set_prev(ll_p, n_act, n_new);
123 node_set_next(ll_p, n_new, n_act);
124 }
125
126 return n_new;
127 }
128
129 /**
130 * Add a new tail to a linked list
131 * @param ll_p pointer to linked list
132 * @return pointer to the new tail
133 */
lv_ll_ins_tail(lv_ll_t * ll_p)134 void * lv_ll_ins_tail(lv_ll_t * ll_p)
135 {
136 lv_ll_node_t * n_new;
137
138 n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);
139 if(n_new == NULL) return NULL;
140
141 if(n_new != NULL) {
142 node_set_next(ll_p, n_new, NULL); /*No next after the new tail*/
143 node_set_prev(ll_p, n_new, ll_p->tail); /*The prev. before new is tho old tail*/
144 if(ll_p->tail != NULL) { /*If there is old tail then the new comes after it*/
145 node_set_next(ll_p, ll_p->tail, n_new);
146 }
147
148 ll_p->tail = n_new; /*Set the new tail in the dsc.*/
149 if(ll_p->head == NULL) { /*If there is no head (1. node) set the head too*/
150 ll_p->head = n_new;
151 }
152 }
153
154 return n_new;
155 }
156
157 /**
158 * Remove the node 'node_p' from 'll_p' linked list.
159 * It does not free the the memory of node.
160 * @param ll_p pointer to the linked list of 'node_p'
161 * @param node_p pointer to node in 'll_p' linked list
162 */
lv_ll_rem(lv_ll_t * ll_p,void * node_p)163 void lv_ll_rem(lv_ll_t * ll_p, void * node_p)
164 {
165 if(lv_ll_get_head(ll_p) == node_p) {
166 /*The new head will be the node after 'n_act'*/
167 ll_p->head = lv_ll_get_next(ll_p, node_p);
168 if(ll_p->head == NULL) {
169 ll_p->tail = NULL;
170 } else {
171 node_set_prev(ll_p, ll_p->head, NULL);
172 }
173 } else if(lv_ll_get_tail(ll_p) == node_p) {
174 /*The new tail will be the node before 'n_act'*/
175 ll_p->tail = lv_ll_get_prev(ll_p, node_p);
176 if(ll_p->tail == NULL) {
177 ll_p->head = NULL;
178 } else {
179 node_set_next(ll_p, ll_p->tail, NULL);
180 }
181 } else {
182 lv_ll_node_t * n_prev = lv_ll_get_prev(ll_p, node_p);
183 lv_ll_node_t * n_next = lv_ll_get_next(ll_p, node_p);
184
185 node_set_next(ll_p, n_prev, n_next);
186 node_set_prev(ll_p, n_next, n_prev);
187 }
188 }
189
190 /**
191 * Remove and free all elements from a linked list. The list remain valid but become empty.
192 * @param ll_p pointer to linked list
193 */
lv_ll_clear(lv_ll_t * ll_p)194 void lv_ll_clear(lv_ll_t * ll_p)
195 {
196 void * i;
197 void * i_next;
198
199 i = lv_ll_get_head(ll_p);
200 i_next = NULL;
201
202 while(i != NULL) {
203 i_next = lv_ll_get_next(ll_p, i);
204
205 lv_ll_rem(ll_p, i);
206 lv_mem_free(i);
207
208 i = i_next;
209 }
210 }
211
212 /**
213 * Move a node to a new linked list
214 * @param ll_ori_p pointer to the original (old) linked list
215 * @param ll_new_p pointer to the new linked list
216 * @param node pointer to a node
217 * @param head true: be the head in the new list
218 * false be the head in the new list
219 */
lv_ll_chg_list(lv_ll_t * ll_ori_p,lv_ll_t * ll_new_p,void * node,bool head)220 void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node, bool head)
221 {
222 lv_ll_rem(ll_ori_p, node);
223
224 if(head) {
225 /*Set node as head*/
226 node_set_prev(ll_new_p, node, NULL);
227 node_set_next(ll_new_p, node, ll_new_p->head);
228
229 if(ll_new_p->head != NULL) { /*If there is old head then before it goes the new*/
230 node_set_prev(ll_new_p, ll_new_p->head, node);
231 }
232
233 ll_new_p->head = node; /*Set the new head in the dsc.*/
234 if(ll_new_p->tail == NULL) { /*If there is no tail (first node) set the tail too*/
235 ll_new_p->tail = node;
236 }
237 } else {
238 /*Set node as tail*/
239 node_set_prev(ll_new_p, node, ll_new_p->tail);
240 node_set_next(ll_new_p, node, NULL);
241
242 if(ll_new_p->tail != NULL) { /*If there is old tail then after it goes the new*/
243 node_set_next(ll_new_p, ll_new_p->tail, node);
244 }
245
246 ll_new_p->tail = node; /*Set the new tail in the dsc.*/
247 if(ll_new_p->head == NULL) { /*If there is no head (first node) set the head too*/
248 ll_new_p->head = node;
249 }
250 }
251 }
252
253 /**
254 * Return with head node of the linked list
255 * @param ll_p pointer to linked list
256 * @return pointer to the head of 'll_p'
257 */
lv_ll_get_head(const lv_ll_t * ll_p)258 void * lv_ll_get_head(const lv_ll_t * ll_p)
259 {
260 void * head = NULL;
261
262 if(ll_p != NULL) {
263 head = ll_p->head;
264 }
265
266 return head;
267 }
268
269 /**
270 * Return with tail node of the linked list
271 * @param ll_p pointer to linked list
272 * @return pointer to the head of 'll_p'
273 */
lv_ll_get_tail(const lv_ll_t * ll_p)274 void * lv_ll_get_tail(const lv_ll_t * ll_p)
275 {
276 void * tail = NULL;
277
278 if(ll_p != NULL) {
279 tail = ll_p->tail;
280 }
281
282 return tail;
283 }
284
285 /**
286 * Return with the pointer of the next node after 'n_act'
287 * @param ll_p pointer to linked list
288 * @param n_act pointer a node
289 * @return pointer to the next node
290 */
lv_ll_get_next(const lv_ll_t * ll_p,const void * n_act)291 void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act)
292 {
293 void * next = NULL;
294
295 if(ll_p != NULL) {
296 const lv_ll_node_t * n_act_d = n_act;
297 memcpy(&next, n_act_d + LL_NEXT_P_OFFSET(ll_p), sizeof(void *));
298 }
299
300 return next;
301 }
302
303 /**
304 * Return with the pointer of the previous node after 'n_act'
305 * @param ll_p pointer to linked list
306 * @param n_act pointer a node
307 * @return pointer to the previous node
308 */
lv_ll_get_prev(const lv_ll_t * ll_p,const void * n_act)309 void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act)
310 {
311 void * prev = NULL;
312
313 if(ll_p != NULL) {
314 const lv_ll_node_t * n_act_d = n_act;
315 memcpy(&prev, n_act_d + LL_PREV_P_OFFSET(ll_p), sizeof(void *));
316 }
317
318 return prev;
319 }
320
321 /**
322 * Return the length of the linked list.
323 * @param ll_p pointer to linked list
324 * @return length of the linked list
325 */
lv_ll_get_len(const lv_ll_t * ll_p)326 uint32_t lv_ll_get_len(const lv_ll_t * ll_p)
327 {
328 uint32_t len = 0;
329 void * node;
330
331 for(node = lv_ll_get_head(ll_p); node != NULL; node = lv_ll_get_next(ll_p, node)) {
332 len++;
333 }
334
335 return len;
336 }
337
lv_ll_swap(lv_ll_t * ll_p,void * n1_p,void * n2_p)338 void lv_ll_swap(lv_ll_t * ll_p, void * n1_p, void * n2_p)
339 {
340 (void)(ll_p);
341 (void)(n1_p);
342 (void)(n2_p);
343 /*TODO*/
344 }
345
346 /**
347 * Move a nodw before an other node in the same linked list
348 * @param ll_p pointer to a linked list
349 * @param n_act pointer to node to move
350 * @param n_after pointer to a node which should be after `n_act`
351 */
lv_ll_move_before(lv_ll_t * ll_p,void * n_act,void * n_after)352 void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after)
353 {
354 if(n_act == n_after) return; /*Can't move before itself*/
355
356 void * n_before;
357 if(n_after != NULL)
358 n_before = lv_ll_get_prev(ll_p, n_after);
359 else
360 n_before = lv_ll_get_tail(ll_p); /*if `n_after` is NULL `n_act` should be the new tail*/
361
362 if(n_act == n_before) return; /*Already before `n_after`*/
363
364 /*It's much easier to remove from the list and add again*/
365 lv_ll_rem(ll_p, n_act);
366
367 /*Add again by setting the prev. and next nodes*/
368 node_set_next(ll_p, n_before, n_act);
369 node_set_prev(ll_p, n_act, n_before);
370 node_set_prev(ll_p, n_after, n_act);
371 node_set_next(ll_p, n_act, n_after);
372
373 /*If `n_act` was moved before NULL then it become the new tail*/
374 if(n_after == NULL) ll_p->tail = n_act;
375
376 /*If `n_act` was moved before `NULL` then it's the new head*/
377 if(n_before == NULL) ll_p->head = n_act;
378 }
379
380 /**
381 * Check if a linked list is empty
382 * @param ll_p pointer to a linked list
383 * @return true: the linked list is empty; false: not empty
384 */
lv_ll_is_empty(lv_ll_t * ll_p)385 bool lv_ll_is_empty(lv_ll_t * ll_p)
386 {
387 if(ll_p == NULL) return true;
388
389 if(ll_p->head == NULL && ll_p->tail == NULL) return true;
390
391 return false;
392 }
393
394 /**********************
395 * STATIC FUNCTIONS
396 **********************/
397
398 /**
399 * Set the 'pervious node pointer' of a node
400 * @param ll_p pointer to linked list
401 * @param act pointer to a node which prev. node pointer should be set
402 * @param prev pointer to a node which should be the previous node before 'act'
403 */
node_set_prev(lv_ll_t * ll_p,lv_ll_node_t * act,lv_ll_node_t * prev)404 static void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * prev)
405 {
406 if(act == NULL) return; /*Can't set the prev node of `NULL`*/
407
408 uint32_t node_p_size = sizeof(lv_ll_node_t *);
409 if(prev)
410 memcpy(act + LL_PREV_P_OFFSET(ll_p), &prev, node_p_size);
411 else
412 memset(act + LL_PREV_P_OFFSET(ll_p), 0, node_p_size);
413 }
414
415 /**
416 * Set the 'next node pointer' of a node
417 * @param ll_p pointer to linked list
418 * @param act pointer to a node which next node pointer should be set
419 * @param next pointer to a node which should be the next node before 'act'
420 */
node_set_next(lv_ll_t * ll_p,lv_ll_node_t * act,lv_ll_node_t * next)421 static void node_set_next(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * next)
422 {
423 if(act == NULL) return; /*Can't set the next node of `NULL`*/
424
425 uint32_t node_p_size = sizeof(lv_ll_node_t *);
426 if(next)
427 memcpy(act + LL_NEXT_P_OFFSET(ll_p), &next, node_p_size);
428 else
429 memset(act + LL_NEXT_P_OFFSET(ll_p), 0, node_p_size);
430 }
431