1 /*
2 * Copyright (c) 2000, 2001 Peter Bozarov.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Peter Bozarov.
16 * 4. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Note: this "queue" implementation is actually also a linked list. Why
34 * bother with making two things that are essentially the same as far as
35 * implementation is concerned?
36 *
37 * Last modified: Fri Dec 7 10:19:00 EST 2001
38 * Mon Dec 24 10:36:38 EST 2001
39 */
40 # include "local.h"
41
42 # define QNULL ((Queue*) 0)
43 # define QELEMNULL ((QElem*) 0)
44
45 struct QElem
46 {
47 void * qeData;
48 QElem * qePrev;
49 QElem * qeNext;
50 };
51
52 struct Queue
53 {
54 int qTotal;
55 QElem * qHead;
56 QElem * qTail;
57 QElem * qCurr; /* For currencies */
58 };
59
60 # define TOTAL(q) ((Queue*)q)->qTotal
61 # define TAIL(q) ((Queue*)q)->qTail
62 # define HEAD(q) ((Queue*)q)->qHead
63 # define CURR(q) ((Queue*)q)->qCurr
64
65 static QElem*
qelem_new(void * data)66 qelem_new(void *data)
67 {
68 QElem *qelem;
69
70 STDMALLOC(qelem,sizeof(QElem),NULL);
71
72 qelem->qeData = data;
73 qelem->qePrev = QELEMNULL;
74 qelem->qeNext = QELEMNULL;
75
76 return qelem;
77 }
78 static int
qelem_enque(QUEUE q,QELEM elem)79 qelem_enque(QUEUE q,QELEM elem)
80 {
81 QElem * qelem = (QElem*) elem;
82
83 if (!HEAD(q))
84 {
85 CURR(q) = TAIL(q) = HEAD(q) = qelem;
86 }
87 else
88 {
89 qelem->qePrev = TAIL(q);
90 CURR(q) = TAIL(q)->qeNext = qelem;
91 TAIL(q) = TAIL(q)->qeNext;
92 }
93
94 ++TOTAL(q);
95
96 return 0;
97 }
98 /*----------------------------------------------------------------------*
99 * Exported *
100 *----------------------------------------------------------------------*/
101 /*
102 * Standard Queue functions
103 */
104 QUEUE
qMake(void)105 qMake(void)
106 {
107 Queue * q;
108
109 STDMALLOC(q,sizeof(Queue),QNULL);
110
111 q->qHead = QELEMNULL;
112 q->qTail = QELEMNULL;
113 q->qCurr = QELEMNULL;
114 q->qTotal= 0;
115
116 return q;
117 }
118 void
qClose(QUEUE q)119 qClose(QUEUE q)
120 {
121 qCloseWithFunction(q,NULL);
122 }
123 void
qCloseWithFunction(QUEUE queue,void (* f)(void *))124 qCloseWithFunction(QUEUE queue,void (*f)(void*))
125 {
126 if (queue)
127 {
128 /* Loop through all elements and free them. */
129 QElem * tmp = HEAD(queue);
130
131 while (tmp)
132 {
133 QElem * t = tmp;
134 if (f)
135 f(tmp->qeData);
136 tmp = tmp->qeNext;
137 STDFREE(t);
138 }
139 }
140
141 STDFREE(queue);
142 }
143 QELEM
qEnque(QUEUE q,void * data)144 qEnque(QUEUE q,void *data)
145 {
146 QElem * qelem;
147
148 if (!q)
149 return NULL;
150
151 /* Allocate a new QElement to put in the queue */
152
153 if (!(qelem = qelem_new(data)))
154 return NULL;
155
156 qelem_enque(q,(QELEM)qelem);
157
158 return (QELEM) qelem;
159 }
160 void*
qDeque(QUEUE q)161 qDeque(QUEUE q)
162 {
163 QElem * first;
164 void * data = NULL;
165
166 if (!q)
167 return NULL;
168
169 if (HEAD(q))
170 {
171 first = HEAD(q);
172
173 /* Last element found, set TAIL(q) to NIL */
174
175 if (TAIL(q) == HEAD(q))
176 TAIL(q) = QELEMNULL;
177
178 HEAD(q) = HEAD(q)->qeNext;
179
180 if (HEAD(q))
181 HEAD(q)->qePrev = QELEMNULL;
182
183 /* Remember the data ... */
184
185 data = first->qeData;
186
187 /* ... and free the element */
188
189 first->qeNext = QELEMNULL;
190 STDFREE(first);
191
192 --TOTAL(q);
193 }
194 return data;
195 }
196
197 int
qWalk(QUEUE q,void (* fun)(void *))198 qWalk(QUEUE q,void (*fun)(void*))
199 {
200 QElem * tmp;
201
202 if (!q)
203 return -1;
204
205 tmp = HEAD(q);
206
207 while (tmp)
208 {
209 (void)fun(tmp->qeData);
210 tmp = tmp->qeNext;
211 }
212
213 return 0;
214 }
215 int
qWalkAscending(QUEUE q,void (* fun)(void *))216 qWalkAscending(QUEUE q,void (*fun)(void*))
217 {
218 return qWalk(q,fun);
219 }
220 int
qWalkDescending(QUEUE q,void (* fun)(void *))221 qWalkDescending(QUEUE q,void (*fun)(void*))
222 {
223 QElem * tmp;
224
225 if (!q)
226 return -1;
227
228 tmp = TAIL(q);
229
230 while (tmp)
231 {
232 fun(tmp->qeData);
233 tmp = tmp->qePrev;
234 }
235 return 0;
236 }
qLength(QUEUE q)237 int qLength(QUEUE q) { return ((Queue*)q)->qTotal; }
qEmpty(QUEUE q)238 int qEmpty( QUEUE q) { return ! HEAD(q); }
239
240 void*
qCurrent(QUEUE q)241 qCurrent(QUEUE q)
242 {
243 if (!q)
244 return NULL;
245
246 return CURR(q) ? CURR(q)->qeData : NULL;
247 }
248 void
qClearCurrent(QUEUE q)249 qClearCurrent(QUEUE q)
250 {
251 qSetCurrent(q,NULL);
252 }
253 void
qSetCurrent(QUEUE q,QELEM el)254 qSetCurrent(QUEUE q,QELEM el)
255 {
256 if (!q)
257 return;
258 CURR(q) = el;
259 }
260 void*
qFirst(QUEUE q)261 qFirst(QUEUE q)
262 {
263 QElem * first;
264
265 first = qElemFirst(q);
266 CURR(q) = first;
267 return first ? first->qeData : NULL;
268 }
269 void*
qLast(QUEUE q)270 qLast(QUEUE q)
271 {
272 QElem * last;
273
274 last = qElemLast(q);
275 CURR(q) = last;
276 return last ? last->qeData : NULL;
277 }
278 void*
qNext(QUEUE q)279 qNext(QUEUE q)
280 {
281 QElem *next;
282
283 if (!CURR(q))
284 return qFirst(q);
285 next = qElemNext(CURR(q));
286
287 CURR(q) = next;
288
289 return next ? next->qeData : NULL;
290 }
291 void*
qPrev(QUEUE q)292 qPrev(QUEUE q)
293 {
294 QElem *prev;
295
296 if (!CURR(q))
297 return qLast(q);
298 prev = qElemPrev(CURR(q));
299 CURR(q) = prev;
300
301 return prev ? prev->qeData : NULL;
302 }
303 /*----------------------------------------------------------------------*
304 * More sophisticated QELEM functionality *
305 *----------------------------------------------------------------------*/
306 void*
qElemData(QELEM qelem)307 qElemData(QELEM qelem)
308 {
309 if (!qelem)
310 return NULL;
311 return ((QElem*)qelem)->qeData;
312 }
313
314 /*
315 * Insert a QELEM in the queue. The new qelem is placed before the one
316 * given. If the given element is NULL, the qelem put at the end of the
317 * queue.
318 */
319 int
qElemInsert(QUEUE q,QELEM pBefore,QELEM pElem)320 qElemInsert(QUEUE q,QELEM pBefore,QELEM pElem)
321 {
322 QElem * elem = (QElem*)pElem;
323 QElem * before= (QElem*)pBefore;
324
325 if (!before)
326 return qelem_enque(q,elem);
327
328 elem->qeNext = before;
329 elem->qePrev = before->qePrev;
330 if (before->qePrev)
331 before->qePrev->qeNext = elem;
332 before->qePrev = elem;
333 return 0;
334 }
335 /*
336 * Attach an existing QELEM to the given QUEUE. This is the same
337 * as actually enqueing the element, but does not create a new
338 * QELEM.
339 */
340 int
qElemAttach(QUEUE q,QELEM elem)341 qElemAttach(QUEUE q,QELEM elem)
342 {
343 return qelem_enque(q,elem);
344 }
345 /*
346 * Detach the given queue element from the queue.
347 * It can now be added to another queue, or freed using qElemFree().
348 */
349 int
qElemDetach(QUEUE q,QELEM elem)350 qElemDetach(QUEUE q,QELEM elem)
351 {
352 QElem *curr = (QElem*)elem;
353 QElem *prev = curr->qePrev;
354 QElem *next = curr->qeNext;
355
356 /* Detach curr from the queue */
357 if (prev)
358 prev->qeNext = next;
359 else /* This is the head */
360 HEAD(q) = next;
361
362 if (next)
363 next->qePrev = prev;
364 else /* This is the tail element */
365 TAIL(q) = prev;
366
367 curr->qePrev = curr->qeNext = NULL;
368
369 if (CURR(q) == curr)
370 CURR(q) = NULL;
371
372 --TOTAL(q);
373 return 0;
374 }
375
376 void
qElemFree(QELEM elem)377 qElemFree(QELEM elem)
378 {
379 STDFREE(elem);
380 }
381
382 /*
383 * Returns a pointer to the first element in the queue. To get the
384 * actual data, call qElemData(QELEM qelem).
385 */
386 QELEM
qElemFirst(QUEUE q)387 qElemFirst(QUEUE q)
388 {
389 if (!q || !HEAD(q))
390 return NULL;
391 return HEAD(q);
392 }
393 /*
394 * Returns a pointer to the last element of the queue.
395 */
396 QELEM
qElemLast(QUEUE q)397 qElemLast(QUEUE q)
398 {
399 if (!q || !TAIL(q))
400 return NULL;
401 return TAIL(q);
402 }
403 /*
404 * Given a current qElem, return the next one.
405 */
406 QELEM
qElemNext(QELEM curr)407 qElemNext(QELEM curr)
408 {
409 if (!curr)
410 return NULL;
411
412 return ((QElem*)curr)->qeNext;
413 }
414 /*
415 * Given a current element, return the previous.
416 */
417 QELEM
qElemPrev(QELEM curr)418 qElemPrev(QELEM curr)
419 {
420 if (!curr)
421 return NULL;
422
423 return ((QElem*)curr)->qePrev;
424 }
425 QELEM
qElemCurr(QUEUE q)426 qElemCurr(QUEUE q)
427 {
428 return CURR(q);
429 }
430 /*
431 * Given a current qElem, remove it from the queue.
432 * The data stored with the element is returned.
433 * The element itself is free()'d.
434 *
435 * Returns NULL if it fails, or if you stored a NULL pointer with this
436 * element.
437 */
438 void*
qElemRemove(QUEUE q,QELEM elem)439 qElemRemove(QUEUE q,QELEM elem)
440 {
441 void * data;
442 if (!elem)
443 return 0;
444
445 /* Give the data back */
446 data = ((QElem*)elem)->qeData;
447
448 qElemDetach(q,elem);
449 STDFREE(elem);
450 return data;
451 }
452