From c4dc9c8bdbfe6ec413ae43454df63886bc1587ad Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Sun, 15 Jul 2012 09:27:04 -0700 Subject: [PATCH] CPDictionary key methods keysOfEntriesPassingTest: keysOfEntriesWithOptions:passingTest: keysSortedByValueUsingComparator: --- Foundation/CPDictionary.j | 83 +++++++++++++++++---- Tests/Foundation/CPDictionaryTest.j | 111 ++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+), 13 deletions(-) diff --git a/Foundation/CPDictionary.j b/Foundation/CPDictionary.j index 17e3d14bb3..a20bb59a96 100755 --- a/Foundation/CPDictionary.j +++ b/Foundation/CPDictionary.j @@ -25,6 +25,7 @@ @import "CPException.j" @import "CPNull.j" @import "CPObject.j" +#import "Ref.h" /* @ignore */ @implementation _CPDictionaryValueEnumerator : CPEnumerator @@ -359,30 +360,86 @@ var count = _keys.length, index = 0, matchingKeys = [], - thisKey = nil, - thisValue = nil; + key = nil, + value = nil; for (; index < count; ++index) { - thisKey = _keys[index]; - thisValue = _buckets[thisKey]; - if (thisValue.isa && anObject && anObject.isa && [thisValue respondsToSelector:@selector(isEqual:)] && [thisValue isEqual:anObject]) - matchingKeys.push(thisKey); - else if (thisValue === anObject) - matchingKeys.push(thisKey); + key = _keys[index]; + value = _buckets[key]; + + if (value.isa && anObject && anObject.isa && [value respondsToSelector:@selector(isEqual:)] && [value isEqual:anObject]) + matchingKeys.push(key); + else if (value === anObject) + matchingKeys.push(key); } return matchingKeys; } +- (CPArray)keysOfEntriesPassingTest:(Function /*(id key, id obj, @ref BOOL stop)*/)predicate +{ + return [self keysOfEntriesWithOptions:CPEnumerationNormal passingTest:predicate]; +} + +- (CPArray)keysOfEntriesWithOptions:(CPEnumerationOptions)options passingTest:(Function /*(id key, id obj, @ref BOOL stop)*/)predicate +{ + if (options & CPEnumerationReverse) + { + var index = [_keys count] - 1, + stop = -1, + increment = -1; + } + else + { + var index = 0, + stop = [_keys count], + increment = 1; + } + + var matchingKeys = [], + key = nil, + value = nil, + shouldStop = NO, + stopRef = AT_REF(shouldStop); + + for (; index !== stop; index += increment) + { + key = _keys[index]; + value = _buckets[key]; + + if (predicate(key, value, stopRef)) + matchingKeys.push(key); + + if (shouldStop) + break; + } + + return matchingKeys; +} + +- (CPArray)keysSortedByValueUsingComparator:(Function /*(id obj1, id obj2)*/)comparator +{ + return [[self allKeys] sortedArrayUsingFunction:function(a, b) + { + a = [self objectForKey:a]; + b = [self objectForKey:b]; + + return comparator(a, b); + } + ]; +} + - (CPArray)keysSortedByValueUsingSelector:(SEL)theSelector { - return [[self allKeys] sortedArrayUsingFunction:function(a, b) { - a = [self objectForKey:a]; - b = [self objectForKey:b]; + return [[self allKeys] sortedArrayUsingFunction:function(a, b) + { + a = [self objectForKey:a]; + b = [self objectForKey:b]; - return [a performSelector:theSelector withObject:b]; - }]; + return [a performSelector:theSelector withObject:b]; + } + ]; } /*! diff --git a/Tests/Foundation/CPDictionaryTest.j b/Tests/Foundation/CPDictionaryTest.j index 2760de479d..e5c8e9012d 100644 --- a/Tests/Foundation/CPDictionaryTest.j +++ b/Tests/Foundation/CPDictionaryTest.j @@ -206,6 +206,77 @@ }]; } +- (void)testKeysOfEntriesPassingTest +{ + var numberDictionary = [CPDictionary dictionaryWithJSObject:{ + key1: 5, + key2: 1, + key3: 4, + key4: 2, + key5: 3 + }]; + + var expected = [@"key1", @"key3"], + result = [numberDictionary keysOfEntriesPassingTest:function(key, value, stop) + { + return value >= 4; + }]; + + [self assert:expected equals:result]; + + expected = [@"key3", @"key1"], + result = [numberDictionary keysOfEntriesWithOptions:CPEnumerationReverse passingTest:function(key, value, stop) + { + return value >= 4; + }]; + + [self assert:expected equals:result]; + + expected = [@"key3"], + result = [numberDictionary keysOfEntriesWithOptions:CPEnumerationReverse passingTest:function(key, value, stop) + { + if (value === 4) + stop(YES); + + return value >= 4; + }]; + + [self assert:expected equals:result]; + + var stringDictionary = [CPDictionary dictionaryWithJSObject:{ + a: @"Z", b: @"y", c: @"X", d: @"W", + e: @"V", f: @"u", g: @"T", h: @"s", + i: @"R", j: @"q", k: @"P", l: @"o" + }]; + + expected = [@"j", @"k", @"l"]; + result = [stringDictionary keysOfEntriesPassingTest:function(key, value, stop) + { + return value.toLowerCase() <= @"q"; + }]; + + [self assert:expected equals:result]; + + expected = [@"l", @"k", @"j"]; + result = [stringDictionary keysOfEntriesWithOptions:CPEnumerationReverse passingTest:function(key, value, stop) + { + return value.toLowerCase() <= @"q"; + }]; + + [self assert:expected equals:result]; + + expected = [@"j", @"k"]; + result = [stringDictionary keysOfEntriesPassingTest:function(key, value, stop) + { + if (value === @"P") + stop(YES); + + return value.toLowerCase() <= "q"; + }]; + + [self assert:expected equals:result]; +} + - (void)testKeysSortedByValueUsingSelector { var numberDictionary = [CPDictionary dictionaryWithJSObject:{ @@ -237,6 +308,46 @@ [self assert:expected equals:result]; } +- (void)testKeysSortedByValueUsingComparator +{ + var numberDictionary = [CPDictionary dictionaryWithJSObject:{ + key1: 5, + key2: 1, + key3: 4, + key4: 2, + key5: 3 + }]; + + var expected = [@"key2", @"key4", @"key5", @"key3", @"key1"], + result = [numberDictionary keysSortedByValueUsingComparator:function(obj1, obj2) + { + return obj1 < obj2 ? CPOrderedAscending : CPOrderedDescending; + }]; + + [self assert:expected equals:result]; + + var stringDictionary = [CPDictionary dictionaryWithJSObject:{ + a: @"Z", b: @"y", c: @"X", d: @"W", + e: @"V", f: @"u", g: @"T", h: @"s", + i: @"R", j: @"q", k: @"P", l: @"o" + }]; + + expected = [@"l", @"k", @"j", @"i", @"h", @"g", @"f", @"e", @"d", @"c", @"b", @"a"]; + result = [stringDictionary keysSortedByValueUsingComparator:function(obj1, obj2) + { + return obj1.toLowerCase() < obj2.toLowerCase() ? CPOrderedAscending : CPOrderedDescending; + }]; + + [self assert:expected equals:result]; + + expected = [@"k", @"i", @"g", @"e", @"d", @"c", @"a", @"l", @"j", @"h", @"f", @"b"]; + result = [stringDictionary keysSortedByValueUsingComparator:function(obj1, obj2) + { + return obj1 < obj2 ? CPOrderedAscending : CPOrderedDescending; + }]; + [self assert:expected equals:result]; +} + - (void)testJSObjectDescription { var dict = [[CPDictionary alloc] initWithObjects:[CGRectMake(1, 2, 3, 4), CGPointMake(5, 6)] forKeys:[@"key1", @"key2"]],