The LevAWC Project
 All Data Structures Files Functions Variables Typedefs Enumerations Macros Pages
dlist.c
Go to the documentation of this file.
1 /*
2  * _____
3  * ANSI / ___/
4  * / /__
5  * \___/
6  *
7  * Filename: dlist.c
8  * Author : Kyle Loudon/Dan Levin
9  * Date : Fri Mar 22 12:40:45 GMT 2013
10  * Version : 0.51
11  * ---
12  * Description: A doubly-linked list - implemented as a pure, generic ADT.
13  *
14  * Revision history - coming up below:
15  *
16  * Date Revision message
17  * 2012-12-03 Created this file
18  * 2013-02-05 Created a new function 'int DLISTfind_remove(Dlist list, void **data)'
19  * 2013-02-19 Made some revision to the Doxygen documentation. Enhanced the description of
20  * in/out parameters - i.e. double-pointers.
21  * 2015-03-31 This code ready for ver. 0.51
22  *
23  */
24 
30 #include "dlist.h"
31 
32 struct DListElmt_
33 {
34  void *data;
35  struct DListElmt_ *prev;
36  struct DListElmt_ *next;
37 };
38 
39 struct DList_
40 {
41  int size;
42  int (*match)(const void *key1, const void *key2);
43  void (*destroy)(void *data);
44  struct DListElmt_ *head;
45  struct DListElmt_ *tail;
46 };
47 
48 /* FUNCTION DEFINITIONS ------------------------------------------------------ */
49 
50 Dlist DLISTinit(void (*destroy)(void *data))
51 {
52  Dlist list;
53 
54  if ((list = (Dlist)malloc(sizeof(struct DList_))) == NULL)
55  return NULL;
56 
57  list->size = 0;
58  list->match = NULL;
59  list->destroy = destroy;
60  list->head = NULL;
61  list->tail = NULL;
62 
63  return list;
64 }
65 
66 void DLISTdestroy(Dlist list)
67 {
68  void *data;
69 
70  while (DLISTsize(list) > 0)
71  {
72  if (DLISTremove(list, DLISTtail(list), (void **)&data) == 0 &&
73  list->destroy != NULL)
74  {
75  list->destroy(data);
76  }
77  }
78  free(list);
79 }
80 
81 int DLISTinsnext(Dlist list, DlistNode node, const void *data)
82 {
83  DlistNode newnode;
84 
85  /* If trying to insert a NULL node into a non-empty list.. */
86  if (node == NULL && DLISTsize(list) != 0)
87  return -1; /* --- Return error --- */
88 
89  /* --- Allocate space for a new node --- */
90  if ((newnode = (DlistNode)malloc(sizeof(struct DListElmt_))) == NULL)
91  return -1;
92 
93  newnode->data = (void *)data;
94 
95  if (DLISTsize(list) == 0) /* --- List is empty --- */
96  {
97  /* --- Handle insertion of new node accordingly --- */
98  list->head = newnode;
99  list->head->prev = NULL;
100  list->head->next = NULL;
101  list->tail = newnode;
102  }
103  else /* --- List is not empty --- */
104  {
105  newnode->next = node->next;
106  newnode->prev = node;
107 
108  if (node->next == NULL) /* --- Node 'node' is tail.. --- */
109  list->tail = newnode;
110  else
111  node->next->prev = newnode;
112 
113  node->next = newnode;
114  }
115 
116  list->size++;
117 
118  return 0;
119 }
120 
121 int DLISTinsprev(Dlist list, DlistNode node, const void *data)
122 {
123  DlistNode newnode;
124 
125  /* If trying to insert a NULL node into a non-empty list.. */
126  if (node == NULL && DLISTsize(list) != 0)
127  return -1; /* --- Return error --- */
128 
129  /* --- Allocate space for a new node --- */
130  if ((newnode = (DlistNode)malloc(sizeof(struct DListElmt_))) == NULL)
131  return -1;
132 
133  newnode->data = (void *)data;
134 
135  if (DLISTsize(list) == 0) /* --- If list is empty --- */
136  {
137  /* --- Handle insertion of new node accordingly --- */
138  list->head = newnode;
139  list->head->prev = NULL;
140  list->head->next = NULL;
141  list->tail = newnode;
142  }
143  else /* --- List is not empty --- */
144  {
145  newnode->next = node;
146  newnode->prev = node->prev;
147 
148  if (node->prev == NULL) /* --- Node 'node' is head.. --- */
149  list->head = newnode;
150  else
151  node->prev->next = newnode;
152 
153  node->prev = newnode;
154  }
155 
156  list->size++;
157 
158  return 0;
159 }
160 
161 int DLISTremove(Dlist list, DlistNode node, void **data)
162 {
163  /* --- If trying to remove a NULL node or if list is empty --- */
164  if (node == NULL || DLISTsize(list) == 0)
165  return -1;
166 
167  /* --- Remove and return data --- */
168  *data = node->data;
169 
170  if (node == DLISThead(list)) /* --- If 'node' is head of list.. --- */
171  {
172  /* --- Handle removal of 'node' accordingly --- */
173  list->head = node->next;
174 
175  if (list->head == NULL) /* --- 'list->head' now pointing at NULL --- */
176  list->tail = NULL;
177  else
178  node->next->prev = NULL;
179  }
180  else /* --- Handle removal when 'node' is inside list --- */
181  {
182  node->prev->next = node->next;
183 
184  if (node->next == NULL) /* --- If 'node' is tail.. --- */
185  list->tail = node->prev;
186  else
187  node->next->prev = node->prev;
188  }
189 
190  /* --- Free memory occupied by 'node' --- */
191  free(node);
192 
193  /* --- Decrease number of nodes in the list --- */
194  list->size--;
195 
196  return 0;
197 }
198 
199 int DLISTsize(Dlist list)
200 {
201  return list->size;
202 }
203 
205 {
206  return list->head;
207 }
208 
210 {
211  return list->tail;
212 }
213 
214 int DLISTishead(Dlist list, DlistNode node)
215 {
216  return list->head == node ? 1 : 0;
217 }
218 
219 int DLISTistail(Dlist list, DlistNode node)
220 {
221  return list->tail == node ? 1 : 0;
222 }
223 
224 void *DLISTdata(DlistNode node)
225 {
226  return node->data;
227 }
228 
230 {
231  return node->next;
232 }
233 
235 {
236  return node->prev;
237 }
238 
239 DlistNode DLISTfindnode(Dlist list, const void *data)
240 {
241  DlistNode member = NULL;
242 
243  /* If match callback not set */
244  if (list->match == NULL)
245  return NULL;
246 
247  for (member = list->head; member != NULL; member = member->next)
248  {
249  if (list->match(data, DLISTdata(member)))
250  break;
251  }
252 
253  return member;
254 }
255 
256 void DLISTsetmatch(Dlist list, int (*match)(const void *key1, const void *key2))
257 {
258  list->match = match;
259 }
260 
261 int DLISTfind_remove(Dlist list, void **data)
262 {
263  DlistNode member;
264 
265  /* If match-callback not set */
266  if (list->match == NULL)
267  return -2;
268 
269  /* Search list sequentially.. */
270  member = DLISTfindnode(list, *data);
271 
272  if (member == NULL) /* Node not found */
273  return 1;
274 
275  /* Perform the removal.. */
276  return DLISTremove(list, member, data);
277 }
278 
279 void DLISTsort(Dlist list, int (*cmp)(const void *key1, const void *key2))
280 {
281  DlistNode curr, maxmin, tmp;
282  void *tmpdata;
283 
284  if (list->size > 1)
285  {
286  curr = list->head;
287 
288  while (curr->next)
289  {
290  maxmin = curr;
291  tmp = curr->next;
292 
293  while(tmp)
294  {
295  if (cmp(tmp->data, maxmin->data) < 0)
296  maxmin = tmp;
297  tmp = tmp->next;
298  }
299 
300  if (maxmin != curr)
301  {
302  tmpdata = curr->data;
303  curr->data = maxmin->data;
304  maxmin->data = tmpdata;
305  }
306  curr = curr->next;
307  }
308  }
309 }
310 
311 void DLISTtraverse(Dlist list, void (*callback)(const void *data), int direction)
312 {
313  DlistNode curr;
314 
315  if (direction == DLIST_FWD)
316  for (curr=list->head; curr != NULL; curr=curr->next)
317  callback(curr->data);
318 
319  if (direction == DLIST_BWD)
320  for (curr=list->tail; curr != NULL; curr=curr->prev)
321  callback(curr->data);
322 }