ibireme 8 жил өмнө
parent
commit
542114ea2b
44 өөрчлөгдсөн 3672 нэмэгдсэн , 5067 устгасан
  1. 221 203
      Benchmark/CacheBenchmark.xcodeproj/project.pbxproj
  2. 2 2
      Benchmark/CacheBenchmark/AppDelegate.h
  3. 10 4
      Benchmark/CacheBenchmark/AppDelegate.m
  4. 55 0
      Benchmark/CacheBenchmark/Assets.xcassets/AppIcon.appiconset/Contents.json
  5. 5 6
      Benchmark/CacheBenchmark/Base.lproj/LaunchScreen.storyboard
  6. 6 25
      Benchmark/CacheBenchmark/Base.lproj/Main.storyboard
  7. 3 130
      Benchmark/CacheBenchmark/Benchmark.m
  8. 10 3
      Benchmark/CacheBenchmark/Info.plist
  9. 2 2
      Benchmark/CacheBenchmark/ViewController.h
  10. 11 3
      Benchmark/CacheBenchmark/ViewController.m
  11. 2 2
      Benchmark/CacheBenchmark/main.m
  12. 0 20
      Benchmark/Vendor/PINCache/Nullability.h
  13. 55 117
      Benchmark/Vendor/PINCache/PINCache.h
  14. 190 171
      Benchmark/Vendor/PINCache/PINCache.m
  15. 23 0
      Benchmark/Vendor/PINCache/PINCacheMacros.h
  16. 35 0
      Benchmark/Vendor/PINCache/PINCacheObjectSubscripting.h
  17. 189 0
      Benchmark/Vendor/PINCache/PINCaching.h
  18. 225 79
      Benchmark/Vendor/PINCache/PINDiskCache.h
  19. 487 251
      Benchmark/Vendor/PINCache/PINDiskCache.m
  20. 62 147
      Benchmark/Vendor/PINCache/PINMemoryCache.h
  21. 283 144
      Benchmark/Vendor/PINCache/PINMemoryCache.m
  22. 12 0
      Benchmark/Vendor/PINCache/PINOperation/PINOperation.h
  23. 38 0
      Benchmark/Vendor/PINCache/PINOperation/PINOperationGroup.h
  24. 187 0
      Benchmark/Vendor/PINCache/PINOperation/PINOperationGroup.m
  25. 15 0
      Benchmark/Vendor/PINCache/PINOperation/PINOperationMacros.h
  26. 132 0
      Benchmark/Vendor/PINCache/PINOperation/PINOperationQueue.h
  27. 442 0
      Benchmark/Vendor/PINCache/PINOperation/PINOperationQueue.m
  28. 15 0
      Benchmark/Vendor/PINCache/PINOperation/PINOperationTypes.h
  29. 429 113
      Benchmark/Vendor/SQLite/sqlite3.c
  30. 387 126
      Benchmark/Vendor/SQLite/sqlite3.h
  31. 0 177
      Benchmark/Vendor/TMCache/TMCache.h
  32. 0 387
      Benchmark/Vendor/TMCache/TMCache.m
  33. 0 36
      Benchmark/Vendor/TMCache/TMCacheBackgroundTaskManager.h
  34. 0 350
      Benchmark/Vendor/TMCache/TMDiskCache.h
  35. 0 1063
      Benchmark/Vendor/TMCache/TMDiskCache.m
  36. 0 310
      Benchmark/Vendor/TMCache/TMMemoryCache.h
  37. 0 882
      Benchmark/Vendor/TMCache/TMMemoryCache.m
  38. 2 0
      Benchmark/Vendor/version.txt
  39. 1 3
      Framework/Info.plist
  40. 0 189
      Framework/YYCache-Static.xcodeproj/project.pbxproj
  41. 0 7
      Framework/YYCache-Static.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  42. 129 109
      Framework/YYCache.xcodeproj/project.pbxproj
  43. 6 5
      Framework/YYCache.xcodeproj/xcshareddata/xcschemes/YYCache.xcscheme
  44. 1 1
      README.md

+ 221 - 203
Benchmark/CacheBenchmark.xcodeproj/project.pbxproj

@@ -3,77 +3,77 @@
 	archiveVersion = 1;
 	classes = {
 	};
