summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ll.c303
-rw-r--r--src/ll.h24
2 files changed, 136 insertions, 191 deletions
diff --git a/src/ll.c b/src/ll.c
index 4819226..4e018f2 100644
--- a/src/ll.c
+++ b/src/ll.c
@@ -7,199 +7,192 @@
7 7
8typedef struct dll { 8typedef struct dll {
9 void *data; 9 void *data;
10 dlinkedlist_freecallback dfreecb; 10 dll_freecb freecb;
11 11
12 struct dll *next; 12 struct dll *next;
13 struct dll *prev; 13 struct dll *prev;
14} dllnode;
15 14
16typedef struct dlinkedlist { 15} dllnode;
16typedef struct dlinked {
17 int size;
17 dllnode *start; 18 dllnode *start;
18 dllnode *end; 19 dllnode *end;
19 size_t size; 20
20} dlinkedlist; 21} dlinkedlist;
21 22
22dllnode* dllnode_init(void *data, dlinkedlist_freecallback dfreecb) { 23
24dllnode* dllnode_init(void *data, dll_freecb fcb) {
23 dllnode *n = xcalloc(1, sizeof(*n)); 25 dllnode *n = xcalloc(1, sizeof(*n));
24 n->next = NULL;
25 n->prev = NULL;
26 n->data = data; 26 n->data = data;
27 n->dfreecb = dfreecb; 27 n->freecb = fcb;
28 n->prev = NULL;
29 n->next = NULL;
28 30
29 return n; 31 return n;
30} 32}
31 33
32int dllnode_free(dllnode **n) { 34int dllnode_free(dllnode **n) {
33 if(!n) { 35 if(!n)
34 errno = EINVAL; 36 RETURNWERR(EINVAL, 1);
35 return -1; 37 if(!(*n))
36 } 38 RETURNWERR(EINVAL, 1);
37 if(!(*n)) {
38 errno = EINVAL;
39 return -1;
40 }
41 39
42 if((*n)->dfreecb != NULL) 40 if((*n)->freecb != NULL)
43 (*n)->dfreecb((*n)->data); 41 (*n)->freecb((*n)->data);
44 free(*n); 42 free(*n);
45 *n = NULL; 43 *n = NULL;
46 44
47 return 0; 45 return 0;
48} 46}
49 47
50dlinkedlist * dlinkedlist_init(void) { 48dlinkedlist* dlinkedlist_init(void) {
51 dlinkedlist *ll = xcalloc(1, sizeof(*ll)); 49 dlinkedlist *ll = xcalloc(1, sizeof(*ll));
52
53 ll->start = NULL;
54 ll->end = NULL; 50 ll->end = NULL;
51 ll->start = NULL;
55 ll->size = 0; 52 ll->size = 0;
56 53
57 return ll; 54 return ll;
58} 55}
59 56
60int dlinkedlist_free(dlinkedlist **ll) { 57int dlinkedlist_free(dlinkedlist **ll) {
61 if(!ll) { 58 if(!ll)
62 errno = EINVAL; 59 RETURNWERR(EINVAL, 1);
63 return -1; 60 if(!(*ll))
64 } 61 RETURNWERR(EINVAL, 1);
65 if(!(*ll)) { 62
66 errno = EINVAL; 63 for(dllnode *n; (*ll)->start != NULL;) {
67 return -1; 64 n = (*ll)->start->next;
68 } 65 dllnode_free(&((*ll)->start));
69 66 (*ll)->start = n;
70 dllnode *p = (*ll)->start, *n;
71 while(p != NULL) {
72 n = p->next;
73 dllnode_free(&p);
74 p = n;
75 } 67 }
76
77 free(*ll); 68 free(*ll);
78 (*ll) = NULL; 69 *ll = NULL;
70
79 return 0; 71 return 0;
80} 72}
81 73
82int dlinkedlist_firstitem(dlinkedlist * const ll, void *data, dlinkedlist_freecallback dfreecb) { 74int dlinkedlist_size(const dlinkedlist * const ll) {
83 if(!ll) { 75 if(!ll)
84 errno = EINVAL; 76 RETURNWERR(EINVAL, -1);
85 return -1; 77
86 } 78 return ll->size;
87 if(ll->size != 0) 79}
88 return 0;
89 80
90 dllnode *n = dllnode_init(data, dfreecb); 81int dlinkedlist_handlefirstnode(dlinkedlist * const ll, void *data, dll_freecb fcb) {
82 if(!ll)
83 RETURNWERR(EINVAL, 1);
84 if(ll->size > 0)
85 return 1;
91 86
92 ll->start = n; 87 // Need to handle adding the first element differently than other opers, so do it here
88 dllnode *n = dllnode_init(data, fcb);
89 // dllnode_init already sets n.prev and n.next to null, so no need to do so again
90
93 ll->end = n; 91 ll->end = n;
92 ll->start = n;
94 ll->size = 1; 93 ll->size = 1;
95 94
96 return 1; 95 return 0;
97} 96}
98 97
99int dlinkedlist_insert(dlinkedlist * const ll, void *data, dlinkedlist_freecallback dfreecb) { 98int dlinkedlist_xxxend(dlinkedlist * const ll, void *data, dll_freecb fcb, char op) {
100 if(!ll) { 99 if(!ll)
101 errno = EINVAL; 100 RETURNWERR(EINVAL, 1);
102 return -1; 101 if(op != 'a' && op != 'p')
103 } 102 RETURNWERR(EINVAL, 1);
104 if(dlinkedlist_firstitem(ll, data, dfreecb) > 0) 103 if(dlinkedlist_handlefirstnode(ll, data, fcb) == 0)
105 return 0; 104 return 0;
106 105
107 dllnode *n = dllnode_init(data, dfreecb); 106 dllnode *n = dllnode_init(data, fcb);
108 n->prev = NULL; 107 switch (op) {
109 n->next = ll->start; 108 case 'a':
109 n->prev = ll->end;
110 ll->end->next = n;
111 ll->end = n;
112 break;
113
114 case 'p':
115 n->next = ll->start;
116 ll->start->prev = n;
117 ll->start = n;
118 break;
119
120 default:
121 abort();
122 }
110 123
111 ll->start->prev = n;
112 ll->start = n;
113 ll->size++; 124 ll->size++;
114
115 return 0; 125 return 0;
116} 126}
117 127
118int dlinkedlist_append(dlinkedlist * const ll, void *data, dlinkedlist_freecallback dfreecb) { 128int dlinkedlist_append(dlinkedlist * const ll, void *data, dll_freecb fcb) {
119 if(!ll) { 129 return dlinkedlist_xxxend(ll, data, fcb, 'a');
120 errno = EINVAL; 130}
121 return -1;
122 }
123 if(dlinkedlist_firstitem(ll, data, dfreecb) > 0)
124 return 0;
125
126 dllnode *n = dllnode_init(data, dfreecb);
127 n->prev = ll->end;
128 n->next = NULL;
129
130 ll->end->next = n;
131 ll->end = n;
132 ll->size++;
133 131
134 return 0; 132int dlinkedlist_prepend(dlinkedlist * const ll, void *data, dll_freecb fcb) {
133 return dlinkedlist_xxxend(ll, data, fcb, 'p');
135} 134}
136 135
137dllnode *dlinkedlist_getnode(const dlinkedlist * const ll, size_t index) { 136dllnode* dlinkedlist_getnode(const dlinkedlist * const ll, int index) {
138 if(!ll) { 137 if(!ll)
139 errno = EINVAL; 138 RETURNWERR(EINVAL, NULL);
140 return NULL; 139 if(index < 0 || index >= ll->size)
141 } 140 RETURNWERR(EINVAL, NULL);
142 if(index >= ll->size) {
143 errno = EINVAL;
144 return NULL;
145 }
146 141
147 // No need to loop if the desired indices are either the first or last
148 if(index == 0) 142 if(index == 0)
149 return ll->start->data; 143 return ll->start;
150 if(index == (ll->size - 1)) 144 if(index == (ll->size - 1))
151 return ll->end->data; 145 return ll->end;
152 146
153 int spoint = (index < (ll->size / 2)); 147 int spoint = (index <= (ll->size / 2));
154 dllnode *p = (spoint) ? ll->start : ll->end; 148 dllnode *p = (spoint) ? ll->start : ll->end;
155 size_t i = (spoint) ? 0 : ll->size-1; 149 int i = (spoint) ? 0 : ll->size - 1;
156 150
157 // This should (theoretically) cut down on fetch times 151 // This should (theoretically) be faster on average
158 for(; ((spoint) ? (i < index) : (i > index)) && p != NULL; ((spoint) ? i++ : i--), p = ((spoint) ? p->next : p->prev)); 152 for(; p != NULL && ((spoint) ? (i < index) : (i > index)); (spoint) ? i++ : i--, p = (spoint) ? p->next : p->prev);
159
160 // old imp (above is untested)
161 // for(size_t i = 0; i < index && p != NULL; i++, p = p->next);
162 153
163 return p; 154 return p;
164} 155}
165 156
166void *dlinkedlist_get(const dlinkedlist * const ll, size_t index) { 157int dlinkedlist_insert(dlinkedlist * const ll, void *data, dll_freecb fcb, int index) {
167 dllnode *n = dlinkedlist_getnode(ll, index); 158 if(!ll)
168 if(!n) 159 RETURNWERR(EINVAL, 1);
169 return NULL; 160 if(index < 0 || index >= ll->size)
161 RETURNWERR(EINVAL, 1);
162
163 // Handle the special cases of appending or prepending
164 if(index == 0)
165 return dlinkedlist_prepend(ll, data, fcb);
166 if(index == (ll->size - 1))
167 return dlinkedlist_append(ll, data, fcb);
168
169 // Insert between 2 nodes
170 // If you're inserting at index 2, the new node becomes index 2, and the previous node at index 2 moves to index 3
170 171
171 return n->data; 172 dllnode *new = dllnode_init(data, fcb);
172} 173 dllnode *current = dlinkedlist_getnode(ll, index);
174 if(!current)
175 abort();
176
177 current->prev->next = new;
178 new->prev = current->prev;
179 new->next = current;
180 current->prev = new;
173 181
174void *dlinkedlist_getfirst(const dlinkedlist * const ll) { 182 ll->size++;
175 return dlinkedlist_get(ll, 0); 183 return 0;
176} 184}
177 185
178void *dlinkedlist_getlast(const dlinkedlist * const ll) { 186int dlinkedlist_remove(dlinkedlist * const ll, int index) {
179 return dlinkedlist_get(ll, ll->size - 1); 187 if(!ll)
180} 188 RETURNWERR(EINVAL, 1);
189 if(index < 0 || index >= ll->size)
190 RETURNWERR(EINVAL, 2);
181 191
182int dlinkedlist_remove(dlinkedlist * const ll, size_t index) {
183 if(!ll) {
184 errno = EINVAL;
185 return -1;
186 }
187 if(index >= ll->size) {
188 errno = EINVAL;
189 return -1;
190 }
191
192 dllnode *current = dlinkedlist_getnode(ll, index); 192 dllnode *current = dlinkedlist_getnode(ll, index);
193 if(!current) { 193 if(!current)
194 /* gcc is halucinating an error where there isn't one, claiming that the size of the linked list could, somehow, magically 194 abort();
195 // grow in the time it takes to grab the desired node, and thus return NULL and cause a NULL Dereference. I am willing to 195
196 // be humble and state that the compiler is probably smarter than me, and there is MAYBE an edge case where is COULD occur,
197 // and thus I should do this check, but I'm unconvinced */
198 errno = ENOTRECOVERABLE;
199 return -2;
200 }
201
202 // Handle special cases of removing the start or end
203 if(index == 0) { 196 if(index == 0) {
204 ll->start = current->next; 197 ll->start = current->next;
205 ll->start->prev = NULL; 198 ll->start->prev = NULL;
@@ -207,13 +200,9 @@ int dlinkedlist_remove(dlinkedlist * const ll, size_t index) {
207 ll->end = current->prev; 200 ll->end = current->prev;
208 ll->end->next = NULL; 201 ll->end->next = NULL;
209 } else { 202 } else {
210 // Set the prior's next to the next, set the next's prior to the prior, delete the current one 203 current->prev->next = current->next;
211 dllnode *prev = current->prev; 204 current->next->prev = current->prev;
212 dllnode *next = current->next;
213 prev->next = next;
214 next->prev = prev;
215 } 205 }
216 // Wow, I genuinely can't think of the last time I've needed to use an if-elif-else block
217 206
218 dllnode_free(&current); 207 dllnode_free(&current);
219 ll->size--; 208 ll->size--;
@@ -221,50 +210,10 @@ int dlinkedlist_remove(dlinkedlist * const ll, size_t index) {
221 return 0; 210 return 0;
222} 211}
223 212
224size_t dlinkedlist_size(const dlinkedlist * const ll) { 213void* dlinkedlist_get(const dlinkedlist * const ll, int index) {
225 if(!ll) 214 dllnode *n = dlinkedlist_getnode(ll, index);
226 RETURNWERR(EINVAL, -1); 215 if(!n)
227 216 return NULL;
228 return ll->size;
229}
230
231int dlinkedlist_isempty(const dlinkedlist * const ll) {
232 if(!ll)
233 RETURNWERR(EINVAL, -1);
234
235 return (ll->size == 0);
236}
237
238
239
240
241// Sample code
242#define COMPILE_SAMPLE
243#ifdef COMPILE_SAMPLE
244
245#include <stdio.h>
246#include <string.h>
247
248int genfree(void *data) {
249 free(data);
250 return 0;
251}
252
253int main() {
254 dlinkedlist *dll = dlinkedlist_init();
255 dlinkedlist_append(dll, (void*)strdup("THIS"), genfree);
256 dlinkedlist_append(dll, (void*)strdup("IS"), genfree);
257 dlinkedlist_append(dll, (void*)strdup("A"), genfree);
258 dlinkedlist_append(dll, (void*)strdup("STRING"), genfree);
259
260 // This is crashing as of right now
261 char *retval;
262 for(int i = 0; i < dlinkedlist_size(dll); i++)
263 printf("%s ", (((retval = (char*)dlinkedlist_get(dll, i)) != NULL) ? retval : "null") );
264 printf("\n");
265
266 dlinkedlist_free(&dll);
267 217
268 return 0; 218 return n->data;
269} 219} \ No newline at end of file
270#endif \ No newline at end of file
diff --git a/src/ll.h b/src/ll.h
index 6e79ccd..6e4ccf9 100644
--- a/src/ll.h
+++ b/src/ll.h
@@ -1,22 +1,18 @@
1#ifndef __VXGG_REWRITE___LL_H___305861098005___ 1#ifndef __VXGG_REWRITE___LL_H___305861098005___
2#define __VXGG_REWRITE___LL_H___305861098005___ 2#define __VXGG_REWRITE___LL_H___305861098005___
3 3
4#include <stddef.h> 4typedef int (*dll_freecb)(void*);
5typedef struct dlinked dlinkedlist;
5 6
6typedef int (*dlinkedlist_freecallback)(void*); 7dlinkedlist* dlinkedlist_init(void);
7typedef struct dlinkedlist dlinkedlist;
8
9dlinkedlist * dlinkedlist_init(void);
10int dlinkedlist_free(dlinkedlist **ll); 8int dlinkedlist_free(dlinkedlist **ll);
9int dlinkedlist_append(dlinkedlist * const ll, void *data, dll_freecb fcb);
10int dlinkedlist_prepend(dlinkedlist * const ll, void *data, dll_freecb fcb);
11int dlinkedlist_insert(dlinkedlist * const ll, void *data, dll_freecb fcb, int index);
12void* dlinkedlist_get(const dlinkedlist * const ll, int index);
13int dlinkedlist_remove(dlinkedlist * const ll, int index);
11 14
12int dlinkedlist_insert(dlinkedlist * const ll, void *data, dlinkedlist_freecallback dfreecb); 15int dlinkedlist_size(const dlinkedlist * const ll);
13int dlinkedlist_append(dlinkedlist * const ll, void *data, dlinkedlist_freecallback dfreecb); 16#define dlinkedlist_isempty(ll) (dlinkedlist_size((ll)) == 0)
14void *dlinkedlist_get(const dlinkedlist * const ll, size_t index);
15void *dlinkedlist_getfirst(const dlinkedlist * const ll);
16void *dlinkedlist_getlast(const dlinkedlist * const ll);
17int dlinkedlist_remove(dlinkedlist * const ll, size_t index);
18
19size_t dlinkedlist_size(const dlinkedlist * const ll);
20int dlinkedlist_isempty(const dlinkedlist * const ll);
21 17
22#endif \ No newline at end of file 18#endif \ No newline at end of file