From abf8d0cad093b43ce36216e7d030131a667a0621 Mon Sep 17 00:00:00 2001 From: lizhihong Date: Thu, 6 Aug 2020 09:47:49 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=8C=89=E7=85=A7pr=E6=84=8F=E8=A7=81?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=8C=E5=B9=B6=E5=8A=A0=E5=85=A5trim?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 + Sources/ClaretCache/MemoryCache.swift | 164 ++++++++++++++++-- 2 files changed, 161 insertions(+), 11 deletions(-) create mode 100644 ClaretCacheDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/ClaretCacheDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ClaretCacheDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ClaretCacheDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Sources/ClaretCache/MemoryCache.swift b/Sources/ClaretCache/MemoryCache.swift index 47ab54e..c9a0fd8 100644 --- a/Sources/ClaretCache/MemoryCache.swift +++ b/Sources/ClaretCache/MemoryCache.swift @@ -114,7 +114,9 @@ public extension MemoryCache { /// - Parameter atKey: atKey An object identifying the value. If nil, just return **NO**. /// - Returns: Whether the atKey is in cache. final func contains(_ atKey: Key?) -> Bool { - return false + let node = lru.get(atKey) + + return node != nil } /// Sets the value of the specified key in the cache, and associates the key-value @@ -122,21 +124,43 @@ public extension MemoryCache { /// - Parameter value: The object to store in the cache. If nil, it calls **remove(_ atKey:)**. /// - Parameter atKey: The atKey with which to associate the value. If nil, this method has no effect. /// - Parameter cost: The cost with which to associate the key-value pair. - final func set(_ value: Value?, _ atKey: Key?, cost: UInt = 0) { + final func set(_ value: Value?, _ atKey: Key?, cost: UInt = 0) { // Delete new if value is nil // Cache if value is not nil + guard let atKey = atKey else { + + return + } + + guard let value = value else { + + remove(atKey) + return + } + + lru.put(atKey, value, cost: cost) + + if lru.totalCount > countLimit { + + trimTo(count: countLimit) + } + + if lru.totalCost > costLimit { + + trimTo(cost: countLimit) + } } /// Removes the value of the specified key in the cache. /// - Parameter atKey: atKey The atKey identifying the value to be removed. /// If nil, this method has no effect. final func remove(_ atKey: Key?) { - + lru.delete(atKey) } /// Empties the cache immediately. final func removeAll() { - + lru.deleteAll() } final subscript(_ atKey: Key?) -> Value? { @@ -206,11 +230,17 @@ private extension MemoryCache { #endif final func trimCount(_ count: UInt) { - + while lru.totalCount > count { + + _ = lru.deleteTail() + } } final func trimCost(_ cost: UInt) { - + while lru.totalCost > cost { + + _ = lru.deleteTail() + } } final func trimAge(_ age: UInt) { @@ -224,8 +254,9 @@ private extension MemoryCache { Typically, you should not use this class directly. */ + fileprivate final class LinkedMap where Key : Hashable { - var dic: [Key:Value] = [:] + var dic: [Key:Node] = Dictionary>.init() var totalCost: UInt = 0 var totalCount: UInt = 0 var head: Node? // MRU, do not change it directly @@ -233,18 +264,129 @@ fileprivate final class LinkedMap where Key : Hashable { var releaseOnMainThread: Bool = false var releaseAsynchronously: Bool = true - final class Node where Key : Hashable { + fileprivate final class Node : Equatable where Key : Hashable { var prev: Node? var next: Node? - var key: Key? - var value: Value? + var key: Key + var value: Value var cost: UInt = 0 var time: TimeInterval = 0.0 + init(key: Key, value: Value, cost: UInt) { + self.key = key + self.value = value + self.cost = cost + } + + static func == (lhs: Node, rhs: Node) -> Bool { + return lhs.key == rhs.key + } } - + init() { } + + // MARK: - + /// 从内存中查询key,如果有缓存存在,则返回。并将缓存移至最前。 + func get(_ key: Key?) -> Node? { + guard let key = key else { + + return nil + } + let dicNode = dic[key] + if dicNode != nil { + + let prevDicNode = dicNode!.prev + let nextDicNode = dicNode!.next + nextDicNode?.prev = prevDicNode + prevDicNode?.next = nextDicNode + + dicNode?.prev = nil + dicNode?.next = head + head?.prev = dicNode + + head = dicNode + } + + return dicNode + } + + func put(_ key: Key, _ value: Value, cost: UInt = 0) { + let node = Node(key: key, value: value, cost: cost) + let dicNode = get(key) + if dicNode != nil { + + dic[key] = node + } else { + + dic.updateValue(node, forKey: key) + totalCount += 1 + totalCost += node.cost + } + } + + func delete(_ key: Key?) { + guard let key = key else { + + return + } + guard let dicNode = dic[key] else { + + return + } + + let prevDicNode = dicNode.prev + let nextDicNode = dicNode.next + if dicNode == head { + + head = nextDicNode + } else if dicNode == tail { + + tail = prevDicNode + } + nextDicNode?.prev = prevDicNode + prevDicNode?.next = nextDicNode + dicNode.prev = nil + dicNode.next = nil + dic.removeValue(forKey: key) + + totalCount -= 1 + totalCost -= dicNode.cost + } + + func deleteTail() -> Node? { + guard let tailNode = tail else { + + return nil + } + + let prevTailNode = tailNode.prev + + tailNode.prev = nil + tail = prevTailNode + tail?.next = nil + + totalCount -= 1 + totalCost -= tailNode.cost + + return tailNode + } + + func deleteAll() { + var node = head + while node != nil { + let tempNode = node?.next + node?.next = nil + tempNode?.prev = nil + node = tempNode + } + dic.removeAll() + head = nil + tail = nil + + totalCount = 0 + totalCost = 0 + } } extension LinkedMap { From 9c65635650ea4718f46068f447357b038d318c09 Mon Sep 17 00:00:00 2001 From: lizhihong Date: Thu, 6 Aug 2020 17:14:09 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=8C=89=E7=85=A7review=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=B8=85=E7=A9=BA=E5=85=A8=E9=83=A8=E7=BC=93=E5=AD=98=E7=9A=84?= =?UTF-8?q?while=E5=BE=AA=E7=8E=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/ClaretCache/MemoryCache.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/ClaretCache/MemoryCache.swift b/Sources/ClaretCache/MemoryCache.swift index c9a0fd8..bfa9cac 100644 --- a/Sources/ClaretCache/MemoryCache.swift +++ b/Sources/ClaretCache/MemoryCache.swift @@ -374,10 +374,10 @@ fileprivate final class LinkedMap where Key : Hashable { func deleteAll() { var node = head - while node != nil { - let tempNode = node?.next + while let tempNode = node?.next { + node?.next = nil - tempNode?.prev = nil + tempNode.prev = nil node = tempNode } dic.removeAll()