-	objectVersion = 46;
+	objectVersion = 48;
 	objects = {
 
 /* Begin PBXBuildFile section */
-		D91525C81BD6756400EE6881 /* Benchmark.m in Sources */ = {isa = PBXBuildFile; fileRef = D91525C71BD6756400EE6881 /* Benchmark.m */; settings = {ASSET_TAGS = (); }; };
-		D99B97231BD79059001477E6 /* Result.txt in Resources */ = {isa = PBXBuildFile; fileRef = D99B97221BD79059001477E6 /* Result.txt */; settings = {ASSET_TAGS = (); }; };
-		D99B97251BD7945B001477E6 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = D99B971F1BD78BD1001477E6 /* sqlite3.c */; };
-		D9EB033A1BD64CB600B3E0F5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB03391BD64CB600B3E0F5 /* main.m */; };
-		D9EB033D1BD64CB600B3E0F5 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB033C1BD64CB600B3E0F5 /* AppDelegate.m */; };
-		D9EB03401BD64CB600B3E0F5 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB033F1BD64CB600B3E0F5 /* ViewController.m */; };
-		D9EB03431BD64CB600B3E0F5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D9EB03411BD64CB600B3E0F5 /* Main.storyboard */; };
-		D9EB03451BD64CB600B3E0F5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D9EB03441BD64CB600B3E0F5 /* Assets.xcassets */; };
-		D9EB03481BD64CB600B3E0F5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D9EB03461BD64CB600B3E0F5 /* LaunchScreen.storyboard */; };
-		D9EB04251BD6516900B3E0F5 /* PINCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB04151BD6516900B3E0F5 /* PINCache.m */; settings = {ASSET_TAGS = (); }; };
-		D9EB04261BD6516900B3E0F5 /* PINDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB04171BD6516900B3E0F5 /* PINDiskCache.m */; settings = {ASSET_TAGS = (); }; };
-		D9EB04271BD6516900B3E0F5 /* PINMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB04191BD6516900B3E0F5 /* PINMemoryCache.m */; settings = {ASSET_TAGS = (); }; };
-		D9EB04281BD6516900B3E0F5 /* TMCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB041C1BD6516900B3E0F5 /* TMCache.m */; settings = {ASSET_TAGS = (); }; };
-		D9EB04291BD6516900B3E0F5 /* TMDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB041F1BD6516900B3E0F5 /* TMDiskCache.m */; settings = {ASSET_TAGS = (); }; };
-		D9EB042A1BD6516900B3E0F5 /* TMMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB04211BD6516900B3E0F5 /* TMMemoryCache.m */; settings = {ASSET_TAGS = (); }; };
-		D9EB042B1BD6516900B3E0F5 /* YYThreadSafeDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB04241BD6516900B3E0F5 /* YYThreadSafeDictionary.m */; settings = {ASSET_TAGS = (); }; };
-		D9EB04351BD652E200B3E0F5 /* YYCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB042E1BD652E200B3E0F5 /* YYCache.m */; settings = {ASSET_TAGS = (); }; };
-		D9EB04361BD652E200B3E0F5 /* YYDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB04301BD652E200B3E0F5 /* YYDiskCache.m */; settings = {ASSET_TAGS = (); }; };
-		D9EB04371BD652E200B3E0F5 /* YYKVStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB04321BD652E200B3E0F5 /* YYKVStorage.m */; settings = {ASSET_TAGS = (); }; };
-		D9EB04381BD652E200B3E0F5 /* YYMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB04341BD652E200B3E0F5 /* YYMemoryCache.m */; settings = {ASSET_TAGS = (); }; };
+		D967E0DC1F0553F000791B80 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = D967E0C61F0553F000791B80 /* sqlite3.c */; };
+		D967E0DD1F0553F000791B80 /* version.txt in Resources */ = {isa = PBXBuildFile; fileRef = D967E0C81F0553F000791B80 /* version.txt */; };
+		D967E0DE1F0553F000791B80 /* YYThreadSafeDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = D967E0CB1F0553F000791B80 /* YYThreadSafeDictionary.m */; };
+		D9C586471F054B5E00320F3B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D9C586461F054B5E00320F3B /* AppDelegate.m */; };
+		D9C5864A1F054B5E00320F3B /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D9C586491F054B5E00320F3B /* ViewController.m */; };
+		D9C5864D1F054B5E00320F3B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D9C5864B1F054B5E00320F3B /* Main.storyboard */; };
+		D9C5864F1F054B5E00320F3B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D9C5864E1F054B5E00320F3B /* Assets.xcassets */; };
+		D9C586521F054B5E00320F3B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D9C586501F054B5E00320F3B /* LaunchScreen.storyboard */; };
+		D9C586551F054B5E00320F3B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D9C586541F054B5E00320F3B /* main.m */; };
+		D9D583F51F0554DE00CBBB61 /* YYCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D583EE1F0554DE00CBBB61 /* YYCache.m */; };
+		D9D583F61F0554DE00CBBB61 /* YYDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D583F01F0554DE00CBBB61 /* YYDiskCache.m */; };
+		D9D583F71F0554DE00CBBB61 /* YYKVStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D583F21F0554DE00CBBB61 /* YYKVStorage.m */; };
+		D9D583F81F0554DE00CBBB61 /* YYMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D583F41F0554DE00CBBB61 /* YYMemoryCache.m */; };
+		D9D584501F05579A00CBBB61 /* PINCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D5843F1F05579000CBBB61 /* PINCache.m */; };
+		D9D584511F05579A00CBBB61 /* PINDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D584441F05579000CBBB61 /* PINDiskCache.m */; };
+		D9D584521F05579A00CBBB61 /* PINMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D584461F05579000CBBB61 /* PINMemoryCache.m */; };
+		D9D584531F05579A00CBBB61 /* PINOperationGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D5844B1F05579000CBBB61 /* PINOperationGroup.m */; };
+		D9D584541F05579A00CBBB61 /* PINOperationQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D5844E1F05579000CBBB61 /* PINOperationQueue.m */; };
+		D9F7E2161F36D7D4003F5035 /* Benchmark.m in Sources */ = {isa = PBXBuildFile; fileRef = D9F7E2151F36D7D4003F5035 /* Benchmark.m */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
-		D91525C61BD6756400EE6881 /* Benchmark.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Benchmark.h; path = CacheBenchmark/Benchmark.h; sourceTree = "<group>"; };
-		D91525C71BD6756400EE6881 /* Benchmark.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Benchmark.m; path = CacheBenchmark/Benchmark.m; sourceTree = "<group>"; };
-		D99B971F1BD78BD1001477E6 /* sqlite3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sqlite3.c; sourceTree = "<group>"; };
-		D99B97201BD78BD1001477E6 /* sqlite3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqlite3.h; sourceTree = "<group>"; };
-		D99B97221BD79059001477E6 /* Result.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Result.txt; sourceTree = "<group>"; };
-		D9EB03351BD64CB600B3E0F5 /* CacheBenchmark.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CacheBenchmark.app; sourceTree = BUILT_PRODUCTS_DIR; };
-		D9EB03391BD64CB600B3E0F5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
-		D9EB033B1BD64CB600B3E0F5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
-		D9EB033C1BD64CB600B3E0F5 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
-		D9EB033E1BD64CB600B3E0F5 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
-		D9EB033F1BD64CB600B3E0F5 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
-		D9EB03421BD64CB600B3E0F5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
-		D9EB03441BD64CB600B3E0F5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
-		D9EB03471BD64CB600B3E0F5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
-		D9EB03491BD64CB600B3E0F5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		D9EB04131BD6516900B3E0F5 /* Nullability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Nullability.h; sourceTree = "<group>"; };
-		D9EB04141BD6516900B3E0F5 /* PINCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PINCache.h; sourceTree = "<group>"; };
-		D9EB04151BD6516900B3E0F5 /* PINCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PINCache.m; sourceTree = "<group>"; };
-		D9EB04161BD6516900B3E0F5 /* PINDiskCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PINDiskCache.h; sourceTree = "<group>"; };
-		D9EB04171BD6516900B3E0F5 /* PINDiskCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PINDiskCache.m; sourceTree = "<group>"; };
-		D9EB04181BD6516900B3E0F5 /* PINMemoryCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PINMemoryCache.h; sourceTree = "<group>"; };
-		D9EB04191BD6516900B3E0F5 /* PINMemoryCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PINMemoryCache.m; sourceTree = "<group>"; };
-		D9EB041B1BD6516900B3E0F5 /* TMCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TMCache.h; sourceTree = "<group>"; };
-		D9EB041C1BD6516900B3E0F5 /* TMCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TMCache.m; sourceTree = "<group>"; };
-		D9EB041D1BD6516900B3E0F5 /* TMCacheBackgroundTaskManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TMCacheBackgroundTaskManager.h; sourceTree = "<group>"; };
-		D9EB041E1BD6516900B3E0F5 /* TMDiskCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TMDiskCache.h; sourceTree = "<group>"; };
-		D9EB041F1BD6516900B3E0F5 /* TMDiskCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TMDiskCache.m; sourceTree = "<group>"; };
-		D9EB04201BD6516900B3E0F5 /* TMMemoryCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TMMemoryCache.h; sourceTree = "<group>"; };
-		D9EB04211BD6516900B3E0F5 /* TMMemoryCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TMMemoryCache.m; sourceTree = "<group>"; };
-		D9EB04231BD6516900B3E0F5 /* YYThreadSafeDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYThreadSafeDictionary.h; sourceTree = "<group>"; };
-		D9EB04241BD6516900B3E0F5 /* YYThreadSafeDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYThreadSafeDictionary.m; sourceTree = "<group>"; };
-		D9EB042D1BD652E200B3E0F5 /* YYCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYCache.h; sourceTree = "<group>"; };
-		D9EB042E1BD652E200B3E0F5 /* YYCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYCache.m; sourceTree = "<group>"; };
-		D9EB042F1BD652E200B3E0F5 /* YYDiskCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYDiskCache.h; sourceTree = "<group>"; };
-		D9EB04301BD652E200B3E0F5 /* YYDiskCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYDiskCache.m; sourceTree = "<group>"; };
-		D9EB04311BD652E200B3E0F5 /* YYKVStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYKVStorage.h; sourceTree = "<group>"; };
-		D9EB04321BD652E200B3E0F5 /* YYKVStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYKVStorage.m; sourceTree = "<group>"; };
-		D9EB04331BD652E200B3E0F5 /* YYMemoryCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYMemoryCache.h; sourceTree = "<group>"; };
-		D9EB04341BD652E200B3E0F5 /* YYMemoryCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYMemoryCache.m; sourceTree = "<group>"; };
-		D9EB04391BD654A100B3E0F5 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
+		D967E0C61F0553F000791B80 /* sqlite3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sqlite3.c; sourceTree = "<group>"; };
+		D967E0C71F0553F000791B80 /* sqlite3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqlite3.h; sourceTree = "<group>"; };
+		D967E0C81F0553F000791B80 /* version.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = version.txt; sourceTree = "<group>"; };
+		D967E0CA1F0553F000791B80 /* YYThreadSafeDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYThreadSafeDictionary.h; sourceTree = "<group>"; };
+		D967E0CB1F0553F000791B80 /* YYThreadSafeDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYThreadSafeDictionary.m; sourceTree = "<group>"; };
+		D9C586421F054B5E00320F3B /* CacheBenchmark.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CacheBenchmark.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		D9C586451F054B5E00320F3B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+		D9C586461F054B5E00320F3B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+		D9C586481F054B5E00320F3B /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+		D9C586491F054B5E00320F3B /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+		D9C5864C1F054B5E00320F3B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+		D9C5864E1F054B5E00320F3B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		D9C586511F054B5E00320F3B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+		D9C586531F054B5E00320F3B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		D9C586541F054B5E00320F3B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+		D9D583ED1F0554DE00CBBB61 /* YYCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYCache.h; sourceTree = "<group>"; };
+		D9D583EE1F0554DE00CBBB61 /* YYCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYCache.m; sourceTree = "<group>"; };
+		D9D583EF1F0554DE00CBBB61 /* YYDiskCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYDiskCache.h; sourceTree = "<group>"; };
+		D9D583F01F0554DE00CBBB61 /* YYDiskCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYDiskCache.m; sourceTree = "<group>"; };
+		D9D583F11F0554DE00CBBB61 /* YYKVStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYKVStorage.h; sourceTree = "<group>"; };
+		D9D583F21F0554DE00CBBB61 /* YYKVStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYKVStorage.m; sourceTree = "<group>"; };
+		D9D583F31F0554DE00CBBB61 /* YYMemoryCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYMemoryCache.h; sourceTree = "<group>"; };
+		D9D583F41F0554DE00CBBB61 /* YYMemoryCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYMemoryCache.m; sourceTree = "<group>"; };
+		D9D5843E1F05579000CBBB61 /* PINCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PINCache.h; sourceTree = "<group>"; };
+		D9D5843F1F05579000CBBB61 /* PINCache.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PINCache.m; sourceTree = "<group>"; };
+		D9D584401F05579000CBBB61 /* PINCacheMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PINCacheMacros.h; sourceTree = "<group>"; };
+		D9D584411F05579000CBBB61 /* PINCacheObjectSubscripting.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PINCacheObjectSubscripting.h; sourceTree = "<group>"; };
+		D9D584421F05579000CBBB61 /* PINCaching.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PINCaching.h; sourceTree = "<group>"; };
+		D9D584431F05579000CBBB61 /* PINDiskCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PINDiskCache.h; sourceTree = "<group>"; };
+		D9D584441F05579000CBBB61 /* PINDiskCache.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PINDiskCache.m; sourceTree = "<group>"; };
+		D9D584451F05579000CBBB61 /* PINMemoryCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PINMemoryCache.h; sourceTree = "<group>"; };
+		D9D584461F05579000CBBB61 /* PINMemoryCache.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PINMemoryCache.m; sourceTree = "<group>"; };
+		D9D584491F05579000CBBB61 /* PINOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PINOperation.h; sourceTree = "<group>"; };
+		D9D5844A1F05579000CBBB61 /* PINOperationGroup.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PINOperationGroup.h; sourceTree = "<group>"; };
+		D9D5844B1F05579000CBBB61 /* PINOperationGroup.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PINOperationGroup.m; sourceTree = "<group>"; };
+		D9D5844C1F05579000CBBB61 /* PINOperationMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PINOperationMacros.h; sourceTree = "<group>"; };
+		D9D5844D1F05579000CBBB61 /* PINOperationQueue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PINOperationQueue.h; sourceTree = "<group>"; };
+		D9D5844E1F05579000CBBB61 /* PINOperationQueue.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PINOperationQueue.m; sourceTree = "<group>"; };
+		D9D5844F1F05579000CBBB61 /* PINOperationTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PINOperationTypes.h; sourceTree = "<group>"; };
+		D9F7E2141F36D7D4003F5035 /* Benchmark.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Benchmark.h; path = CacheBenchmark/Benchmark.h; sourceTree = "<group>"; };
+		D9F7E2151F36D7D4003F5035 /* Benchmark.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Benchmark.m; path = CacheBenchmark/Benchmark.m; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
-		D9EB03321BD64CB600B3E0F5 /* Frameworks */ = {
+		D9C5863F1F054B5E00320F3B /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
@@ -83,139 +83,128 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
-		D91525C51BD6754500EE6881 /* Vendor */ = {
+		D967E09F1F0553F000791B80 /* Vendor */ = {
 			isa = PBXGroup;
 			children = (
-				D99B971E1BD78BD1001477E6 /* SQLite */,
-				D9EB042C1BD652E200B3E0F5 /* YYCache */,
-				D9EB04121BD6516900B3E0F5 /* PINCache */,
-				D9EB041A1BD6516900B3E0F5 /* TMCache */,
-				D9EB04221BD6516900B3E0F5 /* YYThreadSafeDictionary */,
+				D967E0C81F0553F000791B80 /* version.txt */,
+				D9D5843D1F05579000CBBB61 /* PINCache */,
+				D9D583EC1F0554DE00CBBB61 /* YYCache */,
+				D967E0C51F0553F000791B80 /* SQLite */,
+				D967E0C91F0553F000791B80 /* YYThreadSafeDictionary */,
 			);
-			name = Vendor;
+			path = Vendor;
 			sourceTree = "<group>";
 		};
-		D99B971E1BD78BD1001477E6 /* SQLite */ = {
+		D967E0C51F0553F000791B80 /* SQLite */ = {
 			isa = PBXGroup;
 			children = (
-				D99B971F1BD78BD1001477E6 /* sqlite3.c */,
-				D99B97201BD78BD1001477E6 /* sqlite3.h */,
+				D967E0C61F0553F000791B80 /* sqlite3.c */,
+				D967E0C71F0553F000791B80 /* sqlite3.h */,
 			);
-			name = SQLite;
-			path = Vendor/SQLite;
+			path = SQLite;
 			sourceTree = "<group>";
 		};
-		D9EB032C1BD64CB600B3E0F5 = {
+		D967E0C91F0553F000791B80 /* YYThreadSafeDictionary */ = {
 			isa = PBXGroup;
 			children = (
-				D91525C51BD6754500EE6881 /* Vendor */,
-				D91525C61BD6756400EE6881 /* Benchmark.h */,
-				D91525C71BD6756400EE6881 /* Benchmark.m */,
-				D99B97221BD79059001477E6 /* Result.txt */,
-				D9EB03371BD64CB600B3E0F5 /* CacheBenchmark */,
-				D9EB03361BD64CB600B3E0F5 /* Products */,
+				D967E0CA1F0553F000791B80 /* YYThreadSafeDictionary.h */,
+				D967E0CB1F0553F000791B80 /* YYThreadSafeDictionary.m */,
 			);
+			path = YYThreadSafeDictionary;
 			sourceTree = "<group>";
 		};
-		D9EB03361BD64CB600B3E0F5 /* Products */ = {
+		D9C586391F054B5E00320F3B = {
 			isa = PBXGroup;
 			children = (
-				D9EB03351BD64CB600B3E0F5 /* CacheBenchmark.app */,
+				D9F7E2141F36D7D4003F5035 /* Benchmark.h */,
+				D9F7E2151F36D7D4003F5035 /* Benchmark.m */,
+				D967E09F1F0553F000791B80 /* Vendor */,
+				D9C586441F054B5E00320F3B /* CacheBenchmark */,
+				D9C586431F054B5E00320F3B /* Products */,
 			);
-			name = Products;
 			sourceTree = "<group>";
 		};
-		D9EB03371BD64CB600B3E0F5 /* CacheBenchmark */ = {
+		D9C586431F054B5E00320F3B /* Products */ = {
 			isa = PBXGroup;
 			children = (
-				D9EB033B1BD64CB600B3E0F5 /* AppDelegate.h */,
-				D9EB033C1BD64CB600B3E0F5 /* AppDelegate.m */,
-				D9EB033E1BD64CB600B3E0F5 /* ViewController.h */,
-				D9EB033F1BD64CB600B3E0F5 /* ViewController.m */,
-				D9EB03381BD64CB600B3E0F5 /* Supporting Files */,
+				D9C586421F054B5E00320F3B /* CacheBenchmark.app */,
 			);
-			path = CacheBenchmark;
+			name = Products;
 			sourceTree = "<group>";
 		};
-		D9EB03381BD64CB600B3E0F5 /* Supporting Files */ = {
+		D9C586441F054B5E00320F3B /* CacheBenchmark */ = {
 			isa = PBXGroup;
 			children = (
-				D9EB04391BD654A100B3E0F5 /* libsqlite3.tbd */,
-				D9EB03411BD64CB600B3E0F5 /* Main.storyboard */,
-				D9EB03441BD64CB600B3E0F5 /* Assets.xcassets */,
-				D9EB03461BD64CB600B3E0F5 /* LaunchScreen.storyboard */,
-				D9EB03491BD64CB600B3E0F5 /* Info.plist */,
-				D9EB03391BD64CB600B3E0F5 /* main.m */,
+				D9C586451F054B5E00320F3B /* AppDelegate.h */,
+				D9C586461F054B5E00320F3B /* AppDelegate.m */,
+				D9C586481F054B5E00320F3B /* ViewController.h */,
+				D9C586491F054B5E00320F3B /* ViewController.m */,
+				D9C5864B1F054B5E00320F3B /* Main.storyboard */,
+				D9C5864E1F054B5E00320F3B /* Assets.xcassets */,
+				D9C586501F054B5E00320F3B /* LaunchScreen.storyboard */,
+				D9C586531F054B5E00320F3B /* Info.plist */,
+				D9C586541F054B5E00320F3B /* main.m */,
 			);
-			name = "Supporting Files";
+			path = CacheBenchmark;
 			sourceTree = "<group>";
 		};
-		D9EB04121BD6516900B3E0F5 /* PINCache */ = {
-			isa = PBXGroup;
-			children = (
-				D9EB04131BD6516900B3E0F5 /* Nullability.h */,
-				D9EB04141BD6516900B3E0F5 /* PINCache.h */,
-				D9EB04151BD6516900B3E0F5 /* PINCache.m */,
-				D9EB04161BD6516900B3E0F5 /* PINDiskCache.h */,
-				D9EB04171BD6516900B3E0F5 /* PINDiskCache.m */,
-				D9EB04181BD6516900B3E0F5 /* PINMemoryCache.h */,
-				D9EB04191BD6516900B3E0F5 /* PINMemoryCache.m */,
-			);
-			name = PINCache;
-			path = Vendor/PINCache;
-			sourceTree = SOURCE_ROOT;
-		};
-		D9EB041A1BD6516900B3E0F5 /* TMCache */ = {
+		D9D583EC1F0554DE00CBBB61 /* YYCache */ = {
 			isa = PBXGroup;
 			children = (
-				D9EB041B1BD6516900B3E0F5 /* TMCache.h */,
-				D9EB041C1BD6516900B3E0F5 /* TMCache.m */,
-				D9EB041D1BD6516900B3E0F5 /* TMCacheBackgroundTaskManager.h */,
-				D9EB041E1BD6516900B3E0F5 /* TMDiskCache.h */,
-				D9EB041F1BD6516900B3E0F5 /* TMDiskCache.m */,
-				D9EB04201BD6516900B3E0F5 /* TMMemoryCache.h */,
-				D9EB04211BD6516900B3E0F5 /* TMMemoryCache.m */,
+				D9D583ED1F0554DE00CBBB61 /* YYCache.h */,
+				D9D583EE1F0554DE00CBBB61 /* YYCache.m */,
+				D9D583EF1F0554DE00CBBB61 /* YYDiskCache.h */,
+				D9D583F01F0554DE00CBBB61 /* YYDiskCache.m */,
+				D9D583F11F0554DE00CBBB61 /* YYKVStorage.h */,
+				D9D583F21F0554DE00CBBB61 /* YYKVStorage.m */,
+				D9D583F31F0554DE00CBBB61 /* YYMemoryCache.h */,
+				D9D583F41F0554DE00CBBB61 /* YYMemoryCache.m */,
 			);
-			name = TMCache;
-			path = Vendor/TMCache;
-			sourceTree = SOURCE_ROOT;
+			name = YYCache;
+			path = ../../YYCache;
+			sourceTree = "<group>";
 		};
-		D9EB04221BD6516900B3E0F5 /* YYThreadSafeDictionary */ = {
+		D9D5843D1F05579000CBBB61 /* PINCache */ = {
 			isa = PBXGroup;
 			children = (
-				D9EB04231BD6516900B3E0F5 /* YYThreadSafeDictionary.h */,
-				D9EB04241BD6516900B3E0F5 /* YYThreadSafeDictionary.m */,
+				D9D5843E1F05579000CBBB61 /* PINCache.h */,
+				D9D5843F1F05579000CBBB61 /* PINCache.m */,
+				D9D584401F05579000CBBB61 /* PINCacheMacros.h */,
+				D9D584411F05579000CBBB61 /* PINCacheObjectSubscripting.h */,
+				D9D584421F05579000CBBB61 /* PINCaching.h */,
+				D9D584431F05579000CBBB61 /* PINDiskCache.h */,
+				D9D584441F05579000CBBB61 /* PINDiskCache.m */,
+				D9D584451F05579000CBBB61 /* PINMemoryCache.h */,
+				D9D584461F05579000CBBB61 /* PINMemoryCache.m */,
+				D9D584471F05579000CBBB61 /* PINOperation */,
 			);
-			name = YYThreadSafeDictionary;
-			path = Vendor/YYThreadSafeDictionary;
-			sourceTree = SOURCE_ROOT;
+			path = PINCache;
+			sourceTree = "<group>";
 		};
-		D9EB042C1BD652E200B3E0F5 /* YYCache */ = {
+		D9D584471F05579000CBBB61 /* PINOperation */ = {
 			isa = PBXGroup;
 			children = (
-				D9EB042D1BD652E200B3E0F5 /* YYCache.h */,
-				D9EB042E1BD652E200B3E0F5 /* YYCache.m */,
-				D9EB042F1BD652E200B3E0F5 /* YYDiskCache.h */,
-				D9EB04301BD652E200B3E0F5 /* YYDiskCache.m */,
-				D9EB04311BD652E200B3E0F5 /* YYKVStorage.h */,
-				D9EB04321BD652E200B3E0F5 /* YYKVStorage.m */,
-				D9EB04331BD652E200B3E0F5 /* YYMemoryCache.h */,
-				D9EB04341BD652E200B3E0F5 /* YYMemoryCache.m */,
+				D9D584491F05579000CBBB61 /* PINOperation.h */,
+				D9D5844A1F05579000CBBB61 /* PINOperationGroup.h */,
+				D9D5844B1F05579000CBBB61 /* PINOperationGroup.m */,
+				D9D5844C1F05579000CBBB61 /* PINOperationMacros.h */,
+				D9D5844D1F05579000CBBB61 /* PINOperationQueue.h */,
+				D9D5844E1F05579000CBBB61 /* PINOperationQueue.m */,
+				D9D5844F1F05579000CBBB61 /* PINOperationTypes.h */,
 			);
-			name = YYCache;
-			path = ../YYCache;
+			path = PINOperation;
 			sourceTree = "<group>";
 		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
-		D9EB03341BD64CB600B3E0F5 /* CacheBenchmark */ = {
+		D9C586411F054B5E00320F3B /* CacheBenchmark */ = {
 			isa = PBXNativeTarget;
-			buildConfigurationList = D9EB034C1BD64CB600B3E0F5 /* Build configuration list for PBXNativeTarget "CacheBenchmark" */;
+			buildConfigurationList = D9C586581F054B5E00320F3B /* Build configuration list for PBXNativeTarget "CacheBenchmark" */;
 			buildPhases = (
-				D9EB03311BD64CB600B3E0F5 /* Sources */,
-				D9EB03321BD64CB600B3E0F5 /* Frameworks */,
-				D9EB03331BD64CB600B3E0F5 /* Resources */,
+				D9C5863E1F054B5E00320F3B /* Sources */,
+				D9C5863F1F054B5E00320F3B /* Frameworks */,
+				D9C586401F054B5E00320F3B /* Resources */,
 			);
 			buildRules = (
 			);
@@ -223,94 +212,93 @@
 			);
 			name = CacheBenchmark;
 			productName = CacheBenchmark;
-			productReference = D9EB03351BD64CB600B3E0F5 /* CacheBenchmark.app */;
+			productReference = D9C586421F054B5E00320F3B /* CacheBenchmark.app */;
 			productType = "com.apple.product-type.application";
 		};
 /* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
-		D9EB032D1BD64CB600B3E0F5 /* Project object */ = {
+		D9C5863A1F054B5E00320F3B /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0700;
+				LastUpgradeCheck = 0900;
 				ORGANIZATIONNAME = ibireme;
 				TargetAttributes = {
-					D9EB03341BD64CB600B3E0F5 = {
-						CreatedOnToolsVersion = 7.0;
+					D9C586411F054B5E00320F3B = {
+						CreatedOnToolsVersion = 9.0;
 					};
 				};
 			};
-			buildConfigurationList = D9EB03301BD64CB600B3E0F5 /* Build configuration list for PBXProject "CacheBenchmark" */;
-			compatibilityVersion = "Xcode 3.2";
-			developmentRegion = English;
+			buildConfigurationList = D9C5863D1F054B5E00320F3B /* Build configuration list for PBXProject "CacheBenchmark" */;
+			compatibilityVersion = "Xcode 8.0";
+			developmentRegion = en;
 			hasScannedForEncodings = 0;
 			knownRegions = (
 				en,
 				Base,
 			);
-			mainGroup = D9EB032C1BD64CB600B3E0F5;
-			productRefGroup = D9EB03361BD64CB600B3E0F5 /* Products */;
+			mainGroup = D9C586391F054B5E00320F3B;
+			productRefGroup = D9C586431F054B5E00320F3B /* Products */;
 			projectDirPath = "";
 			projectRoot = "";
 			targets = (
-				D9EB03341BD64CB600B3E0F5 /* CacheBenchmark */,
+				D9C586411F054B5E00320F3B /* CacheBenchmark */,
 			);
 		};
 /* End PBXProject section */
 
 /* Begin PBXResourcesBuildPhase section */
-		D9EB03331BD64CB600B3E0F5 /* Resources */ = {
+		D9C586401F054B5E00320F3B /* Resources */ = {
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				D9EB03481BD64CB600B3E0F5 /* LaunchScreen.storyboard in Resources */,
-				D9EB03451BD64CB600B3E0F5 /* Assets.xcassets in Resources */,
-				D9EB03431BD64CB600B3E0F5 /* Main.storyboard in Resources */,
-				D99B97231BD79059001477E6 /* Result.txt in Resources */,
+				D9C586521F054B5E00320F3B /* LaunchScreen.storyboard in Resources */,
+				D9C5864F1F054B5E00320F3B /* Assets.xcassets in Resources */,
+				D9C5864D1F054B5E00320F3B /* Main.storyboard in Resources */,
+				D967E0DD1F0553F000791B80 /* version.txt in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
-		D9EB03311BD64CB600B3E0F5 /* Sources */ = {
+		D9C5863E1F054B5E00320F3B /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				D99B97251BD7945B001477E6 /* sqlite3.c in Sources */,
-				D91525C81BD6756400EE6881 /* Benchmark.m in Sources */,
-				D9EB042B1BD6516900B3E0F5 /* YYThreadSafeDictionary.m in Sources */,
-				D9EB04291BD6516900B3E0F5 /* TMDiskCache.m in Sources */,
-				D9EB04351BD652E200B3E0F5 /* YYCache.m in Sources */,
-				D9EB042A1BD6516900B3E0F5 /* TMMemoryCache.m in Sources */,
-				D9EB04251BD6516900B3E0F5 /* PINCache.m in Sources */,
-				D9EB04381BD652E200B3E0F5 /* YYMemoryCache.m in Sources */,
-				D9EB04271BD6516900B3E0F5 /* PINMemoryCache.m in Sources */,
-				D9EB03401BD64CB600B3E0F5 /* ViewController.m in Sources */,
-				D9EB04281BD6516900B3E0F5 /* TMCache.m in Sources */,
-				D9EB04261BD6516900B3E0F5 /* PINDiskCache.m in Sources */,
-				D9EB04361BD652E200B3E0F5 /* YYDiskCache.m in Sources */,
-				D9EB033D1BD64CB600B3E0F5 /* AppDelegate.m in Sources */,
-				D9EB04371BD652E200B3E0F5 /* YYKVStorage.m in Sources */,
-				D9EB033A1BD64CB600B3E0F5 /* main.m in Sources */,
+				D9F7E2161F36D7D4003F5035 /* Benchmark.m in Sources */,
+				D9D584501F05579A00CBBB61 /* PINCache.m in Sources */,
+				D9D584511F05579A00CBBB61 /* PINDiskCache.m in Sources */,
+				D9D584521F05579A00CBBB61 /* PINMemoryCache.m in Sources */,
+				D9D584531F05579A00CBBB61 /* PINOperationGroup.m in Sources */,
+				D9D584541F05579A00CBBB61 /* PINOperationQueue.m in Sources */,
+				D9D583F81F0554DE00CBBB61 /* YYMemoryCache.m in Sources */,
+				D9C5864A1F054B5E00320F3B /* ViewController.m in Sources */,
+				D9C586551F054B5E00320F3B /* main.m in Sources */,
+				D9D583F71F0554DE00CBBB61 /* YYKVStorage.m in Sources */,
+				D9D583F61F0554DE00CBBB61 /* YYDiskCache.m in Sources */,
+				D9C586471F054B5E00320F3B /* AppDelegate.m in Sources */,
+				D967E0DE1F0553F000791B80 /* YYThreadSafeDictionary.m in Sources */,
+				D9D583F51F0554DE00CBBB61 /* YYCache.m in Sources */,
+				D967E0DC1F0553F000791B80 /* sqlite3.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXVariantGroup section */
-		D9EB03411BD64CB600B3E0F5 /* Main.storyboard */ = {
+		D9C5864B1F054B5E00320F3B /* Main.storyboard */ = {
 			isa = PBXVariantGroup;
 			children = (
-				D9EB03421BD64CB600B3E0F5 /* Base */,
+				D9C5864C1F054B5E00320F3B /* Base */,
 			);
 			name = Main.storyboard;
 			sourceTree = "<group>";
 		};
-		D9EB03461BD64CB600B3E0F5 /* LaunchScreen.storyboard */ = {
+		D9C586501F054B5E00320F3B /* LaunchScreen.storyboard */ = {
 			isa = PBXVariantGroup;
 			children = (
-				D9EB03471BD64CB600B3E0F5 /* Base */,
+				D9C586511F054B5E00320F3B /* Base */,
 			);
 			name = LaunchScreen.storyboard;
 			sourceTree = "<group>";
@@ -318,29 +306,41 @@
 /* End PBXVariantGroup section */
 
 /* Begin XCBuildConfiguration section */
-		D9EB034A1BD64CB600B3E0F5 /* Debug */ = {
+		D9C586561F054B5E00320F3B /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 				CLANG_WARN_EMPTY_BODY = YES;
 				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
 				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
 				COPY_PHASE_STRIP = NO;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_DYNAMIC_NO_PIC = NO;
 				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_OPTIMIZATION_LEVEL = 0;
@@ -354,36 +354,48 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = iphoneos;
 			};
 			name = Debug;
 		};
-		D9EB034B1BD64CB600B3E0F5 /* Release */ = {
+		D9C586571F054B5E00320F3B /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 				CLANG_WARN_EMPTY_BODY = YES;
 				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
 				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
 				COPY_PHASE_STRIP = NO;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				ENABLE_NS_ASSERTIONS = NO;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
@@ -391,59 +403,65 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				SDKROOT = iphoneos;
 				VALIDATE_PRODUCT = YES;
 			};
 			name = Release;
 		};
-		D9EB034D1BD64CB600B3E0F5 /* Debug */ = {
+		D9C586591F054B5E00320F3B /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				DEVELOPMENT_TEAM = "";
+				HEADER_SEARCH_PATHS = "\"$(SRCROOT)\"/**";
 				INFOPLIST_FILE = CacheBenchmark/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = com.ibireme.CacheBenchmark;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				TARGETED_DEVICE_FAMILY = "1,2";
 			};
 			name = Debug;
 		};
-		D9EB034E1BD64CB600B3E0F5 /* Release */ = {
+		D9C5865A1F054B5E00320F3B /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				DEVELOPMENT_TEAM = "";
+				HEADER_SEARCH_PATHS = "\"$(SRCROOT)\"/**";
 				INFOPLIST_FILE = CacheBenchmark/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = com.ibireme.CacheBenchmark;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				TARGETED_DEVICE_FAMILY = "1,2";
 			};
 			name = Release;
 		};
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
-		D9EB03301BD64CB600B3E0F5 /* Build configuration list for PBXProject "CacheBenchmark" */ = {
+		D9C5863D1F054B5E00320F3B /* Build configuration list for PBXProject "CacheBenchmark" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
-				D9EB034A1BD64CB600B3E0F5 /* Debug */,
-				D9EB034B1BD64CB600B3E0F5 /* Release */,
+				D9C586561F054B5E00320F3B /* Debug */,
+				D9C586571F054B5E00320F3B /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		D9EB034C1BD64CB600B3E0F5 /* Build configuration list for PBXNativeTarget "CacheBenchmark" */ = {
+		D9C586581F054B5E00320F3B /* Build configuration list for PBXNativeTarget "CacheBenchmark" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
-				D9EB034D1BD64CB600B3E0F5 /* Debug */,
-				D9EB034E1BD64CB600B3E0F5 /* Release */,
+				D9C586591F054B5E00320F3B /* Debug */,
+				D9C5865A1F054B5E00320F3B /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
 /* End XCConfigurationList section */
 	};
-	rootObject = D9EB032D1BD64CB600B3E0F5 /* Project object */;
+	rootObject = D9C5863A1F054B5E00320F3B /* Project object */;
 }

+ 2 - 2
Benchmark/CacheBenchmark/AppDelegate.h

@@ -2,8 +2,8 @@
 //  AppDelegate.h
 //  CacheBenchmark
 //
-//  Created by ibireme on 15/10/20.
-//  Copyright (C) 2015 ibireme. All rights reserved.
+//  Created by ibireme on 2017/6/29.
+//  Copyright © 2017年 ibireme. All rights reserved.
 //
 
 #import <UIKit/UIKit.h>

+ 10 - 4
Benchmark/CacheBenchmark/AppDelegate.m

@@ -2,8 +2,8 @@
 //  AppDelegate.m
 //  CacheBenchmark
 //
-//  Created by ibireme on 15/10/20.
-//  Copyright (C) 2015 ibireme. All rights reserved.
+//  Created by ibireme on 2017/6/29.
+//  Copyright © 2017年 ibireme. All rights reserved.
 //
 
 #import "AppDelegate.h"
@@ -20,26 +20,32 @@
     return YES;
 }
 
+
 - (void)applicationWillResignActive:(UIApplication *)application {
     // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
-    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
+    // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
 }
 
+
 - (void)applicationDidEnterBackground:(UIApplication *)application {
     // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
     // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
 }
 
+
 - (void)applicationWillEnterForeground:(UIApplication *)application {
-    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
+    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
 }
 
+
 - (void)applicationDidBecomeActive:(UIApplication *)application {
     // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
 }
 
+
 - (void)applicationWillTerminate:(UIApplication *)application {
     // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
 }
 
+
 @end

+ 55 - 0
Benchmark/CacheBenchmark/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -1,5 +1,15 @@
 {
   "images" : [
+    {
+      "idiom" : "iphone",
+      "size" : "20x20",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "20x20",
+      "scale" : "3x"
+    },
     {
       "idiom" : "iphone",
       "size" : "29x29",
@@ -29,6 +39,51 @@
       "idiom" : "iphone",
       "size" : "60x60",
       "scale" : "3x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "20x20",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "20x20",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "29x29",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "29x29",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "40x40",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "40x40",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "76x76",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "76x76",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "83.5x83.5",
+      "scale" : "2x"
     }
   ],
   "info" : {

+ 5 - 6
Benchmark/CacheBenchmark/Base.lproj/LaunchScreen.storyboard

@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8191" systemVersion="15A284" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
     <dependencies>
-        <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11106"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <scenes>
         <!--View Controller-->
@@ -14,10 +14,9 @@
                         <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
                     </layoutGuides>
                     <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
-                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <animations/>
-                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                     </view>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>

+ 6 - 25
Benchmark/CacheBenchmark/Base.lproj/Main.storyboard

@@ -1,45 +1,26 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8191" systemVersion="15A284" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
     <dependencies>
-        <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11106"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <scenes>
         <!--View Controller-->
         <scene sceneID="tne-QT-ifu">
             <objects>
-                <viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
+                <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
                     <layoutGuides>
                         <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
                         <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
                     </layoutGuides>
                     <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
-                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <subviews>
-                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="See logs in Xcode" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TN1-om-dfL">
-                                <rect key="frame" x="222" y="284" width="156" height="31"/>
-                                <animations/>
-                                <constraints>
-                                    <constraint firstAttribute="width" constant="156" id="o70-4J-FUb"/>
-                                    <constraint firstAttribute="height" constant="31" id="vPB-Zk-7PS"/>
-                                </constraints>
-                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
-                                <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
-                                <nil key="highlightedColor"/>
-                            </label>
-                        </subviews>
-                        <animations/>
-                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
-                        <constraints>
-                            <constraint firstItem="TN1-om-dfL" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="TWf-8l-DIP"/>
-                            <constraint firstItem="TN1-om-dfL" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="vPS-7U-Kzf"/>
-                        </constraints>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                     </view>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
             </objects>
-            <point key="canvasLocation" x="305" y="429"/>
         </scene>
     </scenes>
 </document>

+ 3 - 130
Benchmark/CacheBenchmark/Benchmark.m

@@ -9,7 +9,6 @@
 #import "Benchmark.h"
 #import "YYCache.h"
 #import "PINCache.h"
-#import "TMCache.h"
 #import "YYThreadSafeDictionary.h"
 #import <QuartzCore/QuartzCore.h>
 
@@ -22,9 +21,9 @@
     
     // You should benchmark data writing first.
     // Before benchmark data reading, you should kill the app to avoid disk-in-memory cache.
-#define WRITE 1
-#define READ 1
-#define RANDOMLY 1
+#define WRITE    false
+#define READ     true
+#define RANDOMLY true
     
 #if WRITE
     
@@ -85,9 +84,7 @@
     YYThreadSafeDictionary *nsDictLock = [YYThreadSafeDictionary new];
     NSCache *ns = [NSCache new];
     PINMemoryCache *pin = [PINMemoryCache new];
-    TMMemoryCache *tm = [TMMemoryCache new];
     YYMemoryCache *yy = [YYMemoryCache new];
-    yy.releaseOnMainThread = YES;
     
     NSMutableArray *keys = [NSMutableArray new];
     NSMutableArray *values = [NSMutableArray new];
@@ -163,17 +160,6 @@
     printf("NSCache:        %8.2f\n", time * 1000);
     
     
-    begin = CACurrentMediaTime();
-    @autoreleasepool {
-        for (int i = 0; i < count / 100; i++) {
-            [tm setObject:values[i] forKey:keys[i]]; // too slow...
-        }
-    }
-    end = CACurrentMediaTime();
-    time = end - begin;
-    printf("TMMemoryCache:  %8.2f\n", time * 1000 * 100);
-    
-    
     
     
     
@@ -241,17 +227,6 @@
     printf("NSCache:        %8.2f\n", time * 1000);
     
     
-    [tm removeAllObjects];
-    begin = CACurrentMediaTime();
-    @autoreleasepool {
-        for (int i = 0; i < count / 100; i++) {
-            [tm setObject:values[i] forKey:keys[i]]; // too slow...
-        }
-    }
-    end = CACurrentMediaTime();
-    time = end - begin;
-    printf("TMMemoryCache:  %8.2f\n", time * 1000 * 100);
-    
     
     
     
@@ -315,16 +290,6 @@
     printf("NSCache:        %8.2f\n", time * 1000);
     
     
-    begin = CACurrentMediaTime();
-    @autoreleasepool {
-        for (int i = 0; i < count / 100; i++) {
-            [tm objectForKey:keys[i]];
-        }
-    }
-    end = CACurrentMediaTime();
-    time = end - begin;
-    printf("TMMemoryCache:  %8.2f\n", time * 1000 * 100);
-    
     
     
     printf("\n===========================\n");
@@ -389,17 +354,6 @@
     printf("NSCache:        %8.2f\n", time * 1000);
     
     
-    begin = CACurrentMediaTime();
-    @autoreleasepool {
-        for (int i = 0; i < count / 100; i++) {
-            [tm objectForKey:keys[i]];
-        }
-    }
-    end = CACurrentMediaTime();
-    time = end - begin;
-    printf("TMMemoryCache:  %8.2f\n", time * 1000 * 100);
- 
-    
     
     
     
@@ -470,15 +424,6 @@
     printf("NSCache:        %8.2f\n", time * 1000);
     
     
-    begin = CACurrentMediaTime();
-    @autoreleasepool {
-        for (int i = 0; i < count / 100; i++) {
-            [tm objectForKey:keys[i]];
-        }
-    }
-    end = CACurrentMediaTime();
-    time = end - begin;
-    printf("TMMemoryCache:  %8.2f\n", time * 1000 * 100);
 }
 
 
@@ -503,7 +448,6 @@
     YYKVStorage *yykvSQLite = [[YYKVStorage alloc] initWithPath:[basePath stringByAppendingPathComponent:@"yykvSQLite"] type:YYKVStorageTypeSQLite];
     YYDiskCache *yy = [[YYDiskCache alloc] initWithPath:[basePath stringByAppendingPathComponent:@"yy"]];
     PINDiskCache *pin = [[PINDiskCache alloc] initWithName:@"pin" rootPath:[basePath stringByAppendingPathComponent:@"pin"]];
-    TMDiskCache *tm = [[TMDiskCache alloc] initWithName:@"tm" rootPath:[basePath stringByAppendingPathComponent:@"tm"]];
     
     int count = 1000;
     NSMutableArray *keys = [NSMutableArray new];
@@ -563,16 +507,6 @@
     time = end - begin;
     printf("PINDiskCache: %8.2f\n", time * 1000);
     
-    begin = CACurrentMediaTime();
-    @autoreleasepool {
-        for (int i = 0; i < count; i++) {
-            [tm setObject:values[i] forKey:keys[i]];
-        }
-    }
-    end = CACurrentMediaTime();
-    time = end - begin;
-    printf("TMDiskCache:  %8.2f\n", time * 1000);
-    
 }
 
 
@@ -586,7 +520,6 @@
     yy.customArchiveBlock = ^(id object) {return object;};
     yy.customUnarchiveBlock = ^(NSData *object) {return object;};
     PINDiskCache *pin = [[PINDiskCache alloc] initWithName:@"pin" rootPath:[basePath stringByAppendingPathComponent:@"pin"]];
-    TMDiskCache *tm = [[TMDiskCache alloc] initWithName:@"tm" rootPath:[basePath stringByAppendingPathComponent:@"tm"]];
     
     int count = 1000;
     NSMutableArray *keys = [NSMutableArray new];
@@ -648,16 +581,6 @@
     time = end - begin;
     printf("PINDiskCache: %8.2f\n", time * 1000);
     
-    begin = CACurrentMediaTime();
-    @autoreleasepool {
-        for (int i = 0; i < count; i++) {
-            [tm setObject:dataValue forKey:keys[i]];
-        }
-    }
-    end = CACurrentMediaTime();
-    time = end - begin;
-    printf("TMDiskCache:  %8.2f\n", time * 1000);
-    
 }
 
 
@@ -669,7 +592,6 @@
     YYKVStorage *yykvSQLite = [[YYKVStorage alloc] initWithPath:[basePath stringByAppendingPathComponent:@"yykvSQLite"] type:YYKVStorageTypeSQLite];
     YYDiskCache *yy = [[YYDiskCache alloc] initWithPath:[basePath stringByAppendingPathComponent:@"yy"]];
     PINDiskCache *pin = [[PINDiskCache alloc] initWithName:@"pin" rootPath:[basePath stringByAppendingPathComponent:@"pin"]];
-    TMDiskCache *tm = [[TMDiskCache alloc] initWithName:@"tm" rootPath:[basePath stringByAppendingPathComponent:@"tm"]];
     
     int count = 1000;
     NSMutableArray *keys = [NSMutableArray new];
@@ -737,17 +659,6 @@
     time = end - begin;
     printf("PINDiskCache: %8.2f\n", time * 1000);
     
-    begin = CACurrentMediaTime();
-    @autoreleasepool {
-        for (int i = 0; i < count; i++) {
-            NSNumber *value = (id)[tm objectForKey:keys[i]];
-            if (!value) printf("error!");
-        }
-    }
-    end = CACurrentMediaTime();
-    time = end - begin;
-    printf("TMDiskCache:  %8.2f\n", time * 1000);
-    
 }
 
 
@@ -761,8 +672,6 @@
     yy.customArchiveBlock = ^(id object) {return object;};
     yy.customUnarchiveBlock = ^(NSData *object) {return object;};
     PINDiskCache *pin = [[PINDiskCache alloc] initWithName:@"pin" rootPath:[basePath stringByAppendingPathComponent:@"pin"]];
-    TMDiskCache *tm = [[TMDiskCache alloc] initWithName:@"tm" rootPath:[basePath stringByAppendingPathComponent:@"tm"]];
-    
     
     int count = 1000;
     NSMutableArray *keys = [NSMutableArray new];
@@ -830,17 +739,6 @@
     time = end - begin;
     printf("PINDiskCache: %8.2f\n", time * 1000);
     
-    begin = CACurrentMediaTime();
-    @autoreleasepool {
-        for (int i = 0; i < count; i++) {
-            NSData *value = (id)[tm objectForKey:keys[i]];
-            if (!value) printf("error!");
-        }
-    }
-    end = CACurrentMediaTime();
-    time = end - begin;
-    printf("TMDiskCache:  %8.2f\n", time * 1000);
-    
 }
 
 
@@ -854,7 +752,6 @@
     YYKVStorage *yykvSQLite = [[YYKVStorage alloc] initWithPath:[basePath stringByAppendingPathComponent:@"yykvSQLite"] type:YYKVStorageTypeSQLite];
     YYDiskCache *yy = [[YYDiskCache alloc] initWithPath:[basePath stringByAppendingPathComponent:@"yy"]];
     PINDiskCache *pin = [[PINDiskCache alloc] initWithName:@"pin" rootPath:[basePath stringByAppendingPathComponent:@"pin"]];
-    TMDiskCache *tm = [[TMDiskCache alloc] initWithName:@"tm" rootPath:[basePath stringByAppendingPathComponent:@"tm"]];
     
     int count = 1000;
     NSMutableArray *keys = [NSMutableArray new];
@@ -915,17 +812,6 @@
     time = end - begin;
     printf("PINDiskCache: %8.2f\n", time * 1000);
     
-    begin = CACurrentMediaTime();
-    @autoreleasepool {
-        for (int i = 0; i < count; i++) {
-            NSNumber *value = (id)[tm objectForKey:keys[i]];
-            if (value) printf("error!");
-        }
-    }
-    end = CACurrentMediaTime();
-    time = end - begin;
-    printf("TMDiskCache:  %8.2f\n", time * 1000);
-    
 }
 
 
@@ -939,8 +825,6 @@
     yy.customArchiveBlock = ^(id object) {return object;};
     yy.customUnarchiveBlock = ^(NSData *object) {return object;};
     PINDiskCache *pin = [[PINDiskCache alloc] initWithName:@"pin" rootPath:[basePath stringByAppendingPathComponent:@"pin"]];
-    TMDiskCache *tm = [[TMDiskCache alloc] initWithName:@"tm" rootPath:[basePath stringByAppendingPathComponent:@"tm"]];
-    
     
     int count = 1000;
     NSMutableArray *keys = [NSMutableArray new];
@@ -1001,17 +885,6 @@
     time = end - begin;
     printf("PINDiskCache: %8.2f\n", time * 1000);
     
-    begin = CACurrentMediaTime();
-    @autoreleasepool {
-        for (int i = 0; i < count; i++) {
-            NSData *value = (id)[tm objectForKey:keys[i]];
-            if (value) printf("error!");
-        }
-    }
-    end = CACurrentMediaTime();
-    time = end - begin;
-    printf("TMDiskCache:  %8.2f\n", time * 1000);
-    
 }
 
 

+ 10 - 3
Benchmark/CacheBenchmark/Info.plist

@@ -3,7 +3,7 @@
 <plist version="1.0">
 <dict>
 	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
 	<key>CFBundleExecutable</key>
 	<string>$(EXECUTABLE_NAME)</string>
 	<key>CFBundleIdentifier</key>
@@ -16,8 +16,6 @@
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
 	<string>1.0</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
 	<key>CFBundleVersion</key>
 	<string>1</string>
 	<key>LSRequiresIPhoneOS</key>
@@ -33,6 +31,15 @@
 	<key>UISupportedInterfaceOrientations</key>
 	<array>
 		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
 	</array>
 </dict>
 </plist>

+ 2 - 2
Benchmark/CacheBenchmark/ViewController.h

@@ -2,8 +2,8 @@
 //  ViewController.h
 //  CacheBenchmark
 //
-//  Created by ibireme on 15/10/20.
-//  Copyright (C) 2015 ibireme. All rights reserved.
+//  Created by ibireme on 2017/6/29.
+//  Copyright © 2017年 ibireme. All rights reserved.
 //
 
 #import <UIKit/UIKit.h>

+ 11 - 3
Benchmark/CacheBenchmark/ViewController.m

@@ -2,12 +2,12 @@
 //  ViewController.m
 //  CacheBenchmark
 //
-//  Created by ibireme on 15/10/20.
-//  Copyright (C) 2015 ibireme. All rights reserved.
+//  Created by ibireme on 2017/6/29.
+//  Copyright © 2017年 ibireme. All rights reserved.
 //
 
 #import "ViewController.h"
-#import "Benchmark.h"
+#include "Benchmark.h"
 
 @interface ViewController ()
 
@@ -17,10 +17,18 @@
 
 - (void)viewDidLoad {
     [super viewDidLoad];
+    // Do any additional setup after loading the view, typically from a nib.
     
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
         [Benchmark benchmark];
     });
 }
 
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+
 @end

+ 2 - 2
Benchmark/CacheBenchmark/main.m

@@ -2,8 +2,8 @@
 //  main.m
 //  CacheBenchmark
 //
-//  Created by ibireme on 15/10/20.
-//  Copyright (C) 2015 ibireme. All rights reserved.
+//  Created by ibireme on 2017/6/29.
+//  Copyright © 2017年 ibireme. All rights reserved.
 //
 
 #import <UIKit/UIKit.h>

+ 0 - 20
Benchmark/Vendor/PINCache/Nullability.h

@@ -1,20 +0,0 @@
-//  PINCache is a modified version of TMCache
-//  Modifications by Garrett Moon
-//  Copyright (c) 2015 Pinterest. All rights reserved.
-
-#ifndef PINCache_nullability_h
-#define PINCache_nullability_h
-
-#if !__has_feature(nullability)
-#define NS_ASSUME_NONNULL_BEGIN
-#define NS_ASSUME_NONNULL_END
-#define nullable
-#define nonnull
-#define null_unspecified
-#define null_resettable
-#define __nullable
-#define __nonnull
-#define __null_unspecified
-#endif
-
-#endif

+ 55 - 117
Benchmark/Vendor/PINCache/PINCache.h

@@ -4,24 +4,15 @@
 
 #import <Foundation/Foundation.h>
 
-#import "PINDiskCache.h"
-#import "PINMemoryCache.h"
+#import <PINCacheMacros.h>
+#import <PINCaching.h>
+#import <PINDiskCache.h>
+#import <PINMemoryCache.h>
 
 NS_ASSUME_NONNULL_BEGIN
 
 @class PINCache;
 
-/**
- A callback block which provides only the cache as an argument
- */
-
-typedef void (^PINCacheBlock)(PINCache *cache);
-
-/**
- A callback block which provides the cache, key and object as arguments
- */
-
-typedef void (^PINCacheObjectBlock)(PINCache *cache, NSString *key, id __nullable object);
 
 /**
  `PINCache` is a thread safe key/value store designed for persisting temporary objects that are expensive to
@@ -40,21 +31,12 @@ typedef void (^PINCacheObjectBlock)(PINCache *cache, NSString *key, id __nullabl
  @warning when using in extension or watch extension, define PIN_APP_EXTENSIONS=1
  */
 
-@interface PINCache : NSObject
+PIN_SUBCLASSING_RESTRICTED
+@interface PINCache : NSObject <PINCaching, PINCacheObjectSubscripting>
 
 #pragma mark -
 /// @name Core
 
-/**
- The name of this cache, used to create the <diskCache> and also appearing in stack traces.
- */
-@property (readonly) NSString *name;
-
-/**
- A concurrent queue on which blocks passed to the asynchronous access methods are run.
- */
-@property (readonly) dispatch_queue_t concurrentQueue;
-
 /**
  Synchronously retrieves the total byte count of the <diskCache> on the shared disk queue.
  */
@@ -70,7 +52,7 @@ typedef void (^PINCacheObjectBlock)(PINCache *cache, NSString *key, id __nullabl
  */
 @property (readonly) PINMemoryCache *memoryCache;
 
-#pragma mark -
+#pragma mark - Lifecycle
 /// @name Initialization
 
 /**
@@ -78,126 +60,82 @@ typedef void (^PINCacheObjectBlock)(PINCache *cache, NSString *key, id __nullabl
  
  @result The shared singleton cache instance.
  */
-+ (instancetype)sharedCache;
+@property (class, strong, readonly) PINCache *sharedCache;
 
 - (instancetype)init NS_UNAVAILABLE;
 
 /**
- Multiple instances with the same name are allowed and can safely access
- the same data on disk thanks to the magic of seriality. Also used to create the <diskCache>.
+ Multiple instances with the same name are *not* allowed and can *not* safely
+ access the same data on disk. Also used to create the <diskCache>.
  
  @see name
  @param name The name of the cache.
  @result A new cache with the specified name.
  */
-- (instancetype)initWithName:(NSString *)name;
+- (instancetype)initWithName:(nonnull NSString *)name;
 
 /**
- Multiple instances with the same name are allowed and can safely access
- the same data on disk thanks to the magic of seriality. Also used to create the <diskCache>.
+ Multiple instances with the same name are *not* allowed and can *not* safely
+ access the same data on disk. Also used to create the <diskCache>.
  
  @see name
  @param name The name of the cache.
  @param rootPath The path of the cache on disk.
  @result A new cache with the specified name.
  */
-- (instancetype)initWithName:(NSString *)name rootPath:(NSString *)rootPath NS_DESIGNATED_INITIALIZER;
-
-#pragma mark -
-/// @name Asynchronous Methods
-
-/**
- Retrieves the object for the specified key. This method returns immediately and executes the passed
- block after the object is available, potentially in parallel with other blocks on the <concurrentQueue>.
- 
- @param key The key associated with the requested object.
- @param block A block to be executed concurrently when the object is available.
- */
-- (void)objectForKey:(NSString *)key block:(PINCacheObjectBlock)block;
-
-/**
- Stores an object in the cache for the specified key. This method returns immediately and executes the
- passed block after the object has been stored, potentially in parallel with other blocks on the <concurrentQueue>.
- 
- @param object An object to store in the cache.
- @param key A key to associate with the object. This string will be copied.
- @param block A block to be executed concurrently after the object has been stored, or nil.
- */
-- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(nullable PINCacheObjectBlock)block;
-
-/**
- Removes the object for the specified key. This method returns immediately and executes the passed
- block after the object has been removed, potentially in parallel with other blocks on the <concurrentQueue>.
- 
- @param key The key associated with the object to be removed.
- @param block A block to be executed concurrently after the object has been removed, or nil.
- */
-- (void)removeObjectForKey:(NSString *)key block:(nullable PINCacheObjectBlock)block;
+- (instancetype)initWithName:(nonnull NSString *)name rootPath:(nonnull NSString *)rootPath;
 
 /**
- Removes all objects from the cache that have not been used since the specified date. This method returns immediately and
- executes the passed block after the cache has been trimmed, potentially in parallel with other blocks on the <concurrentQueue>.
+ Multiple instances with the same name are *not* allowed and can *not* safely
+ access the same data on disk.. Also used to create the <diskCache>.
+ Initializer allows you to override default NSKeyedArchiver/NSKeyedUnarchiver serialization for <diskCache>.
+ You must provide both serializer and deserializer, or opt-out to default implementation providing nil values.
  
- @param date Objects that haven't been accessed since this date are removed from the cache.
- @param block A block to be executed concurrently after the cache has been trimmed, or nil.
- */
-- (void)trimToDate:(NSDate *)date block:(nullable PINCacheBlock)block;
-
-/**
- Removes all objects from the cache.This method returns immediately and executes the passed block after the
- cache has been cleared, potentially in parallel with other blocks on the <concurrentQueue>.
- 
- @param block A block to be executed concurrently after the cache has been cleared, or nil.
- */
-- (void)removeAllObjects:(nullable PINCacheBlock)block;
-
-#pragma mark -
-/// @name Synchronous Methods
-
-/**
- Retrieves the object for the specified key. This method blocks the calling thread until the object is available.
- Uses a semaphore to achieve synchronicity on the disk cache.
- 
- @see objectForKey:block:
- @param key The key associated with the object.
- @result The object for the specified key.
- */
-- (__nullable id)objectForKey:(NSString *)key;
-
-/**
- Stores an object in the cache for the specified key. This method blocks the calling thread until the object has been set.
- Uses a semaphore to achieve synchronicity on the disk cache.
- 
- @see setObject:forKey:block:
- @param object An object to store in the cache.
- @param key A key to associate with the object. This string will be copied.
+ @see name
+ @param name The name of the cache.
+ @param rootPath The path of the cache on disk.
+ @param serializer   A block used to serialize object before writing to disk. If nil provided, default NSKeyedArchiver serialized will be used.
+ @param deserializer A block used to deserialize object read from disk. If nil provided, default NSKeyedUnarchiver serialized will be used.
+ @result A new cache with the specified name.
  */
-- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key;
+- (instancetype)initWithName:(NSString *)name
+                    rootPath:(NSString *)rootPath
+                  serializer:(nullable PINDiskCacheSerializerBlock)serializer
+                deserializer:(nullable PINDiskCacheDeserializerBlock)deserializer;
 
-/**
- Removes the object for the specified key. This method blocks the calling thread until the object
- has been removed.
- Uses a semaphore to achieve synchronicity on the disk cache.
- 
- @param key The key associated with the object to be removed.
- */
-- (void)removeObjectForKey:(NSString *)key;
 
 /**
- Removes all objects from the cache that have not been used since the specified date.
- This method blocks the calling thread until the cache has been trimmed.
- Uses a semaphore to achieve synchronicity on the disk cache.
+ Multiple instances with the same name are *not* allowed and can *not* safely
+ access the same data on disk. Also used to create the <diskCache>.
+ Initializer allows you to override default NSKeyedArchiver/NSKeyedUnarchiver serialization for <diskCache>.
+ You must provide both serializer and deserializer, or opt-out to default implementation providing nil values.
  
- @param date Objects that haven't been accessed since this date are removed from the cache.
+ @see name
+ @param name The name of the cache.
+ @param rootPath The path of the cache on disk.
+ @param serializer   A block used to serialize object before writing to disk. If nil provided, default NSKeyedArchiver serialized will be used.
+ @param deserializer A block used to deserialize object read from disk. If nil provided, default NSKeyedUnarchiver serialized will be used.
+ @param keyEncoder A block used to encode key(filename). If nil provided, default url encoder will be used
+ @param keyDecoder A block used to decode key(filename). If nil provided, default url decoder will be used
+ @result A new cache with the specified name.
  */
-- (void)trimToDate:(NSDate *)date;
+- (instancetype)initWithName:(nonnull NSString *)name
+                    rootPath:(nonnull NSString *)rootPath
+                  serializer:(nullable PINDiskCacheSerializerBlock)serializer
+                deserializer:(nullable PINDiskCacheDeserializerBlock)deserializer
+                  keyEncoder:(nullable PINDiskCacheKeyEncoderBlock)keyEncoder
+                  keyDecoder:(nullable PINDiskCacheKeyDecoderBlock)keyDecoder NS_DESIGNATED_INITIALIZER;
 
-/**
- Removes all objects from the cache. This method blocks the calling thread until the cache has been cleared.
- Uses a semaphore to achieve synchronicity on the disk cache.
- */
-- (void)removeAllObjects;
+@end
 
+@interface PINCache (Deprecated)
+- (void)containsObjectForKey:(NSString *)key block:(PINCacheObjectContainmentBlock)block __attribute__((deprecated));
+- (void)objectForKey:(NSString *)key block:(PINCacheObjectBlock)block __attribute__((deprecated));
+- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(nullable PINCacheObjectBlock)block __attribute__((deprecated));
+- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key withCost:(NSUInteger)cost block:(nullable PINCacheObjectBlock)block __attribute__((deprecated));
+- (void)removeObjectForKey:(NSString *)key block:(nullable PINCacheObjectBlock)block __attribute__((deprecated));
+- (void)trimToDate:(NSDate *)date block:(nullable PINCacheBlock)block __attribute__((deprecated));
+- (void)removeAllObjects:(nullable PINCacheBlock)block __attribute__((deprecated));
 @end
 
 NS_ASSUME_NONNULL_END

+ 190 - 171
Benchmark/Vendor/PINCache/PINCache.m

@@ -4,29 +4,20 @@
 
 #import "PINCache.h"
 
+#import <PINOperation.h>
+
 static NSString * const PINCachePrefix = @"com.pinterest.PINCache";
 static NSString * const PINCacheSharedName = @"PINCacheShared";
 
 @interface PINCache ()
-#if OS_OBJECT_USE_OBJC
-@property (strong, nonatomic) dispatch_queue_t concurrentQueue;
-#else
-@property (assign, nonatomic) dispatch_queue_t concurrentQueue;
-#endif
+@property (copy, nonatomic) NSString *name;
+@property (strong, nonatomic) PINOperationQueue *operationQueue;
 @end
 
 @implementation PINCache
 
 #pragma mark - Initialization -
 
-#if !OS_OBJECT_USE_OBJC
-- (void)dealloc
-{
-    dispatch_release(_concurrentQueue);
-    _concurrentQueue = nil;
-}
-#endif
-
 - (instancetype)init
 {
     @throw [NSException exceptionWithName:@"Must initialize with a name" reason:@"PINCache must be initialized with a name. Call initWithName: instead." userInfo:nil];
@@ -39,34 +30,54 @@ static NSString * const PINCacheSharedName = @"PINCacheShared";
 }
 
 - (instancetype)initWithName:(NSString *)name rootPath:(NSString *)rootPath
+{
+    return [self initWithName:name rootPath:rootPath serializer:nil deserializer:nil];
+}
+
+- (instancetype)initWithName:(NSString *)name rootPath:(NSString *)rootPath serializer:(PINDiskCacheSerializerBlock)serializer deserializer:(PINDiskCacheDeserializerBlock)deserializer {
+    return [self initWithName:name rootPath:rootPath serializer:serializer deserializer:deserializer keyEncoder:nil keyDecoder:nil];
+}
+
+- (instancetype)initWithName:(NSString *)name
+                    rootPath:(NSString *)rootPath
+                  serializer:(PINDiskCacheSerializerBlock)serializer
+                deserializer:(PINDiskCacheDeserializerBlock)deserializer
+                  keyEncoder:(PINDiskCacheKeyEncoderBlock)keyEncoder
+                  keyDecoder:(PINDiskCacheKeyDecoderBlock)keyDecoder
 {
     if (!name)
         return nil;
     
     if (self = [super init]) {
         _name = [name copy];
-        
-        NSString *queueName = [[NSString alloc] initWithFormat:@"%@.%p", PINCachePrefix, self];
-        _concurrentQueue = dispatch_queue_create([[NSString stringWithFormat:@"%@ Asynchronous Queue", queueName] UTF8String], DISPATCH_QUEUE_CONCURRENT);
-        
-        _diskCache = [[PINDiskCache alloc] initWithName:_name rootPath:rootPath];
-        _memoryCache = [[PINMemoryCache alloc] init];
+      
+        //10 may actually be a bit high, but currently much of our threads are blocked on empyting the trash. Until we can resolve that, lets bump this up.
+        _operationQueue = [[PINOperationQueue alloc] initWithMaxConcurrentOperations:10];
+        _diskCache = [[PINDiskCache alloc] initWithName:_name
+                                                 prefix:PINDiskCachePrefix
+                                               rootPath:rootPath
+                                             serializer:serializer
+                                           deserializer:deserializer
+                                             keyEncoder:nil
+                                             keyDecoder:nil
+                                         operationQueue:_operationQueue];
+        _memoryCache = [[PINMemoryCache alloc] initWithOperationQueue:_operationQueue];
     }
     return self;
 }
 
 - (NSString *)description
 {
-    return [[NSString alloc] initWithFormat:@"%@.%@.%p", PINCachePrefix, _name, self];
+    return [[NSString alloc] initWithFormat:@"%@.%@.%p", PINCachePrefix, _name, (void *)self];
 }
 
-+ (instancetype)sharedCache
++ (PINCache *)sharedCache
 {
-    static id cache;
+    static PINCache *cache;
     static dispatch_once_t predicate;
     
     dispatch_once(&predicate, ^{
-        cache = [[self alloc] initWithName:PINCacheSharedName];
+        cache = [[PINCache alloc] initWithName:PINCacheSharedName];
     });
     
     return cache;
@@ -74,220 +85,162 @@ static NSString * const PINCacheSharedName = @"PINCacheShared";
 
 #pragma mark - Public Asynchronous Methods -
 
+- (void)containsObjectForKeyAsync:(NSString *)key completion:(PINCacheObjectContainmentBlock)block
+{
+    if (!key || !block) {
+        return;
+    }
+    
+    __weak PINCache *weakSelf = self;
+  
+    [self.operationQueue addOperation:^{
+        PINCache *strongSelf = weakSelf;
+        
+        BOOL containsObject = [strongSelf containsObjectForKey:key];
+        block(containsObject);
+    }];
+}
+
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wshadow"
 
-- (void)objectForKey:(NSString *)key block:(PINCacheObjectBlock)block
+- (void)objectForKeyAsync:(NSString *)key completion:(PINCacheObjectBlock)block
 {
     if (!key || !block)
         return;
     
     __weak PINCache *weakSelf = self;
     
-    dispatch_async(_concurrentQueue, ^{
+    [self.operationQueue addOperation:^{
         PINCache *strongSelf = weakSelf;
         if (!strongSelf)
             return;
-        
-        __weak PINCache *weakSelf = strongSelf;
-        
-        [strongSelf->_memoryCache objectForKey:key block:^(PINMemoryCache *memoryCache, NSString *memoryCacheKey, id memoryCacheObject) {
+        [strongSelf->_memoryCache objectForKeyAsync:key completion:^(PINMemoryCache *memoryCache, NSString *memoryCacheKey, id memoryCacheObject) {
             PINCache *strongSelf = weakSelf;
             if (!strongSelf)
                 return;
             
             if (memoryCacheObject) {
-                [strongSelf->_diskCache fileURLForKey:memoryCacheKey block:^(PINDiskCache *diskCache, NSString *diskCacheKey, id <NSCoding> diskCacheObject, NSURL *fileURL) {
-                    // update the access time on disk
-                }];
-                
-                __weak PINCache *weakSelf = strongSelf;
-                
-                dispatch_async(strongSelf->_concurrentQueue, ^{
+                // Update file modification date. TODO: make this a separate method?
+                [strongSelf->_diskCache fileURLForKeyAsync:memoryCacheKey completion:^(NSString * _Nonnull key, NSURL * _Nullable fileURL) {}];
+                [strongSelf->_operationQueue addOperation:^{
                     PINCache *strongSelf = weakSelf;
                     if (strongSelf)
                         block(strongSelf, memoryCacheKey, memoryCacheObject);
-                });
+                }];
             } else {
-                __weak PINCache *weakSelf = strongSelf;
-                
-                [strongSelf->_diskCache objectForKey:memoryCacheKey block:^(PINDiskCache *diskCache, NSString *diskCacheKey, id <NSCoding> diskCacheObject, NSURL *fileURL) {
+                [strongSelf->_diskCache objectForKeyAsync:memoryCacheKey completion:^(PINDiskCache *diskCache, NSString *diskCacheKey, id <NSCoding> diskCacheObject) {
                     PINCache *strongSelf = weakSelf;
                     if (!strongSelf)
                         return;
                     
-                    [strongSelf->_memoryCache setObject:diskCacheObject forKey:diskCacheKey block:nil];
-                    
-                    __weak PINCache *weakSelf = strongSelf;
+                    [strongSelf->_memoryCache setObjectAsync:diskCacheObject forKey:diskCacheKey completion:nil];
                     
-                    dispatch_async(strongSelf->_concurrentQueue, ^{
+                    [strongSelf->_operationQueue addOperation:^{
                         PINCache *strongSelf = weakSelf;
                         if (strongSelf)
                             block(strongSelf, diskCacheKey, diskCacheObject);
-                    });
+                    }];
                 }];
             }
         }];
-    });
+    }];
 }
 
 #pragma clang diagnostic pop
 
-- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(PINCacheObjectBlock)block
+- (void)setObjectAsync:(id <NSCoding>)object forKey:(NSString *)key completion:(PINCacheObjectBlock)block
+{
+    [self setObjectAsync:object forKey:key withCost:0 completion:block];
+}
+
+- (void)setObjectAsync:(id <NSCoding>)object forKey:(NSString *)key withCost:(NSUInteger)cost completion:(PINCacheObjectBlock)block
 {
     if (!key || !object)
         return;
+  
+    PINOperationGroup *group = [PINOperationGroup asyncOperationGroupWithQueue:_operationQueue];
     
-    dispatch_group_t group = nil;
-    PINMemoryCacheObjectBlock memBlock = nil;
-    PINDiskCacheObjectBlock diskBlock = nil;
-    
+    [group addOperation:^{
+        [_memoryCache setObject:object forKey:key withCost:cost];
+    }];
+    [group addOperation:^{
+        [_diskCache setObject:object forKey:key];
+    }];
+  
     if (block) {
-        group = dispatch_group_create();
-        dispatch_group_enter(group);
-        dispatch_group_enter(group);
-        
-        memBlock = ^(PINMemoryCache *memoryCache, NSString *memoryCacheKey, id memoryCacheObject) {
-            dispatch_group_leave(group);
-        };
-        
-        diskBlock = ^(PINDiskCache *diskCache, NSString *diskCacheKey, id <NSCoding> memoryCacheObject, NSURL *memoryCacheFileURL) {
-            dispatch_group_leave(group);
-        };
+        [group setCompletion:^{
+            block(self, key, object);
+        }];
     }
     
-    [_memoryCache setObject:object forKey:key block:memBlock];
-    [_diskCache setObject:object forKey:key block:diskBlock];
-    
-    if (group) {
-        __weak PINCache *weakSelf = self;
-        dispatch_group_notify(group, _concurrentQueue, ^{
-            PINCache *strongSelf = weakSelf;
-            if (strongSelf)
-                block(strongSelf, key, object);
-        });
-        
-#if !OS_OBJECT_USE_OBJC
-        dispatch_release(group);
-#endif
-    }
+    [group start];
 }
 
-- (void)removeObjectForKey:(NSString *)key block:(PINCacheObjectBlock)block
+- (void)removeObjectForKeyAsync:(NSString *)key completion:(PINCacheObjectBlock)block
 {
     if (!key)
         return;
     
-    dispatch_group_t group = nil;
-    PINMemoryCacheObjectBlock memBlock = nil;
-    PINDiskCacheObjectBlock diskBlock = nil;
+    PINOperationGroup *group = [PINOperationGroup asyncOperationGroupWithQueue:_operationQueue];
     
+    [group addOperation:^{
+        [_memoryCache removeObjectForKey:key];
+    }];
+    [group addOperation:^{
+        [_diskCache removeObjectForKey:key];
+    }];
+
     if (block) {
-        group = dispatch_group_create();
-        dispatch_group_enter(group);
-        dispatch_group_enter(group);
-        
-        memBlock = ^(PINMemoryCache *memoryCache, NSString *memoryCacheKey, id memoryCacheObject) {
-            dispatch_group_leave(group);
-        };
-        
-        diskBlock = ^(PINDiskCache *diskCache, NSString *diskCacheKey, id <NSCoding> memoryCacheObject, NSURL *memoryCacheFileURL) {
-            dispatch_group_leave(group);
-        };
+        [group setCompletion:^{
+            block(self, key, nil);
+        }];
     }
     
-    [_memoryCache removeObjectForKey:key block:memBlock];
-    [_diskCache removeObjectForKey:key block:diskBlock];
-    
-    if (group) {
-        __weak PINCache *weakSelf = self;
-        dispatch_group_notify(group, _concurrentQueue, ^{
-            PINCache *strongSelf = weakSelf;
-            if (strongSelf)
-                block(strongSelf, key, nil);
-        });
-        
-#if !OS_OBJECT_USE_OBJC
-        dispatch_release(group);
-#endif
-    }
+    [group start];
 }
 
-- (void)removeAllObjects:(PINCacheBlock)block
+- (void)removeAllObjectsAsync:(PINCacheBlock)block
 {
-    dispatch_group_t group = nil;
-    PINMemoryCacheBlock memBlock = nil;
-    PINDiskCacheBlock diskBlock = nil;
+    PINOperationGroup *group = [PINOperationGroup asyncOperationGroupWithQueue:_operationQueue];
     
+    [group addOperation:^{
+        [_memoryCache removeAllObjects];
+    }];
+    [group addOperation:^{
+        [_diskCache removeAllObjects];
+    }];
+
     if (block) {
-        group = dispatch_group_create();
-        dispatch_group_enter(group);
-        dispatch_group_enter(group);
-        
-        memBlock = ^(PINMemoryCache *cache) {
-            dispatch_group_leave(group);
-        };
-        
-        diskBlock = ^(PINDiskCache *cache) {
-            dispatch_group_leave(group);
-        };
+        [group setCompletion:^{
+            block(self);
+        }];
     }
     
-    [_memoryCache removeAllObjects:memBlock];
-    [_diskCache removeAllObjects:diskBlock];
-    
-    if (group) {
-        __weak PINCache *weakSelf = self;
-        dispatch_group_notify(group, _concurrentQueue, ^{
-            PINCache *strongSelf = weakSelf;
-            if (strongSelf)
-                block(strongSelf);
-        });
-        
-#if !OS_OBJECT_USE_OBJC
-        dispatch_release(group);
-#endif
-    }
+    [group start];
 }
 
-- (void)trimToDate:(NSDate *)date block:(PINCacheBlock)block
+- (void)trimToDateAsync:(NSDate *)date completion:(PINCacheBlock)block
 {
     if (!date)
         return;
     
-    dispatch_group_t group = nil;
-    PINMemoryCacheBlock memBlock = nil;
-    PINDiskCacheBlock diskBlock = nil;
+    PINOperationGroup *group = [PINOperationGroup asyncOperationGroupWithQueue:_operationQueue];
     
+    [group addOperation:^{
+        [_memoryCache trimToDate:date];
+    }];
+    [group addOperation:^{
+        [_diskCache trimToDate:date];
+    }];
+  
     if (block) {
-        group = dispatch_group_create();
-        dispatch_group_enter(group);
-        dispatch_group_enter(group);
-        
-        memBlock = ^(PINMemoryCache *cache) {
-            dispatch_group_leave(group);
-        };
-        
-        diskBlock = ^(PINDiskCache *cache) {
-            dispatch_group_leave(group);
-        };
+        [group setCompletion:^{
+            block(self);
+        }];
     }
     
-    [_memoryCache trimToDate:date block:memBlock];
-    [_diskCache trimToDate:date block:diskBlock];
-    
-    if (group) {
-        __weak PINCache *weakSelf = self;
-        dispatch_group_notify(group, _concurrentQueue, ^{
-            PINCache *strongSelf = weakSelf;
-            if (strongSelf)
-                block(strongSelf);
-        });
-        
-#if !OS_OBJECT_USE_OBJC
-        dispatch_release(group);
-#endif
-    }
+    [group start];
 }
 
 #pragma mark - Public Synchronous Accessors -
@@ -303,7 +256,15 @@ static NSString * const PINCacheSharedName = @"PINCacheShared";
     return byteCount;
 }
 
-- (__nullable id)objectForKey:(NSString *)key
+- (BOOL)containsObjectForKey:(NSString *)key
+{
+    if (!key)
+        return NO;
+    
+    return [_memoryCache containsObjectForKey:key] || [_diskCache containsObjectForKey:key];
+}
+
+- (nullable id)objectForKey:(NSString *)key
 {
     if (!key)
         return nil;
@@ -313,8 +274,8 @@ static NSString * const PINCacheSharedName = @"PINCacheShared";
     object = [_memoryCache objectForKey:key];
     
     if (object) {
-        // update the access time on disk
-        [_diskCache fileURLForKey:key block:NULL];
+        // Update file modification date. TODO: make this a separate method?
+        [_diskCache fileURLForKeyAsync:key completion:^(NSString * _Nonnull key, NSURL * _Nullable fileURL) {}];
     } else {
         object = [_diskCache objectForKey:key];
         [_memoryCache setObject:object forKey:key];
@@ -324,14 +285,33 @@ static NSString * const PINCacheSharedName = @"PINCacheShared";
 }
 
 - (void)setObject:(id <NSCoding>)object forKey:(NSString *)key
+{
+    [self setObject:object forKey:key withCost:0];
+}
+
+- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key withCost:(NSUInteger)cost
 {
     if (!key || !object)
         return;
     
-    [_memoryCache setObject:object forKey:key];
+    [_memoryCache setObject:object forKey:key withCost:cost];
     [_diskCache setObject:object forKey:key];
 }
 
+- (nullable id)objectForKeyedSubscript:(NSString *)key
+{
+    return [self objectForKey:key];
+}
+
+- (void)setObject:(nullable id)obj forKeyedSubscript:(NSString *)key
+{
+    if (obj == nil) {
+        [self removeObjectForKey:key];
+    } else {
+        [self setObject:obj forKey:key];
+    }
+}
+
 - (void)removeObjectForKey:(NSString *)key
 {
     if (!key)
@@ -357,3 +337,42 @@ static NSString * const PINCacheSharedName = @"PINCacheShared";
 }
 
 @end
+
+@implementation PINCache (Deprecated)
+
+- (void)containsObjectForKey:(NSString *)key block:(PINCacheObjectContainmentBlock)block
+{
+    [self containsObjectForKeyAsync:key completion:block];
+}
+
+- (void)objectForKey:(NSString *)key block:(PINCacheObjectBlock)block
+{
+    [self objectForKeyAsync:key completion:block];
+}
+
+- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(nullable PINCacheObjectBlock)block
+{
+    [self setObjectAsync:object forKey:key completion:block];
+}
+
+- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key withCost:(NSUInteger)cost block:(nullable PINCacheObjectBlock)block
+{
+    [self setObjectAsync:object forKey:key withCost:cost completion:block];
+}
+
+- (void)removeObjectForKey:(NSString *)key block:(nullable PINCacheObjectBlock)block
+{
+    [self removeObjectForKeyAsync:key completion:block];
+}
+
+- (void)trimToDate:(NSDate *)date block:(nullable PINCacheBlock)block
+{
+    [self trimToDateAsync:date completion:block];
+}
+
+- (void)removeAllObjects:(nullable PINCacheBlock)block
+{
+    [self removeAllObjectsAsync:block];
+}
+
+@end

+ 23 - 0
Benchmark/Vendor/PINCache/PINCacheMacros.h

@@ -0,0 +1,23 @@
+//
+//  PINCacheMacros.h
+//  PINCache
+//
+//  Created by Adlai Holler on 1/31/17.
+//  Copyright © 2017 Pinterest. All rights reserved.
+//
+
+#ifndef PIN_SUBCLASSING_RESTRICTED
+#if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted)
+#define PIN_SUBCLASSING_RESTRICTED __attribute__((objc_subclassing_restricted))
+#else
+#define PIN_SUBCLASSING_RESTRICTED
+#endif // #if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted)
+#endif // #ifndef PIN_SUBCLASSING_RESTRICTED
+
+#ifndef PIN_NOESCAPE
+#if defined(__has_attribute) && __has_attribute(noescape)
+#define PIN_NOESCAPE __attribute__((noescape))
+#else
+#define PIN_NOESCAPE
+#endif // #if defined(__has_attribute) && __has_attribute(noescape)
+#endif // #ifndef PIN_NOESCAPE

+ 35 - 0
Benchmark/Vendor/PINCache/PINCacheObjectSubscripting.h

@@ -0,0 +1,35 @@
+//
+//  PINCacheObjectSubscripting.h
+//  PINCache
+//
+//  Created by Rocir Marcos Leite Santiago on 4/2/16.
+//  Copyright © 2016 Pinterest. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol PINCacheObjectSubscripting <NSObject>
+
+@required
+
+/**
+ This method enables using literals on the receiving object, such as `id object = cache[@"key"];`.
+ 
+ @param key The key associated with the object.
+ @result The object for the specified key.
+ */
+- (nullable id)objectForKeyedSubscript:(NSString *)key;
+
+/**
+ This method enables using literals on the receiving object, such as `cache[@"key"] = object;`.
+ 
+ @param object An object to be assigned for the key. Pass `nil` to remove the existing object for this key.
+ @param key A key to associate with the object. This string will be copied.
+ */
+- (void)setObject:(nullable id)object forKeyedSubscript:(NSString *)key;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 189 - 0
Benchmark/Vendor/PINCache/PINCaching.h

@@ -0,0 +1,189 @@
+//
+//  PINCaching.h
+//  PINCache
+//
+//  Created by Michael Schneider on 1/31/17.
+//  Copyright © 2017 Pinterest. All rights reserved.
+//
+
+#pragma once
+#import <Foundation/Foundation.h>
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol PINCaching;
+
+/**
+ A callback block which provides only the cache as an argument
+ */
+typedef void (^PINCacheBlock)(id<PINCaching> cache);
+
+/**
+ A callback block which provides the cache, key and object as arguments
+ */
+typedef void (^PINCacheObjectBlock)(id<PINCaching> cache, NSString *key, id _Nullable object);
+
+/**
+ A callback block which provides a BOOL value as argument
+ */
+typedef void (^PINCacheObjectContainmentBlock)(BOOL containsObject);
+
+@protocol PINCaching <NSObject>
+
+#pragma mark - Core
+
+/**
+ The name of this cache, used to create a directory under Library/Caches and also appearing in stack traces.
+ */
+@property (readonly) NSString *name;
+
+#pragma mark - Asynchronous Methods
+
+/// @name Asynchronous Methods
+
+/**
+ This method determines whether an object is present for the given key in the cache. This method returns immediately
+ and executes the passed block after the object is available, potentially in parallel with other blocks on the
+ <concurrentQueue>.
+ 
+ @see containsObjectForKey:
+ @param key The key associated with the object.
+ @param block A block to be executed concurrently after the containment check happened
+ */
+- (void)containsObjectForKeyAsync:(NSString *)key completion:(PINCacheObjectContainmentBlock)block;
+
+/**
+ Retrieves the object for the specified key. This method returns immediately and executes the passed
+ block after the object is available, potentially in parallel with other blocks on the <concurrentQueue>.
+ 
+ @param key The key associated with the requested object.
+ @param block A block to be executed concurrently when the object is available.
+ */
+- (void)objectForKeyAsync:(NSString *)key completion:(PINCacheObjectBlock)block;
+
+/**
+ Stores an object in the cache for the specified key. This method returns immediately and executes the
+ passed block after the object has been stored, potentially in parallel with other blocks on the <concurrentQueue>.
+ 
+ @param object An object to store in the cache.
+ @param key A key to associate with the object. This string will be copied.
+ @param block A block to be executed concurrently after the object has been stored, or nil.
+ */
+- (void)setObjectAsync:(id)object forKey:(NSString *)key completion:(nullable PINCacheObjectBlock)block;
+
+/**
+ Stores an object in the cache for the specified key and the specified memory cost. If the cost causes the total
+ to go over the <memoryCache.costLimit> the cache is trimmed (oldest objects first). This method returns immediately
+ and executes the passed block after the object has been stored, potentially in parallel with other blocks
+ on the <concurrentQueue>.
+ 
+ @param object An object to store in the cache.
+ @param key A key to associate with the object. This string will be copied.
+ @param cost An amount to add to the <memoryCache.totalCost>.
+ @param block A block to be executed concurrently after the object has been stored, or nil.
+ */
+- (void)setObjectAsync:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost completion:(nullable PINCacheObjectBlock)block;
+
+/**
+ Removes the object for the specified key. This method returns immediately and executes the passed
+ block after the object has been removed, potentially in parallel with other blocks on the <concurrentQueue>.
+ 
+ @param key The key associated with the object to be removed.
+ @param block A block to be executed concurrently after the object has been removed, or nil.
+ */
+- (void)removeObjectForKeyAsync:(NSString *)key completion:(nullable PINCacheObjectBlock)block;
+
+/**
+ Removes all objects from the cache that have not been used since the specified date. This method returns immediately and
+ executes the passed block after the cache has been trimmed, potentially in parallel with other blocks on the <concurrentQueue>.
+ 
+ @param date Objects that haven't been accessed since this date are removed from the cache.
+ @param block A block to be executed concurrently after the cache has been trimmed, or nil.
+ */
+- (void)trimToDateAsync:(NSDate *)date completion:(nullable PINCacheBlock)block;
+
+/**
+ Removes all objects from the cache.This method returns immediately and executes the passed block after the
+ cache has been cleared, potentially in parallel with other blocks on the <concurrentQueue>.
+ 
+ @param block A block to be executed concurrently after the cache has been cleared, or nil.
+ */
+- (void)removeAllObjectsAsync:(nullable PINCacheBlock)block;
+
+
+#pragma mark - Synchronous Methods
+/// @name Synchronous Methods
+
+/**
+ This method determines whether an object is present for the given key in the cache.
+ 
+ @see containsObjectForKeyAsync:completion:
+ @param key The key associated with the object.
+ @result YES if an object is present for the given key in the cache, otherwise NO.
+ */
+- (BOOL)containsObjectForKey:(NSString *)key;
+
+/**
+ Retrieves the object for the specified key. This method blocks the calling thread until the object is available.
+ Uses a lock to achieve synchronicity on the disk cache.
+ 
+ @see objectForKeyAsync:completion:
+ @param key The key associated with the object.
+ @result The object for the specified key.
+ */
+- (nullable id)objectForKey:(NSString *)key;
+
+/**
+ Stores an object in the cache for the specified key. This method blocks the calling thread until the object has been set.
+ Uses a lock to achieve synchronicity on the disk cache.
+ 
+ @see setObjectAsync:forKey:completion:
+ @param object An object to store in the cache.
+ @param key A key to associate with the object. This string will be copied.
+ */
+- (void)setObject:(nullable id)object forKey:(NSString *)key;
+
+/**
+ Stores an object in the cache for the specified key and the specified memory cost. If the cost causes the total
+ to go over the <memoryCache.costLimit> the cache is trimmed (oldest objects first). This method blocks the calling thread
+ until the object has been stored.
+ 
+ @param object An object to store in the cache.
+ @param key A key to associate with the object. This string will be copied.
+ @param cost An amount to add to the <memoryCache.totalCost>.
+ */
+- (void)setObject:(nullable id)object forKey:(NSString *)key withCost:(NSUInteger)cost;
+
+/**
+ Removes the object for the specified key. This method blocks the calling thread until the object
+ has been removed.
+ Uses a lock to achieve synchronicity on the disk cache.
+ 
+ @see removeObjectForKeyAsync:completion:
+ @param key The key associated with the object to be removed.
+ */
+- (void)removeObjectForKey:(NSString *)key;
+
+/**
+ Removes all objects from the cache that have not been used since the specified date.
+ This method blocks the calling thread until the cache has been trimmed.
+ Uses a lock to achieve synchronicity on the disk cache.
+ 
+ @see trimToDateAsync:completion:
+ @param date Objects that haven't been accessed since this date are removed from the cache.
+ */
+- (void)trimToDate:(NSDate *)date;
+
+/**
+ Removes all objects from the cache. This method blocks the calling thread until the cache has been cleared.
+ Uses a lock to achieve synchronicity on the disk cache.
+ 
+ @see removeAllObjectsAsync:
+ */
+- (void)removeAllObjects;
+
+@end
+
+NS_ASSUME_NONNULL_END
+

+ 225 - 79
Benchmark/Vendor/PINCache/PINDiskCache.h

@@ -3,23 +3,71 @@
 //  Copyright (c) 2015 Pinterest. All rights reserved.
 
 #import <Foundation/Foundation.h>
-#import "Nullability.h"
+
+#import <PINCacheMacros.h>
+#import <PINCaching.h>
+#import <PINCacheObjectSubscripting.h>
 
 NS_ASSUME_NONNULL_BEGIN
 
 @class PINDiskCache;
+@class PINOperationQueue;
+
+extern NSString * const PINDiskCachePrefix;
 
 /**
- A callback block which provides only the cache as an argument
+ A callback block which provides the cache, key and object as arguments
  */
+typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <NSCoding>  _Nullable object);
 
-typedef void (^PINDiskCacheBlock)(PINDiskCache *cache);
+/**
+ A callback block which provides the key and fileURL of the object
+ */
+typedef void (^PINDiskCacheFileURLBlock)(NSString *key, NSURL * _Nullable fileURL);
 
 /**
- A callback block which provides the cache, key and object as arguments
+ A callback block which provides a BOOL value as argument
+ */
+typedef void (^PINDiskCacheContainsBlock)(BOOL containsObject);
+
+/**
+ *  A block used to serialize object before writing to disk
+ *
+ *  @param object Object to serialize
+ *  @param key The key associated with the object
+ *
+ *  @return Serialized object representation
+ */
+typedef NSData* _Nonnull(^PINDiskCacheSerializerBlock)(id<NSCoding> object, NSString *key);
+
+/**
+ *  A block used to deserialize objects
+ *
+ *  @param data Serialized object data
+ *  @param key The key associated with the object
+ *
+ *  @return Deserialized object
+ */
+typedef id<NSCoding> _Nonnull(^PINDiskCacheDeserializerBlock)(NSData* data, NSString *key);
+
+/**
+ *  A block used to encode keys
+ *
+ *  @param decodedKey Original/decoded key
+ *
+ *  @return encoded key
+ */
+typedef NSString *_Nonnull(^PINDiskCacheKeyEncoderBlock)(NSString *decodedKey);
+
+/**
+ *  A block used to decode keys
+ *
+ *  @param encodedKey An encoded key
+ *
+ *  @return decoded key
  */
+typedef NSString *_Nonnull(^PINDiskCacheKeyDecoderBlock)(NSString *encodedKey);
 
-typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <NSCoding>  __nullable object, NSURL * __nullable fileURL);
 
 /**
  `PINDiskCache` is a thread safe key/value store backed by the file system. It accepts any object conforming
@@ -44,17 +92,26 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
  <ageLimit> will trigger a GCD timer to periodically to trim the cache with <trimToDate:>.
  */
 
-@interface PINDiskCache : NSObject
+PIN_SUBCLASSING_RESTRICTED
+@interface PINDiskCache : NSObject <PINCaching, PINCacheObjectSubscripting>
 
+#pragma mark - Class
 
+/**
+ @param rootPath The path for where the cache should be stored.
+ @param prefix The prefix for the cache name.
+ @param name The name of the cache.
+ @result The full URL of the cache.
+ */
++ (NSURL *)cacheURLWithRootPath:(NSString *)rootPath prefix:(NSString *)prefix name:(NSString *)name;
 
-#pragma mark -
+#pragma mark - Properties
 /// @name Core
 
 /**
- The name of this cache, used to create a directory under Library/Caches and also appearing in stack traces.
+ The prefix to the name of this cache, used to create a directory under Library/Caches and also appearing in stack traces.
  */
-@property (readonly) NSString *name;
+@property (readonly) NSString *prefix;
 
 /**
  The URL of the directory used by this cache, usually `Library/Caches/com.pinterest.PINDiskCache.(name)`
@@ -68,7 +125,7 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
  The total number of bytes used on disk, as reported by `NSURLTotalFileAllocatedSizeKey`.
  
  @warning This property should only be read from a call to <synchronouslyLockFileAccessWhileExecutingBlock:> or
- its asynchronous equivolent <lockFileAccessWhileExecutingBlock:>
+ its asynchronous equivalent <lockFileAccessWhileExecutingBlock:>
  
  For example:
  
@@ -97,42 +154,66 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
  */
 @property (assign) NSTimeInterval ageLimit;
 
-#pragma mark -
+/**
+ The writing protection option used when writing a file on disk. This value is used every time an object is set.
+ NSDataWritingAtomic and NSDataWritingWithoutOverwriting are ignored if set
+ Defaults to NSDataWritingFileProtectionNone.
+ 
+ @warning Only new files are affected by the new writing protection. If you need all files to be affected,
+ you'll have to purge and set the objects back to the cache
+ 
+ Only available on iOS
+ */
+#if TARGET_OS_IPHONE
+@property (assign) NSDataWritingOptions writingProtectionOption;
+#endif
+
+/**
+ If ttlCache is YES, the cache behaves like a ttlCache. This means that once an object enters the
+ cache, it only lives as long as self.ageLimit. This has the following implications:
+    - Accessing an object in the cache does not extend that object's lifetime in the cache
+    - When attempting to access an object in the cache that has lived longer than self.ageLimit,
+      the cache will behave as if the object does not exist
+ 
+ */
+@property (nonatomic, assign, getter=isTTLCache) BOOL ttlCache;
+
+#pragma mark - Event Blocks
 /// @name Event Blocks
 
 /**
  A block to be executed just before an object is added to the cache. The queue waits during execution.
  */
-@property (copy) PINDiskCacheObjectBlock __nullable willAddObjectBlock;
+@property (nullable, copy) PINDiskCacheObjectBlock willAddObjectBlock;
 
 /**
  A block to be executed just before an object is removed from the cache. The queue waits during execution.
  */
-@property (copy) PINDiskCacheObjectBlock __nullable willRemoveObjectBlock;
+@property (nullable, copy) PINDiskCacheObjectBlock willRemoveObjectBlock;
 
 /**
  A block to be executed just before all objects are removed from the cache as a result of <removeAllObjects:>.
  The queue waits during execution.
  */
-@property (copy) PINDiskCacheBlock __nullable willRemoveAllObjectsBlock;
+@property (nullable, copy) PINCacheBlock willRemoveAllObjectsBlock;
 
 /**
  A block to be executed just after an object is added to the cache. The queue waits during execution.
  */
-@property (copy) PINDiskCacheObjectBlock __nullable didAddObjectBlock;
+@property (nullable, copy) PINDiskCacheObjectBlock didAddObjectBlock;
 
 /**
  A block to be executed just after an object is removed from the cache. The queue waits during execution.
  */
-@property (copy) PINDiskCacheObjectBlock __nullable didRemoveObjectBlock;
+@property (nullable, copy) PINDiskCacheObjectBlock didRemoveObjectBlock;
 
 /**
  A block to be executed just after all objects are removed from the cache as a result of <removeAllObjects:>.
  The queue waits during execution.
  */
-@property (copy) PINDiskCacheBlock __nullable didRemoveAllObjectsBlock;
+@property (nullable, copy) PINCacheBlock didRemoveAllObjectsBlock;
 
-#pragma mark -
+#pragma mark - Lifecycle
 /// @name Initialization
 
 /**
@@ -140,7 +221,7 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
  
  @result The shared singleton cache instance.
  */
-+ (instancetype)sharedCache;
+@property (class, readonly, strong) PINDiskCache *sharedCache;
 
 /**
  Empties the trash with `DISPATCH_QUEUE_PRIORITY_BACKGROUND`. Does not use lock.
@@ -157,10 +238,10 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
  @param name The name of the cache.
  @result A new cache with the specified name.
  */
-- (instancetype)initWithName:(NSString *)name;
+- (instancetype)initWithName:(nonnull NSString *)name;
 
 /**
- The designated initializer. Multiple instances with the same name are allowed and can safely access
+ Multiple instances with the same name are allowed and can safely access
  the same data on disk thanks to the magic of seriality.
  
  @see name
@@ -168,9 +249,55 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
  @param rootPath The path of the cache.
  @result A new cache with the specified name.
  */
-- (instancetype)initWithName:(NSString *)name rootPath:(NSString *)rootPath NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithName:(nonnull NSString *)name rootPath:(nonnull NSString *)rootPath;
 
-#pragma mark -
+/**
+ @see name
+ @param name The name of the cache.
+ @param rootPath The path of the cache.
+ @param serializer   A block used to serialize object. If nil provided, default NSKeyedArchiver serialized will be used.
+ @param deserializer A block used to deserialize object. If nil provided, default NSKeyedUnarchiver serialized will be used.
+ @result A new cache with the specified name.
+ */
+- (instancetype)initWithName:(nonnull NSString *)name rootPath:(nonnull NSString *)rootPath serializer:(nullable PINDiskCacheSerializerBlock)serializer deserializer:(nullable PINDiskCacheDeserializerBlock)deserializer;
+
+/**
+ The designated initializer allowing you to override default NSKeyedArchiver/NSKeyedUnarchiver serialization.
+ 
+ @see name
+ @param name The name of the cache.
+ @param rootPath The path of the cache.
+ @param serializer   A block used to serialize object. If nil provided, default NSKeyedArchiver serialized will be used.
+ @param deserializer A block used to deserialize object. If nil provided, default NSKeyedUnarchiver serialized will be used.
+ @param operationQueue A PINOperationQueue to run asynchronous operations
+ @result A new cache with the specified name.
+ */
+- (instancetype)initWithName:(nonnull NSString *)name rootPath:(nonnull NSString *)rootPath serializer:(nullable PINDiskCacheSerializerBlock)serializer deserializer:(nullable PINDiskCacheDeserializerBlock)deserializer operationQueue:(nonnull PINOperationQueue *)operationQueue __attribute__((deprecated));
+
+/**
+ The designated initializer allowing you to override default NSKeyedArchiver/NSKeyedUnarchiver serialization.
+ 
+ @see name
+ @param name The name of the cache.
+ @param prefix The prefix for the cache name. Defaults to com.pinterest.PINDiskCache
+ @param rootPath The path of the cache.
+ @param serializer   A block used to serialize object. If nil provided, default NSKeyedArchiver serialized will be used.
+ @param deserializer A block used to deserialize object. If nil provided, default NSKeyedUnarchiver serialized will be used.
+ @param keyEncoder A block used to encode key(filename). If nil provided, default url encoder will be used
+ @param keyDecoder A block used to decode key(filename). If nil provided, default url decoder will be used
+ @param operationQueue A PINOperationQueue to run asynchronous operations
+ @result A new cache with the specified name.
+ */
+- (instancetype)initWithName:(nonnull NSString *)name
+                      prefix:(nonnull NSString *)prefix
+                    rootPath:(nonnull NSString *)rootPath
+                  serializer:(nullable PINDiskCacheSerializerBlock)serializer
+                deserializer:(nullable PINDiskCacheDeserializerBlock)deserializer
+                  keyEncoder:(nullable PINDiskCacheKeyEncoderBlock)keyEncoder
+                  keyDecoder:(nullable PINDiskCacheKeyDecoderBlock)keyDecoder
+              operationQueue:(nonnull PINOperationQueue *)operationQueue NS_DESIGNATED_INITIALIZER;
+
+#pragma mark - Asynchronous Methods
 /// @name Asynchronous Methods
 /**
  Locks access to ivars and allows safe interaction with files on disk. This method returns immediately.
@@ -179,18 +306,16 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
  
  @param block A block to be executed when a lock is available.
  */
-- (void)lockFileAccessWhileExecutingBlock:(nullable PINDiskCacheBlock)block;
+- (void)lockFileAccessWhileExecutingBlockAsync:(PINCacheBlock)block;
 
 /**
  Retrieves the object for the specified key. This method returns immediately and executes the passed
  block as soon as the object is available.
  
- @warning The fileURL is only valid for the duration of this block, do not use it after the block ends.
- 
  @param key The key associated with the requested object.
  @param block A block to be executed serially when the object is available.
  */
-- (void)objectForKey:(NSString *)key block:(nullable PINDiskCacheObjectBlock)block;
+- (void)objectForKeyAsync:(NSString *)key completion:(nullable PINDiskCacheObjectBlock)block;
 
 /**
  Retrieves the fileURL for the specified key without actually reading the data from disk. This method
@@ -199,10 +324,15 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
  @warning Access is protected for the duration of the block, but to maintain safe disk access do not
  access this fileURL after the block has ended.
  
+ @warning The PINDiskCache lock is held while block is executed. Any synchronous calls to the diskcache
+ or a cache which owns the instance of the disk cache are likely to cause a deadlock. This is why the block is
+ *not* passed the instance of the disk cache. You should also avoid doing extensive work while this
+ lock is held.
+ 
  @param key The key associated with the requested object.
  @param block A block to be executed serially when the file URL is available.
  */
-- (void)fileURLForKey:(nullable NSString *)key block:(nullable PINDiskCacheObjectBlock)block;
+- (void)fileURLForKeyAsync:(NSString *)key completion:(PINDiskCacheFileURLBlock)block;
 
 /**
  Stores an object in the cache for the specified key. This method returns immediately and executes the
@@ -212,7 +342,20 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
  @param key A key to associate with the object. This string will be copied.
  @param block A block to be executed serially after the object has been stored, or nil.
  */
-- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(nullable PINDiskCacheObjectBlock)block;
+- (void)setObjectAsync:(id <NSCoding>)object forKey:(NSString *)key completion:(nullable PINDiskCacheObjectBlock)block;
+
+/**
+ Stores an object in the cache for the specified key and the specified memory cost. If the cost causes the total
+ to go over the <memoryCache.costLimit> the cache is trimmed (oldest objects first). This method returns immediately
+ and executes the passed block after the object has been stored, potentially in parallel with other blocks
+ on the <concurrentQueue>.
+ 
+ @param object An object to store in the cache.
+ @param key A key to associate with the object. This string will be copied.
+ @param cost An amount to add to the <memoryCache.totalCost>.
+ @param block A block to be executed concurrently after the object has been stored, or nil.
+ */
+- (void)setObjectAsync:(id <NSCoding>)object forKey:(NSString *)key withCost:(NSUInteger)cost completion:(nullable PINCacheObjectBlock)block;
 
 /**
  Removes the object for the specified key. This method returns immediately and executes the passed block
@@ -221,16 +364,7 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
  @param key The key associated with the object to be removed.
  @param block A block to be executed serially after the object has been removed, or nil.
  */
-- (void)removeObjectForKey:(NSString *)key block:(nullable PINDiskCacheObjectBlock)block;
-
-/**
- Removes all objects from the cache that have not been used since the specified date.
- This method returns immediately and executes the passed block as soon as the cache has been trimmed.
-
- @param date Objects that haven't been accessed since this date are removed from the cache.
- @param block A block to be executed serially after the cache has been trimmed, or nil.
- */
-- (void)trimToDate:(NSDate *)date block:(nullable PINDiskCacheBlock)block;
+- (void)removeObjectForKeyAsync:(NSString *)key completion:(nullable PINDiskCacheObjectBlock)block;
 
 /**
  Removes objects from the cache, largest first, until the cache is equal to or smaller than the specified byteCount.
@@ -239,7 +373,7 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
  @param byteCount The cache will be trimmed equal to or smaller than this size.
  @param block A block to be executed serially after the cache has been trimmed, or nil.
  */
-- (void)trimToSize:(NSUInteger)byteCount block:(nullable PINDiskCacheBlock)block;
+- (void)trimToSizeAsync:(NSUInteger)byteCount completion:(nullable PINCacheBlock)block;
 
 /**
  Removes objects from the cache, ordered by date (least recently used first), until the cache is equal to or smaller
@@ -249,15 +383,7 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
  @param byteCount The cache will be trimmed equal to or smaller than this size.
  @param block A block to be executed serially after the cache has been trimmed, or nil.
  */
-- (void)trimToSizeByDate:(NSUInteger)byteCount block:(nullable PINDiskCacheBlock)block;
-
-/**
- Removes all objects from the cache. This method returns immediately and executes the passed block as soon as the
- cache has been cleared.
- 
- @param block A block to be executed serially after the cache has been cleared, or nil.
- */
-- (void)removeAllObjects:(nullable PINDiskCacheBlock)block;
+- (void)trimToSizeByDateAsync:(NSUInteger)byteCount completion:(nullable PINCacheBlock)block;
 
 /**
  Loops through all objects in the cache (reads and writes are suspended during the enumeration). Data is not actually
@@ -266,10 +392,16 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
 
  @param block A block to be executed for every object in the cache.
  @param completionBlock An optional block to be executed after the enumeration is complete.
+ 
+ @warning The PINDiskCache lock is held while block is executed. Any synchronous calls to the diskcache
+ or a cache which owns the instance of the disk cache are likely to cause a deadlock. This is why the block is
+ *not* passed the instance of the disk cache. You should also avoid doing extensive work while this
+ lock is held.
+ 
  */
-- (void)enumerateObjectsWithBlock:(PINDiskCacheObjectBlock)block completionBlock:(nullable PINDiskCacheBlock)completionBlock;
+- (void)enumerateObjectsWithBlockAsync:(PINDiskCacheFileURLBlock)block completionBlock:(nullable PINCacheBlock)completionBlock;
 
-#pragma mark -
+#pragma mark - Synchronous Methods
 /// @name Synchronous Methods
 
 /**
@@ -280,58 +412,44 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
  
  @param block A block to be executed when a lock is available.
  */
-- (void)synchronouslyLockFileAccessWhileExecutingBlock:(nullable PINDiskCacheBlock)block;
+- (void)synchronouslyLockFileAccessWhileExecutingBlock:(PIN_NOESCAPE PINCacheBlock)block;
 
 /**
  Retrieves the object for the specified key. This method blocks the calling thread until the
  object is available.
  
- @see objectForKey:block:
+ @see objectForKeyAsync:completion:
  @param key The key associated with the object.
  @result The object for the specified key.
  */
-- (__nullable id <NSCoding>)objectForKey:(NSString *)key;
+- (nullable id <NSCoding>)objectForKey:(NSString *)key;
 
 /**
  Retrieves the file URL for the specified key. This method blocks the calling thread until the
  url is available. Do not use this URL anywhere except with <lockFileAccessWhileExecutingBlock:>. This method probably
  shouldn't even exist, just use the asynchronous one.
  
- @see fileURLForKey:block:
+ @see fileURLForKeyAsync:completion:
  @param key The key associated with the object.
  @result The file URL for the specified key.
  */
-- (NSURL *)fileURLForKey:(nullable NSString *)key;
+- (nullable NSURL *)fileURLForKey:(nullable NSString *)key;
 
 /**
  Stores an object in the cache for the specified key. This method blocks the calling thread until
  the object has been stored.
  
- @see setObject:forKey:block:
+ @see setObjectAsync:forKey:completion:
  @param object An object to store in the cache.
  @param key A key to associate with the object. This string will be copied.
  */
-- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key;
-
-/**
- Removes the object for the specified key. This method blocks the calling thread until the object
- has been removed.
- 
- @param key The key associated with the object to be removed.
- */
-- (void)removeObjectForKey:(NSString *)key;
-
-/**
- Removes all objects from the cache that have not been used since the specified date.
- This method blocks the calling thread until the cache has been trimmed.
- @param date Objects that haven't been accessed since this date are removed from the cache.
- */
-- (void)trimToDate:(nullable NSDate *)date;
+- (void)setObject:(nullable id <NSCoding>)object forKey:(NSString *)key;
 
 /**
  Removes objects from the cache, largest first, until the cache is equal to or smaller than the
  specified byteCount. This method blocks the calling thread until the cache has been trimmed.
  
+ @see trimToSizeAsync:
  @param byteCount The cache will be trimmed equal to or smaller than this size.
  */
 - (void)trimToSize:(NSUInteger)byteCount;
@@ -339,25 +457,53 @@ typedef void (^PINDiskCacheObjectBlock)(PINDiskCache *cache, NSString *key, id <
 /**
  Removes objects from the cache, ordered by date (least recently used first), until the cache is equal to or
  smaller than the specified byteCount. This method blocks the calling thread until the cache has been trimmed.
+ 
+ @see trimToSizeByDateAsync:
  @param byteCount The cache will be trimmed equal to or smaller than this size.
  */
 - (void)trimToSizeByDate:(NSUInteger)byteCount;
 
-/**
- Removes all objects from the cache. This method blocks the calling thread until the cache has been cleared.
- */
-- (void)removeAllObjects;
-
 /**
  Loops through all objects in the cache (reads and writes are suspended during the enumeration). Data is not actually
  read from disk, the `object` parameter of the block will be `nil` but the `fileURL` will be available.
  This method blocks the calling thread until all objects have been enumerated.
+ 
+ @see enumerateObjectsWithBlockAsync:completionBlock
  @param block A block to be executed for every object in the cache.
+ 
  @warning Do not call this method within the event blocks (<didRemoveObjectBlock>, etc.)
  Instead use the asynchronous version, <enumerateObjectsWithBlock:completionBlock:>.
+ 
+ @warning The PINDiskCache lock is held while block is executed. Any synchronous calls to the diskcache
+ or a cache which owns the instance of the disk cache are likely to cause a deadlock. This is why the block is
+ *not* passed the instance of the disk cache. You should also avoid doing extensive work while this
+ lock is held.
+ 
+ */
+- (void)enumerateObjectsWithBlock:(PIN_NOESCAPE PINDiskCacheFileURLBlock)block;
+
+@end
+
+
+#pragma mark - Deprecated
+
+/**
+ A callback block which provides only the cache as an argument
  */
-- (void)enumerateObjectsWithBlock:(nullable PINDiskCacheObjectBlock)block;
+typedef void (^PINDiskCacheBlock)(PINDiskCache *cache);
 
+@interface PINDiskCache (Deprecated)
+- (void)lockFileAccessWhileExecutingBlock:(nullable PINCacheBlock)block __attribute__((deprecated));
+- (void)containsObjectForKey:(NSString *)key block:(PINDiskCacheContainsBlock)block __attribute__((deprecated));
+- (void)objectForKey:(NSString *)key block:(nullable PINDiskCacheObjectBlock)block __attribute__((deprecated));
+- (void)fileURLForKey:(NSString *)key block:(nullable PINDiskCacheFileURLBlock)block __attribute__((deprecated));
+- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(nullable PINDiskCacheObjectBlock)block __attribute__((deprecated));
+- (void)removeObjectForKey:(NSString *)key block:(nullable PINDiskCacheObjectBlock)block __attribute__((deprecated));
+- (void)trimToDate:(NSDate *)date block:(nullable PINDiskCacheBlock)block __attribute__((deprecated));
+- (void)trimToSize:(NSUInteger)byteCount block:(nullable PINDiskCacheBlock)block __attribute__((deprecated));
+- (void)trimToSizeByDate:(NSUInteger)byteCount block:(nullable PINDiskCacheBlock)block __attribute__((deprecated));
+- (void)removeAllObjects:(nullable PINDiskCacheBlock)block __attribute__((deprecated));
+- (void)enumerateObjectsWithBlock:(PINDiskCacheFileURLBlock)block completionBlock:(nullable PINDiskCacheBlock)completionBlock __attribute__((deprecated));
 @end
 
 NS_ASSUME_NONNULL_END

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 487 - 251
Benchmark/Vendor/PINCache/PINDiskCache.m


+ 62 - 147
Benchmark/Vendor/PINCache/PINMemoryCache.h

@@ -3,29 +3,23 @@
 //  Copyright (c) 2015 Pinterest. All rights reserved.
 
 #import <Foundation/Foundation.h>
-#import "Nullability.h"
+
+#import <PINCacheMacros.h>
+#import <PINCaching.h>
+#import <PINCacheObjectSubscripting.h>
 
 NS_ASSUME_NONNULL_BEGIN
 
 @class PINMemoryCache;
+@class PINOperationQueue;
 
-/**
- A callback block which provides only the cache as an argument
- */
-
-typedef void (^PINMemoryCacheBlock)(PINMemoryCache *cache);
-
-/**
- A callback block which provides the cache, key and object as arguments
- */
-typedef void (^PINMemoryCacheObjectBlock)(PINMemoryCache *cache, NSString *key, id __nullable object);
 
 /**
  `PINMemoryCache` is a fast, thread safe key/value store similar to `NSCache`. On iOS it will clear itself
  automatically to reduce memory usage when the app receives a memory warning or goes into the background.
  
  Access is natively synchronous. Asynchronous variations are provided. Every asynchronous method accepts a
- callback block that runs on a concurrent <concurrentQueue>, with cache reads and writes protected by an semaphore.
+ callback block that runs on a concurrent <concurrentQueue>, with cache reads and writes protected by a lock.
  
  All access to the cache is dated so the that the least-used objects can be trimmed first. Setting an
  optional <ageLimit> will trigger a GCD timer to periodically to trim the cache to that age.
@@ -37,17 +31,12 @@ typedef void (^PINMemoryCacheObjectBlock)(PINMemoryCache *cache, NSString *key,
  a memory cache backed by a disk cache.
  */
 
-@interface PINMemoryCache : NSObject
+PIN_SUBCLASSING_RESTRICTED
+@interface PINMemoryCache : NSObject <PINCaching, PINCacheObjectSubscripting>
 
-#pragma mark -
+#pragma mark - Properties
 /// @name Core
 
-/**
- A concurrent queue on which all callbacks are called. It is exposed here so that it can be set to
- target some other queue, such as a global concurrent queue with a priority other than the default.
- */
-@property (readonly) dispatch_queue_t concurrentQueue;
-
 /**
  The total accumulated cost.
  */
@@ -65,6 +54,16 @@ typedef void (^PINMemoryCacheObjectBlock)(PINMemoryCache *cache, NSString *key,
  */
 @property (assign) NSTimeInterval ageLimit;
 
+/**
+ If ttlCache is YES, the cache behaves like a ttlCache. This means that once an object enters the
+ cache, it only lives as long as self.ageLimit. This has the following implications:
+ - Accessing an object in the cache does not extend that object's lifetime in the cache
+ - When attempting to access an object in the cache that has lived longer than self.ageLimit,
+ the cache will behave as if the object does not exist
+ 
+ */
+@property (nonatomic, assign, getter=isTTLCache) BOOL ttlCache;
+
 /**
  When `YES` on iOS the cache will remove all objects when the app receives a memory warning.
  Defaults to `YES`.
@@ -77,7 +76,7 @@ typedef void (^PINMemoryCacheObjectBlock)(PINMemoryCache *cache, NSString *key,
  */
 @property (assign) BOOL removeAllObjectsOnEnteringBackground;
 
-#pragma mark -
+#pragma mark - Event Blocks
 /// @name Event Blocks
 
 /**
@@ -85,56 +84,56 @@ typedef void (^PINMemoryCacheObjectBlock)(PINMemoryCache *cache, NSString *key,
  a lock, i.e. all reads and writes are suspended for the duration of the block.
  Calling synchronous methods on the cache within this callback will likely cause a deadlock.
  */
-@property (copy) PINMemoryCacheObjectBlock __nullable willAddObjectBlock;
+@property (nullable, copy) PINCacheObjectBlock willAddObjectBlock;
 
 /**
  A block to be executed just before an object is removed from the cache. This block will be excuted
  within a lock, i.e. all reads and writes are suspended for the duration of the block.
  Calling synchronous methods on the cache within this callback will likely cause a deadlock.
  */
-@property (copy) PINMemoryCacheObjectBlock __nullable willRemoveObjectBlock;
+@property (nullable, copy) PINCacheObjectBlock willRemoveObjectBlock;
 
 /**
  A block to be executed just before all objects are removed from the cache as a result of <removeAllObjects:>.
  This block will be excuted within a lock, i.e. all reads and writes are suspended for the duration of the block.
  Calling synchronous methods on the cache within this callback will likely cause a deadlock.
  */
-@property (copy) PINMemoryCacheBlock __nullable willRemoveAllObjectsBlock;
+@property (nullable, copy) PINCacheBlock willRemoveAllObjectsBlock;
 
 /**
  A block to be executed just after an object is added to the cache. This block will be excuted within
  a lock, i.e. all reads and writes are suspended for the duration of the block.
  Calling synchronous methods on the cache within this callback will likely cause a deadlock.
  */
-@property (copy) PINMemoryCacheObjectBlock __nullable didAddObjectBlock;
+@property (nullable, copy) PINCacheObjectBlock didAddObjectBlock;
 
 /**
  A block to be executed just after an object is removed from the cache. This block will be excuted
  within a lock, i.e. all reads and writes are suspended for the duration of the block.
  Calling synchronous methods on the cache within this callback will likely cause a deadlock.
  */
-@property (copy) PINMemoryCacheObjectBlock __nullable didRemoveObjectBlock;
+@property (nullable, copy) PINCacheObjectBlock didRemoveObjectBlock;
 
 /**
  A block to be executed just after all objects are removed from the cache as a result of <removeAllObjects:>.
  This block will be excuted within a lock, i.e. all reads and writes are suspended for the duration of the block.
  Calling synchronous methods on the cache within this callback will likely cause a deadlock.
  */
-@property (copy) PINMemoryCacheBlock __nullable didRemoveAllObjectsBlock;
+@property (nullable, copy) PINCacheBlock didRemoveAllObjectsBlock;
 
 /**
  A block to be executed upon receiving a memory warning (iOS only) potentially in parallel with other blocks on the <queue>.
  This block will be executed regardless of the value of <removeAllObjectsOnMemoryWarning>. Defaults to `nil`.
  */
-@property (copy) PINMemoryCacheBlock __nullable didReceiveMemoryWarningBlock;
+@property (nullable, copy) PINCacheBlock didReceiveMemoryWarningBlock;
 
 /**
  A block to be executed when the app enters the background (iOS only) potentially in parallel with other blocks on the <concurrentQueue>.
  This block will be executed regardless of the value of <removeAllObjectsOnEnteringBackground>. Defaults to `nil`.
  */
-@property (copy) PINMemoryCacheBlock __nullable didEnterBackgroundBlock;
+@property (nullable, copy) PINCacheBlock didEnterBackgroundBlock;
 
-#pragma mark -
+#pragma mark - Lifecycle
 /// @name Shared Cache
 
 /**
@@ -142,61 +141,14 @@ typedef void (^PINMemoryCacheObjectBlock)(PINMemoryCache *cache, NSString *key,
  
  @result The shared singleton cache instance.
  */
-+ (instancetype)sharedCache;
+@property (class, strong, readonly) PINMemoryCache *sharedCache;
 
-#pragma mark -
-/// @name Asynchronous Methods
+- (instancetype)initWithOperationQueue:(PINOperationQueue *)operationQueue;
 
-/**
- Retrieves the object for the specified key. This method returns immediately and executes the passed
- block after the object is available, potentially in parallel with other blocks on the <concurrentQueue>.
- 
- @param key The key associated with the requested object.
- @param block A block to be executed concurrently when the object is available.
- */
-- (void)objectForKey:(NSString *)key block:(nullable PINMemoryCacheObjectBlock)block;
-
-/**
- Stores an object in the cache for the specified key. This method returns immediately and executes the
- passed block after the object has been stored, potentially in parallel with other blocks on the <concurrentQueue>.
- 
- @param object An object to store in the cache.
- @param key A key to associate with the object. This string will be copied.
- @param block A block to be executed concurrently after the object has been stored, or nil.
- */
-- (void)setObject:(id)object forKey:(NSString *)key block:(nullable PINMemoryCacheObjectBlock)block;
-
-/**
- Stores an object in the cache for the specified key and the specified cost. If the cost causes the total
- to go over the <costLimit> the cache is trimmed (oldest objects first). This method returns immediately
- and executes the passed block after the object has been stored, potentially in parallel with other blocks
- on the <concurrentQueue>.
- 
- @param object An object to store in the cache.
- @param key A key to associate with the object. This string will be copied.
- @param cost An amount to add to the <totalCost>.
- @param block A block to be executed concurrently after the object has been stored, or nil.
- */
-- (void)setObject:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost block:(nullable PINMemoryCacheObjectBlock)block;
+- (instancetype)initWithName:(NSString *)name operationQueue:(PINOperationQueue *)operationQueue NS_DESIGNATED_INITIALIZER;
 
-/**
- Removes the object for the specified key. This method returns immediately and executes the passed
- block after the object has been removed, potentially in parallel with other blocks on the <concurrentQueue>.
- 
- @param key The key associated with the object to be removed.
- @param block A block to be executed concurrently after the object has been removed, or nil.
- */
-- (void)removeObjectForKey:(NSString *)key block:(nullable PINMemoryCacheObjectBlock)block;
-
-/**
- Removes all objects from the cache that have not been used since the specified date.
- This method returns immediately and executes the passed block after the cache has been trimmed,
- potentially in parallel with other blocks on the <concurrentQueue>.
- 
- @param date Objects that haven't been accessed since this date are removed from the cache.
- @param block A block to be executed concurrently after the cache has been trimmed, or nil.
- */
-- (void)trimToDate:(NSDate *)date block:(nullable PINMemoryCacheBlock)block;
+#pragma mark - Asynchronous Methods
+/// @name Asynchronous Methods
 
 /**
  Removes objects from the cache, costliest objects first, until the <totalCost> is below the specified
@@ -206,7 +158,7 @@ typedef void (^PINMemoryCacheObjectBlock)(PINMemoryCache *cache, NSString *key,
  @param cost The total accumulation allowed to remain after the cache has been trimmed.
  @param block A block to be executed concurrently after the cache has been trimmed, or nil.
  */
-- (void)trimToCost:(NSUInteger)cost block:(nullable PINMemoryCacheBlock)block;
+- (void)trimToCostAsync:(NSUInteger)cost completion:(nullable PINCacheBlock)block;
 
 /**
  Removes objects from the cache, ordered by date (least recently used first), until the <totalCost> is below
@@ -216,15 +168,7 @@ typedef void (^PINMemoryCacheObjectBlock)(PINMemoryCache *cache, NSString *key,
  @param cost The total accumulation allowed to remain after the cache has been trimmed.
  @param block A block to be executed concurrently after the cache has been trimmed, or nil.
  */
-- (void)trimToCostByDate:(NSUInteger)cost block:(nullable PINMemoryCacheBlock)block;
-
-/**
- Removes all objects from the cache. This method returns immediately and executes the passed block after
- the cache has been cleared, potentially in parallel with other blocks on the <concurrentQueue>.
- 
- @param block A block to be executed concurrently after the cache has been cleared, or nil.
- */
-- (void)removeAllObjects:(nullable PINMemoryCacheBlock)block;
+- (void)trimToCostByDateAsync:(NSUInteger)cost completion:(nullable PINCacheBlock)block;
 
 /**
  Loops through all objects in the cache with reads and writes suspended. Calling serial methods which
@@ -233,62 +177,16 @@ typedef void (^PINMemoryCacheObjectBlock)(PINMemoryCache *cache, NSString *key,
  @param block A block to be executed for every object in the cache.
  @param completionBlock An optional block to be executed concurrently when the enumeration is complete.
  */
-- (void)enumerateObjectsWithBlock:(PINMemoryCacheObjectBlock)block completionBlock:(nullable PINMemoryCacheBlock)completionBlock;
+- (void)enumerateObjectsWithBlockAsync:(PINCacheObjectBlock)block completionBlock:(nullable PINCacheBlock)completionBlock;
 
-#pragma mark -
+#pragma mark - Synchronous Methods
 /// @name Synchronous Methods
 
-/**
- Retrieves the object for the specified key. This method blocks the calling thread until the
- object is available.
- 
- @see objectForKey:block:
- @param key The key associated with the object.
- @result The object for the specified key.
- */
-- (__nullable id)objectForKey:(nullable NSString *)key;
-
-/**
- Stores an object in the cache for the specified key. This method blocks the calling thread until the object
- has been set.
- 
- @see setObject:forKey:block:
- @param object An object to store in the cache.
- @param key A key to associate with the object. This string will be copied.
- */
-- (void)setObject:(id)object forKey:(NSString *)key;
-
-/**
- Stores an object in the cache for the specified key and the specified cost. If the cost causes the total
- to go over the <costLimit> the cache is trimmed (oldest objects first). This method blocks the calling thread
- until the object has been stored.
- 
- @param object An object to store in the cache.
- @param key A key to associate with the object. This string will be copied.
- @param cost An amount to add to the <totalCost>.
- */
-- (void)setObject:(nullable id)object forKey:(nullable NSString *)key withCost:(NSUInteger)cost;
-
-/**
- Removes the object for the specified key. This method blocks the calling thread until the object
- has been removed.
- 
- @param key The key associated with the object to be removed.
- */
-- (void)removeObjectForKey:(nullable NSString *)key;
-
-/**
- Removes all objects from the cache that have not been used since the specified date.
- This method blocks the calling thread until the cache has been trimmed.
- 
- @param date Objects that haven't been accessed since this date are removed from the cache.
- */
-- (void)trimToDate:(nullable NSDate *)date;
-
 /**
  Removes objects from the cache, costliest objects first, until the <totalCost> is below the specified
  value. This method blocks the calling thread until the cache has been trimmed.
  
+ @see trimToCostAsync:
  @param cost The total accumulation allowed to remain after the cache has been trimmed.
  */
 - (void)trimToCost:(NSUInteger)cost;
@@ -297,28 +195,45 @@ typedef void (^PINMemoryCacheObjectBlock)(PINMemoryCache *cache, NSString *key,
  Removes objects from the cache, ordered by date (least recently used first), until the <totalCost> is below
  the specified value. This method blocks the calling thread until the cache has been trimmed.
  
+ @see trimToCostByDateAsync:
  @param cost The total accumulation allowed to remain after the cache has been trimmed.
  */
 - (void)trimToCostByDate:(NSUInteger)cost;
 
-/**
- Removes all objects from the cache. This method blocks the calling thread until the cache has been cleared.
- */
-- (void)removeAllObjects;
-
 /**
  Loops through all objects in the cache within a memory lock (reads and writes are suspended during the enumeration).
  This method blocks the calling thread until all objects have been enumerated.
  Calling synchronous methods on the cache within this callback will likely cause a deadlock.
  
+ @see enumerateObjectsWithBlockAsync:completionBlock:
  @param block A block to be executed for every object in the cache.
  
  @warning Do not call this method within the event blocks (<didReceiveMemoryWarningBlock>, etc.)
  Instead use the asynchronous version, <enumerateObjectsWithBlock:completionBlock:>.
  
  */
-- (void)enumerateObjectsWithBlock:(nullable PINMemoryCacheObjectBlock)block;
+- (void)enumerateObjectsWithBlock:(PIN_NOESCAPE PINCacheObjectBlock)block;
+
+@end
+
 
+#pragma mark - Deprecated
+
+typedef void (^PINMemoryCacheBlock)(PINMemoryCache *cache);
+typedef void (^PINMemoryCacheObjectBlock)(PINMemoryCache *cache, NSString *key, id _Nullable object);
+typedef void (^PINMemoryCacheContainmentBlock)(BOOL containsObject);
+
+@interface PINMemoryCache (Deprecated)
+- (void)containsObjectForKey:(NSString *)key block:(PINMemoryCacheContainmentBlock)block __attribute__((deprecated));
+- (void)objectForKey:(NSString *)key block:(nullable PINMemoryCacheObjectBlock)block __attribute__((deprecated));
+- (void)setObject:(id)object forKey:(NSString *)key block:(nullable PINMemoryCacheObjectBlock)block __attribute__((deprecated));
+- (void)setObject:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost block:(nullable PINMemoryCacheObjectBlock)block __attribute__((deprecated));
+- (void)removeObjectForKey:(NSString *)key block:(nullable PINMemoryCacheObjectBlock)block __attribute__((deprecated));
+- (void)trimToDate:(NSDate *)date block:(nullable PINMemoryCacheBlock)block __attribute__((deprecated));
+- (void)trimToCost:(NSUInteger)cost block:(nullable PINMemoryCacheBlock)block __attribute__((deprecated));
+- (void)trimToCostByDate:(NSUInteger)cost block:(nullable PINMemoryCacheBlock)block __attribute__((deprecated));
+- (void)removeAllObjects:(nullable PINMemoryCacheBlock)block __attribute__((deprecated));
+- (void)enumerateObjectsWithBlock:(PINMemoryCacheObjectBlock)block completionBlock:(nullable PINMemoryCacheBlock)completionBlock __attribute__((deprecated));
 @end
 
 NS_ASSUME_NONNULL_END

+ 283 - 144
Benchmark/Vendor/PINCache/PINMemoryCache.m

@@ -4,20 +4,20 @@
 
 #import "PINMemoryCache.h"
 
+#import <pthread.h>
+#import <PINOperation.h>
+
 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
 #import <UIKit/UIKit.h>
 #endif
 
 static NSString * const PINMemoryCachePrefix = @"com.pinterest.PINMemoryCache";
+static NSString * const PINMemoryCacheSharedName = @"PINMemoryCacheSharedName";
 
 @interface PINMemoryCache ()
-#if OS_OBJECT_USE_OBJC
-@property (strong, nonatomic) dispatch_queue_t concurrentQueue;
-@property (strong, nonatomic) dispatch_semaphore_t lockSemaphore;
-#else
-@property (assign, nonatomic) dispatch_queue_t concurrentQueue;
-@property (assign, nonatomic) dispatch_semaphore_t lockSemaphore;
-#endif
+@property (copy, nonatomic) NSString *name;
+@property (strong, nonatomic) PINOperationQueue *operationQueue;
+@property (assign, nonatomic) pthread_mutex_t mutex;
 @property (strong, nonatomic) NSMutableDictionary *dictionary;
 @property (strong, nonatomic) NSMutableDictionary *dates;
 @property (strong, nonatomic) NSMutableDictionary *costs;
@@ -25,9 +25,11 @@ static NSString * const PINMemoryCachePrefix = @"com.pinterest.PINMemoryCache";
 
 @implementation PINMemoryCache
 
+@synthesize name = _name;
 @synthesize ageLimit = _ageLimit;
 @synthesize costLimit = _costLimit;
 @synthesize totalCost = _totalCost;
+@synthesize ttlCache = _ttlCache;
 @synthesize willAddObjectBlock = _willAddObjectBlock;
 @synthesize willRemoveObjectBlock = _willRemoveObjectBlock;
 @synthesize willRemoveAllObjectsBlock = _willRemoveAllObjectsBlock;
@@ -43,65 +45,73 @@ static NSString * const PINMemoryCachePrefix = @"com.pinterest.PINMemoryCache";
 {
     [[NSNotificationCenter defaultCenter] removeObserver:self];
 
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(_concurrentQueue);
-    dispatch_release(_lockSemaphore);
-    _concurrentQueue = nil;
-    #endif
+    __unused int result = pthread_mutex_destroy(&_mutex);
+    NSCAssert(result == 0, @"Failed to destroy lock in PINMemoryCache %p. Code: %d", (void *)self, result);
 }
 
 - (instancetype)init
 {
-    if (self = [super init]) {
-        _lockSemaphore = dispatch_semaphore_create(1);
-        NSString *queueName = [[NSString alloc] initWithFormat:@"%@.%p", PINMemoryCachePrefix, self];
-        _concurrentQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_CONCURRENT);
+    return [self initWithOperationQueue:[PINOperationQueue sharedOperationQueue]];
+}
 
+- (instancetype)initWithOperationQueue:(PINOperationQueue *)operationQueue
+{
+    return [self initWithName:PINMemoryCacheSharedName operationQueue:operationQueue];
+}
+
+- (instancetype)initWithName:(NSString *)name operationQueue:(PINOperationQueue *)operationQueue
+{
+    if (self = [super init]) {
+        __unused int result = pthread_mutex_init(&_mutex, NULL);
+        NSAssert(result == 0, @"Failed to init lock in PINMemoryCache %@. Code: %d", self, result);
+        
+        _name = [name copy];
+        _operationQueue = operationQueue;
+        
         _dictionary = [[NSMutableDictionary alloc] init];
         _dates = [[NSMutableDictionary alloc] init];
         _costs = [[NSMutableDictionary alloc] init];
-
+        
         _willAddObjectBlock = nil;
         _willRemoveObjectBlock = nil;
         _willRemoveAllObjectsBlock = nil;
-
+        
         _didAddObjectBlock = nil;
         _didRemoveObjectBlock = nil;
         _didRemoveAllObjectsBlock = nil;
-
+        
         _didReceiveMemoryWarningBlock = nil;
         _didEnterBackgroundBlock = nil;
-
+        
         _ageLimit = 0.0;
         _costLimit = 0;
         _totalCost = 0;
-
+        
         _removeAllObjectsOnMemoryWarning = YES;
         _removeAllObjectsOnEnteringBackground = YES;
-
-		#if TARGET_OS_IPHONE && defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0 && !TARGET_OS_WATCH
-        for (NSString *name in @[UIApplicationDidReceiveMemoryWarningNotification, UIApplicationDidEnterBackgroundNotification]) {
-            [[NSNotificationCenter defaultCenter] addObserver:self
-                                                     selector:@selector(didObserveApocalypticNotification:)
-                                                         name:name
-#if !defined(PIN_APP_EXTENSIONS)
-                                                       object:[UIApplication sharedApplication]];
-#else
-                                                       object:nil];
+        
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0 && !TARGET_OS_WATCH
+        [[NSNotificationCenter defaultCenter] addObserver:self
+                                                 selector:@selector(didReceiveEnterBackgroundNotification:)
+                                                     name:UIApplicationDidEnterBackgroundNotification
+                                                   object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self
+                                                 selector:@selector(didReceiveMemoryWarningNotification:)
+                                                     name:UIApplicationDidReceiveMemoryWarningNotification
+                                                   object:nil];
+        
 #endif
-        }
-        #endif
     }
     return self;
 }
 
-+ (instancetype)sharedCache
++ (PINMemoryCache *)sharedCache
 {
-    static id cache;
+    static PINMemoryCache *cache;
     static dispatch_once_t predicate;
 
     dispatch_once(&predicate, ^{
-        cache = [[self alloc] init];
+        cache = [[PINMemoryCache alloc] init];
     });
 
     return cache;
@@ -109,51 +119,47 @@ static NSString * const PINMemoryCachePrefix = @"com.pinterest.PINMemoryCache";
 
 #pragma mark - Private Methods -
 
-- (void)didObserveApocalypticNotification:(NSNotification *)notification
+- (void)didReceiveMemoryWarningNotification:(NSNotification *)notification {
+    if (self.removeAllObjectsOnMemoryWarning)
+        [self removeAllObjectsAsync:nil];
+
+    __weak PINMemoryCache *weakSelf = self;
+
+    [self.operationQueue addOperation:^{
+        PINMemoryCache *strongSelf = weakSelf;
+        if (!strongSelf) {
+            return;
+        }
+        
+        [strongSelf lock];
+        PINCacheBlock didReceiveMemoryWarningBlock = strongSelf->_didReceiveMemoryWarningBlock;
+        [strongSelf unlock];
+        
+        if (didReceiveMemoryWarningBlock)
+            didReceiveMemoryWarningBlock(strongSelf);
+    } withPriority:PINOperationQueuePriorityHigh];
+}
+
+- (void)didReceiveEnterBackgroundNotification:(NSNotification *)notification
 {
-    #if TARGET_OS_IPHONE && defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0 && !TARGET_OS_WATCH
+    if (self.removeAllObjectsOnEnteringBackground)
+        [self removeAllObjectsAsync:nil];
 
-    if ([[notification name] isEqualToString:UIApplicationDidReceiveMemoryWarningNotification]) {
-        if (self.removeAllObjectsOnMemoryWarning)
-            [self removeAllObjects:nil];
+    __weak PINMemoryCache *weakSelf = self;
 
-        __weak PINMemoryCache *weakSelf = self;
+    [self.operationQueue addOperation:^{
+        PINMemoryCache *strongSelf = weakSelf;
+        if (!strongSelf) {
+            return;
+        }
 
-        dispatch_async(_concurrentQueue, ^{
-            PINMemoryCache *strongSelf = weakSelf;
-            if (!strongSelf) {
-                return;
-            }
-            
-            [strongSelf lock];
-                PINMemoryCacheBlock didReceiveMemoryWarningBlock = strongSelf->_didReceiveMemoryWarningBlock;
-            [strongSelf unlock];
-            
-            if (didReceiveMemoryWarningBlock)
-                didReceiveMemoryWarningBlock(strongSelf);
-        });
-    } else if ([[notification name] isEqualToString:UIApplicationDidEnterBackgroundNotification]) {
-        if (self.removeAllObjectsOnEnteringBackground)
-            [self removeAllObjects:nil];
-
-        __weak PINMemoryCache *weakSelf = self;
-
-        dispatch_async(_concurrentQueue, ^{
-            PINMemoryCache *strongSelf = weakSelf;
-            if (!strongSelf) {
-                return;
-            }
+        [strongSelf lock];
+            PINCacheBlock didEnterBackgroundBlock = strongSelf->_didEnterBackgroundBlock;
+        [strongSelf unlock];
 
-            [strongSelf lock];
-                PINMemoryCacheBlock didEnterBackgroundBlock = strongSelf->_didEnterBackgroundBlock;
-            [strongSelf unlock];
-            
-            if (didEnterBackgroundBlock)
-                didEnterBackgroundBlock(strongSelf);
-        });
-    }
-    
-    #endif
+        if (didEnterBackgroundBlock)
+            didEnterBackgroundBlock(strongSelf);
+    } withPriority:PINOperationQueuePriorityHigh];
 }
 
 - (void)removeObjectAndExecuteBlocksForKey:(NSString *)key
@@ -161,8 +167,8 @@ static NSString * const PINMemoryCachePrefix = @"com.pinterest.PINMemoryCache";
     [self lock];
         id object = _dictionary[key];
         NSNumber *cost = _costs[key];
-        PINMemoryCacheObjectBlock willRemoveObjectBlock = _willRemoveObjectBlock;
-        PINMemoryCacheObjectBlock didRemoveObjectBlock = _didRemoveObjectBlock;
+        PINCacheObjectBlock willRemoveObjectBlock = _willRemoveObjectBlock;
+        PINCacheObjectBlock didRemoveObjectBlock = _didRemoveObjectBlock;
     [self unlock];
 
     if (willRemoveObjectBlock)
@@ -265,157 +271,206 @@ static NSString * const PINMemoryCachePrefix = @"com.pinterest.PINMemoryCache";
     __weak PINMemoryCache *weakSelf = self;
     
     dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(ageLimit * NSEC_PER_SEC));
-    dispatch_after(time, _concurrentQueue, ^(void){
+    dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
         PINMemoryCache *strongSelf = weakSelf;
-        
-        [strongSelf trimToAgeLimitRecursively];
+        [strongSelf.operationQueue addOperation:^{
+            PINMemoryCache *strongSelf = weakSelf;
+            [strongSelf trimToAgeLimitRecursively];
+        } withPriority:PINOperationQueuePriorityHigh];
     });
 }
 
 #pragma mark - Public Asynchronous Methods -
 
-- (void)objectForKey:(NSString *)key block:(PINMemoryCacheObjectBlock)block
+- (void)containsObjectForKeyAsync:(NSString *)key completion:(PINCacheObjectContainmentBlock)block
+{
+    if (!key || !block)
+        return;
+    
+    __weak PINMemoryCache *weakSelf = self;
+    
+    [self.operationQueue addOperation:^{
+        PINMemoryCache *strongSelf = weakSelf;
+        BOOL containsObject = [strongSelf containsObjectForKey:key];
+        
+        block(containsObject);
+    } withPriority:PINOperationQueuePriorityHigh];
+}
+
+- (void)objectForKeyAsync:(NSString *)key completion:(PINCacheObjectBlock)block
 {
+    if (block == nil) {
+      return;
+    }
     __weak PINMemoryCache *weakSelf = self;
     
-    dispatch_async(_concurrentQueue, ^{
+    [self.operationQueue addOperation:^{
         PINMemoryCache *strongSelf = weakSelf;
         id object = [strongSelf objectForKey:key];
         
-        if (block)
-            block(strongSelf, key, object);
-    });
+        block(strongSelf, key, object);
+    } withPriority:PINOperationQueuePriorityHigh];
 }
 
-- (void)setObject:(id)object forKey:(NSString *)key block:(PINMemoryCacheObjectBlock)block
+- (void)setObjectAsync:(id)object forKey:(NSString *)key completion:(PINCacheObjectBlock)block
 {
-    [self setObject:object forKey:key withCost:0 block:block];
+    [self setObjectAsync:object forKey:key withCost:0 completion:block];
 }
 
-- (void)setObject:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost block:(PINMemoryCacheObjectBlock)block
+- (void)setObjectAsync:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost completion:(PINCacheObjectBlock)block
 {
     __weak PINMemoryCache *weakSelf = self;
     
-    dispatch_async(_concurrentQueue, ^{
+    [self.operationQueue addOperation:^{
         PINMemoryCache *strongSelf = weakSelf;
         [strongSelf setObject:object forKey:key withCost:cost];
         
         if (block)
             block(strongSelf, key, object);
-    });
+    } withPriority:PINOperationQueuePriorityHigh];
 }
 
-- (void)removeObjectForKey:(NSString *)key block:(PINMemoryCacheObjectBlock)block
+- (void)removeObjectForKeyAsync:(NSString *)key completion:(PINCacheObjectBlock)block
 {
     __weak PINMemoryCache *weakSelf = self;
     
-    dispatch_async(_concurrentQueue, ^{
+    [self.operationQueue addOperation:^{
         PINMemoryCache *strongSelf = weakSelf;
         [strongSelf removeObjectForKey:key];
         
         if (block)
             block(strongSelf, key, nil);
-    });
+    } withPriority:PINOperationQueuePriorityHigh];
 }
 
-- (void)trimToDate:(NSDate *)trimDate block:(PINMemoryCacheBlock)block
+- (void)trimToDateAsync:(NSDate *)trimDate completion:(PINCacheBlock)block
 {
     __weak PINMemoryCache *weakSelf = self;
     
-    dispatch_async(_concurrentQueue, ^{
+    [self.operationQueue addOperation:^{
         PINMemoryCache *strongSelf = weakSelf;
         [strongSelf trimToDate:trimDate];
         
         if (block)
             block(strongSelf);
-    });
+    } withPriority:PINOperationQueuePriorityHigh];
 }
 
-- (void)trimToCost:(NSUInteger)cost block:(PINMemoryCacheBlock)block
+- (void)trimToCostAsync:(NSUInteger)cost completion:(PINCacheBlock)block
 {
     __weak PINMemoryCache *weakSelf = self;
     
-    dispatch_async(_concurrentQueue, ^{
+    [self.operationQueue addOperation:^{
         PINMemoryCache *strongSelf = weakSelf;
         [strongSelf trimToCost:cost];
         
         if (block)
             block(strongSelf);
-    });
+    } withPriority:PINOperationQueuePriorityHigh];
 }
 
-- (void)trimToCostByDate:(NSUInteger)cost block:(PINMemoryCacheBlock)block
+- (void)trimToCostByDateAsync:(NSUInteger)cost completion:(PINCacheBlock)block
 {
     __weak PINMemoryCache *weakSelf = self;
     
-    dispatch_async(_concurrentQueue, ^{
+    [self.operationQueue addOperation:^{
         PINMemoryCache *strongSelf = weakSelf;
         [strongSelf trimToCostByDate:cost];
         
         if (block)
             block(strongSelf);
-    });
+    } withPriority:PINOperationQueuePriorityHigh];
 }
 
-- (void)removeAllObjects:(PINMemoryCacheBlock)block
+- (void)removeAllObjectsAsync:(PINCacheBlock)block
 {
     __weak PINMemoryCache *weakSelf = self;
     
-    dispatch_async(_concurrentQueue, ^{
+    [self.operationQueue addOperation:^{
         PINMemoryCache *strongSelf = weakSelf;
         [strongSelf removeAllObjects];
         
         if (block)
             block(strongSelf);
-    });
+    } withPriority:PINOperationQueuePriorityHigh];
 }
 
-- (void)enumerateObjectsWithBlock:(PINMemoryCacheObjectBlock)block completionBlock:(PINMemoryCacheBlock)completionBlock
+- (void)enumerateObjectsWithBlockAsync:(PINCacheObjectBlock)block completionBlock:(PINCacheBlock)completionBlock
 {
     __weak PINMemoryCache *weakSelf = self;
     
-    dispatch_async(_concurrentQueue, ^{
+    [self.operationQueue addOperation:^{
         PINMemoryCache *strongSelf = weakSelf;
         [strongSelf enumerateObjectsWithBlock:block];
         
         if (completionBlock)
             completionBlock(strongSelf);
-    });
+    } withPriority:PINOperationQueuePriorityHigh];
 }
 
 #pragma mark - Public Synchronous Methods -
 
-- (__nullable id)objectForKey:(NSString *)key
+- (BOOL)containsObjectForKey:(NSString *)key
+{
+    if (!key)
+        return NO;
+    
+    [self lock];
+        BOOL containsObject = (_dictionary[key] != nil);
+    [self unlock];
+    return containsObject;
+}
+
+- (nullable id)objectForKey:(NSString *)key
 {
     if (!key)
         return nil;
     
+    NSDate *now = [[NSDate alloc] init];
     [self lock];
-        id object = _dictionary[key];
+        id object = nil;
+        // If the cache should behave like a TTL cache, then only fetch the object if there's a valid ageLimit and  the object is still alive
+        if (!self->_ttlCache || self->_ageLimit <= 0 || fabs([[_dates objectForKey:key] timeIntervalSinceDate:now]) < self->_ageLimit) {
+            object = _dictionary[key];
+        }
     [self unlock];
         
     if (object) {
         [self lock];
-            _dates[key] = [[NSDate alloc] init];
+            _dates[key] = now;
         [self unlock];
     }
 
     return object;
 }
 
+- (id)objectForKeyedSubscript:(NSString *)key
+{
+    return [self objectForKey:key];
+}
+
 - (void)setObject:(id)object forKey:(NSString *)key
 {
     [self setObject:object forKey:key withCost:0];
 }
 
+- (void)setObject:(id)object forKeyedSubscript:(NSString *)key
+{
+    if (object == nil) {
+        [self removeObjectForKey:key];
+    } else {
+        [self setObject:object forKey:key];
+    }
+}
+
 - (void)setObject:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost
 {
     if (!key || !object)
         return;
     
     [self lock];
-        PINMemoryCacheObjectBlock willAddObjectBlock = _willAddObjectBlock;
-        PINMemoryCacheObjectBlock didAddObjectBlock = _didAddObjectBlock;
+        PINCacheObjectBlock willAddObjectBlock = _willAddObjectBlock;
+        PINCacheObjectBlock didAddObjectBlock = _didAddObjectBlock;
         NSUInteger costLimit = _costLimit;
     [self unlock];
     
@@ -423,6 +478,10 @@ static NSString * const PINMemoryCachePrefix = @"com.pinterest.PINMemoryCache";
         willAddObjectBlock(self, key, object);
     
     [self lock];
+        NSNumber* oldCost = _costs[key];
+        if (oldCost)
+            _totalCost -= [oldCost unsignedIntegerValue];
+
         _dictionary[key] = object;
         _dates[key] = [[NSDate alloc] init];
         _costs[key] = @(cost);
@@ -471,8 +530,8 @@ static NSString * const PINMemoryCachePrefix = @"com.pinterest.PINMemoryCache";
 - (void)removeAllObjects
 {
     [self lock];
-        PINMemoryCacheBlock willRemoveAllObjectsBlock = _willRemoveAllObjectsBlock;
-        PINMemoryCacheBlock didRemoveAllObjectsBlock = _didRemoveAllObjectsBlock;
+        PINCacheBlock willRemoveAllObjectsBlock = _willRemoveAllObjectsBlock;
+        PINCacheBlock didRemoveAllObjectsBlock = _didRemoveAllObjectsBlock;
     [self unlock];
     
     if (willRemoveAllObjectsBlock)
@@ -491,144 +550,148 @@ static NSString * const PINMemoryCachePrefix = @"com.pinterest.PINMemoryCache";
     
 }
 
-- (void)enumerateObjectsWithBlock:(PINMemoryCacheObjectBlock)block
+- (void)enumerateObjectsWithBlock:(PINCacheObjectBlock)block
 {
     if (!block)
         return;
     
     [self lock];
+        NSDate *now = [[NSDate alloc] init];
         NSArray *keysSortedByDate = [_dates keysSortedByValueUsingSelector:@selector(compare:)];
         
         for (NSString *key in keysSortedByDate) {
-            block(self, key, _dictionary[key]);
+            // If the cache should behave like a TTL cache, then only fetch the object if there's a valid ageLimit and  the object is still alive
+            if (!self->_ttlCache || self->_ageLimit <= 0 || fabs([[_dates objectForKey:key] timeIntervalSinceDate:now]) < self->_ageLimit) {
+                block(self, key, _dictionary[key]);
+            }
         }
     [self unlock];
 }
 
 #pragma mark - Public Thread Safe Accessors -
 
-- (PINMemoryCacheObjectBlock)willAddObjectBlock
+- (PINCacheObjectBlock)willAddObjectBlock
 {
     [self lock];
-        PINMemoryCacheObjectBlock block = _willAddObjectBlock;
+        PINCacheObjectBlock block = _willAddObjectBlock;
     [self unlock];
 
     return block;
 }
 
-- (void)setWillAddObjectBlock:(PINMemoryCacheObjectBlock)block
+- (void)setWillAddObjectBlock:(PINCacheObjectBlock)block
 {
     [self lock];
         _willAddObjectBlock = [block copy];
     [self unlock];
 }
 
-- (PINMemoryCacheObjectBlock)willRemoveObjectBlock
+- (PINCacheObjectBlock)willRemoveObjectBlock
 {
     [self lock];
-        PINMemoryCacheObjectBlock block = _willRemoveObjectBlock;
+        PINCacheObjectBlock block = _willRemoveObjectBlock;
     [self unlock];
 
     return block;
 }
 
-- (void)setWillRemoveObjectBlock:(PINMemoryCacheObjectBlock)block
+- (void)setWillRemoveObjectBlock:(PINCacheObjectBlock)block
 {
     [self lock];
         _willRemoveObjectBlock = [block copy];
     [self unlock];
 }
 
-- (PINMemoryCacheBlock)willRemoveAllObjectsBlock
+- (PINCacheBlock)willRemoveAllObjectsBlock
 {
     [self lock];
-        PINMemoryCacheBlock block = _willRemoveAllObjectsBlock;
+        PINCacheBlock block = _willRemoveAllObjectsBlock;
     [self unlock];
 
     return block;
 }
 
-- (void)setWillRemoveAllObjectsBlock:(PINMemoryCacheBlock)block
+- (void)setWillRemoveAllObjectsBlock:(PINCacheBlock)block
 {
     [self lock];
         _willRemoveAllObjectsBlock = [block copy];
     [self unlock];
 }
 
-- (PINMemoryCacheObjectBlock)didAddObjectBlock
+- (PINCacheObjectBlock)didAddObjectBlock
 {
     [self lock];
-        PINMemoryCacheObjectBlock block = _didAddObjectBlock;
+        PINCacheObjectBlock block = _didAddObjectBlock;
     [self unlock];
 
     return block;
 }
 
-- (void)setDidAddObjectBlock:(PINMemoryCacheObjectBlock)block
+- (void)setDidAddObjectBlock:(PINCacheObjectBlock)block
 {
     [self lock];
         _didAddObjectBlock = [block copy];
     [self unlock];
 }
 
-- (PINMemoryCacheObjectBlock)didRemoveObjectBlock
+- (PINCacheObjectBlock)didRemoveObjectBlock
 {
     [self lock];
-        PINMemoryCacheObjectBlock block = _didRemoveObjectBlock;
+        PINCacheObjectBlock block = _didRemoveObjectBlock;
     [self unlock];
 
     return block;
 }
 
-- (void)setDidRemoveObjectBlock:(PINMemoryCacheObjectBlock)block
+- (void)setDidRemoveObjectBlock:(PINCacheObjectBlock)block
 {
     [self lock];
         _didRemoveObjectBlock = [block copy];
     [self unlock];
 }
 
-- (PINMemoryCacheBlock)didRemoveAllObjectsBlock
+- (PINCacheBlock)didRemoveAllObjectsBlock
 {
     [self lock];
-        PINMemoryCacheBlock block = _didRemoveAllObjectsBlock;
+        PINCacheBlock block = _didRemoveAllObjectsBlock;
     [self unlock];
 
     return block;
 }
 
-- (void)setDidRemoveAllObjectsBlock:(PINMemoryCacheBlock)block
+- (void)setDidRemoveAllObjectsBlock:(PINCacheBlock)block
 {
     [self lock];
         _didRemoveAllObjectsBlock = [block copy];
     [self unlock];
 }
 
-- (PINMemoryCacheBlock)didReceiveMemoryWarningBlock
+- (PINCacheBlock)didReceiveMemoryWarningBlock
 {
     [self lock];
-        PINMemoryCacheBlock block = _didReceiveMemoryWarningBlock;
+        PINCacheBlock block = _didReceiveMemoryWarningBlock;
     [self unlock];
 
     return block;
 }
 
-- (void)setDidReceiveMemoryWarningBlock:(PINMemoryCacheBlock)block
+- (void)setDidReceiveMemoryWarningBlock:(PINCacheBlock)block
 {
     [self lock];
         _didReceiveMemoryWarningBlock = [block copy];
     [self unlock];
 }
 
-- (PINMemoryCacheBlock)didEnterBackgroundBlock
+- (PINCacheBlock)didEnterBackgroundBlock
 {
     [self lock];
-        PINMemoryCacheBlock block = _didEnterBackgroundBlock;
+        PINCacheBlock block = _didEnterBackgroundBlock;
     [self unlock];
 
     return block;
 }
 
-- (void)setDidEnterBackgroundBlock:(PINMemoryCacheBlock)block
+- (void)setDidEnterBackgroundBlock:(PINCacheBlock)block
 {
     [self lock];
         _didEnterBackgroundBlock = [block copy];
@@ -681,14 +744,90 @@ static NSString * const PINMemoryCachePrefix = @"com.pinterest.PINMemoryCache";
     return cost;
 }
 
+- (BOOL)isTTLCache {
+    BOOL isTTLCache;
+    
+    [self lock];
+        isTTLCache = _ttlCache;
+    [self unlock];
+    
+    return isTTLCache;
+}
+
+- (void)setTtlCache:(BOOL)ttlCache {
+    [self lock];
+        _ttlCache = ttlCache;
+    [self unlock];
+}
+
+
 - (void)lock
 {
-    dispatch_semaphore_wait(_lockSemaphore, DISPATCH_TIME_FOREVER);
+    __unused int result = pthread_mutex_lock(&_mutex);
+    NSAssert(result == 0, @"Failed to lock PINMemoryCache %@. Code: %d", self, result);
 }
 
 - (void)unlock
 {
-    dispatch_semaphore_signal(_lockSemaphore);
+    __unused int result = pthread_mutex_unlock(&_mutex);
+    NSAssert(result == 0, @"Failed to unlock PINMemoryCache %@. Code: %d", self, result);
+}
+
+@end
+
+
+#pragma mark - Deprecated
+
+@implementation PINMemoryCache (Deprecated)
+
+- (void)containsObjectForKey:(NSString *)key block:(PINMemoryCacheContainmentBlock)block
+{
+    [self containsObjectForKeyAsync:key completion:block];
+}
+
+- (void)objectForKey:(NSString *)key block:(nullable PINMemoryCacheObjectBlock)block
+{
+    [self objectForKeyAsync:key completion:block];
+}
+
+- (void)setObject:(id)object forKey:(NSString *)key block:(nullable PINMemoryCacheObjectBlock)block
+{
+    [self setObjectAsync:object forKey:key completion:block];
+}
+
+- (void)setObject:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost block:(nullable PINMemoryCacheObjectBlock)block
+{
+    [self setObjectAsync:object forKey:key withCost:cost completion:block];
+}
+
+- (void)removeObjectForKey:(NSString *)key block:(nullable PINMemoryCacheObjectBlock)block
+{
+    [self removeObjectForKeyAsync:key completion:block];
+}
+
+- (void)trimToDate:(NSDate *)date block:(nullable PINMemoryCacheBlock)block
+{
+    [self trimToDateAsync:date completion:block];
+}
+
+- (void)trimToCost:(NSUInteger)cost block:(nullable PINMemoryCacheBlock)block
+{
+    [self trimToCostAsync:cost completion:block];
+}
+
+- (void)trimToCostByDate:(NSUInteger)cost block:(nullable PINMemoryCacheBlock)block
+{
+    [self trimToCostByDateAsync:cost completion:block];
+}
+
+- (void)removeAllObjects:(nullable PINMemoryCacheBlock)block
+{
+    [self removeAllObjectsAsync:block];
+}
+
+- (void)enumerateObjectsWithBlock:(PINMemoryCacheObjectBlock)block completionBlock:(nullable PINMemoryCacheBlock)completionBlock
+{
+    [self enumerateObjectsWithBlockAsync:block completionBlock:completionBlock];
 }
 
 @end

+ 12 - 0
Benchmark/Vendor/PINCache/PINOperation/PINOperation.h

@@ -0,0 +1,12 @@
+//
+//  PINOperation.h
+//  PINOperation
+//
+//  Created by Adlai Holler on 1/10/17.
+//  Copyright © 2017 Pinterest. All rights reserved.
+//
+
+#import <PINOperation/PINOperationMacros.h>
+#import <PINOperation/PINOperationTypes.h>
+#import <PINOperation/PINOperationQueue.h>
+#import <PINOperation/PINOperationGroup.h>

+ 38 - 0
Benchmark/Vendor/PINCache/PINOperation/PINOperationGroup.h

@@ -0,0 +1,38 @@
+//
+//  PINOperationGroup.h
+//  PINQueue
+//
+//  Created by Garrett Moon on 10/8/16.
+//  Copyright © 2016 Pinterest. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "PINOperationTypes.h"
+#import "PINOperationMacros.h"
+
+@class PINOperationQueue;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol PINGroupOperationReference;
+
+PINOP_SUBCLASSING_RESTRICTED
+@interface PINOperationGroup : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
++ (instancetype)asyncOperationGroupWithQueue:(PINOperationQueue *)operationQueue;
+
+- (nullable id <PINGroupOperationReference>)addOperation:(dispatch_block_t)operation;
+- (nullable id <PINGroupOperationReference>)addOperation:(dispatch_block_t)operation withPriority:(PINOperationQueuePriority)priority;
+- (void)start;
+- (void)cancel;
+- (void)setCompletion:(dispatch_block_t)completion;
+- (void)waitUntilComplete;
+
+@end
+
+@protocol PINGroupOperationReference <NSObject>
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 187 - 0
Benchmark/Vendor/PINCache/PINOperation/PINOperationGroup.m

@@ -0,0 +1,187 @@
+//
+//  PINOperationGroup.m
+//  PINQueue
+//
+//  Created by Garrett Moon on 10/8/16.
+//  Copyright © 2016 Pinterest. All rights reserved.
+//
+
+#import "PINOperationGroup.h"
+#import "PINOperation.h"
+#import <pthread.h>
+
+@interface NSNumber (PINGroupOperationQueue) <PINGroupOperationReference>
+@end
+
+@interface PINOperationGroup ()
+{
+  pthread_mutex_t _lock;
+  
+  PINOperationQueue *_operationQueue;
+  NSMutableArray <dispatch_block_t> *_operations;
+  NSMutableArray <NSNumber *> *_operationPriorities;
+  NSMutableArray <id <PINGroupOperationReference>> *_operationReferences;
+  NSMapTable <id <PINGroupOperationReference>, id <PINOperationReference>> *_groupToOperationReferences;
+  NSUInteger _operationReferenceCount;
+  
+  dispatch_group_t _group;
+  
+  dispatch_block_t _completion;
+  
+  BOOL _started;
+  BOOL _canceled;
+}
+
+- (instancetype)initWithOperationQueue:(PINOperationQueue *)operationQueue NS_DESIGNATED_INITIALIZER;
+
+@end
+
+@implementation PINOperationGroup
+
+- (instancetype)initWithOperationQueue:(PINOperationQueue *)operationQueue
+{
+  if (self = [super init]) {
+    pthread_mutex_init(&_lock, NULL);
+    
+    _operationQueue = operationQueue;
+    
+    _operations = [[NSMutableArray alloc] init];
+    _operationReferences = [[NSMutableArray alloc] init];
+    _operationPriorities = [[NSMutableArray alloc] init];
+    
+    _groupToOperationReferences = [NSMapTable weakToStrongObjectsMapTable];
+    _group = dispatch_group_create();
+  }
+  return self;
+}
+
+- (void)dealloc
+{
+  pthread_mutex_destroy(&_lock);
+}
+
++ (instancetype)asyncOperationGroupWithQueue:(PINOperationQueue *)operationQueue
+{
+  return [[self alloc] initWithOperationQueue:operationQueue];
+}
+
+- (id <PINGroupOperationReference>)locked_nextOperationReference
+{
+  id <PINGroupOperationReference> reference = [NSNumber numberWithUnsignedInteger:++_operationReferenceCount];
+  return reference;
+}
+
+- (void)start
+{
+  [self lock];
+    NSAssert(_canceled == NO, @"Operation group canceled.");
+    if (_started == NO && _canceled == NO) {
+      for (NSUInteger idx = 0; idx < _operations.count; idx++) {
+        dispatch_group_enter(_group);
+        dispatch_block_t originalOperation = _operations[idx];
+        dispatch_block_t groupBlock = ^{
+          originalOperation();
+          dispatch_group_leave(_group);
+        };
+        
+        id <PINOperationReference> operationReference = [_operationQueue addOperation:groupBlock withPriority:[_operationPriorities[idx] unsignedIntegerValue]];
+        [_groupToOperationReferences setObject:operationReference forKey:_operationReferences[idx]];
+      }
+      
+      if (_completion) {
+        dispatch_queue_t completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+        dispatch_group_notify(_group, completionQueue, ^{
+          [self runCompletionIfNeeded];
+        });
+      }
+      
+      _operations = nil;
+      _operationPriorities = nil;
+      _operationReferences = nil;
+    }
+  [self unlock];
+}
+
+- (void)cancel
+{
+  [self lock];
+    _canceled = YES;
+  
+    for (id <PINOperationReference>operationReference in [_groupToOperationReferences objectEnumerator]) {
+      if ([_operationQueue cancelOperation:operationReference]) {
+        dispatch_group_leave(_group);
+      }
+    }
+  
+    //TODO just nil out instead? Does it make sense to support adding operations after cancelation?
+    [_groupToOperationReferences removeAllObjects];
+    [_operations removeAllObjects];
+    [_operationPriorities removeAllObjects];
+    [_operationReferences removeAllObjects];
+    
+    _completion = nil;
+  [self unlock];
+}
+
+- (id <PINGroupOperationReference>)addOperation:(dispatch_block_t)operation
+{
+  return [self addOperation:operation withPriority:PINOperationQueuePriorityDefault];
+}
+
+- (id <PINGroupOperationReference>)addOperation:(dispatch_block_t)operation withPriority:(PINOperationQueuePriority)priority
+{
+  [self lock];
+    id <PINGroupOperationReference> reference = nil;
+    NSAssert(_started == NO && _canceled == NO, @"Operation group already started or canceled.");
+    if (_started == NO && _canceled == NO) {
+      reference = [self locked_nextOperationReference];
+      [_operations addObject:operation];
+      [_operationPriorities addObject:@(priority)];
+      [_operationReferences addObject:reference];
+    }
+  [self unlock];
+  
+  return reference;
+}
+
+- (void)setCompletion:(dispatch_block_t)completion
+{
+  [self lock];
+    NSAssert(_started == NO && _canceled == NO, @"Operation group already started or canceled.");
+    if (_started == NO && _canceled == NO) {
+      _completion = completion;
+    }
+  [self unlock];
+}
+
+- (void)waitUntilComplete
+{
+  [self start];
+  dispatch_group_wait(_group, DISPATCH_TIME_FOREVER);
+  [self runCompletionIfNeeded];
+}
+
+- (void)runCompletionIfNeeded
+{
+  dispatch_block_t completion;
+  [self lock];
+    completion = _completion;
+    _completion = nil;
+  [self unlock];
+
+  if (completion) {
+    completion();
+  }
+}
+
+- (void)lock
+{
+  pthread_mutex_lock(&_lock);
+}
+
+- (void)unlock
+{
+  pthread_mutex_unlock(&_lock);
+}
+
+@end

+ 15 - 0
Benchmark/Vendor/PINCache/PINOperation/PINOperationMacros.h

@@ -0,0 +1,15 @@
+//
+//  PINOperationMacros.h
+//  PINOperation
+//
+//  Created by Adlai Holler on 1/10/17.
+//  Copyright © 2017 Pinterest. All rights reserved.
+//
+
+#ifndef PINOP_SUBCLASSING_RESTRICTED
+#if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted)
+#define PINOP_SUBCLASSING_RESTRICTED __attribute__((objc_subclassing_restricted))
+#else
+#define PINOP_SUBCLASSING_RESTRICTED
+#endif // #if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted)
+#endif // #ifndef PINOP_SUBCLASSING_RESTRICTED

+ 132 - 0
Benchmark/Vendor/PINCache/PINOperation/PINOperationQueue.h

@@ -0,0 +1,132 @@
+//
+//  PINOperationQueue.h
+//  Pods
+//
+//  Created by Garrett Moon on 8/23/16.
+//
+//
+
+#import <Foundation/Foundation.h>
+#import "PINOperationTypes.h"
+#import "PINOperationMacros.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef void(^PINOperationBlock)(id _Nullable data);
+typedef _Nullable id(^PINOperationDataCoalescingBlock)(id _Nullable existingData, id _Nullable newData);
+
+@protocol PINOperationReference;
+
+PINOP_SUBCLASSING_RESTRICTED
+@interface PINOperationQueue : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ * Initializes and returns a newly allocated operation queue with the specified number of maximum concurrent operations.
+ *
+ * @param maxConcurrentOperations The maximum number of queued operations that can execute at the same time.
+ *
+ */
+- (instancetype)initWithMaxConcurrentOperations:(NSUInteger)maxConcurrentOperations;
+
+/**
+ * Initializes and returns a newly allocated operation queue with the specified number of maximum concurrent operations and the concurrent queue they will be scheduled on.
+ *
+ * @param maxConcurrentOperations The maximum number of queued operations that can execute at the same time.
+ * @param concurrentQueue The operation queue to schedule concurrent operations
+ *
+ */
+- (instancetype)initWithMaxConcurrentOperations:(NSUInteger)maxConcurrentOperations concurrentQueue:(dispatch_queue_t)concurrentQueue NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Returns the shared instance of the PINOperationQueue class.
+ */
++ (instancetype)sharedOperationQueue;
+
+/**
+ * Adds the specified operation object to the receiver.
+ *
+ * @param operation The operation object to be added to the queue.
+ *
+ */
+- (id <PINOperationReference>)addOperation:(dispatch_block_t)operation;
+
+/**
+ * Adds the specified operation object to the receiver.
+ *
+ * @param operation The operation object to be added to the queue.
+ * @param priority The execution priority of the operation in an operation queue.
+ *
+ * @discussion
+ */
+- (id <PINOperationReference>)addOperation:(dispatch_block_t)operation withPriority:(PINOperationQueuePriority)priority;
+
+/**
+ * Adds the specified operation object to the receiver.
+ *
+ * @param operation The operation object to be added to the queue.
+ * @param priority The execution priority of the operation in an operation queue.
+ * @param identifier A string that identifies the operations that can be coalesced.
+ * @param coalescingData The optional data consumed by this operation that needs to be updated/coalesced with data of a new operation when coalescing the two operations happens.
+ * @param dataCoalescingBlock The optional block called to update/coalesce the data of this operation with data of a new operation when coalescing the two operations happens.
+ * @param completion The block to execute after the operation finished.
+ *
+ * @discussion
+ */
+- (id <PINOperationReference>)addOperation:(PINOperationBlock)operation
+                              withPriority:(PINOperationQueuePriority)priority
+                                identifier:(nullable NSString *)identifier
+                            coalescingData:(nullable id)coalescingData
+                       dataCoalescingBlock:(nullable PINOperationDataCoalescingBlock)dataCoalescingBlock
+                                completion:(nullable dispatch_block_t)completion;
+
+/**
+ * The maximum number of queued operations that can execute at the same time.
+ *
+ * @discussion The value in this property affects only the operations that the current queue has executing at the same time. Other operation queues can also execute their maximum number of operations in parallel.
+ * Reducing the number of concurrent operations does not affect any operations that are currently executing.
+ *
+ * Setting this value to 1 the operations will not be processed by priority as the operations will processed in a FIFO order to prevent deadlocks if operations depend on certain other operations to run in order.
+ *
+ */
+@property (assign) NSUInteger maxConcurrentOperations;
+
+/**
+ * Marks the operation as cancelled
+ */
+- (BOOL)cancelOperation:(id <PINOperationReference>)operationReference;
+
+/**
+ * Cancels all queued operations
+ */
+- (void)cancelAllOperations;
+
+/**
+ * Blocks the current thread until all of the receiver’s queued and executing operations finish executing.
+ *
+ * @discussion When called, this method blocks the current thread and waits for the receiver’s current and queued
+ * operations to finish executing. While the current thread is blocked, the receiver continues to launch already
+ * queued operations and monitor those that are executing.
+ *
+ * @warning This should never be called from within an operation submitted to the PINOperationQueue as this will result
+ * in a deadlock.
+ */
+- (void)waitUntilAllOperationsAreFinished;
+
+/**
+ * Sets the priority for a operation via it's reference
+ *
+ * @param priority The new priority for the operation
+ * @param reference The reference for the operation
+ *
+ */
+- (void)setOperationPriority:(PINOperationQueuePriority)priority withReference:(id <PINOperationReference>)reference;
+
+@end
+
+@protocol PINOperationReference <NSObject>
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 442 - 0
Benchmark/Vendor/PINCache/PINOperation/PINOperationQueue.m

@@ -0,0 +1,442 @@
+//
+//  PINOperationQueue.m
+//  Pods
+//
+//  Created by Garrett Moon on 8/23/16.
+//
+//
+
+#import "PINOperationQueue.h"
+#import <pthread.h>
+
+@class PINOperation;
+
+@interface NSNumber (PINOperationQueue) <PINOperationReference>
+
+@end
+
+@interface PINOperationQueue () {
+  pthread_mutex_t _lock;
+  //increments with every operation to allow cancelation
+  NSUInteger _operationReferenceCount;
+  NSUInteger _maxConcurrentOperations;
+  
+  dispatch_group_t _group;
+  
+  dispatch_queue_t _serialQueue;
+  BOOL _serialQueueBusy;
+  
+  dispatch_semaphore_t _concurrentSemaphore;
+  dispatch_queue_t _concurrentQueue;
+  dispatch_queue_t _semaphoreQueue;
+  
+  NSMutableOrderedSet<PINOperation *> *_queuedOperations;
+  NSMutableOrderedSet<PINOperation *> *_lowPriorityOperations;
+  NSMutableOrderedSet<PINOperation *> *_defaultPriorityOperations;
+  NSMutableOrderedSet<PINOperation *> *_highPriorityOperations;
+  
+  NSMapTable<id<PINOperationReference>, PINOperation *> *_referenceToOperations;
+  NSMapTable<NSString *, PINOperation *> *_identifierToOperations;
+}
+
+@end
+
+@interface PINOperation : NSObject
+
+@property (nonatomic, strong) PINOperationBlock block;
+@property (nonatomic, strong) id <PINOperationReference> reference;
+@property (nonatomic, assign) PINOperationQueuePriority priority;
+@property (nonatomic, strong) NSMutableArray<dispatch_block_t> *completions;
+@property (nonatomic, strong) NSString *identifier;
+@property (nonatomic, strong) id data;
+
++ (instancetype)operationWithBlock:(PINOperationBlock)block reference:(id <PINOperationReference>)reference priority:(PINOperationQueuePriority)priority identifier:(nullable NSString *)identifier data:(nullable id)data completion:(nullable dispatch_block_t)completion;
+
+- (void)addCompletion:(nullable dispatch_block_t)completion;
+
+@end
+
+@implementation PINOperation
+
++ (instancetype)operationWithBlock:(PINOperationBlock)block reference:(id<PINOperationReference>)reference priority:(PINOperationQueuePriority)priority identifier:(NSString *)identifier data:(id)data completion:(dispatch_block_t)completion
+{
+  PINOperation *operation = [[self alloc] init];
+  operation.block = block;
+  operation.reference = reference;
+  operation.priority = priority;
+  operation.identifier = identifier;
+  operation.data = data;
+  [operation addCompletion:completion];
+  
+  return operation;
+}
+
+- (void)addCompletion:(dispatch_block_t)completion
+{
+  if (completion == nil) {
+    return;
+  }
+  if (_completions == nil) {
+    _completions = [NSMutableArray array];
+  }
+  [_completions addObject:completion];
+}
+
+@end
+
+@implementation PINOperationQueue
+
+- (instancetype)initWithMaxConcurrentOperations:(NSUInteger)maxConcurrentOperations
+{
+  return [self initWithMaxConcurrentOperations:maxConcurrentOperations concurrentQueue:dispatch_queue_create("PINOperationQueue Concurrent Queue", DISPATCH_QUEUE_CONCURRENT)];
+}
+
+- (instancetype)initWithMaxConcurrentOperations:(NSUInteger)maxConcurrentOperations concurrentQueue:(dispatch_queue_t)concurrentQueue
+{
+  if (self = [super init]) {
+    NSAssert(maxConcurrentOperations > 0, @"Max concurrent operations must be greater than 0.");
+    _maxConcurrentOperations = maxConcurrentOperations;
+    _operationReferenceCount = 0;
+    
+    pthread_mutexattr_t attr;
+    pthread_mutexattr_init(&attr);
+    //mutex must be recursive to allow scheduling of operations from within operations
+    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+    pthread_mutex_init(&_lock, &attr);
+    
+    _group = dispatch_group_create();
+    
+    _serialQueue = dispatch_queue_create("PINOperationQueue Serial Queue", DISPATCH_QUEUE_SERIAL);
+    
+    _concurrentQueue = concurrentQueue;
+    
+    //Create a queue with max - 1 because this plus the serial queue add up to max.
+    _concurrentSemaphore = dispatch_semaphore_create(_maxConcurrentOperations - 1);
+    _semaphoreQueue = dispatch_queue_create("PINOperationQueue Serial Semaphore Queue", DISPATCH_QUEUE_SERIAL);
+    
+    _queuedOperations = [[NSMutableOrderedSet alloc] init];
+    _lowPriorityOperations = [[NSMutableOrderedSet alloc] init];
+    _defaultPriorityOperations = [[NSMutableOrderedSet alloc] init];
+    _highPriorityOperations = [[NSMutableOrderedSet alloc] init];
+    
+    _referenceToOperations = [NSMapTable weakToWeakObjectsMapTable];
+    _identifierToOperations = [NSMapTable weakToWeakObjectsMapTable];
+  }
+  return self;
+}
+
+- (void)dealloc
+{
+  pthread_mutex_destroy(&_lock);
+}
+
++ (instancetype)sharedOperationQueue
+{
+    static PINOperationQueue *sharedOperationQueue = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        sharedOperationQueue = [[PINOperationQueue alloc] initWithMaxConcurrentOperations:MAX([[NSProcessInfo processInfo] activeProcessorCount], 2)];
+    });
+    return sharedOperationQueue;
+}
+
+- (id <PINOperationReference>)nextOperationReference
+{
+  [self lock];
+    id <PINOperationReference> reference = [NSNumber numberWithUnsignedInteger:++_operationReferenceCount];
+  [self unlock];
+  return reference;
+}
+
+- (id <PINOperationReference>)addOperation:(dispatch_block_t)block
+{
+  return [self addOperation:block withPriority:PINOperationQueuePriorityDefault];
+}
+
+- (id <PINOperationReference>)addOperation:(dispatch_block_t)block withPriority:(PINOperationQueuePriority)priority
+{
+  PINOperation *operation = [PINOperation operationWithBlock:^(id data) { block(); }
+                                                   reference:[self nextOperationReference]
+                                                    priority:priority
+                                                  identifier:nil
+                                                        data:nil
+                                                  completion:nil];
+  [self lock];
+    [self locked_addOperation:operation];
+  [self unlock];
+  
+  [self scheduleNextOperations:NO];
+  
+  return operation.reference;
+}
+
+- (id<PINOperationReference>)addOperation:(PINOperationBlock)block
+                             withPriority:(PINOperationQueuePriority)priority
+                               identifier:(NSString *)identifier
+                           coalescingData:(id)coalescingData
+                      dataCoalescingBlock:(PINOperationDataCoalescingBlock)dataCoalescingBlock
+                               completion:(dispatch_block_t)completion
+{
+  id<PINOperationReference> reference = nil;
+  BOOL isNewOperation = NO;
+  
+  [self lock];
+    PINOperation *operation = nil;
+    if (identifier != nil && (operation = [_identifierToOperations objectForKey:identifier]) != nil) {
+      // There is an exisiting operation with the provided identifier, let's coalesce these operations
+      if (dataCoalescingBlock != nil) {
+        operation.data = dataCoalescingBlock(operation.data, coalescingData);
+      }
+      
+      [operation addCompletion:completion];
+    } else {
+      isNewOperation = YES;
+      operation = [PINOperation operationWithBlock:block
+                                         reference:[self nextOperationReference]
+                                          priority:priority
+                                        identifier:identifier
+                                              data:coalescingData
+                                        completion:completion];
+      [self locked_addOperation:operation];
+    }
+    reference = operation.reference;
+  [self unlock];
+  
+  if (isNewOperation) {
+    [self scheduleNextOperations:NO];
+  }
+  
+  return reference;
+}
+
+- (void)locked_addOperation:(PINOperation *)operation
+{
+  NSMutableOrderedSet *queue = [self operationQueueWithPriority:operation.priority];
+  
+  dispatch_group_enter(_group);
+  [queue addObject:operation];
+  [_queuedOperations addObject:operation];
+  [_referenceToOperations setObject:operation forKey:operation.reference];
+  if (operation.identifier != nil) {
+    [_identifierToOperations setObject:operation forKey:operation.identifier];
+  }
+}
+
+- (void)cancelAllOperations
+{
+  [self lock];
+    for (PINOperation *operation in [[_referenceToOperations copy] objectEnumerator]) {
+      [self locked_cancelOperation:operation.reference];
+    }
+  [self unlock];
+}
+
+
+- (BOOL)cancelOperation:(id <PINOperationReference>)operationReference
+{
+  [self lock];
+    BOOL success = [self locked_cancelOperation:operationReference];
+  [self unlock];
+  return success;
+}
+
+- (NSUInteger)maxConcurrentOperations
+{
+  [self lock];
+    NSUInteger maxConcurrentOperations = _maxConcurrentOperations;
+  [self unlock];
+  return maxConcurrentOperations;
+}
+
+- (void)setMaxConcurrentOperations:(NSUInteger)maxConcurrentOperations
+{
+  NSAssert(maxConcurrentOperations > 0, @"Max concurrent operations must be greater than 0.");
+  [self lock];
+    __block NSInteger difference = maxConcurrentOperations - _maxConcurrentOperations;
+    _maxConcurrentOperations = maxConcurrentOperations;
+  [self unlock];
+  
+  if (difference == 0) {
+    return;
+  }
+  
+  dispatch_async(_semaphoreQueue, ^{
+    while (difference != 0) {
+      if (difference > 0) {
+        dispatch_semaphore_signal(_concurrentSemaphore);
+        difference--;
+      } else {
+        dispatch_semaphore_wait(_concurrentSemaphore, DISPATCH_TIME_FOREVER);
+        difference++;
+      }
+    }
+  });
+}
+
+#pragma mark - private methods
+
+- (BOOL)locked_cancelOperation:(id <PINOperationReference>)operationReference
+{
+  BOOL success = NO;
+  PINOperation *operation = [_referenceToOperations objectForKey:operationReference];
+  if (operation) {
+    NSMutableOrderedSet *queue = [self operationQueueWithPriority:operation.priority];
+    if ([queue containsObject:operation]) {
+      success = YES;
+      [queue removeObject:operation];
+      [_queuedOperations removeObject:operation];
+      dispatch_group_leave(_group);
+    }
+  }
+  return success;
+}
+
+- (void)setOperationPriority:(PINOperationQueuePriority)priority withReference:(id <PINOperationReference>)operationReference
+{
+  [self lock];
+    PINOperation *operation = [_referenceToOperations objectForKey:operationReference];
+    if (operation && operation.priority != priority) {
+      NSMutableOrderedSet *oldQueue = [self operationQueueWithPriority:operation.priority];
+      [oldQueue removeObject:operation];
+      
+      operation.priority = priority;
+      
+      NSMutableOrderedSet *queue = [self operationQueueWithPriority:priority];
+      [queue addObject:operation];
+    }
+  [self unlock];
+}
+
+/**
+ Schedule next operations schedules the next operation by queue order onto the serial queue if
+ it's available and one operation by priority order onto the concurrent queue.
+ */
+- (void)scheduleNextOperations:(BOOL)onlyCheckSerial
+{
+  [self lock];
+  
+    //get next available operation in order, ignoring priority and run it on the serial queue
+    if (_serialQueueBusy == NO) {
+      PINOperation *operation = [self locked_nextOperationByQueue];
+      if (operation) {
+        _serialQueueBusy = YES;
+        dispatch_async(_serialQueue, ^{
+          operation.block(operation.data);
+          for (dispatch_block_t completion in operation.completions) {
+            completion();
+          }
+          dispatch_group_leave(_group);
+          
+          [self lock];
+            _serialQueueBusy = NO;
+          [self unlock];
+          
+          //see if there are any other operations
+          [self scheduleNextOperations:YES];
+        });
+      }
+    }
+  
+  NSInteger maxConcurrentOperations = _maxConcurrentOperations;
+  
+  [self unlock];
+  
+  if (onlyCheckSerial) {
+    return;
+  }
+
+  //if only one concurrent operation is set, let's just use the serial queue for executing it
+  if (maxConcurrentOperations < 2) {
+    return;
+  }
+  
+  dispatch_async(_semaphoreQueue, ^{
+    dispatch_semaphore_wait(_concurrentSemaphore, DISPATCH_TIME_FOREVER);
+    [self lock];
+      PINOperation *operation = [self locked_nextOperationByPriority];
+    [self unlock];
+  
+    if (operation) {
+      dispatch_async(_concurrentQueue, ^{
+        operation.block(operation.data);
+        for (dispatch_block_t completion in operation.completions) {
+          completion();
+        }
+        dispatch_group_leave(_group);
+        dispatch_semaphore_signal(_concurrentSemaphore);
+      });
+    } else {
+      dispatch_semaphore_signal(_concurrentSemaphore);
+    }
+  });
+}
+
+- (NSMutableOrderedSet *)operationQueueWithPriority:(PINOperationQueuePriority)priority
+{
+  switch (priority) {
+    case PINOperationQueuePriorityLow:
+      return _lowPriorityOperations;
+      
+    case PINOperationQueuePriorityDefault:
+      return _defaultPriorityOperations;
+      
+    case PINOperationQueuePriorityHigh:
+      return _highPriorityOperations;
+          
+    default:
+      NSAssert(NO, @"Invalid priority set");
+      return _defaultPriorityOperations;
+  }
+}
+
+//Call with lock held
+- (PINOperation *)locked_nextOperationByPriority
+{
+  PINOperation *operation = [_highPriorityOperations firstObject];
+  if (operation == nil) {
+    operation = [_defaultPriorityOperations firstObject];
+  }
+  if (operation == nil) {
+    operation = [_lowPriorityOperations firstObject];
+  }
+  if (operation) {
+    [self locked_removeOperation:operation];
+  }
+  return operation;
+}
+
+//Call with lock held
+- (PINOperation *)locked_nextOperationByQueue
+{
+  PINOperation *operation = [_queuedOperations firstObject];
+  [self locked_removeOperation:operation];
+  return operation;
+}
+
+- (void)waitUntilAllOperationsAreFinished
+{
+  [self scheduleNextOperations:NO];
+  dispatch_group_wait(_group, DISPATCH_TIME_FOREVER);
+}
+
+//Call with lock held
+- (void)locked_removeOperation:(PINOperation *)operation
+{
+  if (operation) {
+    NSMutableOrderedSet *priorityQueue = [self operationQueueWithPriority:operation.priority];
+    [priorityQueue removeObject:operation];
+    [_queuedOperations removeObject:operation];
+  }
+}
+
+- (void)lock
+{
+  pthread_mutex_lock(&_lock);
+}
+
+- (void)unlock
+{
+  pthread_mutex_unlock(&_lock);
+}
+
+@end

+ 15 - 0
Benchmark/Vendor/PINCache/PINOperation/PINOperationTypes.h

@@ -0,0 +1,15 @@
+//
+//  PINOperationTypes.h
+//  PINOperation
+//
+//  Created by Adlai Holler on 1/10/17.
+//  Copyright © 2017 Pinterest. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+typedef NS_ENUM(NSUInteger, PINOperationQueuePriority) {
+    PINOperationQueuePriorityLow,
+    PINOperationQueuePriorityDefault,
+    PINOperationQueuePriorityHigh,
+};

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 429 - 113
Benchmark/Vendor/SQLite/sqlite3.c


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 387 - 126
Benchmark/Vendor/SQLite/sqlite3.h


+ 0 - 177
Benchmark/Vendor/TMCache/TMCache.h

@@ -1,177 +0,0 @@
-/**
- `TMCache` is a thread safe key/value store designed for persisting temporary objects that are expensive to
- reproduce, such as downloaded data or the results of slow processing. It is comprised of two self-similar
- stores, one in memory (<TMMemoryCache>) and one on disk (<TMDiskCache>).
- 
- `TMCache` itself actually does very little; its main function is providing a front end for a common use case:
- a small, fast memory cache that asynchronously persists itself to a large, slow disk cache. When objects are
- removed from the memory cache in response to an "apocalyptic" event they remain in the disk cache and are
- repopulated in memory the next time they are accessed. `TMCache` also does the tedious work of creating a
- dispatch group to wait for both caches to finish their operations without blocking each other.
- 
- The parallel caches are accessible as public properties (<memoryCache> and <diskCache>) and can be manipulated
- separately if necessary. See the docs for <TMMemoryCache> and <TMDiskCache> for more details.
- */
-
-#import <Foundation/Foundation.h>
-
-#import "TMDiskCache.h"
-#import "TMMemoryCache.h"
-
-@class TMCache;
-
-typedef void (^TMCacheBlock)(TMCache *cache);
-typedef void (^TMCacheObjectBlock)(TMCache *cache, NSString *key, id object);
-
-@interface TMCache : NSObject
-
-#pragma mark -
-/// @name Core
-
-/**
- The name of this cache, used to create the <diskCache> and also appearing in stack traces.
- */
-@property (readonly) NSString *name;
-
-/**
- A concurrent queue on which blocks passed to the asynchronous access methods are run.
- */
-@property (readonly) dispatch_queue_t queue;
-
-/**
- Synchronously retrieves the total byte count of the <diskCache> on the shared disk queue.
- */
-@property (readonly) NSUInteger diskByteCount;
-
-/**
- The underlying disk cache, see <TMDiskCache> for additional configuration and trimming options.
- */
-@property (readonly) TMDiskCache *diskCache;
-
-/**
- The underlying memory cache, see <TMMemoryCache> for additional configuration and trimming options.
- */
-@property (readonly) TMMemoryCache *memoryCache;
-
-#pragma mark -
-/// @name Initialization
-
-/**
- A shared cache.
- 
- @result The shared singleton cache instance.
- */
-+ (instancetype)sharedCache;
-
-/**
- Multiple instances with the same name are allowed and can safely access
- the same data on disk thanks to the magic of seriality. Also used to create the <diskCache>.
- 
- @see name
- @param name The name of the cache.
- @result A new cache with the specified name.
- */
-- (instancetype)initWithName:(NSString *)name;
-
-/**
- The designated initializer. Multiple instances with the same name are allowed and can safely access
- the same data on disk thanks to the magic of seriality. Also used to create the <diskCache>.
- 
- @see name
- @param name The name of the cache.
- @param rootPath The path of the cache on disk.
- @result A new cache with the specified name.
- */
-- (instancetype)initWithName:(NSString *)name rootPath:(NSString *)rootPath;
-
-#pragma mark -
-/// @name Asynchronous Methods
-
-/**
- Retrieves the object for the specified key. This method returns immediately and executes the passed
- block after the object is available, potentially in parallel with other blocks on the <queue>.
- 
- @param key The key associated with the requested object.
- @param block A block to be executed concurrently when the object is available.
- */
-- (void)objectForKey:(NSString *)key block:(TMCacheObjectBlock)block;
-
-/**
- Stores an object in the cache for the specified key. This method returns immediately and executes the
- passed block after the object has been stored, potentially in parallel with other blocks on the <queue>.
- 
- @param object An object to store in the cache.
- @param key A key to associate with the object. This string will be copied.
- @param block A block to be executed concurrently after the object has been stored, or nil.
- */
-- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(TMCacheObjectBlock)block;
-
-/**
- Removes the object for the specified key. This method returns immediately and executes the passed
- block after the object has been removed, potentially in parallel with other blocks on the <queue>.
- 
- @param key The key associated with the object to be removed.
- @param block A block to be executed concurrently after the object has been removed, or nil.
- */
-- (void)removeObjectForKey:(NSString *)key block:(TMCacheObjectBlock)block;
-
-/**
- Removes all objects from the cache that have not been used since the specified date. This method returns immediately and
- executes the passed block after the cache has been trimmed, potentially in parallel with other blocks on the <queue>.
- 
- @param date Objects that haven't been accessed since this date are removed from the cache.
- @param block A block to be executed concurrently after the cache has been trimmed, or nil.
- */
-- (void)trimToDate:(NSDate *)date block:(TMCacheBlock)block;
-
-/**
- Removes all objects from the cache.This method returns immediately and executes the passed block after the
- cache has been cleared, potentially in parallel with other blocks on the <queue>.
- 
- @param block A block to be executed concurrently after the cache has been cleared, or nil.
- */
-- (void)removeAllObjects:(TMCacheBlock)block;
-
-#pragma mark -
-/// @name Synchronous Methods
-
-/**
- Retrieves the object for the specified key. This method blocks the calling thread until the object is available.
- 
- @see objectForKey:block:
- @param key The key associated with the object.
- @result The object for the specified key.
- */
-- (id)objectForKey:(NSString *)key;
-
-/**
- Stores an object in the cache for the specified key. This method blocks the calling thread until the object has been set.
- 
- @see setObject:forKey:block:
- @param object An object to store in the cache.
- @param key A key to associate with the object. This string will be copied.
- */
-- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key;
-
-/**
- Removes the object for the specified key. This method blocks the calling thread until the object
- has been removed.
- 
- @param key The key associated with the object to be removed.
- */
-- (void)removeObjectForKey:(NSString *)key;
-
-/**
- Removes all objects from the cache that have not been used since the specified date.
- This method blocks the calling thread until the cache has been trimmed.
- 
- @param date Objects that haven't been accessed since this date are removed from the cache.
- */
-- (void)trimToDate:(NSDate *)date;
-
-/**
- Removes all objects from the cache. This method blocks the calling thread until the cache has been cleared.
- */
-- (void)removeAllObjects;
-
-@end

+ 0 - 387
Benchmark/Vendor/TMCache/TMCache.m

@@ -1,387 +0,0 @@
-#import "TMCache.h"
-
-NSString * const TMCachePrefix = @"com.tumblr.TMCache";
-NSString * const TMCacheSharedName = @"TMCacheShared";
-
-@interface TMCache ()
-#if OS_OBJECT_USE_OBJC
-@property (strong, nonatomic) dispatch_queue_t queue;
-#else
-@property (assign, nonatomic) dispatch_queue_t queue;
-#endif
-@end
-
-@implementation TMCache
-
-#pragma mark - Initialization -
-
-#if !OS_OBJECT_USE_OBJC
-- (void)dealloc
-{
-    dispatch_release(_queue);
-    _queue = nil;
-}
-#endif
-
-- (instancetype)initWithName:(NSString *)name
-{
-    return [self initWithName:name rootPath:[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]];
-}
-
-- (instancetype)initWithName:(NSString *)name rootPath:(NSString *)rootPath
-{
-    if (!name)
-        return nil;
-
-    if (self = [super init]) {
-        _name = [name copy];
-        
-        NSString *queueName = [[NSString alloc] initWithFormat:@"%@.%p", TMCachePrefix, self];
-        _queue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_CONCURRENT);
-
-        _diskCache = [[TMDiskCache alloc] initWithName:_name rootPath:rootPath];
-        _memoryCache = [[TMMemoryCache alloc] init];
-    }
-    return self;
-}
-
-- (NSString *)description
-{
-    return [[NSString alloc] initWithFormat:@"%@.%@.%p", TMCachePrefix, _name, self];
-}
-
-+ (instancetype)sharedCache
-{
-    static id cache;
-    static dispatch_once_t predicate;
-
-    dispatch_once(&predicate, ^{
-        cache = [[self alloc] initWithName:TMCacheSharedName];
-    });
-
-    return cache;
-}
-
-#pragma mark - Public Asynchronous Methods -
-
-- (void)objectForKey:(NSString *)key block:(TMCacheObjectBlock)block
-{
-    if (!key || !block)
-        return;
-
-    __weak TMCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        __weak TMCache *weakSelf = strongSelf;
-        
-        [strongSelf->_memoryCache objectForKey:key block:^(TMMemoryCache *cache, NSString *key, id object) {
-            TMCache *strongSelf = weakSelf;
-            if (!strongSelf)
-                return;
-            
-            if (object) {
-                [strongSelf->_diskCache fileURLForKey:key block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
-                    // update the access time on disk
-                }];
-
-                __weak TMCache *weakSelf = strongSelf;
-                
-                dispatch_async(strongSelf->_queue, ^{
-                    TMCache *strongSelf = weakSelf;
-                    if (strongSelf)
-                        block(strongSelf, key, object);
-                });
-            } else {
-                __weak TMCache *weakSelf = strongSelf;
-
-                [strongSelf->_diskCache objectForKey:key block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
-                    TMCache *strongSelf = weakSelf;
-                    if (!strongSelf)
-                        return;
-                    
-                    [strongSelf->_memoryCache setObject:object forKey:key block:nil];
-                    
-                    __weak TMCache *weakSelf = strongSelf;
-                    
-                    dispatch_async(strongSelf->_queue, ^{
-                        TMCache *strongSelf = weakSelf;
-                        if (strongSelf)
-                            block(strongSelf, key, object);
-                    });
-                }];
-            }
-        }];
-    });
-}
-
-- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(TMCacheObjectBlock)block
-{
-    if (!key || !object)
-        return;
-
-    dispatch_group_t group = nil;
-    TMMemoryCacheObjectBlock memBlock = nil;
-    TMDiskCacheObjectBlock diskBlock = nil;
-    
-    if (block) {
-        group = dispatch_group_create();
-        dispatch_group_enter(group);
-        dispatch_group_enter(group);
-        
-        memBlock = ^(TMMemoryCache *cache, NSString *key, id object) {
-            dispatch_group_leave(group);
-        };
-        
-        diskBlock = ^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
-            dispatch_group_leave(group);
-        };
-    }
-    
-    [_memoryCache setObject:object forKey:key block:memBlock];
-    [_diskCache setObject:object forKey:key block:diskBlock];
-    
-    if (group) {
-        __weak TMCache *weakSelf = self;
-        dispatch_group_notify(group, _queue, ^{
-            TMCache *strongSelf = weakSelf;
-            if (strongSelf)
-                block(strongSelf, key, object);
-        });
-        
-        #if !OS_OBJECT_USE_OBJC
-        dispatch_release(group);
-        #endif
-    }
-}
-
-- (void)removeObjectForKey:(NSString *)key block:(TMCacheObjectBlock)block
-{
-    if (!key)
-        return;
-    
-    dispatch_group_t group = nil;
-    TMMemoryCacheObjectBlock memBlock = nil;
-    TMDiskCacheObjectBlock diskBlock = nil;
-    
-    if (block) {
-        group = dispatch_group_create();
-        dispatch_group_enter(group);
-        dispatch_group_enter(group);
-        
-        memBlock = ^(TMMemoryCache *cache, NSString *key, id object) {
-            dispatch_group_leave(group);
-        };
-        
-        diskBlock = ^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
-            dispatch_group_leave(group);
-        };
-    }
-
-    [_memoryCache removeObjectForKey:key block:memBlock];
-    [_diskCache removeObjectForKey:key block:diskBlock];
-    
-    if (group) {
-        __weak TMCache *weakSelf = self;
-        dispatch_group_notify(group, _queue, ^{
-            TMCache *strongSelf = weakSelf;
-            if (strongSelf)
-                block(strongSelf, key, nil);
-        });
-        
-        #if !OS_OBJECT_USE_OBJC
-        dispatch_release(group);
-        #endif
-    }
-}
-
-- (void)removeAllObjects:(TMCacheBlock)block
-{
-    dispatch_group_t group = nil;
-    TMMemoryCacheBlock memBlock = nil;
-    TMDiskCacheBlock diskBlock = nil;
-    
-    if (block) {
-        group = dispatch_group_create();
-        dispatch_group_enter(group);
-        dispatch_group_enter(group);
-        
-        memBlock = ^(TMMemoryCache *cache) {
-            dispatch_group_leave(group);
-        };
-        
-        diskBlock = ^(TMDiskCache *cache) {
-            dispatch_group_leave(group);
-        };
-    }
-    
-    [_memoryCache removeAllObjects:memBlock];
-    [_diskCache removeAllObjects:diskBlock];
-    
-    if (group) {
-        __weak TMCache *weakSelf = self;
-        dispatch_group_notify(group, _queue, ^{
-            TMCache *strongSelf = weakSelf;
-            if (strongSelf)
-                block(strongSelf);
-        });
-        
-        #if !OS_OBJECT_USE_OBJC
-        dispatch_release(group);
-        #endif
-    }
-}
-
-- (void)trimToDate:(NSDate *)date block:(TMCacheBlock)block
-{
-    if (!date)
-        return;
-
-    dispatch_group_t group = nil;
-    TMMemoryCacheBlock memBlock = nil;
-    TMDiskCacheBlock diskBlock = nil;
-    
-    if (block) {
-        group = dispatch_group_create();
-        dispatch_group_enter(group);
-        dispatch_group_enter(group);
-        
-        memBlock = ^(TMMemoryCache *cache) {
-            dispatch_group_leave(group);
-        };
-        
-        diskBlock = ^(TMDiskCache *cache) {
-            dispatch_group_leave(group);
-        };
-    }
-    
-    [_memoryCache trimToDate:date block:memBlock];
-    [_diskCache trimToDate:date block:diskBlock];
-    
-    if (group) {
-        __weak TMCache *weakSelf = self;
-        dispatch_group_notify(group, _queue, ^{
-            TMCache *strongSelf = weakSelf;
-            if (strongSelf)
-                block(strongSelf);
-        });
-        
-        #if !OS_OBJECT_USE_OBJC
-        dispatch_release(group);
-        #endif
-    }
-}
-
-#pragma mark - Public Synchronous Accessors -
-
-- (NSUInteger)diskByteCount
-{
-    __block NSUInteger byteCount = 0;
-    
-    dispatch_sync([TMDiskCache sharedQueue], ^{
-        byteCount = self.diskCache.byteCount;
-    });
-    
-    return byteCount;
-}
-
-#pragma mark - Public Synchronous Methods -
-
-- (id)objectForKey:(NSString *)key
-{
-    if (!key)
-        return nil;
-    
-    __block id objectForKey = nil;
-
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self objectForKey:key block:^(TMCache *cache, NSString *key, id object) {
-        objectForKey = object;
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-
-    return objectForKey;
-}
-
-- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key
-{
-    if (!object || !key)
-        return;
-    
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self setObject:object forKey:key block:^(TMCache *cache, NSString *key, id object) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)removeObjectForKey:(NSString *)key
-{
-    if (!key)
-        return;
-    
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self removeObjectForKey:key block:^(TMCache *cache, NSString *key, id object) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)trimToDate:(NSDate *)date
-{
-    if (!date)
-        return;
-    
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self trimToDate:date block:^(TMCache *cache) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)removeAllObjects
-{
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self removeAllObjects:^(TMCache *cache) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-@end
-
-// HC SVNT DRACONES

+ 0 - 36
Benchmark/Vendor/TMCache/TMCacheBackgroundTaskManager.h

@@ -1,36 +0,0 @@
-//
-//  TMCacheBackgroundTaskManager.h
-//  TMCache
-//
-//  Created by Bryan Irace on 4/24/15.
-//  Copyright (c) 2015 Tumblr. All rights reserved.
-//
-
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
-#import <UIKit/UIKit.h>
-#else
-typedef NSUInteger UIBackgroundTaskIdentifier;
-#endif
-
-/**
- A protocol that classes who can begin and end background tasks can conform to. This protocol provides an abstraction in
- order to avoid referencing `+ [UIApplication sharedApplication]` from within an iOS application extension.
- */
-@protocol TMCacheBackgroundTaskManager <NSObject>
-
-/**
- Marks the beginning of a new long-running background task.
- 
- @return A unique identifier for the new background task. You must pass this value to the `endBackgroundTask:` method to
- mark the end of this task. This method returns `UIBackgroundTaskInvalid` if running in the background is not possible.
- */
-- (UIBackgroundTaskIdentifier)beginBackgroundTask;
-
-/**
- Marks the end of a specific long-running background task.
- 
- @param identifier An identifier returned by the `beginBackgroundTaskWithExpirationHandler:` method.
- */
-- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier;
-
-@end

+ 0 - 350
Benchmark/Vendor/TMCache/TMDiskCache.h

@@ -1,350 +0,0 @@
-/**
- `TMDiskCache` is a thread safe key/value store backed by the file system. It accepts any object conforming
- to the `NSCoding` protocol, which includes the basic Foundation data types and collection classes and also
- many UIKit classes, notably `UIImage`. All work is performed on a serial queue shared by all instances in
- the app, and archiving is handled by `NSKeyedArchiver`. This is a particular advantage for `UIImage` because
- it skips `UIImagePNGRepresentation()` and retains information like scale and orientation.
- 
- The designated initializer for `TMDiskCache` is <initWithName:>. The <name> string is used to create a directory
- under Library/Caches that scopes disk access for any instance sharing this name. Multiple instances with the
- same name are allowed because all disk access is serialized on the <sharedQueue>. The <name> also appears in
- stack traces and return value for `description:`.
- 
- Unless otherwise noted, all properties and methods are safe to access from any thread at any time. All blocks
- will cause the queue to wait, making it safe to access and manipulate the actual cache files on disk for the
- duration of the block. In addition, the <sharedQueue> can be set to target an existing serial I/O queue, should
- your app already have one.
- 
- Because this cache is bound by disk I/O it can be much slower than <TMMemoryCache>, although values stored in
- `TMDiskCache` persist after application relaunch. Using <TMCache> is recommended over using `TMDiskCache`
- by itself, as it adds a fast layer of additional memory caching while still writing to disk.
-
- All access to the cache is dated so the that the least-used objects can be trimmed first. Setting an optional
- <ageLimit> will trigger a GCD timer to periodically to trim the cache with <trimToDate:>.
- */
-
-#import <Foundation/Foundation.h>
-
-@class TMDiskCache;
-@protocol TMCacheBackgroundTaskManager;
-
-typedef void (^TMDiskCacheBlock)(TMDiskCache *cache);
-typedef void (^TMDiskCacheObjectBlock)(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL);
-
-@interface TMDiskCache : NSObject
-
-#pragma mark -
-/// @name Core
-
-/**
- The name of this cache, used to create a directory under Library/Caches and also appearing in stack traces.
- */
-@property (readonly) NSString *name;
-
-/**
- The URL of the directory used by this cache, usually `Library/Caches/com.tumblr.TMDiskCache.(name)`
- 
- @warning Do not interact with files under this URL except on the <sharedQueue>.
- */
-@property (readonly) NSURL *cacheURL;
-
-/**
- The total number of bytes used on disk, as reported by `NSURLTotalFileAllocatedSizeKey`.
- 
- @warning This property is technically safe to access from any thread, but it reflects the value *right now*,
- not taking into account any pending operations. In most cases this value should only be read from a block on the
- <sharedQueue>, which will ensure its accuracy and prevent it from changing during the lifetime of the block.
- 
- For example:
- 
-    // some background thread, not a block already running on the shared queue
-
-    dispatch_sync([TMDiskCache sharedQueue], ^{
-        NSLog(@"accurate, unchanging byte count: %d", [[TMDiskCache sharedCache] byteCount]);
-    });
- */
-@property (readonly) NSUInteger byteCount;
-
-/**
- The maximum number of bytes allowed on disk. This value is checked every time an object is set, if the written
- size exceeds the limit a trim call is queued. Defaults to `0.0`, meaning no practical limit.
- 
- @warning Do not read this property on the <sharedQueue> (including asynchronous method blocks).
- */
-@property (assign) NSUInteger byteLimit;
-
-/**
- The maximum number of seconds an object is allowed to exist in the cache. Setting this to a value
- greater than `0.0` will start a recurring GCD timer with the same period that calls <trimToDate:>.
- Setting it back to `0.0` will stop the timer. Defaults to `0.0`, meaning no limit.
- 
- @warning Do not read this property on the <sharedQueue> (including asynchronous method blocks).
- */
-@property (assign) NSTimeInterval ageLimit;
-
-#pragma mark -
-/// @name Event Blocks
-
-/**
- A block to be executed just before an object is added to the cache. The queue waits during execution.
- */
-@property (copy) TMDiskCacheObjectBlock willAddObjectBlock;
-
-/**
- A block to be executed just before an object is removed from the cache. The queue waits during execution.
- */
-@property (copy) TMDiskCacheObjectBlock willRemoveObjectBlock;
-
-/**
- A block to be executed just before all objects are removed from the cache as a result of <removeAllObjects:>.
- The queue waits during execution.
- */
-@property (copy) TMDiskCacheBlock willRemoveAllObjectsBlock;
-
-/**
- A block to be executed just after an object is added to the cache. The queue waits during execution.
- */
-@property (copy) TMDiskCacheObjectBlock didAddObjectBlock;
-
-/**
- A block to be executed just after an object is removed from the cache. The queue waits during execution.
- */
-@property (copy) TMDiskCacheObjectBlock didRemoveObjectBlock;
-
-/**
- A block to be executed just after all objects are removed from the cache as a result of <removeAllObjects:>.
- The queue waits during execution.
- */
-@property (copy) TMDiskCacheBlock didRemoveAllObjectsBlock;
-
-#pragma mark -
-/// @name Initialization
-
-/**
- A shared cache.
- 
- @result The shared singleton cache instance.
- */
-+ (instancetype)sharedCache;
-
-/**
- A shared serial queue, used by all instances of this class. Use `dispatch_set_target_queue` to integrate
- this queue with an exisiting serial I/O queue.
- 
- @result The shared singleton queue instance.
- */
-+ (dispatch_queue_t)sharedQueue;
-
-/**
- Empties the trash with `DISPATCH_QUEUE_PRIORITY_BACKGROUND`. Does not block the <sharedQueue>.
- */
-+ (void)emptyTrash;
-
-
-/**
- Multiple instances with the same name are allowed and can safely access
- the same data on disk thanks to the magic of seriality.
- 
- @see name
- @param name The name of the cache.
- @result A new cache with the specified name.
- */
-- (instancetype)initWithName:(NSString *)name;
-
-/**
- The designated initializer. Multiple instances with the same name are allowed and can safely access
- the same data on disk thanks to the magic of seriality.
- 
- @see name
- @param name The name of the cache.
- @param rootPath The path of the cache.
- @result A new cache with the specified name.
- */
-- (instancetype)initWithName:(NSString *)name rootPath:(NSString *)rootPath;
-
-#pragma mark -
-/// @name Asynchronous Methods
-
-/**
- Retrieves the object for the specified key. This method returns immediately and executes the passed
- block as soon as the object is available on the serial <sharedQueue>.
- 
- @warning The fileURL is only valid for the duration of this block, do not use it after the block ends.
- 
- @param key The key associated with the requested object.
- @param block A block to be executed serially when the object is available.
- */
-- (void)objectForKey:(NSString *)key block:(TMDiskCacheObjectBlock)block;
-
-/**
- Retrieves the fileURL for the specified key without actually reading the data from disk. This method
- returns immediately and executes the passed block as soon as the object is available on the serial
- <sharedQueue>.
- 
- @warning Access is protected for the duration of the block, but to maintain safe disk access do not
- access this fileURL after the block has ended. Do all work on the <sharedQueue>.
- 
- @param key The key associated with the requested object.
- @param block A block to be executed serially when the file URL is available.
- */
-- (void)fileURLForKey:(NSString *)key block:(TMDiskCacheObjectBlock)block;
-
-/**
- Stores an object in the cache for the specified key. This method returns immediately and executes the
- passed block as soon as the object has been stored.
- 
- @param object An object to store in the cache.
- @param key A key to associate with the object. This string will be copied.
- @param block A block to be executed serially after the object has been stored, or nil.
- */
-- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(TMDiskCacheObjectBlock)block;
-
-/**
- Removes the object for the specified key. This method returns immediately and executes the passed block
- as soon as the object has been removed.
- 
- @param key The key associated with the object to be removed.
- @param block A block to be executed serially after the object has been removed, or nil.
- */
-- (void)removeObjectForKey:(NSString *)key block:(TMDiskCacheObjectBlock)block;
-
-/**
- Removes all objects from the cache that have not been used since the specified date.
- This method returns immediately and executes the passed block as soon as the cache has been trimmed.
-
- @param date Objects that haven't been accessed since this date are removed from the cache.
- @param block A block to be executed serially after the cache has been trimmed, or nil.
- */
-- (void)trimToDate:(NSDate *)date block:(TMDiskCacheBlock)block;
-
-/**
- Removes objects from the cache, largest first, until the cache is equal to or smaller than the specified byteCount.
- This method returns immediately and executes the passed block as soon as the cache has been trimmed.
- 
- @param byteCount The cache will be trimmed equal to or smaller than this size.
- @param block A block to be executed serially after the cache has been trimmed, or nil.
- */
-- (void)trimToSize:(NSUInteger)byteCount block:(TMDiskCacheBlock)block;
-
-/**
- Removes objects from the cache, ordered by date (least recently used first), until the cache is equal to or smaller
- than the specified byteCount. This method returns immediately and executes the passed block as soon as the cache has
- been trimmed.
-
- @param byteCount The cache will be trimmed equal to or smaller than this size.
- @param block A block to be executed serially after the cache has been trimmed, or nil.
- */
-- (void)trimToSizeByDate:(NSUInteger)byteCount block:(TMDiskCacheBlock)block;
-
-/**
- Removes all objects from the cache. This method returns immediately and executes the passed block as soon as the
- cache has been cleared.
- 
- @param block A block to be executed serially after the cache has been cleared, or nil.
- */
-- (void)removeAllObjects:(TMDiskCacheBlock)block;
-
-/**
- Loops through all objects in the cache (reads and writes are suspended during the enumeration). Data is not actually
- read from disk, the `object` parameter of the block will be `nil` but the `fileURL` will be available.
- This method returns immediately.
-
- @param block A block to be executed for every object in the cache.
- @param completionBlock An optional block to be executed after the enumeration is complete.
- */
-- (void)enumerateObjectsWithBlock:(TMDiskCacheObjectBlock)block completionBlock:(TMDiskCacheBlock)completionBlock;
-
-#pragma mark -
-/// @name Synchronous Methods
-
-/**
- Retrieves the object for the specified key. This method blocks the calling thread until the
- object is available.
- 
- @see objectForKey:block:
- @param key The key associated with the object.
- @result The object for the specified key.
- */
-- (id <NSCoding>)objectForKey:(NSString *)key;
-
-/**
- Retrieves the file URL for the specified key. This method blocks the calling thread until the
- url is available. Do not use this URL anywhere but on the <sharedQueue>. This method probably
- shouldn't even exist, just use the asynchronous one.
- 
- @see fileURLForKey:block:
- @param key The key associated with the object.
- @result The file URL for the specified key.
- */
-- (NSURL *)fileURLForKey:(NSString *)key;
-
-/**
- Stores an object in the cache for the specified key. This method blocks the calling thread until
- the object has been stored.
- 
- @see setObject:forKey:block:
- @param object An object to store in the cache.
- @param key A key to associate with the object. This string will be copied.
- */
-- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key;
-
-/**
- Removes the object for the specified key. This method blocks the calling thread until the object
- has been removed.
- 
- @param key The key associated with the object to be removed.
- */
-- (void)removeObjectForKey:(NSString *)key;
-
-/**
- Removes all objects from the cache that have not been used since the specified date.
- This method blocks the calling thread until the cache has been trimmed.
-
- @param date Objects that haven't been accessed since this date are removed from the cache.
- */
-- (void)trimToDate:(NSDate *)date;
-
-/**
- Removes objects from the cache, largest first, until the cache is equal to or smaller than the
- specified byteCount. This method blocks the calling thread until the cache has been trimmed.
- 
- @param byteCount The cache will be trimmed equal to or smaller than this size.
- */
-- (void)trimToSize:(NSUInteger)byteCount;
-
-/**
- Removes objects from the cache, ordered by date (least recently used first), until the cache is equal to or
- smaller than the specified byteCount. This method blocks the calling thread until the cache has been trimmed.
-
- @param byteCount The cache will be trimmed equal to or smaller than this size.
- */
-- (void)trimToSizeByDate:(NSUInteger)byteCount;
-
-/**
- Removes all objects from the cache. This method blocks the calling thread until the cache has been cleared.
- */
-- (void)removeAllObjects;
-
-/**
- Loops through all objects in the cache (reads and writes are suspended during the enumeration). Data is not actually
- read from disk, the `object` parameter of the block will be `nil` but the `fileURL` will be available.
- This method blocks the calling thread until all objects have been enumerated.
-
- @param block A block to be executed for every object in the cache.
-
- @warning Do not call this method within the event blocks (<didRemoveObjectBlock>, etc.)
- Instead use the asynchronous version, <enumerateObjectsWithBlock:completionBlock:>.
- */
-- (void)enumerateObjectsWithBlock:(TMDiskCacheObjectBlock)block;
-
-#pragma mark -
-/// @name Background Tasks
-
-/**
- Set a global manager to be used for setting up/tearing down any background tasks needed by TMCache.
- 
- @param backgroundTaskManager Background task manager.
- */
-+ (void)setBackgroundTaskManager:(id <TMCacheBackgroundTaskManager>)backgroundTaskManager;
-
-@end

+ 0 - 1063
Benchmark/Vendor/TMCache/TMDiskCache.m

@@ -1,1063 +0,0 @@
-#import "TMDiskCache.h"
-#import "TMCacheBackgroundTaskManager.h"
-
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
-#import <UIKit/UIKit.h>
-#endif
-
-#define TMDiskCacheError(error) if (error) { NSLog(@"%@ (%d) ERROR: %@", \
-                                    [[NSString stringWithUTF8String:__FILE__] lastPathComponent], \
-                                    __LINE__, [error localizedDescription]); }
-
-static id <TMCacheBackgroundTaskManager> TMCacheBackgroundTaskManager;
-
-NSString * const TMDiskCachePrefix = @"com.tumblr.TMDiskCache";
-NSString * const TMDiskCacheSharedName = @"TMDiskCacheShared";
-
-@interface TMDiskCache ()
-@property (assign) NSUInteger byteCount;
-@property (strong, nonatomic) NSURL *cacheURL;
-@property (assign, nonatomic) dispatch_queue_t queue;
-@property (strong, nonatomic) NSMutableDictionary *dates;
-@property (strong, nonatomic) NSMutableDictionary *sizes;
-@end
-
-@implementation TMDiskCache
-
-@synthesize willAddObjectBlock = _willAddObjectBlock;
-@synthesize willRemoveObjectBlock = _willRemoveObjectBlock;
-@synthesize willRemoveAllObjectsBlock = _willRemoveAllObjectsBlock;
-@synthesize didAddObjectBlock = _didAddObjectBlock;
-@synthesize didRemoveObjectBlock = _didRemoveObjectBlock;
-@synthesize didRemoveAllObjectsBlock = _didRemoveAllObjectsBlock;
-@synthesize byteLimit = _byteLimit;
-@synthesize ageLimit = _ageLimit;
-
-#pragma mark - Initialization -
-
-- (instancetype)initWithName:(NSString *)name
-{
-    return [self initWithName:name rootPath:[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]];
-}
-
-- (instancetype)initWithName:(NSString *)name rootPath:(NSString *)rootPath
-{
-    if (!name)
-        return nil;
-
-    if (self = [super init]) {
-        _name = [name copy];
-        _queue = [TMDiskCache sharedQueue];
-
-        _willAddObjectBlock = nil;
-        _willRemoveObjectBlock = nil;
-        _willRemoveAllObjectsBlock = nil;
-        _didAddObjectBlock = nil;
-        _didRemoveObjectBlock = nil;
-        _didRemoveAllObjectsBlock = nil;
-        
-        _byteCount = 0;
-        _byteLimit = 0;
-        _ageLimit = 0.0;
-
-        _dates = [[NSMutableDictionary alloc] init];
-        _sizes = [[NSMutableDictionary alloc] init];
-
-        NSString *pathComponent = [[NSString alloc] initWithFormat:@"%@.%@", TMDiskCachePrefix, _name];
-        _cacheURL = [NSURL fileURLWithPathComponents:@[ rootPath, pathComponent ]];
-
-        __weak TMDiskCache *weakSelf = self;
-
-        dispatch_async(_queue, ^{
-            TMDiskCache *strongSelf = weakSelf;
-            [strongSelf createCacheDirectory];
-            [strongSelf initializeDiskProperties];
-        });
-    }
-    return self;
-}
-
-- (NSString *)description
-{
-    return [[NSString alloc] initWithFormat:@"%@.%@.%p", TMDiskCachePrefix, _name, self];
-}
-
-+ (instancetype)sharedCache
-{
-    static id cache;
-    static dispatch_once_t predicate;
-
-    dispatch_once(&predicate, ^{
-        cache = [[self alloc] initWithName:TMDiskCacheSharedName];
-    });
-
-    return cache;
-}
-
-+ (dispatch_queue_t)sharedQueue
-{
-    static dispatch_queue_t queue;
-    static dispatch_once_t predicate;
-
-    dispatch_once(&predicate, ^{
-        queue = dispatch_queue_create([TMDiskCachePrefix UTF8String], DISPATCH_QUEUE_SERIAL);
-    });
-
-    return queue;
-}
-
-#pragma mark - Private Methods -
-
-- (NSURL *)encodedFileURLForKey:(NSString *)key
-{
-    if (![key length])
-        return nil;
-
-    return [_cacheURL URLByAppendingPathComponent:[self encodedString:key]];
-}
-
-- (NSString *)keyForEncodedFileURL:(NSURL *)url
-{
-    NSString *fileName = [url lastPathComponent];
-    if (!fileName)
-        return nil;
-
-    return [self decodedString:fileName];
-}
-
-- (NSString *)encodedString:(NSString *)string
-{
-    if (![string length])
-        return @"";
-
-    CFStringRef static const charsToEscape = CFSTR(".:/");
-    CFStringRef escapedString = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
-                                                                        (__bridge CFStringRef)string,
-                                                                        NULL,
-                                                                        charsToEscape,
-                                                                        kCFStringEncodingUTF8);
-    return (__bridge_transfer NSString *)escapedString;
-}
-
-- (NSString *)decodedString:(NSString *)string
-{
-    if (![string length])
-        return @"";
-
-    CFStringRef unescapedString = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
-                                                                                          (__bridge CFStringRef)string,
-                                                                                          CFSTR(""),
-                                                                                          kCFStringEncodingUTF8);
-    return (__bridge_transfer NSString *)unescapedString;
-}
-
-#pragma mark - Private Trash Methods -
-
-+ (dispatch_queue_t)sharedTrashQueue
-{
-    static dispatch_queue_t trashQueue;
-    static dispatch_once_t predicate;
-    
-    dispatch_once(&predicate, ^{
-        NSString *queueName = [[NSString alloc] initWithFormat:@"%@.trash", TMDiskCachePrefix];
-        trashQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL);
-        dispatch_set_target_queue(trashQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
-    });
-    
-    return trashQueue;
-}
-
-+ (NSURL *)sharedTrashURL
-{
-    static NSURL *sharedTrashURL;
-    static dispatch_once_t predicate;
-    
-    dispatch_once(&predicate, ^{
-        sharedTrashURL = [[[NSURL alloc] initFileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:TMDiskCachePrefix isDirectory:YES];
-        
-        if (![[NSFileManager defaultManager] fileExistsAtPath:[sharedTrashURL path]]) {
-            NSError *error = nil;
-            [[NSFileManager defaultManager] createDirectoryAtURL:sharedTrashURL
-                                     withIntermediateDirectories:YES
-                                                      attributes:nil
-                                                           error:&error];
-            TMDiskCacheError(error);
-        }
-    });
-    
-    return sharedTrashURL;
-}
-
-+(BOOL)moveItemAtURLToTrash:(NSURL *)itemURL
-{
-    if (![[NSFileManager defaultManager] fileExistsAtPath:[itemURL path]])
-        return NO;
-
-    NSError *error = nil;
-    NSString *uniqueString = [[NSProcessInfo processInfo] globallyUniqueString];
-    NSURL *uniqueTrashURL = [[TMDiskCache sharedTrashURL] URLByAppendingPathComponent:uniqueString];
-    BOOL moved = [[NSFileManager defaultManager] moveItemAtURL:itemURL toURL:uniqueTrashURL error:&error];
-    TMDiskCacheError(error);
-    return moved;
-}
-
-+ (void)emptyTrash
-{
-    UIBackgroundTaskIdentifier taskID = [TMCacheBackgroundTaskManager beginBackgroundTask];
-    
-    dispatch_async([self sharedTrashQueue], ^{        
-        NSError *error = nil;
-        NSArray *trashedItems = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:[self sharedTrashURL]
-                                                              includingPropertiesForKeys:nil
-                                                                                 options:0
-                                                                                   error:&error];
-        TMDiskCacheError(error);
-
-        for (NSURL *trashedItemURL in trashedItems) {
-            NSError *error = nil;
-            [[NSFileManager defaultManager] removeItemAtURL:trashedItemURL error:&error];
-            TMDiskCacheError(error);
-        }
-        
-        [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-    });
-}
-
-#pragma mark - Private Queue Methods -
-
-- (BOOL)createCacheDirectory
-{
-    if ([[NSFileManager defaultManager] fileExistsAtPath:[_cacheURL path]])
-        return NO;
-
-    NSError *error = nil;
-    BOOL success = [[NSFileManager defaultManager] createDirectoryAtURL:_cacheURL
-                                            withIntermediateDirectories:YES
-                                                             attributes:nil
-                                                                  error:&error];
-    TMDiskCacheError(error);
-
-    return success;
-}
-
-- (void)initializeDiskProperties
-{
-    NSUInteger byteCount = 0;
-    NSArray *keys = @[ NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey ];
-
-    NSError *error = nil;
-    NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:_cacheURL
-                                                   includingPropertiesForKeys:keys
-                                                                      options:NSDirectoryEnumerationSkipsHiddenFiles
-                                                                        error:&error];
-    TMDiskCacheError(error);
-
-    for (NSURL *fileURL in files) {
-        NSString *key = [self keyForEncodedFileURL:fileURL];
-
-        error = nil;
-        NSDictionary *dictionary = [fileURL resourceValuesForKeys:keys error:&error];
-        TMDiskCacheError(error);
-
-        NSDate *date = [dictionary objectForKey:NSURLContentModificationDateKey];
-        if (date && key)
-            [_dates setObject:date forKey:key];
-
-        NSNumber *fileSize = [dictionary objectForKey:NSURLTotalFileAllocatedSizeKey];
-        if (fileSize) {
-            [_sizes setObject:fileSize forKey:key];
-            byteCount += [fileSize unsignedIntegerValue];
-        }
-    }
-
-    if (byteCount > 0)
-        self.byteCount = byteCount; // atomic
-}
-
-- (BOOL)setFileModificationDate:(NSDate *)date forURL:(NSURL *)fileURL
-{
-    if (!date || !fileURL) {
-        return NO;
-    }
-    
-    NSError *error = nil;
-    BOOL success = [[NSFileManager defaultManager] setAttributes:@{ NSFileModificationDate: date }
-                                                    ofItemAtPath:[fileURL path]
-                                                           error:&error];
-    TMDiskCacheError(error);
-
-    if (success) {
-        NSString *key = [self keyForEncodedFileURL:fileURL];
-        if (key) {
-            [_dates setObject:date forKey:key];
-        }
-    }
-
-    return success;
-}
-
-- (BOOL)removeFileAndExecuteBlocksForKey:(NSString *)key
-{
-    NSURL *fileURL = [self encodedFileURLForKey:key];
-    if (!fileURL || ![[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]])
-        return NO;
-
-    if (_willRemoveObjectBlock)
-        _willRemoveObjectBlock(self, key, nil, fileURL);
-
-    BOOL trashed = [TMDiskCache moveItemAtURLToTrash:fileURL];
-    if (!trashed)
-        return NO;
-    
-    [TMDiskCache emptyTrash];
-
-    NSNumber *byteSize = [_sizes objectForKey:key];
-    if (byteSize)
-        self.byteCount = _byteCount - [byteSize unsignedIntegerValue]; // atomic
-
-    [_sizes removeObjectForKey:key];
-    [_dates removeObjectForKey:key];
-
-    if (_didRemoveObjectBlock)
-        _didRemoveObjectBlock(self, key, nil, fileURL);
-
-    return YES;
-}
-
-- (void)trimDiskToSize:(NSUInteger)trimByteCount
-{
-    if (_byteCount <= trimByteCount)
-        return;
-
-    NSArray *keysSortedBySize = [_sizes keysSortedByValueUsingSelector:@selector(compare:)];
-
-    for (NSString *key in [keysSortedBySize reverseObjectEnumerator]) { // largest objects first
-        [self removeFileAndExecuteBlocksForKey:key];
-
-        if (_byteCount <= trimByteCount)
-            break;
-    }
-}
-
-- (void)trimDiskToSizeByDate:(NSUInteger)trimByteCount
-{
-    if (_byteCount <= trimByteCount)
-        return;
-
-    NSArray *keysSortedByDate = [_dates keysSortedByValueUsingSelector:@selector(compare:)];
-
-    for (NSString *key in keysSortedByDate) { // oldest objects first
-        [self removeFileAndExecuteBlocksForKey:key];
-
-        if (_byteCount <= trimByteCount)
-            break;
-    }
-}
-
-- (void)trimDiskToDate:(NSDate *)trimDate
-{
-    NSArray *keysSortedByDate = [_dates keysSortedByValueUsingSelector:@selector(compare:)];
-    
-    for (NSString *key in keysSortedByDate) { // oldest files first
-        NSDate *accessDate = [_dates objectForKey:key];
-        if (!accessDate)
-            continue;
-        
-        if ([accessDate compare:trimDate] == NSOrderedAscending) { // older than trim date
-            [self removeFileAndExecuteBlocksForKey:key];
-        } else {
-            break;
-        }
-    }
-}
-
-- (void)trimToAgeLimitRecursively
-{
-    if (_ageLimit == 0.0)
-        return;
-    
-    NSDate *date = [[NSDate alloc] initWithTimeIntervalSinceNow:-_ageLimit];
-    [self trimDiskToDate:date];
-    
-    __weak TMDiskCache *weakSelf = self;
-    
-    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_ageLimit * NSEC_PER_SEC));
-    dispatch_after(time, _queue, ^(void) {
-        TMDiskCache *strongSelf = weakSelf;
-        [strongSelf trimToAgeLimitRecursively];
-    });
-}
-
-#pragma mark - Public Asynchronous Methods -
-
-- (void)objectForKey:(NSString *)key block:(TMDiskCacheObjectBlock)block
-{
-    NSDate *now = [[NSDate alloc] init];
-
-    if (!key || !block)
-        return;
-
-    __weak TMDiskCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        NSURL *fileURL = [strongSelf encodedFileURLForKey:key];
-        id <NSCoding> object = nil;
-
-        if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]) {
-            @try {
-                object = [NSKeyedUnarchiver unarchiveObjectWithFile:[fileURL path]];
-            }
-            @catch (NSException *exception) {
-                NSError *error = nil;
-                [[NSFileManager defaultManager] removeItemAtPath:[fileURL path] error:&error];
-                TMDiskCacheError(error);
-            }
-
-            [strongSelf setFileModificationDate:now forURL:fileURL];
-        }
-
-        block(strongSelf, key, object, fileURL);
-    });
-}
-
-- (void)fileURLForKey:(NSString *)key block:(TMDiskCacheObjectBlock)block
-{
-    NSDate *now = [[NSDate alloc] init];
-
-    if (!key || !block)
-        return;
-
-    __weak TMDiskCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        NSURL *fileURL = [strongSelf encodedFileURLForKey:key];
-
-        if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]) {
-            [strongSelf setFileModificationDate:now forURL:fileURL];
-        } else {
-            fileURL = nil;
-        }
-
-        block(strongSelf, key, nil, fileURL);
-    });
-}
-
-- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(TMDiskCacheObjectBlock)block
-{
-    NSDate *now = [[NSDate alloc] init];
-
-    if (!key || !object)
-        return;
-
-    UIBackgroundTaskIdentifier taskID = [TMCacheBackgroundTaskManager beginBackgroundTask];
-
-    __weak TMDiskCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf) {
-            [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-            return;
-        }
-
-        NSURL *fileURL = [strongSelf encodedFileURLForKey:key];
-
-        if (strongSelf->_willAddObjectBlock)
-            strongSelf->_willAddObjectBlock(strongSelf, key, object, fileURL);
-
-        BOOL written = [NSKeyedArchiver archiveRootObject:object toFile:[fileURL path]];
-
-        if (written) {
-            [strongSelf setFileModificationDate:now forURL:fileURL];
-
-            NSError *error = nil;
-            NSDictionary *values = [fileURL resourceValuesForKeys:@[ NSURLTotalFileAllocatedSizeKey ] error:&error];
-            TMDiskCacheError(error);
-
-            NSNumber *diskFileSize = [values objectForKey:NSURLTotalFileAllocatedSizeKey];
-            if (diskFileSize) {
-                NSNumber *oldEntry = [strongSelf->_sizes objectForKey:key];
-                
-                if ([oldEntry isKindOfClass:[NSNumber class]]){
-                    strongSelf.byteCount = strongSelf->_byteCount - [oldEntry unsignedIntegerValue];
-                }
-                
-                [strongSelf->_sizes setObject:diskFileSize forKey:key];
-                strongSelf.byteCount = strongSelf->_byteCount + [diskFileSize unsignedIntegerValue]; // atomic
-            }
-            
-            if (strongSelf->_byteLimit > 0 && strongSelf->_byteCount > strongSelf->_byteLimit)
-                [strongSelf trimToSizeByDate:strongSelf->_byteLimit block:nil];
-        } else {
-            fileURL = nil;
-        }
-
-        if (strongSelf->_didAddObjectBlock)
-            strongSelf->_didAddObjectBlock(strongSelf, key, object, written ? fileURL : nil);
-
-        if (block)
-            block(strongSelf, key, object, fileURL);
-
-        [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-    });
-}
-
-- (void)removeObjectForKey:(NSString *)key block:(TMDiskCacheObjectBlock)block
-{
-    if (!key)
-        return;
-
-    UIBackgroundTaskIdentifier taskID = [TMCacheBackgroundTaskManager beginBackgroundTask];
-
-    __weak TMDiskCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf) {
-            [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-            return;
-        }
-
-        NSURL *fileURL = [strongSelf encodedFileURLForKey:key];
-        [strongSelf removeFileAndExecuteBlocksForKey:key];
-
-        if (block)
-            block(strongSelf, key, nil, fileURL);
-
-        [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-    });
-}
-
-- (void)trimToSize:(NSUInteger)trimByteCount block:(TMDiskCacheBlock)block
-{
-    if (trimByteCount == 0) {
-        [self removeAllObjects:block];
-        return;
-    }
-
-    UIBackgroundTaskIdentifier taskID = [TMCacheBackgroundTaskManager beginBackgroundTask];
-    
-    __weak TMDiskCache *weakSelf = self;
-    
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf) {
-            [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-            return;
-        }
-
-        [strongSelf trimDiskToSize:trimByteCount];
-
-        if (block)
-            block(strongSelf);
-        
-        [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-    });
-}
-
-- (void)trimToDate:(NSDate *)trimDate block:(TMDiskCacheBlock)block
-{
-    if (!trimDate)
-        return;
-
-    if ([trimDate isEqualToDate:[NSDate distantPast]]) {
-        [self removeAllObjects:block];
-        return;
-    }
-    
-    UIBackgroundTaskIdentifier taskID = [TMCacheBackgroundTaskManager beginBackgroundTask];
-
-    __weak TMDiskCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf) {
-            [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-            return;
-        }
-
-        [strongSelf trimDiskToDate:trimDate];
-
-        if (block)
-            block(strongSelf);
-        
-        [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-    });
-}
-
-- (void)trimToSizeByDate:(NSUInteger)trimByteCount block:(TMDiskCacheBlock)block
-{
-    if (trimByteCount == 0) {
-        [self removeAllObjects:block];
-        return;
-    }
-
-    UIBackgroundTaskIdentifier taskID = [TMCacheBackgroundTaskManager beginBackgroundTask];
-
-    __weak TMDiskCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf) {
-            [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-            return;
-        }
-
-        [strongSelf trimDiskToSizeByDate:trimByteCount];
-
-        if (block)
-            block(strongSelf);
-
-        [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-    });
-}
-
-- (void)removeAllObjects:(TMDiskCacheBlock)block
-{
-    UIBackgroundTaskIdentifier taskID = [TMCacheBackgroundTaskManager beginBackgroundTask];
-    
-    __weak TMDiskCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf) {
-            [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-            return;
-        }
-
-        if (strongSelf->_willRemoveAllObjectsBlock)
-            strongSelf->_willRemoveAllObjectsBlock(strongSelf);
-        
-        [TMDiskCache moveItemAtURLToTrash:strongSelf->_cacheURL];
-        [TMDiskCache emptyTrash];
-
-        [strongSelf createCacheDirectory];
-
-        [strongSelf->_dates removeAllObjects];
-        [strongSelf->_sizes removeAllObjects];
-        strongSelf.byteCount = 0; // atomic
-
-        if (strongSelf->_didRemoveAllObjectsBlock)
-            strongSelf->_didRemoveAllObjectsBlock(strongSelf);
-
-        if (block)
-            block(strongSelf);
-        
-        [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-    });
-}
-
-- (void)enumerateObjectsWithBlock:(TMDiskCacheObjectBlock)block completionBlock:(TMDiskCacheBlock)completionBlock
-{
-    if (!block)
-        return;
-
-    UIBackgroundTaskIdentifier taskID = [TMCacheBackgroundTaskManager beginBackgroundTask];
-
-    __weak TMDiskCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf) {
-            [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-            return;
-        }
-
-        NSArray *keysSortedByDate = [strongSelf->_dates keysSortedByValueUsingSelector:@selector(compare:)];
-
-        for (NSString *key in keysSortedByDate) {
-            NSURL *fileURL = [strongSelf encodedFileURLForKey:key];
-            block(strongSelf, key, nil, fileURL);
-        }
-
-        if (completionBlock)
-            completionBlock(strongSelf);
-
-        [TMCacheBackgroundTaskManager endBackgroundTask:taskID];
-    });
-}
-
-#pragma mark - Public Synchronous Methods -
-
-- (id <NSCoding>)objectForKey:(NSString *)key
-{
-    if (!key)
-        return nil;
-
-    __block id <NSCoding> objectForKey = nil;
-
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self objectForKey:key block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
-        objectForKey = object;
-        dispatch_semaphore_signal(semaphore);
-    }];
-    
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-
-    return objectForKey;
-}
-
-- (NSURL *)fileURLForKey:(NSString *)key
-{
-    if (!key)
-        return nil;
-
-    __block NSURL *fileURLForKey = nil;
-
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self fileURLForKey:key block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
-        fileURLForKey = fileURL;
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-
-    return fileURLForKey;
-}
-
-- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key
-{
-    if (!object || !key)
-        return;
-    
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self setObject:object forKey:key block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)removeObjectForKey:(NSString *)key
-{
-    if (!key)
-        return;
-    
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self removeObjectForKey:key block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)trimToSize:(NSUInteger)byteCount
-{
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self trimToSize:byteCount block:^(TMDiskCache *cache) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)trimToDate:(NSDate *)date
-{
-    if (!date)
-        return;
-
-    if ([date isEqualToDate:[NSDate distantPast]]) {
-        [self removeAllObjects];
-        return;
-    }
-
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self trimToDate:date block:^(TMDiskCache *cache) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)trimToSizeByDate:(NSUInteger)byteCount
-{
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self trimToSizeByDate:byteCount block:^(TMDiskCache *cache) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)removeAllObjects
-{
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self removeAllObjects:^(TMDiskCache *cache) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)enumerateObjectsWithBlock:(TMDiskCacheObjectBlock)block
-{
-    if (!block)
-        return;
-
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self enumerateObjectsWithBlock:block completionBlock:^(TMDiskCache *cache) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-#pragma mark - Public Thread Safe Accessors -
-
-- (TMDiskCacheObjectBlock)willAddObjectBlock
-{
-    __block TMDiskCacheObjectBlock block = nil;
-
-    dispatch_sync(_queue, ^{
-        block = _willAddObjectBlock;
-    });
-
-    return block;
-}
-
-- (void)setWillAddObjectBlock:(TMDiskCacheObjectBlock)block
-{
-    __weak TMDiskCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_willAddObjectBlock = [block copy];
-    });
-}
-
-- (TMDiskCacheObjectBlock)willRemoveObjectBlock
-{
-    __block TMDiskCacheObjectBlock block = nil;
-
-    dispatch_sync(_queue, ^{
-        block = _willRemoveObjectBlock;
-    });
-
-    return block;
-}
-
-- (void)setWillRemoveObjectBlock:(TMDiskCacheObjectBlock)block
-{
-    __weak TMDiskCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_willRemoveObjectBlock = [block copy];
-    });
-}
-
-- (TMDiskCacheBlock)willRemoveAllObjectsBlock
-{
-    __block TMDiskCacheBlock block = nil;
-
-    dispatch_sync(_queue, ^{
-        block = _willRemoveAllObjectsBlock;
-    });
-
-    return block;
-}
-
-- (void)setWillRemoveAllObjectsBlock:(TMDiskCacheBlock)block
-{
-    __weak TMDiskCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_willRemoveAllObjectsBlock = [block copy];
-    });
-}
-
-- (TMDiskCacheObjectBlock)didAddObjectBlock
-{
-    __block TMDiskCacheObjectBlock block = nil;
-
-    dispatch_sync(_queue, ^{
-        block = _didAddObjectBlock;
-    });
-
-    return block;
-}
-
-- (void)setDidAddObjectBlock:(TMDiskCacheObjectBlock)block
-{
-    __weak TMDiskCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_didAddObjectBlock = [block copy];
-    });
-}
-
-- (TMDiskCacheObjectBlock)didRemoveObjectBlock
-{
-    __block TMDiskCacheObjectBlock block = nil;
-
-    dispatch_sync(_queue, ^{
-        block = _didRemoveObjectBlock;
-    });
-
-    return block;
-}
-
-- (void)setDidRemoveObjectBlock:(TMDiskCacheObjectBlock)block
-{
-    __weak TMDiskCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_didRemoveObjectBlock = [block copy];
-    });
-}
-
-- (TMDiskCacheBlock)didRemoveAllObjectsBlock
-{
-    __block TMDiskCacheBlock block = nil;
-
-    dispatch_sync(_queue, ^{
-        block = _didRemoveAllObjectsBlock;
-    });
-
-    return block;
-}
-
-- (void)setDidRemoveAllObjectsBlock:(TMDiskCacheBlock)block
-{
-    __weak TMDiskCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_didRemoveAllObjectsBlock = [block copy];
-    });
-}
-
-- (NSUInteger)byteLimit
-{
-    __block NSUInteger byteLimit = 0;
-    
-    dispatch_sync(_queue, ^{
-        byteLimit = _byteLimit;
-    });
-    
-    return byteLimit;
-}
-
-- (void)setByteLimit:(NSUInteger)byteLimit
-{
-    __weak TMDiskCache *weakSelf = self;
-    
-    dispatch_barrier_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-        
-        strongSelf->_byteLimit = byteLimit;
-
-        if (byteLimit > 0)
-            [strongSelf trimDiskToSizeByDate:byteLimit];
-    });
-}
-
-- (NSTimeInterval)ageLimit
-{
-    __block NSTimeInterval ageLimit = 0.0;
-    
-    dispatch_sync(_queue, ^{
-        ageLimit = _ageLimit;
-    });
-    
-    return ageLimit;
-}
-
-- (void)setAgeLimit:(NSTimeInterval)ageLimit
-{
-    __weak TMDiskCache *weakSelf = self;
-    
-    dispatch_barrier_async(_queue, ^{
-        TMDiskCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-        
-        strongSelf->_ageLimit = ageLimit;
-        
-        [strongSelf trimToAgeLimitRecursively];
-    });
-}
-
-#pragma mark - Background Tasks -
-
-+ (void)setBackgroundTaskManager:(id <TMCacheBackgroundTaskManager>)backgroundTaskManager {
-    TMCacheBackgroundTaskManager = backgroundTaskManager;
-}
-
-@end

