Index: src/OFArray.h ================================================================== --- src/OFArray.h +++ src/OFArray.h @@ -19,10 +19,11 @@ @class OFString; #ifdef OF_HAVE_BLOCKS typedef void (^of_array_enumeration_block_t)(id obj, size_t idx, BOOL *stop); typedef BOOL (^of_array_filter_block_t)(id odj, size_t idx); +typedef id (^of_array_map_block_t)(id obj, size_t idx); #endif /** * \brief A class for storing objects in an array. */ @@ -205,10 +206,18 @@ * * \param block The block to execute for each object */ - (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block; +/** + * Returns a new array, mapping each object using the specified block. + * + * \param block A block which maps an object for each object + * \return A new, autoreleased OFArray + */ +- (OFArray*)mappedArrayUsingBlock: (of_array_map_block_t)block; + /** * Returns a new array, only containing the objects for which the block returns * YES. * * \param block A block which determines if the object should be in the new Index: src/OFArray.m ================================================================== --- src/OFArray.m +++ src/OFArray.m @@ -400,10 +400,30 @@ BOOL stop = NO; for (i = 0; i < count && !stop; i++) block(objs[i], i, &stop); } + +- (OFArray*)mappedArrayUsingBlock: (of_array_map_block_t)block +{ + size_t count = [array count]; + id *tmp = [self allocMemoryForNItems: count + withSize: sizeof(id)]; + + @try { + id *objs = [array cArray]; + size_t i; + + for (i = 0; i < count; i++) + tmp[i] = block(objs[i], i); + + return [OFArray arrayWithCArray: tmp + length: count]; + } @finally { + [self freeMemory: tmp]; + } +} - (OFArray*)filteredArrayUsingBlock: (of_array_filter_block_t)block { size_t count = [array count]; id *tmp = [self allocMemoryForNItems: count Index: src/OFDictionary.h ================================================================== --- src/OFDictionary.h +++ src/OFDictionary.h @@ -18,10 +18,11 @@ @class OFArray; #ifdef OF_HAVE_BLOCKS typedef void (^of_dictionary_enumeration_block_t)(id key, id obj, BOOL *stop); typedef BOOL (^of_dictionary_filter_block_t)(id key, id obj); +typedef id (^of_dictionary_map_block_t)(id key, id obj); #endif struct of_dictionary_bucket { id key; @@ -164,10 +165,18 @@ * \param block The block to execute for each key / object pair. */ - (void)enumerateKeysAndObjectsUsingBlock: (of_dictionary_enumeration_block_t)block; +/** + * Returns a new dictionary, mapping each object using the specified block. + * + * \param block A block which maps an object for each object + * \return A new, autorelease OFDictionary + */ +- (OFDictionary*)mappedDictionaryUsingBlock: (of_dictionary_map_block_t)block; + /** * Returns a new dictionary, only containing the objects for which the block * returns YES. * * \param block A block which determines if the object should be in the new Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -572,10 +572,23 @@ for (i = 0; i < size && !stop; i++) if (data[i] != NULL && data[i] != DELETED) block(data[i]->key, data[i]->object, &stop); } + +- (OFDictionary*)mappedDictionaryUsingBlock: (of_dictionary_map_block_t)block +{ + OFMutableDictionary *dict = [OFMutableDictionary dictionary]; + size_t i; + + for (i = 0; i < size; i++) + if (data[i] != NULL && data[i] != DELETED) + [dict setObject: block(data[i]->key, data[i]->object) + forKey: data[i]->key]; + + return dict; +} - (OFDictionary*)filteredDictionaryUsingBlock: (of_dictionary_filter_block_t)block { OFMutableDictionary *dict = [OFMutableDictionary dictionary]; Index: tests/OFArrayTests.m ================================================================== --- tests/OFArrayTests.m +++ tests/OFArrayTests.m @@ -248,14 +248,26 @@ } return nil; }]) && [[m[0] description] isEqual: @"(foo, bar)"]) + TEST(@"-[mappedArrayUsingBLock]", + [[[m[0] mappedArrayUsingBlock: ^ id (id obj, size_t idx) { + switch (idx) { + case 0: + return @"foobar"; + case 1: + return @"qux"; + } + + return nil; + }] description] isEqual: @"(foobar, qux)"]) + TEST(@"-[filteredArrayUsingBlock:]", [[[m[0] filteredArrayUsingBlock: ^ BOOL (id obj, size_t idx) { return ([obj isEqual: @"foo"] ? YES : NO); }] description] isEqual: @"(foo)"]) #endif [pool drain]; } @end Index: tests/OFDictionaryTests.m ================================================================== --- tests/OFDictionaryTests.m +++ tests/OFDictionaryTests.m @@ -142,10 +142,20 @@ return nil; }]) && [[dict objectForKey: keys[0]] isEqual: @"value_1"] && [[dict objectForKey: keys[1]] isEqual: @"value_2"]) + TEST(@"-[mappedDictionaryUsingBlock:]", + [[[dict mappedDictionaryUsingBlock: ^ id (id key, id obj) { + if ([key isEqual: keys[0]]) + return @"val1"; + if ([key isEqual: keys[1]]) + return @"val2"; + + return nil; + }] description] isEqual: @"{key1 = val1; key2 = val2}"]) + TEST(@"-[filteredDictionaryUsingBlock:]", [[[dict filteredDictionaryUsingBlock: ^ BOOL (id key, id obj) { return ([key isEqual: keys[0]] ? YES : NO); }] description] isEqual: @"{key1 = value_1}"]) #endif