/* NSArray.m Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea. All rights reserved. Author: Mircea Oancea 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "NSConcreteArray.h" #include "NSObject+PropLists.h" /* * NSArray Implementation * * primary methods are * init * initWithObjects:count: * dealloc * count * objectAtIndex: */ @implementation NSArray static Class NSArrayClass = Nil; static Class NSMutableArrayClass = Nil; static Class NSConcreteArrayClass = Nil; /* Allocating and Initializing an Array */ + (id)allocWithZone:(NSZone*)zone { if (NSArrayClass == Nil) NSArrayClass = [NSArray class]; if (NSConcreteArrayClass == Nil) NSConcreteArrayClass = [NSConcreteArray class]; return NSAllocateObject( (self == NSArrayClass) ? NSConcreteArrayClass : (Class)self, 0, zone); } + (id)array { return AUTORELEASE([[self alloc] init]); } + (id)arrayWithObject:(id)anObject { return AUTORELEASE([[self alloc] initWithObjects:&anObject count:1]); } + (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]; } lfFree(objects); return AUTORELEASE(array); } + (id)arrayWithArray:(NSArray*)anotherArray { return AUTORELEASE([[self alloc] initWithArray:anotherArray]); } + (id)arrayWithContentsOfFile:(NSString *)fileName { volatile id plist = nil; NSString *format = @"%@: Caught exception %@ with reason %@ "; NS_DURING { plist = NSParsePropertyListFromFile(fileName); if (NSArrayClass == Nil) NSArrayClass = [NSArray class]; if (![plist isKindOfClass:NSArrayClass]) plist = nil; } NS_HANDLER { NSLog(format, self, [localException name], [localException reason]); plist = nil; } NS_ENDHANDLER; return plist; } + (id)arrayWithContentsOfURL:(NSURL *)_url { id plist; if ([_url isFileURL]) return [self arrayWithContentsOfFile:[_url path]]; if (NSArrayClass == Nil) NSArrayClass = [NSArray class]; plist = [[NSString stringWithContentsOfURL:_url] propertyList]; if (![plist isKindOfClass:NSArrayClass]) return nil; return plist; } + (id)arrayWithObjects:(id*)objects count:(unsigned int)count { return AUTORELEASE([[self alloc] initWithObjects:objects count:count]); } - (NSArray*)arrayByAddingObject:(id)anObject { int i, count = [self count]; id array; id *objects; objects = Malloc(sizeof(id) * (count + 1)); { for (i = 0; i < count; i++) objects[i] = [self objectAtIndex:i]; objects[i] = anObject; if (NSArrayClass == Nil) NSArrayClass = [NSArray class]; array = AUTORELEASE([[NSArrayClass alloc] initWithObjects:objects count:count+1]); } lfFree(objects); return array; } - (NSArray*)arrayByAddingObjectsFromArray:(NSArray*)anotherArray; { unsigned int i, count = [self count], another = [anotherArray count]; id array; id *objects; 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]; if (NSArrayClass == Nil) NSArrayClass = [NSArray class]; array = AUTORELEASE([[NSArrayClass alloc] initWithObjects:objects count:count + another]); } lfFree(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; if (count == 0) return [self initWithObjects:NULL count:0]; objects = Malloc(sizeof(id) * count); { for (i = 0; i < count; i++) { objects[i] = flag ? [anotherArray objectAtIndex:i] : AUTORELEASE([[anotherArray objectAtIndex:i] copyWithZone:NULL]); } self = [self initWithObjects:objects count:count]; } lfFree(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 = [self initWithObjects:objects count:count]; } lfFree(objects); return self; } - (id)initWithObjects:(id*)objects count:(unsigned int)count { [self subclassResponsibility:_cmd]; return self; } - (id)initWithContentsOfFile:(NSString*)fileName { NSArray *plist; if (NSArrayClass == Nil) NSArrayClass = [NSArray class]; if ((plist = [NSArrayClass arrayWithContentsOfFile:fileName])) { return [self initWithArray:plist]; } else { self = AUTORELEASE(self); return nil; } } - (id)initWithContentsOfURL:(NSURL *)_url { NSArray *plist; if (NSArrayClass == Nil) NSArrayClass = [NSArray class]; if ((plist = [NSArrayClass arrayWithContentsOfURL:_url])) { return [self initWithArray:plist]; } else { self = AUTORELEASE(self); return nil; } } /* 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 { int count = [self count]; return count ? [self objectAtIndex:count - 1] : nil; } - (id)objectAtIndex:(unsigned int)index { [self subclassResponsibility:_cmd]; return self; } - (void)getObjects:(id *)buffer { unsigned i, count = [self count]; for (i = 0; i < count; i++) { buffer[i] = [self objectAtIndex: i]; } } - (void)getObjects:(id *)buffer range:(NSRange)range { /* naive implementation, to be fixed ... */ return [[self subarrayWithRange:range] getObjects:buffer]; } - (NSEnumerator *)objectEnumerator { return AUTORELEASE([[_NSArrayEnumerator alloc] initWithArray:self reverse:NO]); } - (NSEnumerator *)reverseObjectEnumerator { return AUTORELEASE([[_NSArrayEnumerator alloc] initWithArray:self reverse:YES]); } /* Sending Messages to Elements */ - (void)makeObjectsPerformSelector:(SEL)aSelector { unsigned int index, count = [self count]; for (index = 0; index < count; index++) [[self objectAtIndex:index] performSelector:aSelector]; } - (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)anObject { unsigned int index, count = [self count]; for (index = 0; index < count; index++) [[self objectAtIndex:index] performSelector:aSelector withObject:anObject]; } /* Obsolete methods */ - (void)makeObjectsPerform:(SEL)aSelector { unsigned int index, count = [self count]; for (index = 0; index < count; index++) [[self objectAtIndex:index] performSelector:aSelector]; } - (void)makeObjectsPerform:(SEL)aSelector withObject:(id)anObject { unsigned int index, count = [self count]; for (index = 0; index < count; index++) [[self objectAtIndex:index] performSelector: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++) { register id o1, o2; o1 = [self objectAtIndex:index]; o2 = [otherArray objectAtIndex:index]; if (![o1 isEqual:o2]) return NO; } return YES; } /* Deriving New Arrays */ - (NSArray *)sortedArrayUsingFunction: (int(*)(id element1, id element2, void *userData))comparator context:(void *)context { NSMutableArray *sortedArray; NSArray *result; sortedArray = [self mutableCopy]; [sortedArray sortUsingFunction:comparator context:context]; result = [sortedArray copy]; RELEASE(sortedArray); return AUTORELEASE(result); } static int compare(id elem1, id elem2, void* comparator) { return (int)(long)[elem1 performSelector: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; objects = Malloc(sizeof(id) * range.length); { for (index = 0; index < range.length; index++) objects[index] = [self objectAtIndex:range.location+index]; if (NSArrayClass == Nil) NSArrayClass = [NSArray class]; array = AUTORELEASE([[NSArrayClass alloc] initWithObjects:objects count:range.length]); } lfFree(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 > 0) { NSMutableString* string = [NSMutableString new]; id elem; SEL sel; IMP imp; CREATE_AUTORELEASE_POOL(pool); elem = [self objectAtIndex:0]; sel = @selector(appendString:); 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); } RELEASE(pool); return AUTORELEASE(string); } return @""; } /* Creating a String Description of the Array */ - (NSString *)propertyListStringWithLocale:(NSDictionary *)_locale indent:(unsigned int)_indent { return [self descriptionWithLocale:_locale indent:_indent]; } - (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 object; id stringRepresentation; unsigned int index; CREATE_AUTORELEASE_POOL(pool); object = [self objectAtIndex:0]; stringRepresentation = [object propertyListStringWithLocale:locale indent:indent1]; (*imp)(description, sel, indentation); (*imp)(description, sel, stringRepresentation); for (index = 1; index < count; index++) { object = [self objectAtIndex:index]; stringRepresentation = [object propertyListStringWithLocale:locale indent:indent1]; (*imp)(description, sel, @",\n"); (*imp)(description, sel, indentation); (*imp)(description, sel, stringRepresentation); } RELEASE(pool); } (*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)hash { return [self count]; } - (BOOL)isEqual:(id)anObject { if (NSArrayClass == Nil) NSArrayClass = [NSArray class]; if (![anObject isKindOfClass:NSArrayClass]) return NO; return [self isEqualToArray:anObject]; } /* Copying */ - (id)copyWithZone:(NSZone *)zone { if (NSShouldRetainWithZone(self, zone)) return RETAIN(self); else { if (NSArrayClass == Nil) NSArrayClass = [NSArray class]; return [[NSArrayClass allocWithZone:zone] initWithArray:self copyItems:NO]; } } - (id)mutableCopyWithZone:(NSZone*)zone { if (NSMutableArrayClass == Nil) NSMutableArrayClass = [NSMutableArray class]; return [[NSMutableArrayClass alloc] initWithArray:self]; } /* Encoding */ - (Class)classForCoder { if (NSArrayClass == Nil) NSArrayClass = [NSArray class]; return NSArrayClass; } - (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; [aDecoder decodeValueOfObjCType:@encode(int) at:&count]; if (count > 0) { id* objects; objects = Malloc(sizeof(id) * count); { for(i = 0; i < count; i++) objects[i] = (*imp)(aDecoder, @selector(decodeObject)); self = [self initWithObjects:objects count:count]; } lfFree(objects); } else { self = [self init]; // empty array } 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] performSelector:aSelector withObject:anObject1 withObject:anObject2]; } /* Deriving New Arrays */ - (NSArray *)map:(SEL)aSelector { unsigned int index, count = [self count]; id array; if (NSMutableArrayClass == Nil) NSMutableArrayClass = [NSMutableArray class]; array = [NSMutableArrayClass arrayWithCapacity:count]; for (index = 0; index < count; index++) { [array insertObject:[[self objectAtIndex:index] performSelector:aSelector] atIndex:index]; } return array; } - (NSArray *)map:(SEL)aSelector with:(id)anObject { unsigned int index, count = [self count]; id array; if (NSMutableArrayClass == Nil) NSMutableArrayClass = [NSMutableArray class]; array = [NSMutableArrayClass arrayWithCapacity:count]; for (index = 0; index < count; index++) { [array insertObject:[[self objectAtIndex:index] performSelector:aSelector withObject:anObject] atIndex:index]; } return array; } - (NSArray *)map:(SEL)aSelector with:(id)anObject with:(id)otherObject; { unsigned int index, count = [self count]; id array; if (NSMutableArrayClass == Nil) NSMutableArrayClass = [NSMutableArray class]; array = [NSMutableArrayClass arrayWithCapacity:count]; for (index = 0; index < count; index++) { [array insertObject:[[self objectAtIndex:index] performSelector: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; id array; objects = Malloc(sizeof(id) * n); { for (i = m = 0; i < n; i++) { id obj = [self objectAtIndex:i]; if (comparator(obj)) objects[m++] = obj; } array = AUTORELEASE([[[self class] alloc] initWithObjects:objects count:m]); } lfFree(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; id array; objects = Malloc(sizeof(id) * n); { for (i = m = 0; i < n; i++) { id obj = [self objectAtIndex:i]; if (comparator(obj)) objects[m++] = function(obj); } array = AUTORELEASE([[[self class] alloc] initWithObjects:objects count:m]); } lfFree(objects); return array; } @end /* * NSMutableArray class * * primary methods are * init * initWithCapacity: * initWithObjects:count: * dealloc * count * objectAtIndex: * addObject: * replaceObjectAtIndex:withObject: * insertObject:atIndex: * removeObjectAtIndex: */ @implementation NSMutableArray + (id)arrayWithContentsOfFile:(NSString *)fileName { id array; if ((array = [super arrayWithContentsOfFile:fileName])) { if (NSMutableArrayClass == Nil) NSMutableArrayClass = [NSMutableArray class]; if (![array isKindOfClass:NSMutableArrayClass]) { array = [[NSMutableArrayClass alloc] initWithArray:array]; array = AUTORELEASE(array); } } return array; } /* Creating and Initializing an NSMutableArray */ + (id)allocWithZone:(NSZone*)zone { static Class NSConcreteMutableArrayClass = Nil; if (NSMutableArrayClass == Nil) NSMutableArrayClass = [NSMutableArray class]; if (NSConcreteMutableArrayClass == Nil) NSConcreteMutableArrayClass = [NSConcreteMutableArray class]; return NSAllocateObject( (self == NSMutableArrayClass) ? NSConcreteMutableArrayClass : (Class)self, 0, zone); } + (id)arrayWithCapacity:(unsigned int)aNumItems { return AUTORELEASE([[self alloc] initWithCapacity:aNumItems]); } - (id)init { return [self initWithCapacity:0]; } - (id)initWithCapacity:(unsigned int)aNumItems { [self subclassResponsibility:_cmd]; return self; } - (id)copyWithZone:(NSZone*)zone { if (NSArrayClass == Nil) NSArrayClass = [NSArray class]; return [[NSArrayClass 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]]; } lfFree(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) register int c,d, stride; BOOL found; int count; id (*objAtIdx)(id, SEL, unsigned int); if ((count = [self count]) < 2) return; objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)]; 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 register id a = objAtIdx(self, @selector(objectAtIndex:), d + stride); register id b = objAtIdx(self, @selector(objectAtIndex:), d); if ((*comparator)(a, b, context) == NSOrderedAscending) { #if !LIB_FOUNDATION_BOEHM_GC [a retain]; [b retain]; #endif [self replaceObjectAtIndex:(d + stride) withObject:b]; [self replaceObjectAtIndex:d withObject:a]; d -= stride; // jump by stride factor #if !LIB_FOUNDATION_BOEHM_GC [a release]; [b release]; #endif } else found = YES; } } } } static int selector_compare(id elem1, id elem2, void* comparator) { return (int)(long)[elem1 performSelector:(SEL)comparator withObject:elem2]; } - (void)sortUsingSelector:(SEL)comparator { [self sortUsingFunction:selector_compare context:(void*)comparator]; } /* Encoding */ - (Class)classForCoder { if (NSMutableArrayClass == Nil) NSMutableArrayClass = [NSMutableArray class]; return NSMutableArrayClass; } @end /* NSMutableArray */ /* * 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(NSMutableArrayExtensions) */ /* * NSArrayEnumerator class */ @implementation _NSArrayEnumerator - (id)initWithArray:(NSArray*)anArray reverse:(BOOL)isReverse { unsigned count = [anArray count]; self->reverse = isReverse; self->array = RETAIN(anArray); self->index = (reverse) ? (count ? count - 1 : NSNotFound) : (count ? 0 : NSNotFound); return self; } - (void)dealloc { RELEASE(self->array); [super dealloc]; } - (id)nextObject { id object; NSAssert(array, @"Invalid Array enumerator"); if (self->index == NSNotFound) return nil; object = [self->array objectAtIndex:index]; if (self->reverse) { if (self->index == 0) self->index = NSNotFound; else self->index--; } else { self->index++; if (self->index >= [array count]) self->index = NSNotFound; } return object; } @end /* _NSArrayEnumerator */ /* Local Variables: c-basic-offset: 4 tab-width: 8 End: */