+ 0 - 310
Benchmark/Vendor/TMCache/TMMemoryCache.h

@@ -1,310 +0,0 @@
-/**
- `TMMemoryCache` is a fast, thread safe key/value store similar to `NSCache`. On iOS it will clear itself
- automatically to reduce memory usage when the app receives a memory warning or goes into the background.
-
- Access is natively asynchronous. Every method accepts a callback block that runs on a concurrent
- <queue>, with cache writes protected by GCD barriers. Synchronous variations are provided.
- 
- All access to the cache is dated so the that the least-used objects can be trimmed first. Setting an
- optional <ageLimit> will trigger a GCD timer to periodically to trim the cache to that age.
- 
- Objects can optionally be set with a "cost", which could be a byte count or any other meaningful integer.
- Setting a <costLimit> will automatically keep the cache below that value with <trimToCostByDate:>.
-
- Values will not persist after application relaunch or returning from the background. See <TMCache> for
- a memory cache backed by a disk cache.
- */
-
-#import <Foundation/Foundation.h>
-
-@class TMMemoryCache;
-
-typedef void (^TMMemoryCacheBlock)(TMMemoryCache *cache);
-typedef void (^TMMemoryCacheObjectBlock)(TMMemoryCache *cache, NSString *key, id object);
-
-@interface TMMemoryCache : NSObject
-
-#pragma mark -
-/// @name Core
-
-/**
- A concurrent queue on which all work is done. It is exposed here so that it can be set to target some
- other queue, such as a global concurrent queue with a priority other than the default.
- */
-@property (readonly) dispatch_queue_t queue;
-
-/**
- The total accumulated cost.
- */
-@property (readonly) NSUInteger totalCost;
-
-/**
- The maximum cost allowed to accumulate before objects begin to be removed with <trimToCostByDate:>.
- */
-@property (assign) NSUInteger costLimit;
-
-/**
- The maximum number of seconds an object is allowed to exist in the cache. Setting this to a value
- greater than `0.0` will start a recurring GCD timer with the same period that calls <trimToDate:>.
- Setting it back to `0.0` will stop the timer. Defaults to `0.0`.
- */
-@property (assign) NSTimeInterval ageLimit;
-
-/**
- When `YES` on iOS the cache will remove all objects when the app receives a memory warning.
- Defaults to `YES`.
- */
-@property (assign) BOOL removeAllObjectsOnMemoryWarning;
-
-/**
- When `YES` on iOS the cache will remove all objects when the app enters the background.
- Defaults to `YES`.
- */
-@property (assign) BOOL removeAllObjectsOnEnteringBackground;
-
-#pragma mark -
-/// @name Event Blocks
-
-/**
- A block to be executed just before an object is added to the cache. This block will be excuted within
- a barrier, i.e. all reads and writes are suspended for the duration of the block.
- */
-@property (copy) TMMemoryCacheObjectBlock willAddObjectBlock;
-
-/**
- A block to be executed just before an object is removed from the cache. This block will be excuted
- within a barrier, i.e. all reads and writes are suspended for the duration of the block.
- */
-@property (copy) TMMemoryCacheObjectBlock willRemoveObjectBlock;
-
-/**
- A block to be executed just before all objects are removed from the cache as a result of <removeAllObjects:>.
- This block will be excuted within a barrier, i.e. all reads and writes are suspended for the duration of the block.
- */
-@property (copy) TMMemoryCacheBlock willRemoveAllObjectsBlock;
-
-/**
- A block to be executed just after an object is added to the cache. This block will be excuted within
- a barrier, i.e. all reads and writes are suspended for the duration of the block.
- */
-@property (copy) TMMemoryCacheObjectBlock didAddObjectBlock;
-
-/**
- A block to be executed just after an object is removed from the cache. This block will be excuted
- within a barrier, i.e. all reads and writes are suspended for the duration of the block.
- */
-@property (copy) TMMemoryCacheObjectBlock didRemoveObjectBlock;
-
-/**
- A block to be executed just after all objects are removed from the cache as a result of <removeAllObjects:>.
- This block will be excuted within a barrier, i.e. all reads and writes are suspended for the duration of the block.
- */
-@property (copy) TMMemoryCacheBlock didRemoveAllObjectsBlock;
-
-/**
- A block to be executed upon receiving a memory warning (iOS only) potentially in parallel with other blocks on the <queue>.
- This block will be executed regardless of the value of <removeAllObjectsOnMemoryWarning>. Defaults to `nil`.
- */
-@property (copy) TMMemoryCacheBlock didReceiveMemoryWarningBlock;
-
-/**
- A block to be executed when the app enters the background (iOS only) potentially in parallel with other blocks on the <queue>.
- This block will be executed regardless of the value of <removeAllObjectsOnEnteringBackground>. Defaults to `nil`.
- */
-@property (copy) TMMemoryCacheBlock didEnterBackgroundBlock;
-
-#pragma mark -
-/// @name Shared Cache
-
-/**
- A shared cache.
- 
- @result The shared singleton cache instance.
- */
-+ (instancetype)sharedCache;
-
-#pragma mark -
-/// @name Asynchronous Methods
-
-/**
- Retrieves the object for the specified key. This method returns immediately and executes the passed
- block after the object is available, potentially in parallel with other blocks on the <queue>.
- 
- @param key The key associated with the requested object.
- @param block A block to be executed concurrently when the object is available.
- */
-- (void)objectForKey:(NSString *)key block:(TMMemoryCacheObjectBlock)block;
-
-/**
- Stores an object in the cache for the specified key. This method returns immediately and executes the
- passed block after the object has been stored, potentially in parallel with other blocks on the <queue>.
- 
- @param object An object to store in the cache.
- @param key A key to associate with the object. This string will be copied.
- @param block A block to be executed concurrently after the object has been stored, or nil.
- */
-- (void)setObject:(id)object forKey:(NSString *)key block:(TMMemoryCacheObjectBlock)block;
-
-/**
- Stores an object in the cache for the specified key and the specified cost. If the cost causes the total
- to go over the <costLimit> the cache is trimmed (oldest objects first). This method returns immediately
- and executes the passed block after the object has been stored, potentially in parallel with other blocks
- on the <queue>.
- 
- @param object An object to store in the cache.
- @param key A key to associate with the object. This string will be copied.
- @param cost An amount to add to the <totalCost>.
- @param block A block to be executed concurrently after the object has been stored, or nil.
- */
-- (void)setObject:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost block:(TMMemoryCacheObjectBlock)block;
-
-/**
- Removes the object for the specified key. This method returns immediately and executes the passed
- block after the object has been removed, potentially in parallel with other blocks on the <queue>.
- 
- @param key The key associated with the object to be removed.
- @param block A block to be executed concurrently after the object has been removed, or nil.
- */
-- (void)removeObjectForKey:(NSString *)key block:(TMMemoryCacheObjectBlock)block;
-
-/**
- Removes all objects from the cache that have not been used since the specified date.
- This method returns immediately and executes the passed block after the cache has been trimmed,
- potentially in parallel with other blocks on the <queue>.
- 
- @param date Objects that haven't been accessed since this date are removed from the cache.
- @param block A block to be executed concurrently after the cache has been trimmed, or nil.
- */
-- (void)trimToDate:(NSDate *)date block:(TMMemoryCacheBlock)block;
-
-/**
- Removes objects from the cache, costliest objects first, until the <totalCost> is below the specified
- value. This method returns immediately and executes the passed block after the cache has been trimmed,
- potentially in parallel with other blocks on the <queue>.
- 
- @param cost The total accumulation allowed to remain after the cache has been trimmed.
- @param block A block to be executed concurrently after the cache has been trimmed, or nil.
- */
-- (void)trimToCost:(NSUInteger)cost block:(TMMemoryCacheBlock)block;
-
-/**
- Removes objects from the cache, ordered by date (least recently used first), until the <totalCost> is below
- the specified value. This method returns immediately and executes the passed block after the cache has been
- trimmed, potentially in parallel with other blocks on the <queue>.
-
- @param cost The total accumulation allowed to remain after the cache has been trimmed.
- @param block A block to be executed concurrently after the cache has been trimmed, or nil.
- */
-- (void)trimToCostByDate:(NSUInteger)cost block:(TMMemoryCacheBlock)block;
-
-/**
- Removes all objects from the cache. This method returns immediately and executes the passed block after
- the cache has been cleared, potentially in parallel with other blocks on the <queue>.
- 
- @param block A block to be executed concurrently after the cache has been cleared, or nil.
- */
-- (void)removeAllObjects:(TMMemoryCacheBlock)block;
-
-/**
- Loops through all objects in the cache within a memory barrier (reads and writes are suspended during the enumeration).
- This method returns immediately.
-
- @param block A block to be executed for every object in the cache.
- @param completionBlock An optional block to be executed concurrently when the enumeration is complete.
- */
-- (void)enumerateObjectsWithBlock:(TMMemoryCacheObjectBlock)block completionBlock:(TMMemoryCacheBlock)completionBlock;
-
-#pragma mark -
-/// @name Synchronous Methods
-
-/**
- Retrieves the object for the specified key. This method blocks the calling thread until the
- object is available.
- 
- @see objectForKey:block:
- @param key The key associated with the object.
- @result The object for the specified key.
- */
-- (id)objectForKey:(NSString *)key;
-
-/**
- Stores an object in the cache for the specified key. This method blocks the calling thread until the object
- has been set.
-
- @see setObject:forKey:block:
- @param object An object to store in the cache.
- @param key A key to associate with the object. This string will be copied.
- */
-- (void)setObject:(id)object forKey:(NSString *)key;
-
-/**
- Stores an object in the cache for the specified key and the specified cost. If the cost causes the total
- to go over the <costLimit> the cache is trimmed (oldest objects first). This method blocks the calling thread
- until the object has been stored.
-
- @param object An object to store in the cache.
- @param key A key to associate with the object. This string will be copied.
- @param cost An amount to add to the <totalCost>.
- */
-- (void)setObject:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost;
-
-/**
- Removes the object for the specified key. This method blocks the calling thread until the object
- has been removed.
- 
- @param key The key associated with the object to be removed.
- */
-- (void)removeObjectForKey:(NSString *)key;
-
-/**
- Removes all objects from the cache that have not been used since the specified date.
- This method blocks the calling thread until the cache has been trimmed.
- 
- @param date Objects that haven't been accessed since this date are removed from the cache.
- */
-- (void)trimToDate:(NSDate *)date;
-
-/**
- Removes objects from the cache, costliest objects first, until the <totalCost> is below the specified
- value. This method blocks the calling thread until the cache has been trimmed.
- 
- @param cost The total accumulation allowed to remain after the cache has been trimmed.
- */
-- (void)trimToCost:(NSUInteger)cost;
-
-/**
- Removes objects from the cache, ordered by date (least recently used first), until the <totalCost> is below
- the specified value. This method blocks the calling thread until the cache has been trimmed.
-
- @param cost The total accumulation allowed to remain after the cache has been trimmed.
- */
-- (void)trimToCostByDate:(NSUInteger)cost;
-
-/**
- Removes all objects from the cache. This method blocks the calling thread until the cache has been cleared.
- */
-- (void)removeAllObjects;
-
-/**
- Loops through all objects in the cache within a memory barrier (reads and writes are suspended during the enumeration).
- This method blocks the calling thread until all objects have been enumerated.
-
- @param block A block to be executed for every object in the cache.
- 
- @warning Do not call this method within the event blocks (<didReceiveMemoryWarningBlock>, etc.)
- Instead use the asynchronous version, <enumerateObjectsWithBlock:completionBlock:>.
- 
- */
-- (void)enumerateObjectsWithBlock:(TMMemoryCacheObjectBlock)block;
-
-/**
- Handle a memory warning.
- */
-- (void)handleMemoryWarning __deprecated_msg("This happens automatically in TMCache 2.1. There’s no longer a need to call it directly.");
-
-/**
- Handle the application having been backgrounded.
- */
-- (void)handleApplicationBackgrounding __deprecated_msg("This happens automatically in TMCache 2.1. There’s no longer a need to call it directly.");
-
-@end

