Landtiger LPC1768 C BigLib 1
A self made, custom C library for the LandTiger board.
 
Loading...
Searching...
No Matches
cl_list.c
Go to the documentation of this file.
1#include "cl_list.h"
2
3#include <stdlib.h>
4#include <string.h>
5
6// TYPE DEFINITION
7
9{
10 void *data;
11 struct __ListNode *prev, *next;
12};
13
20
21// PRIVATE FUNCTIONS
22
23_PRIVATE inline struct __ListNode *create_node(CL_List *list, const void *const elem)
24{
25 struct __ListNode *node = MEM_Alloc(list->allocator, sizeof(struct __ListNode));
26 if (!node)
27 return NULL;
28
29 node->data = MEM_Alloc(list->allocator, list->elem_size);
30 if (!node->data)
31 {
32 MEM_Free(list->allocator, node);
33 return NULL;
34 }
35
36 memcpy(node->data, elem, list->elem_size);
37 node->prev = node->next = NULL;
38 return node;
39}
40
41// PUBLIC FUNCTIONS
42
43CL_List *CL_ListAlloc(MEM_Allocator *const alloc, u32 elem_sz)
44{
45 if (!alloc || !elem_sz)
46 return NULL;
47
48 CL_List *const list = MEM_Alloc(alloc, sizeof(CL_List));
49 if (!list)
50 return NULL;
51
52 *list = (CL_List){
53 .head = NULL,
54 .tail = NULL,
55 .size = 0,
56 .elem_size = elem_sz,
57 .allocator = alloc,
58 };
59
60 return list;
61}
62
63void CL_ListFree(CL_List *const list)
64{
65 if (!list)
66 return;
67
68 struct __ListNode *current = list->head, *copy;
69 while (current)
70 {
71 copy = current;
72 current = current->next;
73 MEM_Free(list->allocator, copy->data);
74 MEM_Free(list->allocator, copy);
75 }
76
77 MEM_Free(list->allocator, list);
78}
79
80CL_Error CL_ListPushBack(CL_List *const list, const void *const elem)
81{
82 if (!list || !elem)
84
85 struct __ListNode *new_node = create_node(list, elem);
86 if (!new_node)
87 return CL_ERR_NO_MEMORY;
88
89 if (!list->tail) // Empty list, set head and tail to the new node.
90 list->head = list->tail = new_node;
91 else
92 {
93 new_node->prev = list->tail; // Set the new node's previous to the current tail.
94 list->tail->next = new_node; // Set the current tail's next to the new node.
95 list->tail = new_node; // The new node is now the tail.
96 }
97
98 list->size++;
99 return CL_ERR_OK;
100}
101
102CL_Error CL_ListPushFront(CL_List *const list, const void *const elem)
103{
104 if (!list || !elem)
106
107 struct __ListNode *new_node = create_node(list, elem);
108 if (!new_node)
109 return CL_ERR_NO_MEMORY;
110
111 if (!list->head) // Empty list, set head and tail to the new node.
112 list->head = list->tail = new_node;
113 else
114 {
115 new_node->next = list->head; // Set the new node's next to the current head.
116 list->head->prev = new_node; // Set the current head's previous to the new node.
117 list->head = new_node; // The new node is now the head.
118 }
119
120 list->size++;
121 return CL_ERR_OK;
122}
123
124void CL_ListPopBack(CL_List *const list, void *out_elem)
125{
126 if (!list || !list->size)
127 return;
128
129 struct __ListNode *last = list->tail;
130 if (out_elem)
131 memcpy(out_elem, last->data, list->elem_size);
132
133 if (list->size == 1) // Only one element in the list, reset head and tail.
134 list->head = list->tail = NULL;
135 else
136 {
137 list->tail = last->prev; // Set the tail to the previous node.
138 list->tail->next = NULL; // The new tail's next is NULL.
139 }
140
141 MEM_Free(list->allocator, last->data);
142 MEM_Free(list->allocator, last);
143 list->size--;
144}
145
146void CL_ListPopFront(CL_List *const list, void *out_elem)
147{
148 if (!list || !list->size)
149 return;
150
151 struct __ListNode *first = list->head;
152 if (out_elem)
153 memcpy(out_elem, first->data, list->elem_size);
154
155 if (list->size == 1) // Only one element in the list, reset head and tail.
156 list->head = list->tail = NULL;
157 else
158 {
159 list->head = first->next; // Set the head to the next node;
160 list->head->prev = NULL; // The new head's previous is NULL.
161 }
162
163 MEM_Free(list->allocator, first->data);
164 MEM_Free(list->allocator, first);
165 list->size--;
166}
167
168CL_Error CL_ListGet(const CL_List *const list, u32 index, void *out_elem)
169{
170 if (!list || !out_elem)
172
173 if (index >= list->size)
175
176 u32 idx = 0;
177 struct __ListNode *current = list->head;
178 while (idx++ < index)
179 current = current->next;
180
181 // Now current is the node at the specified index.
182 memcpy(out_elem, current->data, list->elem_size);
183 return CL_ERR_OK;
184}
185
186CL_Error CL_ListGetPtr(const CL_List *const list, u32 index, void **out_elem)
187{
188 if (!list || !out_elem)
190
191 if (index >= list->size)
193
194 u32 idx = 0;
195 struct __ListNode *current = list->head;
196 while (idx++ < index)
197 current = current->next;
198
199 // Now current is the node at the specified index.
200 *out_elem = current->data;
201 return CL_ERR_OK;
202}
203
204CL_Error CL_ListGetLast(const CL_List *const list, void *out_elem)
205{
206 if (!list || !out_elem)
208
209 if (!list->size)
210 return CL_ERR_EMPTY;
211
212 memcpy(out_elem, list->tail->data, list->elem_size);
213 return CL_ERR_OK;
214}
215
216CL_Error CL_ListGetLastPtr(const CL_List *const list, void **out_elem)
217{
218 if (!list || !out_elem)
220
221 if (!list->size)
222 return CL_ERR_EMPTY;
223
224 *out_elem = list->tail->data;
225 return CL_ERR_OK;
226}
227
228CL_Error CL_ListInsertAt(CL_List *const list, u32 index, const void *const elem)
229{
230 if (!list || !elem)
232
233 if (index > list->size) // list->size is a valid index to insert at (insert at the back).
235
236 if (index == 0) // Insert at the front.
237 return CL_ListPushFront(list, elem);
238 else if (index == list->size) // Insert at the back.
239 return CL_ListPushBack(list, elem);
240
241 // If here, we need to insert in the middle.
242 struct __ListNode *new_node = create_node(list, elem), *current = list->head;
243 if (!new_node)
244 return CL_ERR_NO_MEMORY;
245
246 u32 idx = 0;
247 while (idx++ < index)
248 current = current->next;
249
250 // Now current is the node at the specified index.
251 new_node->prev = current->prev;
252 new_node->next = current;
253 current->prev = new_node;
254 new_node->prev->next = new_node;
255
256 list->size++;
257 return CL_ERR_OK;
258}
259
260CL_Error CL_ListRemoveAt(CL_List *const list, u32 index, void *out_elem)
261{
262 if (!list)
264
265 if (index >= list->size)
267
268 if (index == 0) // Remove from the front.
269 CL_ListPopFront(list, out_elem);
270 else if (index == list->size - 1) // Remove from the back.
271 CL_ListPopBack(list, out_elem);
272 else
273 {
274 // If here, we need to remove from the middle.
275 struct __ListNode *current = list->head;
276 u32 idx = 0;
277 while (idx++ < index)
278 current = current->next;
279
280 // Now current is the node at the specified index.
281 current->prev->next = current->next;
282 current->next->prev = current->prev;
283
284 if (out_elem)
285 memcpy(out_elem, current->data, list->elem_size);
286
287 MEM_Free(list->allocator, current);
288 list->size--;
289 }
290
291 return CL_ERR_OK;
292}
293
294bool CL_ListSearch(const CL_List *const list, const void *const elem, CL_CompareFn compare_fn, u32 *out_index)
295{
296 if (!list || !elem || !compare_fn)
297 return false;
298
299 struct __ListNode *current = list->head;
300 u32 idx = 0;
301 while (current)
302 {
303 if (compare_fn(current->data, elem) == 0)
304 {
305 if (out_index)
306 *out_index = idx;
307 return true;
308 }
309
310 current = current->next;
311 }
312
313 return false;
314}
315
316void CL_ListClear(CL_List *const list)
317{
318 if (!list || !list->size)
319 return;
320
321 struct __ListNode *current = list->head, *copy;
322 while (current)
323 {
324 copy = current;
325 current = current->next;
326 MEM_Free(list->allocator, copy->data);
327 MEM_Free(list->allocator, copy);
328 }
329
330 list->head = list->tail = NULL;
331 list->size = 0;
332}
333
334u32 CL_ListSize(const CL_List *const list)
335{
336 return list ? list->size : 0;
337}
338
339bool CL_ListIsEmpty(const CL_List *const list)
340{
341 return !list || !list->size;
342}
void MEM_Free(MEM_Allocator *ma, void *ptr)
Free a previously allocated block.
Definition allocator.c:98
void * MEM_Alloc(MEM_Allocator *ma, u32 size)
Allocate a block of memory from the pool with at least 'size' bytes.
Definition allocator.c:52
CL_Error CL_ListGetLastPtr(const CL_List *const list, void **out_elem)
Gets the last element from the list as a pointer, so the user can modify it.
Definition cl_list.c:216
void CL_ListPopFront(CL_List *const list, void *out_elem)
Removes the first element from the list, optionally returning it.
Definition cl_list.c:146
CL_Error CL_ListRemoveAt(CL_List *const list, u32 index, void *out_elem)
Removes an element at the specified index.
Definition cl_list.c:260
void CL_ListPopBack(CL_List *const list, void *out_elem)
Removes the last element from the list, optionally returning it.
Definition cl_list.c:124
void CL_ListClear(CL_List *const list)
Removes all elements from the list.
Definition cl_list.c:316
CL_Error CL_ListGetLast(const CL_List *const list, void *out_elem)
Gets the last element from the list.
Definition cl_list.c:204
bool CL_ListSearch(const CL_List *const list, const void *const elem, CL_CompareFn compare_fn, u32 *out_index)
Searches for an element in the list.
Definition cl_list.c:294
u32 CL_ListSize(const CL_List *const list)
Gets the number of elements in the list.
Definition cl_list.c:334
CL_Error CL_ListPushBack(CL_List *const list, const void *const elem)
Adds an element at the end of the list.
Definition cl_list.c:80
bool CL_ListIsEmpty(const CL_List *const list)
Checks if the list is empty.
Definition cl_list.c:339
void CL_ListFree(CL_List *const list)
Frees the memory previously assigned to the list.
Definition cl_list.c:63
CL_Error CL_ListGetPtr(const CL_List *const list, u32 index, void **out_elem)
Gets an element at the specified index as a pointer, so the user can modify it.
Definition cl_list.c:186
CL_List * CL_ListAlloc(MEM_Allocator *const alloc, u32 elem_sz)
Initializes a new doubly-linked list with tail, with the allocated memory provided by the user.
Definition cl_list.c:43
CL_Error CL_ListPushFront(CL_List *const list, const void *const elem)
Adds an element at the front of the list.
Definition cl_list.c:102
_PRIVATE struct __ListNode * create_node(CL_List *list, const void *const elem)
Definition cl_list.c:23
CL_Error CL_ListGet(const CL_List *const list, u32 index, void *out_elem)
Gets an element at the specified index.
Definition cl_list.c:168
CL_Error CL_ListInsertAt(CL_List *const list, u32 index, const void *const elem)
Inserts an element at the specified index.
Definition cl_list.c:228
struct __List CL_List
Definition cl_list.h:11
int(* CL_CompareFn)(const void *, const void *)
A function pointer type for comparing two elements.
Definition cl_types.h:7
CL_Error
Specify this in the size parameter of the collections initialization to tell the library that the num...
Definition cl_types.h:24
@ CL_ERR_EMPTY
Empty collection.
Definition cl_types.h:41
@ CL_ERR_OUT_OF_BOUNDS
Out of bounds.
Definition cl_types.h:32
@ CL_ERR_NO_MEMORY
No memory available.
Definition cl_types.h:35
@ CL_ERR_INVALID_PARAMS
Invalid arguments.
Definition cl_types.h:29
@ CL_ERR_OK
No error.
Definition cl_types.h:26
struct __ListNode * next
Definition cl_list.c:11
struct __ListNode * prev
Definition cl_list.c:11
void * data
Definition cl_list.c:10
u32 elem_size
Definition cl_list.c:17
struct __ListNode * head
Definition cl_list.c:16
struct __ListNode * tail
Definition cl_list.c:16
u32 size
Definition cl_list.c:17
MEM_Allocator * allocator
Definition cl_list.c:18
#define _PRIVATE
Definition types.h:37
uint32_t u32
Definition types.h:6