#include "math.h" #include "Array.h" #include "runtime.h" #define STANDARD_CAPACITY 16 #define ARRAY_MAX_GRANULARITY 100 /* Optimization opportunity: if ([self class] == [Array class]) { [[do things optimally instead of only through primitive methods]] } */ @implementation Array + (id) array { return [self arrayWithCapacity: STANDARD_CAPACITY]; } + (id) arrayWithCapacity: (unsigned)cap { return [[[self alloc] initWithCapacity: cap] autorelease]; } + (id) arrayWithArray: (Array [])array { return [[array copy] autorelease]; } + (id) arrayWithObject: (id)anObject { Array [] newArray = (Array [])[self arrayWithCapacity: STANDARD_CAPACITY]; [newArray addObject: anObject]; return newArray; } + (id) arrayWithObjects: (id)firstObj, ... { local integer i; id newArray = [self arrayWithObject: firstObj]; for (i = 0; i < @args.count; i++) { [newArray addObject: (id) @args.list[i].pointer_val]; } return [newArray autorelease]; } + (id) arrayWithObjects: (id []) objs count: (unsigned)cnt { local integer i; id newArray = [self array]; for (i = 0; i < cnt; i++) { [newArray addObject: (id) objs[i]]; } return newArray; } - (id) init { return [self initWithCapacity: STANDARD_CAPACITY]; } - (id) initWithCapacity: (unsigned)cap { if (!(self = [super init])) return NIL; count = 0; if ((capacity = cap) < 1) capacity = 1; granularity = (capacity + 1) / 2; if (granularity < 1) granularity = 1; if (granularity > ARRAY_MAX_GRANULARITY) granularity = ARRAY_MAX_GRANULARITY; _objs = (id []) obj_malloc (capacity * @sizeof (id)); return self; } - (id) initWithArray: (Array [])array { #if 0 local unsigned i; local unsigned max = [array count]; if (!(self = [self initWithCapacity: max])) return NIL; for (i = 0; i < max; i++) { _objs[i] = [[array objectAtIndex: i] retain]; } return self; #else return [self initWithArray: array copyItems: NO]; #endif } - (id) initWithArray: (Array [])array copyItems: (BOOL)copy { local unsigned i; local unsigned max = [array count]; if (!(self = [self initWithCapacity: max])) return NIL; for (i = 0; i < max; i++) { if (copy) _objs[i] = [[array objectAtIndex: i] copy]; else _objs[i] = [[array objectAtIndex: i] retain]; } return self; } - (id) initWithObjects: (id)firstObj, ... { local integer i; if (!(self = [self initWithCapacity: @args.count + 1])) return NIL; [self addObject: firstObj]; for (i = 0; i < @args.count; i++) { [self addObject: (id) @args.list[i].pointer_val]; } return self; } - (id) initWithObjects: (id []) objs count: (unsigned)cnt { local integer i; if (!(self = [self initWithCapacity: cnt])) return NIL; for (i = 0; i < cnt; i++) { [self addObject: (id) objs[i]]; } return self; } - (BOOL) containsObject: (id)anObject { return [self indexOfObject: anObject] ? YES : NO; } - (unsigned) count { return count; } - (id) objectAtIndex: (unsigned)index { if (index >= count) // FIXME: need exceptions [self error: "-replaceObjectAtIndex:withObject: index out of range"]; return _objs[index]; } - (id) lastObject { return [self objectAtIndex: [self count] - 1]; } /* Finding Objects */ - (unsigned) indexOfObject: (id)anObject { local unsigned i; for (i = 0; i < [self count]; i++) { if ([[self objectAtIndex: i] isEqual: anObject]) return i; } return NotFound; } #if 0 - (unsigned) indexOfObject: (id)anObject inRange: (Range)range; { local unsigned i; local unsigned end = range.location + range.length; for (i = range.location; i < end && i < [self count]; i++) { if ([[self objectAtIndex: i] isEqual: anObject]) return i; } return NotFound; } #endif - (unsigned) indexOfObjectIdenticalTo: (id)anObject { local unsigned i; for (i = 0; i < [self count]; i++) { if ([self objectAtIndex: i] == anObject) return i; } return NotFound; } #if 0 - (unsigned) indexOfObjectIdenticalTo: (id)anObject inRange: (Range)range; { local unsigned i; local unsigned end = range.location + range.length; for (i = range.location; i < end && i < [self count]; i++) { if ([self objectAtIndex: i] == anObject) return i; } return NotFound; } #endif /* Adding objects */ - (void) addObject: (id)anObject { if (count == capacity) { capacity += granularity; _objs = (id [])obj_realloc (_objs, capacity * @sizeof (id)); } _objs[count] = [anObject retain]; count++; } - (void) addObjectsFromArray: (Array [])array { local unsigned i; if (!array) // FIXME: need exceptions [self error: "-addObjectsFromArray: passed nil argument"]; if (array == self) // FIXME: need exceptions [self error: "-addObjectsFromArray: tried to add objects from self"]; // FIXME: need exceptions for (i = 0; i < [array count]; i++) { [self addObject: [array objectAtIndex: i]]; } } - (void) insertObject: (id)anObject atIndex: (unsigned)index { local unsigned i; if (index >= count) // FIXME: need exceptions [self error: "-insertObject:atIndex: index out of range"]; if (count == capacity) { // at capacity, expand _objs = (id [])obj_realloc (_objs, capacity * @sizeof (id)); capacity += granularity; } for (i = count; i > index; i--) { _objs[i] = _objs[i - 1]; } _objs[index] = [anObject retain]; count++; return; } /* Replacing objects */ - (void) replaceObjectAtIndex: (unsigned)index withObject: (id)anObject { local id tmp; if (!anObject) // FIXME: need exceptions [self error: "-replaceObjectAtIndex:withObject: passed nil object"]; if (index >= count) // FIXME: need exceptions [self error: "-replaceObjectAtIndex:withObject: index out of range"]; // retain before release tmp = _objs[index]; _objs[index] = [anObject retain]; [tmp release]; } - (void) setArray: (Array [])array { if (self == array) return; [self removeAllObjects]; [self addObjectsFromArray: array]; } /* Object removal */ - (void) removeAllObjects { #if 0 local id tmp; while (count) { /* We do it this way to avoid having something weird happen when the object is released (dealloc may trigger, which in turn could cause something else to happen). */ tmp = _objs[--count]; _objs[i] = NIL; [tmp release]; } #else while ([self count]) { [self removeLastObject]; } #endif } - (void) removeLastObject { local id tmp; tmp = _objs[--count]; _objs[count] = NIL; [tmp release]; } - (void) removeObject: (id)anObject { local unsigned i = [self count]; do { --i; if ([[self objectAtIndex: i] isEqual: anObject]) { [self removeObjectAtIndex: i]; } } while (i); } - (void) removeObjectAtIndex: (unsigned)index { local integer i; local id temp; if (index >= count) // FIXME: need exceptions [self error: "-removeObjectAtIndex: index out of range"]; temp = _objs[index]; count--; for (i = index; i < count; i++) { // reassign all objs >= index _objs[i] = _objs[i+1]; } [temp release]; } - (void) removeObjectIdenticalTo: (id)anObject { local unsigned i = [self count]; do { --i; if ([self objectAtIndex: i] == anObject) { [self removeObjectAtIndex: i]; } } while (i); } - (void) removeObjectsInArray: (Array [])array { local unsigned i = [array count]; do { --i; [self removeObject: [array objectAtIndex: i]]; } while (i); } - (void) makeObjectsPerformSelector: (SEL)selector { local integer i; for (i = 0; i < [self count]; i++) { [[self objectAtIndex: i] performSelector: selector]; } } - (void) makeObjectsPerformSelector: (SEL)selector withObject: (id)anObject { local integer i; for (i = 0; i < [self count]; i++) { [[self objectAtIndex: i] performSelector: selector withObject: anObject]; } } - (void) dealloc { local unsigned i; for (i = 0; i < count; i++) { if (_objs[i]) [_objs[i] release]; } if (_objs) { obj_free (_objs); } [super dealloc]; } @end @reference Array (Private);