//===----------------------------------------------------------------------===// // Copyright © 2025 Apple Inc. and the container project authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //===----------------------------------------------------------------------===// struct KeyExistsError: Error {} class LRUCache { private class Node { fileprivate var prev: Node? fileprivate var next: Node? fileprivate let key: K fileprivate let value: V init(key: K, value: V) { self.prev = nil self.next = nil self.key = key self.value = value } } private let size: UInt private var head: Node? private var tail: Node? private var members: [K: Node] init(size: UInt) { self.size = size self.head = nil self.tail = nil self.members = [:] } var count: Int { members.count } func get(_ key: K) -> V? { guard let node = members[key] else { return nil } listRemove(node: node) listInsert(node: node, after: tail) return node.value } func put(key: K, value: V) -> (K, V)? { let node = Node(key: key, value: value) var evicted: (K, V)? = nil if let existingNode = members[key] { // evict the replaced node listRemove(node: existingNode) evicted = (existingNode.key, existingNode.value) } else if self.count >= self.size { // evict the least recently used node evicted = evict() } // insert the new node and return any evicted node members[key] = node listInsert(node: node, after: tail) return evicted } private func evict() -> (K, V)? { guard let head else { return nil } let ret = (head.key, head.value) listRemove(node: head) members.removeValue(forKey: head.key) return ret } private func listRemove(node: Node) { if let prev = node.prev { prev.next = node.next } else { head = node.next } if let next = node.next { next.prev = node.prev } else { tail = node.prev } } private func listInsert(node: Node, after: Node?) { let before: Node? if let after { before = after.next after.next = node } else { before = head head = node } if let before { before.prev = node } else { tail = node } node.prev = after node.next = before } }