Files
cappuccino/Foundation/CPArray.j
T
Tom Robinson ba189afaf5 CPArray -componentsJoinedByString fixed
Moved objj object toString override to CPObject.j

Reviewed by me

[#89 state:resolved responsible:tlrobinson]
2008-10-05 18:34:06 -07:00

1083 lines
29 KiB
Plaintext
Executable File

/*
* 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"
import "CPException.j"
/* @ignore */
@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
/* @ignore */
@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
/*
A mutable array class backed by a JavaScript Array.
There is also a <objj>CPMutableArray</objj> class,
but it is just a child class of this class with an
empty implementation. All mutable functionality is
implemented directly in <objj>CPArray</objj>.
*/
@implementation CPArray : CPObject
/*
Returns a new uninitialized <objj>CPArray</objj>.
*/
+ (id)alloc
{
return [];
}
/*
Returns a new initialized <objj>CPArray</objj>.
*/
+ (id)array
{
return [[self alloc] init];
}
/*
Creates a new array containing the objects in <code>anArray</code>.
@param anArray Objects in this array will be added to the new array
@return a new <objj>CPArray</objj> of the provided objects
*/
+ (id)arrayWithArray:(CPArray)anArray
{
return [[self alloc] initWithArray:anArray];
}
/*
Creates a new array with <code>anObject</code> in it.
@param anObject the object to be added to the array
@return a new <objj>CPArray</objj> containing a single object
*/
+ (id)arrayWithObject:(id)anObject
{
return [[self alloc] initWithObjects:anObject];
}
/*
Creates a new <objj>CPArray</objj> containing all the objects passed as arguments to the method.
@param anObject the objects that will be added to the new array
@return a new <objj>CPArray</objj> containing the argument objects
*/
+ (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;
}
/*
Creates a <objj>CPArray</objj> from a JavaScript array of objects.
@param objects the JavaScript Array
@param aCount the number of objects in the JS Array
@return a new <objj>CPArray</objj> containing the specified objects
*/
+ (id)arrayWithObjects:(id)objects count:(unsigned)aCount
{
return [[self alloc] initWithObjects:objects count:aCount];
}
/*
Initializes the <objj>CPArray</objj>.
@return the initialized array
*/
- (id)init
{
return self;
}
// Creating an Array
/*
Creates a new <objj>CPArray</objj> from <code>anArray</code>.
@param anArray objects in this array will be added to the new array
@return a new <objj>CPArray</objj> containing the objects of <code>anArray</code>
*/
- (id)initWithArray:(CPArray)anArray
{
self = [super init];
if (self)
[self setArray:anArray];
return self;
}
/*
Initializes a the array with the contents of <code>anArray</code>
and optionally performs a deep copy of the objects based on <code>copyItems</code>.
@param anArray the array to copy the data from
@param copyItems if <code>YES</code>, each object will be copied by having a <code>copy</code> message sent to it, and the
returned object will be added to the receiver. Otherwise, no copying will be performed.
@return the initialized array of objects
*/
- (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;
}
/*
initializes
*/
- (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;
}
/*
Initializes the array with a JavaScript array of objects.
@param objects the array of objects to add to the receiver
@param aCount the number of objects in <code>objects</code>
@return the initialized <objj>CPArray</objj>
*/
- (id)initWithObjects:(id)objects count:(unsigned)aCount
{
self = [super init];
if (self)
{
var index = 0;
for(; index < aCount; ++index)
push(objects[index]);
}
return self;
}
/*
Returns a hash of the <objj>CPArray</objj>.
@return an unsigned integer hash
*/
- (unsigned)hash
{
if (self.__address == nil)
self.__address = _objj_generateObjectHash();
return self.__address;
}
// Querying an array
/*
Returns <code>YES</code> if the array contains <code>anObject</code>. Otherwise, it returns <code>NO</code>.
@param anObject the method checks if this object is already in the array
*/
- (BOOL)containsObject:(id)anObject
{
return [self indexOfObject:anObject] != CPNotFound;
}
/*
Returns the number of elements in the array
*/
- (int)count
{
return length;
}
/*
Returns the index of <code>anObject</code> in this array.
If the object is <code>nil</code> or not in the array,
returns <code>CPNotFound</code>. It first attempts to find
a match using <code>isEqual:</code>, then <code>==</code>.
@param anObject the object to search for
*/
- (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;
}
/*
Returns the index of <code>anObject</code> in the array
within <code>aRange</code>. It first attempts to find
a match using <code>isEqual:</code>, then <code>==</code>.
@param anObject the object to search for
@param aRange the range to search within
@return the index of the object, or <code>CPNotFound</code> if it was not found.
*/
- (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;
}
/*
Returns the index of <code>anObject</code> in the array. The test for equality is done using only <code>==</code>.
@param anObject the object to search for
@return the index of the object in the array. <code>CPNotFound</code> if the object is not in the array.
*/
- (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;
}
/*
Returns the index of <code>anObject</code> in the array
within <code>aRange</code>. The test for equality is
done using only <code>==</code>.
@param anObject the object to search for
@param aRange the range to search within
@return the index of the object, or <code>CPNotFound</code> if it was not found.
*/
- (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;
}
/*
Returns the last object in the array. If the array is empty, returns <code>nil</code>/
*/
- (id)lastObject
{
var count = [self count];
if (!count) return nil;
return self[count - 1];
}
/*
Returns the object at index <code>anIndex</code>.
@throws CPRangeException if <code>anIndex</code> is out of bounds
*/
- (id)objectAtIndex:(int)anIndex
{
return self[anIndex];
}
/*
Returns the objects at <code>indexes</code> in a new <objj>CPArray</objj>.
@param indexes the set of indices
@throws CPRangeException if any of the indices is greater than or equal to the length of the array
*/
- (CPArray)objectsAtIndexes:(CPIndexSet)indexes
{
var index = [indexes firstIndex],
objects = [];
while(index != CPNotFound)
{
[objects addObject:self[index]];
index = [indexes indexGreaterThanIndex:index];
}
return objects;
}
/*
Returns an enumerator describing the array sequentially
from the first to the last element. You should not modify
the array during enumeration.
*/
- (CPEnumerator)objectEnumerator
{
return [[_CPArrayEnumerator alloc] initWithArray:self];
}
/*
Returns an enumerator describing the array sequentially
from the last to the first element. You should not modify
the array during enumeration.
*/
- (CPEnumerator)reverseObjectEnumerator
{
return [[_CPReverseArrayEnumerator alloc] initWithArray:self];
}
// Sending messages to elements
/*
Sends each element in the array a message.
@param aSelector the selector of the message to send
@throws CPInvalidArgumentException if <code>aSelector</code> is <code>nil</code>
*/
- (void)makeObjectsPerformSelector:(SEL)aSelector
{
if (!aSelector)
[CPException raise:CPInvalidArgumentException reason:"makeObjectsPerformSelector: 'aSelector' can't be nil"];
var index = 0,
count = length;
for(; index < count; ++index)
objj_msgSend(self[index], aSelector);
}
/*
Sends each element in the array a message with an argument.
@param aSelector the selector of the message to send
@param anObject the first argument of the message
@throws CPInvalidArgumentException if <code>aSelector</code> is <code>nil</code>
*/
- (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)anObject
{
if (!aSelector)
[CPException raise:CPInvalidArgumentException reason:"makeObjectsPerformSelector:withObject 'aSelector' can't be nil"];
var index = 0,
count = length;
for(; index < count; ++index)
objj_msgSend(self[index], aSelector, anObject);
}
// Comparing arrays
/*
Returns the first object found in the receiver (starting at index 0) which is present in the
<code>otherArray</code> as determined by using the <code>-containsObject:</code> method.
@return the first object found, or <code>nil</code> if no common object was found.
*/
- (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;
}
/*
Returns true if anArray contains exactly the same objects as the reciever.
*/
- (BOOL)isEqualToArray:(id)anArray
{
if(length != anArray.length)
return NO;
var index = 0,
count = [self count];
for(; index < count; ++index)
if(!self[index] || !anArray[index] || ![self[index] isEqual:anArray[index]])
return NO;
return YES;
}
// Deriving new arrays
/*
Returns a copy of this array plus <code>anObject</code> inside the copy.
@param anObject the object to be added to the array copy
@throws CPInvalidArgumentException if <code>anObject</code> is <code>nil</code>
@return a new array that should be n+1 in size compared to the receiver.
*/
- (CPArray)arrayByAddingObject:(id)anObject
{
if (!anObject)
[CPException raise:CPInvalidArgumentException
reason:"arrayByAddingObject: object can't be nil"];
var array = [self copy];
array.push(anObject);
return array;
}
/*
Returns a new array which is the concatenation of <code>self</code> and otherArray (in this precise order).
@param anArray the array that will be concatenated to the receiver's copy
*/
- (CPArray)arrayByAddingObjectsFromArray:(CPArray)anArray
{
return slice(0).concat(anArray);
}
/*
- (CPArray)filteredArrayUsingPredicate:(CPPredicate)aPredicate
{
var i= 0,
count = [self count],
array = [CPArray array];
for(; i<count; ++i)
if(aPredicate.evaluateWithObject(self[i]))
array.push(self[i]);
return array;
}
*/
/*
Returns a subarray of the receiver containing the objects found in the specified range <code>aRange</code>.
@param aRange the range of objects to be copied into the subarray
@throws CPRangeException if the specified range exceeds the bounds of the array
*/
- (CPArray)subarrayWithRange:(CPRange)aRange
{
if (aRange.location < 0 || (aRange.location + CPMaxRange(aRange)) > length)
[CPException raise:CPRangeException reason:"subarrayWithRange: aRange out of bounds"];
return slice(aRange.location, maxRange);
}
// Sorting arrays
/*
Not yet described.
*/
- (CPArray)sortedArrayUsingDescriptors:(CPArray)descriptors
{
var sorted = [self copy];
[sorted sortUsingDescriptors:descriptors];
return sorted;
}
/*
Returns an array in which the objects are ordered according
to a sort with <code>aFunction</code>. This invokes
<code>-sortUsingFunction:context</code>.
@param aFunction a JavaScript 'Function' type that compares objects
@param aContext context information
@return a new sorted array
*/
- (CPArray)sortedArrayUsingFunction:(Function)aFunction context:(id)aContext
{
var sorted = [self copy];
[sorted sortUsingFunction:aFunction context:aContext];
return sorted;
}
/*
Returns a new array in which the objects are ordered according to a sort with <code>aSelector</code>.
@param aSelector the selector that will perform object comparisons
*/
- (CPArray)sortedArrayUsingSelector:(SEL)aSelector
{
var sorted = [self copy]
[sorted sortUsingSelector:aSelector];
return sorted;
}
// Working with string elements
/*
Returns a string formed by concatenating the objects in the
receiver, with the specified separator string inserted between each part.
If the element is a Objective-J object, then the <code>description</code>
of that object will be used, otherwise the default JavaScript representation will be used.
@param aString the separator that will separate each object string
@return the string representation of the array
*/
- (CPString)componentsJoinedByString:(CPString)aString
{
// Objective-J objects get "description" called on them automatically when coerced to strings
// (see "objj_object.prototype.toString" at bottom of CPObject.j)
return join(aString);
}
// Creating a description of the array
/*
Returns a human readable description of this array and it's elements.
*/
- (CPString)description
{
var i = 0,
count = [self count],
description = '(';
for(; i < count; ++i)
{
if (self[i].isa) description += [self[i] description];
else description += self[i];
if (i != count - 1) description += ", ";
}
return description + ')';
}
// Collecting paths
/*
Returns a new array subset formed by selecting the elements that have
filename extensions from <code>filterTypes</code>. Only elements
that are of type <objj>CPString</objj> are candidates for inclusion in the returned array.
@param filterTypes an array of <objj>CPString</objj> objects that contain file extensions (without the '.')
@return a new array with matching paths
*/
- (CPArray)pathsMatchingExtensions:(CPArray)filterTypes
{
var index = 0,
count = [self count],
array = [];
for(; index < count; ++index)
if (self[index].isa && [self[index] isKindOfClass:[CPString class]] && [filterTypes containsObject:[self[index] pathExtension]])
array.push(self[index]);
return array;
}
// Key value coding
/*
Sets the key-value for each element in the array.
@param aValue the value for the coding
@param aKey the key for the coding
*/
- (void)setValue:(id)aValue forKey:(CPString)aKey
{
var i = 0,
count = [self count];
for(; i < count; ++i)
[self[i] setValue:aValue forKey:aKey];
}
/*
Returns the value for <code>aKey</code> from each element in the array.
@param aKey the key to return the value for
@return an array of containing a value for each element in the array
*/
- (CPArray)valueForKey:(CPString)aKey
{
var i = 0,
count = [self count],
array = [];
for(; i < count; ++i)
array.push([self[i] valueForKey:aKey]);
return array;
}
// Copying arrays
/*
Makes a copy of the receiver.
@return a new <objj>CPArray</objj> copy
*/
- (id)copy
{
return slice(0);
}
@end
@implementation CPArray(CPMutableArray)
// Creating arrays
/*
Creates an array able to store at least <code>aCapacity</code>
items. Because <objj>CPArray</objj> is backed by JavaScript arrays,
this method ends up simply returning a regular array.
*/
+ (CPArray)arrayWithCapacity:(unsigned)aCapacity
{
return [[self alloc] initWithCapacity:aCapacity];
}
/*
Initializes an array able to store at least <code>aCapacity</code> items. Because <objj>CPArray</objj>
is backed by JavaScript arrays, this method ends up simply returning a regular array.
*/
- (id)initWithCapacity:(unsigned)aCapacity
{
return self;
}
// Adding and replacing objects
/*
Adds <code>anObject</code> to the end of the array.
@param anObject the object to add to the array
*/
- (void)addObject:(id)anObject
{
push(anObject);
}
/*
Adds the objects in <code>anArray</code> to the receiver array.
@param anArray the array of objects to add to the end of the receiver
*/
- (void)addObjectsFromArray:(CPArray)anArray
{
splice.apply(self, [length, 0].concat(anArray));
}
/*
Inserts an object into the receiver at the specified location.
@param anObject the object to insert into the array
@param anIndex the location to insert <code>anObject</code> at
*/
- (void)insertObject:(id)anObject atIndex:(int)anIndex
{
splice(anIndex, 0, anObject);
}
/*
Inserts the objects in the provided array into the receiver at the indexes specified.
@param objects the objects to add to this array
@param anIndexSet the indices for the objects
*/
- (void)insertObjects:(CPArray)objects atIndexes:(CPIndexSet)anIndexSet
{
var index = 0,
position = CPNotFound;
while ((position = [indexes indexGreaterThanIndex:position]) != CPNotFound)
[self insertObject:objects[index++] atindex:position];
}
/*
Replaces the element at <code>anIndex</code> with <code>anObject</code>.
The current element at position <code>anIndex</code> will be removed from the array.
@param anIndex the position in the array to place <code>anObject</code>
*/
- (void)replaceObjectAtIndex:(int)anIndex withObject:(id)anObject
{
self[anIndex] = anObject;
}
/*
Replace the elements at the indices specified by <code>anIndexSet</code> with
the objects in <code>objects</code>.
@param anIndexSet the set of indices to array positions that will be replaced
@param objects the array of objects to place in the specified indices
*/
- (void)replaceObjectsAtIndexes:(CPIndexSet)anIndexSet withObjects:(CPArray)objects
{
var i = 0,
index = [anIndexSet firstIndex];
while(index != CPNotFound)
{
[self replaceObjectAtIndex:index withObject:objects[i++]];
index = [anIndexSet indexGreaterThanIndex:index];
}
}
/*
Replaces some of the receiver's objects with objects from <code>anArray</code>. Specifically, the elements of the
receiver in the range specified by <code>aRange</code>,
with the elements of <code>anArray</code> in the range specified by <code>otherRange</code>.
@param aRange the range of elements to be replaced in the receiver
@param anArray the array to retrieve objects for placement into the receiver
@param otherRange the range of objects in <code>anArray</code> to pull from for placement into the receiver
*/
- (void)replaceObjectsInRange:(CPRange)aRange withObjectsFromArray:(CPArray)anArray range:(CPRange)otherRange
{
if (!otherRange.location && otherRange.length == [anArray count])
[self replaceObjectsInRange:aRange withObjectsFromArray:anArray];
else
splice.apply(self, [aRange.location, aRange.length].concat([anArray subarrayWithRange:otherRange]));
}
/*
Replaces some of the receiver's objects with the objects from
<code>anArray</code>. Specifically, the elements of the
receiver in the range specified by <code>aRange</code>.
@param aRange the range of elements to be replaced in the receiver
@param anArray the array to retrieve objects for placement into the receiver
*/
- (void)replaceObjectsInRange:(CPRange)aRange withObjectsFromArray:(CPArray)anArray
{
splice.apply(self, [aRange.location, aRange.length].concat(anArray));
}
/*
Sets the contents of the receiver to be identical to the contents of <code>anArray</code>.
@param anArray the array of objects used to replace the receiver's objects
*/
- (void)setArray:(CPArray)anArray
{
if(self == anArray) return;
splice.apply(self, [0, length].concat(anArray));
}
// Removing Objects
/*
Removes all objects from this array.
*/
- (void)removeAllObjects
{
splice(0, length);
}
/*
Removes the last object from the array.
*/
- (void)removeLastObject
{
pop();
}
/*
Removes all entries of <code>anObject</code> from the array.
@param anObject the object whose entries are to be removed
*/
- (void)removeObject:(id)anObject
{
[self removeObject:anObject inRange:CPMakeRange(0, length)];
}
/*
Removes all entries of <code>anObject</code> from the array, in the range specified by <code>aRange</code>.
@param anObject the object to remove
@param aRange the range to search in the receiver for the object
*/
- (void)removeObject:(id)anObject inRange:(CPRange)aRange
{
var index;
while ((index = [self indexOfObject:anObject inRange:aRange]) != CPNotFound)
{
[self removeObjectAtIndex:index];
aRange = CPIntersectionRange(CPMakeRange(index, length - index), aRange);
}
}
/*
Removes the object at <code>anIndex</code>.
@param anIndex the location of the element to be removed
*/
- (void)removeObjectAtIndex:(int)anIndex
{
splice(anIndex, 1);
}
/*
Removes the objects at the indices specified by <code>CPIndexSet</code>.
@param anIndexSet the indices of the elements to be removed from the array
*/
- (void)removeObjectsAtIndexes:(CPIndexSet)anIndexSet
{
var index = [anIndexSet lastIndex];
while (index != CPNotFound)
{
[self removeObjectAtIndex:index];
index = [anIndexSet indexSmallerThanIndex:index];
}
}
/*
Remove the first instance of <code>anObject</code> from the array.
The search for the object is done using <code>==</code>.
@param anObject the object to remove
*/
- (void)removeObjectIdenticalTo:(id)anObject
{
[self removeObjectIdenticalTo:anObject inRange:CPMakeRange(0, length)];
}
/*
Remove the first instance of <code>anObject</code> from the array,
within the range specified by <code>aRange</code>.
The search for the object is done using <code>==</code>.
@param anObject the object to remove
@param aRange the range in the array to search for the object
*/
- (void)removeObjectIdenticalTo:(id)anObject inRange:(CPRange)aRange
{
var index;
while ((index = [self indexOfObjectIdenticalTo:anObject inRange:aRange]) != CPNotFound)
{
[self removeObjectAtIndex:index];
aRange = CPIntersectionRange(CPMakeRange(index, length - index), aRange);
}
}
/*
Remove the objects in <code>anArray</code> from the receiver array.
@param anArray the array of objects to remove from the receiver
*/
- (void)removeObjectsInArray:(CPArray)anArray
{
var index = 0,
count = [anArray count];
for (; index < count; ++index)
[self removeObject:anArray[index]];
}
/*
Removes all the objects in the specified range from the receiver.
@param aRange the range of objects to remove
*/
- (void)removeObjectsInRange:(CPRange)aRange
{
splice(aRange.location, aRange.length);
}
// Rearranging objects
/*
Swaps the elements at the two specified indices.
@param anIndex the first index to swap from
@param otherIndex the second index to swap from
*/
- (void)exchangeObjectAtIndex:(unsigned)anIndex withObjectAtIndex:(unsigned)otherIndex
{
var temporary = self[anIndex];
self[anIndex] = self[otherIndex];
self[otherIndex] = temporary;
}
- (CPArray)sortUsingDescriptors:(CPArray)descriptors
{
sort(function(lhs, rhs)
{
var i = 0,
count = [descriptors count],
result = CPOrderedSame;
while(i < count)
if((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
return result;
return result;
});
}
/*
Sorts the receiver array using a JavaScript function as a comparator, and a specified context.
@param aFunction a JavaScript function that will be called to compare objects
@param aContext an object that will be passed to <code>aFunction</code> with comparison
*/
- (void)sortUsingFunction:(Function)aFunction context:(id)aContext
{
sort(function(lhs, rhs) { return aFunction(lhs, rhs, aContext); });
}
/*
Sorts the receiver array using an Objective-J method as a comparator.
@param aSelector the selector for the method to call for comparison
*/
- (void)sortUsingSelector:(SEL)aSelector
{
sort(function(lhs, rhs) { return objj_msgSend(lhs, aSelector, rhs); });
}
@end
@implementation CPArray (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
return [aCoder _decodeArrayOfObjectsForKey:@"CP.objects"];
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder _encodeArrayOfObjects:self forKey:@"CP.objects"];
}
@end
/*
This class is just an empty subclass of <objj>CPArray</objj>.
<objj>CPArray</objj> already implements mutable methods and
this class only exists for source compatability.
*/
@implementation CPMutableArray : CPArray
@end
Array.prototype.isa = CPArray;
[CPArray initialize];