// // AMutableDictionary.m // ST4 // // Created by Alan Condit on 4/18/11. // Copyright 2011 Alan Condit. All rights reserved. // #import #import "AMutableDictionary.h" #import "ACBTree.h" @implementation AMutableDictionary @synthesize root; @synthesize nodes_av; @synthesize nodes_inuse; @synthesize nxt_nodeid; //@synthesize count; @synthesize data; @synthesize ptrBuffer; + (AMutableDictionary *) newDictionary { return [[AMutableDictionary alloc] init]; } /** dictionaryWithCapacity * capacity is meaningless to ACBTree because * capacity is automatically increased */ + (AMutableDictionary *) dictionaryWithCapacity { return [[AMutableDictionary alloc] init]; } - (id)init { self = [super init]; if (self) { // Initialization code here. nxt_nodeid = 0; count = 0; root = [ACBTree newNodeWithDictionary:self]; root.nodeType = LEAF; root.numrecs = 0; root.updtd = NO; root.lnodeid = 1; root.lnode = nil; root.rnodeid = 0xffff; root.rnode = nil; } return self; } /** initWithCapacity * capacity is meaningless to ACBTree because * capacity is automatically increased */ - (id) initWithCapacity:(NSUInteger)numItems { self = [super init]; if (self) { // Initialization code here. nxt_nodeid = 0; count = 0; root = [ACBTree newNodeWithDictionary:self]; root.nodeType = LEAF; root.numrecs = 0; root.updtd = NO; root.lnodeid = 1; root.lnode = nil; root.rnodeid = 0xffff; root.rnode = nil; } return self; } - (void) dealloc { #ifdef DEBUG_DEALLOC NSLog( @"called dealloc in AMutableDictionary" ); #endif if ( data ) [data release]; if ( root ) [root release]; [super dealloc]; } - (id) objectForKey:(id)aKey { id obj = nil; ACBTree *node; ACBKey *kp; NSInteger ret; BOOL mustRelease = NO; if ( [aKey isKindOfClass:[NSString class]] ) { kp = [ACBKey newKeyWithKStr:aKey]; mustRelease = YES; } else if ( [aKey isKindOfClass:[ACBKey class]] ) { kp = aKey; //ACBKey *akey = [ACBKey newKey:aKey]; } else { @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"What kind of key is this? %@", aKey] userInfo:nil]; return nil; // not a key that I know how to deal with } node = [root search:kp.key]; if ( node != nil ) { ret = [node searchnode:kp.key match:YES]; if ( ret >= 0 && ret < node.numkeys ) { obj = node.btNodes[ret]; if ( obj == [NSNull null] ) { obj = nil; } } } if ( mustRelease ) [kp release]; return obj; } - (void) setObject:(id)obj forKey:(id)aKey { ACBKey *kp; BOOL mustRelease = NO; if ( [aKey isKindOfClass:[NSString class]] ) { kp = [ACBKey newKeyWithKStr:aKey]; mustRelease = YES; } else if ( [aKey isKindOfClass:[ACBKey class]] ) { kp = (ACBKey *)aKey; } else { @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"What kind of key is this? %@", aKey] userInfo:nil]; } if ( [root search:kp.key] == nil ) { if ( obj == nil ) { obj = [NSNull null]; } root = [root insertkey:kp value:obj]; [kp retain]; [obj retain]; kp.recnum = count++; } else { if ( mustRelease ) [kp release]; @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"key alreadyExists" userInfo:nil]; } return; } - (BOOL) isEqual:(id)object { return [super isEqual:object]; } - (void) removeObjectForKey:(id)aKey { if ( [root deletekey:aKey] == SUCCESS ) count--; } - (NSUInteger) count { return count; } - (NSArray *) allKeys { NSUInteger cnt = [root keyWalkLeaves]; return [NSArray arrayWithObjects:ptrBuffer count:cnt]; } - (NSArray *) allValues { NSUInteger cnt = [root objectWalkLeaves]; return [NSArray arrayWithObjects:ptrBuffer count:cnt]; } - (ArrayIterator *) keyEnumerator { return [ArrayIterator newIterator:[self allKeys]]; } - (ArrayIterator *) objectEnumerator { return [ArrayIterator newIterator:[self allValues]]; } // This is where all the magic happens. // You have two choices when implementing this method: // 1) Use the stack based array provided by stackbuf. If you do this, then you must respect the value of 'len'. // 2) Return your own array of objects. If you do this, return the full length of the array returned until you run out of objects, then return 0. For example, a linked-array implementation may return each array in order until you iterate through all arrays. // In either case, state->itemsPtr MUST be a valid array (non-nil). This sample takes approach #1, using stackbuf to store results. - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len { NSUInteger cnt = 0; // This is the initialization condition, so we'll do one-time setup here. // Ensure that you never set state->state back to 0, or use another method to detect initialization // (such as using one of the values of state->extra). if (state->state == 0) { // We are not tracking mutations, so we'll set state->mutationsPtr to point into one of our extra values, // since these values are not otherwise used by the protocol. // If your class was mutable, you may choose to use an internal variable that is updated when the class is mutated. // state->mutationsPtr MUST NOT be NULL. state->mutationsPtr = &state->extra[0]; [self.root objectWalkLeaves]; } // Now we provide items, which we track with state->state, and determine if we have finished iterating. if (state->state < self.count) { // Set state->itemsPtr to the provided buffer. // Alternate implementations may set state->itemsPtr to an internal C array of objects. // state->itemsPtr MUST NOT be NULL. state->itemsPtr = stackbuf; // Fill in the stack array, either until we've provided all items from the list // or until we've provided as many items as the stack based buffer will hold. while((state->state < self.count) && (cnt < len)) { // For this sample, we generate the contents on the fly. // A real implementation would likely just be copying objects from internal storage. stackbuf[cnt++] = ptrBuffer[state->state++]; } // state->state = ((cnt < len)? cnt : len); } else { // We've already provided all our items, so we signal we are done by returning 0. cnt = 0; } return cnt; } - (void) clear { if ( count ) [self removeAllObjects]; } - (void) removeAllObjects { if ( [self count] > 0 ) { // root = [ACBTree newNodeWithDictionary:self]; NSArray *list = [self allKeys]; for ( NSInteger i = [self count] - 1; i >= 0; i-- ) { [self removeObjectForKey:[list objectAtIndex:i]]; } root.nodeid = 0; nxt_nodeid = 1; } } - (NSInteger) nextNodeId { return nxt_nodeid++; } - (NSArray *) toKeyArray { return nil; } - (NSArray *) toValueArray { return nil; } @end