From 0f5a6b4e5ef00a2a4987a712014fa405845a57e4 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Wed, 4 Jul 2012 15:41:45 -0400 Subject: [PATCH] Added CPArray -indexesOfObjectPassingTest methods --- Foundation/CPArray/CPArray.j | 79 ++++++++++++++++++++++++ Tests/Foundation/CPArrayTest.j | 106 ++++++++++++++++++++++++++++++++- 2 files changed, 184 insertions(+), 1 deletion(-) diff --git a/Foundation/CPArray/CPArray.j b/Foundation/CPArray/CPArray.j index 72af3a0a4..8a2dd673c 100755 --- a/Foundation/CPArray/CPArray.j +++ b/Foundation/CPArray/CPArray.j @@ -483,6 +483,85 @@ var concat = Array.prototype.concat, return CPNotFound; } +/*! + Returns the indexes of the objects in the receiver that pass a test in a given Javascript function. + @param predicate The function to apply to objects of the array. The function should have the signature: + @code function(object, index) @endcode + The predicate function should either return a Boolean value that indicates whether the object passed the test, + or nil to stop the search, which will return \c CPNotFound to the sender. + @return A CPIndexSet of the matching object indexes. +*/ +- (CPIndexSet)indexesOfObjectPassingTest:(Function)aPredicate +{ + return [self indexesOfObjectWithOptions:CPEnumerationNormal passingTest:aPredicate context:undefined]; +} + +/*! + Returns the indexes of the objects in the receiver that pass a test in a given Javascript function. + @param predicate The function to apply to objects of the array. The function should have the signature: + @code function(object, index, context) @endcode + The predicate function should either return a Boolean value that indicates whether the object passed the test, + or nil to stop the search, which will return \c CPNotFound to the sender. + @param context An object that contains context information you want passed to the predicate function. + @return A CPIndexSet of the matching object indexes. +*/ +- (CPIndexSet)indexesOfObjectPassingTest:(Function)aPredicate context:(id)aContext +{ + return [self indexesOfObjectWithOptions:CPEnumerationNormal passingTest:aPredicate context:aContext]; +} + +/*! + Returns the indexes of the objects in the receiver that pass a test in a given Javascript function. + @param options Specifies the direction in which the array is searched. Pass CPEnumerationNormal to search forwards + or CPEnumerationReverse to search in reverse. + @param predicate The function to apply to objects of the array. The function should have the signature: + @code function(object, index) @endcode + The predicate function should either return a Boolean value that indicates whether the object passed the test, + or nil to stop the search, which will return CPNotFound to the sender. + @return A CPIndexSet of the matching object indexes. +*/ +- (CPIndexSet)indexesOfObjectWithOptions:(CPEnumerationOptions)options passingTest:(Function)aPredicate +{ + return [self indexesOfObjectWithOptions:options passingTest:aPredicate context:undefined]; +} + +/*! + Returns the indexes of the objects in the receiver that pass a test in a given Javascript function. + @param options Specifies the direction in which the array is searched. Pass CPEnumerationNormal to search forwards + or CPEnumerationReverse to search in reverse. + @param predicate The function to apply to objects of the array. The function should have the signature: + @code function(object, index, context) @endcode + The predicate function should either return a Boolean value that indicates whether the object passed the test, + or nil to stop the search, which will return CPNotFound to the sender. + @param context An object that contains context information you want passed to the predicate function. + @return A CPIndexSet of the matching object indexes. +*/ +- (CPIndexSet)indexesOfObjectWithOptions:(CPEnumerationOptions)options passingTest:(Function)aPredicate context:(id)aContext +{ + // We don't use an enumerator because they return nil to indicate end of enumeration, + // but nil may actually be the value we are looking for, so we have to loop over the array. + if (options & CPEnumerationReverse) + { + var index = [self count] - 1, + stop = -1, + increment = -1; + } + else + { + var index = 0, + stop = [self count], + increment = 1; + } + + var indexes = [CPIndexSet indexSet]; + + for (; index !== stop; index += increment) + if (aPredicate([self objectAtIndex:index], index, aContext)) + [indexes addIndex:index]; + + return indexes; +} + // Sending messages to elements /*! Sends each element in the array a message. diff --git a/Tests/Foundation/CPArrayTest.j b/Tests/Foundation/CPArrayTest.j index a99dfc931..248df12e5 100644 --- a/Tests/Foundation/CPArrayTest.j +++ b/Tests/Foundation/CPArrayTest.j @@ -198,7 +198,6 @@ } context:13] same:1]; } - - (void)test_indexOfObjectWithOptions_passingTest { var array = [[[self class] arrayClass] arrayWithObjects: @@ -357,6 +356,111 @@ } +- (void)test_indexesOfObjectPassingTest_ +{ + var array = [[[self class] arrayClass] arrayWithObjects: + { name:@"Tom", age:7 }, + { name:@"Dick", age:13 }, + { name:@"Harry", age:27 }, + { name:@"Zelda", age:7 }]; + + [self assert:[array indexesOfObjectPassingTest:function() { return YES; }] equals:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, 4)]]; + [self assert:[array indexesOfObjectPassingTest:function() { return NO; }] equals:[CPIndexSet indexSet]]; + [self assert:[array indexesOfObjectPassingTest:function() { return nil; }] equals:[CPIndexSet indexSet]]; + + [self assert:[array indexesOfObjectPassingTest:function(anObject, anIndex) + { + return [anObject.name isEqual:@"Harry"]; + }] equals:[CPIndexSet indexSetWithIndex:2]]; + + var indexSet = [CPIndexSet indexSetWithIndex:0]; + [indexSet addIndex:3]; + + [self assert:[array indexesOfObjectPassingTest:function(anObject, anIndex) + { + return anObject.age === 7; + }] equals:indexSet]; + + [self assert:[array indexesOfObjectPassingTest:function(anObject, anIndex) + { + return [anObject.name isEqual:@"Horton"]; + }] equals:[CPIndexSet indexSet]]; +} + +- (void)test_indexesOfObjectPassingTest_context_ +{ + var array = [[[self class] arrayClass] arrayWithObjects: + { name:@"Tom", age:7 }, + { name:@"Dick", age:13 }, + { name:@"Harry", age:27 }, + { name:@"Zelda", age:7 }]; + + [self assert:[array indexesOfObjectPassingTest:function(anObject, anIndex, aContext) + { + return [anObject.name isEqual:aContext]; + } context:@"Harry"] equals:[CPIndexSet indexSetWithIndex:2]]; + + var indexSet = [CPIndexSet indexSetWithIndex:0]; + [indexSet addIndex:3]; + + [self assert:[array indexesOfObjectPassingTest:function(anObject, anIndex, aContext) + { + return anObject.age === aContext; + } context:7] equals:indexSet]; +} + +- (void)test_indexesOfObjectWithOptions_passingTest +{ + var array = [[[self class] arrayClass] arrayWithObjects: + { name:@"Tom", age:7 }, + { name:@"Dick", age:13 }, + { name:@"Harry", age:27 }, + { name:@"Zelda", age:7 }], + namePredicate = function(anObject, anIndex) + { + return [anObject.name isEqual:@"Harry"]; + }, + agePredicate = function(anObject, anIndex) + { + return anObject.age === 7; + }; + + [self assert:[array indexesOfObjectWithOptions:CPEnumerationNormal passingTest:namePredicate] equals:[CPIndexSet indexSetWithIndex:2]]; + [self assert:[array indexesOfObjectWithOptions:CPEnumerationReverse passingTest:namePredicate] equals:[CPIndexSet indexSetWithIndex:2]]; + + var indexSet = [CPIndexSet indexSetWithIndex:0]; + [indexSet addIndex:3]; + + [self assert:[array indexesOfObjectWithOptions:CPEnumerationNormal passingTest:agePredicate] equals:indexSet]; + [self assert:[array indexesOfObjectWithOptions:CPEnumerationReverse passingTest:agePredicate] equals:indexSet]; +} + +- (void)test_indexesOfObjectWithOptions_passingTest_context +{ + var array = [[[self class] arrayClass] arrayWithObjects: + { name:@"Tom", age:7 }, + { name:@"Dick", age:13 }, + { name:@"Harry", age:27 }, + { name:@"Zelda", age:7 }], + namePredicate = function(anObject, anIndex, aContext) + { + return [anObject.name isEqual:aContext]; + }, + agePredicate = function(anObject, anIndex, aContext) + { + return anObject.age === aContext; + }; + + [self assert:[array indexesOfObjectWithOptions:CPEnumerationNormal passingTest:namePredicate context:@"Harry"] equals:[CPIndexSet indexSetWithIndex:2]]; + [self assert:[array indexesOfObjectWithOptions:CPEnumerationReverse passingTest:namePredicate context:@"Harry"] equals:[CPIndexSet indexSetWithIndex:2]]; + + var indexSet = [CPIndexSet indexSetWithIndex:0]; + [indexSet addIndex:3]; + + [self assert:[array indexesOfObjectWithOptions:CPEnumerationNormal passingTest:agePredicate context:7] equals:indexSet]; + [self assert:[array indexesOfObjectWithOptions:CPEnumerationReverse passingTest:agePredicate context:7] equals:indexSet]; +} + - (void)test_isEqualToArray_ { var arrayClass = [[self class] arrayClass],