Home | History | Annotate | Download | only in Framework
      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     id tmp;
     95     cnt = [otherArray count];
     96     [self ensureCapacity:count+cnt];
     97     for( i = 0; i < cnt; i++) {
     98         tmp = [otherArray objectAtIndex:i];
     99         [self addObject:tmp];
    100     }
    101     return;
    102 }
    103 
    104 - (id) objectAtIndex:(NSInteger)anIdx
    105 {
    106     id obj;
    107     if ( anIdx < 0 || anIdx >= count ) {
    108         @throw [NSException exceptionWithName:NSRangeException
    109                                        reason:[NSString stringWithFormat:@"Attempt to retrieve objectAtIndex %d past end", anIdx]
    110                                      userInfo:nil];
    111         return nil;
    112     }
    113     ptrBuffer = [buffer mutableBytes];
    114     obj = ptrBuffer[anIdx];
    115     if ( obj == [NSNull null] ) {
    116         obj = nil;
    117     }
    118     return obj;
    119 }
    120 
    121 - (void) insertObject:(id)anObject atIndex:(NSInteger)anIdx
    122 {
    123     if ( anObject == nil ) anObject = [NSNull null];
    124     if ( anObject == nil ) {
    125         @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Attempt to insert nil objectAtIndex" userInfo:nil];
    126     }
    127     if ( anIdx < 0 || anIdx > count ) {
    128         @throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to insertObjectAtIndex past end" userInfo:nil];
    129     }
    130     if ( count == BuffSize ) {
    131         [self ensureCapacity:count];
    132     }
    133     if ( anIdx < count ) {
    134         for (int i = count; i > anIdx; i--) {
    135             ptrBuffer[i] = ptrBuffer[i-1];
    136         }
    137     }
    138     ptrBuffer[anIdx] = [anObject retain];
    139     count++;
    140 }
    141 
    142 - (void) removeObjectAtIndex:(NSInteger)idx;
    143 {
    144     id tmp;
    145     if (idx < 0 || idx >= count) {
    146         @throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to insert removeObjectAtIndex past end" userInfo:nil];
    147     }
    148     else if (count) {
    149         tmp = ptrBuffer[idx];
    150         if ( tmp ) [tmp release];
    151         for (int i = idx; i < count; i++) {
    152             ptrBuffer[i] = ptrBuffer[i+1];
    153         }
    154         count--;
    155     }
    156 }
    157 
    158 - (void) removeLastObject
    159 {
    160     id tmp;
    161     if (count == 0) {
    162         @throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to removeLastObject from 0" userInfo:nil];
    163     }
    164     count--;
    165     tmp = ptrBuffer[count];
    166     if ( tmp ) [tmp release];
    167     ptrBuffer[count] = nil;
    168 }
    169 
    170 - (void)removeAllObjects
    171 {
    172     id tmp;
    173     if (count == 0) {
    174         @throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to removeAllObjects from 0" userInfo:nil];
    175     }
    176     int i;
    177     for ( i = 0; i < BuffSize; i++ ) {
    178         if (i < count) {
    179             tmp = ptrBuffer[i];
    180             if ( tmp ) [tmp release];
    181         }
    182         ptrBuffer[i] = nil;
    183     }
    184     count = 0;
    185 }
    186 
    187 - (void) replaceObjectAtIndex:(NSInteger)idx withObject:(id)obj
    188 {
    189     id tmp;
    190     if ( obj == nil ) {
    191         obj = [NSNull null];
    192     }
    193     if ( idx < 0 || idx >= count ) {
    194         @throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to replace object past end" userInfo:nil];
    195    }
    196     if ( count ) {
    197         [obj retain];
    198         tmp = ptrBuffer[idx];
    199         if ( tmp ) [tmp release];
    200         ptrBuffer[idx] = obj;
    201     }
    202 }
    203 
    204 - (NSInteger) count
    205 {
    206     return count;
    207 }
    208 
    209 - (void) setCount:(NSInteger)cnt
    210 {
    211     count = cnt;
    212 }
    213 
    214 - (NSArray *) allObjects
    215 {
    216     return [NSArray arrayWithObjects:ptrBuffer count:count];
    217 }
    218 
    219 - (ArrayIterator *) objectEnumerator
    220 {
    221     return [ArrayIterator newIterator:[self allObjects]];
    222 }
    223 
    224 // This is where all the magic happens.
    225 // You have two choices when implementing this method:
    226 // 1) Use the stack based array provided by stackbuf. If you do this, then you must respect the value of 'len'.
    227 // 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 // In either case, state->itemsPtr MUST be a valid array (non-nil). This sample takes approach #1, using stackbuf to store results.
    229 - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
    230 {
    231     NSUInteger cnt = 0;
    232     // This is the initialization condition, so we'll do one-time setup here.
    233     // Ensure that you never set state->state back to 0, or use another method to detect initialization
    234     // (such as using one of the values of state->extra).
    235     if (state->state == 0) {
    236         // We are not tracking mutations, so we'll set state->mutationsPtr to point into one of our extra values,
    237         // since these values are not otherwise used by the protocol.
    238         // If your class was mutable, you may choose to use an internal variable that is updated when the class is mutated.
    239         // state->mutationsPtr MUST NOT be NULL.
    240         state->mutationsPtr = &state->extra[0];
    241     }
    242     // Now we provide items, which we track with state->state, and determine if we have finished iterating.
    243     if (state->state < self.count) {
    244         // Set state->itemsPtr to the provided buffer.
    245         // Alternate implementations may set state->itemsPtr to an internal C array of objects.
    246         // state->itemsPtr MUST NOT be NULL.
    247         state->itemsPtr = stackbuf;
    248         // Fill in the stack array, either until we've provided all items from the list
    249         // or until we've provided as many items as the stack based buffer will hold.
    250         while((state->state < self.count) && (cnt < len)) {
    251             // For this sample, we generate the contents on the fly.
    252             // A real implementation would likely just be copying objects from internal storage.
    253             stackbuf[cnt++] = ptrBuffer[state->state++];
    254         }
    255         // state->state = ((cnt < len)? cnt : len);
    256     }
    257     else
    258     {
    259         // We've already provided all our items, so we signal we are done by returning 0.
    260         cnt = 0;
    261     }
    262     return cnt;
    263 }
    264 
    265 - (NSString *) description
    266 {
    267     NSMutableString *str;
    268     NSInteger idx, cnt;
    269     id tmp;
    270     cnt = [self count];
    271     str = [NSMutableString stringWithCapacity:30];
    272     [str appendString:@"["];
    273     for (idx = 0; idx < cnt; idx++ ) {
    274         tmp = [self objectAtIndex:idx];
    275         [str appendString:((tmp == nil) ? @"nil" : [tmp description])];
    276     }
    277     [str appendString:@"]"];
    278     return str;
    279 }
    280 
    281 - (NSString *) toString
    282 {
    283     return [self description];
    284 }
    285 
    286 - (void) ensureCapacity:(NSInteger) index
    287 {
    288 	if ((index * sizeof(id)) >= [buffer length])
    289 	{
    290 		NSInteger newSize = ([buffer length] / sizeof(id)) * 2;
    291 		if (index > newSize) {
    292 			newSize = index + 1;
    293 		}
    294         BuffSize = newSize;
    295 		[buffer setLength:(BuffSize * sizeof(id))];
    296         ptrBuffer = [buffer mutableBytes];
    297 	}
    298 }
    299 
    300 @end
    301