+ 0 - 882
Benchmark/Vendor/TMCache/TMMemoryCache.m

@@ -1,882 +0,0 @@
-#import "TMMemoryCache.h"
-
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
-#import <UIKit/UIKit.h>
-#endif
-
-NSString * const TMMemoryCachePrefix = @"com.tumblr.TMMemoryCache";
-
-@interface TMMemoryCache ()
-#if OS_OBJECT_USE_OBJC
-@property (strong, nonatomic) dispatch_queue_t queue;
-#else
-@property (assign, nonatomic) dispatch_queue_t queue;
-#endif
-@property (strong, nonatomic) NSMutableDictionary *dictionary;
-@property (strong, nonatomic) NSMutableDictionary *dates;
-@property (strong, nonatomic) NSMutableDictionary *costs;
-@end
-
-@implementation TMMemoryCache
-
-@synthesize ageLimit = _ageLimit;
-@synthesize costLimit = _costLimit;
-@synthesize totalCost = _totalCost;
-@synthesize willAddObjectBlock = _willAddObjectBlock;
-@synthesize willRemoveObjectBlock = _willRemoveObjectBlock;
-@synthesize willRemoveAllObjectsBlock = _willRemoveAllObjectsBlock;
-@synthesize didAddObjectBlock = _didAddObjectBlock;
-@synthesize didRemoveObjectBlock = _didRemoveObjectBlock;
-@synthesize didRemoveAllObjectsBlock = _didRemoveAllObjectsBlock;
-@synthesize didReceiveMemoryWarningBlock = _didReceiveMemoryWarningBlock;
-@synthesize didEnterBackgroundBlock = _didEnterBackgroundBlock;
-
-#pragma mark - Initialization -
-
-- (void)dealloc
-{
-    [[NSNotificationCenter defaultCenter] removeObserver:self];
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(_queue);
-    _queue = nil;
-    #endif
-}
-
-- (id)init
-{
-    if (self = [super init]) {
-        NSString *queueName = [[NSString alloc] initWithFormat:@"%@.%p", TMMemoryCachePrefix, self];
-        _queue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_CONCURRENT);
-
-        _dictionary = [[NSMutableDictionary alloc] init];
-        _dates = [[NSMutableDictionary alloc] init];
-        _costs = [[NSMutableDictionary alloc] init];
-
-        _willAddObjectBlock = nil;
-        _willRemoveObjectBlock = nil;
-        _willRemoveAllObjectsBlock = nil;
-
-        _didAddObjectBlock = nil;
-        _didRemoveObjectBlock = nil;
-        _didRemoveAllObjectsBlock = nil;
-
-        _didReceiveMemoryWarningBlock = nil;
-        _didEnterBackgroundBlock = nil;
-
-        _ageLimit = 0.0;
-        _costLimit = 0;
-        _totalCost = 0;
-
-        _removeAllObjectsOnMemoryWarning = YES;
-        _removeAllObjectsOnEnteringBackground = YES;
-        
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
-        [[NSNotificationCenter defaultCenter] addObserver:self
-                                                 selector:@selector(handleMemoryWarning)
-                                                     name:UIApplicationDidReceiveMemoryWarningNotification
-                                                   object:nil];
-        
-        [[NSNotificationCenter defaultCenter] addObserver:self
-                                                 selector:@selector(handleApplicationBackgrounding)
-                                                     name:UIApplicationDidEnterBackgroundNotification
-                                                   object:nil];
-#endif
-    }
-    return self;
-}
-
-+ (instancetype)sharedCache
-{
-    static id cache;
-    static dispatch_once_t predicate;
-
-    dispatch_once(&predicate, ^{
-        cache = [[self alloc] init];
-    });
-
-    return cache;
-}
-
-#pragma mark - Private Methods -
-
-- (void)handleMemoryWarning
-{
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
-    
-    if (self.removeAllObjectsOnMemoryWarning)
-        [self removeAllObjects:nil];
-    
-    __weak TMMemoryCache *weakSelf = self;
-    
-    dispatch_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-        
-        if (strongSelf->_didReceiveMemoryWarningBlock)
-            strongSelf->_didReceiveMemoryWarningBlock(strongSelf);
-    });
-    
-#endif
-}
-
-- (void)handleApplicationBackgrounding
-{
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
-    
-    if (self.removeAllObjectsOnEnteringBackground)
-        [self removeAllObjects:nil];
-    
-    __weak TMMemoryCache *weakSelf = self;
-    
-    dispatch_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-        
-        if (strongSelf->_didEnterBackgroundBlock)
-            strongSelf->_didEnterBackgroundBlock(strongSelf);
-    });
-    
-#endif
-}
-
-- (void)removeObjectAndExecuteBlocksForKey:(NSString *)key
-{
-    id object = [_dictionary objectForKey:key];
-    NSNumber *cost = [_costs objectForKey:key];
-
-    if (_willRemoveObjectBlock)
-        _willRemoveObjectBlock(self, key, object);
-
-    if (cost)
-        _totalCost -= [cost unsignedIntegerValue];
-
-    [_dictionary removeObjectForKey:key];
-    [_dates removeObjectForKey:key];
-    [_costs removeObjectForKey:key];
-
-    if (_didRemoveObjectBlock)
-        _didRemoveObjectBlock(self, key, nil);
-}
-
-- (void)trimMemoryToDate:(NSDate *)trimDate
-{
-    NSArray *keysSortedByDate = [_dates keysSortedByValueUsingSelector:@selector(compare:)];
-    
-    for (NSString *key in keysSortedByDate) { // oldest objects first
-        NSDate *accessDate = [_dates objectForKey:key];
-        if (!accessDate)
-            continue;
-        
-        if ([accessDate compare:trimDate] == NSOrderedAscending) { // older than trim date
-            [self removeObjectAndExecuteBlocksForKey:key];
-        } else {
-            break;
-        }
-    }
-}
-
-- (void)trimToCostLimit:(NSUInteger)limit
-{
-    if (_totalCost <= limit)
-        return;
-
-    NSArray *keysSortedByCost = [_costs keysSortedByValueUsingSelector:@selector(compare:)];
-
-    for (NSString *key in [keysSortedByCost reverseObjectEnumerator]) { // costliest objects first
-        [self removeObjectAndExecuteBlocksForKey:key];
-
-        if (_totalCost <= limit)
-            break;
-    }
-}
-
-- (void)trimToCostLimitByDate:(NSUInteger)limit
-{
-    if (_totalCost <= limit)
-        return;
-
-    NSArray *keysSortedByDate = [_dates keysSortedByValueUsingSelector:@selector(compare:)];
-
-    for (NSString *key in keysSortedByDate) { // oldest objects first
-        [self removeObjectAndExecuteBlocksForKey:key];
-
-        if (_totalCost <= limit)
-            break;
-    }
-}
-
-- (void)trimToAgeLimitRecursively
-{
-    if (_ageLimit == 0.0)
-        return;
-
-    NSDate *date = [[NSDate alloc] initWithTimeIntervalSinceNow:-_ageLimit];
-    [self trimMemoryToDate:date];
-    
-    __weak TMMemoryCache *weakSelf = self;
-    
-    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_ageLimit * NSEC_PER_SEC));
-    dispatch_after(time, _queue, ^(void){
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-        
-        __weak TMMemoryCache *weakSelf = strongSelf;
-        
-        dispatch_barrier_async(strongSelf->_queue, ^{
-            TMMemoryCache *strongSelf = weakSelf;
-            [strongSelf trimToAgeLimitRecursively];
-        });
-    });
-}
-
-#pragma mark - Public Asynchronous Methods -
-
-- (void)objectForKey:(NSString *)key block:(TMMemoryCacheObjectBlock)block
-{
-    NSDate *now = [[NSDate alloc] init];
-    
-    if (!key || !block)
-        return;
-
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        id object = [strongSelf->_dictionary objectForKey:key];
-
-        if (object) {
-            __weak TMMemoryCache *weakSelf = strongSelf;
-            dispatch_barrier_async(strongSelf->_queue, ^{
-                TMMemoryCache *strongSelf = weakSelf;
-                if (strongSelf)
-                    [strongSelf->_dates setObject:now forKey:key];
-            });
-        }
-
-        block(strongSelf, key, object);
-    });
-}
-
-- (void)setObject:(id)object forKey:(NSString *)key block:(TMMemoryCacheObjectBlock)block
-{
-    [self setObject:object forKey:key withCost:0 block:block];
-}
-
-- (void)setObject:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost block:(TMMemoryCacheObjectBlock)block
-{
-    NSDate *now = [[NSDate alloc] init];
-
-    if (!key || !object)
-        return;
-
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        if (strongSelf->_willAddObjectBlock)
-            strongSelf->_willAddObjectBlock(strongSelf, key, object);
-
-        [strongSelf->_dictionary setObject:object forKey:key];
-        [strongSelf->_dates setObject:now forKey:key];
-        [strongSelf->_costs setObject:@(cost) forKey:key];
-
-        _totalCost += cost;
-
-        if (strongSelf->_didAddObjectBlock)
-            strongSelf->_didAddObjectBlock(strongSelf, key, object);
-
-        if (strongSelf->_costLimit > 0)
-            [strongSelf trimToCostByDate:strongSelf->_costLimit block:nil];
-
-        if (block) {
-            __weak TMMemoryCache *weakSelf = strongSelf;
-            dispatch_async(strongSelf->_queue, ^{
-                TMMemoryCache *strongSelf = weakSelf;
-                if (strongSelf)
-                    block(strongSelf, key, object);
-            });
-        }
-    });
-}
-
-- (void)removeObjectForKey:(NSString *)key block:(TMMemoryCacheObjectBlock)block
-{
-    if (!key)
-        return;
-
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        [strongSelf removeObjectAndExecuteBlocksForKey:key];
-
-        if (block) {
-            __weak TMMemoryCache *weakSelf = strongSelf;
-            dispatch_async(strongSelf->_queue, ^{
-                TMMemoryCache *strongSelf = weakSelf;
-                if (strongSelf)
-                    block(strongSelf, key, nil);
-            });
-        }
-    });
-}
-
-- (void)trimToDate:(NSDate *)trimDate block:(TMMemoryCacheBlock)block
-{
-    if (!trimDate)
-        return;
-
-    if ([trimDate isEqualToDate:[NSDate distantPast]]) {
-        [self removeAllObjects:block];
-        return;
-    }
-
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        [strongSelf trimMemoryToDate:trimDate];
-
-        if (block) {
-            __weak TMMemoryCache *weakSelf = strongSelf;
-            dispatch_async(strongSelf->_queue, ^{
-                TMMemoryCache *strongSelf = weakSelf;
-                if (strongSelf)
-                    block(strongSelf);
-            });
-        }
-    });
-}
-
-- (void)trimToCost:(NSUInteger)cost block:(TMMemoryCacheBlock)block
-{
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        [strongSelf trimToCostLimit:cost];
-
-        if (block) {
-            __weak TMMemoryCache *weakSelf = strongSelf;
-            dispatch_async(strongSelf->_queue, ^{
-                TMMemoryCache *strongSelf = weakSelf;
-                if (strongSelf)
-                    block(strongSelf);
-            });
-        }
-    });
-}
-
-- (void)trimToCostByDate:(NSUInteger)cost block:(TMMemoryCacheBlock)block
-{
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        [strongSelf trimToCostLimitByDate:cost];
-
-        if (block) {
-            __weak TMMemoryCache *weakSelf = strongSelf;
-            dispatch_async(strongSelf->_queue, ^{
-                TMMemoryCache *strongSelf = weakSelf;
-                if (strongSelf)
-                    block(strongSelf);
-            });
-        }
-    });
-}
-
-- (void)removeAllObjects:(TMMemoryCacheBlock)block
-{
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        if (strongSelf->_willRemoveAllObjectsBlock)
-            strongSelf->_willRemoveAllObjectsBlock(strongSelf);
-
-        [strongSelf->_dictionary removeAllObjects];
-        [strongSelf->_dates removeAllObjects];
-        [strongSelf->_costs removeAllObjects];
-        
-        strongSelf->_totalCost = 0;
-
-        if (strongSelf->_didRemoveAllObjectsBlock)
-            strongSelf->_didRemoveAllObjectsBlock(strongSelf);
-
-        if (block) {
-            __weak TMMemoryCache *weakSelf = strongSelf;
-            dispatch_async(strongSelf->_queue, ^{
-                TMMemoryCache *strongSelf = weakSelf;
-                if (strongSelf)
-                    block(strongSelf);
-            });
-        }
-    });
-}
-
-- (void)enumerateObjectsWithBlock:(TMMemoryCacheObjectBlock)block completionBlock:(TMMemoryCacheBlock)completionBlock
-{
-    if (!block)
-        return;
-
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        NSArray *keysSortedByDate = [strongSelf->_dates keysSortedByValueUsingSelector:@selector(compare:)];
-        
-        for (NSString *key in keysSortedByDate) {
-            block(strongSelf, key, [strongSelf->_dictionary objectForKey:key]);
-        }
-
-        if (completionBlock) {
-            __weak TMMemoryCache *weakSelf = strongSelf;
-            dispatch_async(strongSelf->_queue, ^{
-                TMMemoryCache *strongSelf = weakSelf;
-                if (strongSelf)
-                    completionBlock(strongSelf);
-            });
-        }
-    });
-}
-
-#pragma mark - Public Synchronous Methods -
-
-- (id)objectForKey:(NSString *)key
-{
-    if (!key)
-        return nil;
-
-    __block id objectForKey = nil;
-
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self objectForKey:key block:^(TMMemoryCache *cache, NSString *key, id object) {
-        objectForKey = object;
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-
-    return objectForKey;
-}
-
-- (void)setObject:(id)object forKey:(NSString *)key
-{
-    [self setObject:object forKey:key withCost:0];
-}
-
-- (void)setObject:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost
-{
-    if (!object || !key)
-        return;
-
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self setObject:object forKey:key withCost:cost block:^(TMMemoryCache *cache, NSString *key, id object) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)removeObjectForKey:(NSString *)key
-{
-    if (!key)
-        return;
-    
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self removeObjectForKey:key block:^(TMMemoryCache *cache, NSString *key, id object) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)trimToDate:(NSDate *)date
-{
-    if (!date)
-        return;
-
-    if ([date isEqualToDate:[NSDate distantPast]]) {
-        [self removeAllObjects];
-        return;
-    }
-    
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self trimToDate:date block:^(TMMemoryCache *cache) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)trimToCost:(NSUInteger)cost
-{
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self trimToCost:cost block:^(TMMemoryCache *cache) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)trimToCostByDate:(NSUInteger)cost
-{
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self trimToCostByDate:cost block:^(TMMemoryCache *cache) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)removeAllObjects
-{
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self removeAllObjects:^(TMMemoryCache *cache) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-- (void)enumerateObjectsWithBlock:(TMMemoryCacheObjectBlock)block
-{
-    if (!block)
-        return;
-
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
-    [self enumerateObjectsWithBlock:block completionBlock:^(TMMemoryCache *cache) {
-        dispatch_semaphore_signal(semaphore);
-    }];
-
-    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
-    #if !OS_OBJECT_USE_OBJC
-    dispatch_release(semaphore);
-    #endif
-}
-
-#pragma mark - Public Thread Safe Accessors -
-
-- (TMMemoryCacheObjectBlock)willAddObjectBlock
-{
-    __block TMMemoryCacheObjectBlock block = nil;
-
-    dispatch_sync(_queue, ^{
-        block = self->_willAddObjectBlock;
-    });
-
-    return block;
-}
-
-- (void)setWillAddObjectBlock:(TMMemoryCacheObjectBlock)block
-{
-    __weak TMMemoryCache *weakSelf = self;
-    
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_willAddObjectBlock = [block copy];
-    });
-}
-
-- (TMMemoryCacheObjectBlock)willRemoveObjectBlock
-{
-    __block TMMemoryCacheObjectBlock block = nil;
-
-    dispatch_sync(_queue, ^{
-        block = _willRemoveObjectBlock;
-    });
-
-    return block;
-}
-
-- (void)setWillRemoveObjectBlock:(TMMemoryCacheObjectBlock)block
-{
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_willRemoveObjectBlock = [block copy];
-    });
-}
-
-- (TMMemoryCacheBlock)willRemoveAllObjectsBlock
-{
-    __block TMMemoryCacheBlock block = nil;
-
-    dispatch_sync(_queue, ^{
-        block = _willRemoveAllObjectsBlock;
-    });
-
-    return block;
-}
-
-- (void)setWillRemoveAllObjectsBlock:(TMMemoryCacheBlock)block
-{
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_willRemoveAllObjectsBlock = [block copy];
-    });
-}
-
-- (TMMemoryCacheObjectBlock)didAddObjectBlock
-{
-    __block TMMemoryCacheObjectBlock block = nil;
-
-    dispatch_sync(_queue, ^{
-        block = _didAddObjectBlock;
-    });
-
-    return block;
-}
-
-- (void)setDidAddObjectBlock:(TMMemoryCacheObjectBlock)block
-{
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_didAddObjectBlock = [block copy];
-    });
-}
-
-- (TMMemoryCacheObjectBlock)didRemoveObjectBlock
-{
-    __block TMMemoryCacheObjectBlock block = nil;
-
-    dispatch_sync(_queue, ^{
-        block = _didRemoveObjectBlock;
-    });
-
-    return block;
-}
-
-- (void)setDidRemoveObjectBlock:(TMMemoryCacheObjectBlock)block
-{
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_didRemoveObjectBlock = [block copy];
-    });
-}
-
-- (TMMemoryCacheBlock)didRemoveAllObjectsBlock
-{
-    __block TMMemoryCacheBlock block = nil;
-
-    dispatch_sync(_queue, ^{
-        block = _didRemoveAllObjectsBlock;
-    });
-
-    return block;
-}
-
-- (void)setDidRemoveAllObjectsBlock:(TMMemoryCacheBlock)block
-{
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_didRemoveAllObjectsBlock = [block copy];
-    });
-}
-
-- (TMMemoryCacheBlock)didReceiveMemoryWarningBlock
-{
-    __block TMMemoryCacheBlock block = nil;
-
-    dispatch_sync(_queue, ^{
-        block = _didReceiveMemoryWarningBlock;
-    });
-
-    return block;
-}
-
-- (void)setDidReceiveMemoryWarningBlock:(TMMemoryCacheBlock)block
-{
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_didReceiveMemoryWarningBlock = [block copy];
-    });
-}
-
-- (TMMemoryCacheBlock)didEnterBackgroundBlock
-{
-    __block TMMemoryCacheBlock block = nil;
-
-    dispatch_sync(_queue, ^{
-        block = _didEnterBackgroundBlock;
-    });
-
-    return block;
-}
-
-- (void)setDidEnterBackgroundBlock:(TMMemoryCacheBlock)block
-{
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_didEnterBackgroundBlock = [block copy];
-    });
-}
-
-- (NSTimeInterval)ageLimit
-{
-    __block NSTimeInterval ageLimit = 0.0;
-    
-    dispatch_sync(_queue, ^{
-        ageLimit = _ageLimit;
-    });
-    
-    return ageLimit;
-}
-
-- (void)setAgeLimit:(NSTimeInterval)ageLimit
-{
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-        
-        strongSelf->_ageLimit = ageLimit;
-        
-        [strongSelf trimToAgeLimitRecursively];
-    });
-}
-
-- (NSUInteger)costLimit
-{
-    __block NSUInteger costLimit = 0;
-
-    dispatch_sync(_queue, ^{
-        costLimit = _costLimit;
-    });
-
-    return costLimit;
-}
-
-- (void)setCostLimit:(NSUInteger)costLimit
-{
-    __weak TMMemoryCache *weakSelf = self;
-
-    dispatch_barrier_async(_queue, ^{
-        TMMemoryCache *strongSelf = weakSelf;
-        if (!strongSelf)
-            return;
-
-        strongSelf->_costLimit = costLimit;
-
-        if (costLimit > 0)
-            [strongSelf trimToCostLimitByDate:costLimit];
-    });
-}
-
-- (NSUInteger)totalCost
-{
-    __block NSUInteger cost = 0;
-    
-    dispatch_sync(_queue, ^{
-        cost = _totalCost;
-    });
-    
-    return cost;
-}
-
-@end

