mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-30 08:00:51 +00:00
505076a98d
This version is a bit more useful, and we should be able to get rid of the Stack class. Also, the Ruamoko parts of the autorelease system should be almost ready now.
367 lines
6.2 KiB
R
367 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];
|
|
}
|
|
|
|
- (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
|