Implement a few blocks related enumeration methods on NSDictionary (with

unit tests).


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@34965 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Niels Grewe 2012-03-20 20:17:45 +00:00
parent b9c5b1414b
commit c6df5dc455
3 changed files with 138 additions and 9 deletions

View file

@ -3,29 +3,29 @@
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu> Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
Date: 1995 Date: 1995
This file is part of the GNUstep Base Library. This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version. version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details. Library General Public License for more details.
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02111 USA. Boston, MA 02111 USA.
*/ */
#ifndef _NSDictionary_h_GNUSTEP_BASE_INCLUDE #ifndef _NSDictionary_h_GNUSTEP_BASE_INCLUDE
#define _NSDictionary_h_GNUSTEP_BASE_INCLUDE #define _NSDictionary_h_GNUSTEP_BASE_INCLUDE
#import <GNUstepBase/GSVersionMacros.h> #import <GNUstepBase/GSVersionMacros.h>
#import <GNUstepBase/GSBlocks.h>
#import <Foundation/NSObject.h> #import <Foundation/NSObject.h>
#import <Foundation/NSEnumerator.h> #import <Foundation/NSEnumerator.h>
@ -33,7 +33,7 @@
extern "C" { extern "C" {
#endif #endif
@class NSArray, NSString, NSURL; @class NSArray, NSSet, NSString, NSURL;
@interface NSDictionary : NSObject <NSCoding, NSCopying, NSMutableCopying, NSFastEnumeration> @interface NSDictionary : NSObject <NSCoding, NSCopying, NSMutableCopying, NSFastEnumeration>
+ (id) dictionary; + (id) dictionary;
@ -86,6 +86,18 @@ extern "C" {
- (id) valueForKey: (NSString*)key; - (id) valueForKey: (NSString*)key;
- (BOOL) writeToURL: (NSURL*)url atomically: (BOOL)useAuxiliaryFile; - (BOOL) writeToURL: (NSURL*)url atomically: (BOOL)useAuxiliaryFile;
#endif #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 @end
@interface NSMutableDictionary: NSDictionary @interface NSMutableDictionary: NSDictionary

View file

@ -34,6 +34,7 @@
#import "Foundation/NSAutoreleasePool.h" #import "Foundation/NSAutoreleasePool.h"
#import "Foundation/NSFileManager.h" #import "Foundation/NSFileManager.h"
#import "Foundation/NSCoder.h" #import "Foundation/NSCoder.h"
#import "Foundation/NSSet.h"
#import "Foundation/NSValue.h" #import "Foundation/NSValue.h"
#import "Foundation/NSKeyValueCoding.h" #import "Foundation/NSKeyValueCoding.h"
#import "Foundation/NSUserDefaults.h" #import "Foundation/NSUserDefaults.h"
@ -366,7 +367,7 @@ static SEL appSel;
id *vals = NSZoneMalloc(NSDefaultMallocZone(), sizeof(id)*count); id *vals = NSZoneMalloc(NSDefaultMallocZone(), sizeof(id)*count);
unsigned i; unsigned i;
IMP dec; IMP dec;
dec = [aCoder methodForSelector: @selector(decodeObject)]; dec = [aCoder methodForSelector: @selector(decodeObject)];
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
@ -824,6 +825,7 @@ static SEL appSel;
return AUTORELEASE(result); return AUTORELEASE(result);
} }
} }
- (void)getObjects: (__unsafe_unretained id[])objects - (void)getObjects: (__unsafe_unretained id[])objects
andKeys: (__unsafe_unretained id[])keys 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<NSFastEnumeration> 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<NSFastEnumeration> 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)
/** /**
* <p>Writes the contents of the dictionary to the file specified by path. * <p>Writes the contents of the dictionary to the file specified by path.
* The file contents will be in property-list format ... under GNUstep * 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) valueForKey: (NSString*)key
{ {
id o; id o;
if ([key hasPrefix: @"@"] == YES) if ([key hasPrefix: @"@"] == YES)
{ {
@ -1121,7 +1192,7 @@ compareIt(id o1, id o2, void* context)
} }
return o; return o;
} }
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state - (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (__unsafe_unretained id[])stackbuf objects: (__unsafe_unretained id[])stackbuf
count: (NSUInteger)len count: (NSUInteger)len
{ {

View file

@ -0,0 +1,46 @@
#import "Testing.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDate.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSSet.h>
#if defined(GNUSTEP_BASE_LIBRARY)
#import <Foundation/NSSerialization.h>
#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;
}