+ 2 - 0
Benchmark/Vendor/version.txt

@@ -0,0 +1,2 @@
+PINCache: 3.0.1 Beta 5
+SQLite: 3.19.03.00

+ 1 - 3
Framework/Info.plist

@@ -3,7 +3,7 @@
 <plist version="1.0">
 <dict>
 	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
 	<key>CFBundleExecutable</key>
 	<string>$(EXECUTABLE_NAME)</string>
 	<key>CFBundleIdentifier</key>
@@ -16,8 +16,6 @@
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
 	<string>1.0.4</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
 	<key>CFBundleVersion</key>
 	<string>$(CURRENT_PROJECT_VERSION)</string>
 	<key>NSPrincipalClass</key>

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 189
Framework/YYCache-Static.xcodeproj/project.pbxproj


+ 0 - 7
Framework/YYCache-Static.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
-   version = "1.0">
-   <FileRef
-      location = "self:/Users/ibireme/Dev/YYKitNew/Projects/YYCache/Framework/Fake/YYCache/YYCache-Static.xcodeproj">
-   </FileRef>
-</Workspace>

+ 129 - 109
Framework/YYCache.xcodeproj/project.pbxproj

@@ -3,126 +3,126 @@
 	archiveVersion = 1;
 	classes = {
 	};
