Added fast enumeration support to GS[Mutable]Dictionary. This follows exactly the same pattern (and uses the same code as) GSSet. It's probably worth factoring out this code, because it is now used in four methods with almost no variation between them.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@29180 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
David Chisnall 2009-12-29 16:21:01 +00:00
parent 41eb58f807
commit 9e003700b4
5 changed files with 133 additions and 6 deletions

View file

@ -1,3 +1,11 @@
2009-12-29 David Chisnall <theraven@gna.org>
* Source/GSDictionary.m
* Source/NSDictionary.m
* Headers/Foundation/NSDictionary.h
Added fast enumeration support to NSDictionary.
2009-12-29 David Chisnall <theraven@gna.org>
* Source/GSSet.m

View file

@ -27,14 +27,15 @@
#import <GNUstepBase/GSVersionMacros.h>
#import <Foundation/NSObject.h>
#import <Foundation/NSEnumerator.h>
#if defined(__cplusplus)
extern "C" {
#endif
@class NSArray, NSString, NSEnumerator, NSURL;
@class NSArray, NSString, NSURL;
@interface NSDictionary : NSObject <NSCoding, NSCopying, NSMutableCopying>
@interface NSDictionary : NSObject <NSCoding, NSCopying, NSMutableCopying, NSFastEnumeration>
+ (id) dictionary;
+ (id) dictionaryWithContentsOfFile: (NSString*)path;
#if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST)

View file

@ -67,6 +67,7 @@ static GC_descr nodeDesc; // Type descriptor for map node.
{
@public
GSIMapTable_t map;
NSUInteger _version;
}
@end
@ -353,6 +354,58 @@ static SEL objSel;
}
return nil;
}
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (id*)stackbuf
count: (NSUInteger)len
{
NSInteger count;
NSInteger i;
/* This is cached in the caller at the start and compared at each
* iteration. If it changes during the iteration then
* objc_enumerationMutation() will be called, throwing an exception.
*/
state->mutationsPtr = (unsigned long *)self;
count = MIN(len, map.nodeCount - state->state);
/* We can store a GSIMapEnumerator inside the extra buffer in state on all
* platforms that don't suck beyond belief (i.e. everything except win64),
* but we can't on anything where long is 32 bits and pointers are 64 bits,
* so we have to construct it here to avoid breaking on that platform.
*/
struct GSPartMapEnumerator
{
GSIMapNode node;
uintptr_t bucket;
};
GSIMapEnumerator_t enumerator;
/* Construct the real enumerator */
enumerator.map = &map;
if (0 == state->state)
{
enumerator = GSIMapEnumeratorForMap(&map);
}
else
{
enumerator.node = ((struct GSPartMapEnumerator*)&(state->extra))->node;
enumerator.bucket = ((struct GSPartMapEnumerator*)&(state->extra))->bucket;
}
/* Get the next count objects and put them in the stack buffer. */
for (i=0 ; i<count ; i++)
{
GSIMapNode node = GSIMapEnumeratorNextNode(&enumerator);
if (0 != node)
{
stackbuf[i] = node->key.obj;
}
}
/* Store the important bits of the enumerator in the caller. */
((struct GSPartMapEnumerator*)&(state->extra))->node = enumerator.node;
((struct GSPartMapEnumerator*)&(state->extra))->bucket = enumerator.bucket;
/* Update the rest of the state. */
state->state += count;
state->itemsPtr = stackbuf;
return count;
}
@end
@ -401,6 +454,7 @@ static SEL objSel;
{
GSIMapNode node;
_version++;
if (aKey == nil)
{
NSException *e;
@ -433,11 +487,14 @@ static SEL objSel;
{
GSIMapAddPair(&map, (GSIMapKey)aKey, (GSIMapVal)anObject);
}
_version++;
}
- (void) removeAllObjects
{
_version++;
GSIMapCleanMap(&map);
_version++;
}
- (void) removeObjectForKey: (id)aKey
@ -447,9 +504,63 @@ static SEL objSel;
NSWarnMLog(@"attempt to remove nil key from dictionary %@", self);
return;
}
_version++;
GSIMapRemoveKey(&map, (GSIMapKey)aKey);
_version++;
}
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (id*)stackbuf
count: (NSUInteger)len
{
NSInteger count;
NSInteger i;
/* This is cached in the caller at the start and compared at each
* iteration. If it changes during the iteration then
* objc_enumerationMutation() will be called, throwing an exception.
*/
state->mutationsPtr = (unsigned long *)&_version;
count = MIN(len, map.nodeCount - state->state);
/* We can store a GSIMapEnumerator inside the extra buffer in state on all
* platforms that don't suck beyond belief (i.e. everything except win64),
* but we can't on anything where long is 32 bits and pointers are 64 bits,
* so we have to construct it here to avoid breaking on that platform.
*/
struct GSPartMapEnumerator
{
GSIMapNode node;
uintptr_t bucket;
};
GSIMapEnumerator_t enumerator;
/* Construct the real enumerator */
enumerator.map = &map;
if (0 == state->state)
{
enumerator = GSIMapEnumeratorForMap(&map);
}
else
{
enumerator.node = ((struct GSPartMapEnumerator*)&(state->extra))->node;
enumerator.bucket = ((struct GSPartMapEnumerator*)&(state->extra))->bucket;
}
/* Get the next count objects and put them in the stack buffer. */
for (i=0 ; i<count ; i++)
{
GSIMapNode node = GSIMapEnumeratorNextNode(&enumerator);
if (0 != node)
{
stackbuf[i] = node->key.obj;
}
}
/* Store the important bits of the enumerator in the caller. */
((struct GSPartMapEnumerator*)&(state->extra))->node = enumerator.node;
((struct GSPartMapEnumerator*)&(state->extra))->bucket = enumerator.bucket;
/* Update the rest of the state. */
state->state += count;
state->itemsPtr = stackbuf;
return count;
}
@end
@implementation GSDictionaryKeyEnumerator

View file

@ -1105,6 +1105,13 @@ compareIt(id o1, id o2, void* context)
}
return o;
}
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (id*)stackbuf
count: (NSUInteger)len
{
[self subclassResponsibility: _cmd];
return 0;
}
@end

View file

@ -903,11 +903,11 @@ static Class NSMutableSet_concrete_class;
}
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (id*)stackbuf
count: (NSUInteger)len
objects: (id*)stackbuf
count: (NSUInteger)len
{
[self subclassResponsibility: _cmd];
return 0;
[self subclassResponsibility: _cmd];
return 0;
}
@end