Compare commits

...

5 commits

Author SHA1 Message Date
506d197a31 update readme 2016-09-06 18:28:09 -07:00
9f38497427 convert to Swift 3 2016-08-26 16:15:32 -07:00
45538b940c fix node removal 2016-08-11 18:39:56 -07:00
fe4dc9a69a convert tabs to spaces 2016-08-11 00:11:51 -07:00
137bb3fac0 replace random eviction with LRU eviction
Also took the opportunity to make the API conform to Swift 3 convention.
2016-08-11 00:11:07 -07:00
20 changed files with 795 additions and 652 deletions

View file

@ -0,0 +1,19 @@
//
// CacheCreek-iOS.h
// CacheCreek-iOS
//
// Created by Christopher Luu on 1/26/16.
//
//
#import <UIKit/UIKit.h>
//! Project version number for CacheCreek-iOS.
FOUNDATION_EXPORT double CacheCreekVersionNumber;
//! Project version string for CacheCreek-iOS.
FOUNDATION_EXPORT const unsigned char CacheCreekVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <CacheCreek_iOS/PublicHeader.h>

View file

@ -0,0 +1,19 @@
//
// CacheCreek-tvOS.h
// CacheCreek-tvOS
//
// Created by Christopher Luu on 1/26/16.
//
//
#import <UIKit/UIKit.h>
//! Project version number for CacheCreek-tvOS.
FOUNDATION_EXPORT double CacheCreeksVersionNumber;
//! Project version string for CacheCreek-tvOS.
FOUNDATION_EXPORT const unsigned char CacheCreekVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <CacheCreek_tvOS/PublicHeader.h>

16
CacheCreek.podspec Normal file
View file

@ -0,0 +1,16 @@
Pod::Spec.new do |s|
s.name = 'CacheCreek'
s.version = '0.1.0'
s.license = 'MIT'
s.summary = 'An LRU cache that can hold anything, including native Swift types.'
s.homepage = 'https://github.com/samsonjs/CacheCreek'
s.authors = { 'Christopher Luu' => 'nuudles@gmail.com', 'Sami Samhuri' => 'sami@samhuri.net' }
s.source = { :git => 'https://github.com/samsonjs/CacheCreek.git', :tag => s.version }
s.ios.deployment_target = '8.0'
s.tvos.deployment_target = '9.0'
s.source_files = 'Source/*.swift'
s.requires_arc = true
end

View file