-	objectVersion = 46;
+	objectVersion = 48;
 	objects = {
 
 /* Begin PBXBuildFile section */
-		D9D4190B1BD0F04000CD8EBF /* YYCache.h in Headers */ = {isa = PBXBuildFile; fileRef = D9D419031BD0F04000CD8EBF /* YYCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9D4190C1BD0F04000CD8EBF /* YYCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D419041BD0F04000CD8EBF /* YYCache.m */; };
-		D9D4190D1BD0F04000CD8EBF /* YYDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = D9D419051BD0F04000CD8EBF /* YYDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9D4190E1BD0F04000CD8EBF /* YYDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D419061BD0F04000CD8EBF /* YYDiskCache.m */; };
-		D9D4190F1BD0F04000CD8EBF /* YYKVStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = D9D419071BD0F04000CD8EBF /* YYKVStorage.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9D419101BD0F04000CD8EBF /* YYKVStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D419081BD0F04000CD8EBF /* YYKVStorage.m */; };
-		D9D419111BD0F04000CD8EBF /* YYMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = D9D419091BD0F04000CD8EBF /* YYMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9D419121BD0F04000CD8EBF /* YYMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D4190A1BD0F04000CD8EBF /* YYMemoryCache.m */; };
-		D9D419151BD0F07100CD8EBF /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9D419141BD0F07100CD8EBF /* UIKit.framework */; };
-		D9D419171BD0F07600CD8EBF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9D419161BD0F07600CD8EBF /* CoreFoundation.framework */; };
-		D9D419191BD0F07E00CD8EBF /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D9D419181BD0F07E00CD8EBF /* libsqlite3.tbd */; };
-		D9D4191B1BD0F08D00CD8EBF /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9D4191A1BD0F08D00CD8EBF /* QuartzCore.framework */; };
+		D9F591EB1F05472F00769742 /* YYCache.h in Headers */ = {isa = PBXBuildFile; fileRef = D9F591E31F05472F00769742 /* YYCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		D9F591EC1F05472F00769742 /* YYCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9F591E41F05472F00769742 /* YYCache.m */; };
+		D9F591ED1F05472F00769742 /* YYDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = D9F591E51F05472F00769742 /* YYDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		D9F591EE1F05472F00769742 /* YYDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9F591E61F05472F00769742 /* YYDiskCache.m */; };
+		D9F591EF1F05472F00769742 /* YYKVStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = D9F591E71F05472F00769742 /* YYKVStorage.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		D9F591F01F05472F00769742 /* YYKVStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9F591E81F05472F00769742 /* YYKVStorage.m */; };
+		D9F591F11F05472F00769742 /* YYMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = D9F591E91F05472F00769742 /* YYMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		D9F591F21F05472F00769742 /* YYMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9F591EA1F05472F00769742 /* YYMemoryCache.m */; };
+		D9F591F51F05474100769742 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D9F591F41F05474100769742 /* libsqlite3.tbd */; };
+		D9F591F81F05477500769742 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9F591F71F05477500769742 /* CoreFoundation.framework */; };
+		D9F591FA1F05477B00769742 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9F591F91F05477B00769742 /* UIKit.framework */; };
+		D9F591FC1F05478400769742 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9F591FB1F05478400769742 /* QuartzCore.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
-		D9D418F51BD0EFE300CD8EBF /* YYCache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YYCache.framework; sourceTree = BUILT_PRODUCTS_DIR; };
-		D9D419001BD0EFFF00CD8EBF /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		D9D419031BD0F04000CD8EBF /* YYCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYCache.h; sourceTree = "<group>"; };
-		D9D419041BD0F04000CD8EBF /* YYCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYCache.m; sourceTree = "<group>"; };
-		D9D419051BD0F04000CD8EBF /* YYDiskCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYDiskCache.h; sourceTree = "<group>"; };
-		D9D419061BD0F04000CD8EBF /* YYDiskCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYDiskCache.m; sourceTree = "<group>"; };
-		D9D419071BD0F04000CD8EBF /* YYKVStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYKVStorage.h; sourceTree = "<group>"; };
-		D9D419081BD0F04000CD8EBF /* YYKVStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYKVStorage.m; sourceTree = "<group>"; };
-		D9D419091BD0F04000CD8EBF /* YYMemoryCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYMemoryCache.h; sourceTree = "<group>"; };
-		D9D4190A1BD0F04000CD8EBF /* YYMemoryCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYMemoryCache.m; sourceTree = "<group>"; };
-		D9D419141BD0F07100CD8EBF /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
-		D9D419161BD0F07600CD8EBF /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
-		D9D419181BD0F07E00CD8EBF /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
-		D9D4191A1BD0F08D00CD8EBF /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+		D93C45AC1F05445A009F80F9 /* YYCache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YYCache.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		D93C45B01F05445A009F80F9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		D9F591E31F05472F00769742 /* YYCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYCache.h; sourceTree = "<group>"; };
+		D9F591E41F05472F00769742 /* YYCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYCache.m; sourceTree = "<group>"; };
+		D9F591E51F05472F00769742 /* YYDiskCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYDiskCache.h; sourceTree = "<group>"; };
+		D9F591E61F05472F00769742 /* YYDiskCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYDiskCache.m; sourceTree = "<group>"; };
+		D9F591E71F05472F00769742 /* YYKVStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYKVStorage.h; sourceTree = "<group>"; };
+		D9F591E81F05472F00769742 /* YYKVStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYKVStorage.m; sourceTree = "<group>"; };
+		D9F591E91F05472F00769742 /* YYMemoryCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYMemoryCache.h; sourceTree = "<group>"; };
+		D9F591EA1F05472F00769742 /* YYMemoryCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYMemoryCache.m; sourceTree = "<group>"; };
+		D9F591F41F05474100769742 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
+		D9F591F71F05477500769742 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
+		D9F591F91F05477B00769742 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+		D9F591FB1F05478400769742 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
-		D9D418F11BD0EFE300CD8EBF /* Frameworks */ = {
+		D93C45A81F05445A009F80F9 /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				D9D419151BD0F07100CD8EBF /* UIKit.framework in Frameworks */,
-				D9D419171BD0F07600CD8EBF /* CoreFoundation.framework in Frameworks */,
-				D9D4191B1BD0F08D00CD8EBF /* QuartzCore.framework in Frameworks */,
-				D9D419191BD0F07E00CD8EBF /* libsqlite3.tbd in Frameworks */,
+				D9F591FC1F05478400769742 /* QuartzCore.framework in Frameworks */,
+				D9F591FA1F05477B00769742 /* UIKit.framework in Frameworks */,
+				D9F591F81F05477500769742 /* CoreFoundation.framework in Frameworks */,
+				D9F591F51F05474100769742 /* libsqlite3.tbd in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
-		D9D418EB1BD0EFE300CD8EBF = {
+		D93C45A21F05445A009F80F9 = {
 			isa = PBXGroup;
 			children = (
-				D9D419021BD0F04000CD8EBF /* YYCache */,
-				D9D419131BD0F04C00CD8EBF /* Supporting Files */,
-				D9D418F61BD0EFE300CD8EBF /* Products */,
+				D9F591E21F05472F00769742 /* YYCache */,
+				D9F591F61F05477500769742 /* Frameworks */,
+				D93C45AD1F05445A009F80F9 /* Products */,
 			);
 			sourceTree = "<group>";
 		};
