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:
thebeing 2012-03-20 20:17:45 +00:00
parent 02a7bf73a7
commit ecec748337
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>
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 <GNUstepBase/GSVersionMacros.h>
#import <GNUstepBase/GSBlocks.h>
#import <Foundation/NSObject.h>
#import <Foundation/NSEnumerator.h>
@ -33,7 +33,7 @@
extern "C" {
#endif
@class NSArray, NSString, NSURL;
@class NSArray, NSSet, NSString, NSURL;
@interface NSDictionary : NSObject <NSCoding, NSCopying, NSMutableCopying, NSFastEnumeration>
+ (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

View file

@ -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<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.
* 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
{

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;
}