Annotation of embedaddon/php/ext/xmlrpc/libxmlrpc/queue.c, revision 1.1.1.1
1.1 misho 1: static const char rcsid[] = "#(@) $Id: queue.c 87765 2002-07-05 04:43:55Z danda $";
2:
3: /*
4: * Date last modified: Jan 2001
5: * Modifications by Dan Libby (dan@libby.com), including:
6: * - various fixes, null checks, etc
7: * - addition of Q_Iter funcs, macros
8: */
9:
10:
11: /*-**************************************************************
12: *
13: * File : q.c
14: *
15: * Author: Peter Yard [1993.01.02] -- 02 Jan 1993
16: *
17: * Disclaimer: This code is released to the public domain.
18: *
19: * Description:
20: * Generic double ended queue (Deque pronounced DEK) for handling
21: * any data types, with sorting.
22: *
23: * By use of various functions in this module the caller
24: * can create stacks, queues, lists, doubly linked lists,
25: * sorted lists, indexed lists. All lists are dynamic.
26: *
27: * It is the responsibility of the caller to malloc and free
28: * memory for insertion into the queue. A pointer to the object
29: * is used so that not only can any data be used but various kinds
30: * of data can be pushed on the same queue if one so wished e.g.
31: * various length string literals mixed with pointers to structures
32: * or integers etc.
33: *
34: * Enhancements:
35: * A future improvement would be the option of multiple "cursors"
36: * so that multiple locations could occur in the one queue to allow
37: * placemarkers and additional flexibility. Perhaps even use queue
38: * itself to have a list of cursors.
39: *
40: * Usage:
41: *
42: * /x init queue x/
43: * queue q;
44: * Q_Init(&q);
45: *
46: * To create a stack :
47: *
48: * Q_PushHead(&q, &mydata1); /x push x/
49: * Q_PushHead(&q, &mydata2);
50: * .....
51: * data_ptr = Q_PopHead(&q); /x pop x/
52: * .....
53: * data_ptr = Q_Head(&q); /x top of stack x/
54: *
55: * To create a FIFO:
56: *
57: * Q_PushHead(&q, &mydata1);
58: * .....
59: * data_ptr = Q_PopTail(&q);
60: *
61: * To create a double list:
62: *
63: * data_ptr = Q_Head(&q);
64: * ....
65: * data_ptr = Q_Next(&q);
66: * data_ptr = Q_Tail(&q);
67: * if (Q_IsEmpty(&q)) ....
68: * .....
69: * data_ptr = Q_Previous(&q);
70: *
71: * To create a sorted list:
72: *
73: * Q_PushHead(&q, &mydata1); /x push x/
74: * Q_PushHead(&q, &mydata2);
75: * .....
76: * if (!Q_Sort(&q, MyFunction))
77: * .. error ..
78: *
79: * /x fill in key field of mydata1.
80: * * NB: Q_Find does linear search
81: * x/
82: *
83: * if (Q_Find(&q, &mydata1, MyFunction))
84: * {
85: * /x found it, queue cursor now at correct record x/
86: * /x can retrieve with x/
87: * data_ptr = Q_Get(&q);
88: *
89: * /x alter data , write back with x/
90: * Q_Put(&q, data_ptr);
91: * }
92: *
93: * /x Search with binary search x/
94: * if (Q_Seek(&q, &mydata, MyFunction))
95: * /x etc x/
96: *
97: *
98: ****************************************************************/
99:
100: #ifdef _WIN32
101: #include "xmlrpc_win32.h"
102: #endif
103: #include <stdlib.h>
104: #include "queue.h"
105:
106:
107: static void QuickSort(void *list[], int low, int high,
108: int (*Comp)(const void *, const void *));
109: static int Q_BSearch(queue *q, void *key,
110: int (*Comp)(const void *, const void *));
111:
112: /* The index: a pointer to pointers */
113:
114: static void **index;
115: static datanode **posn_index;
116:
117:
118: /***
119: *
120: ** function : Q_Init
121: *
122: ** purpose : Initialise queue object and pointers.
123: *
124: ** parameters : 'queue' pointer.
125: *
126: ** returns : True_ if init successful else False_
127: *
128: ** comments :
129: ***/
130:
131: int Q_Init(queue *q)
132: {
133: if(q) {
134: q->head = q->tail = NULL;
135: q->cursor = q->head;
136: q->size = 0;
137: q->sorted = False_;
138: }
139:
140: return True_;
141: }
142:
143: /***
144: *
145: ** function : Q_AtHead
146: *
147: ** purpose : tests if cursor is at head of queue
148: *
149: ** parameters : 'queue' pointer.
150: *
151: ** returns : boolean - True_ is at head else False_
152: *
153: ** comments :
154: *
155: ***/
156:
157: int Q_AtHead(queue *q)
158: {
159: return(q && q->cursor == q->head);
160: }
161:
162:
163: /***
164: *
165: ** function : Q_AtTail
166: *
167: ** purpose : boolean test if cursor at tail of queue
168: *
169: ** parameters : 'queue' pointer to test.
170: *
171: ** returns : True_ or False_
172: *
173: ** comments :
174: *
175: ***/
176:
177: int Q_AtTail(queue *q)
178: {
179: return(q && q->cursor == q->tail);
180: }
181:
182:
183: /***
184: *
185: ** function : Q_IsEmpty
186: *
187: ** purpose : test if queue has nothing in it.
188: *
189: ** parameters : 'queue' pointer
190: *
191: ** returns : True_ if IsEmpty queue, else False_
192: *
193: ** comments :
194: *
195: ***/
196:
197: inline int Q_IsEmpty(queue *q)
198: {
199: return(!q || q->size == 0);
200: }
201:
202: /***
203: *
204: ** function : Q_Size
205: *
206: ** purpose : return the number of elements in the queue
207: *
208: ** parameters : queue pointer
209: *
210: ** returns : number of elements
211: *
212: ** comments :
213: *
214: ***/
215:
216: int Q_Size(queue *q)
217: {
218: return q ? q->size : 0;
219: }
220:
221:
222: /***
223: *
224: ** function : Q_Head
225: *
226: ** purpose : position queue cursor to first element (head) of queue.
227: *
228: ** parameters : 'queue' pointer
229: *
230: ** returns : pointer to data at head. If queue is IsEmpty returns NULL
231: *
232: ** comments :
233: *
234: ***/
235:
236: void *Q_Head(queue *q)
237: {
238: if(Q_IsEmpty(q))
239: return NULL;
240:
241: q->cursor = q->head;
242:
243: return q->cursor->data;
244: }
245:
246:
247: /***
248: *
249: ** function : Q_Tail
250: *
251: ** purpose : locate cursor at tail of queue.
252: *
253: ** parameters : 'queue' pointer
254: *
255: ** returns : pointer to data at tail , if queue IsEmpty returns NULL
256: *
257: ** comments :
258: *
259: ***/
260:
261: void *Q_Tail(queue *q)
262: {
263: if(Q_IsEmpty(q))
264: return NULL;
265:
266: q->cursor = q->tail;
267:
268: return q->cursor->data;
269: }
270:
271:
272: /***
273: *
274: ** function : Q_PushHead
275: *
276: ** purpose : put a data pointer at the head of the queue
277: *
278: ** parameters : 'queue' pointer, void pointer to the data.
279: *
280: ** returns : True_ if success else False_ if unable to push data.
281: *
282: ** comments :
283: *
284: ***/
285:
286: int Q_PushHead(queue *q, void *d)
287: {
288: if(q && d) {
289: node *n;
290: datanode *p;
291:
292: p = malloc(sizeof(datanode));
293: if(p == NULL)
294: return False_;
295:
296: n = q->head;
297:
298: q->head = (node*)p;
299: q->head->prev = NULL;
300:
301: if(q->size == 0) {
302: q->head->next = NULL;
303: q->tail = q->head;
304: }
305: else {
306: q->head->next = (datanode*)n;
307: n->prev = q->head;
308: }
309:
310: q->head->data = d;
311: q->size++;
312:
313: q->cursor = q->head;
314:
315: q->sorted = False_;
316:
317: return True_;
318: }
319: return False_;
320: }
321:
322:
323:
324: /***
325: *
326: ** function : Q_PushTail
327: *
328: ** purpose : put a data element pointer at the tail of the queue
329: *
330: ** parameters : queue pointer, pointer to the data
331: *
332: ** returns : True_ if data pushed, False_ if data not inserted.
333: *
334: ** comments :
335: *
336: ***/
337:
338: int Q_PushTail(queue *q, void *d)
339: {
340: if(q && d) {
341: node *p;
342: datanode *n;
343:
344: n = malloc(sizeof(datanode));
345: if(n == NULL)
346: return False_;
347:
348: p = q->tail;
349: q->tail = (node *)n;
350:
351: if(q->size == 0) {
352: q->tail->prev = NULL;
353: q->head = q->tail;
354: }
355: else {
356: q->tail->prev = (datanode *)p;
357: p->next = q->tail;
358: }
359:
360: q->tail->next = NULL;
361:
362: q->tail->data = d;
363: q->cursor = q->tail;
364: q->size++;
365:
366: q->sorted = False_;
367:
368: return True_;
369: }
370: return False_;
371: }
372:
373:
374:
375: /***
376: *
377: ** function : Q_PopHead
378: *
379: ** purpose : remove and return the top element at the head of the
380: * queue.
381: *
382: ** parameters : queue pointer
383: *
384: ** returns : pointer to data element or NULL if queue is IsEmpty.
385: *
386: ** comments :
387: *
388: ***/
389:
390: void *Q_PopHead(queue *q)
391: {
392: datanode *n;
393: void *d;
394:
395: if(Q_IsEmpty(q))
396: return NULL;
397:
398: d = q->head->data;
399: n = q->head->next;
400: free(q->head);
401:
402: q->size--;
403:
404: if(q->size == 0)
405: q->head = q->tail = q->cursor = NULL;
406: else {
407: q->head = (node *)n;
408: q->head->prev = NULL;
409: q->cursor = q->head;
410: }
411:
412: q->sorted = False_;
413:
414: return d;
415: }
416:
417:
418: /***
419: *
420: ** function : Q_PopTail
421: *
422: ** purpose : remove element from tail of queue and return data.
423: *
424: ** parameters : queue pointer
425: *
426: ** returns : pointer to data element that was at tail. NULL if queue
427: * IsEmpty.
428: *
429: ** comments :
430: *
431: ***/
432:
433: void *Q_PopTail(queue *q)
434: {
435: datanode *p;
436: void *d;
437:
438: if(Q_IsEmpty(q))
439: return NULL;
440:
441: d = q->tail->data;
442: p = q->tail->prev;
443: free(q->tail);
444: q->size--;
445:
446: if(q->size == 0)
447: q->head = q->tail = q->cursor = NULL;
448: else {
449: q->tail = (node *)p;
450: q->tail->next = NULL;
451: q->cursor = q->tail;
452: }
453:
454: q->sorted = False_;
455:
456: return d;
457: }
458:
459:
460:
461: /***
462: *
463: ** function : Q_Next
464: *
465: ** purpose : Move to the next element in the queue without popping
466: *
467: ** parameters : queue pointer.
468: *
469: ** returns : pointer to data element of new element or NULL if end
470: * of the queue.
471: *
472: ** comments : This uses the cursor for the current position. Q_Next
473: * only moves in the direction from the head of the queue
474: * to the tail.
475: ***/
476:
477: void *Q_Next(queue *q)
478: {
479: if(!q)
480: return NULL;
481:
482: if(!q->cursor || q->cursor->next == NULL)
483: return NULL;
484:
485: q->cursor = (node *)q->cursor->next;
486:
487: return q->cursor->data ;
488: }
489:
490:
491:
492: /***
493: *
494: ** function : Q_Previous
495: *
496: ** purpose : Opposite of Q_Next. Move to next element closer to the
497: * head of the queue.
498: *
499: ** parameters : pointer to queue
500: *
501: ** returns : pointer to data of new element else NULL if queue IsEmpty
502: *
503: ** comments : Makes cursor move towards the head of the queue.
504: *
505: ***/
506:
507: void *Q_Previous(queue *q)
508: {
509: if(!q)
510: return NULL;
511:
512: if(q->cursor->prev == NULL)
513: return NULL;
514:
515: q->cursor = (node *)q->cursor->prev;
516:
517: return q->cursor->data;
518: }
519:
520:
521: void *Q_Iter_Del(queue *q, q_iter iter)
522: {
523: void *d;
524: datanode *n, *p;
525:
526: if(!q)
527: return NULL;
528:
529: if(iter == NULL)
530: return NULL;
531:
532: if(iter == (q_iter)q->head)
533: return Q_PopHead(q);
534:
535: if(iter == (q_iter)q->tail)
536: return Q_PopTail(q);
537:
538: n = ((node*)iter)->next;
539: p = ((node*)iter)->prev;
540: d = ((node*)iter)->data;
541:
542: free(iter);
543:
544: if(p) {
545: p->next = n;
546: }
547: if (q->cursor == (node*)iter) {
548: if (p) {
549: q->cursor = p;
550: } else {
551: q->cursor = n;
552: }
553: }
554:
555:
556: if (n != NULL) {
557: n->prev = p;
558: }
559:
560: q->size--;
561:
562: q->sorted = False_;
563:
564: return d;
565: }
566:
567:
568:
569: /***
570: *
571: ** function : Q_DelCur
572: *
573: ** purpose : Delete the current queue element as pointed to by
574: * the cursor.
575: *
576: ** parameters : queue pointer
577: *
578: ** returns : pointer to data element.
579: *
580: ** comments : WARNING! It is the responsibility of the caller to
581: * free any memory. Queue cannot distinguish between
582: * pointers to literals and malloced memory.
583: *
584: ***/
585:
586: void *Q_DelCur(queue* q) {
587: if(q) {
588: return Q_Iter_Del(q, (q_iter)q->cursor);
589: }
590: return 0;
591: }
592:
593:
594: /***
595: *
596: ** function : Q_Destroy
597: *
598: ** purpose : Free all queue resources
599: *
600: ** parameters : queue pointer
601: *
602: ** returns : null.
603: *
604: ** comments : WARNING! It is the responsibility of the caller to
605: * free any memory. Queue cannot distinguish between
606: * pointers to literals and malloced memory.
607: *
608: ***/
609:
610: void Q_Destroy(queue *q)
611: {
612: while(!Q_IsEmpty(q)) {
613: Q_PopHead(q);
614: }
615: }
616:
617:
618: /***
619: *
620: ** function : Q_Get
621: *
622: ** purpose : get the pointer to the data at the cursor location
623: *
624: ** parameters : queue pointer
625: *
626: ** returns : data element pointer
627: *
628: ** comments :
629: *
630: ***/
631:
632: void *Q_Get(queue *q)
633: {
634: if(!q)
635: return NULL;
636:
637: if(q->cursor == NULL)
638: return NULL;
639: return q->cursor->data;
640: }
641:
642:
643:
644: /***
645: *
646: ** function : Q_Put
647: *
648: ** purpose : replace pointer to data with new pointer to data.
649: *
650: ** parameters : queue pointer, data pointer
651: *
652: ** returns : boolean- True_ if successful, False_ if cursor at NULL
653: *
654: ** comments :
655: *
656: ***/
657:
658: int Q_Put(queue *q, void *data)
659: {
660: if(q && data) {
661: if(q->cursor == NULL)
662: return False_;
663:
664: q->cursor->data = data;
665: return True_;
666: }
667: return False_;
668: }
669:
670:
671: /***
672: *
673: ** function : Q_Find
674: *
675: ** purpose : Linear search of queue for match with key in *data
676: *
677: ** parameters : queue pointer q, data pointer with data containing key
678: * comparison function here called Comp.
679: *
680: ** returns : True_ if found , False_ if not in queue.
681: *
682: ** comments : Useful for small queues that are constantly changing
683: * and would otherwise need constant sorting with the
684: * Q_Seek function.
685: * For description of Comp see Q_Sort.
686: * Queue cursor left on position found item else at end.
687: *
688: ***/
689:
690: int Q_Find(queue *q, void *data,
691: int (*Comp)(const void *, const void *))
692: {
693: void *d;
694:
695: if (q == NULL) {
696: return False_;
697: }
698:
699: d = Q_Head(q);
700: do {
701: if(Comp(d, data) == 0)
702: return True_;
703: d = Q_Next(q);
704: } while(!Q_AtTail(q));
705:
706: if(Comp(d, data) == 0)
707: return True_;
708:
709: return False_;
710: }
711:
712: /*======== Sorted Queue and Index functions ========= */
713:
714:
715: static void QuickSort(void *list[], int low, int high,
716: int (*Comp)(const void *, const void *))
717: {
718: int flag = 1, i, j;
719: void *key, *temp;
720:
721: if(low < high) {
722: i = low;
723: j = high + 1;
724:
725: key = list[ low ];
726:
727: while(flag) {
728: i++;
729: while(Comp(list[i], key) < 0)
730: i++;
731:
732: j--;
733: while(Comp(list[j], key) > 0)
734: j--;
735:
736: if(i < j) {
737: temp = list[i];
738: list[i] = list[j];
739: list[j] = temp;
740: }
741: else flag = 0;
742: }
743:
744: temp = list[low];
745: list[low] = list[j];
746: list[j] = temp;
747:
748: QuickSort(list, low, j-1, Comp);
749: QuickSort(list, j+1, high, Comp);
750: }
751: }
752:
753:
754: /***
755: *
756: ** function : Q_Sort
757: *
758: ** purpose : sort the queue and allow index style access.
759: *
760: ** parameters : queue pointer, comparison function compatible with
761: * with 'qsort'.
762: *
763: ** returns : True_ if sort succeeded. False_ if error occurred.
764: *
765: ** comments : Comp function supplied by caller must return
766: * -1 if data1 < data2
767: * 0 if data1 == data2
768: * +1 if data1 > data2
769: *
770: * for Comp(data1, data2)
771: *
772: * If queue is already sorted it frees the memory of the
773: * old index and starts again.
774: *
775: ***/
776:
777: int Q_Sort(queue *q, int (*Comp)(const void *, const void *))
778: {
779: int i;
780: void *d;
781: datanode *dn;
782:
783: /* if already sorted free memory for tag array */
784:
785: if(q->sorted) {
786: free(index);
787: free(posn_index);
788: q->sorted = False_;
789: }
790:
791: /* Now allocate memory of array, array of pointers */
792:
793: index = malloc(q->size * sizeof(q->cursor->data));
794: if(index == NULL)
795: return False_;
796:
797: posn_index = malloc(q->size * sizeof(q->cursor));
798: if(posn_index == NULL) {
799: free(index);
800: return False_;
801: }
802:
803: /* Walk queue putting pointers into array */
804:
805: d = Q_Head(q);
806: for(i=0; i < q->size; i++) {
807: index[i] = d;
808: posn_index[i] = q->cursor;
809: d = Q_Next(q);
810: }
811:
812: /* Now sort the index */
813:
814: QuickSort(index, 0, q->size - 1, Comp);
815:
816: /* Rearrange the actual queue into correct order */
817:
818: dn = q->head;
819: i = 0;
820: while(dn != NULL) {
821: dn->data = index[i++];
822: dn = dn->next;
823: }
824:
825: /* Re-position to original element */
826:
827: if(d != NULL)
828: Q_Find(q, d, Comp);
829: else Q_Head(q);
830:
831: q->sorted = True_;
832:
833: return True_;
834: }
835:
836:
837: /***
838: *
839: ** function : Q_BSearch
840: *
841: ** purpose : binary search of queue index for node containing key
842: *
843: ** parameters : queue pointer 'q', data pointer of key 'key',
844: * Comp comparison function.
845: *
846: ** returns : integer index into array of node pointers,
847: * or -1 if not found.
848: *
849: ** comments : see Q_Sort for description of 'Comp' function.
850: *
851: ***/
852:
853: static int Q_BSearch( queue *q, void *key,
854: int (*Comp)(const void *, const void*))
855: {
856: int low, mid, hi, val;
857:
858: low = 0;
859: hi = q->size - 1;
860:
861: while(low <= hi) {
862: mid = (low + hi) / 2;
863: val = Comp(key, index[ mid ]);
864:
865: if(val < 0)
866: hi = mid - 1;
867:
868: else if(val > 0)
869: low = mid + 1;
870:
871: else /* Success */
872: return mid;
873: }
874:
875: /* Not Found */
876:
877: return -1;
878: }
879:
880:
881: /***
882: *
883: ** function : Q_Seek
884: *
885: ** purpose : use index to locate data according to key in 'data'
886: *
887: ** parameters : queue pointer 'q', data pointer 'data', Comp comparison
888: * function.
889: *
890: ** returns : pointer to data or NULL if could not find it or could
891: * not sort queue.
892: *
893: ** comments : see Q_Sort for description of 'Comp' function.
894: *
895: ***/
896:
897: void *Q_Seek(queue *q, void *data, int (*Comp)(const void *, const void *))
898: {
899: int idx;
900:
901: if (q == NULL) {
902: return NULL;
903: }
904:
905: if(!q->sorted) {
906: if(!Q_Sort(q, Comp))
907: return NULL;
908: }
909:
910: idx = Q_BSearch(q, data, Comp);
911:
912: if(idx < 0)
913: return NULL;
914:
915: q->cursor = posn_index[idx];
916:
917: return index[idx];
918: }
919:
920:
921:
922: /***
923: *
924: ** function : Q_Insert
925: *
926: ** purpose : Insert an element into an indexed queue
927: *
928: ** parameters : queue pointer 'q', data pointer 'data', Comp comparison
929: * function.
930: *
931: ** returns : pointer to data or NULL if could not find it or could
932: * not sort queue.
933: *
934: ** comments : see Q_Sort for description of 'Comp' function.
935: * WARNING! This code can be very slow since each new
936: * element means a new Q_Sort. Should only be used for
937: * the insertion of the odd element ,not the piecemeal
938: * building of an entire queue.
939: ***/
940:
941: int Q_Insert(queue *q, void *data, int (*Comp)(const void *, const void *))
942: {
943: if (q == NULL) {
944: return False_;
945: }
946:
947: Q_PushHead(q, data);
948:
949: if(!Q_Sort(q, Comp))
950: return False_;
951:
952: return True_;
953: }
954:
955: /* read only funcs for iterating through queue. above funcs modify queue */
956: q_iter Q_Iter_Head(queue *q) {
957: return q ? (q_iter)q->head : NULL;
958: }
959:
960: q_iter Q_Iter_Tail(queue *q) {
961: return q ? (q_iter)q->tail : NULL;
962: }
963:
964: q_iter Q_Iter_Next(q_iter qi) {
965: return qi ? (q_iter)((node*)qi)->next : NULL;
966: }
967:
968: q_iter Q_Iter_Prev(q_iter qi) {
969: return qi ? (q_iter)((node*)qi)->prev : NULL;
970: }
971:
972: void * Q_Iter_Get(q_iter qi) {
973: return qi ? ((node*)qi)->data : NULL;
974: }
975:
976: int Q_Iter_Put(q_iter qi, void* data) {
977: if(qi) {
978: ((node*)qi)->data = data;
979: return True_;
980: }
981: return False_;
982: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>