/* * CPArray.j * Foundation * * Created by Francisco Tolmasky. * Copyright 2008, 280 North, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ import "CPObject.j" import "CPRange.j" import "CPEnumerator.j" import "CPSortDescriptor.j" @implementation _CPArrayEnumerator : CPEnumerator { CPArray _array; int _index; } - (id)initWithArray:(CPArray)anArray { self = [super init]; if (self) { _array = anArray; _index = -1; } return self; } - (id)nextObject { if (++_index >= [_array count]) return nil; return _array[_index]; } @end @implementation _CPReverseArrayEnumerator : CPEnumerator { CPArray _array; int _index; } - (id)initWithArray:(CPArray)anArray { self = [super init]; if (self) { _array = anArray; _index = [_array count]; } return self; } - (id)nextObject { if (--_index < 0) return nil; return _array[_index]; } @end @implementation CPArray : CPObject + (id)alloc { return []; } + (id)array { return [[self alloc] init]; } + (id)arrayWithArray:(CPArray)anArray { return [[self alloc] initWithArray:anArray]; } + (id)arrayWithObject:(id)anObject { return [[self alloc] initWithObjects:anObject]; } + (id)arrayWithObjects:(id)anObject, ... { var i = 2, array = [[self alloc] init], argument; for(; i < arguments.length && (argument = arguments[i]) != nil; ++i) array.push(argument); return array; } + (id)arrayWithObjects:(id)objects count:(unsigned)aCount { return [[self alloc] initWithObjects:objects count:aCount]; } - (id)init { return self; } // Creating an Array - (id)initWithArray:(CPArray)anArray { self = [super init]; if (self) [self setArray:anArray]; return self; } - (id)initWithArray:(CPArray)anArray copyItems:(BOOL)copyItems { if (!copyItems) return [self initWithArray:anArray]; self = [super init]; if (self) { var index = 0, count = [anArray count]; for(; index < count; ++i) { if (anArray[i].isa) self[i] = [anArray copy]; // Do a deep/shallow copy? else self[i] = anArray; } } return self; } - (id)initWithObjects:(Array)anObject, ... { // The arguments array contains self and _cmd, so the first object is at position 2. var i = 2, argument; for(; i < arguments.length && (argument = arguments[i]) != nil; ++i) push(argument); return self; } - (id)initWithObjects:(id)objects count:(unsigned)aCount { self = [super init]; if (self) { var index = 0; for(; index < aCount; ++index) push(objects[index]); } return self; } - (unsigned)hash { if (self.__address == nil) self.__address = _objj_generateObjectHash(); return self.__address; } // Querying an array - (BOOL)containsObject:(id)anObject { return [self indexOfObject:anObject] != CPNotFound; } - (int)count { return length; } - (int)indexOfObject:(id)anObject { if (anObject === nil) return CPNotFound; var i = 0, count = length; // Only use isEqual: if our object is a CPObject. if (anObject.isa) { for(; i < count; ++i) if([self[i] isEqual:anObject]) return i; } // If indexOf exists, use it since it's probably // faster than anything we can implement. else if (self.indexOf) return indexOf(anObject); // Last resort, do a straight forward linear O(N) search. else for(; i < count; ++i) if(self[i] == anObject) return i; return CPNotFound; } - (int)indexOfObject:(id)anObject inRange:(CPRange)aRange { if (anObject === nil) return CPNotFound; var i = aRange.location, count = MIN(CPMaxRange(aRange), length); // Only use isEqual: if our object is a CPObject. if (anObject.isa) { for(; i < count; ++i) if([self[i] isEqual:anObject]) return i; } // Last resort, do a straight forward linear O(N) search. else for(; i < count; ++i) if(self[i] == anObject) return i; return CPNotFound; } - (int)indexOfObjectIdenticalTo:(id)anObject { if (anObject === nil) return CPNotFound; // If indexOf exists, use it since it's probably // faster than anything we can implement. if (self.indexOf) return indexOf(anObject); // Last resort, do a straight forward linear O(N) search. else { var index = 0, count = length; for(; index < count; ++index) if(self[index] == anObject) return index; } return CPNotFound; } - (int)indexOfObjectIdenticalTo:(id)anObject inRange:(CPRange)aRange { if (anObject === nil) return CPNotFound; // If indexOf exists, use it since it's probably // faster than anything we can implement. if (self.indexOf) { var index = indexOf(anObject, aRange.location); if (CPLocationInRange(index, aRange)) return index; } // Last resort, do a straight forward linear O(N) search. else { var index = aRange.location, count = MIN(CPMaxRange(aRange), length); for(; index < count; ++index) if(self[index] == anObject) return index; } return CPNotFound; } - (id)lastObject { var count = [self count]; if (!count) return nil; return self[count - 1]; } - (id)objectAtIndex:(int)anIndex { return self[anIndex]; } - (CPArray)objectsAtIndexes:(CPIndexSet)indexes { var index = [indexes firstIndex], objects = []; while(index != CPNotFound) { [objects addObject:self[index]]; index = [indexes indexGreaterThanIndex:index]; } return objects; } - (CPEnumerator)objectEnumerator { return [[_CPArrayEnumerator alloc] initWithArray:self]; } - (CPEnumerator)reverseObjectEnumerator { return [[_CPReverseArrayEnumerator alloc] initWithArray:self]; } // Sending messages to elements - (void)makeObjectsPerformSelector:(SEL)aSelector { var index = 0, count = length; for(; index < count; ++index) objj_msgSend(self[index], aSelector); } - (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)anObject { var index = 0, count = length; for(; index < count; ++index) objj_msgSend(self[index], aSelector, anObject); } // Comparing arrays - (id)firstObjectCommonWithArray:(CPArray)anArray { if (![anArray count] || ![self count]) return nil; var i = 0, count = [self count]; for(; i < count; ++i) if([anArray containsObject:self[i]]) return self[i]; return nil; } - (BOOL)isEqualToArray:(id)anArray { if(length != anArray.length) return NO; var index = 0, count = [self count]; for(; index < count; ++index) if(self[index] != anObject && (!self[index].isa || !anObject.isa || ![self[index] isEqual:anObject])) return NO; return YES; } // Deriving new arrays - (CPArray)arrayByAddingObject:(id)anObject { var array = [self copy]; array.push(anObject); return array; } - (CPArray)arrayByAddingObjectsFromArray:(CPArray)anArray { return slice(0).concat(anArray); } /* - (CPArray)filteredArrayUsingPredicate:(CPPredicate)aPredicate { var i= 0, count = [self count], array = [CPArray array]; for(; i