mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Detect the presence of libdispatch and, if available, use it for collection
enumeration methods that take blocks as arguments. This allows us to implement the NSEnumerationConcurrent option of those methods with minimal effort. The searching methods on NSIndexSet and all the sorting methods are still missing. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@35010 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
95e88e9a7e
commit
fa47f6da10
15 changed files with 22804 additions and 4578 deletions
25
ChangeLog
25
ChangeLog
|
@ -1,3 +1,28 @@
|
|||
2012-03-27 Niels Grewe <niels.grewe@halbordnung.de>
|
||||
* configure.ac
|
||||
* config.mak.in
|
||||
* Headers/GNUstepBase/GSConfig.h.in
|
||||
* Headers/GNUstepBase/config.h.in:
|
||||
Implement configure check for libdispatch.
|
||||
* configure: Regenerate
|
||||
* Source/GSDispatch.h: Add portability header with macros for compiling
|
||||
with or without libdispatch.
|
||||
* Source/NSArray.m
|
||||
* Source/NSDictionary.m
|
||||
* Source/NSIndexSet.m
|
||||
* Source/NSSet.m
|
||||
* Headers/Foundation/NSIndexSet.h:
|
||||
Implement libdispatch support for block enumeration methods.
|
||||
* Tests/base/NSMutableIndexSet/blocks.m
|
||||
* Tests/base/NSDictionary/blocks.m
|
||||
* Tests/base/NSArray/blocks.m:
|
||||
Test cases for new code.
|
||||
|
||||
Detect the presence of libdispatch and, if available, use it for
|
||||
collection enumeration methods that take blocks as arguments. This
|
||||
allows us to implement the NSEnumerationConcurrent option of those
|
||||
methods with minimal effort.
|
||||
|
||||
2012-03-27 Niels Grewe <niels.grewe@halbordnung.de>
|
||||
|
||||
* Source/NSOperation.m: Remove leftover debugging statements.
|
||||
|
|
|
@ -3,19 +3,19 @@
|
|||
|
||||
Written by: Richard Frith-Macdonald <rfm@gnu.org>
|
||||
Created: Feb 2004
|
||||
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
|
@ -23,11 +23,12 @@
|
|||
|
||||
AutogsdocSource: NSIndexSet.m
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef _NSIndexSet_h_GNUSTEP_BASE_INCLUDE
|
||||
#define _NSIndexSet_h_GNUSTEP_BASE_INCLUDE
|
||||
#import <GNUstepBase/GSVersionMacros.h>
|
||||
#import <GNUstepBase/GSBlocks.h>
|
||||
|
||||
#if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST)
|
||||
|
||||
|
@ -89,13 +90,28 @@ extern "C" {
|
|||
*/
|
||||
- (NSUInteger) count;
|
||||
|
||||
#if OS_API_VERSION(100500,GS_API_LATEST)
|
||||
#if OS_API_VERSION(100500,GS_API_LATEST)
|
||||
/** Not implemented
|
||||
* Returns the number of indexes set within the specified range.
|
||||
*/
|
||||
- (NSUInteger) countOfIndexesInRange: (NSRange)range;
|
||||
#endif
|
||||
|
||||
#if OS_API_VERSION(100600,GS_API_LATEST)
|
||||
DEFINE_BLOCK_TYPE(GSIndexSetEnumerationBlock, void, NSUInteger, BOOL*);
|
||||
- (void)enumerateIndexesInRange: (NSRange)range
|
||||
options: (NSEnumerationOptions)opts
|
||||
usingBlock: (GSIndexSetEnumerationBlock)aBlock;
|
||||
/**
|
||||
* Enumerate all indices in the set by applying a block to them.
|
||||
*/
|
||||
- (void)enumerateIndexesUsingBlock: (GSIndexSetEnumerationBlock)aBlock;
|
||||
|
||||
- (void)enumerateIndexesWithOptions: (NSEnumerationOptions)opts
|
||||
usingBlock: (GSIndexSetEnumerationBlock)aBlock;
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the first index value in the receiver or NSNotFound if the
|
||||
* receiver is empty.
|
||||
|
@ -222,7 +238,7 @@ extern "C" {
|
|||
* anIndex.
|
||||
*/
|
||||
- (void) shiftIndexesStartingAtIndex: (NSUInteger)anIndex
|
||||
by: (NSInteger)amount;
|
||||
by: (NSInteger)amount;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -226,7 +226,7 @@ typedef struct {
|
|||
#define GS_USE_AVAHI @HAVE_AVAHI@
|
||||
#define GS_USE_MDNS @HAVE_MDNS@
|
||||
#define GS_USE_ICU @HAVE_ICU@
|
||||
|
||||
#define GS_USE_LIBDISPATCH @HAVE_LIBDISPATCH@
|
||||
|
||||
#if defined(__WIN32__) || defined(_WIN32) || defined(__MS_WIN32__)
|
||||
# if !defined(__WIN32__)
|
||||
|
@ -292,11 +292,11 @@ typedef struct {
|
|||
beenHere = YES; fprintf(stderr, "%s:%d %s", __FILE__, __LINE__, (M));}})
|
||||
|
||||
#define OBJC_MALLOC(VAR, TYPE, NUM) \
|
||||
(OBJC_DEP("OBJC_MALLOC is deprecated ... use malloc\n"),(VAR) = (TYPE *) malloc ((unsigned)(NUM)*sizeof(TYPE)))
|
||||
(OBJC_DEP("OBJC_MALLOC is deprecated ... use malloc\n"),(VAR) = (TYPE *) malloc ((unsigned)(NUM)*sizeof(TYPE)))
|
||||
#define OBJC_VALLOC(VAR, TYPE, NUM) \
|
||||
(OBJC_DEP("OBJC_VALLOC is deprecated\n"),(VAR) = (TYPE *) valloc ((unsigned)(NUM)*sizeof(TYPE)))
|
||||
(OBJC_DEP("OBJC_VALLOC is deprecated\n"),(VAR) = (TYPE *) valloc ((unsigned)(NUM)*sizeof(TYPE)))
|
||||
#define OBJC_ATOMIC_MALLOC(VAR, TYPE, NUM) \
|
||||
(OBJC_DEP("OBJC_ATOMIC_MALLOC is deprecated\n"),(VAR) = (TYPE *) malloc ((unsigned)(NUM)*sizeof(TYPE)))
|
||||
(OBJC_DEP("OBJC_ATOMIC_MALLOC is deprecated\n"),(VAR) = (TYPE *) malloc ((unsigned)(NUM)*sizeof(TYPE)))
|
||||
#define OBJC_REALLOC(VAR, TYPE, NUM) \
|
||||
(OBJC_DEP("OBJC_REALLOC is deprecated ... use realloc\n"),(VAR) = (TYPE *) realloc ((VAR), (unsigned)(NUM)*sizeof(TYPE)))
|
||||
#define OBJC_CALLOC(VAR, TYPE, NUM) \
|
||||
|
@ -338,13 +338,13 @@ typedef struct {
|
|||
#define LONG2PTR(L) (((char*)0)+(L))
|
||||
#endif
|
||||
|
||||
#if VSPRINTF_RETURNS_LENGTH
|
||||
#if VSPRINTF_RETURNS_LENGTH
|
||||
#define VSPRINTF_LENGTH(VSPF_CALL) (VSPF_CALL)
|
||||
#else
|
||||
#define VSPRINTF_LENGTH(VSPF_CALL) strlen((VSPF_CALL))
|
||||
#endif /* VSPRINTF_RETURNS_LENGTH */
|
||||
|
||||
#if VASPRINTF_RETURNS_LENGTH
|
||||
#if VASPRINTF_RETURNS_LENGTH
|
||||
#define VASPRINTF_LENGTH(VASPF_CALL) (VASPF_CALL)
|
||||
#else
|
||||
#define VASPRINTF_LENGTH(VASPF_CALL) strlen((VASPF_CALL))
|
||||
|
@ -390,8 +390,8 @@ typedef struct {
|
|||
# define __strong __attribute__((objc_gc(strong)))
|
||||
# define __weak __attribute__((objc_gc(weak)))
|
||||
# else
|
||||
# define __strong
|
||||
# define __weak
|
||||
# define __strong
|
||||
# define __weak
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
/* Headers/GNUstepBase/config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
#undef AC_APPLE_UNIVERSAL_BUILD
|
||||
|
||||
/* The normal alignment of `pthread_cond_t', in bytes. */
|
||||
#undef ALIGNOF_PTHREAD_COND_T
|
||||
|
||||
|
@ -193,6 +190,12 @@
|
|||
*/
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
/* Define to 1 if you have the <dispatch/dispatch.h> header file. */
|
||||
#undef HAVE_DISPATCH_DISPATCH_H
|
||||
|
||||
/* Define to 1 if you have the <dispatch.h> header file. */
|
||||
#undef HAVE_DISPATCH_H
|
||||
|
||||
/* Define to 1 if you have the `dladdr' function. */
|
||||
#undef HAVE_DLADDR
|
||||
|
||||
|
@ -762,44 +765,26 @@
|
|||
/* Define if using the libffi library for invocations */
|
||||
#undef USE_LIBFFI
|
||||
|
||||
/* Enable extensions on AIX 3, Interix. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
|
||||
|
||||
/* Define if vasprintf returns the length printed */
|
||||
#undef VASPRINTF_RETURNS_LENGTH
|
||||
|
||||
/* Define if vsprintf returns the length printed */
|
||||
#undef VSPRINTF_RETURNS_LENGTH
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# undef WORDS_BIGENDIAN
|
||||
# endif
|
||||
/* Define to 1 if your processor stores words with the most significant byte
|
||||
first (like Motorola and SPARC, unlike Intel and VAX). */
|
||||
#undef WORDS_BIGENDIAN
|
||||
|
||||
/* Define to 1 if on AIX 3.
|
||||
System headers sometimes define this.
|
||||
We just want to avoid a redefinition error message. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
|
@ -812,6 +797,14 @@
|
|||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
#undef _POSIX_SOURCE
|
||||
|
||||
/* Enable extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
|
|
139
Source/GSDispatch.h
Normal file
139
Source/GSDispatch.h
Normal file
|
@ -0,0 +1,139 @@
|
|||
/* Support header for conditionally enabling use of libdispatch.
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Niels Grewe <niels.grewe@halbordnung.de>
|
||||
Date: March 2012
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#import "GNUstepBase/GSConfig.h"
|
||||
#import <GNUstepBase/GSBlocks.h>
|
||||
#if HAVE_DISPATCH_H
|
||||
#include <dispatch.h>
|
||||
#elif HAVE_DISPATCH_DISPATCH_H
|
||||
#include <dispatch/dispatch.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* If gnustep-base is built with libdispatch support, these macros will expand
|
||||
* to code for creating and cleaning up after libdispach queues to which blocks
|
||||
* can be submitted. If libdispatch is not available, setup and teardown will
|
||||
* be no-ops, and the block will simply be executed on the calling thread.
|
||||
*/
|
||||
#if __has_feature(blocks) && (GS_USE_LIBDISPATCH == 1)
|
||||
|
||||
/*
|
||||
* Older versions of libdispatch do not support concurrent queues. We define away the
|
||||
* attributes in this case.
|
||||
*/
|
||||
#ifndef DISPATCH_QUEUE_SERIAL
|
||||
#define DISPATCH_QUEUE_SERIAL NULL
|
||||
#endif
|
||||
#ifndef DISPATCH_QUEUE_CONCURRENT
|
||||
#define DISPATCH_QUEUE_CONCURRENT NULL
|
||||
#endif
|
||||
|
||||
#define GS_DISPATCH_GET_DEFAULT_CONCURRENT_QUEUE() dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
|
||||
/**
|
||||
* This macro creates a dispatch queue using the attributes
|
||||
*/
|
||||
#define GS_DISPATCH_QUEUE_CREATE(attr) dispatch_queue_create(NULL, attr)
|
||||
|
||||
/**
|
||||
* Create a dispatch group
|
||||
*/
|
||||
#define GS_DISPATCH_GROUP_CREATE() dispatch_group_create()
|
||||
|
||||
/**
|
||||
* Wait for the dispatch group to finish
|
||||
*/
|
||||
#define GS_DISPATCH_GROUP_FINISH(group) dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
|
||||
|
||||
/**
|
||||
* Release an dispatch object.
|
||||
*/
|
||||
#define GS_DISPATCH_RELEASE(x) dispatch_release(x)
|
||||
/**
|
||||
* Allows an arbitrary block to be submitted to the queue. Since dispatch blocks
|
||||
* return nothing and take no arguments, the caller can use the before and after
|
||||
* arguments to set up and tear down the block as required.
|
||||
*/
|
||||
#define GS_DISPATCH_SUBMIT_BLOCK(group, queue, before, after, block, args, ...) \
|
||||
dispatch_group_async(group, queue, ^(void){before; block(args, ## __VA_ARGS__); after;})
|
||||
|
||||
/**
|
||||
* Submits a block without special provisions.
|
||||
*/
|
||||
#define GS_DISPATCH_SUBMIT_BLOCK_NO_ARGS(group, queue, block) dispatch_group_async(group, queue, block)
|
||||
|
||||
|
||||
/**
|
||||
* Convenience macro to create serial or concurrent dispatch queues for the
|
||||
* various -enumerateUsingBlock: methods.
|
||||
*/
|
||||
#define GS_DISPATCH_CREATE_QUEUE_AND_GROUP_FOR_ENUMERATION(queue, opts)\
|
||||
dispatch_queue_t queue;\
|
||||
dispatch_group_t queue ## Group;\
|
||||
if (opts & NSEnumerationConcurrent)\
|
||||
{\
|
||||
queue = GS_DISPATCH_GET_DEFAULT_CONCURRENT_QUEUE();\
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
queue = GS_DISPATCH_QUEUE_CREATE(DISPATCH_QUEUE_SERIAL);\
|
||||
}\
|
||||
queue ## Group = GS_DISPATCH_GROUP_CREATE();
|
||||
|
||||
/**
|
||||
* Convenience macro to destroy serial or concurrent dispatch queues for the
|
||||
* various -enumerateUsingBlock: methods.
|
||||
*/
|
||||
#define GS_DISPATCH_TEARDOWN_QUEUE_AND_GROUP_FOR_ENUMERATION(queue, opts)\
|
||||
GS_DISPATCH_GROUP_FINISH(queue ## Group);\
|
||||
GS_DISPATCH_RELEASE(enumQueueGroup);\
|
||||
if (NO == (opts & NSEnumerationConcurrent))\
|
||||
{\
|
||||
GS_DISPATCH_RELEASE(enumQueue);\
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* No-Op defintions if libdispatch is not supposed to be used.
|
||||
*/
|
||||
#define DISPATCH_QUEUE_SERIAL 0
|
||||
#define DISPATCH_QUEUE_CONCURRENT 0
|
||||
#define dispatch_queue_attr_t int
|
||||
#define dispatch_queue_t int
|
||||
#define dispatch_group_t int
|
||||
#define GS_DISPATCH_GET_DEFAULT_CONCURRENT_QUEUE() 0
|
||||
#define GS_DISPATCH_QUEUE_CREATE(attr) 0
|
||||
#define GS_DISPATCH_GROUP_CREATE() 0
|
||||
#define GS_DISPATCH_GROUP_FINISH(group)
|
||||
#define GS_DISPATCH_RELEASE(x)
|
||||
#define GS_DISPATCH_SUBMIT_BLOCK(group, queue, before, after, block, args...) CALL_BLOCK(block, args)
|
||||
#define GS_DISPATCH_SUBMIT_BLOCK_NO_ARGS(group, queue, block) CALL_BLOCK_NO_ARGS(block)
|
||||
#define GS_DISPATCH_CREATE_QUEUE_AND_GROUP_FOR_ENUMERATION(queue, opts)
|
||||
#define GS_DISPATCH_TEARDOWN_QUEUE_AND_GROUP_FOR_ENUMERATION(queue, opts)
|
||||
#endif
|
||||
|
||||
|
||||
|
181
Source/NSArray.m
181
Source/NSArray.m
|
@ -52,7 +52,7 @@
|
|||
#import "GNUstepBase/NSObject+GNUstepBase.h"
|
||||
#import "GSPrivate.h"
|
||||
#import "GSFastEnumeration.h"
|
||||
|
||||
#import "GSDispatch.h"
|
||||
static BOOL GSMacOSXCompatiblePropertyLists(void)
|
||||
{
|
||||
if (GSPrivateDefaultsFlag(NSWriteOldStylePropertyLists) == YES)
|
||||
|
@ -388,7 +388,7 @@ static SEL rlSel;
|
|||
return 0;
|
||||
}
|
||||
|
||||
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
|
||||
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
|
||||
objects: (__unsafe_unretained id[])stackbuf
|
||||
count: (NSUInteger)len
|
||||
{
|
||||
|
@ -1442,7 +1442,7 @@ compare(id elem1, id elem2, void* context)
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
d += [[o valueForKeyPath: rem] doubleValue];
|
||||
|
@ -1457,7 +1457,7 @@ compare(id elem1, id elem2, void* context)
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
o = [o valueForKeyPath: rem];
|
||||
|
@ -1475,7 +1475,7 @@ compare(id elem1, id elem2, void* context)
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
o = [o valueForKeyPath: rem];
|
||||
|
@ -1495,7 +1495,7 @@ compare(id elem1, id elem2, void* context)
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
d += [[o valueForKeyPath: rem] doubleValue];
|
||||
|
@ -1509,7 +1509,7 @@ compare(id elem1, id elem2, void* context)
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
result = [NSMutableSet set];
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
|
@ -1529,7 +1529,7 @@ compare(id elem1, id elem2, void* context)
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
result = [NSMutableSet set];
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
|
@ -1549,7 +1549,7 @@ compare(id elem1, id elem2, void* context)
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
result = [NSMutableSet set];
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
|
@ -1569,7 +1569,7 @@ compare(id elem1, id elem2, void* context)
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
result = [GSMutableArray array];
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
|
@ -1589,7 +1589,7 @@ compare(id elem1, id elem2, void* context)
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
result = [GSMutableArray array];
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
|
@ -1609,7 +1609,7 @@ compare(id elem1, id elem2, void* context)
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
result = [GSMutableArray array];
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
|
@ -1641,45 +1641,63 @@ compare(id elem1, id elem2, void* context)
|
|||
{
|
||||
[self enumerateObjectsWithOptions: 0 usingBlock: aBlock];
|
||||
}
|
||||
- (void) enumerateObjectsWithOptions: (NSEnumerationOptions)opts
|
||||
- (void) enumerateObjectsWithOptions: (NSEnumerationOptions)opts
|
||||
usingBlock: (GSEnumeratorBlock)aBlock
|
||||
{
|
||||
NSUInteger count = 0;
|
||||
BOOL shouldStop = NO;
|
||||
BLOCK_SCOPE BOOL shouldStop = NO;
|
||||
BOOL isReverse = (opts & NSEnumerationReverse);
|
||||
id<NSFastEnumeration> enumerator = self;
|
||||
|
||||
/* If we are enumerating in reverse, use the reverse enumerator for fast
|
||||
* enumeration. */
|
||||
if (opts & NSEnumerationReverse)
|
||||
if (isReverse)
|
||||
{
|
||||
enumerator = [self reverseObjectEnumerator];
|
||||
count = ([self count] - 1);
|
||||
}
|
||||
|
||||
{
|
||||
GS_DISPATCH_CREATE_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
||||
FOR_IN (id, obj, enumerator)
|
||||
CALL_BLOCK(aBlock, obj, count++, &shouldStop);
|
||||
if (shouldStop)
|
||||
{
|
||||
return;
|
||||
}
|
||||
END_FOR_IN(enumerator)
|
||||
GS_DISPATCH_SUBMIT_BLOCK(enumQueueGroup, enumQueue, if (YES == shouldStop) {return;}, return, aBlock, obj, count, &shouldStop);
|
||||
if (isReverse)
|
||||
{
|
||||
count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
if (shouldStop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
END_FOR_IN(enumerator)
|
||||
GS_DISPATCH_TEARDOWN_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
||||
}
|
||||
}
|
||||
|
||||
- (void) enumerateObjectsAtIndexes: (NSIndexSet*)indexSet
|
||||
options: (NSEnumerationOptions)opts
|
||||
usingBlock: (GSEnumeratorBlock)block
|
||||
{
|
||||
[[self objectsAtIndexes: indexSet] enumerateObjectsWithOptions: opts
|
||||
[[self objectsAtIndexes: indexSet] enumerateObjectsWithOptions: opts
|
||||
usingBlock: block];
|
||||
}
|
||||
|
||||
- (NSIndexSet *) indexesOfObjectsWithOptions: (NSEnumerationOptions)opts
|
||||
- (NSIndexSet *) indexesOfObjectsWithOptions: (NSEnumerationOptions)opts
|
||||
passingTest: (GSPredicateBlock)predicate
|
||||
{
|
||||
/* TODO: Concurrency. */
|
||||
NSMutableIndexSet *set = [NSMutableIndexSet indexSet];
|
||||
BOOL shouldStop = NO;
|
||||
BLOCK_SCOPE BOOL shouldStop = NO;
|
||||
id<NSFastEnumeration> enumerator = self;
|
||||
NSUInteger count = 0;
|
||||
BLOCK_SCOPE NSLock *setLock = nil;
|
||||
|
||||
|
||||
|
||||
/* If we are enumerating in reverse, use the reverse enumerator for fast
|
||||
* enumeration. */
|
||||
|
@ -1687,20 +1705,44 @@ compare(id elem1, id elem2, void* context)
|
|||
{
|
||||
enumerator = [self reverseObjectEnumerator];
|
||||
}
|
||||
if (opts & NSEnumerationConcurrent)
|
||||
{
|
||||
setLock = [NSLock new];
|
||||
}
|
||||
{
|
||||
GS_DISPATCH_CREATE_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
||||
FOR_IN (id, obj, enumerator)
|
||||
# if __has_feature(blocks) && (GS_USE_LIBDISPATCH == 1)
|
||||
|
||||
FOR_IN (id, obj, enumerator)
|
||||
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(enumerator)
|
||||
dispatch_group_async(enumQueueGroup, enumQueue, ^(void){
|
||||
if (shouldStop)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (predicate(obj, count, &shouldStop))
|
||||
{
|
||||
[setLock lock];
|
||||
[set addIndex: count];
|
||||
[setLock unlock];
|
||||
}
|
||||
});
|
||||
# else
|
||||
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];
|
||||
}
|
||||
# endif
|
||||
if (shouldStop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
END_FOR_IN(enumerator)
|
||||
GS_DISPATCH_TEARDOWN_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts);
|
||||
}
|
||||
[setLock release];
|
||||
return set;
|
||||
}
|
||||
|
||||
|
@ -1718,14 +1760,15 @@ compare(id elem1, id elem2, void* context)
|
|||
passingTest: predicate];
|
||||
}
|
||||
|
||||
- (NSUInteger)indexOfObjectWithOptions: (NSEnumerationOptions)opts
|
||||
- (NSUInteger)indexOfObjectWithOptions: (NSEnumerationOptions)opts
|
||||
passingTest: (GSPredicateBlock)predicate
|
||||
{
|
||||
/* TODO: Concurrency. */
|
||||
id<NSFastEnumeration> enumerator = self;
|
||||
BOOL shouldStop = NO;
|
||||
BLOCK_SCOPE BOOL shouldStop = NO;
|
||||
NSUInteger count = 0;
|
||||
|
||||
BLOCK_SCOPE NSUInteger index = NSNotFound;
|
||||
BLOCK_SCOPE NSLock *indexLock = nil;
|
||||
/* If we are enumerating in reverse, use the reverse enumerator for fast
|
||||
* enumeration. */
|
||||
if (opts & NSEnumerationReverse)
|
||||
|
@ -1733,18 +1776,48 @@ compare(id elem1, id elem2, void* context)
|
|||
enumerator = [self reverseObjectEnumerator];
|
||||
}
|
||||
|
||||
FOR_IN (id, obj, enumerator)
|
||||
if (CALL_BLOCK(predicate, obj, count, &shouldStop))
|
||||
{
|
||||
return count;
|
||||
}
|
||||
if (shouldStop)
|
||||
{
|
||||
return NSNotFound;
|
||||
}
|
||||
count++;
|
||||
END_FOR_IN(enumerator)
|
||||
return NSNotFound;
|
||||
if (opts & NSEnumerationConcurrent)
|
||||
{
|
||||
indexLock = [NSLock new];
|
||||
}
|
||||
{
|
||||
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)
|
||||
{
|
||||
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];
|
||||
}
|
||||
});
|
||||
# else
|
||||
if (CALL_BLOCK(predicate, obj, count, &shouldStop))
|
||||
{
|
||||
|
||||
index = count;
|
||||
shouldStop = YES;
|
||||
}
|
||||
# endif
|
||||
if (shouldStop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
END_FOR_IN(enumerator)
|
||||
GS_DISPATCH_TEARDOWN_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts);
|
||||
}
|
||||
[indexLock release];
|
||||
return index;
|
||||
}
|
||||
|
||||
- (NSUInteger) indexOfObjectPassingTest: (GSPredicateBlock)predicate
|
||||
|
@ -2215,8 +2288,8 @@ compare(id elem1, id elem2, void* context)
|
|||
NSUInteger count = [indexes count];
|
||||
NSUInteger indexArray[count];
|
||||
|
||||
[indexes getIndexes: indexArray
|
||||
maxCount: count
|
||||
[indexes getIndexes: indexArray
|
||||
maxCount: count
|
||||
inIndexRange: NULL];
|
||||
|
||||
[self removeObjectsFromIndices: indexArray
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#import "Foundation/NSAutoreleasePool.h"
|
||||
#import "Foundation/NSFileManager.h"
|
||||
#import "Foundation/NSCoder.h"
|
||||
#import "Foundation/NSLock.h"
|
||||
#import "Foundation/NSSet.h"
|
||||
#import "Foundation/NSValue.h"
|
||||
#import "Foundation/NSKeyValueCoding.h"
|
||||
|
@ -43,6 +44,7 @@
|
|||
#import "GNUstepBase/NSObject+GNUstepBase.h"
|
||||
#import "GSPrivate.h"
|
||||
#import "GSFastEnumeration.h"
|
||||
#import "GSDispatch.h"
|
||||
|
||||
static BOOL GSMacOSXCompatiblePropertyLists(void)
|
||||
{
|
||||
|
@ -162,25 +164,26 @@ static SEL appSel;
|
|||
usingBlock: (GSKeysAndObjectsEnumeratorBlock)aBlock
|
||||
{
|
||||
/*
|
||||
* NOTE: For the moment, we ignore the NSEnumerationOptions because, according
|
||||
* to the Cocoa documentation, NSEnumerationReverse is undefined for
|
||||
* NSDictionary and we cannot handle NSEnumerationConcurrent without
|
||||
* libdispatch.
|
||||
* NOTE: According to the Cocoa documentation, NSEnumerationReverse is
|
||||
* undefined for NSDictionary. NSEnumerationConcurrent will be handled through
|
||||
* the GS_DISPATCH_* macros if libdispatch is available.
|
||||
*/
|
||||
id<NSFastEnumeration> enumerator = [self keyEnumerator];
|
||||
SEL objectForKeySelector = @selector(objectForKey:);
|
||||
IMP objectForKey = [self methodForSelector: objectForKeySelector];
|
||||
BOOL shouldStop = NO;
|
||||
BLOCK_SCOPE BOOL shouldStop = NO;
|
||||
id obj;
|
||||
|
||||
GS_DISPATCH_CREATE_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
||||
FOR_IN(id, key, enumerator)
|
||||
obj = (*objectForKey)(self, objectForKeySelector, key);
|
||||
CALL_BLOCK(aBlock, key, obj, &shouldStop);
|
||||
GS_DISPATCH_SUBMIT_BLOCK(enumQueueGroup, enumQueue, if (shouldStop){return;};, return;, aBlock, key, obj, &shouldStop);
|
||||
if (YES == shouldStop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
END_FOR_IN(enumerator)
|
||||
GS_DISPATCH_TEARDOWN_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1008,24 +1011,47 @@ compareIt(id o1, id o2, void* context)
|
|||
id<NSFastEnumeration> enumerator = [self keyEnumerator];
|
||||
SEL objectForKeySelector = @selector(objectForKey:);
|
||||
IMP objectForKey = [self methodForSelector: objectForKeySelector];
|
||||
BOOL shouldStop = NO;
|
||||
BLOCK_SCOPE BOOL shouldStop = NO;
|
||||
NSMutableSet *buildSet = [NSMutableSet new];
|
||||
SEL addObjectSelector = @selector(addObject:);
|
||||
IMP addObject = [buildSet methodForSelector: addObjectSelector];
|
||||
NSSet *resultSet = nil;
|
||||
id obj;
|
||||
id obj = nil;
|
||||
BLOCK_SCOPE NSLock *setLock = nil;
|
||||
|
||||
if (opts & NSEnumerationConcurrent)
|
||||
{
|
||||
setLock = [NSLock new];
|
||||
}
|
||||
GS_DISPATCH_CREATE_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
||||
FOR_IN(id, key, enumerator)
|
||||
obj = (*objectForKey)(self, objectForKeySelector, key);
|
||||
# if (__has_feature(blocks) && (GS_USE_LIBDISPATCH == 1))
|
||||
dispatch_group_async(enumQueueGroup, enumQueue, ^(void){if (shouldStop)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (aPredicate(key, obj, &shouldStop))
|
||||
{
|
||||
[setLock lock];
|
||||
addObject(buildSet, addObjectSelector, key);
|
||||
[setLock unlock];
|
||||
}
|
||||
});
|
||||
# else
|
||||
if (CALL_BLOCK(aPredicate, key, obj, &shouldStop))
|
||||
{
|
||||
addObject(buildSet, addObjectSelector, key);
|
||||
}
|
||||
# endif
|
||||
|
||||
if (YES == shouldStop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
END_FOR_IN(enumerator)
|
||||
GS_DISPATCH_TEARDOWN_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
||||
[setLock release];
|
||||
resultSet = [NSSet setWithSet: buildSet];
|
||||
[buildSet release];
|
||||
return resultSet;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#import "Foundation/NSData.h"
|
||||
#import "Foundation/NSIndexSet.h"
|
||||
#import "Foundation/NSException.h"
|
||||
#import "GSDispatch.h"
|
||||
|
||||
#define GSI_ARRAY_TYPE NSRange
|
||||
|
||||
|
@ -44,6 +45,7 @@
|
|||
static void sanity(GSIArray array)
|
||||
{
|
||||
if (array != 0)
|
||||
|
||||
{
|
||||
NSUInteger c = GSIArrayCount(array);
|
||||
NSUInteger i;
|
||||
|
@ -68,7 +70,7 @@ static void sanity(GSIArray array)
|
|||
}
|
||||
#define SANITY() sanity(_array)
|
||||
#else
|
||||
#define SANITY()
|
||||
#define SANITY()
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -254,7 +256,7 @@ static NSUInteger posForIndex(GSIArray array, NSUInteger index)
|
|||
while (i < count)
|
||||
{
|
||||
NSRange r = GSIArrayItemAtIndex(_array, i).ext;
|
||||
|
||||
|
||||
r = NSIntersectionRange(r, range);
|
||||
total += r.length;
|
||||
i++;
|
||||
|
@ -313,7 +315,7 @@ static NSUInteger posForIndex(GSIArray array, NSUInteger index)
|
|||
{
|
||||
rangeCount = GSIArrayCount(_array);
|
||||
}
|
||||
|
||||
|
||||
if ([aCoder allowsKeyedCoding])
|
||||
{
|
||||
[aCoder encodeInt: rangeCount forKey: @"NSRangeCount"];
|
||||
|
@ -323,7 +325,7 @@ static NSUInteger posForIndex(GSIArray array, NSUInteger index)
|
|||
[aCoder encodeValueOfObjCType: @encode(NSUInteger)
|
||||
at: &rangeCount];
|
||||
}
|
||||
|
||||
|
||||
if (rangeCount == 0)
|
||||
{
|
||||
// Do nothing
|
||||
|
@ -331,7 +333,7 @@ static NSUInteger posForIndex(GSIArray array, NSUInteger index)
|
|||
else if (rangeCount == 1)
|
||||
{
|
||||
NSRange r;
|
||||
|
||||
|
||||
r = GSIArrayItemAtIndex(_array, 0).ext;
|
||||
if ([aCoder allowsKeyedCoding])
|
||||
{
|
||||
|
@ -356,14 +358,14 @@ static NSUInteger posForIndex(GSIArray array, NSUInteger index)
|
|||
NSRange r;
|
||||
NSUInteger v;
|
||||
uint8_t b;
|
||||
|
||||
|
||||
r = GSIArrayItemAtIndex(_array, i).ext;
|
||||
v = r.location;
|
||||
do
|
||||
{
|
||||
if (v > 0x7f)
|
||||
{
|
||||
b = (v & 0x7f) | 0x80;
|
||||
b = (v & 0x7f) | 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -378,7 +380,7 @@ static NSUInteger posForIndex(GSIArray array, NSUInteger index)
|
|||
{
|
||||
if (v > 0x7f)
|
||||
{
|
||||
b = (v & 0x7f) | 0x80;
|
||||
b = (v & 0x7f) | 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -602,7 +604,7 @@ static NSUInteger posForIndex(GSIArray array, NSUInteger index)
|
|||
{
|
||||
NSUInteger len = 0;
|
||||
NSUInteger loc = 0;
|
||||
|
||||
|
||||
if ([aCoder allowsKeyedCoding])
|
||||
{
|
||||
if ([aCoder containsValueForKey: @"NSLocation"])
|
||||
|
@ -861,6 +863,125 @@ static NSUInteger posForIndex(GSIArray array, NSUInteger index)
|
|||
return [c initWithIndexSet: self];
|
||||
}
|
||||
|
||||
|
||||
- (void)enumerateIndexesInRange: (NSRange)range
|
||||
options: (NSEnumerationOptions)opts
|
||||
usingBlock: (GSIndexSetEnumerationBlock)aBlock
|
||||
{
|
||||
NSUInteger lastInRange = (NSMaxRange(range) - 1);
|
||||
NSUInteger startArrayIndex = posForIndex(_array, range.location);
|
||||
NSUInteger endArrayIndex = MIN(posForIndex(_array, lastInRange), (GSIArrayCount(_array) - 1));
|
||||
NSUInteger i;
|
||||
NSUInteger c;
|
||||
BOOL isReverse = opts & NSEnumerationReverse;
|
||||
BLOCK_SCOPE BOOL shouldStop = NO;
|
||||
|
||||
if ((0 == [self count]) || (NSNotFound == range.location))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (NSNotFound == startArrayIndex)
|
||||
{
|
||||
startArrayIndex = 0;
|
||||
}
|
||||
|
||||
if (NSNotFound == endArrayIndex)
|
||||
{
|
||||
endArrayIndex = GSIArrayCount(_array) - 1;
|
||||
}
|
||||
|
||||
if (isReverse)
|
||||
{
|
||||
i = endArrayIndex;
|
||||
c = startArrayIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = startArrayIndex;
|
||||
c = endArrayIndex;
|
||||
}
|
||||
|
||||
GS_DISPATCH_CREATE_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
||||
while (isReverse ? i >= c : i <= c)
|
||||
{
|
||||
NSRange r = GSIArrayItemAtIndex(_array, i).ext;
|
||||
NSUInteger innerI;
|
||||
NSUInteger innerC;
|
||||
if (isReverse)
|
||||
{
|
||||
innerI = NSMaxRange(r) - 1;
|
||||
innerC = r.location;
|
||||
}
|
||||
else
|
||||
{
|
||||
innerI = r.location;
|
||||
innerC = NSMaxRange(r) - 1;
|
||||
}
|
||||
while (isReverse ? innerI >= innerC : innerI <= innerC)
|
||||
{
|
||||
if ((innerI <= lastInRange) && (innerI >= range.location))
|
||||
{
|
||||
GS_DISPATCH_SUBMIT_BLOCK(enumQueueGroup, enumQueue, if (shouldStop) {return;}, return;, aBlock, innerI, &shouldStop);
|
||||
}
|
||||
if (shouldStop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (isReverse)
|
||||
{
|
||||
if (0 == innerI)
|
||||
{
|
||||
break;
|
||||
}
|
||||
innerI--;
|
||||
}
|
||||
else
|
||||
{
|
||||
innerI++;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldStop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (isReverse)
|
||||
{
|
||||
if (0 == i)
|
||||
{
|
||||
break;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
GS_DISPATCH_TEARDOWN_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
||||
|
||||
}
|
||||
|
||||
- (void)enumerateIndexesWithOptions: (NSEnumerationOptions)opts
|
||||
usingBlock: (GSIndexSetEnumerationBlock)aBlock
|
||||
{
|
||||
NSUInteger firstIndex = [self firstIndex];
|
||||
NSUInteger lastIndex = [self lastIndex];
|
||||
if (NSNotFound == firstIndex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
[self enumerateIndexesInRange: NSMakeRange(firstIndex, ((lastIndex - firstIndex) + 1))
|
||||
options: opts
|
||||
usingBlock: aBlock];
|
||||
}
|
||||
|
||||
- (void)enumerateIndexesUsingBlock: (GSIndexSetEnumerationBlock)aBlock
|
||||
{
|
||||
[self enumerateIndexesWithOptions: 0
|
||||
usingBlock: aBlock];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#import "GSPrivate.h"
|
||||
#import "GNUstepBase/NSObject+GNUstepBase.h"
|
||||
#import "GSFastEnumeration.h"
|
||||
#import "GSDispatch.h"
|
||||
|
||||
@class GSSet;
|
||||
@interface GSSet : NSObject // Help the compiler
|
||||
|
@ -260,7 +261,7 @@ static Class NSMutableSet_concrete_class;
|
|||
{
|
||||
unsigned i;
|
||||
GS_BEGINIDBUF(objs, count);
|
||||
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
[aCoder decodeValueOfObjCType: @encode(id) at: &objs[i]];
|
||||
|
@ -663,7 +664,7 @@ static Class NSMutableSet_concrete_class;
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
d += [[o valueForKeyPath: rem] doubleValue];
|
||||
|
@ -678,7 +679,7 @@ static Class NSMutableSet_concrete_class;
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
o = [o valueForKeyPath: rem];
|
||||
|
@ -696,7 +697,7 @@ static Class NSMutableSet_concrete_class;
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
o = [o valueForKeyPath: rem];
|
||||
|
@ -716,7 +717,7 @@ static Class NSMutableSet_concrete_class;
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
d += [[o valueForKeyPath: rem] doubleValue];
|
||||
|
@ -730,7 +731,7 @@ static Class NSMutableSet_concrete_class;
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
result = [NSMutableSet set];
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
|
@ -750,7 +751,7 @@ static Class NSMutableSet_concrete_class;
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
result = [NSMutableSet set];
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
|
@ -770,7 +771,7 @@ static Class NSMutableSet_concrete_class;
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
result = [NSMutableSet set];
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
|
@ -790,7 +791,7 @@ static Class NSMutableSet_concrete_class;
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
result = [GSMutableArray array];
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
|
@ -810,7 +811,7 @@ static Class NSMutableSet_concrete_class;
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
result = [GSMutableArray array];
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
|
@ -830,7 +831,7 @@ static Class NSMutableSet_concrete_class;
|
|||
{
|
||||
NSEnumerator *e = [self objectEnumerator];
|
||||
id o;
|
||||
|
||||
|
||||
result = [GSMutableArray array];
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
|
@ -866,18 +867,20 @@ static Class NSMutableSet_concrete_class;
|
|||
- (void) enumerateObjectsWithOptions: (NSEnumerationOptions)opts
|
||||
usingBlock: (GSSetEnumeratorBlock)aBlock
|
||||
{
|
||||
BOOL shouldStop = NO;
|
||||
BLOCK_SCOPE BOOL shouldStop = NO;
|
||||
id<NSFastEnumeration> enumerator = self;
|
||||
|
||||
|
||||
GS_DISPATCH_CREATE_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
||||
FOR_IN (id, obj, enumerator)
|
||||
{
|
||||
CALL_BLOCK(aBlock, obj, &shouldStop);
|
||||
GS_DISPATCH_SUBMIT_BLOCK(enumQueueGroup,enumQueue, if (shouldStop) {return;}, return;, aBlock, obj, &shouldStop);
|
||||
if (shouldStop)
|
||||
{
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
END_FOR_IN(enumerator)
|
||||
GS_DISPATCH_TEARDOWN_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
||||
}
|
||||
|
||||
/** Return a set formed by adding anObject to the receiver.
|
||||
|
@ -922,7 +925,7 @@ static Class NSMutableSet_concrete_class;
|
|||
return [s autorelease];
|
||||
}
|
||||
|
||||
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
|
||||
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
|
||||
objects: (id*)stackbuf
|
||||
count: (NSUInteger)len
|
||||
{
|
||||
|
|
58
Tests/base/NSArray/blocks.m
Normal file
58
Tests/base/NSArray/blocks.m
Normal file
|
@ -0,0 +1,58 @@
|
|||
#import "Testing.h"
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSIndexSet.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
|
||||
|
||||
static NSUInteger fooCount = 0;
|
||||
static NSUInteger lastIndex = NSNotFound;
|
||||
int main()
|
||||
{
|
||||
START_SET("NSArray Blocks")
|
||||
# ifndef __has_feature
|
||||
# define __has_feature(x) 0
|
||||
# endif
|
||||
# if __has_feature(blocks)
|
||||
NSAutoreleasePool *arp = [NSAutoreleasePool new];
|
||||
|
||||
NSArray *array = [NSArray arrayWithObjects: @"foo", @"bar", @"foo", nil];
|
||||
void(^enumBlock)(id,NSUInteger,BOOL*) = ^(id obj, NSUInteger index, BOOL *stop){
|
||||
if ([obj isEqual: @"foo"]){ fooCount++;} lastIndex = index;};
|
||||
[array enumerateObjectsUsingBlock: enumBlock];
|
||||
PASS((2 == fooCount) && (lastIndex == 2),
|
||||
"Can forward enumerate array using a block");
|
||||
fooCount = 0;
|
||||
lastIndex = NSNotFound;
|
||||
[array enumerateObjectsWithOptions: NSEnumerationConcurrent
|
||||
usingBlock: enumBlock];
|
||||
PASS((2 == fooCount) && (lastIndex == 2),
|
||||
"Can forward enumerate array concurrently using a block");
|
||||
fooCount = 0;
|
||||
lastIndex = NSNotFound;
|
||||
[array enumerateObjectsWithOptions: NSEnumerationReverse
|
||||
usingBlock: enumBlock];
|
||||
PASS((0 == lastIndex), "Can enumerate array in reverse using a block");
|
||||
fooCount = 0;
|
||||
lastIndex = NSNotFound;
|
||||
enumBlock = ^(id obj, NSUInteger index, BOOL *stop){if ([obj isEqual: @"foo"]){
|
||||
fooCount++;} else if ([obj isEqual: @"bar"]){ *stop=YES;}; lastIndex =
|
||||
index;};
|
||||
[array enumerateObjectsUsingBlock: enumBlock];
|
||||
PASS(((1 == fooCount) && (lastIndex == 1)),
|
||||
"Block can stop enumeration prematurely.");
|
||||
|
||||
NSIndexSet *set = [array indexesOfObjectsPassingTest: ^(id obj, NSUInteger index, BOOL* stop){ if ([obj isEqual: @"foo"]) { return YES;} return NO;}];
|
||||
PASS(((2 == [set count])
|
||||
&& (YES == [set containsIndex: 0])
|
||||
&& (YES == [set containsIndex: 2])
|
||||
&& (NO == [set containsIndex: 1])),
|
||||
"Can select object indices based on block predicate.");
|
||||
[arp release]; arp = nil;
|
||||
# else
|
||||
SKIP("No Blocks support in the compiler.")
|
||||
# endif
|
||||
END_SET("NSArray Blocks")
|
||||
return 0;
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
#import <Foundation/NSData.h>
|
||||
#import <Foundation/NSDate.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSLock.h>
|
||||
#import <Foundation/NSSet.h>
|
||||
#if defined(GNUSTEP_BASE_LIBRARY)
|
||||
#import <Foundation/NSSerialization.h>
|
||||
|
@ -23,20 +24,26 @@ int main()
|
|||
# endif
|
||||
# if __has_feature(blocks)
|
||||
NSAutoreleasePool *arp = [NSAutoreleasePool new];
|
||||
|
||||
__block NSLock *fooLock = [NSLock new];
|
||||
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: @"foo",
|
||||
@"key1", @"bar", @"key2", @"foo", @"key3", nil];
|
||||
[dict enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop){
|
||||
if ([obj isEqual: @"foo"]){ fooCount++;}}];
|
||||
void(^enumBlock)(id,id,BOOL*) = ^(id key, id obj, BOOL *stop){
|
||||
if ([obj isEqual: @"foo"]){ [fooLock lock]; fooCount++; [fooLock unlock];}};
|
||||
[dict enumerateKeysAndObjectsUsingBlock: enumBlock];
|
||||
PASS((2 == fooCount),
|
||||
"Can enumerate dictionary using a block");
|
||||
|
||||
fooCount = 0;
|
||||
[dict enumerateKeysAndObjectsWithOptions: NSEnumerationConcurrent
|
||||
usingBlock: enumBlock];
|
||||
PASS((2 == fooCount),
|
||||
"Can enumerate dictionary concurrently using a block");
|
||||
NSSet *fooKeys = [dict keysOfEntriesPassingTest: ^(id key, id obj, BOOL *stop){
|
||||
return [obj isEqual: @"foo"];}];
|
||||
PASS((([fooKeys count] == 2)
|
||||
&& ([fooKeys containsObject: @"key1"])
|
||||
&& ([fooKeys containsObject: @"key3"]))
|
||||
, "Can use blocks as predicates.");
|
||||
[fooLock release];
|
||||
[arp release]; arp = nil;
|
||||
# else
|
||||
SKIP("No Blocks support in the compiler.")
|
||||
|
|
88
Tests/base/NSMutableIndexSet/blocks.m
Normal file
88
Tests/base/NSMutableIndexSet/blocks.m
Normal file
|
@ -0,0 +1,88 @@
|
|||
#include <Foundation/NSAutoreleasePool.h>
|
||||
#include <Foundation/NSIndexSet.h>
|
||||
#import <Foundation/NSLock.h>
|
||||
#include <Testing.h>
|
||||
int main()
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
NSMutableIndexSet *set = [NSMutableIndexSet indexSetWithIndexesInRange: NSMakeRange(1,5)];
|
||||
[set addIndex:20];
|
||||
[set addIndex:25];
|
||||
|
||||
|
||||
START_SET("NSIndexSet Blocks")
|
||||
# ifndef __has_feature
|
||||
# define __has_feature(x) 0
|
||||
# endif
|
||||
# if __has_feature(blocks)
|
||||
|
||||
NSMutableIndexSet *referenceSet = nil;
|
||||
__block NSMutableIndexSet *newSet = [NSMutableIndexSet indexSet];
|
||||
__block BOOL didContainWrongIndex = NO;
|
||||
__block NSUInteger lastIndex = NSNotFound;
|
||||
NSLock *setLock = [NSLock new];
|
||||
void(^enumBlock)(NSUInteger,BOOL*) = ^(NSUInteger idx, BOOL*shouldStop){
|
||||
[setLock lock];
|
||||
lastIndex = idx;
|
||||
[newSet addIndex: idx];
|
||||
[setLock unlock];
|
||||
};
|
||||
|
||||
// Test forward enumeration:
|
||||
[set enumerateIndexesUsingBlock: enumBlock];
|
||||
PASS((YES == [set isEqual: newSet]),
|
||||
"Can enumerate all indices in an index set using a block");
|
||||
PASS((25 == lastIndex),
|
||||
"Forward enumeration stops at the last index");
|
||||
|
||||
newSet = [NSMutableIndexSet indexSet];
|
||||
didContainWrongIndex = NO;
|
||||
lastIndex = NSNotFound;
|
||||
|
||||
// Test reverse enumeration:
|
||||
[set enumerateIndexesWithOptions: NSEnumerationReverse
|
||||
usingBlock: enumBlock];
|
||||
PASS((YES == [set isEqual: newSet]),
|
||||
"Can reverse enumerate all indices in an index set using a block");
|
||||
PASS((1 == lastIndex),
|
||||
"Reverse enumeration stops at the first index");
|
||||
|
||||
referenceSet = [NSMutableIndexSet indexSetWithIndexesInRange: (NSMakeRange(4,2))];
|
||||
[referenceSet addIndex: 20];
|
||||
newSet = [NSMutableIndexSet indexSet];
|
||||
didContainWrongIndex = NO;
|
||||
lastIndex = NSNotFound;
|
||||
|
||||
// Test subrange enumeration:
|
||||
[set enumerateIndexesInRange: NSMakeRange(4,20)
|
||||
options: 0
|
||||
usingBlock: enumBlock];
|
||||
PASS((YES == [referenceSet isEqual: newSet]), "Can enumerate subranges of an index set");
|
||||
PASS((20 == lastIndex), "Subrange enumeration stops at the correct index");
|
||||
|
||||
newSet = [NSMutableIndexSet indexSet];
|
||||
lastIndex = NSNotFound;
|
||||
referenceSet = [NSMutableIndexSet indexSetWithIndexesInRange: NSMakeRange(1,5)];
|
||||
[referenceSet addIndex: 20];
|
||||
enumBlock = ^(NSUInteger idx, BOOL*shouldStop){
|
||||
[setLock lock];
|
||||
[newSet addIndex: idx];
|
||||
[setLock unlock];
|
||||
if (20 == idx)
|
||||
{
|
||||
*shouldStop = YES;
|
||||
}
|
||||
};
|
||||
|
||||
// Test premature termination of enumeration:
|
||||
[set enumerateIndexesUsingBlock: enumBlock];
|
||||
PASS((YES == [referenceSet isEqual: newSet]), "block can prematurely terminate enumeration");
|
||||
|
||||
[setLock release];
|
||||
# else
|
||||
SKIP("No Blocks support in the compiler.")
|
||||
# endif
|
||||
END_SET("NSIndexSet Blocks")
|
||||
[pool release];
|
||||
return 0;
|
||||
}
|
|
@ -40,6 +40,7 @@ GNUSTEP_BASE_HAVE_GNUTLS=@HAVE_GNUTLS@
|
|||
GNUSTEP_BASE_HAVE_MDNS=@HAVE_MDNS@
|
||||
GNUSTEP_BASE_HAVE_AVAHI=@HAVE_AVAHI@
|
||||
GNUSTEP_BASE_HAVE_ICU=@HAVE_ICU@
|
||||
GNUSTEP_BASE_HAVE_LIBDISPATCH=@HAVE_LIBDISPATCH@
|
||||
|
||||
# Futureproofing ... if we ever use non-ascii string constants in base,
|
||||
# we need to make sure that anyone building base uses the expected input
|
||||
|
|
43
configure.ac
43
configure.ac
|
@ -2972,7 +2972,7 @@ AC_SUBST(HAVE_AVAHI)
|
|||
#--------------------------------------------------------------------
|
||||
HAVE_ICU=0
|
||||
AC_ARG_ENABLE(icu,
|
||||
[ --disable-icu Disable International Components for Unicode],,
|
||||
[ --disable-icu Disable International Components for Unicode],,
|
||||
enable_icu=yes)
|
||||
|
||||
if test $enable_icu = yes; then
|
||||
|
@ -2996,6 +2996,47 @@ if test $enable_icu = yes; then
|
|||
fi
|
||||
AC_SUBST(HAVE_ICU)
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Check for libdispatch
|
||||
# See DEPENDENCIES POLICY at the start of this file.
|
||||
#--------------------------------------------------------------------
|
||||
HAVE_LIBDISPATCH=0
|
||||
AC_ARG_ENABLE(libdispatch,
|
||||
[ --disable-libdispatch Disable dispatching blocks via libdispatch],
|
||||
enable_libdispatch=no,
|
||||
enable_libdispatch=yes)
|
||||
|
||||
if test $enable_libdispatch = yes; then
|
||||
AC_CHECK_HEADERS(dispatch.h, have_dispatch=yes, have_dispatch=no)
|
||||
if test "$have_dispatch" = "no"; then
|
||||
AC_CHECK_HEADERS(dispatch/dispatch.h, have_dispatch=yes, have_dispatch=no)
|
||||
fi
|
||||
if test "$have_dispatch" = "yes"; then
|
||||
AC_CHECK_LIB(dispatch, dispatch_queue_create, have_dispatch=yes, have_dispatch=no)
|
||||
if test "$have_dispatch" = "yes"; then
|
||||
saveLIBS="$LIBS"
|
||||
LIBS="-lobjc -ldispatch";
|
||||
# This check is needed because libdispatch might be linked against a
|
||||
# version of libBlocksRuntime that defines symbols conflicting with libobjc
|
||||
AC_MSG_CHECKING(whether we can link libdispatch and libobjc at the same time)
|
||||
AC_TRY_LINK(,,have_dispatch=yes, have_dispatch=no)
|
||||
if test "$have_dispatch" = "yes"; then
|
||||
LIBS="$saveLIBS -ldispatch";
|
||||
AC_MSG_RESULT(yes);
|
||||
HAVE_LIBDISPATCH=1;
|
||||
else
|
||||
LIBS="$saveLIBS";
|
||||
AC_MSG_RESULT(no);
|
||||
fi
|
||||
fi
|
||||
else
|
||||
HAVE_LIBDISPATCH=0;
|
||||
# just ignore libdispatch if it's not there
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(HAVE_LIBDISPATCH)
|
||||
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Check GMP for NSDecimal
|
||||
#--------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue