2010-12-12 01:25:09 +00:00
|
|
|
#include "math.h"
|
|
|
|
|
2002-10-31 23:00:40 +00:00
|
|
|
#include "Array.h"
|
2010-12-24 06:34:54 +00:00
|
|
|
#include "runtime.h"
|
2002-10-31 23:00:40 +00:00
|
|
|
|
2010-12-12 01:25:09 +00:00
|
|
|
#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]]
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2002-10-31 23:00:40 +00:00
|
|
|
@implementation Array
|
|
|
|
|
2010-12-12 01:25:09 +00:00
|
|
|
+ (id) array
|
2002-10-31 23:00:40 +00:00
|
|
|
{
|
2010-12-12 01:25:09 +00:00
|
|
|
return [self arrayWithCapacity: STANDARD_CAPACITY];
|
2002-10-31 23:00:40 +00:00
|
|
|
}
|
|
|
|
|
2010-12-12 01:25:09 +00:00
|
|
|
+ (id) arrayWithCapacity: (unsigned)cap
|
2002-10-31 23:00:40 +00:00
|
|
|
{
|
2010-12-12 01:25:09 +00:00
|
|
|
return [[[self alloc] initWithCapacity: cap] autorelease];
|
2002-10-31 23:00:40 +00:00
|
|
|
}
|
|
|
|
|
2011-02-07 13:16:16 +00:00
|
|
|
+ (id) arrayWithArray: (Array *)array
|
2010-12-12 01:25:09 +00:00
|
|
|
{
|
|
|
|
return [[array copy] autorelease];
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (id) arrayWithObject: (id)anObject
|
|
|
|
{
|
2011-02-07 13:16:16 +00:00
|
|
|
Array *newArray = (Array *)[self arrayWithCapacity: STANDARD_CAPACITY];
|
2010-12-12 01:25:09 +00:00
|
|
|
|
|
|
|
[newArray addObject: anObject];
|
|
|
|
return newArray;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (id) arrayWithObjects: (id)firstObj, ...
|
2002-10-31 23:00:40 +00:00
|
|
|
{
|
2011-03-25 07:46:32 +00:00
|
|
|
local int i;
|
2010-12-12 01:25:09 +00:00
|
|
|
id newArray = [self arrayWithObject: firstObj];
|
|
|
|
|
|
|
|
for (i = 0; i < @args.count; i++) {
|
|
|
|
[newArray addObject: (id) @args.list[i].pointer_val];
|
2005-05-06 23:06:50 +00:00
|
|
|
}
|
2010-12-12 01:25:09 +00:00
|
|
|
return [newArray autorelease];
|
|
|
|
}
|
|
|
|
|
2011-02-07 13:16:16 +00:00
|
|
|
+ (id) arrayWithObjects: (id *) objs count: (unsigned)cnt
|
2010-12-12 01:25:09 +00:00
|
|
|
{
|
2011-03-25 07:46:32 +00:00
|
|
|
local int i;
|
2010-12-12 01:25:09 +00:00
|
|
|
id newArray = [self array];
|
|
|
|
|
|
|
|
for (i = 0; i < cnt; i++) {
|
|
|
|
[newArray addObject: (id) objs[i]];
|
2005-05-06 23:06:50 +00:00
|
|
|
}
|
2010-12-12 01:25:09 +00:00
|
|
|
return newArray;
|
2002-10-31 23:00:40 +00:00
|
|
|
}
|
|
|
|
|
2010-12-12 01:25:09 +00:00
|
|
|
- (id) init
|
2002-10-31 23:00:40 +00:00
|
|
|
{
|
2010-12-12 01:25:09 +00:00
|
|
|
return [self initWithCapacity: STANDARD_CAPACITY];
|
2002-10-31 23:00:40 +00:00
|
|
|
}
|
|
|
|
|
2010-12-12 01:25:09 +00:00
|
|
|
- (id) initWithCapacity: (unsigned)cap
|
2002-10-31 23:00:40 +00:00
|
|
|
{
|
2010-12-12 01:25:09 +00:00
|
|
|
if (!(self = [super init]))
|
2011-01-14 03:07:40 +00:00
|
|
|
return nil;
|
2010-12-12 01:25:09 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2011-02-07 13:16:16 +00:00
|
|
|
_objs = (id *) obj_malloc (capacity * @sizeof (id));
|
2010-12-12 01:25:09 +00:00
|
|
|
return self;
|
2002-10-31 23:00:40 +00:00
|
|
|
}
|
|
|
|
|
2011-02-07 13:16:16 +00:00
|
|
|
- (id) initWithArray: (Array *)array
|
2002-10-31 23:00:40 +00:00
|
|
|
{
|
2010-12-12 01:25:09 +00:00
|
|
|
#if 0
|
|
|
|
local unsigned i;
|
|
|
|
local unsigned max = [array count];
|
|
|
|
|
|
|
|
if (!(self = [self initWithCapacity: max]))
|
2011-01-14 03:07:40 +00:00
|
|
|
return nil;
|
2010-12-12 01:25:09 +00:00
|
|
|
|
|
|
|
for (i = 0; i < max; i++) {
|
|
|
|
_objs[i] = [[array objectAtIndex: i] retain];
|
2002-10-31 23:00:40 +00:00
|
|
|
}
|
2010-12-12 01:25:09 +00:00
|
|
|
return self;
|
|
|
|
#else
|
|
|
|
return [self initWithArray: array copyItems: NO];
|
|
|
|
#endif
|
2002-10-31 23:00:40 +00:00
|
|
|
}
|
|
|
|
|
2011-02-07 13:16:16 +00:00
|
|
|
- (id) initWithArray: (Array *)array
|
2010-12-12 01:25:09 +00:00
|
|
|
copyItems: (BOOL)copy
|
2003-05-14 21:11:23 +00:00
|
|
|
{
|
2010-12-12 01:25:09 +00:00
|
|
|
local unsigned i;
|
|
|
|
local unsigned max = [array count];
|
2003-05-14 21:11:23 +00:00
|
|
|
|
2010-12-12 01:25:09 +00:00
|
|
|
if (!(self = [self initWithCapacity: max]))
|
2011-01-14 03:07:40 +00:00
|
|
|
return nil;
|
2010-12-12 01:25:09 +00:00
|
|
|
|
|
|
|
for (i = 0; i < max; i++) {
|
|
|
|
if (copy)
|
|
|
|
_objs[i] = [[array objectAtIndex: i] copy];
|
|
|
|
else
|
|
|
|
_objs[i] = [[array objectAtIndex: i] retain];
|
|
|
|
}
|
|
|
|
return self;
|
2003-05-14 21:11:23 +00:00
|
|
|
}
|
|
|
|
|
2010-12-12 01:25:09 +00:00
|
|
|
- (id) initWithObjects: (id)firstObj, ...
|
2002-10-31 23:00:40 +00:00
|
|
|
{
|
2011-03-25 07:46:32 +00:00
|
|
|
local int i;
|
2002-10-31 23:00:40 +00:00
|
|
|
|
2010-12-12 01:25:09 +00:00
|
|
|
if (!(self = [self initWithCapacity: @args.count + 1]))
|
2011-01-14 03:07:40 +00:00
|
|
|
return nil;
|
2010-12-12 01:25:09 +00:00
|
|
|
|
|
|
|
[self addObject: firstObj];
|
|
|
|
for (i = 0; i < @args.count; i++) {
|
|
|
|
[self addObject: (id) @args.list[i].pointer_val];
|
|
|
|
}
|
|
|
|
return self;
|
2002-10-31 23:00:40 +00:00
|
|
|
}
|
|
|
|
|
2011-02-07 13:16:16 +00:00
|
|
|
- (id) initWithObjects: (id *) objs count: (unsigned)cnt
|
2002-10-31 23:00:40 +00:00
|
|
|
{
|
2011-03-25 07:46:32 +00:00
|
|
|
local int i;
|
2010-12-12 01:25:09 +00:00
|
|
|
|
|
|
|
if (!(self = [self initWithCapacity: cnt]))
|
2011-01-14 03:07:40 +00:00
|
|
|
return nil;
|
2010-12-12 01:25:09 +00:00
|
|
|
|
|
|
|
for (i = 0; i < cnt; i++) {
|
|
|
|
[self addObject: (id) objs[i]];
|
|
|
|
}
|
|
|
|
return self;
|
2002-10-31 23:00:40 +00:00
|
|
|
}
|
|
|
|
|
2010-12-16 11:22:33 +00:00
|
|
|
- (BOOL) containsObject: (id)anObject
|
2003-04-07 22:34:39 +00:00
|
|
|
{
|
2010-12-16 11:22:33 +00:00
|
|
|
return [self indexOfObject: anObject] ? YES : NO;
|
2003-04-07 22:34:39 +00:00
|
|
|
}
|
|
|
|
|
2010-12-16 11:22:33 +00:00
|
|
|
- (unsigned) count
|
2006-12-16 13:59:29 +00:00
|
|
|
{
|
2010-12-16 11:22:33 +00:00
|
|
|
return count;
|
2006-12-16 13:59:29 +00:00
|
|
|
}
|
|
|
|
|
2010-12-12 01:25:09 +00:00
|
|
|
- (id) objectAtIndex: (unsigned)index
|
2003-07-24 20:50:40 +00:00
|
|
|
{
|
2010-12-12 10:41:52 +00:00
|
|
|
if (index >= count) // FIXME: need exceptions
|
|
|
|
[self error: "-replaceObjectAtIndex:withObject: index out of range"];
|
|
|
|
|
2010-12-12 01:25:09 +00:00
|
|
|
return _objs[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) lastObject
|
|
|
|
{
|
|
|
|
return [self objectAtIndex: [self count] - 1];
|
|
|
|
}
|
|
|
|
|
2010-12-16 11:22:33 +00:00
|
|
|
/*
|
|
|
|
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
|
|
|
|
|
2010-12-12 01:25:09 +00:00
|
|
|
/*
|
|
|
|
Adding objects
|
|
|
|
*/
|
|
|
|
|
|
|
|
- (void) addObject: (id)anObject
|
|
|
|
{
|
|
|
|
if (count == capacity) {
|
|
|
|
capacity += granularity;
|
2011-02-07 13:16:16 +00:00
|
|
|
_objs = (id *)obj_realloc (_objs, capacity * @sizeof (id));
|
2010-12-12 01:25:09 +00:00
|
|
|
}
|
2010-12-12 05:16:33 +00:00
|
|
|
_objs[count] = [anObject retain];
|
|
|
|
count++;
|
2010-12-12 01:25:09 +00:00
|
|
|
}
|
|
|
|
|
2011-02-07 13:16:16 +00:00
|
|
|
- (void) addObjectsFromArray: (Array *)array
|
2010-12-12 01:25:09 +00:00
|
|
|
{
|
|
|
|
local unsigned i;
|
|
|
|
|
2010-12-12 10:41:52 +00:00
|
|
|
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
|
2010-12-12 01:25:09 +00:00
|
|
|
|
|
|
|
for (i = 0; i < [array count]; i++) {
|
|
|
|
[self addObject: [array objectAtIndex: i]];
|
|
|
|
}
|
2003-07-24 20:50:40 +00:00
|
|
|
}
|
|
|
|
|
2010-12-12 01:25:09 +00:00
|
|
|
- (void) insertObject: (id)anObject
|
|
|
|
atIndex: (unsigned)index
|
2003-07-24 20:50:40 +00:00
|
|
|
{
|
2010-12-12 10:41:52 +00:00
|
|
|
local unsigned i;
|
2010-12-12 01:25:09 +00:00
|
|
|
|
2010-12-12 10:41:52 +00:00
|
|
|
if (index >= count) // FIXME: need exceptions
|
|
|
|
[self error: "-insertObject:atIndex: index out of range"];
|
2010-12-12 01:25:09 +00:00
|
|
|
|
|
|
|
if (count == capacity) { // at capacity, expand
|
2011-02-07 13:16:16 +00:00
|
|
|
_objs = (id *)obj_realloc (_objs, capacity * @sizeof (id));
|
2010-12-12 01:25:09 +00:00
|
|
|
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;
|
|
|
|
|
2010-12-12 10:41:52 +00:00
|
|
|
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"];
|
2010-12-12 01:25:09 +00:00
|
|
|
|
|
|
|
// retain before release
|
|
|
|
tmp = _objs[index];
|
|
|
|
_objs[index] = [anObject retain];
|
|
|
|
[tmp release];
|
|
|
|
}
|
|
|
|
|
2011-02-07 13:16:16 +00:00
|
|
|
- (void) setArray: (Array *)array
|
2010-12-12 01:25:09 +00:00
|
|
|
{
|
|
|
|
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];
|
2011-01-14 03:07:40 +00:00
|
|
|
_objs[i] = nil;
|
2010-12-12 01:25:09 +00:00
|
|
|
[tmp release];
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
while ([self count]) {
|
|
|
|
[self removeLastObject];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) removeLastObject
|
|
|
|
{
|
|
|
|
local id tmp;
|
|
|
|
|
|
|
|
tmp = _objs[--count];
|
2011-01-14 03:07:40 +00:00
|
|
|
_objs[count] = nil;
|
2010-12-12 01:25:09 +00:00
|
|
|
[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
|
|
|
|
{
|
2011-03-25 07:46:32 +00:00
|
|
|
local int i;
|
2010-12-12 01:25:09 +00:00
|
|
|
local id temp;
|
|
|
|
|
2010-12-12 10:41:52 +00:00
|
|
|
if (index >= count) // FIXME: need exceptions
|
|
|
|
[self error: "-removeObjectAtIndex: index out of range"];
|
2010-12-12 01:25:09 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-02-07 13:16:16 +00:00
|
|
|
- (void) removeObjectsInArray: (Array *)array
|
2010-12-12 01:25:09 +00:00
|
|
|
{
|
|
|
|
local unsigned i = [array count];
|
|
|
|
|
|
|
|
do {
|
|
|
|
--i;
|
|
|
|
[self removeObject: [array objectAtIndex: i]];
|
|
|
|
} while (i);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) makeObjectsPerformSelector: (SEL)selector
|
|
|
|
{
|
2011-03-25 07:46:32 +00:00
|
|
|
local int i;
|
2010-12-12 01:25:09 +00:00
|
|
|
|
|
|
|
for (i = 0; i < [self count]; i++) {
|
|
|
|
[[self objectAtIndex: i] performSelector: selector];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) makeObjectsPerformSelector: (SEL)selector
|
|
|
|
withObject: (id)anObject
|
|
|
|
{
|
2011-03-25 07:46:32 +00:00
|
|
|
local int i;
|
2010-12-12 01:25:09 +00:00
|
|
|
|
|
|
|
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];
|
2003-07-24 20:50:40 +00:00
|
|
|
}
|
|
|
|
|
2002-10-31 23:00:40 +00:00
|
|
|
@end
|
2010-12-12 11:44:46 +00:00
|
|
|
|
|
|
|
@reference Array (Private);
|