Added implementations of some of the new (10.6) NSArray methods that take blocks as arguments. These all use the new GSBlocks.h macros, so compile cleanly with GCC, but can be used by code compiled by clang.

Some of these implementations are not as efficient as they could be (especially the ones that take an NSIndexSet as the first argument).  They also don't yet support concurrent enumeration.  Apple implements these using Grand Central.  We could possibly have a background thread that we send these things to (or use GCD if libdispatch is available).  It's not worth spawning a new thread for them, except in exceptional circumstances (and, unfortunately, we can't easily tell how expensive a single iteration of a block is.  Possibly we could time one block invocation, and if it's longer than some threshold make it concurrent, but it's probably not worth the effort).



git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@29176 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
David Chisnall 2009-12-27 16:49:52 +00:00
parent 05f18160df
commit 34c77138fc
4 changed files with 213 additions and 2 deletions

View file

@ -1,3 +1,13 @@
2009-12-27 David Chisnall <theraven@gna.org>
* Source/NSArray.m
* Headers/Foundation/NSArray.h
Added some block method implementations.
* Headers/Foundation/NSObjCRuntime.h
Added constants for enumeration.
2009-12-27 David Chisnall <theraven@gna.org>
* Source/GSFastEnumeration.h: Added macros implementing for..in loops.

View file

@ -117,6 +117,7 @@ extern "C" {
- (id) valueForKey: (NSString*)key;
#endif
DEFINE_BLOCK_TYPE(GSEnumeratorBlock, void, id, NSUInteger, BOOL*);
DEFINE_BLOCK_TYPE(GSPredicateBlock, BOOL, id, NSUInteger, BOOL*);
/**
* Enumerate over the collection using the given block. The first argument is
* the object and the second is the index in the array. The final argument is
@ -124,6 +125,84 @@ DEFINE_BLOCK_TYPE(GSEnumeratorBlock, void, id, NSUInteger, BOOL*);
* this to YES will interrupt the enumeration.
*/
- (void)enumerateObjectsUsingBlock: (GSEnumeratorBlock)aBlock;
/**
* Enumerate over the collection using the given block. The first argument is
* the object and the second is the index in the array. The final argument is
* a pointer to a BOOL indicating whether the enumeration should stop. Setting
* this to YES will interrupt the enumeration.
*
* The opts argument is a bitfield. Setting the NSNSEnumerationConcurrent flag
* specifies that it is thread-safe. The NSEnumerationReverse bit specifies
* that it should be enumerated in reverse order.
*/
- (void)enumerateObjectsWithOptions: (NSEnumerationOptions)opts
usingBlock: (GSEnumeratorBlock)aBlock;
/**
* Enumerate over the specified indexes in the collection using the given
* block. The first argument is the object and the second is the index in the
* array. The final argument is a pointer to a BOOL indicating whether the
* enumeration should stop. Setting this to YES will interrupt the
* enumeration.
*
* The opts argument is a bitfield. Setting the NSNSEnumerationConcurrent flag
* specifies that it is thread-safe. The NSEnumerationReverse bit specifies
* that it should be enumerated in reverse order.
*/
- (void)enumerateObjectsAtIndexes: (NSIndexSet*)indexSet
options: (NSEnumerationOptions)opts
usingBlock: (GSEnumeratorBlock)block;
/**
* Returns the indexes of the objects in a collection that match the condition
* specified by the block.
*
* The opts argument is a bitfield. Setting the NSNSEnumerationConcurrent flag
* specifies that it is thread-safe. The NSEnumerationReverse bit specifies
* that it should be enumerated in reverse order.
*/
- (NSIndexSet *)indexesOfObjectsWithOptions: (NSEnumerationOptions)opts
passingTest: (GSPredicateBlock)predicate;
/**
* Returns the indexes of the objects in a collection that match the condition
* specified by the block.
*/
- (NSIndexSet*)indexesOfObjectsPassingTest: (GSPredicateBlock)predicate;
/**
* Returns the indexes of the objects in a collection that match the condition
* specified by the block and are in the range specified by the index set.
*
* The opts argument is a bitfield. Setting the NSNSEnumerationConcurrent flag
* specifies that it is thread-safe. The NSEnumerationReverse bit specifies
* that it should be enumerated in reverse order.
*/
- (NSIndexSet*)indexesOfObjectsAtIndexes: (NSIndexSet*)indexSet
options: (NSEnumerationOptions)opts
passingTest: (GSPredicateBlock)predicate;
/**
* Returns the index of the first object in the array that matches the
* condition specified by the block.
*
* The opts argument is a bitfield. Setting the NSNSEnumerationConcurrent flag
* specifies that it is thread-safe. The NSEnumerationReverse bit specifies
* that it should be enumerated in reverse order.
*/
- (NSUInteger)indexOfObjectWithOptions: (NSEnumerationOptions)opts
passingTest: (GSPredicateBlock)predicate;
/**
* Returns the index of the first object in the array that matches the
* condition specified by the block.
*/
- (NSUInteger)indexOfObjectPassingTest: (GSPredicateBlock)predicate;
/**
* Returns the index of the first object in the specified range in a collection
* that matches the condition specified by the block.
*
* The opts argument is a bitfield. Setting the NSNSEnumerationConcurrent flag
* specifies that it is thread-safe. The NSEnumerationReverse bit specifies
* that it should be enumerated in reverse order.
*/
- (NSUInteger)indexOfObjectAtIndexes: (NSIndexSet*)indexSet
options: (NSEnumerationOptions)opts
passingTest: (GSPredicateBlock)predicate;
@end

View file

@ -67,6 +67,25 @@ typedef float CGFloat;
extern "C" {
#endif
enum
{
/**
* Specifies that the enumeration is concurrency-safe. Note that this does
* not mean that it will be carried out in a concurrent manner, only that
* it can be.
*/
NSEnumerationConcurrent = (1UL << 0),
/**
* Specifies that the enumeration should happen in the opposite of the
* natural order of the collection.
*/
NSEnumerationReverse = (1UL << 1)
};
/** Bitfield used to specify options to control enumeration over collections.
*/
typedef NSUInteger NSEnumerationOptions;
#if OS_API_VERSION(100500,GS_API_LATEST)
GS_EXPORT NSString *NSStringFromProtocol(Protocol *aProtocol);
GS_EXPORT Protocol *NSProtocolFromString(NSString *aProtocolName);

View file

@ -1619,19 +1619,122 @@ compare(id elem1, id elem2, void* context)
return result;
}
- (void)enumerateObjectsUsingBlock: (GSEnumeratorBlock)aBlock
{
[self enumerateObjectsWithOptions: 0 usingBlock: aBlock];
}
- (void)enumerateObjectsWithOptions: (NSEnumerationOptions)opts
usingBlock: (GSEnumeratorBlock)aBlock
{
NSUInteger count = 0;
BOOL shouldStop = NO;
FOR_IN (id, obj, self)
id<NSFastEnumeration> enumerator = self;
/* If we are enumerating in reverse, use the reverse enumerator for fast
* enumeration. */
if (opts & NSEnumerationReverse)
{
enumerator = [self reverseObjectEnumerator];
}
FOR_IN (id, obj, enumerator)
CALL_BLOCK(aBlock, obj, count++, &shouldStop);
if (shouldStop)
{
return;
}
END_FOR_IN(self)
END_FOR_IN(enumerator)
}
- (void)enumerateObjectsAtIndexes: (NSIndexSet*)indexSet
options: (NSEnumerationOptions)opts
usingBlock: (GSEnumeratorBlock)block
{
[[self objectsAtIndexes: indexSet] enumerateObjectsWithOptions: opts
usingBlock: block];
}
- (NSIndexSet *)indexesOfObjectsWithOptions: (NSEnumerationOptions)opts
passingTest: (GSPredicateBlock)predicate
{
/* TODO: Concurrency. */
NSMutableIndexSet *set = [NSMutableIndexSet indexSet];
BOOL shouldStop = NO;
id<NSFastEnumeration> enumerator = self;
NSUInteger count = 0;
/* If we are enumerating in reverse, use the reverse enumerator for fast
* enumeration. */
if (opts & NSEnumerationReverse)
{
enumerator = [self reverseObjectEnumerator];
}
FOR_IN (id, obj, self)
if (CALL_BLOCK(predicate, obj, count, &shouldStop))
{
/* TODO: It would be more efficient to collect an NSRange and only
* pass it to the index set when CALL_BLOCK returned NO. */
[set addIndex: count];
}
if (shouldStop)
{
return set;
}
count++;
END_FOR_IN(self)
return set;
}
- (NSIndexSet*)indexesOfObjectsPassingTest: (GSPredicateBlock)predicate
{
return [self indexesOfObjectsWithOptions: 0 passingTest: predicate];
}
- (NSIndexSet*)indexesOfObjectsAtIndexes: (NSIndexSet*)indexSet
options: (NSEnumerationOptions)opts
passingTest: (GSPredicateBlock)predicate
{
return [[self objectsAtIndexes: indexSet] indexesOfObjectsWithOptions: opts
passingTest: predicate];
}
- (NSUInteger)indexOfObjectWithOptions: (NSEnumerationOptions)opts
passingTest: (GSPredicateBlock)predicate
{
/* TODO: Concurrency. */
id<NSFastEnumeration> enumerator = self;
BOOL shouldStop = NO;
NSUInteger count = 0;
/* If we are enumerating in reverse, use the reverse enumerator for fast
* enumeration. */
if (opts & NSEnumerationReverse)
{
enumerator = [self reverseObjectEnumerator];
}
FOR_IN (id, obj, self)
if (CALL_BLOCK(predicate, obj, count, &shouldStop))
{
return count;
}
if (shouldStop)
{
return NSNotFound;
}
count++;
END_FOR_IN(self)
return NSNotFound;
}
- (NSUInteger)indexOfObjectPassingTest: (GSPredicateBlock)predicate
{
return [self indexOfObjectWithOptions: 0 passingTest: predicate];
}
- (NSUInteger)indexOfObjectAtIndexes: (NSIndexSet*)indexSet
options: (NSEnumerationOptions)opts
passingTest: (GSPredicateBlock)predicate
{
return [[self objectsAtIndexes: indexSet] indexOfObjectWithOptions: 0
passingTest: predicate];
}
@end