quakeforge/ruamoko/lib/Array.r
Jeff Teunissen 22dd7cd20d Avoid wasting a local and giving the compiler a minor aneurysm
qfcc doesn't yet like foo[bar++] = baz; let's be nice and not give it
indigestion.
2010-12-12 00:16:33 -05:00

368 lines
6.2 KiB
R

#include "math.h"
#include "Array.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;
}
- (unsigned) count
{
return count;
}
- (BOOL) containsObject: (id)anObject
{
return [self indexOfObject: anObject] ? YES : NO;
}
- (id) objectAtIndex: (unsigned)index
{
if (index >= count) {
return NIL; // FIXME: need exceptions
}
return _objs[index];
}
- (id) lastObject
{
return [self objectAtIndex: [self count] - 1];
}
/*
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 || array == self)
return; // FIXME: need exceptions
for (i = 0; i < [array count]; i++) {
[self addObject: [array objectAtIndex: i]];
}
}
- (void) insertObject: (id)anObject
atIndex: (unsigned)index
{
local integer i;
if (index >= count)
return; // FIXME: need exceptions
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 || index >= count) {
return; // FIXME: need exceptions
}
// 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)
return; // FIXME: need exceptions
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