From 5724dfe21df60383f4569dddefad49b0dba67fc4 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Tue, 17 Jul 2012 20:48:52 +0100 Subject: [PATCH] `CPDictionary enumerateKeysAndObjectsUsingBlock:`. --- Foundation/CPDictionary.j | 26 +++++++++++++++++++++ Tests/Foundation/CPDictionaryTest.j | 36 +++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/Foundation/CPDictionary.j b/Foundation/CPDictionary.j index a20bb59a9..1f3257cf5 100755 --- a/Foundation/CPDictionary.j +++ b/Foundation/CPDictionary.j @@ -654,6 +654,32 @@ var value = [self objectForKey:aKey]; return ((value !== nil) && (value !== undefined)); } + +- (void)enumerateKeysAndObjectsUsingBlock:(Function /*(id aKey, id anObject, @ref BOOL stop)*/)aFunction +{ + var shouldStop = NO, + shouldStopRef = AT_REF(shouldStop); + + for (var index = 0; index < _count; index++) + { + var key = _keys[index], + value = valueForKey(key); + + aFunction(key, value, shouldStopRef); + + if (shouldStop) + return; + } +} + +- (void)enumerateKeysAndObjectsWithOptions:(CPEnumerationOptions)opts usingBlock:(Function /*(id aKey, id anObject, @ref BOOL stop)*/)aFunction +{ + // Ignore the options because neither option has an effect. + // CPEnumerationReverse has no effect on enumerating a CPDictionary because dictionary enumeration is not ordered. + // CPEnumerationConcurrent is not possible in a single threaded environment. + [self enumerateKeysAndObjectsUsingBlock:aFunction]; +} + @end @implementation CPDictionary (CPCoding) diff --git a/Tests/Foundation/CPDictionaryTest.j b/Tests/Foundation/CPDictionaryTest.j index e5c8e9012..96a6651ec 100644 --- a/Tests/Foundation/CPDictionaryTest.j +++ b/Tests/Foundation/CPDictionaryTest.j @@ -348,6 +348,42 @@ [self assert:expected equals:result]; } +- (void)testEnumerateKeysAndObjectsUsingBlock_ +{ + var input0 = [CPDictionary dictionary], + input1 = [CPDictionary dictionaryWithJSObject:{a: 1, b: 3, c: "b"}], + output = [CPMutableDictionary dictionary], + outputFunction = function(aKey, anObject) + { + [output setValue:anObject forKey:aKey]; + }; + + [input0 enumerateKeysAndObjectsUsingBlock:outputFunction]; + [self assert:0 equals:[output count] message:@"output when enumerating empty dictionary"]; + + [input1 enumerateKeysAndObjectsUsingBlock:outputFunction]; + [self assert:3 equals:[output count] message:@"output when enumerating input1"]; + [self assert:input1 equals:output message:@"output should equal input"]; + + // Stop enumerating after two keys. + output = [CPMutableDictionary dictionary]; + stoppingFunction = function(aKey, anObject, stop) + { + [output setValue:anObject forKey:aKey]; + if ([output count] > 1) + stop(YES); // AT_DEREF(stop, YES) - FIXME Replace with proper @ref @deref when in ObjJ. + } + + [input1 enumerateKeysAndObjectsUsingBlock:stoppingFunction]; + [self assert:2 equals:[output count] message:@"output when enumerating input1 and stopping after 2"]; + + // CPEnumerationReverse shouldn't have any particular effect. Just check that it doesn't crash. + output = [CPMutableDictionary dictionary]; + [input1 enumerateKeysAndObjectsWithOptions:CPEnumerationReverse usingBlock:outputFunction]; + [self assert:3 equals:[output count] message:@"output when enumerating input1"]; + [self assert:input1 equals:output message:@"output should equal input"]; +} + - (void)testJSObjectDescription { var dict = [[CPDictionary alloc] initWithObjects:[CGRectMake(1, 2, 3, 4), CGPointMake(5, 6)] forKeys:[@"key1", @"key2"]],