1 // 2 // AMutableArray.m 3 // a_ST4 4 // 5 // Created by Alan Condit on 3/12/11. 6 // Copyright 2011 Alan's MachineWorks. All rights reserved. 7 // 8 #import "AMutableArray.h" 9 #import "ArrayIterator.h" 10 11 #define BUFFSIZE 25 12 13 @implementation AMutableArray 14 15 @synthesize BuffSize; 16 @synthesize buffer; 17 @synthesize ptrBuffer; 18 //@synthesize count; 19 20 21 + (id) newArray 22 { 23 return [[AMutableArray alloc] init]; 24 } 25 26 + (id) arrayWithCapacity:(NSInteger)size 27 { 28 return [[AMutableArray alloc] initWithCapacity:size]; 29 } 30 31 - (id) init 32 { 33 self=[super init]; 34 if ( self != nil ) { 35 BuffSize = BUFFSIZE; 36 buffer = [[NSMutableData dataWithLength:(BuffSize * sizeof(id))] retain]; 37 ptrBuffer = (id *)[buffer mutableBytes]; 38 for( int idx = 0; idx < BuffSize; idx++ ) { 39 ptrBuffer[idx] = nil; 40 } 41 } 42 return self; 43 } 44 45 - (id) initWithCapacity:(NSInteger)len 46 { 47 self=[super init]; 48 if ( self != nil ) { 49 BuffSize = (len >= BUFFSIZE) ? len : BUFFSIZE; 50 buffer = [[NSMutableData dataWithLength:(BuffSize * sizeof(id))] retain]; 51 ptrBuffer = (id *)[buffer mutableBytes]; 52 for( int idx = 0; idx < BuffSize; idx++ ) { 53 ptrBuffer[idx] = nil; 54 } 55 } 56 return self; 57 } 58 59 - (void) dealloc 60 { 61 #ifdef DEBUG_DEALLOC 62 NSLog( @"called dealloc in AMutableArray" ); 63 #endif 64 if ( count ) [self removeAllObjects]; 65 if ( buffer ) [buffer release]; 66 [super dealloc]; 67 } 68 69 - (id) copyWithZone:(NSZone *)aZone 70 { 71 AMutableArray *copy; 72 73 copy = [[[self class] allocWithZone:aZone] init]; 74 if ( buffer ) { 75 copy.buffer = [buffer copyWithZone:aZone]; 76 } 77 copy.ptrBuffer = [copy.buffer mutableBytes]; 78 copy.count = count; 79 copy.BuffSize = BuffSize; 80 return copy; 81 } 82 83 - (void) addObject:(id)anObject 84 { 85 if ( anObject == nil ) anObject = [NSNull null]; 86 [anObject retain]; 87 [self ensureCapacity:count]; 88 ptrBuffer[count++] = anObject; 89 } 90 91 - (void) addObjectsFromArray:(NSArray *)otherArray 92 { 93 NSInteger cnt, i; 94 cnt = [otherArray count]; 95 [self ensureCapacity:count+cnt]; 96 for( i = 0; i < cnt; i++) { 97 [self addObject:[otherArray objectAtIndex:i]]; 98 } 99 return; 100 } 101 102 - (id) objectAtIndex:(NSInteger)anIdx 103 { 104 id obj; 105 if ( anIdx < 0 || anIdx >= count ) { 106 @throw [NSException exceptionWithName:NSRangeException 107 reason:[NSString stringWithFormat:@"Attempt to retrieve objectAtIndex %d past end", anIdx] 108 userInfo:nil]; 109 return nil; 110 } 111 ptrBuffer = [buffer mutableBytes]; 112 obj = ptrBuffer[anIdx]; 113 if ( obj == [NSNull null] ) { 114 obj = nil; 115 } 116 return obj; 117 } 118 119 - (void) insertObject:(id)anObject atIndex:(NSInteger)anIdx 120 { 121 if ( anObject == nil ) anObject = [NSNull null]; 122 if ( anObject == nil ) { 123 @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Attempt to insert nil objectAtIndex" userInfo:nil]; 124 } 125 if ( anIdx < 0 || anIdx > count ) { 126 @throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to insertObjectAtIndex past end" userInfo:nil]; 127 } 128 if ( count == BuffSize ) { 129 [self ensureCapacity:count]; 130 } 131 if ( anIdx < count ) { 132 for (int i = count; i > anIdx; i--) { 133 ptrBuffer[i] = ptrBuffer[i-1]; 134 } 135 } 136 ptrBuffer[anIdx] = [anObject retain]; 137 count++; 138 } 139 140 - (void) removeObjectAtIndex:(NSInteger)idx; 141 { 142 id tmp; 143 if (idx < 0 || idx >= count) { 144 @throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to insert removeObjectAtIndex past end" userInfo:nil]; 145 } 146 else if (count) { 147 tmp = ptrBuffer[idx]; 148 if ( tmp ) [tmp release]; 149 for (int i = idx; i < count; i++) { 150 ptrBuffer[i] = ptrBuffer[i+1]; 151 } 152 count--; 153 } 154 } 155 156 - (void) removeLastObject 157 { 158 id tmp; 159 if (count == 0) { 160 @throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to removeLastObject from 0" userInfo:nil]; 161 } 162 count--; 163 tmp = ptrBuffer[count]; 164 if ( tmp ) [tmp release]; 165 ptrBuffer[count] = nil; 166 } 167 168 - (void)removeAllObjects 169 { 170 id tmp; 171 if (count == 0) { 172 @throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to removeAllObjects from 0" userInfo:nil]; 173 } 174 int i; 175 for ( i = 0; i < BuffSize; i++ ) { 176 if (i < count) { 177 tmp = ptrBuffer[i]; 178 if ( tmp ) [tmp release]; 179 } 180 ptrBuffer[i] = nil; 181 } 182 count = 0; 183 } 184 185 - (void) replaceObjectAtIndex:(NSInteger)idx withObject:(id)obj 186 { 187 id tmp; 188 if ( obj == nil ) { 189 obj = [NSNull null]; 190 } 191 if ( idx < 0 || idx >= count ) { 192 @throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to replace object past end" userInfo:nil]; 193 } 194 if ( count ) { 195 [obj retain]; 196 tmp = ptrBuffer[idx]; 197 if ( tmp ) [tmp release]; 198 ptrBuffer[idx] = obj; 199 } 200 } 201 202 - (NSInteger) count 203 { 204 return count; 205 } 206 207 - (void) setCount:(NSInteger)cnt 208 { 209 count = cnt; 210 } 211 212 - (NSArray *) allObjects 213 { 214 return [NSArray arrayWithObjects:ptrBuffer count:count]; 215 } 216 217 - (ArrayIterator *) objectEnumerator 218 { 219 return [ArrayIterator newIterator:[self allObjects]]; 220 } 221 222 // This is where all the magic happens. 223 // You have two choices when implementing this method: 224 // 1) Use the stack based array provided by stackbuf. If you do this, then you must respect the value of 'len'. 225 // 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. 226 // In either case, state->itemsPtr MUST be a valid array (non-nil). This sample takes approach #1, using stackbuf to store results. 227 - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len 228 { 229 NSUInteger cnt = 0; 230 // This is the initialization condition, so we'll do one-time setup here. 231 // Ensure that you never set state->state back to 0, or use another method to detect initialization 232 // (such as using one of the values of state->extra). 233 if (state->state == 0) { 234 // We are not tracking mutations, so we'll set state->mutationsPtr to point into one of our extra values, 235 // since these values are not otherwise used by the protocol. 236 // If your class was mutable, you may choose to use an internal variable that is updated when the class is mutated. 237 // state->mutationsPtr MUST NOT be NULL. 238 state->mutationsPtr = &state->extra[0]; 239 } 240 // Now we provide items, which we track with state->state, and determine if we have finished iterating. 241 if (state->state < self.count) { 242 // Set state->itemsPtr to the provided buffer. 243 // Alternate implementations may set state->itemsPtr to an internal C array of objects. 244 // state->itemsPtr MUST NOT be NULL. 245 state->itemsPtr = stackbuf; 246 // Fill in the stack array, either until we've provided all items from the list 247 // or until we've provided as many items as the stack based buffer will hold. 248 while((state->state < self.count) && (cnt < len)) { 249 // For this sample, we generate the contents on the fly. 250 // A real implementation would likely just be copying objects from internal storage. 251 stackbuf[cnt++] = ptrBuffer[state->state++]; 252 } 253 // state->state = ((cnt < len)? cnt : len); 254 } 255 else 256 { 257 // We've already provided all our items, so we signal we are done by returning 0. 258 cnt = 0; 259 } 260 return cnt; 261 } 262 263 - (NSString *) description 264 { 265 NSMutableString *str; 266 NSInteger idx, cnt; 267 cnt = [self count]; 268 str = [NSMutableString stringWithCapacity:30]; 269 [str appendString:@"["]; 270 for (idx = 0; idx < cnt; idx++ ) { 271 [str appendString:[[self objectAtIndex:idx] toString]]; 272 } 273 [str appendString:@"]"]; 274 return str; 275 } 276 277 - (NSString *) toString 278 { 279 return [self description]; 280 } 281 282 - (void) ensureCapacity:(NSInteger) index 283 { 284 if ((index * sizeof(id)) >= [buffer length]) 285 { 286 NSInteger newSize = ([buffer length] / sizeof(id)) * 2; 287 if (index > newSize) { 288 newSize = index + 1; 289 } 290 BuffSize = newSize; 291 [buffer setLength:(BuffSize * sizeof(id))]; 292 ptrBuffer = [buffer mutableBytes]; 293 } 294 } 295 296 @end 297