@ -7,14 +7,16 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
30D75C271C57CE1400F4E62D /* CacheIsKing.h in Headers */ = {isa = PBXBuildFile; fileRef = 30D75C261C57CE1400F4E62D /* CacheIsKing.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30D75C271C57CE1400F4E62D /* CacheCreek.h in Headers */ = {isa = PBXBuildFile; fileRef = 30D75C261C57CE1400F4E62D /* CacheCreek.h */; settings = {ATTRIBUTES = (Public, ); }; };
30D75C2E1C57CEC500F4E62D /* KingCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D75C2D1C57CEC500F4E62D /* KingCache.swift */; }; 30D75C2E1C57CEC500F4E62D /* LRUCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D75C2D1C57CEC500F4E62D /* LRUCache.swift */; };
30D75C371C57D17400F4E62D /* CacheIsKing.h in Headers */ = {isa = PBXBuildFile; fileRef = 30D75C361C57D17400F4E62D /* CacheIsKing.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30D75C371C57D17400F4E62D /* CacheCreek.h in Headers */ = {isa = PBXBuildFile; fileRef = 30D75C361C57D17400F4E62D /* CacheCreek.h */; settings = {ATTRIBUTES = (Public, ); }; };
30D75C3C1C57D1A300F4E62D /* KingCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D75C2D1C57CEC500F4E62D /* KingCache.swift */; }; 30D75C3C1C57D1A300F4E62D /* LRUCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D75C2D1C57CEC500F4E62D /* LRUCache.swift */; };
30D75C441C57D2CA00F4E62D /* CacheIsKingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D75C431C57D2CA00F4E62D /* CacheIsKingTests.swift */; }; 30D75C461C57D2CA00F4E62D /* CacheCreek.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30D75C231C57CE1400F4E62D /* CacheCreek.framework */; };
30D75C461C57D2CA00F4E62D /* CacheIsKing.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30D75C231C57CE1400F4E62D /* CacheIsKing.framework */; };
30D75C4D1C57F1C800F4E62D /* AnyKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D75C4C1C57F1C800F4E62D /* AnyKey.swift */; }; 30D75C4D1C57F1C800F4E62D /* AnyKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D75C4C1C57F1C800F4E62D /* AnyKey.swift */; };
30D75C4E1C58033B00F4E62D /* AnyKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D75C4C1C57F1C800F4E62D /* AnyKey.swift */; }; 30D75C4E1C58033B00F4E62D /* AnyKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D75C4C1C57F1C800F4E62D /* AnyKey.swift */; };
7BC24BAC1D5C432200B1C208 /* LRUCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC24BAB1D5C432200B1C208 /* LRUCacheTests.swift */; };
7BC24BAF1D5C54E300B1C208 /* DoublyLinkedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC24BAD1D5C462100B1C208 /* DoublyLinkedList.swift */; };
7BC24BB01D5C54E300B1C208 /* DoublyLinkedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC24BAD1D5C462100B1C208 /* DoublyLinkedList.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -23,22 +25,23 @@
containerPortal = 30D75C181C57CD6100F4E62D /* Project object */; containerPortal = 30D75C181C57CD6100F4E62D /* Project object */;
proxyType = 1; proxyType = 1;
remoteGlobalIDString = 30D75C221C57CE1400F4E62D; remoteGlobalIDString = 30D75C221C57CE1400F4E62D;
remoteInfo = "CacheIsKing-iOS"; remoteInfo = "CacheCreek-iOS";
}; };
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
30D75C231C57CE1400F4E62D /* CacheIsKing.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CacheIsKing.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 30D75C231C57CE1400F4E62D /* CacheCreek.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CacheCreek.framework; sourceTree = BUILT_PRODUCTS_DIR; };
30D75C261C57CE1400F4E62D /* CacheIsKing.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CacheIsKing.h; sourceTree = "<group>"; }; 30D75C261C57CE1400F4E62D /* CacheCreek.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CacheCreek.h; sourceTree = "<group>"; };
30D75C281C57CE1400F4E62D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 30D75C281C57CE1400F4E62D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
30D75C2D1C57CEC500F4E62D /* KingCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KingCache.swift; sourceTree = "<group>"; }; 30D75C2D1C57CEC500F4E62D /* LRUCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LRUCache.swift; sourceTree = "<group>"; };
30D75C341C57D17400F4E62D /* CacheIsKing.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CacheIsKing.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 30D75C341C57D17400F4E62D /* CacheCreek.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CacheCreek.framework; sourceTree = BUILT_PRODUCTS_DIR; };
30D75C361C57D17400F4E62D /* CacheIsKing.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CacheIsKing.h; sourceTree = "<group>"; }; 30D75C361C57D17400F4E62D /* CacheCreek.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CacheCreek.h; sourceTree = "<group>"; };
30D75C381C57D17400F4E62D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 30D75C381C57D17400F4E62D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
30D75C411C57D2CA00F4E62D /* CacheIsKingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CacheIsKingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 30D75C411C57D2CA00F4E62D /* CacheCreekTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CacheCreekTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
30D75C431C57D2CA00F4E62D /* CacheIsKingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheIsKingTests.swift; sourceTree = "<group>"; };
30D75C451C57D2CA00F4E62D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 30D75C451C57D2CA00F4E62D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
30D75C4C1C57F1C800F4E62D /* AnyKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyKey.swift; sourceTree = "<group>"; }; 30D75C4C1C57F1C800F4E62D /* AnyKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyKey.swift; sourceTree = "<group>"; };
7BC24BAB1D5C432200B1C208 /* LRUCacheTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LRUCacheTests.swift; sourceTree = "<group>"; };
7BC24BAD1D5C462100B1C208 /* DoublyLinkedList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoublyLinkedList.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -60,7 +63,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
30D75C461C57D2CA00F4E62D /* CacheIsKing.framework in Frameworks */, 30D75C461C57D2CA00F4E62D /* CacheCreek.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -71,9 +74,9 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
30D75C2C1C57CEB600F4E62D /* Source */, 30D75C2C1C57CEB600F4E62D /* Source */,
30D75C251C57CE1400F4E62D /* CacheIsKing-iOS */, 30D75C251C57CE1400F4E62D /* CacheCreek-iOS */,
30D75C351C57D17400F4E62D /* CacheIsKing-tvOS */, 30D75C351C57D17400F4E62D /* CacheCreek-tvOS */,
30D75C421C57D2CA00F4E62D /* CacheIsKingTests */, 30D75C421C57D2CA00F4E62D /* CacheCreekTests */,
30D75C241C57CE1400F4E62D /* Products */, 30D75C241C57CE1400F4E62D /* Products */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
@ -81,47 +84,48 @@
30D75C241C57CE1400F4E62D /* Products */ = { 30D75C241C57CE1400F4E62D /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
30D75C231C57CE1400F4E62D /* CacheIsKing.framework */, 30D75C231C57CE1400F4E62D /* CacheCreek.framework */,
30D75C341C57D17400F4E62D /* CacheIsKing.framework */, 30D75C341C57D17400F4E62D /* CacheCreek.framework */,
30D75C411C57D2CA00F4E62D /* CacheIsKingTests.xctest */, 30D75C411C57D2CA00F4E62D /* CacheCreekTests.xctest */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
30D75C251C57CE1400F4E62D /* CacheIsKing-iOS */ = { 30D75C251C57CE1400F4E62D /* CacheCreek-iOS */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
30D75C261C57CE1400F4E62D /* CacheIsKing.h */, 30D75C261C57CE1400F4E62D /* CacheCreek.h */,
30D75C281C57CE1400F4E62D /* Info.plist */, 30D75C281C57CE1400F4E62D /* Info.plist */,
); );
path = "CacheIsKing-iOS"; path = "CacheCreek-iOS";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
30D75C2C1C57CEB600F4E62D /* Source */ = { 30D75C2C1C57CEB600F4E62D /* Source */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
30D75C2D1C57CEC500F4E62D /* KingCache.swift */,
30D75C4C1C57F1C800F4E62D /* AnyKey.swift */, 30D75C4C1C57F1C800F4E62D /* AnyKey.swift */,
7BC24BAD1D5C462100B1C208 /* DoublyLinkedList.swift */,
30D75C2D1C57CEC500F4E62D /* LRUCache.swift */,
); );
path = Source; path = Source;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
30D75C351C57D17400F4E62D /* CacheIsKing-tvOS */ = { 30D75C351C57D17400F4E62D /* CacheCreek-tvOS */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
30D75C361C57D17400F4E62D /* CacheIsKing.h */, 30D75C361C57D17400F4E62D /* CacheCreek.h */,
30D75C381C57D17400F4E62D /* Info.plist */, 30D75C381C57D17400F4E62D /* Info.plist */,
); );
path = "CacheIsKing-tvOS"; path = "CacheCreek-tvOS";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
30D75C421C57D2CA00F4E62D /* CacheIsKingTests */ = { 30D75C421C57D2CA00F4E62D /* CacheCreekTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
30D75C431C57D2CA00F4E62D /* CacheIsKingTests.swift */, 7BC24BAB1D5C432200B1C208 /* LRUCacheTests.swift */,
30D75C451C57D2CA00F4E62D /* Info.plist */, 30D75C451C57D2CA00F4E62D /* Info.plist */,
); );
path = CacheIsKingTests; path = CacheCreekTests;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
/* End PBXGroup section */ /* End PBXGroup section */
@ -131,7 +135,7 @@
isa = PBXHeadersBuildPhase; isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
30D75C271C57CE1400F4E62D /* CacheIsKing.h in Headers */, 30D75C271C57CE1400F4E62D /* CacheCreek.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -139,16 +143,16 @@
isa = PBXHeadersBuildPhase; isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
30D75C371C57D17400F4E62D /* CacheIsKing.h in Headers */, 30D75C371C57D17400F4E62D /* CacheCreek.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
/* End PBXHeadersBuildPhase section */ /* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
30D75C221C57CE1400F4E62D /* CacheIsKing-iOS */ = { 30D75C221C57CE1400F4E62D /* CacheCreek-iOS */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 30D75C291C57CE1400F4E62D /* Build configuration list for PBXNativeTarget "CacheIsKing-iOS" */; buildConfigurationList = 30D75C291C57CE1400F4E62D /* Build configuration list for PBXNativeTarget "CacheCreek-iOS" */;
buildPhases = ( buildPhases = (
30D75C1E1C57CE1400F4E62D /* Sources */, 30D75C1E1C57CE1400F4E62D /* Sources */,
30D75C1F1C57CE1400F4E62D /* Frameworks */, 30D75C1F1C57CE1400F4E62D /* Frameworks */,
@ -159,14 +163,14 @@
); );
dependencies = ( dependencies = (
); );
name = "CacheIsKing-iOS"; name = "CacheCreek-iOS";
productName = "CacheIsKing-iOS"; productName = "CacheCreek-iOS";
productReference = 30D75C231C57CE1400F4E62D /* CacheIsKing.framework */; productReference = 30D75C231C57CE1400F4E62D /* CacheCreek.framework */;
productType = "com.apple.product-type.framework"; productType = "com.apple.product-type.framework";
}; };
30D75C331C57D17400F4E62D /* CacheIsKing-tvOS */ = { 30D75C331C57D17400F4E62D /* CacheCreek-tvOS */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 30D75C391C57D17400F4E62D /* Build configuration list for PBXNativeTarget "CacheIsKing-tvOS" */; buildConfigurationList = 30D75C391C57D17400F4E62D /* Build configuration list for PBXNativeTarget "CacheCreek-tvOS" */;
buildPhases = ( buildPhases = (
30D75C2F1C57D17400F4E62D /* Sources */, 30D75C2F1C57D17400F4E62D /* Sources */,
30D75C301C57D17400F4E62D /* Frameworks */, 30D75C301C57D17400F4E62D /* Frameworks */,
@ -177,14 +181,14 @@
); );
dependencies = ( dependencies = (
); );
name = "CacheIsKing-tvOS"; name = "CacheCreek-tvOS";
productName = "CacheIsKing-tvOS"; productName = "CacheCreek-tvOS";
productReference = 30D75C341C57D17400F4E62D /* CacheIsKing.framework */; productReference = 30D75C341C57D17400F4E62D /* CacheCreek.framework */;
productType = "com.apple.product-type.framework"; productType = "com.apple.product-type.framework";
}; };
30D75C401C57D2CA00F4E62D /* CacheIsKingTests */ = { 30D75C401C57D2CA00F4E62D /* CacheCreekTests */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 30D75C491C57D2CA00F4E62D /* Build configuration list for PBXNativeTarget "CacheIsKingTests" */; buildConfigurationList = 30D75C491C57D2CA00F4E62D /* Build configuration list for PBXNativeTarget "CacheCreekTests" */;
buildPhases = ( buildPhases = (
30D75C3D1C57D2CA00F4E62D /* Sources */, 30D75C3D1C57D2CA00F4E62D /* Sources */,
30D75C3E1C57D2CA00F4E62D /* Frameworks */, 30D75C3E1C57D2CA00F4E62D /* Frameworks */,
@ -195,9 +199,9 @@
dependencies = ( dependencies = (
30D75C481C57D2CA00F4E62D /* PBXTargetDependency */, 30D75C481C57D2CA00F4E62D /* PBXTargetDependency */,
); );
name = CacheIsKingTests; name = CacheCreekTests;
productName = CacheIsKingTests; productName = CacheCreekTests;
productReference = 30D75C411C57D2CA00F4E62D /* CacheIsKingTests.xctest */; productReference = 30D75C411C57D2CA00F4E62D /* CacheCreekTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test"; productType = "com.apple.product-type.bundle.unit-test";
}; };
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
@ -207,20 +211,22 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 0720; LastSwiftUpdateCheck = 0720;
LastUpgradeCheck = 0720; LastUpgradeCheck = 0800;
TargetAttributes = { TargetAttributes = {
30D75C221C57CE1400F4E62D = { 30D75C221C57CE1400F4E62D = {
CreatedOnToolsVersion = 7.2; CreatedOnToolsVersion = 7.2;
LastSwiftMigration = 0800;
}; };
30D75C331C57D17400F4E62D = { 30D75C331C57D17400F4E62D = {
CreatedOnToolsVersion = 7.2; CreatedOnToolsVersion = 7.2;
}; };
30D75C401C57D2CA00F4E62D = { 30D75C401C57D2CA00F4E62D = {
CreatedOnToolsVersion = 7.2; CreatedOnToolsVersion = 7.2;
LastSwiftMigration = 0800;
}; };
}; };
}; };
buildConfigurationList = 30D75C1B1C57CD6100F4E62D /* Build configuration list for PBXProject "CacheIsKing" */; buildConfigurationList = 30D75C1B1C57CD6100F4E62D /* Build configuration list for PBXProject "CacheCreek" */;
compatibilityVersion = "Xcode 3.2"; compatibilityVersion = "Xcode 3.2";
developmentRegion = English; developmentRegion = English;
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
@ -232,9 +238,9 @@
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
targets = ( targets = (
30D75C221C57CE1400F4E62D /* CacheIsKing-iOS */, 30D75C221C57CE1400F4E62D /* CacheCreek-iOS */,
30D75C331C57D17400F4E62D /* CacheIsKing-tvOS */, 30D75C331C57D17400F4E62D /* CacheCreek-tvOS */,
30D75C401C57D2CA00F4E62D /* CacheIsKingTests */, 30D75C401C57D2CA00F4E62D /* CacheCreekTests */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@ -269,7 +275,8 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
30D75C4D1C57F1C800F4E62D /* AnyKey.swift in Sources */, 30D75C4D1C57F1C800F4E62D /* AnyKey.swift in Sources */,
30D75C2E1C57CEC500F4E62D /* KingCache.swift in Sources */, 7BC24BAF1D5C54E300B1C208 /* DoublyLinkedList.swift in Sources */,
30D75C2E1C57CEC500F4E62D /* LRUCache.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -278,7 +285,8 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
30D75C4E1C58033B00F4E62D /* AnyKey.swift in Sources */, 30D75C4E1C58033B00F4E62D /* AnyKey.swift in Sources */,
30D75C3C1C57D1A300F4E62D /* KingCache.swift in Sources */, 7BC24BB01D5C54E300B1C208 /* DoublyLinkedList.swift in Sources */,
30D75C3C1C57D1A300F4E62D /* LRUCache.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -286,7 +294,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
30D75C441C57D2CA00F4E62D /* CacheIsKingTests.swift in Sources */, 7BC24BAC1D5C432200B1C208 /* LRUCacheTests.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -295,7 +303,7 @@
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
30D75C481C57D2CA00F4E62D /* PBXTargetDependency */ = { 30D75C481C57D2CA00F4E62D /* PBXTargetDependency */ = {
isa = PBXTargetDependency; isa = PBXTargetDependency;
target = 30D75C221C57CE1400F4E62D /* CacheIsKing-iOS */; target = 30D75C221C57CE1400F4E62D /* CacheCreek-iOS */;
targetProxy = 30D75C471C57D2CA00F4E62D /* PBXContainerItemProxy */; targetProxy = 30D75C471C57D2CA00F4E62D /* PBXContainerItemProxy */;
}; };
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
@ -304,12 +312,49 @@
30D75C1C1C57CD6100F4E62D /* Debug */ = { 30D75C1C1C57CD6100F4E62D /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
ONLY_ACTIVE_ARCH = YES;
}; };
name = Debug; name = Debug;
}; };
30D75C1D1C57CD6100F4E62D /* Release */ = { 30D75C1D1C57CD6100F4E62D /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
}; };
name = Release; name = Release;
}; };
@ -330,7 +375,7 @@
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
@ -354,17 +399,18 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "CacheIsKing-iOS/Info.plist"; INFOPLIST_FILE = "CacheCreek-iOS/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.nuudles.CacheIsKing-iOS"; PRODUCT_BUNDLE_IDENTIFIER = "com.nuudles.CacheCreek-iOS";
PRODUCT_NAME = CacheIsKing; PRODUCT_NAME = CacheCreek;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = ""; VERSION_INFO_PREFIX = "";
@ -388,7 +434,7 @@
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
@ -406,15 +452,16 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "CacheIsKing-iOS/Info.plist"; INFOPLIST_FILE = "CacheCreek-iOS/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.nuudles.CacheIsKing-iOS"; PRODUCT_BUNDLE_IDENTIFIER = "com.nuudles.CacheCreek-iOS";
PRODUCT_NAME = CacheIsKing; PRODUCT_NAME = CacheCreek;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
@ -439,6 +486,7 @@
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
@ -462,13 +510,13 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "CacheIsKing-tvOS/Info.plist"; INFOPLIST_FILE = "CacheCreek-tvOS/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.nuudles.CacheIsKing-tvOS"; PRODUCT_BUNDLE_IDENTIFIER = "com.nuudles.CacheCreek-tvOS";
PRODUCT_NAME = CacheIsKing; PRODUCT_NAME = CacheCreek;
SDKROOT = appletvos; SDKROOT = appletvos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -496,6 +544,7 @@
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
@ -513,12 +562,12 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "CacheIsKing-tvOS/Info.plist"; INFOPLIST_FILE = "CacheCreek-tvOS/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.nuudles.CacheIsKing-tvOS"; PRODUCT_BUNDLE_IDENTIFIER = "com.nuudles.CacheCreek-tvOS";
PRODUCT_NAME = CacheIsKing; PRODUCT_NAME = CacheCreek;
SDKROOT = appletvos; SDKROOT = appletvos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = 3; TARGETED_DEVICE_FAMILY = 3;
@ -565,15 +614,16 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = CacheIsKingTests/Info.plist; INFOPLIST_FILE = CacheCreekTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.2; IPHONEOS_DEPLOYMENT_TARGET = 9.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.nuudles.CacheIsKingTests; PRODUCT_BUNDLE_IDENTIFIER = com.nuudles.CacheCreekTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
}; };
name = Debug; name = Debug;
}; };
@ -607,13 +657,14 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = CacheIsKingTests/Info.plist; INFOPLIST_FILE = CacheCreekTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.2; IPHONEOS_DEPLOYMENT_TARGET = 9.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = com.nuudles.CacheIsKingTests; PRODUCT_BUNDLE_IDENTIFIER = com.nuudles.CacheCreekTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_VERSION = 3.0;
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
name = Release; name = Release;
@ -621,7 +672,7 @@
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
30D75C1B1C57CD6100F4E62D /* Build configuration list for PBXProject "CacheIsKing" */ = { 30D75C1B1C57CD6100F4E62D /* Build configuration list for PBXProject "CacheCreek" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
30D75C1C1C57CD6100F4E62D /* Debug */, 30D75C1C1C57CD6100F4E62D /* Debug */,
@ -630,7 +681,7 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
30D75C291C57CE1400F4E62D /* Build configuration list for PBXNativeTarget "CacheIsKing-iOS" */ = { 30D75C291C57CE1400F4E62D /* Build configuration list for PBXNativeTarget "CacheCreek-iOS" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
30D75C2A1C57CE1400F4E62D /* Debug */, 30D75C2A1C57CE1400F4E62D /* Debug */,
@ -639,7 +690,7 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
30D75C391C57D17400F4E62D /* Build configuration list for PBXNativeTarget "CacheIsKing-tvOS" */ = { 30D75C391C57D17400F4E62D /* Build configuration list for PBXNativeTarget "CacheCreek-tvOS" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
30D75C3A1C57D17400F4E62D /* Debug */, 30D75C3A1C57D17400F4E62D /* Debug */,
@ -648,7 +699,7 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
30D75C491C57D2CA00F4E62D /* Build configuration list for PBXNativeTarget "CacheIsKingTests" */ = { 30D75C491C57D2CA00F4E62D /* Build configuration list for PBXNativeTarget "CacheCreekTests" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
30D75C4A1C57D2CA00F4E62D /* Debug */, 30D75C4A1C57D2CA00F4E62D /* Debug */,

View file

@ -2,6 +2,6 @@
<Workspace <Workspace
version = "1.0"> version = "1.0">
<FileRef <FileRef
location = "self:CacheIsKing.xcodeproj"> location = "self:/Users/sjs/Projects/CacheCreek/CacheCreek.xcodeproj">
</FileRef> </FileRef>
</Workspace> </Workspace>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0720" LastUpgradeVersion = "0800"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@ -15,9 +15,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "30D75C221C57CE1400F4E62D" BlueprintIdentifier = "30D75C221C57CE1400F4E62D"
BuildableName = "CacheIsKing.framework" BuildableName = "CacheCreek.framework"
BlueprintName = "CacheIsKing-iOS" BlueprintName = "CacheCreek-iOS"
ReferencedContainer = "container:CacheIsKing.xcodeproj"> ReferencedContainer = "container:CacheCreek.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
</BuildActionEntries> </BuildActionEntries>
@ -26,17 +26,16 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES">
codeCoverageEnabled = "YES">
<Testables> <Testables>
<TestableReference <TestableReference
skipped = "NO"> skipped = "NO">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "30D75C401C57D2CA00F4E62D" BlueprintIdentifier = "30D75C401C57D2CA00F4E62D"
BuildableName = "CacheIsKingTests.xctest" BuildableName = "CacheCreekTests.xctest"
BlueprintName = "CacheIsKingTests" BlueprintName = "CacheCreekTests"
ReferencedContainer = "container:CacheIsKing.xcodeproj"> ReferencedContainer = "container:CacheCreek.xcodeproj">
</BuildableReference> </BuildableReference>
</TestableReference> </TestableReference>
</Testables> </Testables>
@ -44,9 +43,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "30D75C221C57CE1400F4E62D" BlueprintIdentifier = "30D75C221C57CE1400F4E62D"
BuildableName = "CacheIsKing.framework" BuildableName = "CacheCreek.framework"
BlueprintName = "CacheIsKing-iOS" BlueprintName = "CacheCreek-iOS"
ReferencedContainer = "container:CacheIsKing.xcodeproj"> ReferencedContainer = "container:CacheCreek.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<AdditionalOptions> <AdditionalOptions>
@ -66,9 +65,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "30D75C221C57CE1400F4E62D" BlueprintIdentifier = "30D75C221C57CE1400F4E62D"
BuildableName = "CacheIsKing.framework" BuildableName = "CacheCreek.framework"
BlueprintName = "CacheIsKing-iOS" BlueprintName = "CacheCreek-iOS"
ReferencedContainer = "container:CacheIsKing.xcodeproj"> ReferencedContainer = "container:CacheCreek.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<AdditionalOptions> <AdditionalOptions>
@ -84,9 +83,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "30D75C221C57CE1400F4E62D" BlueprintIdentifier = "30D75C221C57CE1400F4E62D"
BuildableName = "CacheIsKing.framework" BuildableName = "CacheCreek.framework"
BlueprintName = "CacheIsKing-iOS" BlueprintName = "CacheCreek-iOS"
ReferencedContainer = "container:CacheIsKing.xcodeproj"> ReferencedContainer = "container:CacheCreek.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
</ProfileAction> </ProfileAction>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0720" LastUpgradeVersion = "0800"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@ -15,9 +15,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "30D75C331C57D17400F4E62D" BlueprintIdentifier = "30D75C331C57D17400F4E62D"
BuildableName = "CacheIsKing.framework" BuildableName = "CacheCreek.framework"
BlueprintName = "CacheIsKing-tvOS" BlueprintName = "CacheCreek-tvOS"
ReferencedContainer = "container:CacheIsKing.xcodeproj"> ReferencedContainer = "container:CacheCreek.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
</BuildActionEntries> </BuildActionEntries>
@ -46,9 +46,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "30D75C331C57D17400F4E62D" BlueprintIdentifier = "30D75C331C57D17400F4E62D"
BuildableName = "CacheIsKing.framework" BuildableName = "CacheCreek.framework"
BlueprintName = "CacheIsKing-tvOS" BlueprintName = "CacheCreek-tvOS"
ReferencedContainer = "container:CacheIsKing.xcodeproj"> ReferencedContainer = "container:CacheCreek.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<AdditionalOptions> <AdditionalOptions>
@ -64,9 +64,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "30D75C331C57D17400F4E62D" BlueprintIdentifier = "30D75C331C57D17400F4E62D"
BuildableName = "CacheIsKing.framework" BuildableName = "CacheCreek.framework"
BlueprintName = "CacheIsKing-tvOS" BlueprintName = "CacheCreek-tvOS"
ReferencedContainer = "container:CacheIsKing.xcodeproj"> ReferencedContainer = "container:CacheCreek.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
</ProfileAction> </ProfileAction>

View file

@ -0,0 +1,261 @@
//
// CacheCreekTests.swift
// CacheCreekTests
//
// Created by Christopher Luu on 1/26/16.
//
//
import XCTest
@testable import CacheCreek
class CacheCreekTests: XCTestCase {
typealias Node = DoublyLinkedListNode
func testSettingAndGettingItems() {
let cache = LRUCache()
cache.set(item: 123, forKey: "123")
XCTAssert(cache.count == 1)
XCTAssert(cache.item(forKey: "123") == 123)
XCTAssert(cache[123] == nil)
cache[234] = "234"
XCTAssert(cache.count == 2)
XCTAssert(cache.item(forKey: 234) == "234")
// Test setting/getting an array
let array = [1, 2, 3, 4, 5]
cache[5] = array
XCTAssert(cache.count == 3)
if let fetchedArray: [Int] = cache.item(forKey: 5) {
XCTAssert(fetchedArray == array)
}
else {
XCTFail("Expected an int array")
}
let testStruct = TestStruct(name: "Testing", value: Int(arc4random_uniform(100000)))
cache["TestingStruct"] = testStruct
guard let fetchedStruct: TestStruct = cache.item(forKey: "TestingStruct") else {
XCTFail()
return
}
XCTAssert(testStruct.name == fetchedStruct.name)
XCTAssert(testStruct.value == fetchedStruct.value)
}
func testDifferentKindsOfKeys() {
let cache = LRUCache()
let floatKey: Float = 123.456
cache.set(item: 123.456, forKey: floatKey)
XCTAssert(cache.item(forKey: floatKey) as Double? == .some(123.456))
cache[floatKey] = 456.789
XCTAssert(cache.count == 1)
XCTAssert(cache[floatKey] as? Double == .some(456.789))
cache.set(item: "123.456", forKey: "123.456")
XCTAssert(cache.count == 2)
XCTAssert(cache.item(forKey: "123.456") as String? == .some("123.456"))
let boolKey = true
cache.set(item: true, forKey: boolKey)
XCTAssert(cache.count == 3)
XCTAssert(cache.item(forKey: boolKey) as Bool? == .some(true))
cache.removeItem(forKey: boolKey)
XCTAssert(cache.count == 2)
XCTAssert(cache.item(forKey: boolKey) as Bool? == .none)
}
func testSettingAndGettingEnum() {
let cache = LRUCache()
cache["ABC"] = TestEnum.abc
cache["DEF"] = TestEnum.def("BlahBlahBlah")
cache["GHI"] = TestEnum.ghi(-500)
guard let abc: TestEnum = cache.item(forKey: "ABC"),
let def: TestEnum = cache.item(forKey: "DEF"),
let ghi: TestEnum = cache.item(forKey: "GHI")
else {
XCTFail()
return
}
switch (abc, def, ghi) {
case (.abc, .def(let stringValue), .ghi(let intValue)):
XCTAssert(stringValue == "BlahBlahBlah")
XCTAssert(intValue == -500)
default:
XCTFail()
}
}
func testSubscripts() {
let cache = LRUCache()
// Int subscript
cache[123] = 123
XCTAssert(cache[123] as? Int == .some(123))
XCTAssert(cache.count == 1)
cache[123] = nil
XCTAssert(cache[123] as? Int == .none)
XCTAssert(cache.count == 0)
// String subscript
cache["123"] = 123
XCTAssert(cache["123"] as? Int == .some(123))
XCTAssert(cache.count == 1)
cache["123"] = nil
XCTAssert(cache["123"] as? Int == .none)
XCTAssert(cache.count == 0)
// Float subscript
let floatKey: Float = 3.14
cache[floatKey] = 123
XCTAssert(cache[floatKey] as? Int == .some(123))
XCTAssert(cache.count == 1)
cache[floatKey] = nil
XCTAssert(cache[floatKey] as? Int == .none)
XCTAssert(cache.count == 0)
}
func testRemovingItems() {
let cache = LRUCache()
cache.set(item: 123, forKey: 123)
cache.set(item: 234, forKey: 234)
cache.set(item: 345, forKey: 345)
cache.set(item: 456, forKey: 456)
XCTAssert(cache.count == 4)
cache.removeItem(forKey: 123)
XCTAssert(cache.count == 3)
XCTAssert(cache[123] == nil)
cache[234] = nil
XCTAssert(cache.count == 2)
XCTAssert(cache[234] == nil)
cache.removeAllItems()
XCTAssert(cache.count == 0)
cache.set(item: 123, forKey: 123)
cache.set(item: 234, forKey: 234)
cache.set(item: 345, forKey: 345)
cache.set(item: 456, forKey: 456)
XCTAssert(cache.count == 4)
NotificationCenter.default.post(name: NSNotification.Name.UIApplicationDidReceiveMemoryWarning, object: UIApplication.shared)
XCTAssert(cache.count == 0)
cache.set(item: 123, forKey: 123)
cache.set(item: 234, forKey: 234)
cache.set(item: 345, forKey: 345)
cache.set(item: 456, forKey: 456)
XCTAssert(cache.count == 4)
NotificationCenter.default.post(name: NSNotification.Name.UIApplicationDidEnterBackground, object: UIApplication.shared)
XCTAssert(cache.count == 0)
cache.set(item: 123, forKey: 123)
cache.set(item: 234, forKey: 234)
cache.set(item: 345, forKey: 345)
cache.set(item: 456, forKey: 456)
XCTAssert(cache.count == 4)
// Make sure an unknown key doesn't have any weird side effects
cache[567] = nil
XCTAssert(cache.count == 4)
cache.removeItem(forKey: 999)
XCTAssert(cache.count == 4)
}
func testCountLimit() {
let cache = LRUCache()
cache.set(item: 123, forKey: 123)
cache.set(item: 234, forKey: 234)
cache.set(item: 345, forKey: 345)
cache.set(item: 456, forKey: 456)
XCTAssert(cache.count == 4)
cache.countLimit = 3
XCTAssert(cache.count == 3)
cache.removeAllItems()
XCTAssert(cache.count == 0)
cache.set(item: 123, forKey: 123)
cache.set(item: 234, forKey: 234)
cache.set(item: 345, forKey: 345)
cache.set(item: 456, forKey: 456)
XCTAssert(cache.count == 3)
cache[567] = 567
XCTAssert(cache.count == 3)
cache.removeAllItems()
cache.set(item: 123, forKey: 123)
cache.set(item: 234, forKey: 234)
cache.set(item: 345, forKey: 345)
cache.set(item: 456, forKey: 456)
cache.countLimit = 2
XCTAssert(cache.count == 2)
}
func testEmptyEviction() {
// Make sure that an eviction on an empty dictionary doesn't crash
let cache = LRUCache()
cache.evictItems()
}
func testObjCObjects() {
let cache = LRUCache()
let boxedInt = NSNumber(value: 42)
cache.set(item: boxedInt, forKey: "Answer")
guard let answer: NSNumber = cache.item(forKey: "Answer") else {
XCTFail("Expected an NSNumber object")
return
}
XCTAssert(answer.intValue == 42)
}
}
private struct TestStruct {
let name: String
let value: Int
}
private enum TestEnum {
case abc
case def(String)
case ghi(Int)
}

View file

@ -1,19 +0,0 @@
//
// CacheIsKing-iOS.h
// CacheIsKing-iOS
//
// Created by Christopher Luu on 1/26/16.
//
//
#import <UIKit/UIKit.h>
//! Project version number for CacheIsKing-iOS.
FOUNDATION_EXPORT double CacheIsKingVersionNumber;
//! Project version string for CacheIsKing-iOS.
FOUNDATION_EXPORT const unsigned char CacheIsKingVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <CacheIsKing_iOS/PublicHeader.h>

View file

@ -1,19 +0,0 @@
//
// CacheIsKing-tvOS.h
// CacheIsKing-tvOS
//
// Created by Christopher Luu on 1/26/16.
//
//
#import <UIKit/UIKit.h>
//! Project version number for CacheIsKing-tvOS.
FOUNDATION_EXPORT double CacheIsKingsVersionNumber;
//! Project version string for CacheIsKing-tvOS.
FOUNDATION_EXPORT const unsigned char CacheIsKingVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <CacheIsKing_tvOS/PublicHeader.h>

View file

@ -1,16 +0,0 @@
Pod::Spec.new do |s|
s.name = 'CacheIsKing'
s.version = '0.0.2'
s.license = 'MIT'
s.summary = 'A simple cache that can hold anything, including Swift items'
s.homepage = 'https://github.com/nuudles/CacheIsKing'
s.authors = { 'Christopher Luu' => 'nuudles@gmail.com' }
s.source = { :git => 'https://github.com/nuudles/CacheIsKing.git', :tag => s.version }
s.ios.deployment_target = '8.0'
s.tvos.deployment_target = '9.0'
s.source_files = 'Source/*.swift'
s.requires_arc = true
end

View file

@ -1,262 +0,0 @@
//
// CacheIsKingTests.swift
// CacheIsKingTests
//
// Created by Christopher Luu on 1/26/16.
//
//
import XCTest
@testable import CacheIsKing
class CacheIsKingTests: XCTestCase {
func testSettingAndGettingItems() {
let cache = KingCache()
cache.setItem(123, forKey: "123")
XCTAssert(cache.cacheDictionary.count == 1)
XCTAssert(cache.count == 1)
XCTAssert(cache.itemForKey("123") == 123)
XCTAssert(cache.cacheDictionary[AnyKey("123")] as? Int == .Some(123))
XCTAssert(cache[123] == nil)
cache[234] = "234"
XCTAssert(cache.cacheDictionary.count == 2)
XCTAssert(cache.count == 2)
XCTAssert(cache.itemForKey(234) == "234")
XCTAssert(cache.cacheDictionary[AnyKey(234)] as? String == .Some("234"))
// Test setting/getting an array
let array = [1, 2, 3, 4, 5]
cache[5] = array
XCTAssert(cache.cacheDictionary.count == 3)
XCTAssert(cache.count == 3)
if let fetchedArray: [Int] = cache.itemForKey(5) {
XCTAssert(fetchedArray == array)
}
else {
XCTFail("Expected an int array")
}
let testStruct = TestStruct(name: "Testing", value: Int(arc4random_uniform(100000)))
cache["TestingStruct"] = testStruct
guard let fetchedStruct: TestStruct = cache.itemForKey("TestingStruct") else {
XCTFail()
return
}
XCTAssert(testStruct.name == fetchedStruct.name)
XCTAssert(testStruct.value == fetchedStruct.value)
}
func testDifferentKindsOfKeys() {
let cache = KingCache()
let floatKey: Float = 123.456
cache.setItem(123.456, forKey: floatKey)
XCTAssert(cache.itemForKey(floatKey) as Double? == .Some(123.456))
cache[floatKey] = 456.789
XCTAssert(cache.count == 1)
XCTAssert(cache[floatKey] as? Double == .Some(456.789))
cache.setItem("123.456", forKey: "123.456")
XCTAssert(cache.count == 2)
XCTAssert(cache.itemForKey("123.456") as String? == .Some("123.456"))
let boolKey = true
cache.setItem(true, forKey: boolKey)
XCTAssert(cache.count == 3)
XCTAssert(cache.itemForKey(boolKey) as Bool? == .Some(true))
cache.removeItemForKey(boolKey)
XCTAssert(cache.count == 2)
XCTAssert(cache.itemForKey(boolKey) as Bool? == .None)
}
func testSettingAndGettingEnum() {
let cache = KingCache()
cache["ABC"] = TestEnum.ABC
cache["DEF"] = TestEnum.DEF("BlahBlahBlah")
cache["GHI"] = TestEnum.GHI(-500)
guard let abc: TestEnum = cache.itemForKey("ABC"),
def: TestEnum = cache.itemForKey("DEF"),
ghi: TestEnum = cache.itemForKey("GHI")
else {
XCTFail()
return
}
switch (abc, def, ghi) {
case (.ABC, .DEF(let stringValue), .GHI(let intValue)):
XCTAssert(stringValue == "BlahBlahBlah")
XCTAssert(intValue == -500)
default:
XCTFail()
}
}
func testSubscripts() {
let cache = KingCache()
// Int subscript
cache[123] = 123
XCTAssert(cache[123] as? Int == .Some(123))
XCTAssert(cache.count == 1)
cache[123] = nil
XCTAssert(cache[123] as? Int == .None)
XCTAssert(cache.count == 0)
// String subscript
cache["123"] = 123
XCTAssert(cache["123"] as? Int == .Some(123))
XCTAssert(cache.count == 1)
cache["123"] = nil
XCTAssert(cache["123"] as? Int == .None)
XCTAssert(cache.count == 0)
// Float subscript
let floatKey: Float = 3.14
cache[floatKey] = 123
XCTAssert(cache[floatKey] as? Int == .Some(123))
XCTAssert(cache.count == 1)
cache[floatKey] = nil
XCTAssert(cache[floatKey] as? Int == .None)
XCTAssert(cache.count == 0)
}
func testRemovingItems() {
let cache = KingCache()
cache.setItem(123, forKey: 123)
cache.setItem(234, forKey: 234)
cache.setItem(345, forKey: 345)
cache.setItem(456, forKey: 456)
XCTAssert(cache.count == 4)
cache.removeItemForKey(123)
XCTAssert(cache.count == 3)
XCTAssert(cache[123] == nil)
cache[234] = nil
XCTAssert(cache.count == 2)
XCTAssert(cache[234] == nil)
cache.removeAllItems()
XCTAssert(cache.count == 0)
cache.setItem(123, forKey: 123)
cache.setItem(234, forKey: 234)
cache.setItem(345, forKey: 345)
cache.setItem(456, forKey: 456)
XCTAssert(cache.count == 4)
NSNotificationCenter.defaultCenter().postNotificationName(UIApplicationDidReceiveMemoryWarningNotification, object: UIApplication.sharedApplication())
XCTAssert(cache.count == 0)
cache.setItem(123, forKey: 123)
cache.setItem(234, forKey: 234)
cache.setItem(345, forKey: 345)
cache.setItem(456, forKey: 456)
XCTAssert(cache.count == 4)
NSNotificationCenter.defaultCenter().postNotificationName(UIApplicationDidEnterBackgroundNotification, object: UIApplication.sharedApplication())
XCTAssert(cache.count == 0)
cache.setItem(123, forKey: 123)
cache.setItem(234, forKey: 234)
cache.setItem(345, forKey: 345)
cache.setItem(456, forKey: 456)
XCTAssert(cache.count == 4)
// Make sure an unknown key doesn't have any weird side effects
cache[567] = nil
XCTAssert(cache.count == 4)
cache.removeItemForKey(999)
XCTAssert(cache.count == 4)
}
func testCountLimit() {
let cache = KingCache()
cache.setItem(123, forKey: 123)
cache.setItem(234, forKey: 234)
cache.setItem(345, forKey: 345)
cache.setItem(456, forKey: 456)
XCTAssert(cache.count == 4)
cache.countLimit = 3
XCTAssert(cache.count == 3)
cache.removeAllItems()
XCTAssert(cache.count == 0)
cache.setItem(123, forKey: 123)
cache.setItem(234, forKey: 234)
cache.setItem(345, forKey: 345)
cache.setItem(456, forKey: 456)
XCTAssert(cache.count == 3)
cache[567] = 567
XCTAssert(cache.count == 3)
cache.removeAllItems()
cache.setItem(123, forKey: 123)
cache.setItem(234, forKey: 234)
cache.setItem(345, forKey: 345)
cache.setItem(456, forKey: 456)
cache.countLimit = 2
XCTAssert(cache.count == 2)
}
func testEmptyEviction() {
// Make sure that an eviction on an empty dictionary doesn't crash
let cache = KingCache()
cache.evictItemsIfNeeded()
}
func testObjCObjects() {
let cache = KingCache()
let oldCache = NSCache()
cache.setItem(oldCache, forKey: "InceptionCache")
guard let _: NSCache = cache.itemForKey("InceptionCache") else {
XCTFail("Expected an NSCache object")
return
}
}
}
private struct TestStruct {
let name: String
let value: Int
}
private enum TestEnum {
case ABC
case DEF(String)
case GHI(Int)
}

View file

@ -1,10 +1,10 @@
# CacheIsKing # CacheCreek
<a href="https://github.com/Carthage/Carthage/issues/179"> ### Forked from [CacheIsKing]()
<img src="https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat">
</a>
`CacheIsKing` is a simple cache that allows you to store any item, including objects, pure Swift structs, enums (with associated values), etc. Simply put, it's designed to act like an `NSCache` for everything, including Swift variables. `CacheCreek` provides an an LRU cache that allows you to store any item, including objects, pure Swift structs, enums (with associated values), etc. Simply put, it's designed to act like an `NSCache` for everything, including Swift variables.
![Swift version 3.0](https://img.shields.io/badge/Swift-3.0-brightgreen.svg?style=flat)] ![version 0.2.0 on Carthage](https://img.shields.io/badge/Carthage-0.2.0-brightgreen.svg?style=flat) [![MIT License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat)](https://sjs.mit-license.org)
## Features ## Features
@ -21,45 +21,23 @@
- tvOS 9.0+ - tvOS 9.0+
- Xcode 7+ - Xcode 7+
## Installation using CocoaPods
[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects.
Because `CacheIsKing ` is written in Swift, you must use frameworks.
To integrate `CacheIsKing ` into your Xcode project using CocoaPods, specify it in your `Podfile`:
```ruby
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
pod 'CacheIsKing'
```
Then, run the following command:
```bash
$ pod install
```
## Installation using Carthage ## Installation using Carthage
Add this to your `Cartfile`: Add this to your `Cartfile`:
``` ```
github "nuudles/CacheIsKing" github "samsonjs/CacheCreek"
``` ```
## Usage ## Usage
Simply use the `KingCache` class similar to how you'd use a `NSCache`. Using the `setItem` and `itemForKey` methods allow you to use type inference to get the values you want. Simply use the `LRUCache` class similar to how you'd use a `NSCache`. Using the `setItem` and `itemForKey` methods allow you to use type inference to get the values you want.
```swift ```swift
let cache = KingCache() let cache = LRUCache()
cache.setItem(123, forKey: "123") cache.set(item: 123, forKey: "123")
if let item: Int = cache.itemForKey(456) { if let item: Int = cache.item(forKey: 456) {
doSomethingWithItem(item) doSomethingWithItem(item)
} }
``` ```
@ -67,7 +45,7 @@ if let item: Int = cache.itemForKey(456) {
You can also use subscripts to set/get items from the cache. Unfortunately since Swift doesn't support subscript methods with generics yet, you'll have to cast your items as necessary. Also currently only `String`, `Int`, and `Float` keys are supported: You can also use subscripts to set/get items from the cache. Unfortunately since Swift doesn't support subscript methods with generics yet, you'll have to cast your items as necessary. Also currently only `String`, `Int`, and `Float` keys are supported:
```swift ```swift
let cache = KingCache() let cache = LRUCache()
cache["123"] = 123 cache["123"] = 123
if let item = cache[456] as? Int { if let item = cache[456] as? Int {
@ -75,10 +53,10 @@ if let item = cache[456] as? Int {
} }
``` ```
The `KingCache` also has a `countLimit` property, which allows you to set the maximum number of items in the cache. It currently evicts randomly until the `countLimit` is met. The `LRUCache` also has a `countLimit` property, which allows you to set the maximum number of items in the cache.
```swift ```swift
let cache = KingCache() let cache = LRUCache()
cache.countLimit = 2 cache.countLimit = 2
cache[123] = 123 cache[123] = 123
@ -90,5 +68,11 @@ print("\(cache.count)") // shows a count of 2
## TODO ## TODO
- Refine eviction algorithm (currently evicts randomly)
- Update with better subscript support once Swift supports subscripts with generics - Update with better subscript support once Swift supports subscripts with generics
# License
Copyright (c) 2015 Christopher Luu [MIT License](https://github.com/nuudles/CacheIsKing/blob/f93527d8ccc3f88b2e0697e9fd78be28d40a3a26/LICENSE)
Copyright &copy; 2016 Sami Samhuri [MIT License](https://sjs.mit-license.org)

View file

@ -1,6 +1,6 @@
// //
// AnyKey.swift // AnyKey.swift
// CacheIsKing // CacheCreek
// //
// Created by Christopher Luu on 1/26/16. // Created by Christopher Luu on 1/26/16.
// //
@ -13,33 +13,33 @@ import Foundation
/// ///
/// `AnyKey` is a simple struct that conforms to `Hashable` to allow any other `Hashable` key to be used in the cache dictionary /// `AnyKey` is a simple struct that conforms to `Hashable` to allow any other `Hashable` key to be used in the cache dictionary
struct AnyKey: Hashable { struct AnyKey: Hashable {
/// The underlying value /// The underlying value
private let underlying: Any fileprivate let underlying: Any
/// The hashing function /// The hashing function
private let hashValueFunc: () -> Int fileprivate let hashValueFunc: () -> Int
/// The equality function /// The equality function
private let equalityFunc: (Any) -> Bool fileprivate let equalityFunc: (Any) -> Bool
init<T: Hashable>(_ key: T) { init<T: Hashable>(_ key: T) {
underlying = key underlying = key
// Capture the key's hashability and equatability using closures. // Capture the key's hashability and equatability using closures.
// The Key shares the hash of the underlying value. // The Key shares the hash of the underlying value.
hashValueFunc = { key.hashValue } hashValueFunc = { key.hashValue }
// The Key is equal to a Key of the same underlying type, // The Key is equal to a Key of the same underlying type,
// whose underlying value is "==" to ours. // whose underlying value is "==" to ours.
equalityFunc = { equalityFunc = {
if let other = $0 as? T { if let other = $0 as? T {
return key == other return key == other
} }
return false return false
} }
} }
/// `Hashable` protocol conformance /// `Hashable` protocol conformance
var hashValue: Int { return hashValueFunc() } var hashValue: Int { return hashValueFunc() }
} }
func ==(x: AnyKey, y: AnyKey) -> Bool { func ==(x: AnyKey, y: AnyKey) -> Bool {
return x.equalityFunc(y.underlying) return x.equalityFunc(y.underlying)
} }

View file

@ -0,0 +1,97 @@
//
// DoublyLinkedList.swift
// CacheCreek
//
// Created by Sami Samhuri on 2016-08-10.
//
struct DoublyLinkedList {
typealias Node = DoublyLinkedListNode
fileprivate(set) var head: Node?
fileprivate(set) var tail: Node?
fileprivate(set) var count = 0
var isEmpty: Bool {
return head == nil
}
mutating func prepend(key: AnyKey, value: Any) -> Node {
let node = Node(key: key, value: value)
node.next = head
head?.prev = node
head = node
if tail == nil {
tail = node
}
count += 1
return node
}
mutating func append(key: AnyKey, value: Any) -> Node {
let node = Node(key: key, value: value)
node.prev = tail
tail?.next = node
tail = node
if head == nil {
head = node
}
count += 1
return node
}
mutating func removeAll() {
head = nil
tail = nil
count = 0
}
mutating func removeLast() -> Node? {
if let node = tail {
remove(node: node)
return node
}
return nil
}
mutating func remove(node: Node) {
if node === head {
head = node.next
}
if node === tail {
tail = node.prev
}
node.prev?.next = node.next
node.next?.prev = node.prev
node.next = nil
node.prev = nil
count -= 1
}
mutating func moveToHead(node: Node) {
remove(node: node)
let _ = prepend(key: node.key, value: node.value)
}
}
class DoublyLinkedListNode {
let key: AnyKey
let value: Any
var next: DoublyLinkedListNode?
weak var prev: DoublyLinkedListNode?
init(key: AnyKey, value: Any) {
self.key = key
self.value = value
}
}

View file

@ -1,166 +0,0 @@
//
// KingCache.swift
// CacheIsKing
//
// Created by Christopher Luu on 1/26/16.
//
//
import Foundation
/// `KingCache` is a simple cache that can hold anything, including Swift structs, enums, and values.
/// It is designed to work similar to the `NSCache`, but with native Swift support.
///
public class KingCache {
// MARK: - Private variables
/// An array of `NSNotificationCenter` observers that need to be removed upon deinitialization
private var notificationObservers: [NSObjectProtocol] = []
// MARK: - Internal variables
/// The dictionary that holds the cached values
var cacheDictionary: [AnyKey: Any] = [:]
// MARK: - Public variables
/// The number of items in the cache
public var count: Int {
return cacheDictionary.count
}
/// The limit of the amount of items that can be held in the cache. This defaults to 0, which means there is no limit.
public var countLimit: UInt = 0 {
didSet {
evictItemsIfNeeded()
}
}
// MARK: - Initialization methods
public init() {
let removalBlock = { [unowned self] (_: NSNotification) in
self.cacheDictionary.removeAll()
}
var notificationObserver = NSNotificationCenter.defaultCenter()
.addObserverForName(UIApplicationDidReceiveMemoryWarningNotification,
object: UIApplication.sharedApplication(),
queue: nil,
usingBlock: removalBlock)
notificationObservers.append(notificationObserver)
notificationObserver = NSNotificationCenter.defaultCenter()
.addObserverForName(UIApplicationDidEnterBackgroundNotification,
object: UIApplication.sharedApplication(),
queue: nil,
usingBlock: removalBlock)
notificationObservers.append(notificationObserver)
}
deinit {
notificationObservers.forEach {
NSNotificationCenter.defaultCenter().removeObserver($0)
}
}
// MARK: - Internal methods
/// Evicts items if the `countLimit` has been reached.
/// This currently uses a random eviction policy, kicking out random items until the `countLimit` is satisfied.
///
func evictItemsIfNeeded() {
if countLimit > 0 && cacheDictionary.count > Int(countLimit) {
// TODO: Evict items with more rhyme or reason
var keys = cacheDictionary.keys.flatMap { $0 }
while cacheDictionary.count > Int(countLimit) {
let randomIndex = Int(arc4random_uniform(UInt32(keys.count)))
let key = keys.removeAtIndex(randomIndex)
cacheDictionary.removeValueForKey(key)
}
}
}
// MARK: - Public methods
/// Adds an item to the cache for any given `Hashable` key.
///
/// - parameter item: The item to be cached
/// - parameter key: The key with which to cache the item
///
public func setItem<K: Hashable>(item: Any, forKey key: K) {
cacheDictionary[AnyKey(key)] = item
evictItemsIfNeeded()
}
/// Gets an item from the cache if it exists for a given `Hashable` key.
/// This method uses generics to infer the type that should be returned.
///
/// Note: Even if an item exists for the key, but does not match the given type, it will return `nil`.
///
/// - parameter key: The key whose item should be fetched
/// - returns: The item from the cache if it exists, or `nil` if an item could not be found
///
public func itemForKey<T, K: Hashable>(key: K) -> T? {
if let item = cacheDictionary[AnyKey(key)] as? T {
return item
}
return nil
}
/// Discards an item for a given `Hashable` key.
///
/// - parameter key: The key whose item should be removed
///
public func removeItemForKey<K: Hashable>(key: K) {
cacheDictionary[AnyKey(key)] = nil
}
/// Clears the entire cache.
///
public func removeAllItems() {
cacheDictionary.removeAll()
}
// MARK: - Subscript methods
// TODO: Consolidate these subscript methods once subscript generics with constraints are supported
/// A subscript method that allows `Int` key subscripts.
///
public subscript(key: Int) -> Any? {
get {
return itemForKey(key)
}
set {
if let newValue = newValue {
setItem(newValue, forKey: key)
}
else {
removeItemForKey(key)
}
}
}
/// A subscript method that allows `Float` key subscripts.
///
public subscript(key: Float) -> Any? {
get {
return itemForKey(key)
}
set {
if let newValue = newValue {
setItem(newValue, forKey: key)
}
else {
removeItemForKey(key)
}
}
}
/// A subscript method that allows `String` key subscripts.
///
public subscript(key: String) -> Any? {
get {
return itemForKey(key)
}
set {
if let newValue = newValue {
setItem(newValue, forKey: key)
}
else {
removeItemForKey(key)
}
}
}
}

179
Source/LRUCache.swift Normal file
View file

@ -0,0 +1,179 @@
//
// LRUCache.swift
// CacheCreek
//
// Created by Christopher Luu on 1/26/16.
//
// Modified to use LRU eviction by Sami Samhuri on 2016-08-10.
//
import UIKit
/// `LRUCache` is an LRU cache that can hold anything, including Swift structs, enums, and values.
/// It is designed to work similar to the `NSCache`, but with native Swift support.
///
public final class LRUCache {
// MARK: - Private variables
/// An array of `NSNotificationCenter` observers that need to be removed upon deinitialization
fileprivate var notificationObservers: [NSObjectProtocol] = []
/// The list of cached items. Most recently used item at head, least recently used item at tail.
fileprivate var items: DoublyLinkedList = DoublyLinkedList()
/// Maps keys of cached items to nodes in the linked list.
fileprivate var keyToNodeMap: [AnyKey:DoublyLinkedListNode] = [:]
// MARK: - Public variables
/// The number of items in the cache.
public var count: Int {
return items.count
}
/// The limit of the amount of items that can be held in the cache. This defaults to 0, which means there is no limit.
public var countLimit: Int = 0 {
didSet {
assert(countLimit >= 0)
evictItems()
}
}
// MARK: - Initialization methods
public init() {
let removalBlock = { [unowned self] (_: Notification) in
self.removeAllItems()
}
var notificationObserver = NotificationCenter.default
.addObserver(forName: NSNotification.Name.UIApplicationDidReceiveMemoryWarning,
object: UIApplication.shared,
queue: nil,
using: removalBlock)
notificationObservers.append(notificationObserver)
notificationObserver = NotificationCenter.default
.addObserver(forName: NSNotification.Name.UIApplicationDidEnterBackground,
object: UIApplication.shared,
queue: nil,
using: removalBlock)
notificationObservers.append(notificationObserver)
}
deinit {
notificationObservers.forEach {
NotificationCenter.default.removeObserver($0)
}
}
// MARK: - Internal methods
/// Evicts items if the `countLimit` has been reached.
///
func evictItems() {
guard countLimit > 0 else { return }
while items.count > countLimit {
if let node = items.removeLast() {
keyToNodeMap[node.key] = nil
}
}
}
// MARK: - Public methods
/// Adds an item to the cache for any given `Hashable` key.
///
/// - parameter item: The item to be cached
/// - parameter key: The key with which to cache the item
///
public func set<K: Hashable>(item: Any, forKey key: K) {
let key = AnyKey(key)
if let existingNode = keyToNodeMap[key] {
items.remove(node: existingNode)
}
let node = items.prepend(key: key, value: item)
keyToNodeMap[key] = node
evictItems()
}
/// Gets an item from the cache if it exists for a given `Hashable` key.
/// This method uses generics to infer the type that should be returned.
///
/// Note: Even if an item exists for the key, but does not match the given type, it will return `nil`.
///
/// - parameter key: The key whose item should be fetched
/// - returns: The item from the cache if it exists, or `nil` if an item could not be found
///
public func item<T, K: Hashable>(forKey key: K) -> T? {
let key = AnyKey(key)
if let node = keyToNodeMap[key], let item = node.value as? T {
items.moveToHead(node: node)
return item
}
return nil
}
/// Discards an item for a given `Hashable` key.
///
/// - parameter key: The key whose item should be removed
///
public func removeItem<K: Hashable>(forKey key: K) {
let key = AnyKey(key)
if let node = keyToNodeMap[key] {
items.remove(node: node)
keyToNodeMap[key] = nil
}
}
/// Clears the entire cache.
///
public func removeAllItems() {
items.removeAll()
keyToNodeMap.removeAll()
}
// MARK: - Subscript methods
// TODO: Consolidate these subscript methods once subscript generics with constraints are supported
/// A subscript method that allows `Int` key subscripts.
///
public subscript(key: Int) -> Any? {
get {
return item(forKey: key)
}
set {
if let newValue = newValue {
set(item: newValue, forKey: key)
}
else {
removeItem(forKey: key)
}
}
}
/// A subscript method that allows `Float` key subscripts.
///
public subscript(key: Float) -> Any? {
get {
return item(forKey: key)
}
set {
if let newValue = newValue {
set(item: newValue, forKey: key)
}
else {
removeItem(forKey: key)
}
}
}
/// A subscript method that allows `String` key subscripts.
///
public subscript(key: String) -> Any? {
get {
return item(forKey: key)
}
set {
if let newValue = newValue {
set(item: newValue, forKey: key)
}
else {
removeItem(forKey: key)
}
}
}
}