/projects/antlr-3.4/runtime/ObjC/Framework/ACBTree.m
Objective C | 721 lines | 597 code | 60 blank | 64 comment | 168 complexity | b18aaf8e1d6913759468490a9f80d5d1 MD5 | raw file
- //
- // ACBTree.m
- // ST4
- //
- // Created by Alan Condit on 4/18/11.
- // Copyright 2011 Alan Condit. All rights reserved.
- //
- #import <Cocoa/Cocoa.h>
- #import "ACBTree.h"
- #import "AMutableDictionary.h"
- #import "ANTLRRuntimeException.h"
- @class AMutableDictionary;
- @implementation ACBKey
- static NSInteger RECNUM = 0;
- @synthesize recnum;
- @synthesize key;
- + (ACBKey *)newKey
- {
- return [[ACBKey alloc] init];
- }
- + (ACBKey *)newKeyWithKStr:(NSString *)aKey
- {
- return [[ACBKey alloc] initWithKStr:(NSString *)aKey];
- }
- - (id) init
- {
- self =[super init];
- if ( self != nil ) {
- recnum = RECNUM++;
- }
- return self;
- }
- - (id) initWithKStr:(NSString *)aKey
- {
- self =[super init];
- if ( self != nil ) {
- NSInteger len;
- recnum = RECNUM++;
- key = aKey;
- len = [aKey length];
- if ( len >= BTKeySize ) {
- len = BTKeySize - 1;
- }
- strncpy( kstr, [aKey cStringUsingEncoding:NSASCIIStringEncoding], len);
- kstr[len] = '\0';
- }
- return self;
- }
- @end
- @implementation ACBTree
- @synthesize dict;
- @synthesize lnode;
- @synthesize rnode;
- @synthesize keys;
- @synthesize btNodes;
- @synthesize lnodeid;
- @synthesize rnodeid;
- @synthesize nodeid;
- @synthesize nodeType;
- @synthesize numkeys;
- @synthesize numrecs;
- @synthesize updtd;
- @synthesize keylen;
- @synthesize kidx;
- + (ACBTree *) newNodeWithDictionary:(AMutableDictionary *)theDict
- {
- return [[ACBTree alloc] initWithDictionary:theDict];
- }
- - (id)initWithDictionary:(AMutableDictionary *)theDict
- {
- self = [super init];
- if (self) {
- // Initialization code here.
- dict = theDict;
- nodeid = theDict.nxt_nodeid++;
- keys = keyArray;
- btNodes = btNodeArray;
- if ( nodeid == 0 ) {
- numkeys = 0;
- }
- }
-
- return self;
- }
- - (ACBTree *)createnode:(ACBKey *)kp
- {
- ACBTree *tmp;
-
- tmp = [ACBTree newNodeWithDictionary:dict];
- tmp.nodeType = nodeType;
- tmp.lnode = self;
- tmp.rnode = self.rnode;
- self.rnode = tmp;
- //tmp.btNodes[0] = self;
- //tmp.keys[0] = kp;
- tmp.updtd = YES;
- tmp.numrecs = ((nodeType == LEAF)?1:numrecs);
- updtd = YES;
- tmp.numkeys = 1;
- [tmp retain];
- return(tmp);
- }
- - (ACBTree *)deletekey:(NSString *)dkey
- {
- ACBKey /* *del, */ *dkp;
- ACBTree *told, *sNode;
- BOOL mustRelease = NO;
- if ( [dkey isKindOfClass:[NSString class]] ) {
- dkp = [ACBKey newKeyWithKStr:dkey];
- mustRelease = YES;
- }
- else if ( [dkey isKindOfClass:[ACBKey class]] )
- dkp = (ACBKey *)dkey;
- else
- @throw [ANTLRIllegalArgumentException newException:[NSString stringWithFormat:@"Don't understand this key:\"%@\"", dkey]];
- sNode = [self search:dkp.key];
- if ( sNode == nil || [sNode searchnode:dkp.key match:YES] == FAILURE ) {
- if ( mustRelease ) [dkp release];
- return(self);
- }
- told = dict.root;
- /* del = */[self internaldelete:dkp];
-
- /* check for shrink at the root */
- if ( numkeys == 1 && nodeType != LEAF ) {
- told = btNodes[0];
- told.nodeid = 1;
- told.updtd = YES;
- dict.root = told;
- }
- #ifdef DONTUSENOMO
- if (debug == 'd') [self printtree];
- #endif
- if ( mustRelease ) [dkp release];
- return(told);
- }
- /** insertKey is the insertion entry point
- * It determines if the key exists in the tree already
- * it calls internalInsert to determine if the key already exists in the tree,
- * and returns the node to be updated
- */
- - (ACBTree *)insertkey:(ACBKey *)kp value:(id)value
- {
- ACBTree *tnew, *q;
- NSInteger h, nodeNum;
-
- tnew = self;
- q = [self internalinsert:kp value:value split:&h];
- /* check for growth at the root */
- if ( q != nil ) {
- tnew = [[ACBTree newNodeWithDictionary:dict] retain];
- tnew.nodeType = BTNODE;
- nodeNum = tnew.nodeid;
- tnew.nodeid = 0;
- self.nodeid = nodeNum;
- [tnew insert:self.keys[numkeys-1] value:self index:0 split:&h];
- [tnew insert:q.keys[q.numkeys-1] value:q index:1 split:&h];
- tnew.numrecs = self.numrecs + q.numrecs;
- tnew.lnodeid = self.nodeid;
- tnew.rnodeid = self.rnodeid;
- self.rnodeid = tnew.nodeid;
- tnew.lnode = self;
- tnew.rnode = self.rnode;
- self.rnode = tnew;
- /* affected by nodeid swap */
- // newnode.lnodeid = tnew.btNodes[0].nodeid;
- }
- //dict.root = t;
- //l.reccnt++;
- return(tnew);
- }
- - (ACBTree *)search:(NSString *)kstr
- {
- NSInteger i, ret;
- NSInteger srchlvl = 0;
- ACBTree *t;
- t = self;
- if ( self.numkeys == 0 && self.nodeType == LEAF )
- return nil;
- while (t != nil) {
- for (i = 0; i < t.numkeys; i++) {
- ret = [t.keys[i].key compare:kstr];
- if ( ret >= 0 ) {
- if ( t.nodeType == LEAF ) {
- if ( ret == 0 ) return (t); /* node containing keyentry found */
- else return nil;
- }
- else {
- break;
- }
- }
- }
- srchlvl++;
- if ( t.nodeType == BTNODE ) t = t.btNodes[i];
- else {
- t = nil;
- }
- }
- return(nil); /* entry not found */
- }
- /** SEARCHNODE
- * calling parameters --
- * BKEY PTR for key to search for.
- * TYPE for exact match(YES) or position(NO)
- * returns -- i
- * i == FAILURE when match required but does not exist.
- * i == t.numkeys if no existing insertion branch found.
- * otherwise i == insertion branch.
- */
- - (NSInteger)searchnode:(NSString *)kstr match:(BOOL)match
- {
- NSInteger i, ret;
- for ( i = 0; i < numkeys; i++ ) {
- ret = [keys[i].key compare:kstr];
- if ( ret >= 0 ) { /* key node found */
- if ( ret == 0 && match == NO ) {
- return FAILURE;
- }
- else if ( ret > 0 && match == YES ) {
- return FAILURE;
- }
- break;
- }
- }
- if ( i == numkeys && match == YES ) {
- i = FAILURE;
- }
- return(i);
- }
- - (ACBKey *)internaldelete:(ACBKey *)dkp
- {
- NSInteger i, nkey;
- __strong ACBKey *del = nil;
- ACBTree *tsb;
- NSInteger srchlvl = 0;
-
- /* find deletion branch */
- if ( self.nodeType != LEAF ) {
- srchlvl++;
- /* search for end of tree */
- i = [self searchnode:dkp.key match:NO];
- del = [btNodes[i] internaldelete:dkp];
- srchlvl--;
- /* if not LEAF propagate back high key */
- tsb = btNodes[i];
- nkey = tsb.numkeys - 1;
- }
- /*** the bottom of the tree has been reached ***/
- else { /* set up deletion ptrs */
- if ( [self delfrmnode:dkp] == SUCCESS ) {
- if ( numkeys < BTHNODESIZE+1 ) {
- del = dkp;
- }
- else {
- del = nil;
- }
- dkp.recnum = nodeid;
- return(del);
- }
- }
- /*** indicate deletion to be done ***/
- if ( del != nil ) {
- /*** the key in "del" has to be deleted from in present node ***/
- if ( btNodes[i].numkeys >= BTHNODESIZE+1 ) {
- /* node does not need balancing */
- del = nil;
- self.keys[i] = tsb.keys[nkey];
- }
- else { /* node requires balancing */
- if ( i == 0 ) {
- [self rotateright:0];
- self.btNodes[0] = tsb;
- } else if ( i < numkeys-1 ) { /* look to the right first */
- if ( self.btNodes[i+1].numkeys > BTHNODESIZE+1 ) { /* carry from right */
- [self borrowright:i];
- }
- else { /* merge present node with right node */
- [self mergenode:i];
- }
- }
- else { /* look to the left */
- if ( i > 0 ) { /* carry or merge with left node */
- if ( self.btNodes[i-1].numkeys > BTHNODESIZE+1 ) { /* carry from left */
- [self borrowleft:i];
- }
- else { /*** merge present node with left node ***/
- i--;
- [self mergenode:i];
- tsb = self.btNodes[i];
- }
- }
- }
- self.keys[i] = tsb.keys[nkey];
- }
- }
- numrecs--;
- updtd = TRUE;
- return(del);
- }
- /** Search key kp on B-tree with root t; if found increment counter.
- * otherwise insert an item with key kp in tree. If an ACBKey
- * emerges to be passed to a lower level, then assign it to kp;
- * h = "tree t has become higher"
- */
- - (ACBTree *) internalinsert:(ACBKey *)kp value:(id)value split:(NSInteger *)h
- {
- /* search key ins on node t^; h = false */
- NSInteger i, ret;
- ACBTree *q, *tmp;
-
- for (i = 0; i < numkeys; i++) {
- ret = [keys[i].key compare:kp.key];
- if ( ret >= 0 ) {
- if ( nodeType == LEAF && ret == 0 ) return (self); /* node containing keyentry found */
- break;
- }
- }
- if ( nodeType == LEAF ) { /* key goes in this node */
- q = [self insert:kp value:value index:i split:h];
- }
- else { /* nodeType == BTNODE */
- /* key is not on this node */
- q = [self.btNodes[i] internalinsert:kp value:value split:h];
- if ( *h ) {
- [self insert:kp value:q index:i split:h];
- }
- else {
- self.numrecs++;
- }
- tmp = self.btNodes[numkeys-1];
- keys[numkeys-1] = tmp.keys[tmp.numkeys-1];
- if ( i != numkeys-1 ) {
- tmp = self.btNodes[i];
- keys[i] = tmp.keys[tmp.numkeys-1];
- }
- updtd = YES;
- } /* search */
- return q;
- }
- /** Do the actual insertion or split and insert
- * insert key to the right of t.keys[hi]
- */
- - (ACBTree *) insert:(ACBKey *)kp value:(id)value index:(NSInteger)hi split:(NSInteger *)h
- {
- ACBTree *b;
-
- if ( numkeys < BTNODESIZE ) {
- *h = NO;
- [self rotateright:hi];
- keys[hi] = kp;
- btNodes[hi] = value;
- numrecs++;
- numkeys++;
- updtd = YES;
- //[kp retain];
- return nil;
- }
- else { /* node t is full; split it and assign the emerging ACBKey to olditem */
- b = [self splitnode:hi];
- if ( hi <= BTHNODESIZE ) { /* insert key in left page */
- [self rotateright:hi];
- keys[hi] = kp;
- btNodes[hi] = value;
- numrecs++;
- numkeys++;
- }
- else { /* insert key in right page */
- hi -= BTHNODESIZE;
- if ( b.rnode == nil ) hi--;
- [b rotateright:hi];
- b.keys[hi] = kp;
- b.btNodes[hi] = value;
- b.numrecs++;
- b.numkeys++;
- }
- numkeys = b.numkeys = BTHNODESIZE+1;
- b.updtd = updtd = YES;
- }
- return b;
- } /* insert */
- - (void)borrowleft:(NSInteger)i
- {
- ACBTree *t0, *t1;
- NSInteger nkey;
-
- t0 = btNodes[i];
- t1 = btNodes[i-1];
- nkey = t1.numkeys-1;
- [t0 insinnode:t1.keys[nkey] value:t1.btNodes[nkey]];
- [t1 delfrmnode:t1.keys[nkey]];
- nkey--;
- keys[i-1] = t1.keys[nkey];
- keys[i-1].recnum = t1.nodeid;
- }
- - (void)borrowright:(NSInteger)i
- {
- ACBTree *t0, *t1;
- NSInteger nkey;
-
- t0 = btNodes[i];
- t1 = btNodes[i+1];
- [t0 insinnode:t1.keys[0] value:t1.btNodes[0]];
- [t1 delfrmnode:t1.keys[0]];
- nkey = t0.numkeys - 1;
- keys[i] = t0.keys[nkey];
- keys[i].recnum = t0.nodeid;
- }
- - (NSInteger)delfrmnode:(ACBKey *)ikp
- {
- NSInteger j;
-
- j = [self searchnode:ikp.key match:YES];
- if (j == FAILURE) {
- return(FAILURE);
- }
- ACBKey *k0 = nil;
- ACBTree *n0 = nil;
- if ( self.nodeType == LEAF ) {
- k0 = self.keys[j];
- n0 = self.btNodes[j];
- }
- [self rotateleft:j];
- self.numkeys--;
- numrecs -= ((self.nodeType == LEAF)?1:btNodes[j].numrecs);
- if ( k0 ) [k0 release];
- if ( n0 ) [n0 release];
- updtd = TRUE;
- return(SUCCESS);
- }
- - (NSInteger)insinnode:(ACBKey *)ikp value:(id)value
- {
- NSInteger j;
-
- j = [self searchnode:ikp.key match:NO];
- [self rotateright:j];
- keys[j] = ikp;
- btNodes[j] = value;
- numkeys++;
- if ( nodeType == LEAF ) {
- numrecs++;
- }
- else {
- numrecs += btNodes[j].numrecs;
- }
- updtd = TRUE;
- return(j);
- }
- - (void)mergenode:(NSInteger)i
- {
- ACBTree *t0, *t1, *tr;
- NSInteger j, k, nkeys;
-
- t0 = btNodes[i];
- t1 = btNodes[i+1];
- /*** move keys and pointers from
- t1 node to t0 node ***/
- for (j=t0.numkeys, k=0; j < BTNODESIZE && k < t1.numkeys; j++, k++) {
- t0.keys[j] = t1.keys[k];
- t0.btNodes[j] = t1.btNodes[k];
- t0.numkeys++;
- }
- t0.numrecs += t1.numrecs;
- t0.rnode = t1.rnode;
- t0.rnodeid = t1.rnodeid;
- t0.updtd = YES;
- nkeys = t0.numkeys - 1;
- keys[i] = t0.keys[nkeys]; /* update key to point to new high key */
- [self rotateleft:i+1]; /* copy over the keys and nodes */
-
- t1.nodeType = -1;
- if (t1.rnodeid != 0xffff && i < numkeys - 2) {
- tr = btNodes[i+1];
- tr.lnodeid = t0.nodeid;
- tr.lnode = t0;
- tr.updtd = YES;
- }
- self.numkeys--;
- updtd = YES;
- }
- - (ACBTree *)splitnode:(NSInteger)idx
- {
- ACBTree *t1;
- NSInteger j, k;
-
- k = (idx <= BTHNODESIZE) ? BTHNODESIZE : BTHNODESIZE+1;
- /*** create new node ***/
- // checknode(l, t, k);
- t1 = [ACBTree newNodeWithDictionary:dict];
- t1.nodeType = nodeType;
- t1.rnode = self.rnode;
- self.rnode = t1;
- t1.lnode = self;
- self.updtd = t1.updtd = YES;
- /*** move keys and pointers ***/
- NSInteger i = 0;
- for (j = k; j < BTNODESIZE; j++, i++ ) {
- t1.keys[i] = keys[j];
- t1.btNodes[i] = btNodes[j];
- t1.numrecs += ((nodeType == LEAF) ? 1 : btNodes[j].numrecs);
- numrecs -= ((nodeType == LEAF) ? 1 : btNodes[j].numrecs);
- keys[j] = nil;
- btNodes[j] = nil;
- }
- t1.numkeys = BTNODESIZE-k;
- self.numkeys = k;
- return(t1);
- }
- #ifdef DONTUSENOMO
- freetree(l, t)
- FIDB *l;
- ACBTree *t;
- {
- ACBTree *tmp;
- NSInteger i;
-
- if (dict.root == nil) return(SUCCESS);
- if (t.nodeid == 1) {
- srchlvl = 0;
- }
- else srchlvl++;
- for (i = 0; i < t.numkeys; i++) {
- tmp = t.btNodes[i];
- if (tmp != nil) {
- if (tmp.nodeType == LEAF) {
- free(tmp); /* free the leaf */
- if (tmp == l.rrnode) {
- l.rrnode = nil;
- }
- t.btNodes[i] = nil;
- l.chknode.nods_inuse--;
- /* putpage(l, l.chknode, 0);
- */
- }
- else {
- freetree(l, tmp); /* continue up the tree */
- srchlvl--; /* decrement the srchlvl on return */
- }
- }
- }
- free(t); /* free the node entered with */
- if (t == l.rrnode) {
- l.rrnode = nil;
- }
- l.chknode.nods_inuse--;
- /* putpage(l, l.chknode, 0);
- */
- t = nil;
- }
- - (void) notfound:(ACBKey *)kp
- {
- /* error routine to perform if entry was expected and not found */
- }
- - (void)printtree:(ACBTree *)t
- {
- BYTE *str;
- NSInteger i, j;
- NSUInteger *pdate, *ptime;
-
- syslst = stdprn;
- if ( t.nodeid == 1 ) {
- srchlvl = 0;
- }
- else srchlvl++;
- for (j = 0; j < t.numkeys; j++) {
- checknode(l, t, j);
- if ( t.btNodes[j] != nil ) [self printtree:t.btNodes[j]];
- }
- NSLog(@"Nodeid = %d, nodeType = %s, numkeys = %d, numrecs = %d\n",
- t.nodeid, (t.nodeType == BTNODE)?@"NODE":@"LEAF", t.numkeys, t.numrecs);
- NSLog(@"Left nodeid = %d, Right nodeid = %d\n", t.lnodeid, t.rnodeid);
- for (i = 0; i < t.numkeys; i++) {
- NSLog(@" t.keys[%d] recnum = %d, keyval = %@",
- i, t.keys[i].recnum, t.keys[i]);
- str = t.keys[i].kstr;
- pdate = (NSUInteger *) (str + 6);
- ptime = (NSUInteger *) (str + 8);
- NSLog(@" date = %04.4x, time = %04.4x\n",
- *pdate, *ptime);
- }
- }
- - (BOOL)puttree:(ACBTree *)t
- {
- NSInteger i;
- if (t.nodeType != LEAF) {
- for (i = 0; i < t.numkeys; i++) {
- if ( t.btNodes[i] != nil ) puttree(l, t.btNodes[i]);
- }
- }
- if ( t.updtd ) {
- putnode(l, t, t.nodeid);
- return(YES);
- }
- return(NO);
- }
- #endif
- /** ROTATELEFT -- rotate keys from right to the left
- * starting at position j
- */
- - (void)rotateleft:(NSInteger)j
- {
- while ( j+1 < numkeys ) {
- keys[j] = keys[j+1];
- btNodes[j] = btNodes[j+1];
- j++;
- }
- }
- /** ROTATERIGHT -- rotate keys to the right by 1 position
- * starting at the last key down to position j.
- */
- - (void)rotateright:(NSInteger)j
- {
- NSInteger k;
-
- for ( k = numkeys; k > j; k-- ) {
- keys[k] = keys[k-1];
- btNodes[k] = btNodes[k-1];
- }
- keys[j] = nil;
- btNodes[j] = nil;
- }
- - (NSInteger) keyWalkLeaves
- {
- NSInteger i, idx = 0;
- NSInteger keycnt;
- ACBTree *t;
- if ( self != dict.root ) {
- return 0; // maybe I need to throw an exception here
- }
- t = self;
- self.dict.data = [[NSMutableData dataWithLength:(numkeys * sizeof(id))] retain];
- self.dict.ptrBuffer = [self.dict.data mutableBytes];
- while ( t != nil && t.nodeType != LEAF ) {
- t = t.btNodes[0];
- }
- do {
- keycnt = t.numkeys;
- for ( i = 0; i < keycnt; i++ ) {
- if ( t.btNodes[i] != nil ) {
- dict.ptrBuffer[idx++] = (id) t.keys[i].key;
- }
- }
- t = t.rnode;
- } while ( t != nil );
- return( idx );
- }
- - (NSInteger) objectWalkLeaves
- {
- NSInteger i, idx = 0;
- NSInteger keycnt;
- ACBTree *t;
-
- if ( self != dict.root ) {
- return 0; // maybe I need to throw an exception here
- }
- t = self;
- self.dict.data = [[NSMutableData dataWithLength:(numrecs * sizeof(id))] retain];
- self.dict.ptrBuffer = [self.dict.data mutableBytes];
- while ( t != nil && t.nodeType != LEAF ) {
- t = t.btNodes[0];
- }
- do {
- keycnt = t.numkeys;
- for ( i = 0; i < keycnt; i++ ) {
- if ( t.btNodes[i] != nil ) {
- dict.ptrBuffer[idx++] = (id) t.btNodes[i];
- }
- }
- t = t.rnode;
- } while ( t != nil );
- return( idx );
- }
- - (void)dealloc
- {
- #ifdef DEBUG_DEALLOC
- NSLog( @"called dealloc in ACBTree" );
- #endif
- [super dealloc];
- }
- @end