4 Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea.
7 Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro>
9 This file is part of libFoundation.
11 Permission to use, copy, modify, and distribute this software and its
12 documentation for any purpose and without fee is hereby granted, provided
13 that the above copyright notice appear in all copies and that both that
14 copyright notice and this permission notice appear in supporting
17 We disclaim all warranties with regard to this software, including all
18 implied warranties of merchantability and fitness, in no event shall
19 we be liable for any special, indirect or consequential damages or any
20 damages whatsoever resulting from loss of use, data or profits, whether in
21 an action of contract, negligence or other tortious action, arising out of
22 or in connection with the use or performance of this software.
27 #include <Foundation/common.h>
28 #include <Foundation/NSArray.h>
29 #include <Foundation/NSString.h>
30 #include <Foundation/NSException.h>
31 #include <Foundation/exceptions/GeneralExceptions.h>
33 #include <extensions/objc-runtime.h>
35 #include "NSConcreteArray.h"
37 #define DO_NOT_USE_ZONE 1
39 static NSConcreteEmptyArray *sharedEmptyArray = nil;
42 * NSConcreteArray class
45 @implementation NSConcreteArray
49 if (sharedEmptyArray == nil)
50 sharedEmptyArray = [[NSConcreteEmptyArray alloc] init];
56 return RETAIN(sharedEmptyArray);
59 - (id)initWithObjects:(id *)objects count:(unsigned int)count
65 return RETAIN(sharedEmptyArray);
67 else if (count == 1) {
69 return [[NSConcreteSingleObjectArray alloc]
70 initWithObjects:objects count:1];
74 self->items = calloc(count, sizeof(id));
76 self->items = NSZoneCalloc([self zone], sizeof(id), count);
78 self->itemsCount = count;
79 for (i = 0; i < count; i++) {
80 if (!(self->items[i] = RETAIN(objects[i]))) {
81 [[[InvalidArgumentException alloc]
82 initWithReason:@"Nil object to be added in array"] raise];
88 - (id)initWithArray:(NSArray *)anotherArray
90 unsigned i, count = [anotherArray count];
94 return RETAIN(sharedEmptyArray);
96 else if (count == 1) {
97 id item = [anotherArray objectAtIndex:0];
100 return [[NSConcreteSingleObjectArray alloc]
101 initWithObjects:&item count:1];
105 self->items = calloc(count, sizeof(id));
107 self->items = NSZoneCalloc([self zone], sizeof(id), count);
109 self->itemsCount = count;
110 for (i = 0; i < itemsCount; i++)
111 self->items[i] = RETAIN([anotherArray objectAtIndex:i]);
117 register signed int index; // Note: this limits the size of the array
119 if ((index = self->itemsCount) > 0) {
121 Not using static cache because the array content is only similiar
122 inside a single collection, not across collections (arrays being
123 used in various contexts).
124 Hitrate of the cache is about 75% (including initial miss).
126 register Class LastClass = Nil;
127 register IMP objRelease = NULL;
129 for (index--; index >= 0; index--) {
130 // TODO: cache RELEASE IMP
131 #if LIB_FOUNDATION_BOEHM_GC
132 self->items[index] = nil;
134 register id obj = self->items[index];
136 if (*(id *)obj != LastClass) {
137 LastClass = *(id *)obj;
138 objRelease = method_get_imp(object_is_instance(obj)
139 ? class_get_instance_method(LastClass, @selector(release))
140 : class_get_class_method(LastClass, @selector(release)));
143 objRelease(obj, NULL /* dangerous? */);
149 if (self->items) free(self->items);
156 /* Querying the Array */
158 - (id)objectAtIndex:(unsigned int)index
160 if (index >= self->itemsCount) {
161 [[[RangeException alloc]
162 initWithReason:@"objectAtIndex: in NSArray"
163 size:self->itemsCount index:index] raise];
165 return self->items[index];
168 - (unsigned int)count
170 return self->itemsCount;
173 - (unsigned int)indexOfObjectIdenticalTo:(id)anObject
177 for (i = 0; i < self->itemsCount; i++) {
178 if (items[i] == anObject)
184 @end /* NSConcreteArray */
187 * NSConcreteEmptyArray class
190 @implementation NSConcreteEmptyArray
196 - (id)initWithObjects:(id *)objects count:(unsigned int)count
200 self = [[NSConcreteArray alloc] initWithObjects:objects count:count];
204 - (id)initWithArray:(NSArray *)anotherArray
206 if ([anotherArray count] > 0) {
208 tmp = [[NSConcreteArray alloc] initWithArray:anotherArray];
215 - (id)objectAtIndex:(unsigned int)index
217 [[[RangeException alloc]
218 initWithReason:@"objectAtIndex: in NSArray" size:0 index:index] raise];
221 - (unsigned int)count
225 - (unsigned int)indexOfObjectIdenticalTo:(id)anObject
230 @end /* NSConcreteEmptyArray */
233 * NSConcreteSingleObjectArray class
236 @implementation NSConcreteSingleObjectArray
239 // force setup of shared emtpy
240 if (sharedEmptyArray == nil)
241 sharedEmptyArray = [[NSConcreteEmptyArray alloc] init];
247 return RETAIN(sharedEmptyArray);
249 - (id)initWithObjects:(id *)objects count:(unsigned int)count
253 return RETAIN(sharedEmptyArray);
257 self = [[NSConcreteArray allocWithZone:[self zone]]
258 initWithObjects:objects count:count];
261 if ((self->item = objects[0]) == nil) {
262 [[[InvalidArgumentException alloc]
263 initWithReason:@"Nil object to be added in array"] raise];
265 self->item = RETAIN(self->item);
268 - (id)initWithArray:(NSArray *)anotherArray
270 unsigned count = [anotherArray count];
274 return RETAIN(sharedEmptyArray);
278 self = [[NSConcreteArray alloc] initWithArray:anotherArray];
281 if ((self->item = [anotherArray objectAtIndex:0]) == nil) {
282 [[[InvalidArgumentException alloc]
283 initWithReason:@"Nil object to be added in array"] raise];
285 self->item = RETAIN(self->item);
297 - (id)objectAtIndex:(unsigned int)index
300 [[[RangeException alloc]
301 initWithReason:@"objectAtIndex: in NSArray" size:1 index:index] raise];
305 - (unsigned int)count
309 - (unsigned int)indexOfObjectIdenticalTo:(id)anObject
311 return (self->item == anObject) ? 0 : NSNotFound;
314 @end /* NSConcreteSingleObjectArray */
317 * NSConcreteMutableArray class
320 @implementation NSConcreteMutableArray
324 static BOOL initialized = NO;
327 class_add_behavior(self, [NSConcreteArray class]);
334 self->items = calloc(1, sizeof(id));
336 self->items = NSZoneCalloc([self zone], 1, sizeof(id));
339 self->itemsCount = 0;
343 - (id)initWithCapacity:(unsigned int)aNumItems
345 self->maxItems = aNumItems ? aNumItems : 16;
347 self->items = calloc(self->maxItems, sizeof(id));
349 self->items = NSZoneCalloc([self zone], sizeof(id), self->maxItems);
351 self->itemsCount = 0;
355 - (id)initWithObjects:(id *)objects count:(unsigned int)count
360 self->maxItems = count;
361 self->itemsCount = count;
365 self->itemsCount = 0;
369 self->items = calloc(self->maxItems, sizeof(id));
371 self->items = NSZoneCalloc([self zone], sizeof(id), self->maxItems);
374 for (i = 0; i < count; i++) {
375 if ((self->items[i] = RETAIN(objects[i])) == nil) {
376 [[[InvalidArgumentException alloc]
377 initWithReason:@"Nil object to be added in array"] raise];
383 - (id)initWithArray:(NSArray *)anotherArray
385 unsigned i, count = [anotherArray count];
388 self->maxItems = count;
389 self->itemsCount = count;
393 self->itemsCount = 0;
397 self->items = calloc(self->maxItems, sizeof(id));
399 self->items = NSZoneCalloc([self zone], sizeof(id), self->maxItems);
402 for (i = 0; i < self->itemsCount; i++) {
403 self->items[i] = RETAIN([anotherArray objectAtIndex:i]);
410 /* basically a copy of the NSConcreteArray -dealloc, might use a macro */
411 register signed int index;
413 if ((index = self->itemsCount) > 0) {
415 Not using static cache because the array content is only similiar
416 inside a single collection, not across collections (arrays being
417 used in various contexts).
418 Hitrate of the cache is about 75% including initial miss.
420 register Class LastClass = Nil;
421 register IMP objRelease = NULL;
423 for (index--; index >= 0; index--) {
424 // TODO: cache RELEASE IMP
425 #if LIB_FOUNDATION_BOEHM_GC
426 self->items[index] = nil;
428 register id obj = self->items[index];
430 if (*(id *)obj != LastClass) {
431 LastClass = *(id *)obj;
432 objRelease = method_get_imp(object_is_instance(obj)
433 ? class_get_instance_method(LastClass, @selector(release))
434 : class_get_class_method(LastClass, @selector(release)));
437 objRelease(obj, NULL /* dangerous? */);
443 if (self->items) free(self->items);
450 /* Altering the Array */
452 - (void)insertObject:(id)anObject atIndex:(unsigned int)index
456 if (anObject == nil) {
457 [[[InvalidArgumentException alloc]
458 initWithReason:@"Nil object to be added in array"] raise];
460 if (index > itemsCount) {
461 [[[RangeException alloc]
462 initWithReason:@"__insertObject:atIndex: in NSMutableArray"
463 size:itemsCount index:index] raise];
466 /* resize item array */
467 if (itemsCount == maxItems) {
469 maxItems += (maxItems >> 1) ? (maxItems >>1) : 1;
474 items = (id*)Realloc(items, sizeof(id) * maxItems);
478 for(i = itemsCount; i > index; i--)
479 items[i] = items[i - 1];
482 items[index] = RETAIN(anObject);
486 - (void)replaceObjectAtIndex:(unsigned int)index withObject:(id)anObject
488 if (anObject == nil) {
489 [[[InvalidArgumentException alloc]
490 initWithReason:@"Nil object to be added in array"] raise];
492 if (index >= self->itemsCount) {
493 [[[RangeException alloc]
494 initWithReason:@"NSConcreteMutableArray replaceObjectAtIndex"
495 size:self->itemsCount index:index] raise];
497 ASSIGN(self->items[index], anObject);
500 /* removing objects */
503 _removeObjectsFrom(register NSConcreteMutableArray *self,
504 register unsigned int index, register unsigned int count)
506 register unsigned int i;
508 if ((index + count) > self->itemsCount) {
509 [[[RangeException alloc]
510 initWithReason:@"removeObjectsFrom:count in NSMutableArray"
511 size:self->itemsCount index:(index + count)] raise];
516 #if !LIB_FOUNDATION_BOEHM_GC
517 // TODO: why autorelease?
518 for (i = index; i < index + count; i++)
519 [self->items[i] autorelease];
522 for (i = index + count; i < self->itemsCount; i++, index++)
523 self->items[index] = self->items[i];
524 for (; index < self->itemsCount; index++) {
525 #if DEBUG // better for crashing
526 self->items[index] = (id)0x3;
527 #else // more stable against bugs
528 self->items[index] = nil;
532 self->itemsCount -= count;
535 - (void)removeObjectsFrom:(unsigned int)index count:(unsigned int)count
537 _removeObjectsFrom(self, index, count);
539 - (void)removeObjectsInRange:(NSRange)aRange
541 _removeObjectsFrom(self, aRange.location, aRange.length);
543 - (void)removeAllObjects
545 _removeObjectsFrom(self, 0, self->itemsCount);
547 - (void)removeLastObject
549 if (self->itemsCount > 0) _removeObjectsFrom(self, (itemsCount - 1), 1);
551 - (void)removeObjectAtIndex:(unsigned int)index
553 _removeObjectsFrom(self, index, 1);
556 @end /* NSConcreteMutableArray */