Annotation of embedaddon/mpd/src/contrib/libpdel/util/gtree.c, revision 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>