Refactored last two commits so that all of the real code is in GSIMap.h and is just called from the relevant classes, rather than copied and pasted everywhere. Also added fast enumeration support to GSCountedSet.

I think that's all of the classes that use GSIMaps for their implementation now fully supporting fast enumeration.  If there are any that I've missed, then just copy the methods from GSSet to implement them.  You just need to set the mutations pointer to something sensible (i.e. something that will change if the collection mutates) and then call the new GSIMapCountByEnumeratingWithStateObjectsCount() function.



git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@29181 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
theraven 2009-12-29 16:49:07 +00:00
parent 55e8317350
commit 0bd156fa4a
5 changed files with 97 additions and 201 deletions

View file

@ -3,16 +3,14 @@
* Source/GSDictionary.m
* Source/NSDictionary.m
* Headers/Foundation/NSDictionary.h
Added fast enumeration support to NSDictionary.
2009-12-29 David Chisnall <theraven@gna.org>
Added fast enumeration support to GSDictionary, and GSMutableSet.
* Source/GSSet.m
* Source/GSCountedSet.m
* Source/NSSet.m
* Headers/Foundation/NSSet.h
Added fast enumeration support to NSSet.
Added fast enumeration support to GSSet, GSMutableSet, and GSCountedSet
* Headers/Additions/GNUstepBase/GSIMap.h
Added function for implementing fast enumeration with GSIMaps.
2009-12-27 David Chisnall <theraven@gna.org>

View file

@ -28,6 +28,7 @@
#if OS_API_VERSION(GS_API_NONE,GS_API_LATEST)
#include <Foundation/NSObject.h>
#include <Foundation/NSEnumerator.h>
#include <Foundation/NSGarbageCollector.h>
#include <Foundation/NSZone.h>
@ -929,6 +930,64 @@ GSIMapEnumeratorNextNode(GSIMapEnumerator enumerator)
return node;
}
/**
* Used to implement fast enumeration methods in classes that use GSIMap for
* their data storaae.
*/
static INLINE NSUInteger
GSIMapCountByEnumeratingWithStateObjectsCount(GSIMapTable map,
NSFastEnumerationState *state,
id *stackbuf,
NSUInteger len)
{
NSInteger count;
NSInteger i;
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 */
if (0 == state->state)
{
enumerator = GSIMapEnumeratorForMap(map);
}
else
{
enumerator.map = map;
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)
{
/* UGLY HACK: Lets this compile with any key type. Fast enumeration
* will only work with things that are id-sized, however, so don't
* try using it with non-object collections.
*/
stackbuf[i] = *(id*)&node->key;
}
}
/* 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;
}
#if GSI_MAP_HAS_VALUE
static INLINE GSIMapNode
GSIMapAddPairNoRetain(GSIMapTable map, GSIMapKey key, GSIMapVal value)

View file

@ -50,6 +50,8 @@ static GC_descr nodeDesc; // Type descriptor for map node.
{
@public
GSIMapTable_t map;
@private
NSUInteger _version;
}
@end
@ -127,6 +129,7 @@ static GC_descr nodeDesc; // Type descriptor for map node.
format: @"Tried to nil value to counted set"];
}
_version++;
node = GSIMapNodeForKey(&map, (GSIMapKey)anObject);
if (node == 0)
{
@ -136,6 +139,7 @@ static GC_descr nodeDesc; // Type descriptor for map node.
{
node->value.uint++;
}
_version++;
}
- (unsigned) count
@ -296,8 +300,10 @@ static GC_descr nodeDesc; // Type descriptor for map node.
{
if (node->value.uint <= (unsigned int)level)
{
_version++;
GSIMapRemoveNodeFromMap(&map, bucket, node);
GSIMapFreeNode(&map, node);
_version++;
}
bucket = GSIMapEnumeratorBucket(&enumerator);
node = GSIMapEnumeratorNextNode(&enumerator);
@ -308,7 +314,9 @@ static GC_descr nodeDesc; // Type descriptor for map node.
- (void) removeAllObjects
{
_version++;
GSIMapCleanMap(&map);
_version++;
}
/**
@ -326,6 +334,7 @@ static GC_descr nodeDesc; // Type descriptor for map node.
NSWarnMLog(@"attempt to remove nil object");
return;
}
_version++;
bucket = GSIMapBucketForKey(&map, (GSIMapKey)anObject);
if (bucket != 0)
{
@ -341,12 +350,14 @@ static GC_descr nodeDesc; // Type descriptor for map node.
}
}
}
_version++;
}
- (id) unique: (id)anObject
{
GSIMapNode node;
id result;
_version++;
if (anObject == nil)
{
@ -372,6 +383,14 @@ static GC_descr nodeDesc; // Type descriptor for map node.
}
#endif
}
_version++;
return result;
}
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (id*)stackbuf
count: (NSUInteger)len
{
state->mutationsPtr = (unsigned long *)&_version;
return GSIMapCountByEnumeratingWithStateObjectsCount(&map, state, stackbuf, len);
}
@end

View file

@ -358,53 +358,8 @@ static SEL objSel;
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;
state->mutationsPtr = (unsigned long *)self;
return GSIMapCountByEnumeratingWithStateObjectsCount(&map, state, stackbuf, len);
}
@end
@ -513,53 +468,8 @@ static SEL objSel;
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;
state->mutationsPtr = (unsigned long *)&_version;
return GSIMapCountByEnumeratingWithStateObjectsCount(&map, state, stackbuf, len);
}
@end

View file

@ -523,57 +523,12 @@ static Class mutableSetClass;
return AUTORELEASE([[GSSetEnumerator alloc] initWithSet: self]);
}
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (id*)stackbuf
count: (NSUInteger)len
- (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;
state->mutationsPtr = (unsigned long *)self;
return GSIMapCountByEnumeratingWithStateObjectsCount(&map, state, stackbuf, len);
}
@end
@ -776,57 +731,12 @@ static Class mutableSetClass;
}
}
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (id*)stackbuf
count: (NSUInteger)len
- (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;
state->mutationsPtr = (unsigned long *)&_version;
return GSIMapCountByEnumeratingWithStateObjectsCount(&map, state, stackbuf, len);
}
@end