diff --git a/Headers/Foundation/NSDictionary.h b/Headers/Foundation/NSDictionary.h index 02d3c8b76..8e6cff6c8 100644 --- a/Headers/Foundation/NSDictionary.h +++ b/Headers/Foundation/NSDictionary.h @@ -3,29 +3,29 @@ Written by: Andrew Kachites McCallum Date: 1995 - + This file is part of the GNUstep Base Library. 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 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 Library 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 02111 USA. - */ + */ #ifndef _NSDictionary_h_GNUSTEP_BASE_INCLUDE #define _NSDictionary_h_GNUSTEP_BASE_INCLUDE #import - +#import #import #import @@ -33,7 +33,7 @@ extern "C" { #endif -@class NSArray, NSString, NSURL; +@class NSArray, NSSet, NSString, NSURL; @interface NSDictionary : NSObject + (id) dictionary; @@ -86,6 +86,18 @@ extern "C" { - (id) valueForKey: (NSString*)key; - (BOOL) writeToURL: (NSURL*)url atomically: (BOOL)useAuxiliaryFile; #endif + + +#if OS_API_VERSION(100600, GS_API_LATEST) +DEFINE_BLOCK_TYPE(GSKeysAndObjectsEnumeratorBlock, void, id, id, BOOL*); +DEFINE_BLOCK_TYPE(GSKeysAndObjectsPredicateBlock, BOOL, id, id, BOOL*); +- (void)enumerateKeysAndObjectsWithOptions: (NSEnumerationOptions)opts + usingBlock: (GSKeysAndObjectsEnumeratorBlock)aBlock; +- (void)enumerateKeysAndObjectsUsingBlock: (GSKeysAndObjectsEnumeratorBlock)aBlock; +- (NSSet*)keysOfEntriesWithOptions: (NSEnumerationOptions)opts + passingTest: (GSKeysAndObjectsPredicateBlock)aPredicate; +- (NSSet*)keysOfEntriesPassingTest: (GSKeysAndObjectsPredicateBlock)aPredicate; +#endif @end @interface NSMutableDictionary: NSDictionary diff --git a/Source/NSDictionary.m b/Source/NSDictionary.m index 170ac0f27..6b0a32a95 100644 --- a/Source/NSDictionary.m +++ b/Source/NSDictionary.m @@ -34,6 +34,7 @@ #import "Foundation/NSAutoreleasePool.h" #import "Foundation/NSFileManager.h" #import "Foundation/NSCoder.h" +#import "Foundation/NSSet.h" #import "Foundation/NSValue.h" #import "Foundation/NSKeyValueCoding.h" #import "Foundation/NSUserDefaults.h" @@ -366,7 +367,7 @@ static SEL appSel; id *vals = NSZoneMalloc(NSDefaultMallocZone(), sizeof(id)*count); unsigned i; IMP dec; - + dec = [aCoder methodForSelector: @selector(decodeObject)]; for (i = 0; i < count; i++) { @@ -824,6 +825,7 @@ static SEL appSel; return AUTORELEASE(result); } } + - (void)getObjects: (__unsafe_unretained id[])objects andKeys: (__unsafe_unretained id[])keys { @@ -964,6 +966,75 @@ compareIt(id o1, id o2, void* context) } } +#if OS_API_VERSION(100600, GS_API_LATEST) +- (void)enumerateKeysAndObjectsWithOptions: (NSEnumerationOptions)opts + usingBlock: (GSKeysAndObjectsEnumeratorBlock)aBlock +{ + /* + * NOTE: For the moment, we ignore the NSEnumerationOptions because, according + * to the Cocoa documentation, NSEnumerationReverse is undefined for + * NSDictionary and we cannot handle NSEnumerationConcurrent without + * libdispatch. + */ + id enumerator = [self keyEnumerator]; + SEL objectForKeySelector = @selector(objectForKey:); + IMP objectForKey = [self methodForSelector: objectForKeySelector]; + BOOL shouldStop = NO; + FOR_IN(id, key, enumerator) + id obj = objectForKey(self, objectForKeySelector, key); + CALL_BLOCK(aBlock, key, obj, &shouldStop); + if (YES == shouldStop) + { + break; + } + END_FOR_IN(enumerator) +} + +- (void)enumerateKeysAndObjectsUsingBlock: (GSKeysAndObjectsEnumeratorBlock)aBlock +{ + [self enumerateKeysAndObjectsWithOptions: 0 + usingBlock: aBlock]; +} + + +- (NSSet*)keysOfEntriesWithOptions: (NSEnumerationOptions)opts + passingTest: (GSKeysAndObjectsPredicateBlock)aPredicate; +{ + /* + * See -enumerateKeysAndObjectsWithOptions:usingBlock: for note about + * NSEnumerationOptions. + */ + id enumerator = [self keyEnumerator]; + SEL objectForKeySelector = @selector(objectForKey:); + IMP objectForKey = [self methodForSelector: objectForKeySelector]; + BOOL shouldStop = NO; + NSMutableSet *buildSet = [NSMutableSet new]; + SEL addObjectSelector = @selector(addObject:); + IMP addObject = [buildSet methodForSelector: addObjectSelector]; + NSSet *resultSet = nil; + FOR_IN(id, key, enumerator) + id obj = objectForKey(self, objectForKeySelector, key); + if (CALL_BLOCK(aPredicate, key, obj, &shouldStop)) + { + addObject(buildSet, addObjectSelector, key); + } + if (YES == shouldStop) + { + break; + } + END_FOR_IN(enumerator) + resultSet = [NSSet setWithSet: buildSet]; + [buildSet release]; + return resultSet; +} + +- (NSSet*)keysOfEntriesPassingTest: (GSKeysAndObjectsPredicateBlock)aPredicate +{ + return [self keysOfEntriesWithOptions: 0 + passingTest: aPredicate]; +} + +#endif //OS_API_VERSION(100600,GS_API_LATEST) /** *