-		D9D418F61BD0EFE300CD8EBF /* Products */ = {
+		D93C45AD1F05445A009F80F9 /* Products */ = {
 			isa = PBXGroup;
 			children = (
-				D9D418F51BD0EFE300CD8EBF /* YYCache.framework */,
+				D93C45AC1F05445A009F80F9 /* YYCache.framework */,
 			);
 			name = Products;
 			sourceTree = "<group>";
 		};
-		D9D419021BD0F04000CD8EBF /* YYCache */ = {
+		D9F591E21F05472F00769742 /* YYCache */ = {
 			isa = PBXGroup;
 			children = (
-				D9D419031BD0F04000CD8EBF /* YYCache.h */,
-				D9D419041BD0F04000CD8EBF /* YYCache.m */,
-				D9D419091BD0F04000CD8EBF /* YYMemoryCache.h */,
-				D9D4190A1BD0F04000CD8EBF /* YYMemoryCache.m */,
-				D9D419051BD0F04000CD8EBF /* YYDiskCache.h */,
-				D9D419061BD0F04000CD8EBF /* YYDiskCache.m */,
-				D9D419071BD0F04000CD8EBF /* YYKVStorage.h */,
-				D9D419081BD0F04000CD8EBF /* YYKVStorage.m */,
+				D9F591E31F05472F00769742 /* YYCache.h */,
+				D9F591E41F05472F00769742 /* YYCache.m */,
+				D9F591E91F05472F00769742 /* YYMemoryCache.h */,
+				D9F591EA1F05472F00769742 /* YYMemoryCache.m */,
+				D9F591E51F05472F00769742 /* YYDiskCache.h */,
+				D9F591E61F05472F00769742 /* YYDiskCache.m */,
+				D9F591E71F05472F00769742 /* YYKVStorage.h */,
+				D9F591E81F05472F00769742 /* YYKVStorage.m */,
 			);
 			name = YYCache;
 			path = ../YYCache;
 			sourceTree = "<group>";
 		};
-		D9D419131BD0F04C00CD8EBF /* Supporting Files */ = {
+		D9F591F61F05477500769742 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
-				D9D419161BD0F07600CD8EBF /* CoreFoundation.framework */,
-				D9D419141BD0F07100CD8EBF /* UIKit.framework */,
-				D9D4191A1BD0F08D00CD8EBF /* QuartzCore.framework */,
-				D9D419181BD0F07E00CD8EBF /* libsqlite3.tbd */,
-				D9D419001BD0EFFF00CD8EBF /* Info.plist */,
+				D9F591F91F05477B00769742 /* UIKit.framework */,
+				D9F591F71F05477500769742 /* CoreFoundation.framework */,
+				D9F591FB1F05478400769742 /* QuartzCore.framework */,
+				D9F591F41F05474100769742 /* libsqlite3.tbd */,
+				D93C45B01F05445A009F80F9 /* Info.plist */,
 			);
-			name = "Supporting Files";
+			name = Frameworks;
 			sourceTree = "<group>";
 		};
 /* End PBXGroup section */
 
 /* Begin PBXHeadersBuildPhase section */
-		D9D418F21BD0EFE300CD8EBF /* Headers */ = {
+		D93C45A91F05445A009F80F9 /* Headers */ = {
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				D9D419111BD0F04000CD8EBF /* YYMemoryCache.h in Headers */,
-				D9D4190F1BD0F04000CD8EBF /* YYKVStorage.h in Headers */,
-				D9D4190D1BD0F04000CD8EBF /* YYDiskCache.h in Headers */,
-				D9D4190B1BD0F04000CD8EBF /* YYCache.h in Headers */,
+				D9F591F11F05472F00769742 /* YYMemoryCache.h in Headers */,
+				D9F591EF1F05472F00769742 /* YYKVStorage.h in Headers */,
+				D9F591ED1F05472F00769742 /* YYDiskCache.h in Headers */,
+				D9F591EB1F05472F00769742 /* YYCache.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXHeadersBuildPhase section */
 
 /* Begin PBXNativeTarget section */
-		D9D418F41BD0EFE300CD8EBF /* YYCache */ = {
+		D93C45AB1F05445A009F80F9 /* YYCache */ = {
 			isa = PBXNativeTarget;
-			buildConfigurationList = D9D418FD1BD0EFE300CD8EBF /* Build configuration list for PBXNativeTarget "YYCache" */;
+			buildConfigurationList = D93C45B41F05445A009F80F9 /* Build configuration list for PBXNativeTarget "YYCache" */;
 			buildPhases = (
-				D9D418F01BD0EFE300CD8EBF /* Sources */,
-				D9D418F11BD0EFE300CD8EBF /* Frameworks */,
-				D9D418F21BD0EFE300CD8EBF /* Headers */,
-				D9D418F31BD0EFE300CD8EBF /* Resources */,
+				D93C45A71F05445A009F80F9 /* Sources */,
+				D93C45A81F05445A009F80F9 /* Frameworks */,
+				D93C45A91F05445A009F80F9 /* Headers */,
+				D93C45AA1F05445A009F80F9 /* Resources */,
 			);
 			buildRules = (
 			);
@@ -130,42 +130,42 @@
 			);
 			name = YYCache;
 			productName = YYCache;
-			productReference = D9D418F51BD0EFE300CD8EBF /* YYCache.framework */;
+			productReference = D93C45AC1F05445A009F80F9 /* YYCache.framework */;
 			productType = "com.apple.product-type.framework";
 		};
 /* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
-		D9D418EC1BD0EFE300CD8EBF /* Project object */ = {
+		D93C45A31F05445A009F80F9 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0800;
+				LastUpgradeCheck = 0900;
 				ORGANIZATIONNAME = ibireme;
 				TargetAttributes = {
-					D9D418F41BD0EFE300CD8EBF = {
-						CreatedOnToolsVersion = 7.0;
+					D93C45AB1F05445A009F80F9 = {
+						CreatedOnToolsVersion = 9.0;
 					};
 				};
 			};
-			buildConfigurationList = D9D418EF1BD0EFE300CD8EBF /* Build configuration list for PBXProject "YYCache" */;
-			compatibilityVersion = "Xcode 3.2";
-			developmentRegion = English;
+			buildConfigurationList = D93C45A61F05445A009F80F9 /* Build configuration list for PBXProject "YYCache" */;
+			compatibilityVersion = "Xcode 8.0";
+			developmentRegion = en;
 			hasScannedForEncodings = 0;
 			knownRegions = (
 				en,
 			);
-			mainGroup = D9D418EB1BD0EFE300CD8EBF;
-			productRefGroup = D9D418F61BD0EFE300CD8EBF /* Products */;
+			mainGroup = D93C45A21F05445A009F80F9;
+			productRefGroup = D93C45AD1F05445A009F80F9 /* Products */;
 			projectDirPath = "";
 			projectRoot = "";
 			targets = (
-				D9D418F41BD0EFE300CD8EBF /* YYCache */,
+				D93C45AB1F05445A009F80F9 /* YYCache */,
 			);
 		};
 /* End PBXProject section */
 
 /* Begin PBXResourcesBuildPhase section */
-		D9D418F31BD0EFE300CD8EBF /* Resources */ = {
+		D93C45AA1F05445A009F80F9 /* Resources */ = {
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
@@ -175,46 +175,56 @@
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
-		D9D418F01BD0EFE300CD8EBF /* Sources */ = {
+		D93C45A71F05445A009F80F9 /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				D9D419101BD0F04000CD8EBF /* YYKVStorage.m in Sources */,
-				D9D419121BD0F04000CD8EBF /* YYMemoryCache.m in Sources */,
-				D9D4190C1BD0F04000CD8EBF /* YYCache.m in Sources */,
-				D9D4190E1BD0F04000CD8EBF /* YYDiskCache.m in Sources */,
+				D9F591F01F05472F00769742 /* YYKVStorage.m in Sources */,
+				D9F591F21F05472F00769742 /* YYMemoryCache.m in Sources */,
+				D9F591EC1F05472F00769742 /* YYCache.m in Sources */,
+				D9F591EE1F05472F00769742 /* YYDiskCache.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXSourcesBuildPhase section */
 
 /* Begin XCBuildConfiguration section */
-		D9D418FB1BD0EFE300CD8EBF /* Debug */ = {
+		D93C45B21F05445A009F80F9 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 				CLANG_WARN_EMPTY_BODY = YES;
 				CLANG_WARN_ENUM_CONVERSION = YES;
 				CLANG_WARN_INFINITE_RECURSION = YES;
 				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
 				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
 				COPY_PHASE_STRIP = NO;
 				CURRENT_PROJECT_VERSION = 1;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_DYNAMIC_NO_PIC = NO;
 				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_OPTIMIZATION_LEVEL = 0;
@@ -232,38 +242,47 @@
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = iphoneos;
-				TARGETED_DEVICE_FAMILY = "1,2";
 				VERSIONING_SYSTEM = "apple-generic";
 				VERSION_INFO_PREFIX = "";
 			};
 			name = Debug;
 		};
-		D9D418FC1BD0EFE300CD8EBF /* Release */ = {
+		D93C45B31F05445A009F80F9 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 				CLANG_WARN_EMPTY_BODY = YES;
 				CLANG_WARN_ENUM_CONVERSION = YES;
 				CLANG_WARN_INFINITE_RECURSION = YES;
 				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
 				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
 				COPY_PHASE_STRIP = NO;
 				CURRENT_PROJECT_VERSION = 1;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				ENABLE_NS_ASSERTIONS = NO;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
@@ -274,71 +293,72 @@
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				SDKROOT = iphoneos;
-				TARGETED_DEVICE_FAMILY = "1,2";
 				VALIDATE_PRODUCT = YES;
 				VERSIONING_SYSTEM = "apple-generic";
 				VERSION_INFO_PREFIX = "";
 			};
 			name = Release;
 		};
-		D9D418FE1BD0EFE300CD8EBF /* Debug */ = {
+		D93C45B51F05445A009F80F9 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				CODE_SIGN_IDENTITY = "";
 				DEFINES_MODULE = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
-				INFOPLIST_FILE = Info.plist;
+				INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
-				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = com.ibireme.YYCache;
-				PRODUCT_NAME = "$(TARGET_NAME)";
+				PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
 				SKIP_INSTALL = YES;
+				TARGETED_DEVICE_FAMILY = "1,2";
 			};
 			name = Debug;
 		};
-		D9D418FF1BD0EFE300CD8EBF /* Release */ = {
+		D93C45B61F05445A009F80F9 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				CODE_SIGN_IDENTITY = "";
 				DEFINES_MODULE = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
-				INFOPLIST_FILE = Info.plist;
+				INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
-				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = com.ibireme.YYCache;
-				PRODUCT_NAME = "$(TARGET_NAME)";
+				PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
 				SKIP_INSTALL = YES;
+				TARGETED_DEVICE_FAMILY = "1,2";
 			};
 			name = Release;
 		};
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
-		D9D418EF1BD0EFE300CD8EBF /* Build configuration list for PBXProject "YYCache" */ = {
+		D93C45A61F05445A009F80F9 /* Build configuration list for PBXProject "YYCache" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
-				D9D418FB1BD0EFE300CD8EBF /* Debug */,
-				D9D418FC1BD0EFE300CD8EBF /* Release */,
+				D93C45B21F05445A009F80F9 /* Debug */,
+				D93C45B31F05445A009F80F9 /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		D9D418FD1BD0EFE300CD8EBF /* Build configuration list for PBXNativeTarget "YYCache" */ = {
+		D93C45B41F05445A009F80F9 /* Build configuration list for PBXNativeTarget "YYCache" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
-				D9D418FE1BD0EFE300CD8EBF /* Debug */,
-				D9D418FF1BD0EFE300CD8EBF /* Release */,
+				D93C45B51F05445A009F80F9 /* Debug */,
+				D93C45B61F05445A009F80F9 /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
 /* End XCConfigurationList section */
 	};
-	rootObject = D9D418EC1BD0EFE300CD8EBF /* Project object */;
+	rootObject = D93C45A31F05445A009F80F9 /* Project object */;
 }

+ 6 - 5
Framework/YYCache.xcodeproj/xcshareddata/xcschemes/YYCache.xcscheme

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "0800"
-   version = "1.3">
+   LastUpgradeVersion = "0900"
+   version = "1.8">
    <BuildAction
       parallelizeBuildables = "YES"
       buildImplicitDependencies = "YES">
@@ -14,7 +14,7 @@
             buildForAnalyzing = "YES">
             <BuildableReference
                BuildableIdentifier = "primary"
-               BlueprintIdentifier = "D9D418F41BD0EFE300CD8EBF"
+               BlueprintIdentifier = "D93C45AB1F05445A009F80F9"
                BuildableName = "YYCache.framework"
                BlueprintName = "YYCache"
                ReferencedContainer = "container:YYCache.xcodeproj">
@@ -26,6 +26,7 @@
       buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      language = ""
       shouldUseLaunchSchemeArgsEnv = "YES">
       <Testables>
       </Testables>
@@ -45,7 +46,7 @@
       <MacroExpansion>
          <BuildableReference
             BuildableIdentifier = "primary"
-            BlueprintIdentifier = "D9D418F41BD0EFE300CD8EBF"
+            BlueprintIdentifier = "D93C45AB1F05445A009F80F9"
             BuildableName = "YYCache.framework"
             BlueprintName = "YYCache"
             ReferencedContainer = "container:YYCache.xcodeproj">
@@ -63,7 +64,7 @@
       <MacroExpansion>
          <BuildableReference
             BuildableIdentifier = "primary"
-            BlueprintIdentifier = "D9D418F41BD0EFE300CD8EBF"
+            BlueprintIdentifier = "D93C45AB1F05445A009F80F9"
             BuildableName = "YYCache.framework"
             BlueprintName = "YYCache"
             ReferencedContainer = "container:YYCache.xcodeproj">

+ 1 - 1
README.md

@@ -102,7 +102,7 @@ iPhone 6 上,磁盘缓存每秒响应次数 (越高越好):
 ![Disk benchmark result](https://raw.github.com/ibireme/YYCache/master/Benchmark/Result_disk.png
 )
 
-推荐到 SQLite 官网[下载](http://www.sqlite.org/download.html)和编译最新的 SQLite,以替换 iOS 自带的 libsqlite3.dylib,以获得最高 1.5~3 倍的性能提升
+推荐到 SQLite 官网[下载](http://www.sqlite.org/download.html)和编译最新的 SQLite,替换 iOS 自带的 libsqlite3.dylib,以获得更好的性能
 
 更多测试代码和用例见 `Benchmark/CacheBenchmark.xcodeproj`。
 

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно