Annotation of embedaddon/libpdel/util/gtree.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>