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