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