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