Writes the contents of the dictionary to the file specified by path. * The file contents will be in property-list format ... under GNUstep @@ -1109,7 +1180,7 @@ compareIt(id o1, id o2, void* context) */ - (id) valueForKey: (NSString*)key { - id o; + id o; if ([key hasPrefix: @"@"] == YES) { @@ -1121,7 +1192,7 @@ compareIt(id o1, id o2, void* context) } return o; } -- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state +- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state objects: (__unsafe_unretained id[])stackbuf count: (NSUInteger)len { diff --git a/Tests/base/NSDictionary/blocks.m b/Tests/base/NSDictionary/blocks.m new file mode 100644 index 000000000..67ad4d30d --- /dev/null +++ b/Tests/base/NSDictionary/blocks.m @@ -0,0 +1,46 @@ +#import "Testing.h" +#import +#import +#import +#import +#import +#import +#import +#import +#import +#if defined(GNUSTEP_BASE_LIBRARY) +#import +#endif + + +static NSUInteger fooCount = 0; + +int main() +{ + START_SET("NSDictionary Blocks") +# ifndef __has_feature +# define __has_feature(x) 0 +# endif +# if __has_feature(blocks) + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + + NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: @"foo", + @"key1", @"bar", @"key2", @"foo", @"key3", nil]; + [dict enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop){ + if ([obj isEqual: @"foo"]){ fooCount++;}}]; + PASS((2 == fooCount), + "Can enumerate dictionary using a block"); + + NSSet *fooKeys = [dict keysOfEntriesPassingTest: ^(id key, id obj, BOOL *stop){ + return [obj isEqual: @"foo"];}]; + PASS((([fooKeys count] == 2) + && ([fooKeys containsObject: @"key1"]) + && ([fooKeys containsObject: @"key3"])) + , "Can use blocks as predicates."); + [arp release]; arp = nil; +# else + SKIP("No Blocks support in the compiler.") +# endif + END_SET("NSDictionary Blocks") + return 0; +}