1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "lnklist.h"
4
5 struct lnklist_node {
6 struct lnklist_node *next;
7 struct lnklist_node *prev;
8 void *data;
9 };
10
11 struct lnklist {
12 struct lnklist_node *head;
13 struct lnklist_node *tail;
14 struct lnklist_node *iter;
15 int size;
16 };
17
18 static const struct lnklist_node LNKLIST_ITER_UNDERFLOW = {NULL, NULL, NULL};
19
20 #ifdef __LNKLIST_DEBUG__
21 int
main(int argc,char * argv[])22 main(int argc, char *argv[]) {
23 struct lnklist *list;
24 int count;
25
26 list = lnklist_create();
27 for(count = 0; count < 10000; count++) {
28 lnklist_add(list, malloc(100), lnklist_size(list));
29 }
30 for(count = 1000; count < 2000; count++) {
31 lnklist_add(list, malloc(100), lnklist_size(list));
32 }
33 for(count = 3000; count < 4000; count++) {
34 lnklist_add(list, malloc(100), lnklist_size(list));
35 }
36 for(count = 7000; count < 8000; count++) {
37 lnklist_add(list, malloc(100), lnklist_size(list));
38 }
39 for(count = 10000; count < 11000; count++) {
40 lnklist_add(list, malloc(100), lnklist_size(list));
41 }
42 for(count = 14000; count < 15000; count++) {
43 lnklist_add(list, malloc(100), lnklist_size(list));
44 }
45 fprintf(stderr, "lnklist_size(): %zd\n", lnklist_size(list));
46 lnklist_iter_init(list);
47 while(lnklist_iter_hasnext(list)) {
48 free(lnklist_iter_remove_next(list));
49 }
50 fprintf(stderr, "lnklist_size(): %zd\n", lnklist_size(list));
51 lnklist_destroy(list);
52 return 0;
53 }
54 #endif
55
56 struct lnklist *
lnklist_create(void)57 lnklist_create(void) {
58 struct lnklist *obj;
59
60 obj = (struct lnklist *)malloc(sizeof(struct lnklist));
61 if(obj) {
62 obj->head = NULL;
63 obj->tail = NULL;
64 obj->iter = (struct lnklist_node *)&LNKLIST_ITER_UNDERFLOW;
65 obj->size = 0;
66 }
67 return obj;
68 }
69
70 void
lnklist_destroy(struct lnklist * obj)71 lnklist_destroy(struct lnklist *obj) {
72 lnklist_destroy_with_destructor(obj, NULL);
73 }
74
75 void
lnklist_destroy_with_destructor(struct lnklist * obj,void (* destructor)(void *))76 lnklist_destroy_with_destructor(struct lnklist *obj, void (*destructor)(void *)) {
77 lnklist_iter_init(obj);
78 while(lnklist_iter_hasnext(obj)) {
79 destructor ? destructor(lnklist_iter_remove_next(obj)) : lnklist_iter_remove_next(obj);
80 }
81 free(obj);
82 }
83
84 ssize_t
lnklist_size(struct lnklist * obj)85 lnklist_size(struct lnklist *obj) {
86 return obj ? obj->size : -1;
87 }
88
89 void *
lnklist_add(struct lnklist * obj,void * data,int index)90 lnklist_add(struct lnklist *obj, void *data, int index) {
91 struct lnklist_node *node, *ptr;
92 int offset;
93
94 if(!obj || obj->size < index) {
95 return NULL;
96 }
97 node = (struct lnklist_node *)malloc(sizeof(struct lnklist_node));
98 if(!node) {
99 return NULL;
100 }
101 node->data = data;
102 if(index == 0 || index < obj->size / 2) {
103 ptr = obj->head;
104 for(offset = 0; offset < index; offset++) {
105 ptr = ptr->next;
106 }
107 node->prev = ptr ? ptr->prev : NULL;
108 node->next = ptr;
109 }
110 else {
111 ptr = obj->tail;
112 for(offset = obj->size - 1; offset > index; offset--) {
113 ptr = ptr->prev;
114 }
115 node->prev = ptr;
116 node->next = ptr ? ptr->next : NULL;
117 }
118 if(node->next) {
119 node->next->prev = node;
120 }
121 else {
122 obj->tail = node;
123 }
124 if(node->prev) {
125 node->prev->next = node;
126 }
127 else {
128 obj->head = node;
129 }
130 obj->size++;
131 return node->data;
132 }
133
134 void *
lnklist_add_tail(struct lnklist * obj,void * data)135 lnklist_add_tail(struct lnklist *obj, void *data) {
136 return obj ? lnklist_add(obj, data, obj->size) : NULL;
137 }
138
139 void *
lnklist_remove(struct lnklist * obj,int index)140 lnklist_remove(struct lnklist *obj, int index) {
141 struct lnklist_node *ptr;
142 int offset;
143 void *data;
144
145 if(!obj || obj->size <= index) {
146 return NULL;
147 }
148 if(index < obj->size / 2) {
149 ptr = obj->head;
150 for(offset = 0; offset < index; offset++) {
151 ptr = ptr->next;
152 }
153 }
154 else {
155 ptr = obj->tail;
156 for(offset = obj->size - 1; offset > index; offset--) {
157 ptr = ptr->prev;
158 }
159 }
160 if(ptr->prev) {
161 ptr->prev->next = ptr->next;
162 }
163 else {
164 obj->head = ptr->next;
165 if(obj->head) {
166 obj->head->prev = NULL;
167 }
168 }
169 if(ptr->next) {
170 ptr->next->prev = ptr->prev;
171 }
172 else {
173 obj->tail = ptr->prev;
174 if(obj->tail) {
175 obj->tail->next = NULL;
176 }
177 }
178 data = ptr->data;
179 free(ptr);
180 obj->size--;
181 return data;
182 }
183
184 void *
lnklist_get(struct lnklist * obj,int index)185 lnklist_get(struct lnklist *obj, int index) {
186 struct lnklist_node *ptr;
187 int offset;
188
189 if(!obj || obj->size <= index) {
190 return NULL;
191 }
192 if(index < obj->size / 2) {
193 ptr = obj->head;
194 for(offset = 0; offset < index; offset++) {
195 ptr = ptr->next;
196 }
197 }
198 else {
199 ptr = obj->tail;
200 for(offset = obj->size - 1; offset > index; offset--) {
201 ptr = ptr->prev;
202 }
203 }
204 return ptr->data;
205 }
206
207 void
lnklist_iter_init(struct lnklist * obj)208 lnklist_iter_init(struct lnklist *obj) {
209 if(obj) {
210 obj->iter = (struct lnklist_node *)&LNKLIST_ITER_UNDERFLOW;
211 }
212 }
213
214 int
lnklist_iter_hasnext(struct lnklist * obj)215 lnklist_iter_hasnext(struct lnklist *obj) {
216 struct lnklist_node *next;
217
218 if(!obj || !obj->iter) {
219 return 0;
220 }
221 next = (obj->iter == &LNKLIST_ITER_UNDERFLOW) ? obj->head : obj->iter->next;
222 return next ? 1 : 0;
223 }
224
225 void *
lnklist_iter_next(struct lnklist * obj)226 lnklist_iter_next(struct lnklist *obj) {
227 if(!obj || !obj->iter) {
228 return NULL;
229 }
230 obj->iter = (obj->iter == &LNKLIST_ITER_UNDERFLOW) ? obj->head : obj->iter->next;
231 return obj->iter ? obj->iter->data : NULL;
232 }
233
234 void *
lnklist_iter_remove(struct lnklist * obj)235 lnklist_iter_remove(struct lnklist *obj) {
236 struct lnklist_node *ptr;
237 void *data;
238
239 if(!obj || !obj->iter || obj->iter == &LNKLIST_ITER_UNDERFLOW) {
240 return NULL;
241 }
242 ptr = obj->iter;
243 if(ptr->prev) {
244 ptr->prev->next = ptr->next;
245 obj->iter = ptr->prev;
246 }
247 else {
248 obj->head = ptr->next;
249 if(obj->head) {
250 obj->head->prev = NULL;
251 }
252 obj->iter = (struct lnklist_node *)&LNKLIST_ITER_UNDERFLOW;
253 }
254 if(ptr->next) {
255 ptr->next->prev = ptr->prev;
256 }
257 else {
258 obj->tail = ptr->prev;
259 if(obj->tail) {
260 obj->tail->next = NULL;
261 }
262 }
263 data = ptr->data;
264 free(ptr);
265 obj->size--;
266 return data;
267 }
268
269 void *
lnklist_iter_remove_next(struct lnklist * obj)270 lnklist_iter_remove_next(struct lnklist *obj) {
271 struct lnklist_node *ptr;
272 void *data;
273
274 if(!obj || !obj->iter) {
275 return NULL;
276 }
277 ptr = (obj->iter == &LNKLIST_ITER_UNDERFLOW) ? obj->head : obj->iter->next;
278 if(!ptr) {
279 return NULL;
280 }
281 if(ptr->prev) {
282 ptr->prev->next = ptr->next;
283 }
284 else {
285 obj->head = ptr->next;
286 if(obj->head) {
287 obj->head->prev = NULL;
288 }
289 }
290 if(ptr->next) {
291 ptr->next->prev = ptr->prev;
292 }
293 else {
294 obj->tail = ptr->prev;
295 if(obj->tail) {
296 obj->tail->next = NULL;
297 }
298 }
299 data = ptr->data;
300 free(ptr);
301 obj->size--;
302 return data;
303 }
304