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