1// 2// AMutableDictionary.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 "AMutableDictionary.h" 11#import "ACBTree.h" 12 13@implementation AMutableDictionary 14 15@synthesize root; 16@synthesize nodes_av; 17@synthesize nodes_inuse; 18@synthesize nxt_nodeid; 19//@synthesize count; 20@synthesize data; 21@synthesize ptrBuffer; 22 23+ (AMutableDictionary *) newDictionary 24{ 25 return [[AMutableDictionary alloc] init]; 26} 27 28/** dictionaryWithCapacity 29 * capacity is meaningless to ACBTree because 30 * capacity is automatically increased 31 */ 32+ (AMutableDictionary *) dictionaryWithCapacity 33{ 34 return [[AMutableDictionary alloc] init]; 35} 36 37- (id)init 38{ 39 self = [super init]; 40 if (self) { 41 // Initialization code here. 42 nxt_nodeid = 0; 43 count = 0; 44 root = [ACBTree newNodeWithDictionary:self]; 45 root.nodeType = LEAF; 46 root.numrecs = 0; 47 root.updtd = NO; 48 root.lnodeid = 1; 49 root.lnode = nil; 50 root.rnodeid = 0xffff; 51 root.rnode = nil; 52 } 53 return self; 54} 55 56/** initWithCapacity 57 * capacity is meaningless to ACBTree because 58 * capacity is automatically increased 59 */ 60- (id) initWithCapacity:(NSUInteger)numItems 61{ 62 self = [super init]; 63 if (self) { 64 // Initialization code here. 65 nxt_nodeid = 0; 66 count = 0; 67 root = [ACBTree newNodeWithDictionary:self]; 68 root.nodeType = LEAF; 69 root.numrecs = 0; 70 root.updtd = NO; 71 root.lnodeid = 1; 72 root.lnode = nil; 73 root.rnodeid = 0xffff; 74 root.rnode = nil; 75 } 76 return self; 77} 78 79- (void) dealloc 80{ 81#ifdef DEBUG_DEALLOC 82 NSLog( @"called dealloc in AMutableDictionary" ); 83#endif 84 if ( data ) [data release]; 85 if ( root ) [root release]; 86 [super dealloc]; 87} 88 89- (id) objectForKey:(id)aKey 90{ 91 id obj = nil; 92 ACBTree *node; 93 ACBKey *kp; 94 NSInteger ret; 95 BOOL mustRelease = NO; 96 97 if ( [aKey isKindOfClass:[NSString class]] ) { 98 kp = [ACBKey newKeyWithKStr:aKey]; 99 mustRelease = YES; 100 } 101 else if ( [aKey isKindOfClass:[ACBKey class]] ) { 102 kp = aKey; 103 //ACBKey *akey = [ACBKey newKey:aKey]; 104 } 105 else { 106 @throw [NSException exceptionWithName:NSInvalidArgumentException 107 reason:[NSString stringWithFormat:@"What kind of key is this? %@", aKey] 108 userInfo:nil]; 109 return nil; // not a key that I know how to deal with 110 } 111 node = [root search:kp.key]; 112 if ( node != nil ) { 113 ret = [node searchnode:kp.key match:YES]; 114 if ( ret >= 0 && ret < node.numkeys ) { 115 obj = node.btNodes[ret]; 116 if ( obj == [NSNull null] ) { 117 obj = nil; 118 } 119 } 120 } 121 if ( mustRelease ) [kp release]; 122 return obj; 123} 124 125- (void) setObject:(id)obj forKey:(id)aKey 126{ 127 ACBKey *kp; 128 BOOL mustRelease = NO; 129 if ( [aKey isKindOfClass:[NSString class]] ) { 130 kp = [ACBKey newKeyWithKStr:aKey]; 131 mustRelease = YES; 132 } 133 else if ( [aKey isKindOfClass:[ACBKey class]] ) { 134 kp = (ACBKey *)aKey; 135 } 136 else { 137 @throw [NSException exceptionWithName:NSInvalidArgumentException 138 reason:[NSString stringWithFormat:@"What kind of key is this? %@", aKey] 139 userInfo:nil]; 140 } 141 if ( [root search:kp.key] == nil ) { 142 if ( obj == nil ) { 143 obj = [NSNull null]; 144 } 145 root = [root insertkey:kp value:obj]; 146 [kp retain]; 147 [obj retain]; 148 kp.recnum = count++; 149 } 150 else { 151 if ( mustRelease ) [kp release]; 152 @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"key alreadyExists" userInfo:nil]; 153 } 154 return; 155} 156 157- (BOOL) isEqual:(id)object 158{ 159 return [super isEqual:object]; 160} 161 162- (void) removeObjectForKey:(id)aKey 163{ 164 if ( [root deletekey:aKey] == SUCCESS ) 165 count--; 166} 167 168- (NSUInteger) count 169{ 170 return count; 171} 172 173- (NSArray *) allKeys 174{ 175 NSUInteger cnt = [root keyWalkLeaves]; 176 return [NSArray arrayWithObjects:ptrBuffer count:cnt]; 177} 178 179- (NSArray *) allValues 180{ 181 NSUInteger cnt = [root objectWalkLeaves]; 182 return [NSArray arrayWithObjects:ptrBuffer count:cnt]; 183} 184 185- (ArrayIterator *) keyEnumerator 186{ 187 return [ArrayIterator newIterator:[self allKeys]]; 188} 189 190- (ArrayIterator *) objectEnumerator 191{ 192 return [ArrayIterator newIterator:[self allValues]]; 193} 194 195// This is where all the magic happens. 196// You have two choices when implementing this method: 197// 1) Use the stack based array provided by stackbuf. If you do this, then you must respect the value of 'len'. 198// 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. 199// In either case, state->itemsPtr MUST be a valid array (non-nil). This sample takes approach #1, using stackbuf to store results. 200- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len 201{ 202 NSUInteger cnt = 0; 203 // This is the initialization condition, so we'll do one-time setup here. 204 // Ensure that you never set state->state back to 0, or use another method to detect initialization 205 // (such as using one of the values of state->extra). 206 if (state->state == 0) { 207 // We are not tracking mutations, so we'll set state->mutationsPtr to point into one of our extra values, 208 // since these values are not otherwise used by the protocol. 209 // If your class was mutable, you may choose to use an internal variable that is updated when the class is mutated. 210 // state->mutationsPtr MUST NOT be NULL. 211 state->mutationsPtr = &state->extra[0]; 212 [self.root objectWalkLeaves]; 213 } 214 // Now we provide items, which we track with state->state, and determine if we have finished iterating. 215 if (state->state < self.count) { 216 // Set state->itemsPtr to the provided buffer. 217 // Alternate implementations may set state->itemsPtr to an internal C array of objects. 218 // state->itemsPtr MUST NOT be NULL. 219 state->itemsPtr = stackbuf; 220 // Fill in the stack array, either until we've provided all items from the list 221 // or until we've provided as many items as the stack based buffer will hold. 222 while((state->state < self.count) && (cnt < len)) { 223 // For this sample, we generate the contents on the fly. 224 // A real implementation would likely just be copying objects from internal storage. 225 stackbuf[cnt++] = ptrBuffer[state->state++]; 226 } 227 // state->state = ((cnt < len)? cnt : len); 228 } 229 else 230 { 231 // We've already provided all our items, so we signal we are done by returning 0. 232 cnt = 0; 233 } 234 return cnt; 235} 236 237- (void) clear 238{ 239 if ( count ) [self removeAllObjects]; 240} 241 242- (void) removeAllObjects 243{ 244 root = [ACBTree newNodeWithDictionary:self]; 245 root.nodeid = 0; 246 nxt_nodeid = 1; 247} 248 249- (NSInteger) nextNodeId 250{ 251 return nxt_nodeid++; 252} 253 254- (NSArray *) toKeyArray 255{ 256 return nil; 257} 258 259- (NSArray *) toValueArray 260{ 261 return nil; 262} 263 264@end 265