Perform non-concurrent block enumeration in place.

Was previously using serial queue, which doesn't match Apple platforms.
This commit is contained in:
Frederik Seiffert 2019-09-25 11:14:43 +02:00
parent ecedcd6743
commit 561cef3797
7 changed files with 144 additions and 117 deletions

View file

@ -657,7 +657,7 @@ static SEL remSel;
{
GS_DISPATCH_CREATE_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
FOR_IN (id, obj, enumerator)
GS_DISPATCH_SUBMIT_BLOCK(enumQueueGroup, enumQueue, if (YES == shouldStop) {return;}, return, aBlock, obj, count, &shouldStop);
GS_DISPATCH_SUBMIT_BLOCK(enumQueueGroup, enumQueue, if (shouldStop == NO) {, }, aBlock, obj, count, &shouldStop);
if (isReverse)
{
count--;
@ -865,33 +865,35 @@ static SEL remSel;
GS_DISPATCH_CREATE_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
FOR_IN (id, obj, enumerator)
# if __has_feature(blocks) && (GS_USE_LIBDISPATCH == 1)
dispatch_group_async(enumQueueGroup, enumQueue, ^(void){
if (shouldStop)
if (enumQueue != NULL)
{
return;
dispatch_group_async(enumQueueGroup, enumQueue, ^(void){
if (shouldStop)
{
return;
}
if (predicate(obj, count, &shouldStop))
{
// FIXME: atomic operation on the shouldStop variable would be nicer,
// but we don't expose the GSAtomic* primitives anywhere.
[indexLock lock];
index = count;
// Cancel all other predicate evaluations:
shouldStop = YES;
[indexLock unlock];
}
});
}
if (predicate(obj, count, &shouldStop))
{
// FIXME: atomic operation on the shouldStop variable would be nicer,
// but we don't expose the GSAtomic* primitives anywhere.
[indexLock lock];
index = count;
// Cancel all other predicate evaluations:
shouldStop = YES;
[indexLock unlock];
}
});
# else
else // call block directly
# endif
if (CALL_BLOCK(predicate, obj, count, &shouldStop))
{
index = count;
shouldStop = YES;
index = count;
shouldStop = YES;
}
# endif
if (shouldStop)
{
break;
break;
}
count++;
END_FOR_IN(enumerator)
@ -940,30 +942,32 @@ static SEL remSel;
GS_DISPATCH_CREATE_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
FOR_IN (id, obj, enumerator)
# if __has_feature(blocks) && (GS_USE_LIBDISPATCH == 1)
dispatch_group_async(enumQueueGroup, enumQueue, ^(void){
if (shouldStop)
if (enumQueue != NULL)
{
return;
dispatch_group_async(enumQueueGroup, enumQueue, ^(void){
if (shouldStop)
{
return;
}
if (predicate(obj, count, &shouldStop))
{
[setLock lock];
[set addIndex: count];
[setLock unlock];
}
});
}
if (predicate(obj, count, &shouldStop))
{
[setLock lock];
[set addIndex: count];
[setLock unlock];
}
});
# else
else // call block directly
# endif
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];
/* 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];
}
# endif
if (shouldStop)
{
break;
break;
}
count++;
END_FOR_IN(enumerator)