Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -36,12 +36,11 @@ for (id i in n); ], [ AC_DEFINE(OF_HAVE_FAST_ENUMERATION, 1, [Compiler support for Fast Enumeration]) AC_MSG_RESULT(yes) - ], [ - AC_MSG_RESULT(no)]) + ], [AC_MSG_RESULT(no)]) AC_MSG_CHECKING(whether Objective C compiler supports properties) AC_TRY_COMPILE([ #import @@ -58,12 +57,25 @@ [foo bar]; ], [ AC_DEFINE(OF_HAVE_PROPERTIES, 1, [Compiler support for properties]) AC_SUBST(PROPERTIESTESTS_M, "PropertiesTests.m") AC_MSG_RESULT(yes) + ], [AC_MSG_RESULT(no)]) + +AC_MSG_CHECKING(whether Objective C compiler supports blocks) +old_OBJCFLAGS="$OBJCFLAGS" +OBJCFLAGS="$OBJCFLAGS -fblocks" +AC_TRY_COMPILE([], [ + int (^foo)(int bar); + foo = ^(int bar) { return 0; } + ], [ + AC_DEFINE(OF_HAVE_BLOCKS, 1, [Compiler support for blocks]) + AC_MSG_RESULT(yes) ], [ - AC_MSG_RESULT(no)]) + AC_MSG_RESULT(no) + OBJCFLAGS="$old_OBJCFLAGS" + ]) AC_CHECK_HEADERS([objfw-rt.h objc/objc.h]) test x"$ac_cv_header_objfw_rt_h" = x"yes" && objc_runtime="ObjFW-RT" Index: src/OFArray.h ================================================================== --- src/OFArray.h +++ src/OFArray.h @@ -15,10 +15,14 @@ #import "OFEnumerator.h" @class OFDataArray; @class OFString; +#ifdef OF_HAVE_BLOCKS +typedef void (^of_array_enumeration_block_t)(id obj, size_t idx, BOOL *stop); +#endif + /** * \brief A class for storing objects in an array. */ @interface OFArray: OFObject { @@ -180,10 +184,19 @@ /** * \return An OFEnumerator to enumarate through the array's objects */ - (OFEnumerator*)enumerator; + +#ifdef OF_HAVE_BLOCKS +/** + * Executes a block for each object. + * + * \param block The block to execute for each object + */ +- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block; +#endif @end /// \cond internal @interface OFArrayEnumerator: OFEnumerator { Index: src/OFArray.m ================================================================== --- src/OFArray.m +++ src/OFArray.m @@ -209,11 +209,11 @@ return new; } - (id)objectAtIndex: (size_t)index { - return *((OFObject**)[array itemAtIndex: index]); + return *((id*)[array itemAtIndex: index]); } - (size_t)indexOfObject: (OFObject*)obj { id *objs = [array cArray]; @@ -348,10 +348,22 @@ { return [[[OFArrayEnumerator alloc] initWithDataArray: array mutationsPointer: NULL] autorelease]; } + +#ifdef OF_HAVE_BLOCKS +- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block +{ + OFObject **objs = [array cArray]; + size_t i, count = [array count]; + BOOL stop = NO; + + for (i = 0; i < count && !stop; i++) + block(objs[i], i, &stop); +} +#endif - (void)dealloc { OFObject **objs = [array cArray]; size_t i, count = [array count]; Index: src/OFDictionary.h ================================================================== --- src/OFDictionary.h +++ src/OFDictionary.h @@ -13,10 +13,14 @@ #import "OFObject.h" #import "OFEnumerator.h" @class OFArray; + +#ifdef OF_HAVE_BLOCKS +typedef void (^of_dictionary_enumeration_block_t)(id key, id obj, BOOL *stop); +#endif /// \cond internal struct of_dictionary_bucket { OFObject *key; @@ -164,10 +168,20 @@ /** * \return An OFEnumerator to enumerate through the dictionary's keys */ - (OFEnumerator*)keyEnumerator; + +#ifdef OF_HAVE_BLOCKS +/** + * Executes a block for each key / object pair. + * + * \param block The block to execute for each key / object pair. + */ +- (void)enumerateKeysAndObjectsUsingBlock: + (of_dictionary_enumeration_block_t)block; +#endif @end /// \cond internal @interface OFDictionaryEnumerator: OFEnumerator { Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -634,10 +634,23 @@ return [[[OFDictionaryKeyEnumerator alloc] initWithData: data size: size mutationsPointer: NULL] autorelease]; } + +#ifdef OF_HAVE_BLOCKS +- (void)enumerateKeysAndObjectsUsingBlock: + (of_dictionary_enumeration_block_t)block +{ + size_t i; + BOOL stop = NO; + + for (i = 0; i < size && !stop; i++) + if (data[i] != NULL && data[i] != DELETED) + block(data[i]->key, data[i]->object, &stop); +} +#endif - (void)dealloc { uint32_t i; Index: src/OFMutableArray.m ================================================================== --- src/OFMutableArray.m +++ src/OFMutableArray.m @@ -233,6 +233,24 @@ { return [[[OFArrayEnumerator alloc] initWithDataArray: array mutationsPointer: &mutations] autorelease]; } + +#ifdef OF_HAVE_BLOCKS +- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block +{ + OFObject **objs = [array cArray]; + size_t i, count = [array count]; + BOOL stop = NO; + unsigned long mutations2 = mutations; + + for (i = 0; i < count && !stop; i++) { + if (mutations != mutations2) + @throw [OFEnumerationMutationException + newWithClass: isa]; + + block(objs[i], i, &stop); + } +} +#endif @end Index: src/OFMutableDictionary.m ================================================================== --- src/OFMutableDictionary.m +++ src/OFMutableDictionary.m @@ -262,6 +262,25 @@ return [[[OFDictionaryKeyEnumerator alloc] initWithData: data size: size mutationsPointer: &mutations] autorelease]; } + +#ifdef OF_HAVE_BLOCKS +- (void)enumerateKeysAndObjectsUsingBlock: + (of_dictionary_enumeration_block_t)block +{ + size_t i; + BOOL stop = NO; + unsigned long mutations2 = mutations; + + for (i = 0; i < size && !stop; i++) { + if (mutations != mutations2) + @throw [OFEnumerationMutationException + newWithClass: isa]; + + if (data[i] != NULL && data[i] != DELETED) + block(data[i]->key, data[i]->object, &stop); + } +} +#endif @end Index: src/objfw-defs.h.in ================================================================== --- src/objfw-defs.h.in +++ src/objfw-defs.h.in @@ -2,10 +2,11 @@ #undef OF_HAVE_ASPRINTF #undef OF_ATOMIC_OPS #undef OF_BIG_ENDIAN #undef OF_GNU_RUNTIME #undef OF_HAVE_ASPRINTF +#undef OF_HAVE_BLOCKS #undef OF_HAVE_FAST_ENUMERATION #undef OF_HAVE_GCC_ATOMIC_OPS #undef OF_HAVE_LIBKERN_OSATOMIC_H #undef OF_HAVE_POLL #undef OF_HAVE_PROPERTIES Index: tests/OFArrayTests.m ================================================================== --- tests/OFArrayTests.m +++ tests/OFArrayTests.m @@ -184,9 +184,46 @@ TEST(@"Detection of mutation during Fast Enumeration", ok) [m[0] removeNObjects: 1]; #endif + +#ifdef OF_HAVE_BLOCKS + { + __block BOOL ok = YES; + __block size_t count = 0; + OFArray *cmp = a[0]; + OFMutableArray *a2; + + m[0] = [[a[0] mutableCopy] autorelease]; + [m[0] enumerateObjectsUsingBlock: + ^ (id obj, size_t idx, BOOL *stop) { + count++; + if (![obj isEqual: [cmp objectAtIndex: idx]]) + ok = NO; + }]; + + if (count != [cmp count]) + ok = NO; + + TEST(@"Enumeration using blocks", ok) + + ok = NO; + a2 = m[0]; + @try { + [a2 enumerateObjectsUsingBlock: + ^ (id obj, size_t idx, BOOL *stop) { + [a2 removeObjectAtIndex: idx]; + }]; + } @catch (OFEnumerationMutationException *e) { + ok = YES; + [e dealloc]; + } + + TEST(@"Detection of mutation during enumeration using blocks", + ok) + } +#endif [pool drain]; } @end Index: tests/OFDictionaryTests.m ================================================================== --- tests/OFDictionaryTests.m +++ tests/OFDictionaryTests.m @@ -92,10 +92,45 @@ TEST(@"Detection of mutation during Fast Enumeration", ok) [dict removeObjectForKey: @""]; #endif + +#ifdef OF_HAVE_BLOCKS + { + __block size_t i = 0; + __block BOOL ok = YES; + + [dict enumerateKeysAndObjectsUsingBlock: + ^ (id key, id obj, BOOL *stop) { + if (![key isEqual: keys[i]]) + ok = NO; + [dict setObject: [dict objectForKey: key] + forKey: key]; + i++; + }]; + + TEST(@"Enumeration using blocks", ok) + + ok = NO; + @try { + [dict enumerateKeysAndObjectsUsingBlock: + ^ (id key, id obj, BOOL *stop) { + [dict setObject: @"" + forKey: @""]; + }]; + } @catch (OFEnumerationMutationException *e) { + ok = YES; + [e dealloc]; + } + + TEST(@"Detection of mutation during enumeration using blocks", + ok) + + [dict removeObjectForKey: @""]; + } +#endif TEST(@"-[count]", [dict count] == 2) TEST(@"+[dictionaryWithKeysAndObjects:]", (dict = [OFDictionary dictionaryWithKeysAndObjects: @"foo", @"bar",