mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
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:
parent
41eb58f807
commit
9e003700b4
5 changed files with 133 additions and 6 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 = ↦
|
||||
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 = ↦
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue