├── .gitignore ├── ConcurrentCollectionOperations.podspec ├── ConcurrentCollectionOperations.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── ConcurrentCollectionOperations ├── BlockTypedefs.h ├── ConcurrentCollectionOperations-Info.plist ├── ConcurrentCollectionOperations-Prefix.pch ├── ConcurrentCollectionOperations-iOS-Prefix.pch ├── ConcurrentCollectionOperations.h ├── NSArray+ConcurrentCollectionOperations.h ├── NSArray+ConcurrentCollectionOperations.m ├── NSDictionary+ConcurrentCollectionOperations.h ├── NSDictionary+ConcurrentCollectionOperations.m ├── NSMapTable+ConcurrentCollectionOperations.h ├── NSMapTable+ConcurrentCollectionOperations.m ├── NSOrderedSet+ConcurrentCollectionOperations.h ├── NSOrderedSet+ConcurrentCollectionOperations.m ├── NSSet+ConcurrentCollectionOperations.h ├── NSSet+ConcurrentCollectionOperations.m └── en.lproj │ └── InfoPlist.strings ├── ConcurrentCollectionOperationsTests ├── ConcurrentCollectionOperationsBenchmarks.m ├── ConcurrentCollectionOperationsTests-Info.plist ├── ConcurrentCollectionOperationsTests.m └── en.lproj │ └── InfoPlist.strings ├── LICENSE.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | xcuserdata 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "ConcurrentCollectionOperations" 3 | s.version = "0.1.0" 4 | s.summary = "Concurrent map and filter on NSArray, NSDictionary, NSSet using GCD." 5 | s.description = <<-DESC 6 | This is a set of categories for performing concurrent map and filter 7 | operations on Foundation data structures, currently NSArray, NSDictionary, 8 | NSSet. 9 | 10 | Concurrency is achieved using Grand Central Dispatch's (GCD) dispatch_apply. 11 | By default, operations are run on the default priority global concurrent 12 | queue. The operations can be performed on any concurrent queue. This library 13 | provides similar functionality to `pmap` as found in other languages. 14 | DESC 15 | s.homepage = "https://github.com/kastiglione/ConcurrentCollectionOperations" 16 | s.license = 'MIT' 17 | s.authors = { "Dave Lee" => "dave@kastiglione.com", "Eloy Durán" => "eloy.de.enige@gmail.com", "Mateus Armando" => "seanlilmateus@yahoo.de" } 18 | s.source = { :git => "https://github.com/kastiglione/ConcurrentCollectionOperations.git", :tag => "v#{s.version}" } 19 | s.source_files = 'ConcurrentCollectionOperations' 20 | s.requires_arc = false 21 | end 22 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 552267F8176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.h in Headers */ = {isa = PBXBuildFile; fileRef = 552267F6176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 552267F9176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 552267F7176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.m */; }; 12 | 552267FA176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 552267F7176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.m */; }; 13 | 552267FB1765146000108850 /* NSOrderedSet+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 552267F7176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.m */; }; 14 | 552267FC1765146000108850 /* NSOrderedSet+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 552267F7176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.m */; }; 15 | 552267FD17652D0500108850 /* NSMapTable+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 8436C8261760289300835D7A /* NSMapTable+ConcurrentCollectionOperations.m */; }; 16 | 552267FE17652D1300108850 /* NSMapTable+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 8436C8261760289300835D7A /* NSMapTable+ConcurrentCollectionOperations.m */; }; 17 | 552267FF17652D1500108850 /* NSMapTable+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 8436C8261760289300835D7A /* NSMapTable+ConcurrentCollectionOperations.m */; }; 18 | 5545FD64175E9F9000AC003B /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5545FD63175E9F9000AC003B /* LICENSE.txt */; }; 19 | 5581C89417678D3D001E475B /* ConcurrentCollectionOperationsBenchmarks.m in Sources */ = {isa = PBXBuildFile; fileRef = 5581C89317678D3D001E475B /* ConcurrentCollectionOperationsBenchmarks.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; 20 | 5581C89517678D3D001E475B /* ConcurrentCollectionOperationsBenchmarks.m in Sources */ = {isa = PBXBuildFile; fileRef = 5581C89317678D3D001E475B /* ConcurrentCollectionOperationsBenchmarks.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; 21 | 5588EEDA175BDF8B00196831 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5588EED9175BDF8B00196831 /* Cocoa.framework */; }; 22 | 5588EEE4175BDF8B00196831 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5588EEE2175BDF8B00196831 /* InfoPlist.strings */; }; 23 | 5588EEF0175BDF8B00196831 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5588EEEF175BDF8B00196831 /* SenTestingKit.framework */; }; 24 | 5588EEF1175BDF8B00196831 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5588EED9175BDF8B00196831 /* Cocoa.framework */; }; 25 | 5588EEF4175BDF8B00196831 /* ConcurrentCollectionOperations.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5588EED6175BDF8B00196831 /* ConcurrentCollectionOperations.framework */; }; 26 | 5588EEFA175BDF8B00196831 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5588EEF8175BDF8B00196831 /* InfoPlist.strings */; }; 27 | 5588EEFD175BDF8B00196831 /* ConcurrentCollectionOperationsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5588EEFC175BDF8B00196831 /* ConcurrentCollectionOperationsTests.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; 28 | 5588EF08175BE14500196831 /* NSArray+ConcurrentCollectionOperations.h in Headers */ = {isa = PBXBuildFile; fileRef = 5588EF06175BE14500196831 /* NSArray+ConcurrentCollectionOperations.h */; settings = {ATTRIBUTES = (Public, ); }; }; 29 | 5588EF09175BE14500196831 /* NSArray+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 5588EF07175BE14500196831 /* NSArray+ConcurrentCollectionOperations.m */; }; 30 | 5588EF0A175BE14500196831 /* NSArray+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 5588EF07175BE14500196831 /* NSArray+ConcurrentCollectionOperations.m */; }; 31 | 5588EF12175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.h in Headers */ = {isa = PBXBuildFile; fileRef = 5588EF10175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32 | 5588EF13175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 5588EF11175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.m */; }; 33 | 5588EF14175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 5588EF11175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.m */; }; 34 | 5588EF17175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.h in Headers */ = {isa = PBXBuildFile; fileRef = 5588EF15175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.h */; settings = {ATTRIBUTES = (Public, ); }; }; 35 | 5588EF18175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 5588EF16175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.m */; }; 36 | 5588EF19175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 5588EF16175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.m */; }; 37 | 5588EF1A175C48E700196831 /* ConcurrentCollectionOperations.h in Headers */ = {isa = PBXBuildFile; fileRef = 5588EEE6175BDF8B00196831 /* ConcurrentCollectionOperations.h */; settings = {ATTRIBUTES = (Public, ); }; }; 38 | 5588EF1C175C493B00196831 /* BlockTypedefs.h in Headers */ = {isa = PBXBuildFile; fileRef = 5588EF1B175C493A00196831 /* BlockTypedefs.h */; }; 39 | 5588EF26175C4E4000196831 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5588EF25175C4E4000196831 /* Foundation.framework */; }; 40 | 5588EF34175C4E4000196831 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5588EEEF175BDF8B00196831 /* SenTestingKit.framework */; }; 41 | 5588EF36175C4E4000196831 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5588EF35175C4E4000196831 /* UIKit.framework */; }; 42 | 5588EF37175C4E4000196831 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5588EF25175C4E4000196831 /* Foundation.framework */; }; 43 | 5588EF3A175C4E4000196831 /* libConcurrentCollectionOperations-iOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5588EF24175C4E4000196831 /* libConcurrentCollectionOperations-iOS.a */; }; 44 | 5588EF4A175C4EE900196831 /* NSArray+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 5588EF07175BE14500196831 /* NSArray+ConcurrentCollectionOperations.m */; }; 45 | 5588EF4B175C4EEA00196831 /* NSArray+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 5588EF07175BE14500196831 /* NSArray+ConcurrentCollectionOperations.m */; }; 46 | 5588EF4C175C4EED00196831 /* NSDictionary+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 5588EF11175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.m */; }; 47 | 5588EF4D175C4EEE00196831 /* NSDictionary+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 5588EF11175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.m */; }; 48 | 5588EF4E175C4EF100196831 /* NSSet+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 5588EF16175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.m */; }; 49 | 5588EF4F175C4EF200196831 /* NSSet+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 5588EF16175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.m */; }; 50 | 5588EF50175C4EF600196831 /* ConcurrentCollectionOperationsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5588EEFC175BDF8B00196831 /* ConcurrentCollectionOperationsTests.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; 51 | 8436C8271760289300835D7A /* NSMapTable+ConcurrentCollectionOperations.h in Headers */ = {isa = PBXBuildFile; fileRef = 8436C8251760289300835D7A /* NSMapTable+ConcurrentCollectionOperations.h */; settings = {ATTRIBUTES = (Public, ); }; }; 52 | 8436C8281760289300835D7A /* NSMapTable+ConcurrentCollectionOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 8436C8261760289300835D7A /* NSMapTable+ConcurrentCollectionOperations.m */; }; 53 | /* End PBXBuildFile section */ 54 | 55 | /* Begin PBXContainerItemProxy section */ 56 | 5588EEF2175BDF8B00196831 /* PBXContainerItemProxy */ = { 57 | isa = PBXContainerItemProxy; 58 | containerPortal = 5588EECD175BDF8B00196831 /* Project object */; 59 | proxyType = 1; 60 | remoteGlobalIDString = 5588EED5175BDF8B00196831; 61 | remoteInfo = ConcurrentCollectionOperations; 62 | }; 63 | 5588EF38175C4E4000196831 /* PBXContainerItemProxy */ = { 64 | isa = PBXContainerItemProxy; 65 | containerPortal = 5588EECD175BDF8B00196831 /* Project object */; 66 | proxyType = 1; 67 | remoteGlobalIDString = 5588EF23175C4E4000196831; 68 | remoteInfo = "ConcurrentCollectionOperations-iOS"; 69 | }; 70 | /* End PBXContainerItemProxy section */ 71 | 72 | /* Begin PBXCopyFilesBuildPhase section */ 73 | 5588EF22175C4E4000196831 /* CopyFiles */ = { 74 | isa = PBXCopyFilesBuildPhase; 75 | buildActionMask = 2147483647; 76 | dstPath = "include/${PRODUCT_NAME}"; 77 | dstSubfolderSpec = 16; 78 | files = ( 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | /* End PBXCopyFilesBuildPhase section */ 83 | 84 | /* Begin PBXFileReference section */ 85 | 552267F6176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSOrderedSet+ConcurrentCollectionOperations.h"; sourceTree = ""; }; 86 | 552267F7176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSOrderedSet+ConcurrentCollectionOperations.m"; sourceTree = ""; }; 87 | 5545FD63175E9F9000AC003B /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; 88 | 5545FD65175EA22800AC003B /* ConcurrentCollectionOperations.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = ConcurrentCollectionOperations.podspec; sourceTree = ""; }; 89 | 5581C89317678D3D001E475B /* ConcurrentCollectionOperationsBenchmarks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConcurrentCollectionOperationsBenchmarks.m; sourceTree = ""; }; 90 | 5588EED6175BDF8B00196831 /* ConcurrentCollectionOperations.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ConcurrentCollectionOperations.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 91 | 5588EED9175BDF8B00196831 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 92 | 5588EEDC175BDF8B00196831 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 93 | 5588EEDD175BDF8B00196831 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 94 | 5588EEDE175BDF8B00196831 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 95 | 5588EEE1175BDF8B00196831 /* ConcurrentCollectionOperations-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ConcurrentCollectionOperations-Info.plist"; sourceTree = ""; }; 96 | 5588EEE3175BDF8B00196831 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 97 | 5588EEE5175BDF8B00196831 /* ConcurrentCollectionOperations-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ConcurrentCollectionOperations-Prefix.pch"; sourceTree = ""; }; 98 | 5588EEE6175BDF8B00196831 /* ConcurrentCollectionOperations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ConcurrentCollectionOperations.h; sourceTree = ""; }; 99 | 5588EEEE175BDF8B00196831 /* ConcurrentCollectionOperationsTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ConcurrentCollectionOperationsTests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 100 | 5588EEEF175BDF8B00196831 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; 101 | 5588EEF7175BDF8B00196831 /* ConcurrentCollectionOperationsTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ConcurrentCollectionOperationsTests-Info.plist"; sourceTree = ""; }; 102 | 5588EEF9175BDF8B00196831 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 103 | 5588EEFC175BDF8B00196831 /* ConcurrentCollectionOperationsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ConcurrentCollectionOperationsTests.m; sourceTree = ""; }; 104 | 5588EF06175BE14500196831 /* NSArray+ConcurrentCollectionOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+ConcurrentCollectionOperations.h"; sourceTree = ""; }; 105 | 5588EF07175BE14500196831 /* NSArray+ConcurrentCollectionOperations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+ConcurrentCollectionOperations.m"; sourceTree = ""; }; 106 | 5588EF10175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+ConcurrentCollectionOperations.h"; sourceTree = ""; }; 107 | 5588EF11175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+ConcurrentCollectionOperations.m"; sourceTree = ""; }; 108 | 5588EF15175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSSet+ConcurrentCollectionOperations.h"; sourceTree = ""; }; 109 | 5588EF16175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSSet+ConcurrentCollectionOperations.m"; sourceTree = ""; }; 110 | 5588EF1B175C493A00196831 /* BlockTypedefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockTypedefs.h; sourceTree = ""; }; 111 | 5588EF1D175C4AB400196831 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; }; 112 | 5588EF24175C4E4000196831 /* libConcurrentCollectionOperations-iOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libConcurrentCollectionOperations-iOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 113 | 5588EF25175C4E4000196831 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 114 | 5588EF29175C4E4000196831 /* ConcurrentCollectionOperations-iOS-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "ConcurrentCollectionOperations-iOS-Prefix.pch"; path = "ConcurrentCollectionOperations/ConcurrentCollectionOperations-iOS-Prefix.pch"; sourceTree = SOURCE_ROOT; }; 115 | 5588EF33175C4E4000196831 /* ConcurrentCollectionOperations-iOSTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "ConcurrentCollectionOperations-iOSTests.octest"; sourceTree = BUILT_PRODUCTS_DIR; }; 116 | 5588EF35175C4E4000196831 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; 117 | 8436C8251760289300835D7A /* NSMapTable+ConcurrentCollectionOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMapTable+ConcurrentCollectionOperations.h"; sourceTree = ""; }; 118 | 8436C8261760289300835D7A /* NSMapTable+ConcurrentCollectionOperations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMapTable+ConcurrentCollectionOperations.m"; sourceTree = ""; }; 119 | /* End PBXFileReference section */ 120 | 121 | /* Begin PBXFrameworksBuildPhase section */ 122 | 5588EED2175BDF8B00196831 /* Frameworks */ = { 123 | isa = PBXFrameworksBuildPhase; 124 | buildActionMask = 2147483647; 125 | files = ( 126 | 5588EEDA175BDF8B00196831 /* Cocoa.framework in Frameworks */, 127 | ); 128 | runOnlyForDeploymentPostprocessing = 0; 129 | }; 130 | 5588EEEA175BDF8B00196831 /* Frameworks */ = { 131 | isa = PBXFrameworksBuildPhase; 132 | buildActionMask = 2147483647; 133 | files = ( 134 | 5588EEF0175BDF8B00196831 /* SenTestingKit.framework in Frameworks */, 135 | 5588EEF1175BDF8B00196831 /* Cocoa.framework in Frameworks */, 136 | 5588EEF4175BDF8B00196831 /* ConcurrentCollectionOperations.framework in Frameworks */, 137 | ); 138 | runOnlyForDeploymentPostprocessing = 0; 139 | }; 140 | 5588EF21175C4E4000196831 /* Frameworks */ = { 141 | isa = PBXFrameworksBuildPhase; 142 | buildActionMask = 2147483647; 143 | files = ( 144 | 5588EF26175C4E4000196831 /* Foundation.framework in Frameworks */, 145 | ); 146 | runOnlyForDeploymentPostprocessing = 0; 147 | }; 148 | 5588EF2F175C4E4000196831 /* Frameworks */ = { 149 | isa = PBXFrameworksBuildPhase; 150 | buildActionMask = 2147483647; 151 | files = ( 152 | 5588EF34175C4E4000196831 /* SenTestingKit.framework in Frameworks */, 153 | 5588EF36175C4E4000196831 /* UIKit.framework in Frameworks */, 154 | 5588EF37175C4E4000196831 /* Foundation.framework in Frameworks */, 155 | 5588EF3A175C4E4000196831 /* libConcurrentCollectionOperations-iOS.a in Frameworks */, 156 | ); 157 | runOnlyForDeploymentPostprocessing = 0; 158 | }; 159 | /* End PBXFrameworksBuildPhase section */ 160 | 161 | /* Begin PBXGroup section */ 162 | 5588EECC175BDF8B00196831 = { 163 | isa = PBXGroup; 164 | children = ( 165 | 5588EF1D175C4AB400196831 /* README.md */, 166 | 5545FD65175EA22800AC003B /* ConcurrentCollectionOperations.podspec */, 167 | 5545FD63175E9F9000AC003B /* LICENSE.txt */, 168 | 5588EEDF175BDF8B00196831 /* ConcurrentCollectionOperations */, 169 | 5588EEF5175BDF8B00196831 /* ConcurrentCollectionOperationsTests */, 170 | 5588EED8175BDF8B00196831 /* Frameworks */, 171 | 5588EED7175BDF8B00196831 /* Products */, 172 | ); 173 | sourceTree = ""; 174 | }; 175 | 5588EED7175BDF8B00196831 /* Products */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | 5588EED6175BDF8B00196831 /* ConcurrentCollectionOperations.framework */, 179 | 5588EEEE175BDF8B00196831 /* ConcurrentCollectionOperationsTests.octest */, 180 | 5588EF24175C4E4000196831 /* libConcurrentCollectionOperations-iOS.a */, 181 | 5588EF33175C4E4000196831 /* ConcurrentCollectionOperations-iOSTests.octest */, 182 | ); 183 | name = Products; 184 | sourceTree = ""; 185 | }; 186 | 5588EED8175BDF8B00196831 /* Frameworks */ = { 187 | isa = PBXGroup; 188 | children = ( 189 | 5588EED9175BDF8B00196831 /* Cocoa.framework */, 190 | 5588EEEF175BDF8B00196831 /* SenTestingKit.framework */, 191 | 5588EF25175C4E4000196831 /* Foundation.framework */, 192 | 5588EF35175C4E4000196831 /* UIKit.framework */, 193 | 5588EEDB175BDF8B00196831 /* Other Frameworks */, 194 | ); 195 | name = Frameworks; 196 | sourceTree = ""; 197 | }; 198 | 5588EEDB175BDF8B00196831 /* Other Frameworks */ = { 199 | isa = PBXGroup; 200 | children = ( 201 | 5588EEDC175BDF8B00196831 /* AppKit.framework */, 202 | 5588EEDD175BDF8B00196831 /* CoreData.framework */, 203 | 5588EEDE175BDF8B00196831 /* Foundation.framework */, 204 | ); 205 | name = "Other Frameworks"; 206 | sourceTree = ""; 207 | }; 208 | 5588EEDF175BDF8B00196831 /* ConcurrentCollectionOperations */ = { 209 | isa = PBXGroup; 210 | children = ( 211 | 5588EEE6175BDF8B00196831 /* ConcurrentCollectionOperations.h */, 212 | 5588EF1B175C493A00196831 /* BlockTypedefs.h */, 213 | 5588EF06175BE14500196831 /* NSArray+ConcurrentCollectionOperations.h */, 214 | 5588EF07175BE14500196831 /* NSArray+ConcurrentCollectionOperations.m */, 215 | 5588EF10175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.h */, 216 | 5588EF11175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.m */, 217 | 8436C8251760289300835D7A /* NSMapTable+ConcurrentCollectionOperations.h */, 218 | 8436C8261760289300835D7A /* NSMapTable+ConcurrentCollectionOperations.m */, 219 | 5588EF15175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.h */, 220 | 5588EF16175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.m */, 221 | 552267F6176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.h */, 222 | 552267F7176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.m */, 223 | 5588EEE0175BDF8B00196831 /* Supporting Files */, 224 | ); 225 | path = ConcurrentCollectionOperations; 226 | sourceTree = ""; 227 | }; 228 | 5588EEE0175BDF8B00196831 /* Supporting Files */ = { 229 | isa = PBXGroup; 230 | children = ( 231 | 5588EEE1175BDF8B00196831 /* ConcurrentCollectionOperations-Info.plist */, 232 | 5588EEE2175BDF8B00196831 /* InfoPlist.strings */, 233 | 5588EEE5175BDF8B00196831 /* ConcurrentCollectionOperations-Prefix.pch */, 234 | 5588EF29175C4E4000196831 /* ConcurrentCollectionOperations-iOS-Prefix.pch */, 235 | ); 236 | name = "Supporting Files"; 237 | sourceTree = ""; 238 | }; 239 | 5588EEF5175BDF8B00196831 /* ConcurrentCollectionOperationsTests */ = { 240 | isa = PBXGroup; 241 | children = ( 242 | 5581C89317678D3D001E475B /* ConcurrentCollectionOperationsBenchmarks.m */, 243 | 5588EEFC175BDF8B00196831 /* ConcurrentCollectionOperationsTests.m */, 244 | 5588EEF6175BDF8B00196831 /* Supporting Files */, 245 | ); 246 | path = ConcurrentCollectionOperationsTests; 247 | sourceTree = ""; 248 | }; 249 | 5588EEF6175BDF8B00196831 /* Supporting Files */ = { 250 | isa = PBXGroup; 251 | children = ( 252 | 5588EEF7175BDF8B00196831 /* ConcurrentCollectionOperationsTests-Info.plist */, 253 | 5588EEF8175BDF8B00196831 /* InfoPlist.strings */, 254 | ); 255 | name = "Supporting Files"; 256 | sourceTree = ""; 257 | }; 258 | /* End PBXGroup section */ 259 | 260 | /* Begin PBXHeadersBuildPhase section */ 261 | 5588EED3175BDF8B00196831 /* Headers */ = { 262 | isa = PBXHeadersBuildPhase; 263 | buildActionMask = 2147483647; 264 | files = ( 265 | 5588EF08175BE14500196831 /* NSArray+ConcurrentCollectionOperations.h in Headers */, 266 | 5588EF12175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.h in Headers */, 267 | 5588EF17175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.h in Headers */, 268 | 5588EF1A175C48E700196831 /* ConcurrentCollectionOperations.h in Headers */, 269 | 5588EF1C175C493B00196831 /* BlockTypedefs.h in Headers */, 270 | 8436C8271760289300835D7A /* NSMapTable+ConcurrentCollectionOperations.h in Headers */, 271 | 552267F8176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.h in Headers */, 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | /* End PBXHeadersBuildPhase section */ 276 | 277 | /* Begin PBXNativeTarget section */ 278 | 5588EED5175BDF8B00196831 /* ConcurrentCollectionOperations */ = { 279 | isa = PBXNativeTarget; 280 | buildConfigurationList = 5588EF00175BDF8B00196831 /* Build configuration list for PBXNativeTarget "ConcurrentCollectionOperations" */; 281 | buildPhases = ( 282 | 5588EED1175BDF8B00196831 /* Sources */, 283 | 5588EED2175BDF8B00196831 /* Frameworks */, 284 | 5588EED3175BDF8B00196831 /* Headers */, 285 | 5588EED4175BDF8B00196831 /* Resources */, 286 | ); 287 | buildRules = ( 288 | ); 289 | dependencies = ( 290 | ); 291 | name = ConcurrentCollectionOperations; 292 | productName = ConcurrentCollectionOperations; 293 | productReference = 5588EED6175BDF8B00196831 /* ConcurrentCollectionOperations.framework */; 294 | productType = "com.apple.product-type.framework"; 295 | }; 296 | 5588EEED175BDF8B00196831 /* ConcurrentCollectionOperationsTests */ = { 297 | isa = PBXNativeTarget; 298 | buildConfigurationList = 5588EF03175BDF8B00196831 /* Build configuration list for PBXNativeTarget "ConcurrentCollectionOperationsTests" */; 299 | buildPhases = ( 300 | 5588EEE9175BDF8B00196831 /* Sources */, 301 | 5588EEEA175BDF8B00196831 /* Frameworks */, 302 | 5588EEEB175BDF8B00196831 /* Resources */, 303 | 5588EEEC175BDF8B00196831 /* ShellScript */, 304 | ); 305 | buildRules = ( 306 | ); 307 | dependencies = ( 308 | 5588EEF3175BDF8B00196831 /* PBXTargetDependency */, 309 | ); 310 | name = ConcurrentCollectionOperationsTests; 311 | productName = ConcurrentCollectionOperationsTests; 312 | productReference = 5588EEEE175BDF8B00196831 /* ConcurrentCollectionOperationsTests.octest */; 313 | productType = "com.apple.product-type.bundle"; 314 | }; 315 | 5588EF23175C4E4000196831 /* ConcurrentCollectionOperations-iOS */ = { 316 | isa = PBXNativeTarget; 317 | buildConfigurationList = 5588EF44175C4E4000196831 /* Build configuration list for PBXNativeTarget "ConcurrentCollectionOperations-iOS" */; 318 | buildPhases = ( 319 | 5588EF20175C4E4000196831 /* Sources */, 320 | 5588EF21175C4E4000196831 /* Frameworks */, 321 | 5588EF22175C4E4000196831 /* CopyFiles */, 322 | ); 323 | buildRules = ( 324 | ); 325 | dependencies = ( 326 | ); 327 | name = "ConcurrentCollectionOperations-iOS"; 328 | productName = "ConcurrentCollectionOperations-iOS"; 329 | productReference = 5588EF24175C4E4000196831 /* libConcurrentCollectionOperations-iOS.a */; 330 | productType = "com.apple.product-type.library.static"; 331 | }; 332 | 5588EF32175C4E4000196831 /* ConcurrentCollectionOperations-iOSTests */ = { 333 | isa = PBXNativeTarget; 334 | buildConfigurationList = 5588EF47175C4E4000196831 /* Build configuration list for PBXNativeTarget "ConcurrentCollectionOperations-iOSTests" */; 335 | buildPhases = ( 336 | 5588EF2E175C4E4000196831 /* Sources */, 337 | 5588EF2F175C4E4000196831 /* Frameworks */, 338 | 5588EF30175C4E4000196831 /* Resources */, 339 | 5588EF31175C4E4000196831 /* ShellScript */, 340 | ); 341 | buildRules = ( 342 | ); 343 | dependencies = ( 344 | 5588EF39175C4E4000196831 /* PBXTargetDependency */, 345 | ); 346 | name = "ConcurrentCollectionOperations-iOSTests"; 347 | productName = "ConcurrentCollectionOperations-iOSTests"; 348 | productReference = 5588EF33175C4E4000196831 /* ConcurrentCollectionOperations-iOSTests.octest */; 349 | productType = "com.apple.product-type.bundle"; 350 | }; 351 | /* End PBXNativeTarget section */ 352 | 353 | /* Begin PBXProject section */ 354 | 5588EECD175BDF8B00196831 /* Project object */ = { 355 | isa = PBXProject; 356 | attributes = { 357 | LastUpgradeCheck = 0460; 358 | ORGANIZATIONNAME = ""; 359 | }; 360 | buildConfigurationList = 5588EED0175BDF8B00196831 /* Build configuration list for PBXProject "ConcurrentCollectionOperations" */; 361 | compatibilityVersion = "Xcode 3.2"; 362 | developmentRegion = English; 363 | hasScannedForEncodings = 0; 364 | knownRegions = ( 365 | en, 366 | ); 367 | mainGroup = 5588EECC175BDF8B00196831; 368 | productRefGroup = 5588EED7175BDF8B00196831 /* Products */; 369 | projectDirPath = ""; 370 | projectRoot = ""; 371 | targets = ( 372 | 5588EED5175BDF8B00196831 /* ConcurrentCollectionOperations */, 373 | 5588EEED175BDF8B00196831 /* ConcurrentCollectionOperationsTests */, 374 | 5588EF23175C4E4000196831 /* ConcurrentCollectionOperations-iOS */, 375 | 5588EF32175C4E4000196831 /* ConcurrentCollectionOperations-iOSTests */, 376 | ); 377 | }; 378 | /* End PBXProject section */ 379 | 380 | /* Begin PBXResourcesBuildPhase section */ 381 | 5588EED4175BDF8B00196831 /* Resources */ = { 382 | isa = PBXResourcesBuildPhase; 383 | buildActionMask = 2147483647; 384 | files = ( 385 | 5588EEE4175BDF8B00196831 /* InfoPlist.strings in Resources */, 386 | 5545FD64175E9F9000AC003B /* LICENSE.txt in Resources */, 387 | ); 388 | runOnlyForDeploymentPostprocessing = 0; 389 | }; 390 | 5588EEEB175BDF8B00196831 /* Resources */ = { 391 | isa = PBXResourcesBuildPhase; 392 | buildActionMask = 2147483647; 393 | files = ( 394 | 5588EEFA175BDF8B00196831 /* InfoPlist.strings in Resources */, 395 | ); 396 | runOnlyForDeploymentPostprocessing = 0; 397 | }; 398 | 5588EF30175C4E4000196831 /* Resources */ = { 399 | isa = PBXResourcesBuildPhase; 400 | buildActionMask = 2147483647; 401 | files = ( 402 | ); 403 | runOnlyForDeploymentPostprocessing = 0; 404 | }; 405 | /* End PBXResourcesBuildPhase section */ 406 | 407 | /* Begin PBXShellScriptBuildPhase section */ 408 | 5588EEEC175BDF8B00196831 /* ShellScript */ = { 409 | isa = PBXShellScriptBuildPhase; 410 | buildActionMask = 2147483647; 411 | files = ( 412 | ); 413 | inputPaths = ( 414 | ); 415 | outputPaths = ( 416 | ); 417 | runOnlyForDeploymentPostprocessing = 0; 418 | shellPath = /bin/sh; 419 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 420 | }; 421 | 5588EF31175C4E4000196831 /* ShellScript */ = { 422 | isa = PBXShellScriptBuildPhase; 423 | buildActionMask = 2147483647; 424 | files = ( 425 | ); 426 | inputPaths = ( 427 | ); 428 | outputPaths = ( 429 | ); 430 | runOnlyForDeploymentPostprocessing = 0; 431 | shellPath = /bin/sh; 432 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 433 | }; 434 | /* End PBXShellScriptBuildPhase section */ 435 | 436 | /* Begin PBXSourcesBuildPhase section */ 437 | 5588EED1175BDF8B00196831 /* Sources */ = { 438 | isa = PBXSourcesBuildPhase; 439 | buildActionMask = 2147483647; 440 | files = ( 441 | 5588EF09175BE14500196831 /* NSArray+ConcurrentCollectionOperations.m in Sources */, 442 | 5588EF13175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.m in Sources */, 443 | 5588EF18175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.m in Sources */, 444 | 8436C8281760289300835D7A /* NSMapTable+ConcurrentCollectionOperations.m in Sources */, 445 | 552267F9176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.m in Sources */, 446 | ); 447 | runOnlyForDeploymentPostprocessing = 0; 448 | }; 449 | 5588EEE9175BDF8B00196831 /* Sources */ = { 450 | isa = PBXSourcesBuildPhase; 451 | buildActionMask = 2147483647; 452 | files = ( 453 | 5588EF0A175BE14500196831 /* NSArray+ConcurrentCollectionOperations.m in Sources */, 454 | 5588EF14175BED7F00196831 /* NSDictionary+ConcurrentCollectionOperations.m in Sources */, 455 | 5588EF19175C3F6700196831 /* NSSet+ConcurrentCollectionOperations.m in Sources */, 456 | 552267FB1765146000108850 /* NSOrderedSet+ConcurrentCollectionOperations.m in Sources */, 457 | 552267FD17652D0500108850 /* NSMapTable+ConcurrentCollectionOperations.m in Sources */, 458 | 5588EEFD175BDF8B00196831 /* ConcurrentCollectionOperationsTests.m in Sources */, 459 | 5581C89417678D3D001E475B /* ConcurrentCollectionOperationsBenchmarks.m in Sources */, 460 | ); 461 | runOnlyForDeploymentPostprocessing = 0; 462 | }; 463 | 5588EF20175C4E4000196831 /* Sources */ = { 464 | isa = PBXSourcesBuildPhase; 465 | buildActionMask = 2147483647; 466 | files = ( 467 | 5588EF4A175C4EE900196831 /* NSArray+ConcurrentCollectionOperations.m in Sources */, 468 | 5588EF4C175C4EED00196831 /* NSDictionary+ConcurrentCollectionOperations.m in Sources */, 469 | 5588EF4E175C4EF100196831 /* NSSet+ConcurrentCollectionOperations.m in Sources */, 470 | 552267FA176510D800108850 /* NSOrderedSet+ConcurrentCollectionOperations.m in Sources */, 471 | 552267FE17652D1300108850 /* NSMapTable+ConcurrentCollectionOperations.m in Sources */, 472 | ); 473 | runOnlyForDeploymentPostprocessing = 0; 474 | }; 475 | 5588EF2E175C4E4000196831 /* Sources */ = { 476 | isa = PBXSourcesBuildPhase; 477 | buildActionMask = 2147483647; 478 | files = ( 479 | 5588EF4B175C4EEA00196831 /* NSArray+ConcurrentCollectionOperations.m in Sources */, 480 | 5588EF4D175C4EEE00196831 /* NSDictionary+ConcurrentCollectionOperations.m in Sources */, 481 | 5588EF4F175C4EF200196831 /* NSSet+ConcurrentCollectionOperations.m in Sources */, 482 | 552267FC1765146000108850 /* NSOrderedSet+ConcurrentCollectionOperations.m in Sources */, 483 | 552267FF17652D1500108850 /* NSMapTable+ConcurrentCollectionOperations.m in Sources */, 484 | 5588EF50175C4EF600196831 /* ConcurrentCollectionOperationsTests.m in Sources */, 485 | 5581C89517678D3D001E475B /* ConcurrentCollectionOperationsBenchmarks.m in Sources */, 486 | ); 487 | runOnlyForDeploymentPostprocessing = 0; 488 | }; 489 | /* End PBXSourcesBuildPhase section */ 490 | 491 | /* Begin PBXTargetDependency section */ 492 | 5588EEF3175BDF8B00196831 /* PBXTargetDependency */ = { 493 | isa = PBXTargetDependency; 494 | target = 5588EED5175BDF8B00196831 /* ConcurrentCollectionOperations */; 495 | targetProxy = 5588EEF2175BDF8B00196831 /* PBXContainerItemProxy */; 496 | }; 497 | 5588EF39175C4E4000196831 /* PBXTargetDependency */ = { 498 | isa = PBXTargetDependency; 499 | target = 5588EF23175C4E4000196831 /* ConcurrentCollectionOperations-iOS */; 500 | targetProxy = 5588EF38175C4E4000196831 /* PBXContainerItemProxy */; 501 | }; 502 | /* End PBXTargetDependency section */ 503 | 504 | /* Begin PBXVariantGroup section */ 505 | 5588EEE2175BDF8B00196831 /* InfoPlist.strings */ = { 506 | isa = PBXVariantGroup; 507 | children = ( 508 | 5588EEE3175BDF8B00196831 /* en */, 509 | ); 510 | name = InfoPlist.strings; 511 | sourceTree = ""; 512 | }; 513 | 5588EEF8175BDF8B00196831 /* InfoPlist.strings */ = { 514 | isa = PBXVariantGroup; 515 | children = ( 516 | 5588EEF9175BDF8B00196831 /* en */, 517 | ); 518 | name = InfoPlist.strings; 519 | sourceTree = ""; 520 | }; 521 | /* End PBXVariantGroup section */ 522 | 523 | /* Begin XCBuildConfiguration section */ 524 | 5588EEFE175BDF8B00196831 /* Debug */ = { 525 | isa = XCBuildConfiguration; 526 | buildSettings = { 527 | ALWAYS_SEARCH_USER_PATHS = NO; 528 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 529 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 530 | CLANG_CXX_LIBRARY = "libc++"; 531 | CLANG_ENABLE_OBJC_ARC = NO; 532 | CLANG_WARN_CONSTANT_CONVERSION = YES; 533 | CLANG_WARN_EMPTY_BODY = YES; 534 | CLANG_WARN_ENUM_CONVERSION = YES; 535 | CLANG_WARN_INT_CONVERSION = YES; 536 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 537 | COPY_PHASE_STRIP = NO; 538 | GCC_C_LANGUAGE_STANDARD = gnu99; 539 | GCC_DYNAMIC_NO_PIC = NO; 540 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 541 | GCC_OPTIMIZATION_LEVEL = 0; 542 | GCC_PREPROCESSOR_DEFINITIONS = ( 543 | "DEBUG=1", 544 | "$(inherited)", 545 | ); 546 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 547 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 548 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 549 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 550 | GCC_WARN_UNUSED_VARIABLE = YES; 551 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 552 | MACOSX_DEPLOYMENT_TARGET = 10.7; 553 | ONLY_ACTIVE_ARCH = YES; 554 | SDKROOT = macosx; 555 | }; 556 | name = Debug; 557 | }; 558 | 5588EEFF175BDF8B00196831 /* Release */ = { 559 | isa = XCBuildConfiguration; 560 | buildSettings = { 561 | ALWAYS_SEARCH_USER_PATHS = NO; 562 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 563 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 564 | CLANG_CXX_LIBRARY = "libc++"; 565 | CLANG_ENABLE_OBJC_ARC = NO; 566 | CLANG_WARN_CONSTANT_CONVERSION = YES; 567 | CLANG_WARN_EMPTY_BODY = YES; 568 | CLANG_WARN_ENUM_CONVERSION = YES; 569 | CLANG_WARN_INT_CONVERSION = YES; 570 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 571 | COPY_PHASE_STRIP = YES; 572 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 573 | GCC_C_LANGUAGE_STANDARD = gnu99; 574 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 575 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 576 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 577 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 578 | GCC_WARN_UNUSED_VARIABLE = YES; 579 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 580 | MACOSX_DEPLOYMENT_TARGET = 10.7; 581 | SDKROOT = macosx; 582 | }; 583 | name = Release; 584 | }; 585 | 5588EF01175BDF8B00196831 /* Debug */ = { 586 | isa = XCBuildConfiguration; 587 | buildSettings = { 588 | COMBINE_HIDPI_IMAGES = YES; 589 | DYLIB_COMPATIBILITY_VERSION = 1; 590 | DYLIB_CURRENT_VERSION = 1; 591 | FRAMEWORK_VERSION = A; 592 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 593 | GCC_PREFIX_HEADER = "ConcurrentCollectionOperations/ConcurrentCollectionOperations-Prefix.pch"; 594 | INFOPLIST_FILE = "ConcurrentCollectionOperations/ConcurrentCollectionOperations-Info.plist"; 595 | PRODUCT_NAME = "$(TARGET_NAME)"; 596 | WRAPPER_EXTENSION = framework; 597 | }; 598 | name = Debug; 599 | }; 600 | 5588EF02175BDF8B00196831 /* Release */ = { 601 | isa = XCBuildConfiguration; 602 | buildSettings = { 603 | COMBINE_HIDPI_IMAGES = YES; 604 | DYLIB_COMPATIBILITY_VERSION = 1; 605 | DYLIB_CURRENT_VERSION = 1; 606 | FRAMEWORK_VERSION = A; 607 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 608 | GCC_PREFIX_HEADER = "ConcurrentCollectionOperations/ConcurrentCollectionOperations-Prefix.pch"; 609 | INFOPLIST_FILE = "ConcurrentCollectionOperations/ConcurrentCollectionOperations-Info.plist"; 610 | PRODUCT_NAME = "$(TARGET_NAME)"; 611 | WRAPPER_EXTENSION = framework; 612 | }; 613 | name = Release; 614 | }; 615 | 5588EF04175BDF8B00196831 /* Debug */ = { 616 | isa = XCBuildConfiguration; 617 | buildSettings = { 618 | COMBINE_HIDPI_IMAGES = YES; 619 | FRAMEWORK_SEARCH_PATHS = "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\""; 620 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 621 | GCC_PREFIX_HEADER = "ConcurrentCollectionOperations/ConcurrentCollectionOperations-Prefix.pch"; 622 | INFOPLIST_FILE = "ConcurrentCollectionOperationsTests/ConcurrentCollectionOperationsTests-Info.plist"; 623 | PRODUCT_NAME = "$(TARGET_NAME)"; 624 | WRAPPER_EXTENSION = octest; 625 | }; 626 | name = Debug; 627 | }; 628 | 5588EF05175BDF8B00196831 /* Release */ = { 629 | isa = XCBuildConfiguration; 630 | buildSettings = { 631 | COMBINE_HIDPI_IMAGES = YES; 632 | FRAMEWORK_SEARCH_PATHS = "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\""; 633 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 634 | GCC_PREFIX_HEADER = "ConcurrentCollectionOperations/ConcurrentCollectionOperations-Prefix.pch"; 635 | INFOPLIST_FILE = "ConcurrentCollectionOperationsTests/ConcurrentCollectionOperationsTests-Info.plist"; 636 | PRODUCT_NAME = "$(TARGET_NAME)"; 637 | WRAPPER_EXTENSION = octest; 638 | }; 639 | name = Release; 640 | }; 641 | 5588EF45175C4E4000196831 /* Debug */ = { 642 | isa = XCBuildConfiguration; 643 | buildSettings = { 644 | DSTROOT = /tmp/ConcurrentCollectionOperations_iOS.dst; 645 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 646 | GCC_PREFIX_HEADER = "ConcurrentCollectionOperations/ConcurrentCollectionOperations-iOS-Prefix.pch"; 647 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 648 | OTHER_LDFLAGS = "-ObjC"; 649 | PRODUCT_NAME = "$(TARGET_NAME)"; 650 | SDKROOT = iphoneos; 651 | SKIP_INSTALL = YES; 652 | }; 653 | name = Debug; 654 | }; 655 | 5588EF46175C4E4000196831 /* Release */ = { 656 | isa = XCBuildConfiguration; 657 | buildSettings = { 658 | DSTROOT = /tmp/ConcurrentCollectionOperations_iOS.dst; 659 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 660 | GCC_PREFIX_HEADER = "ConcurrentCollectionOperations/ConcurrentCollectionOperations-iOS-Prefix.pch"; 661 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 662 | OTHER_LDFLAGS = "-ObjC"; 663 | PRODUCT_NAME = "$(TARGET_NAME)"; 664 | SDKROOT = iphoneos; 665 | SKIP_INSTALL = YES; 666 | VALIDATE_PRODUCT = YES; 667 | }; 668 | name = Release; 669 | }; 670 | 5588EF48175C4E4000196831 /* Debug */ = { 671 | isa = XCBuildConfiguration; 672 | buildSettings = { 673 | FRAMEWORK_SEARCH_PATHS = ( 674 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 675 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 676 | ); 677 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 678 | GCC_PREFIX_HEADER = "ConcurrentCollectionOperations/ConcurrentCollectionOperations-iOS-Prefix.pch"; 679 | INFOPLIST_FILE = "ConcurrentCollectionOperations/ConcurrentCollectionOperations-Info.plist"; 680 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 681 | PRODUCT_NAME = "$(TARGET_NAME)"; 682 | SDKROOT = iphoneos; 683 | WRAPPER_EXTENSION = octest; 684 | }; 685 | name = Debug; 686 | }; 687 | 5588EF49175C4E4000196831 /* Release */ = { 688 | isa = XCBuildConfiguration; 689 | buildSettings = { 690 | FRAMEWORK_SEARCH_PATHS = ( 691 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 692 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 693 | ); 694 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 695 | GCC_PREFIX_HEADER = "ConcurrentCollectionOperations/ConcurrentCollectionOperations-iOS-Prefix.pch"; 696 | INFOPLIST_FILE = "ConcurrentCollectionOperations/ConcurrentCollectionOperations-Info.plist"; 697 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 698 | PRODUCT_NAME = "$(TARGET_NAME)"; 699 | SDKROOT = iphoneos; 700 | VALIDATE_PRODUCT = YES; 701 | WRAPPER_EXTENSION = octest; 702 | }; 703 | name = Release; 704 | }; 705 | /* End XCBuildConfiguration section */ 706 | 707 | /* Begin XCConfigurationList section */ 708 | 5588EED0175BDF8B00196831 /* Build configuration list for PBXProject "ConcurrentCollectionOperations" */ = { 709 | isa = XCConfigurationList; 710 | buildConfigurations = ( 711 | 5588EEFE175BDF8B00196831 /* Debug */, 712 | 5588EEFF175BDF8B00196831 /* Release */, 713 | ); 714 | defaultConfigurationIsVisible = 0; 715 | defaultConfigurationName = Release; 716 | }; 717 | 5588EF00175BDF8B00196831 /* Build configuration list for PBXNativeTarget "ConcurrentCollectionOperations" */ = { 718 | isa = XCConfigurationList; 719 | buildConfigurations = ( 720 | 5588EF01175BDF8B00196831 /* Debug */, 721 | 5588EF02175BDF8B00196831 /* Release */, 722 | ); 723 | defaultConfigurationIsVisible = 0; 724 | defaultConfigurationName = Release; 725 | }; 726 | 5588EF03175BDF8B00196831 /* Build configuration list for PBXNativeTarget "ConcurrentCollectionOperationsTests" */ = { 727 | isa = XCConfigurationList; 728 | buildConfigurations = ( 729 | 5588EF04175BDF8B00196831 /* Debug */, 730 | 5588EF05175BDF8B00196831 /* Release */, 731 | ); 732 | defaultConfigurationIsVisible = 0; 733 | defaultConfigurationName = Release; 734 | }; 735 | 5588EF44175C4E4000196831 /* Build configuration list for PBXNativeTarget "ConcurrentCollectionOperations-iOS" */ = { 736 | isa = XCConfigurationList; 737 | buildConfigurations = ( 738 | 5588EF45175C4E4000196831 /* Debug */, 739 | 5588EF46175C4E4000196831 /* Release */, 740 | ); 741 | defaultConfigurationIsVisible = 0; 742 | defaultConfigurationName = Release; 743 | }; 744 | 5588EF47175C4E4000196831 /* Build configuration list for PBXNativeTarget "ConcurrentCollectionOperations-iOSTests" */ = { 745 | isa = XCConfigurationList; 746 | buildConfigurations = ( 747 | 5588EF48175C4E4000196831 /* Debug */, 748 | 5588EF49175C4E4000196831 /* Release */, 749 | ); 750 | defaultConfigurationIsVisible = 0; 751 | defaultConfigurationName = Release; 752 | }; 753 | /* End XCConfigurationList section */ 754 | }; 755 | rootObject = 5588EECD175BDF8B00196831 /* Project object */; 756 | } 757 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/BlockTypedefs.h: -------------------------------------------------------------------------------- 1 | // 2 | // BlockTypedefs.h 3 | // ConcurrentCollectionOperations 4 | // 5 | // Created by Dave Lee on 2013-06-02. 6 | // 7 | 8 | typedef id (^CCOMapBlock)(id object); 9 | typedef BOOL (^CCOPredicateBlock)(id object); 10 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/ConcurrentCollectionOperations-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.internet.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSHumanReadableCopyright 26 | Copyright © 2013 David Lee. All rights reserved. 27 | NSPrincipalClass 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/ConcurrentCollectionOperations-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'ConcurrentCollectionOperations' target in the 'ConcurrentCollectionOperations' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/ConcurrentCollectionOperations-iOS-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'ConcurrentCollectionOperations-iOS' target in the 'ConcurrentCollectionOperations' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/ConcurrentCollectionOperations.h: -------------------------------------------------------------------------------- 1 | // 2 | // ConcurrentCollectionOperations.h 3 | // ConcurrentCollectionOperations 4 | // 5 | // Created by Dave Lee on 2013-06-02. 6 | // 7 | 8 | #import "NSArray+ConcurrentCollectionOperations.h" 9 | #import "NSDictionary+ConcurrentCollectionOperations.h" 10 | #import "NSSet+ConcurrentCollectionOperations.h" 11 | #import "NSMapTable+ConcurrentCollectionOperations.h" 12 | #import "NSOrderedSet+ConcurrentCollectionOperations.h" 13 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/NSArray+ConcurrentCollectionOperations.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+ConcurrentCollectionOperations.h 3 | // ConcurrentCollectionOperations 4 | // 5 | // Created by Dave Lee on 2013-06-02. 6 | // 7 | 8 | #import 9 | #import "BlockTypedefs.h" 10 | 11 | @interface NSArray (ConcurrentCollectionOperations) 12 | 13 | /** 14 | * Returns an array containing the results of calling the supplied block on each 15 | * object in the array. The block calls are performed concurrently, but the 16 | * order is preserved. 17 | * 18 | * The block calls are dispatched on the global concurrent dispatch queue with 19 | * default priority (`DISPATCH_QUEUE_PRIORITY_DEFAULT`). 20 | * 21 | * @see -cco_concurrentWithQueue:map: 22 | * 23 | * @param mapBlock Block that takes one object argument and another object. 24 | * 25 | * @result Array containing the ordered result of each block call. 26 | */ 27 | - (NSArray *)cco_concurrentMap:(CCOMapBlock)mapBlock; 28 | 29 | /** 30 | * Returns an array containing the results of calling the supplied block on each 31 | * object in the array. The block calls are performed concurrently, but the 32 | * order is preserved. The block calls are dispatched on the supplied concurrent 33 | * dispatch queue. 34 | * 35 | * @see -cco_concurrentMap: 36 | * 37 | * @param queue Concurrent dispatch queue for executing mapBlock. 38 | * @param mapBlock Block that takes one object argument and another object. 39 | * 40 | * @result Array containing the ordered result of each block call. 41 | */ 42 | - (NSArray *)cco_concurrentWithQueue:(dispatch_queue_t)queue map:(CCOMapBlock)mapBlock; 43 | 44 | /** 45 | * Returns a subsequence of the array, containing only the objects for which the 46 | * predicate block returns true. The block calls are performed concurrently, but 47 | * the order is preserved. 48 | * 49 | * The block calls are dispatched on the global concurrent dispatch queue with 50 | * default priority (`DISPATCH_QUEUE_PRIORITY_DEFAULT`). 51 | * 52 | * @see -cco_concurrentWithQueue:filter: 53 | * 54 | * @param predicateBlock Block that determines inclusion (YES) or exclusion (NO). 55 | * 56 | * @result Array containing only the objects for which the predicate block returned true. 57 | */ 58 | - (NSArray *)cco_concurrentFilter:(CCOPredicateBlock)predicateBlock; 59 | 60 | /** 61 | * Returns a subsequence of the array, containing only the objects for which the 62 | * predicate block returns true. The block calls are performed concurrently, but 63 | * the order is preserved. The block calls are dispatched on the supplied 64 | * concurrent dispatch queue. 65 | * 66 | * @see -cco_concurrentFilter: 67 | * 68 | * @param queue Concurrent dispatch queue for executing predicateBlock. 69 | * @param predicateBlock Block that determines inclusion (YES) or exclusion (NO). 70 | * 71 | * @result Array containing only the objects for which the predicate block returned true. 72 | */ 73 | - (NSArray *)cco_concurrentWithQueue:(dispatch_queue_t)queue filter:(CCOPredicateBlock)predicateBlock; 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/NSArray+ConcurrentCollectionOperations.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+ConcurrentCollectionOperations.m 3 | // ConcurrentCollectionOperations 4 | // 5 | // Created by Dave Lee on 2013-06-02. 6 | // 7 | 8 | #import "NSArray+ConcurrentCollectionOperations.h" 9 | 10 | @implementation NSArray (ConcurrentCollectionOperations) 11 | 12 | - (NSArray *)cco_concurrentMap:(CCOMapBlock)mapBlock { 13 | NSParameterAssert(mapBlock != nil); 14 | 15 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 16 | return [self cco_concurrentWithQueue:queue map:mapBlock]; 17 | } 18 | 19 | - (NSArray *)cco_concurrentWithQueue:(dispatch_queue_t)queue map:(CCOMapBlock)mapBlock { 20 | NSParameterAssert(mapBlock != nil); 21 | 22 | NSArray *snapshot = [self copy]; 23 | 24 | id *objects = calloc(snapshot.count, sizeof(id)); 25 | [snapshot getObjects:objects range:NSMakeRange(0, snapshot.count)]; 26 | 27 | dispatch_apply(snapshot.count, queue, ^(size_t i) { 28 | objects[i] = [mapBlock(objects[i]) retain]; 29 | }); 30 | 31 | NSArray *result = [NSArray arrayWithObjects:objects count:snapshot.count]; 32 | 33 | dispatch_apply(snapshot.count, queue, ^(size_t i) { 34 | [objects[i] release]; 35 | }); 36 | free(objects); 37 | [snapshot release]; 38 | 39 | return result; 40 | } 41 | 42 | - (NSArray *)cco_concurrentFilter:(CCOPredicateBlock)predicateBlock { 43 | NSParameterAssert(predicateBlock != nil); 44 | 45 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 46 | return [self cco_concurrentWithQueue:queue filter:predicateBlock]; 47 | } 48 | 49 | - (NSArray *)cco_concurrentWithQueue:(dispatch_queue_t)queue filter:(CCOPredicateBlock)predicateBlock { 50 | NSParameterAssert(predicateBlock != nil); 51 | 52 | NSArray *snapshot = [self copy]; 53 | 54 | id *objects = calloc(snapshot.count, sizeof(id)); 55 | [snapshot getObjects:objects range:NSMakeRange(0, snapshot.count)]; 56 | 57 | dispatch_apply(snapshot.count, queue, ^(size_t i) { 58 | if (!predicateBlock(objects[i])) { 59 | objects[i] = nil; 60 | } 61 | }); 62 | 63 | NSUInteger cursor = 0, nextFree = 0; 64 | while (cursor < snapshot.count) { 65 | if (objects[cursor]) { 66 | objects[nextFree++] = objects[cursor++]; 67 | } else { 68 | cursor++; 69 | } 70 | } 71 | 72 | NSArray *result = [NSArray arrayWithObjects:objects count:nextFree]; 73 | 74 | free(objects); 75 | [snapshot release]; 76 | 77 | return result; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/NSDictionary+ConcurrentCollectionOperations.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary+ConcurrentCollectionOperations.h 3 | // ConcurrentCollectionOperations 4 | // 5 | // Created by Dave Lee on 2013-06-02. 6 | // 7 | 8 | #import 9 | #import "BlockTypedefs.h" 10 | 11 | @interface NSDictionary (ConcurrentCollectionOperations) 12 | 13 | /** 14 | * Returns a dictionary containing the results of calling the supplied block on 15 | * each object in the dictionary. The block calls are performed concurrently. 16 | * 17 | * The block calls are dispatched on the global concurrent dispatch queue with 18 | * default priority (`DISPATCH_QUEUE_PRIORITY_DEFAULT`). 19 | * 20 | * @see -cco_concurrentWithQueue:map: 21 | * 22 | * @param mapBlock Block that takes one object argument and another object. 23 | * 24 | * @result Dictionary containing the result of each block call. 25 | */ 26 | - (NSDictionary *)cco_concurrentMap:(CCOMapBlock)mapBlock; 27 | 28 | /** 29 | * Returns a dictionary containing the results of calling the supplied block on 30 | * each object in the dictionary. The block calls are performed concurrently. 31 | * The block calls are dispatched on the supplied concurrent dispatch queue. 32 | * 33 | * @see -cco_concurrentMap: 34 | * 35 | * @param queue Concurrent dispatch queue for executing mapBlock. 36 | * @param mapBlock Block that takes one object argument and another object. 37 | * 38 | * @result Dictionary containing the result of each block call. 39 | */ 40 | - (NSDictionary *)cco_concurrentWithQueue:(dispatch_queue_t)queue map:(CCOMapBlock)mapBlock; 41 | 42 | /** 43 | * Returns a subset of the dictionary, containing only the objects for which the 44 | * predicate block returns true. The block calls are performed concurrently. 45 | * 46 | * The block calls are dispatched on the global concurrent dispatch queue with 47 | * default priority (`DISPATCH_QUEUE_PRIORITY_DEFAULT`). 48 | * 49 | * @see -cco_concurrentWithQueue:filter: 50 | * 51 | * @param predicateBlock Block that determines inclusion (YES) or exclusion (NO). 52 | * 53 | * @result Dictionary containing only the objects for which the predicate block returned true. 54 | */ 55 | - (NSDictionary *)cco_concurrentFilter:(CCOPredicateBlock)predicateBlock; 56 | 57 | /** 58 | * Returns a subset of the dictionary, containing only the objects for which the 59 | * predicate block returns true. The block calls are performed concurrently. The 60 | * block calls are dispatched on the supplied concurrent dispatch queue. 61 | * 62 | * @see -cco_concurrentFilter: 63 | * 64 | * @param queue Concurrent dispatch queue for executing predicateBlock. 65 | * @param predicateBlock Block that determines inclusion (YES) or exclusion (NO). 66 | * 67 | * @result Dictionary containing only the objects for which the predicate block returned true. 68 | */ 69 | - (NSDictionary *)cco_concurrentWithQueue:(dispatch_queue_t)queue filter:(CCOPredicateBlock)predicateBlock; 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/NSDictionary+ConcurrentCollectionOperations.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary+ConcurrentCollectionOperations.m 3 | // ConcurrentCollectionOperations 4 | // 5 | // Created by Dave Lee on 2013-06-02. 6 | // 7 | 8 | #import "NSDictionary+ConcurrentCollectionOperations.h" 9 | 10 | @implementation NSDictionary (ConcurrentCollectionOperations) 11 | 12 | - (NSDictionary *)cco_concurrentMap:(CCOMapBlock)mapBlock { 13 | NSParameterAssert(mapBlock != nil); 14 | 15 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 16 | return [self cco_concurrentWithQueue:queue map:mapBlock]; 17 | } 18 | 19 | - (NSDictionary *)cco_concurrentWithQueue:(dispatch_queue_t)queue map:(CCOMapBlock)mapBlock { 20 | NSParameterAssert(mapBlock != nil); 21 | 22 | NSDictionary *snapshot = [self copy]; 23 | 24 | id *keys = calloc(snapshot.count, sizeof(id)); 25 | id *objects = calloc(snapshot.count, sizeof(id));; 26 | [snapshot getObjects:objects andKeys:keys]; 27 | 28 | dispatch_apply(snapshot.count, queue, ^(size_t i) { 29 | objects[i] = [mapBlock(objects[i]) retain]; 30 | }); 31 | 32 | NSDictionary *result = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:snapshot.count]; 33 | 34 | dispatch_apply(snapshot.count, queue, ^(size_t i) { 35 | [objects[i] release]; 36 | }); 37 | free(objects); 38 | free(keys); 39 | [snapshot release]; 40 | 41 | return result; 42 | } 43 | 44 | - (NSDictionary *)cco_concurrentFilter:(CCOPredicateBlock)predicateBlock { 45 | NSParameterAssert(predicateBlock != nil); 46 | 47 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 48 | return [self cco_concurrentWithQueue:queue filter:predicateBlock]; 49 | } 50 | 51 | - (NSDictionary *)cco_concurrentWithQueue:(dispatch_queue_t)queue filter:(CCOPredicateBlock)predicateBlock { 52 | NSParameterAssert(predicateBlock != nil); 53 | 54 | NSDictionary *snapshot = [self copy]; 55 | 56 | id *keys = calloc(snapshot.count, sizeof(id)); 57 | id *objects = calloc(snapshot.count, sizeof(id)); 58 | [snapshot getObjects:objects andKeys:keys]; 59 | 60 | dispatch_apply(snapshot.count, queue, ^(size_t i) { 61 | if (!predicateBlock(objects[i])) { 62 | objects[i] = nil; 63 | } 64 | }); 65 | 66 | NSUInteger cursor = 0, nextFree = 0; 67 | while (cursor < snapshot.count) { 68 | if (objects[cursor]) { 69 | keys[nextFree] = keys[cursor]; 70 | objects[nextFree++] = objects[cursor++]; 71 | } else { 72 | cursor++; 73 | } 74 | } 75 | 76 | NSDictionary *result = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:nextFree]; 77 | 78 | free(objects); 79 | free(keys); 80 | [snapshot release]; 81 | 82 | return result; 83 | } 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/NSMapTable+ConcurrentCollectionOperations.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMapTable+ConcurrentCollectionOperations.h 3 | // ConcurrentCollectionOperations 4 | // 5 | // Created by Robert Widmann on 6/5/13. 6 | // 7 | 8 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 9 | 10 | #import 11 | #import "BlockTypedefs.h" 12 | 13 | @interface NSMapTable (ConcurrentCollectionOperations) 14 | 15 | /** 16 | * Returns an map table containing the results of calling the supplied block on 17 | * each value in the map table. The block calls are performed concurrently. 18 | * 19 | * The block calls are dispatched on the global concurrent dispatch queue with 20 | * default priority (`DISPATCH_QUEUE_PRIORITY_DEFAULT`). 21 | * 22 | * @see -cco_concurrentWithQueue:map: 23 | * 24 | * @param mapBlock Block that takes one object argument and another object. 25 | * 26 | * @result Map table containing the result of each block call. 27 | */ 28 | - (NSMapTable *)cco_concurrentMap:(CCOMapBlock)mapBlock; 29 | 30 | /** 31 | * Returns an map table containing the results of calling the supplied block on 32 | * each value in the map table. The block calls are performed concurrently. The 33 | * block calls are dispatched on the supplied concurrent dispatch queue. 34 | * 35 | * @see -cco_concurrentMap: 36 | * 37 | * @param queue Concurrent dispatch queue for executing mapBlock. 38 | * @param mapBlock Block that takes one object argument and another object. 39 | * 40 | * @result Map table containing the result of each block call. 41 | */ 42 | - (NSMapTable *)cco_concurrentWithQueue:(dispatch_queue_t)queue map:(CCOMapBlock)mapBlock; 43 | 44 | /** 45 | * Returns a subset of the map table, containing only the values for which the 46 | * predicate block returns true. The block calls are performed concurrently. 47 | * 48 | * The block calls are dispatched on the global concurrent dispatch queue with 49 | * default priority (`DISPATCH_QUEUE_PRIORITY_DEFAULT`). 50 | * 51 | * @see -cco_concurrentWithQueue:filter: 52 | * 53 | * @param predicateBlock Block that determines inclusion (YES) or exclusion (NO). 54 | * 55 | * @result Map table containing only the objects for which the predicate block returned true. 56 | */ 57 | - (NSMapTable *)cco_concurrentFilter:(CCOPredicateBlock)predicateBlock; 58 | 59 | /** 60 | * Returns a subset of the map table, containing only the values for which the 61 | * predicate block returns true. The block calls are performed concurrently. 62 | * The block calls are dispatched on the supplied concurrent dispatch queue. 63 | * 64 | * @see -cco_concurrentFilter: 65 | * 66 | * @param queue Concurrent dispatch queue for executing predicateBlock. 67 | * @param predicateBlock Block that determines inclusion (YES) or exclusion (NO). 68 | * 69 | * @result Map table containing only the objects for which the predicate block returned true. 70 | */ 71 | - (NSMapTable *)cco_concurrentWithQueue:(dispatch_queue_t)queue filter:(CCOPredicateBlock)predicateBlock; 72 | 73 | @end 74 | 75 | #endif -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/NSMapTable+ConcurrentCollectionOperations.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSMapTable+ConcurrentCollectionOperations.m 3 | // ConcurrentCollectionOperations 4 | // 5 | // Created by Robert Widmann on 6/5/13. 6 | // 7 | 8 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 9 | 10 | #import "NSMapTable+ConcurrentCollectionOperations.h" 11 | #import 12 | 13 | @implementation NSMapTable (ConcurrentCollectionOperations) 14 | 15 | - (NSMapTable *)cco_concurrentMap:(CCOMapBlock)mapBlock { 16 | NSParameterAssert(mapBlock != nil); 17 | 18 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 19 | return [self cco_concurrentWithQueue:queue map:mapBlock]; 20 | } 21 | 22 | - (NSMapTable *)cco_concurrentWithQueue:(dispatch_queue_t)queue map:(CCOMapBlock)mapBlock { 23 | NSParameterAssert(mapBlock != nil); 24 | 25 | __block OSSpinLock spinlock = OS_SPINLOCK_INIT; 26 | 27 | NSMapTable *result = NSCopyMapTableWithZone(self, NULL); 28 | NSResetMapTable(result); 29 | 30 | NSArray *keys = NSAllMapTableKeys(self); 31 | NSArray *objects = NSAllMapTableValues(self); 32 | 33 | dispatch_apply(self.count, queue, ^(size_t i) { 34 | OSSpinLockLock(&spinlock); 35 | [result setObject:mapBlock(objects[i]) forKey:keys[i]]; 36 | OSSpinLockUnlock(&spinlock); 37 | }); 38 | 39 | return [result autorelease]; 40 | } 41 | 42 | - (NSMapTable *)cco_concurrentFilter:(CCOPredicateBlock)predicateBlock { 43 | NSParameterAssert(predicateBlock != nil); 44 | 45 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 46 | return [self cco_concurrentWithQueue:queue filter:predicateBlock]; 47 | } 48 | 49 | - (NSMapTable *)cco_concurrentWithQueue:(dispatch_queue_t)queue filter:(CCOPredicateBlock)predicateBlock { 50 | NSParameterAssert(predicateBlock != nil); 51 | 52 | __block OSSpinLock spinlock = OS_SPINLOCK_INIT; 53 | 54 | NSMapTable *result = NSCopyMapTableWithZone(self, NULL); 55 | NSResetMapTable(result); 56 | 57 | NSArray *keys = NSAllMapTableKeys(self); 58 | NSMutableArray *objects = NSAllMapTableValues(self).mutableCopy; 59 | 60 | dispatch_apply(self.count, queue, ^(size_t i) { 61 | if (predicateBlock(objects[i])) { 62 | OSSpinLockLock(&spinlock); 63 | [result setObject:objects[i] forKey:keys[i]]; 64 | OSSpinLockUnlock(&spinlock); 65 | } 66 | }); 67 | 68 | return [result autorelease]; 69 | } 70 | 71 | @end 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/NSOrderedSet+ConcurrentCollectionOperations.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSOrderedSet+ConcurrentCollectionOperations.h 3 | // ConcurrentCollectionOperations 4 | // 5 | // Created by Dave Lee on 2013-06-09. 6 | // 7 | 8 | #import 9 | #import "BlockTypedefs.h" 10 | 11 | @interface NSOrderedSet (ConcurrentCollectionOperations) 12 | 13 | /** 14 | * Returns an ordered set containing the results of calling the supplied block 15 | * on each object in the ordered set. The block calls are performed 16 | * concurrently, but the order is preserved. 17 | * 18 | * The block calls are dispatched on the global concurrent dispatch queue with 19 | * default priority (`DISPATCH_QUEUE_PRIORITY_DEFAULT`). 20 | * 21 | * @see -cco_concurrentWithQueue:map: 22 | * 23 | * @param mapBlock Block that takes one object argument and another object. 24 | * 25 | * @result Ordered set containing the ordered result of each block call. 26 | */ 27 | - (NSOrderedSet *)cco_concurrentMap:(CCOMapBlock)mapBlock; 28 | 29 | /** 30 | * Returns an ordered set containing the results of calling the supplied block 31 | * on each object in the ordered set. The block calls are performed 32 | * concurrently, but the order is preserved. The block calls are dispatched on 33 | * the supplied concurrent dispatch queue. 34 | * 35 | * @see -cco_concurrentMap: 36 | * 37 | * @param queue Concurrent dispatch queue for executing mapBlock. 38 | * @param mapBlock Block that takes one object argument and another object. 39 | * 40 | * @result Ordered set containing the ordered result of each block call. 41 | */ 42 | - (NSOrderedSet *)cco_concurrentWithQueue:(dispatch_queue_t)queue map:(CCOMapBlock)mapBlock; 43 | 44 | /** 45 | * Returns a subsequence of the ordered set, containing only the objects for 46 | * which the predicate block returns true. The block calls are performed 47 | * concurrently, but the order is preserved. 48 | * 49 | * The block calls are dispatched on the global concurrent dispatch queue with 50 | * default priority (`DISPATCH_QUEUE_PRIORITY_DEFAULT`). 51 | * 52 | * @see -cco_concurrentWithQueue:filter: 53 | * 54 | * @param predicateBlock Block that determines inclusion (YES) or exclusion (NO). 55 | * 56 | * @result Ordered set containing only the objects for which the predicate block returned true. 57 | */ 58 | - (NSOrderedSet *)cco_concurrentFilter:(CCOPredicateBlock)predicateBlock; 59 | 60 | /** 61 | * Returns a subsequence of the ordered set, containing only the objects for 62 | * which the predicate block returns true. The block calls are performed 63 | * concurrently, but the order is preserved. The block calls are dispatched on 64 | * the supplied concurrent dispatch queue. 65 | * 66 | * @see -cco_concurrentFilter: 67 | * 68 | * @param queue Concurrent dispatch queue for executing predicateBlock. 69 | * @param predicateBlock Block that determines inclusion (YES) or exclusion (NO). 70 | * 71 | * @result Ordered set containing only the objects for which the predicate block returned true. 72 | */ 73 | - (NSOrderedSet *)cco_concurrentWithQueue:(dispatch_queue_t)queue filter:(CCOPredicateBlock)predicateBlock; 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/NSOrderedSet+ConcurrentCollectionOperations.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSOrderedSet+ConcurrentCollectionOperations.m 3 | // ConcurrentCollectionOperations 4 | // 5 | // Created by Dave Lee on 2013-06-09. 6 | // 7 | 8 | #import "NSOrderedSet+ConcurrentCollectionOperations.h" 9 | 10 | @implementation NSOrderedSet (ConcurrentCollectionOperations) 11 | 12 | - (NSOrderedSet *)cco_concurrentMap:(CCOMapBlock)mapBlock { 13 | NSParameterAssert(mapBlock != nil); 14 | 15 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 16 | return [self cco_concurrentWithQueue:queue map:mapBlock]; 17 | } 18 | 19 | - (NSOrderedSet *)cco_concurrentWithQueue:(dispatch_queue_t)queue map:(CCOMapBlock)mapBlock { 20 | NSParameterAssert(mapBlock != nil); 21 | 22 | NSOrderedSet *snapshot = [self copy]; 23 | 24 | id *objects = calloc(snapshot.count, sizeof(id)); 25 | [snapshot getObjects:objects range:NSMakeRange(0, snapshot.count)]; 26 | 27 | dispatch_apply(snapshot.count, queue, ^(size_t i) { 28 | objects[i] = [mapBlock(objects[i]) retain]; 29 | }); 30 | 31 | NSOrderedSet *result = [NSOrderedSet orderedSetWithObjects:objects count:snapshot.count]; 32 | 33 | dispatch_apply(snapshot.count, queue, ^(size_t i) { 34 | [objects[i] release]; 35 | }); 36 | free(objects); 37 | [snapshot release]; 38 | 39 | return result; 40 | } 41 | 42 | - (NSOrderedSet *)cco_concurrentFilter:(CCOPredicateBlock)predicateBlock { 43 | NSParameterAssert(predicateBlock != nil); 44 | 45 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 46 | return [self cco_concurrentWithQueue:queue filter:predicateBlock]; 47 | } 48 | 49 | - (NSOrderedSet *)cco_concurrentWithQueue:(dispatch_queue_t)queue filter:(CCOPredicateBlock)predicateBlock { 50 | NSParameterAssert(predicateBlock != nil); 51 | 52 | NSOrderedSet *snapshot = [self copy]; 53 | 54 | id *objects = calloc(snapshot.count, sizeof(id)); 55 | [snapshot getObjects:objects range:NSMakeRange(0, snapshot.count)]; 56 | 57 | dispatch_apply(snapshot.count, queue, ^(size_t i) { 58 | if (!predicateBlock(objects[i])) { 59 | objects[i] = nil; 60 | } 61 | }); 62 | 63 | NSUInteger cursor = 0, nextFree = 0; 64 | while (cursor < snapshot.count) { 65 | if (objects[cursor]) { 66 | objects[nextFree++] = objects[cursor++]; 67 | } else { 68 | cursor++; 69 | } 70 | } 71 | 72 | NSOrderedSet *result = [NSOrderedSet orderedSetWithObjects:objects count:nextFree]; 73 | 74 | free(objects); 75 | [snapshot release]; 76 | 77 | return result; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/NSSet+ConcurrentCollectionOperations.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSSet+ConcurrentCollectionOperations.h 3 | // ConcurrentCollectionOperations 4 | // 5 | // Created by Dave Lee on 2013-06-02. 6 | // 7 | 8 | #import 9 | #import "BlockTypedefs.h" 10 | 11 | @interface NSSet (ConcurrentCollectionOperations) 12 | 13 | /** 14 | * Returns a set containing the results of calling the supplied block on each 15 | * object in the set. The block calls are performed concurrently. 16 | * 17 | * The block calls are dispatched on the global concurrent dispatch queue with 18 | * default priority (`DISPATCH_QUEUE_PRIORITY_DEFAULT`). 19 | * 20 | * @see -cco_concurrentWithQueue:map: 21 | * 22 | * @param mapBlock Block that takes one object argument and another object. 23 | * 24 | * @result Set containing the result of each block call. 25 | */ 26 | - (NSSet *)cco_concurrentMap:(CCOMapBlock)mapBlock; 27 | 28 | /** 29 | * Returns a set containing the results of calling the supplied block on each 30 | * object in the set. The block calls are performed concurrently. The block 31 | * calls are dispatched on the supplied concurrent dispatch queue. 32 | * 33 | * @see -cco_concurrentMap: 34 | * 35 | * @param queue Concurrent dispatch queue for executing mapBlock. 36 | * @param mapBlock Block that takes one object argument and another object. 37 | * 38 | * @result Set containing the result of each block call. 39 | */ 40 | - (NSSet *)cco_concurrentWithQueue:(dispatch_queue_t)queue map:(CCOMapBlock)mapBlock; 41 | 42 | /** 43 | * Returns a subset containing only the objects for which the predicate block 44 | * returns true. The block calls are performed concurrently. 45 | * 46 | * The block calls are dispatched on the global concurrent dispatch queue with 47 | * default priority (`DISPATCH_QUEUE_PRIORITY_DEFAULT`). 48 | * 49 | * @see -cco_concurrentWithQueue:filter: 50 | * 51 | * @param predicateBlock Block that determines inclusion (YES) or exclusion (NO). 52 | * 53 | * @result Set containing only the objects for which the predicate block returned true. 54 | */ 55 | - (NSSet *)cco_concurrentFilter:(CCOPredicateBlock)predicateBlock; 56 | 57 | /** 58 | * Returns a subset containing only the objects for which the predicate block 59 | * returns true. The block calls are performed concurrently. The block calls are 60 | * dispatched on the supplied concurrent dispatch queue. 61 | * 62 | * @see -cco_concurrentFilter: 63 | * 64 | * @param queue Concurrent dispatch queue for executing predicateBlock. 65 | * @param predicateBlock Block that determines inclusion (YES) or exclusion (NO). 66 | * 67 | * @result Set containing only the objects for which the predicate block returned true. 68 | */ 69 | - (NSSet *)cco_concurrentWithQueue:(dispatch_queue_t)queue filter:(CCOPredicateBlock)predicateBlock; 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/NSSet+ConcurrentCollectionOperations.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSSet+ConcurrentCollectionOperations.m 3 | // ConcurrentCollectionOperations 4 | // 5 | // Created by Dave Lee on 2013-06-02. 6 | // 7 | 8 | #import "NSSet+ConcurrentCollectionOperations.h" 9 | 10 | @implementation NSSet (ConcurrentCollectionOperations) 11 | 12 | - (NSSet *)cco_concurrentMap:(CCOMapBlock)mapBlock { 13 | NSParameterAssert(mapBlock != nil); 14 | 15 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 16 | return [self cco_concurrentWithQueue:queue map:mapBlock]; 17 | } 18 | 19 | - (NSSet *)cco_concurrentWithQueue:(dispatch_queue_t)queue map:(CCOMapBlock)mapBlock { 20 | NSParameterAssert(mapBlock != nil); 21 | 22 | NSSet *snapshot = [self copy]; 23 | 24 | id *objects = calloc(snapshot.count, sizeof(id));; 25 | CFSetGetValues((CFSetRef)snapshot, (void *)objects); 26 | 27 | dispatch_apply(snapshot.count, queue, ^(size_t i) { 28 | objects[i] = [mapBlock(objects[i]) retain]; 29 | }); 30 | 31 | NSSet *result = [NSSet setWithObjects:objects count:snapshot.count]; 32 | 33 | dispatch_apply(snapshot.count, queue, ^(size_t i) { 34 | [objects[i] release]; 35 | }); 36 | free(objects); 37 | [snapshot release]; 38 | 39 | return result; 40 | } 41 | 42 | - (NSSet *)cco_concurrentFilter:(CCOPredicateBlock)predicateBlock { 43 | NSParameterAssert(predicateBlock != nil); 44 | 45 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 46 | return [self cco_concurrentWithQueue:queue filter:predicateBlock]; 47 | } 48 | 49 | - (NSSet *)cco_concurrentWithQueue:(dispatch_queue_t)queue filter:(CCOPredicateBlock)predicateBlock { 50 | NSParameterAssert(predicateBlock != nil); 51 | 52 | NSSet *snapshot = [self copy]; 53 | 54 | id *objects = calloc(snapshot.count, sizeof(id)); 55 | CFSetGetValues((CFSetRef)snapshot, (void *)objects); 56 | 57 | dispatch_apply(snapshot.count, queue, ^(size_t i) { 58 | if (!predicateBlock(objects[i])) { 59 | objects[i] = nil; 60 | } 61 | }); 62 | 63 | NSUInteger cursor = 0, nextFree = 0; 64 | while (cursor < snapshot.count) { 65 | if (objects[cursor]) { 66 | objects[nextFree++] = objects[cursor++]; 67 | } else { 68 | cursor++; 69 | } 70 | } 71 | 72 | NSSet *result = [NSSet setWithObjects:objects count:nextFree]; 73 | 74 | free(objects); 75 | [snapshot release]; 76 | 77 | return result; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperations/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperationsTests/ConcurrentCollectionOperationsBenchmarks.m: -------------------------------------------------------------------------------- 1 | // 2 | // ConcurrentCollectionOperationsBenchmarks.m 3 | // ConcurrentCollectionOperations 4 | // 5 | // Created by Josh Ballanco on 6/9/13. 6 | // 7 | 8 | #import 9 | #import "ConcurrentCollectionOperations.h" 10 | #import 11 | 12 | @interface ConcurrentCollectionOperationsBenchmarks : SenTestCase 13 | @property(strong, nonatomic) NSArray *numbersArray; 14 | @property(strong, nonatomic) NSDictionary *numbersDictionary; 15 | @property(strong, nonatomic) NSSet *numbersSet; 16 | @property(strong, nonatomic) NSOrderedSet *numbersOrderedSet; 17 | @end 18 | 19 | @implementation ConcurrentCollectionOperationsBenchmarks 20 | 21 | static NSTimeInterval totalRuntime = (NSTimeInterval)0; 22 | 23 | - (void)setUp { 24 | NSUInteger const SIZE = 1000; 25 | 26 | __unsafe_unretained id *tmp = (__unsafe_unretained id *)calloc(SIZE, sizeof(id)); 27 | for (NSUInteger i = 0; i < SIZE; i++) { 28 | tmp[i] = [NSNumber numberWithUnsignedInteger:i]; 29 | } 30 | 31 | self.numbersArray = [NSArray arrayWithObjects:tmp count:SIZE]; 32 | self.numbersDictionary = [NSDictionary dictionaryWithObjects:self.numbersArray 33 | forKeys:self.numbersArray]; 34 | self.numbersSet = [NSSet setWithArray:self.numbersArray]; 35 | self.numbersOrderedSet = [NSOrderedSet orderedSetWithArray:self.numbersArray]; 36 | 37 | free(tmp); 38 | } 39 | 40 | - (void)runBenchmark:(NSString *)name withBlock:(void (^)(void))block { 41 | NSUInteger const LOOP_COUNT = 20000; 42 | NSDate *start = [NSDate date]; 43 | NSTimeInterval runtime; 44 | 45 | for (uint64_t i = 0; i < LOOP_COUNT; i++) { 46 | block(); 47 | } 48 | 49 | totalRuntime += runtime = -[start timeIntervalSinceNow]; 50 | NSLog(@"%@ benchmark: %.3fs", name, runtime); 51 | } 52 | 53 | + (NSArray *)testInvocations { 54 | unsigned int methodCount; 55 | Method *methods = class_copyMethodList(self, &methodCount); 56 | assert(methodCount); 57 | 58 | Method method; 59 | SEL methodName; 60 | NSMethodSignature *methodSig; 61 | 62 | NSMutableArray *invocations = [[NSMutableArray alloc] init]; 63 | NSInvocation *invocation; 64 | 65 | do { 66 | method = methods[--methodCount]; 67 | methodName = method_getName(method); 68 | if (!strncmp("benchmark", sel_getName(methodName), 9)) { 69 | methodSig = [NSMethodSignature signatureWithObjCTypes:method_getTypeEncoding(method)]; 70 | invocation = [NSInvocation invocationWithMethodSignature:methodSig]; 71 | [invocation setSelector:methodName]; 72 | [invocations addObject:invocation]; 73 | } 74 | } while (methodCount); 75 | 76 | return invocations; 77 | } 78 | 79 | + (void)tearDown { 80 | NSLog(@"\n*****\nTotal Benchmark Runtime: %.3fs\n*****", totalRuntime); 81 | } 82 | 83 | #pragma mark - NSArray 84 | 85 | - (void)benchmarkArrayMap { 86 | [self runBenchmark:@"Array Map" withBlock:^{ 87 | [self.numbersArray cco_concurrentMap:^(NSNumber *number) { 88 | return @(2 * number.unsignedIntegerValue); 89 | }]; 90 | }]; 91 | } 92 | 93 | - (void)benchmarkArrayFilter { 94 | [self runBenchmark:@"Array Filter" withBlock:^{ 95 | [self.numbersArray cco_concurrentFilter:^BOOL (NSNumber *number) { 96 | return number.unsignedIntegerValue % 2 == 1; 97 | }]; 98 | }]; 99 | } 100 | 101 | #pragma mark - NSDictionary 102 | 103 | - (void)benchmarkDictionaryMap { 104 | [self runBenchmark:@"Dictionary Map" withBlock:^{ 105 | [self.numbersDictionary cco_concurrentMap:^(NSNumber *number) { 106 | return @(2 * number.unsignedIntegerValue); 107 | }]; 108 | }]; 109 | } 110 | 111 | - (void)benchmarkDictionaryFilter { 112 | [self runBenchmark:@"Dictionary Filter" withBlock:^{ 113 | [self.numbersDictionary cco_concurrentFilter:^BOOL (NSNumber *number) { 114 | return number.unsignedIntegerValue % 2 == 1; 115 | }]; 116 | }]; 117 | } 118 | 119 | #pragma mark - NSSet 120 | 121 | - (void)benchmarkSetMap { 122 | [self runBenchmark:@"Set Map" withBlock:^{ 123 | [self.numbersSet cco_concurrentMap:^(NSNumber *number) { 124 | return @(2 * number.unsignedIntegerValue); 125 | }]; 126 | }]; 127 | } 128 | 129 | - (void)benchmarkSetFilter { 130 | [self runBenchmark:@"Set Filter" withBlock:^{ 131 | [self.numbersSet cco_concurrentFilter:^BOOL (NSNumber *number) { 132 | return number.unsignedIntegerValue % 2 == 1; 133 | }]; 134 | }]; 135 | } 136 | 137 | #pragma mark - NSOrderedSet 138 | 139 | - (void)benchmarkOrderedSetMap { 140 | [self runBenchmark:@"Ordered Set Map" withBlock:^{ 141 | [self.numbersOrderedSet cco_concurrentMap:^(NSNumber *number) { 142 | return @(2 * number.unsignedIntegerValue); 143 | }]; 144 | }]; 145 | } 146 | 147 | - (void)benchmarkOrderedSetFilter { 148 | [self runBenchmark:@"Ordered Set Filter" withBlock:^{ 149 | [self.numbersOrderedSet cco_concurrentFilter:^BOOL (NSNumber *number) { 150 | return number.unsignedIntegerValue % 2 == 1; 151 | }]; 152 | }]; 153 | } 154 | 155 | @end 156 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperationsTests/ConcurrentCollectionOperationsTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.internet.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperationsTests/ConcurrentCollectionOperationsTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ConcurrentCollectionOperationsTests.m 3 | // ConcurrentCollectionOperationsTests 4 | // 5 | // Created by Dave Lee on 2013-06-02. 6 | // 7 | 8 | #import 9 | #import "ConcurrentCollectionOperations.h" 10 | 11 | static const NSUInteger kCollectionCount = 100; 12 | 13 | @interface ConcurrentCollectionOperationsTests : SenTestCase 14 | 15 | @property (strong, nonatomic) NSMutableArray *numbersArray; 16 | @property (strong, nonatomic) NSMutableDictionary *numbersDictionary; 17 | @property (strong, nonatomic) NSMutableSet *numbersSet; 18 | 19 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 20 | @property (strong, nonatomic) NSMapTable *numbersMapTable; 21 | #endif 22 | 23 | @property (strong, nonatomic) NSMutableArray *doubledNumbers; 24 | @property (strong, nonatomic) NSMutableArray *oddNumbers; 25 | 26 | @property (strong, nonatomic) NSMutableArray *mutableObjectsArray; 27 | 28 | @end 29 | 30 | @implementation ConcurrentCollectionOperationsTests 31 | 32 | - (void)setUp { 33 | self.numbersArray = [NSMutableArray arrayWithCapacity:kCollectionCount]; 34 | self.numbersDictionary = [NSMutableDictionary dictionaryWithCapacity:kCollectionCount]; 35 | self.numbersSet = [NSMutableSet setWithCapacity:kCollectionCount]; 36 | 37 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 38 | NSPointerFunctionsOptions mapTableOptions = (NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPersonality); 39 | self.numbersMapTable = [NSMapTable mapTableWithKeyOptions:mapTableOptions valueOptions:mapTableOptions]; 40 | #endif 41 | 42 | self.doubledNumbers = [NSMutableArray arrayWithCapacity:kCollectionCount]; 43 | self.oddNumbers = [NSMutableArray arrayWithCapacity:(kCollectionCount / 2)]; 44 | 45 | self.mutableObjectsArray = [NSMutableArray arrayWithCapacity:kCollectionCount]; 46 | 47 | for (NSUInteger i = 0; i < kCollectionCount; ++i) { 48 | [self.numbersArray addObject:@(i)]; 49 | [self.numbersDictionary setObject:@(i) forKey:@(i)]; 50 | [self.numbersSet addObject:@(i)]; 51 | 52 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 53 | [self.numbersMapTable setObject:@(i) forKey:@(i)]; 54 | #endif 55 | [self.doubledNumbers addObject:@(2 * i)]; 56 | if (i % 2 == 1) [self.oddNumbers addObject:@(i)]; 57 | 58 | [self.mutableObjectsArray addObject:[NSObject new]]; 59 | } 60 | } 61 | 62 | #pragma mark - NSArray 63 | 64 | - (void)testArrayDoublingMap { 65 | NSArray *mapped = [self.numbersArray cco_concurrentMap:^(NSNumber *number) { 66 | return @(2 * number.unsignedIntegerValue); 67 | }]; 68 | STAssertEqualObjects(mapped, self.doubledNumbers, @"Failed to perform array doubling map"); 69 | } 70 | 71 | - (void)testArrayOddFilter { 72 | NSArray *filtered = [self.numbersArray cco_concurrentFilter:^BOOL (NSNumber *number) { 73 | return number.unsignedIntegerValue % 2 == 1; 74 | }]; 75 | STAssertEqualObjects(filtered, self.oddNumbers, @"Failed for filter array for odds"); 76 | } 77 | 78 | #pragma mark - NSDictionary 79 | 80 | - (void)testDictionaryDoublingMap { 81 | NSDictionary *mapped = [self.numbersDictionary cco_concurrentMap:^(NSNumber *number) { 82 | return @(2 * number.unsignedIntegerValue); 83 | }]; 84 | NSArray *mappedNumbers = [mapped.allValues sortedArrayUsingSelector:@selector(compare:)]; 85 | STAssertEqualObjects(mappedNumbers, self.doubledNumbers, @"Failed to perform dictionary doubling map"); 86 | } 87 | 88 | - (void)testDictionaryOddFilter { 89 | NSDictionary *filtered = [self.numbersDictionary cco_concurrentFilter:^BOOL (NSNumber *number) { 90 | return number.unsignedIntegerValue % 2 == 1; 91 | }]; 92 | NSArray *filteredNumbers = [filtered.allValues sortedArrayUsingSelector:@selector(compare:)]; 93 | STAssertEqualObjects(filteredNumbers, self.oddNumbers, @"Failed to filter dictionary for odds"); 94 | } 95 | 96 | #pragma mark - NSMapTable 97 | 98 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 99 | 100 | - (void)testMapTableDoublingMap { 101 | NSMapTable *mapped = [self.numbersMapTable cco_concurrentMap:^(NSNumber *number) { 102 | return @(2 * number.unsignedIntegerValue); 103 | }]; 104 | NSArray *mappedNumbers = [mapped.dictionaryRepresentation.allValues sortedArrayUsingSelector:@selector(compare:)]; 105 | STAssertEqualObjects(mappedNumbers, self.doubledNumbers, @"Failed to perform map table doubling map"); 106 | } 107 | 108 | - (void)testMapTableOddFilter { 109 | NSMapTable *filtered = [self.numbersMapTable cco_concurrentFilter:^BOOL (NSNumber *number) { 110 | return number.unsignedIntegerValue % 2 == 1; 111 | }]; 112 | NSArray *filteredNumbers = [filtered.dictionaryRepresentation.allValues sortedArrayUsingSelector:@selector(compare:)]; 113 | STAssertEqualObjects(filteredNumbers, self.oddNumbers, @"Failed to filter map table for odds"); 114 | } 115 | 116 | #endif 117 | 118 | #pragma mark - NSSet 119 | 120 | - (void)testSetDoublingMap { 121 | NSSet *mapped = [self.numbersSet cco_concurrentMap:^(NSNumber *number) { 122 | return @(2 * number.unsignedIntegerValue); 123 | }]; 124 | STAssertEqualObjects(mapped, [NSSet setWithArray:self.doubledNumbers], @"Failed to perform set doubling map"); 125 | } 126 | 127 | - (void)testSetOddFilter { 128 | NSSet *filtered = [self.numbersSet cco_concurrentFilter:^BOOL (NSNumber *number) { 129 | return number.unsignedIntegerValue % 2 == 1; 130 | }]; 131 | STAssertEqualObjects(filtered, [NSSet setWithArray:self.oddNumbers], @"Failed for filter set for odds"); 132 | } 133 | 134 | #pragma mark - NSSet 135 | 136 | - (void)testOrderedSetDoublingMap { 137 | NSOrderedSet *numbersOrderedSet = [NSOrderedSet orderedSetWithArray:self.numbersArray]; 138 | NSOrderedSet *mapped = [numbersOrderedSet cco_concurrentMap:^(NSNumber *number) { 139 | return @(2 * number.unsignedIntegerValue); 140 | }]; 141 | STAssertEqualObjects(mapped.array, self.doubledNumbers, @"Failed to perform ordered set doubling map"); 142 | } 143 | 144 | - (void)testOrderedSetOddFilter { 145 | NSOrderedSet *numbersOrderedSet = [NSOrderedSet orderedSetWithArray:self.numbersArray]; 146 | NSOrderedSet *filtered = [numbersOrderedSet cco_concurrentFilter:^BOOL (NSNumber *number) { 147 | return number.unsignedIntegerValue % 2 == 1; 148 | }]; 149 | STAssertEqualObjects(filtered.array, self.oddNumbers, @"Failed for filter ordered set for odds"); 150 | } 151 | 152 | #pragma mark - Concurrent with Mutation 153 | 154 | - (void)testArrayMapConcurrentWithMutation { 155 | NSArray *mapped = [self.mutableObjectsArray cco_concurrentMap:^(id object) { 156 | @synchronized (self.mutableObjectsArray) { [self.mutableObjectsArray removeAllObjects]; } 157 | return [NSObject new]; 158 | }]; 159 | STAssertEquals(mapped.count, kCollectionCount, @"Failed to perform array map concurrent with mutation"); 160 | } 161 | 162 | - (void)testArrayFilterConcurrentWithMutation { 163 | NSArray *filtered = [self.mutableObjectsArray cco_concurrentFilter:^(id object) { 164 | @synchronized (self.mutableObjectsArray) { [self.mutableObjectsArray removeAllObjects]; } 165 | return YES; 166 | }]; 167 | STAssertEquals(filtered.count, kCollectionCount, @"Failed to perform array filter concurrent with mutation"); 168 | } 169 | 170 | - (void)testDictionaryMapConcurrentWithMutation { 171 | NSMutableDictionary *mutableObjectsDictionary = [NSMutableDictionary dictionaryWithObjects:self.mutableObjectsArray forKeys:[self.mutableObjectsArray valueForKey:@"description"]]; 172 | NSDictionary *mapped = [mutableObjectsDictionary cco_concurrentMap:^(id object) { 173 | @synchronized (mutableObjectsDictionary) { [mutableObjectsDictionary removeAllObjects]; } 174 | return [NSObject new]; 175 | }]; 176 | STAssertEquals(mapped.count, kCollectionCount, @"Failed to perform dictionary map concurrent with mutation"); 177 | } 178 | 179 | - (void)testDictionaryFilterConcurrentWithMutation { 180 | NSMutableDictionary *mutableObjectsDictionary = [NSMutableDictionary dictionaryWithObjects:self.mutableObjectsArray forKeys:[self.mutableObjectsArray valueForKey:@"description"]]; 181 | NSDictionary *filtered = [mutableObjectsDictionary cco_concurrentFilter:^(id object) { 182 | @synchronized (mutableObjectsDictionary) { [mutableObjectsDictionary removeAllObjects]; } 183 | return YES; 184 | }]; 185 | STAssertEquals(filtered.count, kCollectionCount, @"Failed to perform dictionary filter concurrent with mutation"); 186 | } 187 | 188 | - (void)testSetMapConcurrentWithMutation { 189 | NSMutableSet *mutableObjectsSet = [NSMutableSet setWithArray:self.mutableObjectsArray]; 190 | NSSet *mapped = [mutableObjectsSet cco_concurrentMap:^(id object) { 191 | @synchronized (mutableObjectsSet) { [mutableObjectsSet removeAllObjects]; } 192 | return [NSObject new]; 193 | }]; 194 | STAssertEquals(mapped.count, kCollectionCount, @"Failed to perform set map concurrent with mutation"); 195 | } 196 | 197 | - (void)testSetFilterConcurrentWithMutation { 198 | NSMutableSet *mutableObjectsSet = [NSMutableSet setWithArray:self.mutableObjectsArray]; 199 | NSSet *filtered = [mutableObjectsSet cco_concurrentFilter:^(id object) { 200 | @synchronized (mutableObjectsSet) { [mutableObjectsSet removeAllObjects]; } 201 | return YES; 202 | }]; 203 | STAssertEquals(filtered.count, kCollectionCount, @"Failed to perform set filter concurrent with mutation"); 204 | } 205 | 206 | - (void)testOrderedSetMapConcurrentWithMutation { 207 | NSMutableOrderedSet *mutableObjectsOrderedSet = [NSMutableOrderedSet orderedSetWithArray:self.mutableObjectsArray]; 208 | NSOrderedSet *mapped = [mutableObjectsOrderedSet cco_concurrentMap:^(id object) { 209 | @synchronized (mutableObjectsOrderedSet) { [mutableObjectsOrderedSet removeAllObjects]; } 210 | return [NSObject new]; 211 | }]; 212 | STAssertEquals(mapped.count, kCollectionCount, @"Failed to perform set map concurrent with mutation"); 213 | } 214 | 215 | - (void)testOrderedSetFilterConcurrentWithMutation { 216 | NSMutableOrderedSet *mutableObjectsOrderedSet = [NSMutableOrderedSet orderedSetWithArray:self.mutableObjectsArray]; 217 | NSOrderedSet *filtered = [mutableObjectsOrderedSet cco_concurrentFilter:^(id object) { 218 | @synchronized (mutableObjectsOrderedSet) { [mutableObjectsOrderedSet removeAllObjects]; } 219 | return YES; 220 | }]; 221 | STAssertEquals(filtered.count, kCollectionCount, @"Failed to perform set filter concurrent with mutation"); 222 | } 223 | 224 | @end 225 | -------------------------------------------------------------------------------- /ConcurrentCollectionOperationsTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 David Lee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Concurrent Collection Operations 2 | 3 | A set of categories for performing concurrent map and filter operations on 4 | Foundation data structures. `NSArray`, `NSDictionary`, `NSSet`, `NSOrderedSet`, 5 | and `NSMapTable` (OS X) are currently supported. 6 | 7 | Concurrency is achieved using Grand Central Dispatch's `dispatch_apply`. By 8 | default, operations are run on the default priority global concurrent queue 9 | (`DISPATCH_QUEUE_PRIORITY_DEFAULT`). The operations can be performed on any 10 | concurrent queue, see the category header files. 11 | 12 | Please note that using this code could actually result in slower performance. 13 | For example, if a map or filter operation uses up a large amount of memory, 14 | then performing it concurrently could cause memory thrashing. Currently, this 15 | API does not offer a way to limit the amount of concurrency, but doing so 16 | explicitly with `dispatch_semaphore` is straight forward. 17 | 18 | This library is based off code and ideas from [@alloy](https://github.com/alloy) 19 | and [@seanlilmateus](https://github.com/seanlilmateus). 20 | 21 | ### Installation 22 | 23 | Install via [CocoaPods](http://cocoapods.org/), or by adding the Xcode project 24 | to your project. 25 | 26 | ### Examples 27 | 28 | These examples are taken from the [tests](https://github.com/kastiglione/ConcurrentCollectionOperations/blob/master/ConcurrentCollectionOperationsTests/ConcurrentCollectionOperationsTests.m). 29 | 30 | Doubling the values of an array: 31 | 32 | ```objc 33 | NSArray *doubled = [numbersArray cco_concurrentMap:^(NSNumber *number) { 34 | return @(2 * number.unsignedIntegerValue); 35 | }]; 36 | ``` 37 | 38 | Filtering even numbers out of a dictionary: 39 | 40 | ```objc 41 | NSDictionary *filtered = [numbersDictionary cco_concurrentFilter:^BOOL (NSNumber *number) { 42 | return number.unsignedIntegerValue % 2 == 1; 43 | }]; 44 | ``` 45 | 46 | ### Contributors 47 | 48 | ConcurrentCollectionOperations has been made by [@alloy](https://github.com/alloy), 49 | [@CodaFi](https://github.com/CodaFi), [@jballanc](https://github.com/jballanc), 50 | [@kastiglione](https://github.com/kastiglione), and 51 | [@seanlilmateus](https://github.com/seanlilmateus). 52 | 53 | ### TODO 54 | 55 | 1. Write heavier/stressing tests. 56 | 57 | ### License 58 | 59 | Concurrent Collection Operations is released under the MIT License. See 60 | [LICENSE.txt](https://github.com/kastiglione/ConcurrentCollectionOperations/blob/master/LICENSE.txt). 61 | 62 | ### Contributing 63 | 64 | 1. Fork it 65 | 1. Create your feature branch (git checkout -b my-new-feature) 66 | 1. Commit your changes (git commit -am 'Add some feature') 67 | 1. Push to the branch (git push origin my-new-feature) 68 | 1. Create new Pull Request 69 | --------------------------------------------------------------------------------