Home | History | Annotate | Download | only in Framework
      1 //
      2 //  ACBTree.m
      3 //  ST4
      4 //
      5 //  Created by Alan Condit on 4/18/11.
      6 //  Copyright 2011 Alan Condit. All rights reserved.
      7 //
      8 
      9 #import <Cocoa/Cocoa.h>
     10 #import "ACBTree.h"
     11 #import "AMutableDictionary.h"
     12 #import "ANTLRRuntimeException.h"
     13 
     14 @class AMutableDictionary;
     15 
     16 @implementation ACBKey
     17 
     18 static NSInteger RECNUM = 0;
     19 
     20 @synthesize recnum;
     21 @synthesize key;
     22 
     23 + (ACBKey *)newKey
     24 {
     25     return [[ACBKey alloc] init];
     26 }
     27 
     28 + (ACBKey *)newKeyWithKStr:(NSString *)aKey
     29 {
     30     return [[ACBKey alloc] initWithKStr:(NSString *)aKey];
     31 }
     32 
     33 - (id) init
     34 {
     35     self =[super init];
     36     if ( self != nil ) {
     37         recnum = RECNUM++;
     38     }
     39     return self;
     40 }
     41 
     42 - (id) initWithKStr:(NSString *)aKey
     43 {
     44     self =[super init];
     45     if ( self != nil ) {
     46         NSInteger len;
     47         recnum = RECNUM++;
     48         key = aKey;
     49         len = [aKey length];
     50         if ( len >= BTKeySize ) {
     51             len = BTKeySize - 1;
     52         }
     53         strncpy( kstr, [aKey cStringUsingEncoding:NSASCIIStringEncoding], len);
     54         kstr[len] = '\0';
     55     }
     56     return self;
     57 }
     58 
     59 @end
     60 
     61 @implementation ACBTree
     62 
     63 @synthesize dict;
     64 @synthesize lnode;
     65 @synthesize rnode;
     66 @synthesize keys;
     67 @synthesize btNodes;
     68 @synthesize lnodeid;
     69 @synthesize rnodeid;
     70 @synthesize nodeid;
     71 @synthesize nodeType;
     72 @synthesize numkeys;
     73 @synthesize numrecs;
     74 @synthesize updtd;
     75 @synthesize keylen;
     76 @synthesize kidx;
     77 
     78 + (ACBTree *) newNodeWithDictionary:(AMutableDictionary *)theDict
     79 {
     80     return [[ACBTree alloc] initWithDictionary:theDict];
     81 }
     82 
     83 - (id)initWithDictionary:(AMutableDictionary *)theDict
     84 {
     85     self = [super init];
     86     if (self) {
     87         // Initialization code here.
     88         dict = theDict;
     89         nodeid = theDict.nxt_nodeid++;
     90         keys = keyArray;
     91         btNodes = btNodeArray;
     92         if ( nodeid == 0 ) {
     93             numkeys = 0;
     94         }
     95     }
     96     
     97     return self;
     98 }
     99 
    100 - (ACBTree *)createnode:(ACBKey *)kp
    101 {
    102     ACBTree *tmp;
    103     
    104     tmp = [ACBTree newNodeWithDictionary:dict];
    105     tmp.nodeType = nodeType;
    106     tmp.lnode = self;
    107     tmp.rnode = self.rnode;
    108     self.rnode = tmp;
    109     //tmp.btNodes[0] = self;
    110     //tmp.keys[0] = kp;
    111     tmp.updtd = YES;
    112     tmp.numrecs = ((nodeType == LEAF)?1:numrecs);
    113     updtd = YES;
    114     tmp.numkeys = 1;
    115     [tmp retain];
    116     return(tmp);
    117 }
    118 
    119 - (ACBTree *)deletekey:(NSString *)dkey
    120 {
    121     ACBKey /* *del, */ *dkp;
    122     ACBTree *told, *sNode;
    123     BOOL mustRelease = NO;
    124 
    125     if ( [dkey isKindOfClass:[NSString class]] ) {
    126         dkp = [ACBKey newKeyWithKStr:dkey];
    127         mustRelease = YES;
    128     }
    129     else if ( [dkey isKindOfClass:[ACBKey class]] )
    130         dkp = (ACBKey *)dkey;
    131     else
    132         @throw [ANTLRIllegalArgumentException newException:[NSString stringWithFormat:@"Don't understand this key:\"%@\"", dkey]];
    133     sNode = [self search:dkp.key];
    134     if ( sNode == nil || [sNode searchnode:dkp.key match:YES] == FAILURE ) {
    135         if ( mustRelease ) [dkp release];
    136         return(self);
    137     }
    138     told = dict.root;
    139     /* del = */[self internaldelete:dkp];
    140     
    141     /*  check for shrink at the root  */
    142     if ( numkeys == 1 && nodeType != LEAF ) {
    143         told = btNodes[0];
    144         told.nodeid = 1;
    145         told.updtd = YES;
    146         dict.root = told;
    147     }
    148 #ifdef DONTUSENOMO
    149     if (debug == 'd') [self printtree];
    150 #endif
    151     if ( mustRelease ) [dkp release];
    152     return(told);
    153 }
    154 
    155 /** insertKey is the insertion entry point
    156  *  It determines if the key exists in the tree already
    157  *  it calls internalInsert to determine if the key already exists in the tree,
    158  *  and returns the node to be updated
    159  */
    160 - (ACBTree *)insertkey:(ACBKey *)kp value:(id)value
    161 {
    162     ACBTree *tnew, *q;
    163     NSInteger h, nodeNum;
    164     
    165     tnew = self;
    166     q = [self internalinsert:kp value:value split:&h];
    167     /*  check for growth at the root  */
    168     if ( q != nil ) {
    169         tnew = [[ACBTree newNodeWithDictionary:dict] retain];
    170         tnew.nodeType = BTNODE;
    171         nodeNum = tnew.nodeid;
    172         tnew.nodeid = 0;
    173         self.nodeid = nodeNum;
    174         [tnew insert:self.keys[numkeys-1] value:self index:0 split:&h];
    175         [tnew insert:q.keys[q.numkeys-1] value:q index:1 split:&h];
    176         tnew.numrecs = self.numrecs + q.numrecs;
    177         tnew.lnodeid = self.nodeid;
    178         tnew.rnodeid = self.rnodeid;
    179         self.rnodeid = tnew.nodeid;
    180         tnew.lnode = self;
    181         tnew.rnode = self.rnode;
    182         self.rnode = tnew;
    183         /* affected by nodeid swap */
    184         // newnode.lnodeid = tnew.btNodes[0].nodeid;
    185     }
    186     //dict.root = t;
    187     //l.reccnt++;
    188     return(tnew);
    189 }
    190 
    191 - (ACBTree *)search:(NSString *)kstr
    192 {
    193     NSInteger i, ret;
    194     NSInteger srchlvl = 0;
    195     ACBTree *t;
    196 
    197     t = self;
    198     if ( self.numkeys == 0 && self.nodeType == LEAF )
    199         return nil;
    200     while (t != nil) {
    201         for (i = 0; i < t.numkeys; i++) {
    202             ret = [t.keys[i].key compare:kstr];
    203             if ( ret >= 0 ) {
    204                 if ( t.nodeType == LEAF ) {
    205                     if ( ret == 0 ) return (t);    /* node containing keyentry found */
    206                     else return nil;
    207                 }
    208                 else {
    209                     break;
    210                 }
    211             }
    212         }
    213         srchlvl++;
    214         if ( t.nodeType == BTNODE ) t = t.btNodes[i];
    215         else {
    216             t = nil;
    217         }
    218     }
    219     return(nil);          /* entry not found */
    220 }
    221 
    222 /** SEARCHNODE
    223  *  calling parameters --
    224  *      BKEY PTR for key to search for.
    225  *      TYPE for exact match(YES) or position(NO)
    226  *  returns -- i
    227  *      i == FAILURE when match required but does not exist.
    228  *      i == t.numkeys if no existing insertion branch found.
    229  *      otherwise i == insertion branch.
    230  */
    231 - (NSInteger)searchnode:(NSString *)kstr match:(BOOL)match
    232 {
    233     NSInteger i, ret;
    234     for ( i = 0; i < numkeys; i++ ) {
    235         ret = [keys[i].key compare:kstr];
    236         if ( ret >= 0 ) {         /* key node found */
    237             if ( ret == 0 && match == NO ) {
    238                 return FAILURE;
    239             }
    240             else if ( ret > 0 &&  match == YES ) {
    241                 return FAILURE;
    242             }
    243             break;
    244         }
    245     }
    246     if ( i == numkeys && match == YES ) {
    247         i = FAILURE;
    248     }
    249     return(i);
    250 }
    251 
    252 - (ACBKey *)internaldelete:(ACBKey *)dkp
    253 {
    254     NSInteger i, nkey;
    255     __strong ACBKey *del = nil;
    256     ACBTree *tsb;
    257     NSInteger srchlvl = 0;
    258     
    259     /* find deletion branch */
    260     if ( self.nodeType != LEAF ) {
    261         srchlvl++;
    262         /* search for end of tree */
    263         i = [self searchnode:dkp.key match:NO];
    264         del = [btNodes[i] internaldelete:dkp];
    265         srchlvl--;
    266         /* if not LEAF propagate back high key    */
    267         tsb = btNodes[i];
    268         nkey = tsb.numkeys - 1;
    269     }
    270     /***  the bottom of the tree has been reached       ***/
    271     else {                   /* set up deletion ptrs      */
    272         if ( [self delfrmnode:dkp] == SUCCESS ) {
    273             if ( numkeys < BTHNODESIZE+1 ) {
    274                 del = dkp;
    275             }
    276             else {
    277                 del = nil;
    278             }
    279             dkp.recnum = nodeid;
    280             return(del);
    281         }
    282     }
    283     /***       indicate deletion to be done            ***/
    284     if ( del != nil ) {
    285         /*** the key in "del" has to be deleted from in present node ***/
    286         if ( btNodes[i].numkeys >= BTHNODESIZE+1 ) {
    287             /* node does not need balancing */
    288             del = nil;
    289             self.keys[i] = tsb.keys[nkey];
    290         }
    291         else {                         /* node requires balancing */
    292             if ( i == 0 ) {
    293                 [self rotateright:0];
    294                 self.btNodes[0] = tsb;
    295             } else if ( i < numkeys-1 ) {     /* look to the right first */
    296                 if ( self.btNodes[i+1].numkeys > BTHNODESIZE+1 ) {  /* carry from right */
    297                     [self borrowright:i];
    298                 }
    299                 else {           /* merge present node with right node */
    300                     [self mergenode:i];
    301                 }
    302             }
    303             else {                      /* look to the left */
    304                 if ( i > 0 ) {          /* carry or merge with left node */
    305                     if ( self.btNodes[i-1].numkeys > BTHNODESIZE+1 ) { /* carry from left */
    306                         [self borrowleft:i];
    307                     }
    308                     else { /*** merge present node with left node ***/
    309                         i--;
    310                         [self mergenode:i];
    311                         tsb = self.btNodes[i];
    312                     }
    313                 }
    314             }
    315         self.keys[i] = tsb.keys[nkey];
    316         }
    317     }
    318     numrecs--;
    319     updtd = TRUE;
    320     return(del);
    321 }
    322 
    323 /** Search key kp on B-tree with root t; if found increment counter.
    324  *  otherwise insert an item with key kp in tree.  If an ACBKey
    325  *  emerges to be passed to a lower level, then assign it to kp;
    326  *  h = "tree t has become higher"
    327  */
    328 - (ACBTree *) internalinsert:(ACBKey *)kp value:(id)value split:(NSInteger *)h
    329 {
    330     /* search key ins on node t^; h = false  */
    331     NSInteger i, ret;
    332     ACBTree *q, *tmp;
    333     
    334     for (i = 0; i < numkeys; i++) {
    335         ret = [keys[i].key compare:kp.key];
    336         if ( ret >= 0 ) {
    337             if ( nodeType == LEAF && ret == 0 ) return (self);    /* node containing keyentry found */
    338             break;
    339         }
    340     }
    341     if ( nodeType == LEAF ) { /*  key goes in this node  */
    342         q = [self insert:kp value:value index:i split:h];
    343     }
    344     else  { /* nodeType == BTNODE */
    345         /*  key is not on this node  */
    346         q = [self.btNodes[i] internalinsert:kp value:value split:h];
    347         if ( *h ) {
    348             [self insert:kp value:q index:i split:h];
    349         }
    350         else {
    351             self.numrecs++;
    352         }
    353         tmp = self.btNodes[numkeys-1];
    354         keys[numkeys-1] = tmp.keys[tmp.numkeys-1];
    355         if ( i != numkeys-1 ) {
    356             tmp = self.btNodes[i];
    357             keys[i] = tmp.keys[tmp.numkeys-1];
    358         }
    359         updtd = YES;
    360     } /* search */
    361     return q;
    362 }
    363 
    364 /** Do the actual insertion or split and insert
    365  *  insert key to the right of t.keys[hi] 
    366  */
    367 - (ACBTree *) insert:(ACBKey *)kp value:(id)value index:(NSInteger)hi split:(NSInteger *)h
    368 {
    369     ACBTree *b;
    370     
    371     if ( numkeys < BTNODESIZE ) {
    372         *h = NO;
    373         [self rotateright:hi];
    374         keys[hi] = kp;
    375         btNodes[hi] = value;
    376         numrecs++;
    377         numkeys++;
    378         updtd = YES;
    379         //[kp retain];
    380         return nil;
    381     }
    382     else { /*  node t is full; split it and assign the emerging ACBKey to olditem  */
    383         b = [self splitnode:hi];
    384         if ( hi <= BTHNODESIZE ) {              /* insert key in left page */
    385             [self rotateright:hi];
    386             keys[hi] = kp;
    387             btNodes[hi] = value;
    388             numrecs++;
    389             numkeys++;
    390         }
    391         else {                                  /* insert key in right page */
    392             hi -= BTHNODESIZE;
    393             if ( b.rnode == nil ) hi--;
    394             [b rotateright:hi];
    395             b.keys[hi] = kp;
    396             b.btNodes[hi] = value;
    397             b.numrecs++;
    398             b.numkeys++;
    399         }
    400         numkeys = b.numkeys = BTHNODESIZE+1;
    401         b.updtd = updtd = YES;
    402     }
    403     return b;
    404 } /* insert */
    405 
    406 - (void)borrowleft:(NSInteger)i
    407 {
    408     ACBTree *t0, *t1;
    409     NSInteger nkey;
    410     
    411     t0 = btNodes[i];
    412     t1 = btNodes[i-1];
    413     nkey = t1.numkeys-1;
    414     [t0 insinnode:t1.keys[nkey] value:t1.btNodes[nkey]];
    415     [t1 delfrmnode:t1.keys[nkey]];
    416     nkey--;
    417     keys[i-1] = t1.keys[nkey];
    418     keys[i-1].recnum = t1.nodeid;
    419 }
    420 
    421 - (void)borrowright:(NSInteger)i
    422 {
    423     ACBTree *t0, *t1;
    424     NSInteger nkey;
    425     
    426     t0 = btNodes[i];
    427     t1 = btNodes[i+1];
    428     [t0 insinnode:t1.keys[0] value:t1.btNodes[0]];
    429     [t1 delfrmnode:t1.keys[0]];
    430     nkey = t0.numkeys - 1;
    431     keys[i] = t0.keys[nkey];
    432     keys[i].recnum = t0.nodeid;
    433 }
    434 
    435 - (NSInteger)delfrmnode:(ACBKey *)ikp
    436 {
    437     NSInteger j;
    438     
    439     j = [self searchnode:ikp.key match:YES];
    440     if (j == FAILURE) {
    441         return(FAILURE);
    442     }
    443     ACBKey *k0 = nil;
    444     ACBTree *n0 = nil;
    445     if ( self.nodeType == LEAF ) {
    446         k0 = self.keys[j];
    447         n0 = self.btNodes[j];
    448     }
    449     [self rotateleft:j];
    450     self.numkeys--;
    451     numrecs -= ((self.nodeType == LEAF)?1:btNodes[j].numrecs);
    452     if ( k0 ) [k0 release];
    453     if ( n0 ) [n0 release];
    454     updtd = TRUE;
    455     return(SUCCESS);
    456 }
    457 
    458 - (NSInteger)insinnode:(ACBKey *)ikp value:(id)value
    459 {
    460     NSInteger j;
    461     
    462     j = [self searchnode:ikp.key match:NO];
    463     [self rotateright:j];
    464     keys[j] = ikp;
    465     btNodes[j] = value;
    466     numkeys++;
    467     if ( nodeType == LEAF ) {
    468         numrecs++;
    469     }
    470     else {
    471         numrecs += btNodes[j].numrecs;
    472     }
    473     updtd = TRUE;
    474     return(j);
    475 }
    476 
    477 - (void)mergenode:(NSInteger)i
    478 {
    479     ACBTree *t0, *t1, *tr;
    480     NSInteger j, k, nkeys;
    481     
    482     t0 = btNodes[i];
    483     t1 = btNodes[i+1];
    484     /*** move keys and pointers from
    485      t1 node to t0 node           ***/
    486     for (j=t0.numkeys, k=0; j < BTNODESIZE && k < t1.numkeys; j++, k++) {
    487         t0.keys[j] = t1.keys[k];
    488         t0.btNodes[j] = t1.btNodes[k];
    489         t0.numkeys++;
    490     }
    491     t0.numrecs += t1.numrecs;
    492     t0.rnode = t1.rnode;
    493     t0.rnodeid = t1.rnodeid;
    494     t0.updtd = YES;
    495     nkeys = t0.numkeys - 1;
    496     keys[i] = t0.keys[nkeys]; /* update key to point to new high key */
    497     [self rotateleft:i+1]; /* copy over the keys and nodes */
    498     
    499     t1.nodeType = -1;
    500     if (t1.rnodeid != 0xffff && i < numkeys - 2) {
    501         tr = btNodes[i+1];
    502         tr.lnodeid = t0.nodeid;
    503         tr.lnode = t0;
    504         tr.updtd = YES;
    505     }
    506     self.numkeys--;
    507     updtd = YES;
    508 }
    509 
    510 - (ACBTree *)splitnode:(NSInteger)idx
    511 {
    512     ACBTree *t1;
    513     NSInteger j, k;
    514     
    515     k = (idx <= BTHNODESIZE) ? BTHNODESIZE : BTHNODESIZE+1;
    516     /*** create new node ***/
    517     // checknode(l, t, k);
    518     t1 = [ACBTree newNodeWithDictionary:dict];
    519     t1.nodeType = nodeType;
    520     t1.rnode = self.rnode;
    521     self.rnode = t1;
    522     t1.lnode = self;
    523     self.updtd = t1.updtd = YES;
    524     /*** move keys and pointers ***/
    525     NSInteger i = 0;
    526     for (j = k; j < BTNODESIZE; j++, i++ ) {
    527         t1.keys[i] = keys[j];
    528         t1.btNodes[i] = btNodes[j];
    529         t1.numrecs += ((nodeType == LEAF) ? 1 : btNodes[j].numrecs);
    530         numrecs     -= ((nodeType == LEAF) ? 1 : btNodes[j].numrecs);
    531         keys[j] = nil;
    532         btNodes[j] = nil;
    533     }
    534     t1.numkeys  = BTNODESIZE-k;
    535     self.numkeys = k;
    536     return(t1);
    537 }
    538 
    539 #ifdef DONTUSENOMO
    540 freetree(l, t)
    541 FIDB *l;
    542 ACBTree *t;
    543 {
    544     ACBTree *tmp;
    545     NSInteger i;
    546     
    547     if (dict.root == nil) return(SUCCESS);
    548     if (t.nodeid == 1) {
    549         srchlvl = 0;
    550     }
    551     else srchlvl++;
    552     for (i = 0; i < t.numkeys; i++) {
    553         tmp = t.btNodes[i];
    554         if (tmp != nil) {
    555             if (tmp.nodeType == LEAF) {
    556                 free(tmp);    /* free the leaf */
    557                 if (tmp == l.rrnode) {
    558                     l.rrnode = nil;
    559                 }
    560                 t.btNodes[i] = nil;
    561                 l.chknode.nods_inuse--;
    562                 /*              putpage(l, l.chknode, 0);
    563                  */
    564             }
    565             else {
    566                 freetree(l, tmp); /* continue up the tree */
    567                 srchlvl--;        /* decrement the srchlvl on return */
    568             }
    569         }
    570     }
    571     free(t); /* free the node entered with */
    572     if (t == l.rrnode) {
    573         l.rrnode = nil;
    574     }
    575     l.chknode.nods_inuse--;
    576     /*     putpage(l, l.chknode, 0);
    577      */
    578     t = nil;
    579 }
    580 
    581 - (void) notfound:(ACBKey *)kp
    582 {
    583     /* error routine to perform if entry was expected and not found */
    584 }
    585 
    586 - (void)printtree:(ACBTree *)t
    587 {
    588     BYTE *str;
    589     NSInteger i, j;
    590     NSUInteger *pdate, *ptime;
    591     
    592     syslst = stdprn;
    593     if ( t.nodeid == 1 ) {
    594         srchlvl = 0;
    595     }
    596     else srchlvl++;
    597     for (j = 0; j < t.numkeys; j++) {
    598         checknode(l, t, j);
    599         if ( t.btNodes[j] != nil ) [self printtree:t.btNodes[j]];
    600     }
    601     NSLog(@"Nodeid = %d, nodeType = %s, numkeys = %d, numrecs = %d\n",
    602           t.nodeid, (t.nodeType == BTNODE)?@"NODE":@"LEAF", t.numkeys, t.numrecs);
    603     NSLog(@"Left nodeid = %d, Right nodeid = %d\n", t.lnodeid, t.rnodeid);
    604     for (i = 0; i < t.numkeys; i++) {
    605         NSLog(@"     t.keys[%d] recnum = %d, keyval = %@",
    606               i, t.keys[i].recnum, t.keys[i]);
    607         str = t.keys[i].kstr;
    608         pdate = (NSUInteger *) (str + 6);
    609         ptime = (NSUInteger *) (str + 8);
    610         NSLog(@" date = %04.4x,  time = %04.4x\n",
    611               *pdate, *ptime);
    612     }
    613 }
    614 
    615 - (BOOL)puttree:(ACBTree *)t
    616 {
    617     NSInteger i;
    618     if (t.nodeType != LEAF) {
    619         for (i = 0; i < t.numkeys; i++) {
    620             if ( t.btNodes[i] != nil ) puttree(l, t.btNodes[i]);
    621         }
    622     }
    623     if ( t.updtd ) {
    624         putnode(l, t, t.nodeid);
    625         return(YES);
    626     }
    627     return(NO);
    628 }
    629 
    630 #endif
    631 
    632 /** ROTATELEFT -- rotate keys from right to the left
    633  *  starting at position j
    634  */
    635 - (void)rotateleft:(NSInteger)j
    636 {
    637     while ( j+1 < numkeys ) {
    638         keys[j] = keys[j+1];
    639         btNodes[j] = btNodes[j+1];
    640         j++;
    641     }
    642 }
    643 
    644 /** ROTATERIGHT -- rotate keys to the right by 1 position
    645  *  starting at the last key down to position j.
    646  */
    647 - (void)rotateright:(NSInteger)j
    648 {
    649     NSInteger k;
    650     
    651     for ( k = numkeys; k > j; k-- ) {
    652         keys[k] = keys[k-1];
    653         btNodes[k] = btNodes[k-1];
    654     }
    655     keys[j] = nil;
    656     btNodes[j] = nil;
    657 }
    658 
    659 - (NSInteger) keyWalkLeaves
    660 {
    661     NSInteger i, idx = 0;
    662     NSInteger keycnt;
    663     ACBTree *t;
    664 
    665     if ( self != dict.root ) {
    666         return 0; // maybe I need to throw an exception here
    667     }
    668     t = self;
    669     self.dict.data = [[NSMutableData dataWithLength:(numkeys * sizeof(id))] retain];
    670     self.dict.ptrBuffer = [self.dict.data mutableBytes];
    671     while ( t != nil && t.nodeType != LEAF ) {
    672         t = t.btNodes[0];
    673     }
    674     do {
    675         keycnt = t.numkeys;
    676         for ( i = 0; i < keycnt; i++ ) {
    677             if ( t.btNodes[i] != nil ) {
    678                 dict.ptrBuffer[idx++] = (id) t.keys[i].key;
    679             }
    680         }
    681         t = t.rnode;
    682     } while ( t != nil );
    683     return( idx );
    684 }
    685 
    686 - (NSInteger) objectWalkLeaves
    687 {
    688     NSInteger i, idx = 0;
    689     NSInteger keycnt;
    690     ACBTree *t;
    691     
    692     if ( self != dict.root ) {
    693         return 0; // maybe I need to throw an exception here
    694     }
    695     t = self;
    696     self.dict.data = [[NSMutableData dataWithLength:(numrecs * sizeof(id))] retain];
    697     self.dict.ptrBuffer = [self.dict.data mutableBytes];
    698     while ( t != nil && t.nodeType != LEAF ) {
    699         t = t.btNodes[0];
    700     }
    701     do {
    702         keycnt = t.numkeys;
    703         for ( i = 0; i < keycnt; i++ ) {
    704             if ( t.btNodes[i] != nil ) {
    705                 dict.ptrBuffer[idx++] = (id) t.btNodes[i];
    706             }
    707         }
    708         t = t.rnode;
    709     } while ( t != nil );
    710     return( idx );
    711 }
    712 
    713 - (void)dealloc
    714 {
    715 #ifdef DEBUG_DEALLOC
    716     NSLog( @"called dealloc in ACBTree" );
    717 #endif
    718     [super dealloc];
    719 }
    720 
    721 @end
    722