Skip to content

Instantly share code, notes, and snippets.

@idfumg
Created March 4, 2024 06:24
Show Gist options
  • Save idfumg/1375eb4bf273d1357f57a39a1442aded to your computer and use it in GitHub Desktop.
Save idfumg/1375eb4bf273d1357f57a39a1442aded to your computer and use it in GitHub Desktop.
from typing import TypeVar, Generic, Optional, Hashable, TypeAlias
from icecream import ic # type: ignore
KeyT = TypeVar("KeyT", bound=Hashable)
ValueT = TypeVar("ValueT")
class Node(Generic[KeyT, ValueT]):
def __init__(self, key: Optional[KeyT], value: Optional[ValueT]):
assert key is not None
assert value is not None
self.key: KeyT = key
self.value: ValueT = value
self.prev: Node[KeyT, ValueT]
self.next: Node[KeyT, ValueT]
class List(Generic[KeyT, ValueT]):
def __init__(self):
self.head: Node[KeyT, ValueT] = Node[KeyT, ValueT](None, None)
self.tail: Node[KeyT, ValueT] = Node[KeyT, ValueT](None, None)
self.head.next = self.tail
self.tail.prev = self.head
def push_front(self, node: Node[KeyT, ValueT]) -> None:
node.prev = self.head
node.next = self.head.next
self.head.next.prev = node
self.head.next = node
def remove(self, node: Node[KeyT, ValueT] | None) -> None:
if not node: return
prev = node.prev
next = node.next
prev.next = next
next.prev = prev
def move_front(self, node: Node[KeyT, ValueT] | None) -> None:
if not node: return
self.remove(node)
self.push_front(node)
def back(self) -> Node[KeyT, ValueT] | None:
if self.tail == self.head: return None
return self.tail.prev
class LRUCache(Generic[KeyT, ValueT]):
def __init__(self, capacity: int):
self.capacity: int = capacity
self.cache: dict[KeyT, Node[KeyT, ValueT]] = {}
self.list: List[KeyT, ValueT] = List[KeyT, ValueT]()
def get(self, key: KeyT) -> ValueT | None:
node = self.cache.get(key, None)
if not node:
return None
self.list.move_front(node)
return node.value
def put(self, key: KeyT, value: ValueT) -> None:
node = self.cache.get(key)
if node:
node.value = value
self.list.move_front(node)
return
if len(self.cache) == self.capacity:
tail = self.list.back()
if tail:
self.list.remove(tail)
del self.cache[tail.key]
newNode = Node[KeyT, ValueT](key, value)
self.cache[key] = newNode
self.list.push_front(newNode)
if __name__ == '__main__':
cache = LRUCache[str, str](2)
cache.put("Response1", "Content1")
cache.put("Response2", "Content2") # Response1, Response2
ic(cache.get("Response1")) # Content1
cache.put("Response3", "Content3") # Response3, Response1
ic(cache.get("Response2")) # nil
cache.put("Response4", "Content4") # Response4, Response3
ic(cache.get("Response1")) # nil
ic(cache.get("Response2")) # nil
ic(cache.get("Response3")) # Content3
ic(cache.get("Response4")) # Content4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment