diff --git a/CacheCreek.xcodeproj/project.xcworkspace/xcshareddata/CacheCreek.xcscmblueprint b/CacheCreek.xcodeproj/project.xcworkspace/xcshareddata/CacheCreek.xcscmblueprint new file mode 100644 index 0000000..bda20dc --- /dev/null +++ b/CacheCreek.xcodeproj/project.xcworkspace/xcshareddata/CacheCreek.xcscmblueprint @@ -0,0 +1,30 @@ +{ + "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "949E2619AD9C70590D5C2B00C5D03CE3824EE763", + "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { + + }, + "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { + "643B3DC915360BBE488C9CC33DF04516EA01C6C3" : 0, + "949E2619AD9C70590D5C2B00C5D03CE3824EE763" : 0 + }, + "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "BB3C86DC-2757-463B-9957-C1F08638D390", + "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { + "643B3DC915360BBE488C9CC33DF04516EA01C6C3" : "..\/..", + "949E2619AD9C70590D5C2B00C5D03CE3824EE763" : "CacheCreek\/" + }, + "DVTSourceControlWorkspaceBlueprintNameKey" : "CacheCreek", + "DVTSourceControlWorkspaceBlueprintVersion" : 204, + "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CacheCreek.xcodeproj", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:samsonjs\/1SE.git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "643B3DC915360BBE488C9CC33DF04516EA01C6C3" + }, + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/samsonjs\/CacheCreek.git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "949E2619AD9C70590D5C2B00C5D03CE3824EE763" + } + ] +} \ No newline at end of file diff --git a/Source/AnyKey.swift b/Source/AnyKey.swift index f3201b2..6953d09 100644 --- a/Source/AnyKey.swift +++ b/Source/AnyKey.swift @@ -38,6 +38,10 @@ struct AnyKey: Hashable { /// `Hashable` protocol conformance var hashValue: Int { return hashValueFunc() } + + var description: String { + return "\(underlying)" + } } func ==(x: AnyKey, y: AnyKey) -> Bool { diff --git a/Source/DoublyLinkedList.swift b/Source/DoublyLinkedList.swift index 1bc157a..930edcf 100644 --- a/Source/DoublyLinkedList.swift +++ b/Source/DoublyLinkedList.swift @@ -5,6 +5,15 @@ // Created by Sami Samhuri on 2016-08-10. // +import Dispatch +import UIKit + +extension NSIndexPath { + override public var description: String { + return "{\(section),\(item)}" + } +} + struct DoublyLinkedList { typealias Node = DoublyLinkedListNode @@ -19,7 +28,42 @@ struct DoublyLinkedList { return head == nil } + private func log(m: String) { + print("[List] \(m) (count=\(count) head=\(head?.description) tail=\(tail?.description))") + } + + private func look() { + print("new look: \(description)") + } + + var description: String { + var nodeDescriptions: [String] = [] + var node = head + var prev: Node? = nil + while node != nil { + if prev !== node!.prev { + fatalError("prev(\(prev?.description)) !== node.prev(\(node!.prev?.description))") + } + nodeDescriptions.append("[\(node!.key.description)]") + prev = node + node = node!.next + if prev!.next !== node { + fatalError("prev.next(\(prev!.next?.description)) !== node(\(node?.description))") + } + } + if nodeDescriptions.count > 10 { + let firstRange = nodeDescriptions.startIndex.. "))>" + } + mutating func prepend(key key: AnyKey, value: Any) -> Node { + log("prepend key \(key.description)") let node = Node(key: key, value: value) node.next = head head?.prev = node @@ -28,10 +72,12 @@ struct DoublyLinkedList { tail = node } count += 1 + look() return node } mutating func append(key key: AnyKey, value: Any) -> Node { + log("append key \(key.description)") let node = Node(key: key, value: value) node.prev = tail tail?.next = node @@ -40,42 +86,52 @@ struct DoublyLinkedList { head = node } count += 1 + look() return node } mutating func removeAll() { + log("remove all") head = nil tail = nil count = 0 + look() } mutating func removeLast() -> Node? { + log("remove last") if let node = tail { remove(node: node) + look() return node } + look() return nil } mutating func remove(node node: Node) { - if let prev = node.prev { - prev.next = node.next - } - else { + log("remove node \(node.description)") + if node === head { head = node.next } - if let next = node.next { - next.prev = node.prev - } - else { + if node === tail { tail = node.prev } + + node.prev?.next = node.next + node.next?.prev = node.prev node.next = nil node.prev = nil count -= 1 + if head == nil && tail == nil && count > 0 { + log("removal fucked up: \(node.description)") + fatalError("fucked") + } + look() } mutating func moveToHead(node node: Node) { + log("move to head: \(node.description)") remove(node: node) prepend(key: node.key, value: node.value) } @@ -97,4 +153,8 @@ class DoublyLinkedListNode { self.value = value } + var description: String { + return "" + } + } diff --git a/Source/LRUCache.swift b/Source/LRUCache.swift index a5c99d2..1e58ff4 100644 --- a/Source/LRUCache.swift +++ b/Source/LRUCache.swift @@ -7,7 +7,7 @@ // Modified to use LRU eviction by Sami Samhuri on 2016-08-10. // -import Foundation +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.