Annotation of embedaddon/mpd/src/contrib/libpdel/util/gtree.c, revision 1.1.1.2
1.1 misho 1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include <sys/types.h>
42: #include <sys/param.h>
43:
44: #ifdef _KERNEL
45: #include <sys/systm.h>
46: #else
47: #include <stdio.h>
48: #include <stdlib.h>
49: #include <stdarg.h>
50: #include <string.h>
51: #include <assert.h>
52: #include <errno.h>
53: #endif /* !_KERNEL */
54:
55: #include "structs/structs.h"
56: #include "structs/type/array.h"
57:
58: #include "util/gtree.h"
59: #include "util/typed_mem.h"
60:
1.1.1.2 ! misho 61: #include "defs.h"
! 62: #include "log.h"
! 63:
1.1 misho 64: /* Enabled debug tracing: only use this when keys are strings */
65: #define GTREE_TRACE 0
66:
67: enum node_color {
68: BLACK=0,
69: RED=1
70: };
71:
72: /* One node in the tree */
73: struct node {
74: enum node_color color; /* item color */
75: struct node *left; /* left child */
76: struct node *right; /* right child */
77: struct node *parent; /* parent */
1.1.1.2 ! misho 78: void *item; /* this item */
1.1 misho 79: };
80:
81: /* The tree itself */
82: struct gtree {
83: void *arg;
84: gtree_cmp_t *cmp;
85: gtree_add_t *add;
86: gtree_del_t *del;
87: gtree_print_t *print;
88: u_int mods; /* modification counter */
89: u_int size; /* number of items in table */
90: struct node *root; /* root of tree */
91: const char *mtype; /* memory type */
92: char mtbuf[TYPED_MEM_TYPELEN];
93: u_char locked;
94: };
95:
96: /*
97: * Internal functions
98: */
99: static struct node *gtree_find(struct gtree *g,
100: const void *item, struct node **parentp);
101: static struct node *gtree_get_next(struct gtree *g, struct node *node);
102: static struct node *gtree_get_prev(struct gtree *g, struct node *node);
103: static void gtree_insert_fixup(struct gtree *g, struct node *x);
104: static void gtree_delete_fixup(struct gtree *g, struct node *x);
105: static void gtree_rotate_left(struct gtree *g, struct node *x);
106: static void gtree_rotate_right(struct gtree *g, struct node *x);
107: #ifndef _KERNEL
108: static void gtree_print_node(struct gtree *g, FILE *fp,
109: struct node *node, const char *which, int depth);
110: #endif
111:
112: static gtree_cmp_t gtree_default_cmp;
113: static gtree_add_t gtree_default_add;
114: static gtree_del_t gtree_default_del;
115:
116: /*
117: * Internal variables
118: */
119:
120: #define NIL (&nil)
121:
122: /* Note: nil->parent is modified during normal operation */
1.1.1.2 ! misho 123: static struct node nil = { BLACK, NIL, NIL, NULL, NULL };
1.1 misho 124:
125: /*
126: * Create a new tree.
127: */
128: struct gtree *
129: gtree_create(void *arg, const char *mtype, gtree_cmp_t *cmp,
130: gtree_add_t *add, gtree_del_t *del, gtree_print_t *print)
131: {
132: struct gtree *g;
133:
134: /* Create new tree object */
135: if ((g = MALLOC(mtype, sizeof(*g))) == NULL)
136: return (NULL);
137: memset(g, 0, sizeof(*g));
138: g->arg = arg;
139: g->cmp = cmp != NULL ? cmp : gtree_default_cmp;
140: g->add = add != NULL ? add : gtree_default_add;
141: g->del = del != NULL ? del: gtree_default_del;
142: g->print = print;
143: g->root = NIL;
144:
145: /* Create memory subtypes */
146: if (mtype != NULL) {
147: strlcpy(g->mtbuf, mtype, sizeof(g->mtbuf));
148: g->mtype = g->mtbuf;
149: }
150:
151: #if GTREE_TRACE
152: /* Tracing */
153: if (g->print != NULL)
154: fprintf(stderr, "%s[%p]: tree created\n", __FUNCTION__, g);
155: #endif
156:
157: /* Done */
158: return (g);
159: }
160:
161: /*
162: * Destroy a tree.
163: */
164: void
165: gtree_destroy(struct gtree **gp)
166: {
167: struct gtree *const g = *gp;
168:
169: /* Sanity check */
170: if (g == NULL)
171: return;
172: assert(!g->locked);
173:
174: /* Remove all remaining nodes */
175: while (g->root != NIL)
176: gtree_remove(g, g->root->item);
177:
178: #if GTREE_TRACE
179: /* Tracing */
180: if (g->print != NULL)
181: fprintf(stderr, "%s[%p]: tree destroyed\n", __FUNCTION__, g);
182: #endif
183:
184: /* Free object */
185: FREE(g->mtype, g);
186: *gp = NULL;
187: }
188:
189: /*
190: * Get the argument supplied to gtree_create().
191: */
192: void *
193: gtree_arg(struct gtree *g)
194: {
195: return (g->arg);
196: }
197:
198: /*
199: * Return number of items in the table.
200: */
201: u_int
202: gtree_size(struct gtree *g)
203: {
204: return (g->size);
205: }
206:
207: /*
208: * Get an item.
209: *
210: * Returns the item, or NULL if the item does not exist.
211: */
212: void *
1.1.1.2 ! misho 213: gtree_get(struct gtree *g, void *item)
1.1 misho 214: {
215: struct node *dummy;
216: struct node *node;
217:
218: /* Find node */
219: node = gtree_find(g, item, &dummy);
220:
221: #if GTREE_TRACE
222: /* Tracing */
223: if (g->print != NULL) {
224: fprintf(stderr, "%s[%p]: key=\"%s\" found=%d size=%u\n",
225: __FUNCTION__, g, (*g->print)(g, (void *)item),
226: node != NULL, g->size);
227: }
228: #endif
229:
230: /* Return result */
231: if (node != NULL)
232: return ((void *)node->item);
233: return (NULL);
234: }
235:
236: /*
237: * Put an item.
238: *
239: * Returns 0 if the item is new, 1 if it replaces an existing
240: * item, and -1 if there was an error.
241: */
242: int
1.1.1.2 ! misho 243: gtree_put(struct gtree *g, void *item)
1.1 misho 244: {
245: return (gtree_put_prealloc(g, item, NULL));
246: }
247:
248: /*
249: * Put an item -- common internal code.
250: */
251: int
1.1.1.2 ! misho 252: gtree_put_prealloc(struct gtree *g, void *item, void *new_node)
1.1 misho 253: {
254: struct node *parent;
255: struct node *node;
256:
257: /* NULL item is invalid */
258: if (item == NULL) {
259: errno = EINVAL;
260: return (-1);
261: }
262:
263: /* Lock tree */
264: if (g->locked) {
265: errno = EBUSY;
266: return (-1);
267: }
268: g->locked = 1;
269:
270: /* See if item already exists */
271: node = gtree_find(g, item, &parent);
272:
273: #if GTREE_TRACE
274: /* Tracing */
275: if (g->print != NULL) {
276: fprintf(stderr, "%s[%p]: key=\"%s\" exists=%d newsize=%u\n",
277: __FUNCTION__, g, (*g->print)(g, (void *)item),
278: node != NULL, g->size + (node == NULL));
279: }
280: #endif
281:
282: /* If item already exists, just replace */
283: if (node != NULL) {
284: if (new_node != NULL)
285: FREE(g->mtype, new_node); /* didn't need it */
286: g->mods++;
287: (*g->del)(g, (void *)node->item);
288: node->item = item;
289: (*g->add)(g, (void *)node->item);
290: g->locked = 0;
291: return (1);
292: }
293:
294: /* Allocate or use caller-supplied memory for new node */
295: if (new_node != NULL)
296: node = new_node;
297: else if ((node = MALLOC(g->mtype, sizeof(*node))) == NULL) {
298: g->locked = 0;
299: return (-1);
300: }
301: memset(node, 0, sizeof(*node));
302: node->color = RED;
303: node->left = NIL;
304: node->right = NIL;
305: node->parent = parent;
306: node->item = item;
307: g->mods++;
308: g->size++;
309:
310: /* Add to tree */
311: if (parent != NULL) {
312: if ((*g->cmp)(g, node->item, parent->item) < 0)
313: parent->left = node;
314: else
315: parent->right = node;
316: } else
317: g->root = node;
318:
319: /* Rebalance */
320: gtree_insert_fixup(g, node);
321:
322: /* Notify caller of new item */
323: (*g->add)(g, (void *)node->item);
324:
325: #if GTREE_TRACE
326: /* Tracing */
327: if (g->print != NULL)
328: gtree_print(g, stderr);
329: #endif
330:
331: /* Unlock tree and return */
332: g->locked = 0;
333: return (0);
334: }
335:
336: /*
337: * Remove an item.
338: *
339: * Returns 1 if the item was found and removed, 0 if not found.
340: */
341: int
342: gtree_remove(struct gtree *g, const void *item)
343: {
344: struct node *dummy;
345: struct node *node;
346: struct node *x;
347: struct node *y;
348:
349: /* Lock tree */
350: if (g->locked) {
351: errno = EBUSY;
352: return (-1);
353: }
354: g->locked = 1;
355:
356: /* Find node */
357: node = gtree_find(g, item, &dummy);
358:
359: #if GTREE_TRACE
360: /* Tracing */
361: if (g->print != NULL) {
362: fprintf(stderr, "%s[%p]: key=\"%s\" exists=%d newsize=%u\n",
363: __FUNCTION__, g, (*g->print)(g, (void *)item),
364: node != NULL, g->size - (node != NULL));
365: }
366: #endif
367:
368: /* If not found, nothing to do */
369: if (node == NULL) {
370: g->locked = 0;
371: return (0);
372: }
373:
374: /* Notify caller of deletion */
375: (*g->del)(g, (void *)node->item);
376:
377: /* Set y to node or first successor with a NIL child */
378: if (node->left == NIL || node->right == NIL)
379: y = node;
380: else
381: for (y = node->right; y->left != NIL; y = y->left);
382:
383: /* Set x to y's only child, or NIL if no children */
384: if (y->left != NIL)
385: x = y->left;
386: else
387: x = y->right;
388:
389: /* Remove y from the parent chain */
390: x->parent = y->parent;
391: if (y->parent != NULL) {
392: if (y == y->parent->left)
393: y->parent->left = x;
394: else
395: y->parent->right = x;
396: } else
397: g->root = x;
398:
399: /* Move y's item to node */
400: if (y != node)
401: node->item = y->item;
402:
403: /* Do fixup if necessary */
404: if (y->color == BLACK)
405: gtree_delete_fixup(g, x);
406:
407: /* Free node y */
408: FREE(g->mtype, y);
409:
410: /* Update stats */
411: g->mods++;
412: g->size--;
413:
414: #if GTREE_TRACE
415: /* Tracing */
416: if (g->print != NULL)
417: gtree_print(g, stderr);
418: #endif
419:
420: /* Unlock tree and return */
421: g->locked = 0;
422: return (1);
423: }
424:
425: /*
426: * Get the size of a node.
427: */
428: u_int
429: gtree_node_size(void)
430: {
431: return (sizeof(struct node));
432: }
433:
434: /*
435: * Get the first item.
436: */
437: void *
438: gtree_first(struct gtree *g)
439: {
440: struct node *node;
441:
442: if ((node = gtree_get_next(g, NULL)) == NULL)
443: return (NULL);
444: return ((void *)node->item);
445: }
446:
447: /*
448: * Get the next item.
449: */
450: void *
451: gtree_next(struct gtree *g, const void *item)
452: {
453: struct node *dummy;
454: struct node *node;
455:
456: if ((node = gtree_find(g, item, &dummy)) == NULL)
457: return (NULL);
458: if ((node = gtree_get_next(g, node)) == NULL)
459: return (NULL);
460: return ((void *)node->item);
461: }
462:
463: /*
464: * Get the last item.
465: */
466: void *
467: gtree_last(struct gtree *g)
468: {
469: struct node *node;
470:
471: if ((node = gtree_get_prev(g, NULL)) == NULL)
472: return (NULL);
473: return ((void *)node->item);
474: }
475:
476: /*
477: * Get the previous item.
478: */
479: void *
480: gtree_prev(struct gtree *g, const void *item)
481: {
482: struct node *dummy;
483: struct node *node;
484:
485: if ((node = gtree_find(g, item, &dummy)) == NULL)
486: return (NULL);
487: if ((node = gtree_get_prev(g, node)) == NULL)
488: return (NULL);
489: return ((void *)node->item);
490: }
491:
492: /*
493: * Traverse the tree.
494: */
495: int
496: gtree_traverse(struct gtree *g, int (*handler)(struct gtree *g, void *item))
497: {
498: struct node *node;
499: int r = 0;
500:
501: /* Lock tree */
502: if (g->locked) {
503: errno = EBUSY;
504: return (-1);
505: }
506: g->locked = 1;
507:
508: /* Get items in a list */
509: for (node = gtree_get_next(g, NULL);
510: node != NULL; node = gtree_get_next(g, node)) {
511: if ((*handler)(g, (void *)node->item) == -1) {
512: r = -1;
513: break;
514: }
515: }
516:
517: /* Done */
518: g->locked = 0;
519: return (r);
520: }
521:
522: /*
523: * Get a sorted array of tree contents.
524: */
525: int
526: gtree_dump(struct gtree *g, void ***listp, const char *mtype)
527: {
528: struct node *node;
529: void **list;
1.1.1.2 ! misho 530: unsigned i;
1.1 misho 531:
532: /* Get items in a list */
533: if ((list = MALLOC(mtype, g->size * sizeof(*list))) == NULL)
534: return (-1);
535: for (i = 0, node = gtree_get_next(g, NULL);
536: node != NULL; node = gtree_get_next(g, node))
537: list[i++] = (void *)node->item;
538: assert(i == g->size);
539:
540: /* Done */
541: *listp = list;
542: return (i);
543: }
544:
545: #ifndef _KERNEL
546: /*
547: * Print out a tree
548: */
549: void
550: gtree_print(struct gtree *g, FILE *fp)
551: {
552: gtree_print_node(g, fp, g->root, "ROOT", 0);
553: }
554: #endif
555:
556: /**********************************************************************
557: DEFAULT CALLBACKS
558: **********************************************************************/
559:
560: static int
561: gtree_default_cmp(struct gtree *g, const void *item1, const void *item2)
562: {
1.1.1.2 ! misho 563: (void)g;
1.1 misho 564: if (item1 < item2)
565: return (-1);
566: if (item1 > item2)
567: return (-1);
568: return (0);
569: }
570:
571: static void
572: gtree_default_add(struct gtree *g, void *item)
573: {
1.1.1.2 ! misho 574: (void)g;
! 575: (void)item;
! 576:
1.1 misho 577: return;
578: }
579:
580: static void
581: gtree_default_del(struct gtree *g, void *item)
582: {
1.1.1.2 ! misho 583: (void)g;
! 584: (void)item;
! 585:
1.1 misho 586: return;
587: }
588:
589: /**********************************************************************
590: HELPER METHODS
591: **********************************************************************/
592:
593: /*
594: * Find an item. If not found, set *parentp to the would-be parent
595: * (NULL if the tree is empty).
596: */
597: static struct node *
598: gtree_find(struct gtree *g, const void *item, struct node **parentp)
599: {
600: struct node *node;
601: int diff;
602:
603: *parentp = NULL;
604: for (node = g->root; node != NIL; ) {
605: diff = (*g->cmp)(g, item, node->item);
606: if (diff == 0)
607: return (node);
608: *parentp = node;
609: node = (diff < 0) ? node->left : node->right;
610: }
611: return (NULL);
612: }
613:
614: /*
615: * Get the next item in the tree after "node", or the first
616: * item if "node" is NULL.
617: */
618: static struct node *
619: gtree_get_next(struct gtree *g, struct node *node)
620: {
621: if (node == NULL) {
622: if (g->root == NIL)
623: return (NULL);
624: node = g->root;
625: } else if (node->right != NIL)
626: node = node->right;
627: else {
628: while (1) {
629: if (node->parent == NULL
630: || node == node->parent->left)
631: return (node->parent);
632: node = node->parent;
633: }
634: }
635: while (node->left != NIL)
636: node = node->left;
637: return (node);
638: }
639:
640: /*
641: * Get the previous item in the tree before "node", or the last
642: * item if "node" is NULL.
643: */
644: static struct node *
645: gtree_get_prev(struct gtree *g, struct node *node)
646: {
647: if (node == NULL) {
648: if (g->root == NIL)
649: return (NULL);
650: node = g->root;
651: } else if (node->left != NIL)
652: node = node->left;
653: else {
654: while (1) {
655: if (node->parent == NULL
656: || node == node->parent->right)
657: return (node->parent);
658: node = node->parent;
659: }
660: }
661: while (node->right != NIL)
662: node = node->right;
663: return (node);
664: }
665:
666: /*
667: * Rotate node x to the left
668: */
669: static void
670: gtree_rotate_left(struct gtree *g, struct node *x)
671: {
672: struct node *y = x->right;
673:
674: x->right = y->left;
675: if (y->left != NIL)
676: y->left->parent = x;
677: if (y != NIL)
678: y->parent = x->parent;
679: if (x->parent != NULL) {
680: if (x == x->parent->left)
681: x->parent->left = y;
682: else
683: x->parent->right = y;
684: } else
685: g->root = y;
686: y->left = x;
687: if (x != NIL)
688: x->parent = y;
689: }
690:
691: /*
692: * Rotate node x to the right
693: */
694: static void
695: gtree_rotate_right(struct gtree *g, struct node *x)
696: {
697: struct node *y = x->left;
698:
699: x->left = y->right;
700: if (y->right != NIL)
701: y->right->parent = x;
702: if (y != NIL)
703: y->parent = x->parent;
704: if (x->parent != NULL) {
705: if (x == x->parent->right)
706: x->parent->right = y;
707: else
708: x->parent->left = y;
709: } else
710: g->root = y;
711: y->right = x;
712: if (x != NIL)
713: x->parent = y;
714: }
715:
716: /*
717: * Reestablish red/black balance after inserting "node"
718: */
719: static void
720: gtree_insert_fixup(struct gtree *g, struct node *x)
721: {
722: while (x != g->root && x->parent->color == RED) {
723: if (x->parent == x->parent->parent->left) {
724: struct node *y = x->parent->parent->right;
725:
726: if (y->color == RED) {
727: x->parent->color = BLACK;
728: y->color = BLACK;
729: x->parent->parent->color = RED;
730: x = x->parent->parent;
731: } else {
732: if (x == x->parent->right) {
733: x = x->parent;
734: gtree_rotate_left(g, x);
735: }
736: x->parent->color = BLACK;
737: x->parent->parent->color = RED;
738: gtree_rotate_right(g, x->parent->parent);
739: }
740: } else {
741: struct node *y = x->parent->parent->left;
742:
743: if (y->color == RED) {
744: x->parent->color = BLACK;
745: y->color = BLACK;
746: x->parent->parent->color = RED;
747: x = x->parent->parent;
748: } else {
749: if (x == x->parent->left) {
750: x = x->parent;
751: gtree_rotate_right(g, x);
752: }
753: x->parent->color = BLACK;
754: x->parent->parent->color = RED;
755: gtree_rotate_left(g, x->parent->parent);
756: }
757: }
758: }
759: g->root->color = BLACK;
760: }
761:
762: /*
763: * Reestablish red/black balance after deleting node x
764: */
765: static void
766: gtree_delete_fixup(struct gtree *g, struct node *x)
767: {
768: while (x != g->root && x->color == BLACK) {
769: if (x == x->parent->left) {
770: struct node *w = x->parent->right;
771:
772: if (w->color == RED) {
773: w->color = BLACK;
774: x->parent->color = RED;
775: gtree_rotate_left(g, x->parent);
776: w = x->parent->right;
777: }
778: if (w->left->color == BLACK
779: && w->right->color == BLACK) {
780: w->color = RED;
781: x = x->parent;
782: } else {
783: if (w->right->color == BLACK) {
784: w->left->color = BLACK;
785: w->color = RED;
786: gtree_rotate_right(g, w);
787: w = x->parent->right;
788: }
789: w->color = x->parent->color;
790: x->parent->color = BLACK;
791: w->right->color = BLACK;
792: gtree_rotate_left(g, x->parent);
793: x = g->root;
794: }
795: } else {
796: struct node *w = x->parent->left;
797:
798: if (w->color == RED) {
799: w->color = BLACK;
800: x->parent->color = RED;
801: gtree_rotate_right(g, x->parent);
802: w = x->parent->left;
803: }
804: if (w->right->color == BLACK
805: && w->left->color == BLACK) {
806: w->color = RED;
807: x = x->parent;
808: } else {
809: if (w->left->color == BLACK) {
810: w->right->color = BLACK;
811: w->color = RED;
812: gtree_rotate_left(g, w);
813: w = x->parent->left;
814: }
815: w->color = x->parent->color;
816: x->parent->color = BLACK;
817: w->left->color = BLACK;
818: gtree_rotate_right(g, x->parent);
819: x = g->root;
820: }
821: }
822: }
823: x->color = BLACK;
824: }
825:
826: #ifndef _KERNEL
827: /*
828: * Recursively print out one node and all its descendants.
829: */
830: static void
831: gtree_print_node(struct gtree *g, FILE *fp, struct node *node,
832: const char *which, int depth)
833: {
834: int i;
835:
836: for (i = 0; i < depth; i++)
837: fprintf(fp, " ");
838: fprintf(fp, "%s: ", which);
839: if (node == NIL) {
840: fprintf(fp, "NIL\n");
841: return;
842: }
843: if (g->print != NULL)
844: fprintf(fp, "%s", (*g->print)(g, (void *)node->item));
845: else
846: fprintf(fp, "%p", node);
847: fprintf(fp, " %s\n", node->color == RED ? "RED" : "BLACK");
848: if (node->left != NIL)
849: gtree_print_node(g, fp, node->left, "LEFT", depth + 1);
850: if (node->right != NIL)
851: gtree_print_node(g, fp, node->right, "RIGHT", depth + 1);
852: }
853: #endif /* !_KERNEL */
854:
855: #ifdef GTREE_TEST
856:
857: /**********************************************************************
858: TEST ROUTINE
859: **********************************************************************/
860:
861: #include <err.h>
862: #include <string.h>
863: #include <signal.h>
864: #include <unistd.h>
865: #include <time.h>
866:
867: /* Debugging */
868: #define DBG(fmt, args...) \
869: do { \
870: if (debug) \
871: printf(fmt "\n" , ## args); \
872: } while (0)
873:
874: static gtree_cmp_t gtree_test_cmp;
875: static gtree_add_t gtree_test_add;
876: static gtree_del_t gtree_test_del;
877: static gtree_print_t gtree_test_print;
878:
879: static int *trin; /* trin[i] iff i in the tree, according to add, del */
880: static int trsz; /* size of tree according to add, del */
881: static int *nums; /* fixed array where nums[i] == i */
882: static u_long num; /* size of nums[] array */
883: static int debug;
884: static struct gtree *g;
885:
886: static void gtree_assert(int i, const char *s, const char *func, int line);
887: static int chknode(struct node *node);
888:
889: #define CHECK(x) gtree_assert(x, #x, __FUNCTION__, __LINE__)
890:
891: int
892: main(int ac, char **av)
893: {
894: u_long count;
895: u_long seed;
896: int size = 0; /* my idea of what the tree size should be */
897: int *myin; /* our idea of what values are in the tree */
898: int ch;
899: int i;
900:
901: /* Default seed and count */
902: seed = htonl(getpid()) ^ time(NULL);
903: count = 10000;
904:
905: /* Parse command line */
906: while ((ch = getopt(ac, av, "dc:s:n:")) != -1) {
907: switch (ch) {
908: case 'c':
909: count = strtoul(optarg, NULL, 0);
910: break;
911: case 'd':
912: debug++;
913: break;
914: case 'n':
915: num = strtoul(optarg, NULL, 0);
916: break;
917: case 's':
918: seed = strtoul(optarg, NULL, 0);
919: break;
920: default:
921: usage:
922: errx(1, "usage: gtree [-s seed] [-c count] [-n num]");
923: }
924: }
925: ac -= optind;
926: av += optind;
927: if (ac != 0)
928: goto usage;
929:
930: /* Seed RNG */
931: srandom(seed);
932: if (num == 0)
933: num = (random() % 500) + 1;
934: printf("seed = %lu num = %lu count = %lu\n", seed, num, count);
935:
936: /* Initialize number array */
937: if ((nums = MALLOC(TYPED_MEM_TEMP, num * sizeof(*nums))) == NULL)
938: err(1, "malloc");
939: if ((myin = MALLOC(TYPED_MEM_TEMP, num * sizeof(*myin))) == NULL)
940: err(1, "malloc");
941: if ((trin = MALLOC(TYPED_MEM_TEMP, num * sizeof(*trin))) == NULL)
942: err(1, "malloc");
943: for (i = 0; i < num; i++)
944: nums[i] = i;
945: memset(myin, 0, num * sizeof(*myin));
946: memset(trin, 0, num * sizeof(*trin));
947:
948: /* Get tree */
949: if ((g = gtree_create(NULL, "gtree", gtree_test_cmp,
950: gtree_test_add, gtree_test_del, gtree_test_print)) == NULL)
951: err(1, "gtree_create");
952:
953: /* Iterate */
954: for (i = 0; i < count; i++) {
955: void **list;
956: int first;
957: int last;
958: int add;
959: int *p;
960: int i;
961: int r;
962:
963: /* Pick a random number and action */
964: i = random() % num;
965: add = (random() & (1 << (i % 17))) != 0;
966: DBG("%s %u siz=%u in=%d",
967: add ? "add" : "del", i, size, myin[i]);
968:
969: /* Do an operation (add or remove) */
970: if (add) {
971: if (gtree_put(g, &nums[i]) == -1) {
972: warn("gtree_put");
973: CHECK(0);
974: }
975: if (!myin[i])
976: size++;
977: myin[i] = 1;
978: } else {
979: r = gtree_remove(g, &nums[i]);
980: if (r == -1) {
981: warn("gtree_remove");
982: CHECK(0);
983: }
984: CHECK(r == myin[i]);
985: if (myin[i])
986: size--;
987: myin[i] = 0;
988: }
989:
990: /* Dump tree */
991: if (debug >= 2)
992: gtree_print(g, stdout);
993:
994: /* Check sizes */
995: CHECK(trsz == size);
996: CHECK(gtree_size(g) == size);
997:
998: /* Check presence of items */
999: if (memcmp(trin, myin, num * sizeof(*trin)) != 0)
1000: CHECK(0);
1001:
1002: /* Check first and last */
1003: p = (int *)gtree_first(g);
1004: first = p ? *p : -1;
1005: p = (int *)gtree_last(g);
1006: last = p ? *p : -1;
1007: for (i = 0; i < num && myin[i] == 0; i++);
1008: if (i == num)
1009: i = -1;
1010: CHECK(first == i);
1011:
1012: /* Check last */
1013: for (i = num - 1; i >= 0 && myin[i] == 0; i--);
1014: CHECK(last == i);
1015:
1016: /* Check sorting */
1017: if ((r = gtree_dump(g, &list, TYPED_MEM_TEMP)) == -1)
1018: err(1, "gtree_dump");
1019: CHECK(r == size);
1020: for (i = 1; i < r; i++) {
1021: const int this = *((int *)list[i]);
1022: const int prev = *((int *)list[i - 1]);
1023:
1024: CHECK(prev < this);
1025: }
1026: FREE(TYPED_MEM_TEMP, list);
1027:
1028: /* Check red-black property */
1029: chknode(g->root);
1030: }
1031:
1032: /* Done */
1033: gtree_destroy(&g);
1034: FREE(TYPED_MEM_TEMP, nums);
1035: FREE(TYPED_MEM_TEMP, myin);
1036: FREE(TYPED_MEM_TEMP, trin);
1037: if (debug)
1038: typed_mem_dump(stdout);
1039: return (0);
1040: }
1041:
1042: static int
1043: gtree_test_cmp(struct gtree *g, const void *item1, const void *item2)
1044: {
1045: const int *const p1 = item1;
1046: const int *const p2 = item2;
1047:
1048: CHECK(p1 >= &nums[0] && p1 < &nums[num]);
1049: CHECK(p2 >= &nums[0] && p2 < &nums[num]);
1050: return (*((int *)item1) - *((int *)item2));
1051: }
1052:
1053: static void
1054: gtree_test_add(struct gtree *g, void *item)
1055: {
1056: const int *const p = item;
1057: const int i = *((int *)item);
1058:
1059: DBG(" add->%u", i);
1060: CHECK(p >= &nums[0] && p < &nums[num]);
1061: if (gtree_remove(g, item) != -1 || errno != EBUSY)
1062: CHECK(0);
1063: CHECK(!trin[i]);
1064: trin[i] = 1;
1065: trsz++;
1066: }
1067:
1068: static void
1069: gtree_test_del(struct gtree *g, void *item)
1070: {
1071: const int *const p = item;
1072: const int i = *((int *)item);
1073:
1074: DBG(" del->%u", i);
1075: CHECK(p >= &nums[0] && p < &nums[num]);
1076: if (gtree_put(g, item) != -1 || errno != EBUSY)
1077: CHECK(0);
1078: CHECK(trin[i]);
1079: trin[i] = 0;
1080: trsz--;
1081: }
1082:
1083: static const char *
1084: gtree_test_print(struct gtree *g, const void *item)
1085: {
1086: static char buf[16];
1087:
1088: snprintf(buf, sizeof(buf), "%03u", *((u_int *)item));
1089: return (buf);
1090: }
1091:
1092: static void
1093: gtree_assert(int pred, const char *s, const char *func, int line)
1094: {
1095: if (pred)
1096: return;
1.1.1.2 ! misho 1097: Perror("FAILURE: %s:%u: %s\n", func, line, s);
1.1 misho 1098: gtree_print(g, stdout);
1099: kill(getpid(), SIGABRT);
1100: }
1101:
1102: static int
1103: chknode(struct node *node)
1104: {
1105: int l, r;
1106:
1107: CHECK(node->color == RED || node->color == BLACK);
1108: if (node == NIL) {
1109: CHECK(node->left == NIL && node->right == NIL);
1110: CHECK(node->color == BLACK);
1111: return (1);
1112: }
1113: if (node->color == RED) {
1114: CHECK(node->left->color == BLACK);
1115: CHECK(node->right->color == BLACK);
1116: }
1117: l = chknode(node->left);
1118: r = chknode(node->right);
1119: CHECK(l == r);
1120: return (l + (node->color == BLACK));
1121: }
1122:
1123: #endif /* GTREE_TEST */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>