Annotation of frontvm/as68k/dict.c, revision 1.1

1.1     ! root        1: 
        !             2: #include <stdio.h>
        !             3: #include <string.h>
        !             4: #include <stdlib.h>
        !             5: #include <assert.h>
        !             6: #include "dict.h"
        !             7: 
        !             8: /*#define DEBUG*/
        !             9: 
        !            10: #ifndef MIN
        !            11: # define MIN(a,b)              ((a)<(b) ? (a) : (b))
        !            12: #endif
        !            13: #ifndef MAX
        !            14: # define MAX(a,b)              ((a)>(b) ? (a) : (b))
        !            15: #endif
        !            16: 
        !            17: #define _NONE  -1
        !            18: #define LEFT   0
        !            19: #define RIGHT  1
        !            20: #define _ERR   2
        !            21: 
        !            22: static int parent_side (const struct Node *node)
        !            23: {
        !            24:        if (node->parent == NULL)
        !            25:                return _NONE;
        !            26:        else if (node->parent->child[LEFT] == node)
        !            27:                return LEFT;
        !            28:        else if (node->parent->child[RIGHT] == node)
        !            29:                return RIGHT;
        !            30:        else
        !            31:                return _ERR;
        !            32: }
        !            33: 
        !            34: static void print_tree (const struct Node *node, int depth)
        !            35: {
        !            36:        int i;
        !            37:        //assert (depth < 10);
        !            38:        if (depth==0) printf ("Tree printout:\n");
        !            39:        if (!node) return;
        !            40:        for (i=0; i<depth; i++) {
        !            41:                printf ("\t");
        !            42:        }
        !            43:        
        !            44:        switch (parent_side (node)) {
        !            45:                case _NONE: printf ("+ "); break;
        !            46:                case LEFT: printf ("L "); break;
        !            47:                case RIGHT: printf ("R "); break;
        !            48:                default: printf ("? "); break;
        !            49:        }
        !            50:        printf ("\"%s\" bal %d: obj %x\n", node->key, node->balance, (int)node->obj);
        !            51:        
        !            52:        if (node->child[LEFT]) print_tree (node->child[LEFT], depth+1);
        !            53:        if (node->child[RIGHT]) print_tree (node->child[RIGHT], depth+1);
        !            54: }
        !            55: 
        !            56: static struct Node *alloc_node ()
        !            57: {
        !            58:        struct Node *node = (struct Node *) malloc (sizeof (struct Node));
        !            59:        memset (node, 0, sizeof (struct Node));
        !            60:        return node;
        !            61: }
        !            62: 
        !            63: static void free_node (struct Node *node)
        !            64: {
        !            65:        if (node->key) free (node->key);
        !            66:        free (node);
        !            67: }
        !            68: 
        !            69: static void set_node (struct Node *node, const char *key, void *obj)
        !            70: {
        !            71:        node->key = (char *) malloc (strlen(key)+1);
        !            72:        strcpy (node->key, key);
        !            73:        node->obj = obj;
        !            74: }
        !            75: 
        !            76: /*
        !            77:  * This node is unbalanced :-o
        !            78:  * Returns new top node.
        !            79:  */
        !            80: static struct Node *balance_node (struct Dict *tree, struct Node *high)
        !            81: {
        !            82:        struct Node *mid = NULL;
        !            83:        struct Node *low = NULL;
        !            84:        
        !            85:        /* Single, rightwards */
        !            86:        if ((high->balance == +2) && (high->child[RIGHT]->balance >= 0)) {
        !            87:                mid = high->child[RIGHT];
        !            88:                low = mid->child[RIGHT];
        !            89: 
        !            90:                /* this one ends at top */
        !            91:                mid->parent = high->parent;
        !            92:                switch (parent_side (high)) {
        !            93:                        case _NONE: tree->root = mid; break;
        !            94:                        case LEFT: mid->parent->child[LEFT] = mid; break;
        !            95:                        case RIGHT: mid->parent->child[RIGHT] = mid; break;
        !            96:                }
        !            97: 
        !            98:                high->child[RIGHT] = mid->child[LEFT];
        !            99:                if (mid->child[LEFT]) mid->child[LEFT]->parent = high;
        !           100:                
        !           101:                mid->child[LEFT] = high;
        !           102:                high->parent = mid;
        !           103:                
        !           104:                high->balance = high->balance - 1 - MAX (mid->balance, 0);
        !           105:                mid->balance = mid->balance - 1 + MIN (high->balance, 0);
        !           106: 
        !           107:                return mid;
        !           108:        }
        !           109:        /* Single, leftwards */
        !           110:        else if ((high->balance == -2) && (high->child[LEFT]->balance <= 0)) {
        !           111:                mid = high->child[LEFT];
        !           112:                low = mid->child[LEFT];
        !           113: 
        !           114:                /* this one ends at top */
        !           115:                mid->parent = high->parent;
        !           116:                switch (parent_side (high)) {
        !           117:                        case _NONE: tree->root = mid; break;
        !           118:                        case LEFT: mid->parent->child[LEFT] = mid; break;
        !           119:                        case RIGHT: mid->parent->child[RIGHT] = mid; break;
        !           120:                }
        !           121: 
        !           122:                high->child[LEFT] = mid->child[RIGHT];
        !           123:                if (mid->child[RIGHT]) mid->child[RIGHT]->parent = high;
        !           124:                
        !           125:                mid->child[RIGHT] = high;
        !           126:                high->parent = mid;
        !           127: 
        !           128:                high->balance = high->balance + 1 - MIN (mid->balance, 0);
        !           129:                mid->balance = mid->balance + 1 + MAX (high->balance, 0);
        !           130: 
        !           131:                return mid;
        !           132:        }
        !           133:        /* Double, rightwards */
        !           134:        else if ((high->balance == +2) && (high->child[RIGHT]->balance == -1)) {
        !           135:                mid = high->child[RIGHT];
        !           136:                low = mid->child[LEFT];
        !           137:                /* this one ends at top */
        !           138:                low->parent = high->parent;
        !           139:                switch (parent_side (high)) {
        !           140:                        case _NONE: tree->root = low; break;
        !           141:                        case LEFT: low->parent->child[LEFT] = low; break;
        !           142:                        case RIGHT: low->parent->child[RIGHT] = low; break;
        !           143:                }
        !           144: 
        !           145:                high->child[RIGHT] = low->child[LEFT];
        !           146:                if (low->child[LEFT]) low->child[LEFT]->parent = high;
        !           147:                
        !           148:                mid->child[LEFT] = low->child[RIGHT];
        !           149:                if (low->child[RIGHT]) low->child[RIGHT]->parent = mid;
        !           150:                
        !           151:                low->child[LEFT] = high;
        !           152:                high->parent = low;
        !           153:                
        !           154:                low->child[RIGHT] = mid;
        !           155:                mid->parent = low;
        !           156: 
        !           157:                high->balance = -MAX (low->balance, 0);
        !           158:                mid->balance = -MIN (low->balance, 0);
        !           159:                low->balance = 0;
        !           160:                
        !           161:                return low;
        !           162:        }
        !           163:        /* Double, leftwards */
        !           164:        else if ((high->balance == -2) && (high->child[LEFT]->balance == +1)) {
        !           165:                mid = high->child[LEFT];
        !           166:                low = mid->child[RIGHT];
        !           167: 
        !           168:                /* this one ends at top */
        !           169:                low->parent = high->parent;
        !           170:                switch (parent_side (high)) {
        !           171:                        case _NONE: tree->root = low; break;
        !           172:                        case LEFT: low->parent->child[LEFT] = low; break;
        !           173:                        case RIGHT: low->parent->child[RIGHT] = low; break;
        !           174:                }
        !           175: 
        !           176:                high->child[LEFT] = low->child[RIGHT];
        !           177:                if (low->child[RIGHT]) low->child[RIGHT]->parent = high;
        !           178:                
        !           179:                mid->child[RIGHT] = low->child[LEFT];
        !           180:                if (low->child[LEFT]) low->child[LEFT]->parent = mid;
        !           181:                
        !           182:                low->child[RIGHT] = high;
        !           183:                high->parent = low;
        !           184:                
        !           185:                low->child[LEFT] = mid;
        !           186:                mid->parent = low;
        !           187: 
        !           188:                high->balance = -MIN (low->balance, 0);
        !           189:                mid->balance = -MAX (low->balance, 0);
        !           190:                low->balance = 0;
        !           191: 
        !           192:                return low;
        !           193:        } else {
        !           194:                assert ("This shouldn't happen in balance_node()");
        !           195:                return NULL;
        !           196:        }
        !           197: }
        !           198: 
        !           199: void dict_init (struct Dict *tree)
        !           200: {
        !           201:        tree->root = NULL;
        !           202:        tree->len = 0;
        !           203: }
        !           204: 
        !           205: static void node_recurse_free (struct Node *node)
        !           206: {
        !           207:        if (node->child[LEFT]) {
        !           208:                node_recurse_free (node->child[LEFT]);
        !           209:        }
        !           210:        if (node->child[RIGHT]) {
        !           211:                node_recurse_free (node->child[RIGHT]);
        !           212:        }
        !           213:        free_node (node);
        !           214: }
        !           215: 
        !           216: void dict_free (struct Dict *tree)
        !           217: {
        !           218:        node_recurse_free (tree->root);
        !           219: }
        !           220: 
        !           221: void dict_remove (struct Dict *tree, const char *key)
        !           222: {
        !           223:        int side;
        !           224:        struct Node *to_remove;
        !           225:        struct Node *iter;
        !           226:        struct Node *rem_pos;
        !           227:        int rem_dir;
        !           228: 
        !           229:        to_remove = dict_get (tree, key);
        !           230: 
        !           231:        if (to_remove == NULL) return;
        !           232: 
        !           233:        side = parent_side (to_remove);
        !           234:        
        !           235:        /* easy. no children */
        !           236:        if ((to_remove->child[LEFT] == NULL) && (to_remove->child[RIGHT] == NULL)) {
        !           237:                if (side == _NONE) {
        !           238:                        tree->root = NULL;
        !           239:                } else {
        !           240:                        to_remove->parent->child[side] = NULL;
        !           241:                }
        !           242:                rem_pos = to_remove->parent;
        !           243:                rem_dir = side;
        !           244:        } else if (to_remove->child[LEFT] == NULL) {
        !           245:                /* only righthand child. give it to parent */
        !           246:                if (side == _NONE) {
        !           247:                        tree->root = to_remove->child[RIGHT];
        !           248:                } else {
        !           249:                        to_remove->parent->child[side] = to_remove->child[RIGHT];
        !           250:                }
        !           251:                to_remove->child[RIGHT]->parent = to_remove->parent;
        !           252:                
        !           253:                rem_pos = to_remove->parent;
        !           254:                rem_dir = side;
        !           255:        } else if (to_remove->child[RIGHT] == NULL) {
        !           256:                /* only lefthand child. give it to parent... */
        !           257:                if (side == _NONE) {
        !           258:                        tree->root = to_remove->child[LEFT];
        !           259:                } else {
        !           260:                        to_remove->parent->child[side] = to_remove->child[LEFT];
        !           261:                }
        !           262:                to_remove->child[LEFT]->parent = to_remove->parent;
        !           263:                
        !           264:                rem_pos = to_remove->parent;
        !           265:                rem_dir = side;
        !           266:        } else {
        !           267:                /* 2 children.. more complex. we give the parent the
        !           268:                 * rightmost child of the left child :-) */
        !           269:                iter = to_remove->child[LEFT];
        !           270:                while (iter->child[RIGHT]) {
        !           271:                        iter = iter->child[RIGHT];
        !           272:                }
        !           273:                
        !           274:                /* maybe it has a left child. reparent it if so */
        !           275:                if (iter->child[LEFT]) {
        !           276:                        iter->child[LEFT]->parent = iter->parent;
        !           277:                        iter->parent->child[parent_side (iter)] = iter->child[LEFT];
        !           278:                        iter->child[LEFT] = NULL;
        !           279:                } else {
        !           280:                        iter->parent->child[parent_side (iter)] = NULL;
        !           281:                }
        !           282:                rem_pos = iter->parent;
        !           283:                rem_dir = RIGHT;
        !           284:                if (rem_pos == to_remove) {
        !           285:                        rem_pos = iter;
        !           286:                        rem_dir = LEFT;
        !           287:                }
        !           288:                
        !           289:                switch (parent_side (to_remove)) {
        !           290:                        case _NONE:
        !           291:                                tree->root = iter;
        !           292:                                iter->parent = NULL;
        !           293:                                break;
        !           294:                        case LEFT:
        !           295:                                iter->parent = to_remove->parent;
        !           296:                                iter->parent->child[LEFT] = iter;
        !           297:                                break;
        !           298:                        case RIGHT:
        !           299:                                iter->parent = to_remove->parent;
        !           300:                                iter->parent->child[RIGHT] = iter;
        !           301:                                break;
        !           302:                }
        !           303:                
        !           304:                if ((to_remove->child[LEFT] != NULL) &&
        !           305:                    (to_remove->child[LEFT] != iter)) {
        !           306:                        iter->child[LEFT] = to_remove->child[LEFT];
        !           307:                        iter->child[LEFT]->parent = iter;
        !           308:                } else {
        !           309:                        iter->child[LEFT] = NULL;
        !           310:                }
        !           311:                if ((to_remove->child[RIGHT] != NULL) &&
        !           312:                    (to_remove->child[RIGHT] != iter)) {
        !           313:                        iter->child[RIGHT] = to_remove->child[RIGHT];
        !           314:                        iter->child[RIGHT]->parent = iter;
        !           315:                } else {
        !           316:                        iter->child[RIGHT] = NULL;
        !           317:                }
        !           318:                iter->balance = to_remove->balance;
        !           319:        }
        !           320:        /* Iter should now be parent of [re]moved node.
        !           321:         * we need to recalculate balance */
        !           322:        iter = rem_pos;
        !           323:        assert (iter != to_remove);
        !           324:        /* AVL rotate if required */
        !           325:        /* Go back through parents seeing if some cunt is fucked */
        !           326:        while (iter) {
        !           327:                switch (rem_dir) {
        !           328:                        case LEFT: side = -1; break;
        !           329:                        case RIGHT: side = 1; break;
        !           330:                }
        !           331:                iter->balance -= side;
        !           332:                
        !           333:                /* unbalanced node */
        !           334:                if (abs (iter->balance) >= 2) {
        !           335:                        iter = balance_node (tree, iter);
        !           336:                        if (iter->balance != 0) return;
        !           337:                } else if (abs (iter->balance) == 1) {
        !           338:                        break;
        !           339:                }
        !           340:                rem_dir = parent_side (iter);
        !           341:                iter = iter->parent;
        !           342:        }
        !           343:        free_node (to_remove);
        !           344: }
        !           345: 
        !           346: struct Node *dict_get (struct Dict *tree, const char *key)
        !           347: {
        !           348:        int cmp;
        !           349:        struct Node *parent = NULL;
        !           350:        struct Node *node;
        !           351: 
        !           352:        if (tree->root == NULL) {
        !           353:                return NULL;
        !           354:        }
        !           355: 
        !           356:        node = tree->root;
        !           357:        while (1) {
        !           358:                /* Not found */
        !           359:                if ((parent) && (node == NULL))
        !           360:                        return NULL;
        !           361:                
        !           362:                cmp = strcmp (node->key, key);
        !           363: 
        !           364:                if (cmp < 0) {
        !           365:                        parent = node;
        !           366:                        node = node->child[LEFT];
        !           367:                } else if (cmp > 0) {
        !           368:                        parent = node;
        !           369:                        node = node->child[RIGHT];
        !           370:                } else {
        !           371:                        /* match */
        !           372:                        return node;
        !           373:                }
        !           374:        }
        !           375: 
        !           376: 
        !           377: }
        !           378: 
        !           379: /*
        !           380:  * Returns 1 if key is new, otherwise zero.
        !           381:  */
        !           382: int dict_set (struct Dict *tree, const char *key, void *obj)
        !           383: {
        !           384:        int cmp = 0;
        !           385:        int side;
        !           386:        struct Node *parent = NULL;
        !           387:        struct Node *node;
        !           388: 
        !           389:        if (tree->root == NULL) {
        !           390:                tree->root = alloc_node ();
        !           391:                set_node (tree->root, key, obj);
        !           392:                tree->len++;
        !           393:                return 1;
        !           394:        }
        !           395: 
        !           396:        node = tree->root;
        !           397:        while (1) {
        !           398:                /* Found adding position */
        !           399:                if ((parent) && (node == NULL))
        !           400:                        break;
        !           401:                cmp = strcmp (node->key, key);
        !           402: 
        !           403:                if (cmp < 0) {
        !           404:                        parent = node;
        !           405:                        node = node->child[LEFT];
        !           406:                } else if (cmp > 0) {
        !           407:                        parent = node;
        !           408:                        node = node->child[RIGHT];
        !           409:                } else {
        !           410:                        /* match */
        !           411:                        node->obj = obj;
        !           412:                        return 0;
        !           413:                }
        !           414:        }
        !           415: 
        !           416:        /* add new */
        !           417:        node = alloc_node ();
        !           418:        set_node (node, key, obj);
        !           419:        tree->len++;
        !           420:        if (cmp < 0) {
        !           421:                parent->child[LEFT] = node;
        !           422:        } else {
        !           423:                parent->child[RIGHT] = node;
        !           424:        }
        !           425:        node->parent = parent;
        !           426:        
        !           427:        /* AVL rotate if required */
        !           428:        /* Go back through parents seeing if some cunt is fucked */
        !           429:        while (parent) {
        !           430:                if (parent->child[LEFT] == node) {
        !           431:                        side = -1;
        !           432:                } else {
        !           433:                        side = +1;
        !           434:                }
        !           435:                
        !           436:                parent->balance += side;
        !           437:                
        !           438:                /* unbalanced node */
        !           439:                if (abs (parent->balance) >= 2) {
        !           440:                        parent = balance_node (tree, parent);
        !           441:                        if (parent->balance == 0) return 1;
        !           442:                } else if (parent->balance == 0) {
        !           443:                        break;
        !           444:                }
        !           445:                node = parent;
        !           446:                parent = node->parent;
        !           447:        }
        !           448:        /* nothing unbalanced */
        !           449:        return 1;
        !           450: }
        !           451: 
        !           452: #ifdef DEBUG
        !           453: /*
        !           454:  * Asserts if the tree's balance is fucked in some way.
        !           455:  */
        !           456: static int node_isbalanced (struct Node *node)
        !           457: {
        !           458:        /* heights of trees */
        !           459:        int left = 0;
        !           460:        int right = 0;
        !           461: 
        !           462:        if (node->child[LEFT]) {
        !           463:                left += 1 + abs (node_isbalanced (node->child[LEFT]));
        !           464:        }
        !           465:        if (node->child[RIGHT]) {
        !           466:                right += 1 + abs (node_isbalanced (node->child[RIGHT]));
        !           467:        }
        !           468: 
        !           469:        //printf ("Node '%s' has height %d, balance %d (claims %d)\n", node->key, MAX (left, right), right-left, node->balance);
        !           470:        
        !           471:        assert ((right-left) == node->balance);
        !           472:        assert (abs (right-left) < 2);
        !           473: 
        !           474:        return MAX (left, right);
        !           475: }
        !           476: 
        !           477: #define TEST_SIZE      40
        !           478: 
        !           479: int main (void)
        !           480: {
        !           481:        int i;
        !           482:        int errs;
        !           483:        char buf[20];
        !           484:        char *keys[TEST_SIZE];
        !           485:        void *objs[TEST_SIZE];
        !           486:        struct Dict t;
        !           487:        struct Node *n;
        !           488: 
        !           489:        srand (4);
        !           490:        dict_init (&t);
        !           491: 
        !           492:        for (i=0; i<TEST_SIZE; i++) {
        !           493:                /* Make key */
        !           494:                sprintf(buf, "Node%d:%02d", rand(), i);
        !           495:                keys[i] = (char *) malloc (strlen(buf)+1);
        !           496:                strcpy (keys[i], buf);
        !           497:                /* Data */
        !           498:                objs[i] = (void *) rand();
        !           499:                
        !           500:                dict_set (&t, keys[i], objs[i]);
        !           501:        }
        !           502: 
        !           503:        print_tree (t.root, 0);
        !           504:        node_isbalanced (t.root);
        !           505:        
        !           506:        for (i=0, errs=0; i<TEST_SIZE; i++) {
        !           507:                /* Check if returned keys are correct */
        !           508:                n = dict_get (&t, keys[i]);
        !           509:                if ((n == NULL) || (n->obj != objs[i])) {
        !           510:                        errs++;
        !           511:                }
        !           512:        }
        !           513:        printf ("%d incorrect gets.\n", errs);
        !           514:        
        !           515:        printf ("Removing half the keys...\n");
        !           516:        /* now remove half of them */
        !           517:        for (i=0; i<6*TEST_SIZE/8; i++) {
        !           518:                dict_remove (&t, keys[i]);
        !           519:        }
        !           520:        print_tree (t.root, 0);
        !           521: 
        !           522:        for (i=6*TEST_SIZE/8, errs=0; i<TEST_SIZE; i++) {
        !           523:                /* Check if returned keys are correct */
        !           524:                n = dict_get (&t, keys[i]);
        !           525:                if ((n == NULL) || (n->obj != objs[i])) {
        !           526:                        errs++;
        !           527:                }
        !           528:        }
        !           529:        printf ("%d incorrect gets.\n", errs);
        !           530:        node_isbalanced (t.root);
        !           531:        
        !           532:        dict_free (&t);
        !           533:        
        !           534:        return 0;
        !           535: }
        !           536: #endif /* DEBUG */
        !           537: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.