You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
301 lines
8.4 KiB
301 lines
8.4 KiB
//
|
|
// AMutableArray.m
|
|
// a_ST4
|
|
//
|
|
// Created by Alan Condit on 3/12/11.
|
|
// Copyright 2011 Alan's MachineWorks. All rights reserved.
|
|
//
|
|
#import "AMutableArray.h"
|
|
#import "ArrayIterator.h"
|
|
|
|
#define BUFFSIZE 25
|
|
|
|
@implementation AMutableArray
|
|
|
|
@synthesize BuffSize;
|
|
@synthesize buffer;
|
|
@synthesize ptrBuffer;
|
|
//@synthesize count;
|
|
|
|
|
|
+ (id) newArray
|
|
{
|
|
return [[AMutableArray alloc] init];
|
|
}
|
|
|
|
+ (id) arrayWithCapacity:(NSInteger)size
|
|
{
|
|
return [[AMutableArray alloc] initWithCapacity:size];
|
|
}
|
|
|
|
- (id) init
|
|
{
|
|
self=[super init];
|
|
if ( self != nil ) {
|
|
BuffSize = BUFFSIZE;
|
|
buffer = [[NSMutableData dataWithLength:(BuffSize * sizeof(id))] retain];
|
|
ptrBuffer = (id *)[buffer mutableBytes];
|
|
for( int idx = 0; idx < BuffSize; idx++ ) {
|
|
ptrBuffer[idx] = nil;
|
|
}
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (id) initWithCapacity:(NSInteger)len
|
|
{
|
|
self=[super init];
|
|
if ( self != nil ) {
|
|
BuffSize = (len >= BUFFSIZE) ? len : BUFFSIZE;
|
|
buffer = [[NSMutableData dataWithLength:(BuffSize * sizeof(id))] retain];
|
|
ptrBuffer = (id *)[buffer mutableBytes];
|
|
for( int idx = 0; idx < BuffSize; idx++ ) {
|
|
ptrBuffer[idx] = nil;
|
|
}
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
#ifdef DEBUG_DEALLOC
|
|
NSLog( @"called dealloc in AMutableArray" );
|
|
#endif
|
|
if ( count ) [self removeAllObjects];
|
|
if ( buffer ) [buffer release];
|
|
[super dealloc];
|
|
}
|
|
|
|
- (id) copyWithZone:(NSZone *)aZone
|
|
{
|
|
AMutableArray *copy;
|
|
|
|
copy = [[[self class] allocWithZone:aZone] init];
|
|
if ( buffer ) {
|
|
copy.buffer = [buffer copyWithZone:aZone];
|
|
}
|
|
copy.ptrBuffer = [copy.buffer mutableBytes];
|
|
copy.count = count;
|
|
copy.BuffSize = BuffSize;
|
|
return copy;
|
|
}
|
|
|
|
- (void) addObject:(id)anObject
|
|
{
|
|
if ( anObject == nil ) anObject = [NSNull null];
|
|
[anObject retain];
|
|
[self ensureCapacity:count];
|
|
ptrBuffer[count++] = anObject;
|
|
}
|
|
|
|
- (void) addObjectsFromArray:(NSArray *)otherArray
|
|
{
|
|
NSInteger cnt, i;
|
|
id tmp;
|
|
cnt = [otherArray count];
|
|
[self ensureCapacity:count+cnt];
|
|
for( i = 0; i < cnt; i++) {
|
|
tmp = [otherArray objectAtIndex:i];
|
|
[self addObject:tmp];
|
|
}
|
|
return;
|
|
}
|
|
|
|
- (id) objectAtIndex:(NSInteger)anIdx
|
|
{
|
|
id obj;
|
|
if ( anIdx < 0 || anIdx >= count ) {
|
|
@throw [NSException exceptionWithName:NSRangeException
|
|
reason:[NSString stringWithFormat:@"Attempt to retrieve objectAtIndex %d past end", anIdx]
|
|
userInfo:nil];
|
|
return nil;
|
|
}
|
|
ptrBuffer = [buffer mutableBytes];
|
|
obj = ptrBuffer[anIdx];
|
|
if ( obj == [NSNull null] ) {
|
|
obj = nil;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
- (void) insertObject:(id)anObject atIndex:(NSInteger)anIdx
|
|
{
|
|
if ( anObject == nil ) anObject = [NSNull null];
|
|
if ( anObject == nil ) {
|
|
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Attempt to insert nil objectAtIndex" userInfo:nil];
|
|
}
|
|
if ( anIdx < 0 || anIdx > count ) {
|
|
@throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to insertObjectAtIndex past end" userInfo:nil];
|
|
}
|
|
if ( count == BuffSize ) {
|
|
[self ensureCapacity:count];
|
|
}
|
|
if ( anIdx < count ) {
|
|
for (int i = count; i > anIdx; i--) {
|
|
ptrBuffer[i] = ptrBuffer[i-1];
|
|
}
|
|
}
|
|
ptrBuffer[anIdx] = [anObject retain];
|
|
count++;
|
|
}
|
|
|
|
- (void) removeObjectAtIndex:(NSInteger)idx;
|
|
{
|
|
id tmp;
|
|
if (idx < 0 || idx >= count) {
|
|
@throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to insert removeObjectAtIndex past end" userInfo:nil];
|
|
}
|
|
else if (count) {
|
|
tmp = ptrBuffer[idx];
|
|
if ( tmp ) [tmp release];
|
|
for (int i = idx; i < count; i++) {
|
|
ptrBuffer[i] = ptrBuffer[i+1];
|
|
}
|
|
count--;
|
|
}
|
|
}
|
|
|
|
- (void) removeLastObject
|
|
{
|
|
id tmp;
|
|
if (count == 0) {
|
|
@throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to removeLastObject from 0" userInfo:nil];
|
|
}
|
|
count--;
|
|
tmp = ptrBuffer[count];
|
|
if ( tmp ) [tmp release];
|
|
ptrBuffer[count] = nil;
|
|
}
|
|
|
|
- (void)removeAllObjects
|
|
{
|
|
id tmp;
|
|
if (count == 0) {
|
|
@throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to removeAllObjects from 0" userInfo:nil];
|
|
}
|
|
int i;
|
|
for ( i = 0; i < BuffSize; i++ ) {
|
|
if (i < count) {
|
|
tmp = ptrBuffer[i];
|
|
if ( tmp ) [tmp release];
|
|
}
|
|
ptrBuffer[i] = nil;
|
|
}
|
|
count = 0;
|
|
}
|
|
|
|
- (void) replaceObjectAtIndex:(NSInteger)idx withObject:(id)obj
|
|
{
|
|
id tmp;
|
|
if ( obj == nil ) {
|
|
obj = [NSNull null];
|
|
}
|
|
if ( idx < 0 || idx >= count ) {
|
|
@throw [NSException exceptionWithName:NSRangeException reason:@"Attempt to replace object past end" userInfo:nil];
|
|
}
|
|
if ( count ) {
|
|
[obj retain];
|
|
tmp = ptrBuffer[idx];
|
|
if ( tmp ) [tmp release];
|
|
ptrBuffer[idx] = obj;
|
|
}
|
|
}
|
|
|
|
- (NSInteger) count
|
|
{
|
|
return count;
|
|
}
|
|
|
|
- (void) setCount:(NSInteger)cnt
|
|
{
|
|
count = cnt;
|
|
}
|
|
|
|
- (NSArray *) allObjects
|
|
{
|
|
return [NSArray arrayWithObjects:ptrBuffer count:count];
|
|
}
|
|
|
|
- (ArrayIterator *) objectEnumerator
|
|
{
|
|
return [ArrayIterator newIterator:[self allObjects]];
|
|
}
|
|
|
|
// This is where all the magic happens.
|
|
// You have two choices when implementing this method:
|
|
// 1) Use the stack based array provided by stackbuf. If you do this, then you must respect the value of 'len'.
|
|
// 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.
|
|
// In either case, state->itemsPtr MUST be a valid array (non-nil). This sample takes approach #1, using stackbuf to store results.
|
|
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
|
|
{
|
|
NSUInteger cnt = 0;
|
|
// This is the initialization condition, so we'll do one-time setup here.
|
|
// Ensure that you never set state->state back to 0, or use another method to detect initialization
|
|
// (such as using one of the values of state->extra).
|
|
if (state->state == 0) {
|
|
// We are not tracking mutations, so we'll set state->mutationsPtr to point into one of our extra values,
|
|
// since these values are not otherwise used by the protocol.
|
|
// If your class was mutable, you may choose to use an internal variable that is updated when the class is mutated.
|
|
// state->mutationsPtr MUST NOT be NULL.
|
|
state->mutationsPtr = &state->extra[0];
|
|
}
|
|
// Now we provide items, which we track with state->state, and determine if we have finished iterating.
|
|
if (state->state < self.count) {
|
|
// Set state->itemsPtr to the provided buffer.
|
|
// Alternate implementations may set state->itemsPtr to an internal C array of objects.
|
|
// state->itemsPtr MUST NOT be NULL.
|
|
state->itemsPtr = stackbuf;
|
|
// Fill in the stack array, either until we've provided all items from the list
|
|
// or until we've provided as many items as the stack based buffer will hold.
|
|
while((state->state < self.count) && (cnt < len)) {
|
|
// For this sample, we generate the contents on the fly.
|
|
// A real implementation would likely just be copying objects from internal storage.
|
|
stackbuf[cnt++] = ptrBuffer[state->state++];
|
|
}
|
|
// state->state = ((cnt < len)? cnt : len);
|
|
}
|
|
else
|
|
{
|
|
// We've already provided all our items, so we signal we are done by returning 0.
|
|
cnt = 0;
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
- (NSString *) description
|
|
{
|
|
NSMutableString *str;
|
|
NSInteger idx, cnt;
|
|
id tmp;
|
|
cnt = [self count];
|
|
str = [NSMutableString stringWithCapacity:30];
|
|
[str appendString:@"["];
|
|
for (idx = 0; idx < cnt; idx++ ) {
|
|
tmp = [self objectAtIndex:idx];
|
|
[str appendString:((tmp == nil) ? @"nil" : [tmp description])];
|
|
}
|
|
[str appendString:@"]"];
|
|
return str;
|
|
}
|
|
|
|
- (NSString *) toString
|
|
{
|
|
return [self description];
|
|
}
|
|
|
|
- (void) ensureCapacity:(NSInteger) index
|
|
{
|
|
if ((index * sizeof(id)) >= [buffer length])
|
|
{
|
|
NSInteger newSize = ([buffer length] / sizeof(id)) * 2;
|
|
if (index > newSize) {
|
|
newSize = index + 1;
|
|
}
|
|
BuffSize = newSize;
|
|
[buffer setLength:(BuffSize * sizeof(id))];
|
|
ptrBuffer = [buffer mutableBytes];
|
|
}
|
|
}
|
|
|
|
@end
|