This is NSArray.m in view mode; [Download] [Up]
/* NSArray.m Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea. All rights reserved. Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro> This file is part of libFoundation. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. We disclaim all warranties with regard to this software, including all implied warranties of merchantability and fitness, in no event shall we be liable for any special, indirect or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortious action, arising out of or in connection with the use or performance of this software. */ #include <stdarg.h> #include <stdlib.h> #include <string.h> #include <Foundation/common.h> #include <Foundation/NSObject.h> #include <Foundation/NSArray.h> #include <Foundation/NSRange.h> #include <Foundation/NSString.h> #include <Foundation/NSAutoreleasePool.h> #include <Foundation/NSException.h> #include <Foundation/NSCoder.h> #include <Foundation/exceptions/GeneralExceptions.h> #include "NSConcreteArray.h" /* * NSArray Implementation * * primary methods are * init * initWithObjects:count: * dealloc * count * objectAtIndex: */ @implementation NSArray /* Allocating and Initializing an Array */ + (id)allocWithZone:(NSZone*)zone { return NSAllocateObject( (self == [NSArray class]) ? [NSConcreteArray class] : self, 0, zone); } + (id)array { return [[[self alloc] init] autorelease]; } + (id)arrayWithObject:(id)anObject { return [[[self alloc] initWithObjects:&anObject count:1] autorelease]; } + (id)arrayWithObjects:(id)firstObj,... { id array, obj, *objects; va_list list; unsigned int count; va_start(list, firstObj); for (count=0, obj = firstObj; obj; obj = va_arg(list,id)) count++; va_end(list); objects = Malloc(sizeof(id)*count); va_start(list, firstObj); for (count = 0, obj = firstObj; obj; obj = va_arg(list,id)) objects[count++] = obj; va_end(list); array = [[[self alloc] initWithObjects:objects count:count] autorelease]; Free(objects); return array; } + (id)arrayWithArray:(NSArray*)anotherArray { return [[[self alloc] initWithArray:anotherArray] autorelease]; } + (id)arrayWithContentsOfFile:(NSString*)fileName { return [[[self alloc] initWithContentsOfFile:fileName] autorelease]; } + (id)arrayWithObjects:(id*)objects count:(unsigned int)count { return [[[self alloc] initWithObjects:objects count:count] autorelease]; } - (NSArray*)arrayByAddingObject:(id)anObject { int i, count = [self count]; id *objects = Malloc(sizeof(id)*(count+1)); id array; for (i = 0; i < count; i++) objects[i] = [self objectAtIndex:i]; objects[i] = anObject; array = [[[NSArray alloc] initWithObjects:objects count:count+1] autorelease]; Free(objects); return array; } - (NSArray*)arrayByAddingObjectsFromArray:(NSArray*)anotherArray; { unsigned int i, count = [self count], another = [anotherArray count]; id array; id *objects = Malloc(sizeof(id)*(count+another)); for (i=0; i<count; i++) objects[i] = [self objectAtIndex:i]; for (i=0; i<another; i++) objects[i+count] = [anotherArray objectAtIndex:i]; array = [[[NSArray alloc] initWithObjects:objects count:count+another] autorelease]; Free(objects); return array; } - (id)initWithArray:(NSArray*)anotherArray { return [self initWithArray:anotherArray copyItems:NO]; } - (id)initWithArray:(NSArray*)anotherArray copyItems:(BOOL)flag; { unsigned int i, count = [anotherArray count]; id* objects = Malloc(sizeof(id) * count); for (i = 0; i < count; i++) objects[i] = flag ? [anotherArray objectAtIndex:i] : [[[anotherArray objectAtIndex:i] copyWithZone:NULL] autorelease]; [self initWithObjects:objects count:count]; Free(objects); return self; } - (id)initWithObjects:(id)firstObj,... { id obj, *objects; va_list list; unsigned int count; va_start(list, firstObj); for (count=0, obj = firstObj; obj; obj = va_arg(list,id)) count++; va_end(list); objects = Malloc(sizeof(id)*count); va_start(list, firstObj); for (count = 0, obj = firstObj; obj; obj = va_arg(list,id)) objects[count++] = obj; va_end(list); [self initWithObjects:objects count:count]; Free(objects); return self; } - (id)initWithObjects:(id*)objects count:(unsigned int)count { [self subclassResponsibility:_cmd]; return self; } - (id)initWithContentsOfFile:(NSString*)fileName { volatile id plist = nil; TRY { plist = [[NSString stringWithContentsOfFile:fileName] propertyList]; if (![plist isKindOfClass:[NSArray class]]) plist = nil; } END_TRY OTHERWISE { plist = nil; } END_CATCH if (plist == nil) { [self autorelease]; return nil; } else return [self initWithArray:plist]; } /* Querying the Array */ - (BOOL)containsObject:(id)anObject { return ([self indexOfObject:anObject] == NSNotFound) ? NO : YES; } - (unsigned int)count { [self subclassResponsibility:_cmd]; return 0; } - (unsigned int)indexOfObject:(id)anObject { return [self indexOfObject:anObject inRange:NSMakeRange(0, [self count])]; } - (unsigned int)indexOfObjectIdenticalTo:(id)anObject; { return [self indexOfObjectIdenticalTo:anObject inRange:NSMakeRange(0, [self count])]; } - (unsigned int)indexOfObject:(id)anObject inRange:(NSRange)aRange { unsigned int index; for (index = 0; index < aRange.length; index++) if ([anObject isEqual:[self objectAtIndex:aRange.location+index]]) return aRange.location+index; return NSNotFound; } - (unsigned int)indexOfObjectIdenticalTo:(id)anObject inRange:(NSRange)aRange { unsigned int index; for (index = 0; index < aRange.length; index++) if (anObject == [self objectAtIndex:aRange.location+index]) return index; return NSNotFound; } - (id)lastObject { return [self objectAtIndex:[self count]-1]; } - (id)objectAtIndex:(unsigned int)index { [self subclassResponsibility:_cmd]; return self; } - (NSEnumerator*)objectEnumerator { return [[[_NSArrayEnumerator alloc] initWithArray:self reverse:NO] autorelease]; } - (NSEnumerator*)reverseObjectEnumerator { return [[[_NSArrayEnumerator alloc] initWithArray:self reverse:YES] autorelease]; } /* Sending Messages to Elements */ - (void)makeObjectsPerform:(SEL)aSelector { unsigned int index, count = [self count]; for (index = 0; index < count; index++) [[self objectAtIndex:index] perform:aSelector]; } - (void)makeObjectsPerform:(SEL)aSelector withObject:(id)anObject; { unsigned int index, count = [self count]; for (index = 0; index < count; index++) [[self objectAtIndex:index] perform:aSelector withObject:anObject]; } /* Comparing Arrays */ - (id)firstObjectCommonWithArray:(NSArray*)otherArray { unsigned int index, count = [self count]; for (index = 0; index < count; index++) { id object = [self objectAtIndex:index]; if ([otherArray containsObject:object]) return object; } return nil; } - (BOOL)isEqualToArray:(NSArray*)otherArray { unsigned int index, count; if( otherArray == self ) return YES; if ([otherArray count] != (count = [self count])) return NO; for (index = 0; index < count; index++) if (![[self objectAtIndex:index] isEqual: [otherArray objectAtIndex:index]]) return NO; return YES; } /* Deriving New Arrays */ - (NSArray*)sortedArrayUsingFunction: (int(*)(id element1, id element2, void *userData))comparator context:(void*)context { id sortedArray = [[self mutableCopy] autorelease]; [sortedArray sortUsingFunction:comparator context:context]; return [[sortedArray copy] autorelease]; } static int compare(id elem1, id elem2, void* comparator) { return (int)[elem1 perform:comparator withObject:elem2]; } - (NSArray*)sortedArrayUsingSelector:(SEL)comparator // Returns an array listing the receiver's elements in ascending order, // as determined by the comparison method specified by the selector // comparator. { return [self sortedArrayUsingFunction:compare context:(void*)comparator]; } - (NSArray*)subarrayWithRange:(NSRange)range { id array; unsigned int index; id *objects = Malloc(sizeof(id)*range.length); for (index = 0; index<range.length; index++) objects[index] = [self objectAtIndex:range.location+index]; array = [[[NSArray alloc] initWithObjects:objects count:range.length] autorelease]; Free(objects); return array; } // Returns an array containing the receiver's elements // that fall within the limits specified by range. /* Joining String Elements */ - (NSString*)componentsJoinedByString:(NSString*)separator { unsigned int index, count = [self count]; if(!separator) separator = @""; if(count) { NSMutableString* string = [NSMutableString new]; id pool = [NSAutoreleasePool new]; id elem = [self objectAtIndex:0]; SEL sel = @selector(appendString:); IMP imp = [string methodForSelector:sel]; if (![elem isKindOfClass:[NSString class]]) elem = [elem description]; (*imp)(string, sel, elem); for (index = 1; index < count; index++) { elem = [self objectAtIndex:index]; if (![elem isKindOfClass:[NSString class]]) elem = [elem description]; (*imp)(string, sel, separator); (*imp)(string, sel, elem); } [pool release]; return [string autorelease]; } return nil; } /* Creating a String Description of the Array */ - (NSString*)descriptionWithLocale:(NSDictionary*)locale indent:(unsigned int)indent; { NSMutableString* description = [NSMutableString stringWithCString:"(\n"]; unsigned int indent1 = indent + 4; NSMutableString* indentation = [NSString stringWithFormat: [NSString stringWithFormat:@"%%%dc", indent1], ' ']; unsigned int count = [self count]; SEL sel = @selector(appendString:); IMP imp = [description methodForSelector:sel]; if(count) { id pool = [NSAutoreleasePool new]; id object; id stringRepresentation; unsigned int index; object = [self objectAtIndex:0]; if ([object respondsToSelector: @selector(descriptionWithLocale:indent:)]) stringRepresentation = [object descriptionWithLocale:locale indent:indent1]; else if ([object respondsToSelector:@selector(descriptionWithLocale:)]) stringRepresentation = [object descriptionWithLocale:locale]; else stringRepresentation = [object stringRepresentation]; (*imp)(description, sel, indentation); (*imp)(description, sel, stringRepresentation); for (index = 1; index < count; index++) { object = [self objectAtIndex:index]; if ([object respondsToSelector: @selector(descriptionWithLocale:indent:)]) stringRepresentation = [object descriptionWithLocale:locale indent:indent1]; else if ([object respondsToSelector:@selector(descriptionWithLocale:)]) stringRepresentation = [object descriptionWithLocale:locale]; else stringRepresentation = [object stringRepresentation]; (*imp)(description, sel, @",\n"); (*imp)(description, sel, indentation); (*imp)(description, sel, stringRepresentation); } [pool release]; } (*imp)(description, sel, indent ? [NSMutableString stringWithFormat: [NSString stringWithFormat:@"\n%%%dc)", indent], ' '] : [NSMutableString stringWithCString:"\n)"]); return description; } - (NSString*)descriptionWithLocale:(NSDictionary*)locale { return [self descriptionWithLocale:locale indent:0]; } - (NSString*)description { return [self descriptionWithLocale:nil indent:0]; } - (NSString*)stringRepresentation { return [self descriptionWithLocale:nil indent:0]; } /* Write plist to file */ - (BOOL)writeToFile:(NSString*)fileName atomically:(BOOL)flag { volatile BOOL success = NO; TRY { id content = [self description]; success = [content writeToFile:fileName atomically:flag]; } END_TRY OTHERWISE { success = NO; } END_CATCH return success; } /* From adopted/inherited protocols */ - (unsigned int)hash { return [self count]; } - (BOOL)isEqual:(id)anObject { if ([anObject isKindOfClass:[NSArray class]] == NO) return NO; return [self isEqualToArray:anObject]; } /* Copying */ - (id)copyWithZone:(NSZone*)zone { if (NSShouldRetainWithZone(self, zone)) return [self retain]; else return [[NSArray allocWithZone:zone] initWithArray:self copyItems:YES]; } - (id)mutableCopyWithZone:(NSZone*)zone { return [[NSMutableArray alloc] initWithArray:self]; } /* Encoding */ - (Class)classForCoder { return [NSArray class]; } - (void)encodeWithCoder:(NSCoder*)aCoder { IMP imp = [aCoder methodForSelector:@selector(encodeObject:)]; int i, count = [self count]; [aCoder encodeValueOfObjCType:@encode(int) at:&count]; for(i = 0; i < count; i++) (*imp)(aCoder, @selector(encodeObject:), [self objectAtIndex:i]); } - (id)initWithCoder:(NSCoder*)aDecoder { IMP imp = [aDecoder methodForSelector:@selector(decodeObject)]; int i, count; id* objects; [aDecoder decodeValueOfObjCType:@encode(int) at:&count]; objects = Malloc(sizeof(id) * count); for(i = 0; i < count; i++) objects[i] = (*imp)(aDecoder, @selector(decodeObject)); [self initWithObjects:objects count:count]; Free(objects); return self; } @end /* NSArray */ /* * Extensions to NSArray */ @implementation NSArray (NSArrayExtensions) /* Sending Messages to Elements */ - (void)makeObjectsPerform:(SEL)aSelector withObject:(id)anObject1 withObject:(id)anObject2 { unsigned int index, count = [self count]; for (index = 0; index < count; index++) [[self objectAtIndex:index] perform:aSelector withObject:anObject1 withObject:anObject2]; } /* Deriving New Arrays */ - (NSArray*)map:(SEL)aSelector { unsigned int index, count = [self count]; id array = [NSMutableArray arrayWithCapacity:count]; for (index = 0; index < count; index++) [array insertObject:[[self objectAtIndex:index] perform:aSelector] atIndex:index]; return array; } - (NSArray*)map:(SEL)aSelector with:anObject { unsigned int index, count = [self count]; id array = [NSMutableArray arrayWithCapacity:count]; for (index = 0; index < count; index++) [array insertObject:[[self objectAtIndex:index] perform:aSelector withObject:anObject] atIndex:index]; return array; } - (NSArray*)map:(SEL)aSelector with:anObject with:otherObject; { unsigned int index, count = [self count]; id array = [NSMutableArray arrayWithCapacity:count]; for (index = 0; index < count; index++) [array insertObject:[[self objectAtIndex:index] perform:aSelector withObject:anObject withObject:otherObject] atIndex:index]; return array; } - (NSArray*)arrayWithObjectsThat:(BOOL(*)(id anObject))comparator; // Returns an array listing the receiver's elements for that comparator // function returns YES { unsigned i, m, n = [self count]; id *objects = Malloc(sizeof(id)*n); id array; for (i = m = 0; i < n; i++) { id obj = [self objectAtIndex:i]; if (comparator(obj)) objects[m++] = obj; } array = [[[isa alloc] initWithObjects:objects count:m] autorelease]; Free(objects); return array; } - (NSArray*)map:(id(*)(id anObject))function objectsThat:(BOOL(*)(id anObject))comparator; // Returns an array listing the objects returned by function applied to // objects for that comparator returns YES { unsigned i, m, n = [self count]; id *objects = Malloc(sizeof(id)*n); id array; for (i = m = 0; i < n; i++) { id obj = [self objectAtIndex:i]; if (comparator(obj)) objects[m++] = function(obj); } array = [[[isa alloc] initWithObjects:objects count:m] autorelease]; Free(objects); return array; } @end /* * NSMutableArray class * * primary methods are * init * initWithCapacity: * initWithObjects:count: * dealloc * count * objectAtIndex: * addObject: * replaceObjectAtIndex:withObject: * insertObject:atIndex: * removeObjectAtIndex: */ @implementation NSMutableArray : NSArray /* Creating and Initializing an NSMutableArray */ + (id)allocWithZone:(NSZone*)zone { return NSAllocateObject( (self == [NSMutableArray class]) ? [NSConcreteMutableArray class] : self, 0, zone); } + (id)arrayWithCapacity:(unsigned int)aNumItems { return [[[self alloc] initWithCapacity:aNumItems] autorelease]; } - (id)init { return [self initWithCapacity:0]; } - (id)initWithCapacity:(unsigned int)aNumItems { [self subclassResponsibility:_cmd]; return self; } - (id)copyWithZone:(NSZone*)zone { return [[NSArray alloc] initWithArray:self copyItems:YES]; } /* Adding Objects */ - (void)addObject:(id)anObject { [self insertObject:anObject atIndex:[self count]]; } - (void)addObjectsFromArray:(NSArray*)anotherArray { unsigned int i, j, n; n = [anotherArray count]; for (i = 0, j = [self count]; i < n; i++) [self insertObject:[anotherArray objectAtIndex:i] atIndex:j++]; } - (void)insertObject:(id)anObject atIndex:(unsigned int)index { [self subclassResponsibility:_cmd]; } /* Removing Objects */ - (void)removeAllObjects { int count = [self count]; while (--count >= 0) [self removeObjectAtIndex:count]; } - (void)removeLastObject { [self removeObjectAtIndex:[self count]-1]; } - (void)removeObject:(id)anObject { unsigned int i, n; n = [self count]; for (i = 0; i < n; i++) { id obj = [self objectAtIndex:i]; if ([obj isEqual:anObject]) { [self removeObjectAtIndex:i]; n--; i--; } } } - (void)removeObjectAtIndex:(unsigned int)index { [self subclassResponsibility:_cmd]; } - (void)removeObjectIdenticalTo:(id)anObject { unsigned int i, n; i = n = [self count]; for (i = 0; i < n; i++) { id obj = [self objectAtIndex:i]; if (obj == anObject) { [self removeObjectAtIndex:i]; n--; i--; } } } static int __cmp_unsigned_ints(unsigned int* i1, unsigned int* i2) { return (*i1 == *i2) ? 0 : ((*i1 < *i2) ? -1 : +1); } - (void)removeObjectsFromIndices:(unsigned int*)indices numIndices:(unsigned int)count; { unsigned int *indexes; int i; if (!count) return; indexes = Malloc(count*sizeof(unsigned int)); memcpy(indexes, indices, count * sizeof(unsigned int)); qsort(indexes, count, sizeof(unsigned int), (int(*)(const void *, const void*))__cmp_unsigned_ints); for (i = count-1; i>=0; i++) [self removeObjectAtIndex:indexes[i]]; Free(indexes); } - (void)removeObjectsInArray:(NSArray*)otherArray { unsigned int i, n = [otherArray count]; for (i = 0; i < n; i++) [self removeObject:[otherArray objectAtIndex:i]]; } - (void)removeObject:(id)anObject inRange:(NSRange)aRange { unsigned int index; for (index = aRange.location-1; index >= aRange.location; index--) if ([anObject isEqual:[self objectAtIndex:index+aRange.location]]) [self removeObjectAtIndex:index+aRange.location]; } - (void)removeObjectIdenticalTo:(id)anObject inRange:(NSRange)aRange { unsigned int index; for (index = aRange.location-1; index >= aRange.location; index--) if (anObject == [self objectAtIndex:index+aRange.location]) [self removeObjectAtIndex:index+aRange.location]; } - (void)removeObjectsInRange:(NSRange)aRange { unsigned int index; for (index = aRange.location-1; index >= aRange.location; index--) [self removeObjectAtIndex:index+aRange.location]; } /* Replacing Objects */ - (void)replaceObjectAtIndex:(unsigned int)index withObject:(id)anObject { [self subclassResponsibility:_cmd]; } - (void)replaceObjectsInRange:(NSRange)rRange withObjectsFromArray:(NSArray*)anArray { [self replaceObjectsInRange:rRange withObjectsFromArray:anArray range:NSMakeRange(0, [anArray count])]; } - (void)replaceObjectsInRange:(NSRange)rRange withObjectsFromArray:(NSArray*)anArray range:(NSRange)aRange { unsigned int index; [self removeObjectsInRange:rRange]; for (index = 0; index < aRange.length; index++) [self insertObject:[anArray objectAtIndex:aRange.location+index] atIndex:rRange.location+index]; } - (void)setArray:(NSArray*)otherArray { [self removeAllObjects]; [self addObjectsFromArray:otherArray]; } - (void)sortUsingFunction: (int(*)(id element1, id element2, void *userData))comparator context:(void*)context { /* Shell sort algorithm taken from SortingInAction - a NeXT example */ #define STRIDE_FACTOR 3 // good value for stride factor is not well-understood // 3 is a fairly good choice (Sedgewick) int c,d, stride; BOOL found; int count = [self count]; stride = 1; while (stride <= count) stride = stride * STRIDE_FACTOR + 1; while(stride > (STRIDE_FACTOR - 1)) { // loop to sort for each value of stride stride = stride / STRIDE_FACTOR; for (c = stride; c < count; c++) { found = NO; d = c - stride; while ((d >= 0) && !found) { // move to left until correct place id a = [self objectAtIndex:d + stride]; id b = [self objectAtIndex:d]; if ((*comparator)(a, b, context) == NSOrderedAscending) { [a retain]; [b retain]; [self replaceObjectAtIndex:d + stride withObject:b]; [self replaceObjectAtIndex:d withObject:a]; d -= stride; // jump by stride factor [a release]; [b release]; } else found = YES; } } } } static int selector_compare(id elem1, id elem2, void* comparator) { return (int)[elem1 perform:(SEL)comparator withObject:elem2]; } - (void)sortUsingSelector:(SEL)comparator { [self sortUsingFunction:selector_compare context:(void*)comparator]; } /* Encoding */ - (Class)classForCoder { return [NSMutableArray class]; } @end /* * Extensions to NSArray */ @implementation NSMutableArray (NSMutableArrayExtensions) - (void)removeObjectsFrom:(unsigned int)index count:(unsigned int)count { if (count) { while (count--) [self removeObjectAtIndex:index+count]; } } - (void)removeObjectsThat:(BOOL(*)(id anObject))comparator { unsigned int index, count = [self count]; for (index = 0; index < count; index++) if (comparator([self objectAtIndex:index])) { [self removeObjectAtIndex:index]; index--; count--; } } @end /* NSMutableArray */ /* * NSArrayEnumerator class */ @implementation _NSArrayEnumerator - (id)initWithArray:(NSArray*)anArray reverse:(BOOL)isReverse { unsigned count = [anArray count]; reverse = isReverse; array = [anArray retain]; index = (reverse) ? (count ? count - 1 : NSNotFound) : (count ? 0 : NSNotFound); return self; } - (void)dealloc { [array release]; [super dealloc]; } - (id)nextObject { id object; NSAssert(array, @"Invalid Array enumerator"); if (index == NSNotFound) return nil; object = [array objectAtIndex:index]; index += reverse ? -1 : +1; if (index == -1 || index >= [array count]) index = NSNotFound; return object; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.