LRUCache.swift 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import Foundation
  2. private class List<Key>: CustomDebugStringConvertible {
  3. var debugDescription: String { "\(value)" }
  4. var value: Key
  5. var prev: List?
  6. var next: List?
  7. init(_ val: Key) {
  8. value = val
  9. }
  10. }
  11. final class LRUCache<Key, Value> where Key: Hashable {
  12. private var cache: [Key: Value] = [:]
  13. private var listBegin: List<Key>?
  14. private var listEnd: List<Key>?
  15. private var listCache: [Key: List<Key>] = [:]
  16. private let lock = NSRecursiveLock()
  17. private let capacity: Int
  18. init(capacity: Int) {
  19. cache.reserveCapacity(capacity)
  20. listCache.reserveCapacity(capacity)
  21. self.capacity = capacity
  22. }
  23. var isEmpty: Bool {
  24. lock.perform {
  25. cache.isEmpty
  26. }
  27. }
  28. var isFull: Bool {
  29. lock.perform {
  30. cache.count == capacity
  31. }
  32. }
  33. var count: Int {
  34. lock.perform {
  35. cache.count
  36. }
  37. }
  38. var allValues: [Value] {
  39. lock.perform {
  40. Array(cache.values)
  41. }
  42. }
  43. func removeAll() {
  44. listCache.keys.forEach(remove(_:))
  45. }
  46. subscript(key: Key) -> Value? {
  47. get {
  48. lock.perform {
  49. guard let value = cache[key] else { return nil }
  50. self[key] = value
  51. return value
  52. }
  53. }
  54. set {
  55. lock.perform {
  56. remove(key)
  57. if let value = newValue {
  58. insert(key, value)
  59. }
  60. }
  61. }
  62. }
  63. private func remove(_ key: Key) {
  64. autoreleasepool {
  65. guard let node = listCache[key] else { return }
  66. listCache[key] = nil
  67. cache[key] = nil
  68. let p = node.prev
  69. let n = node.next
  70. p?.next = n
  71. n?.prev = p
  72. if node.value == listBegin!.value {
  73. listBegin = n
  74. }
  75. if node.value == listEnd!.value {
  76. listEnd = listEnd!.prev
  77. }
  78. }
  79. }
  80. private func insert(_ key: Key, _ value: Value) {
  81. if cache.count == capacity {
  82. remove(listBegin!.value)
  83. }
  84. let le = listEnd
  85. listEnd = List(key)
  86. le?.next = listEnd
  87. listEnd!.prev = le
  88. listBegin = listBegin ?? listEnd
  89. listCache[key] = listEnd
  90. cache[key] = value
  91. }
  92. }