from typing import TYPE_CHECKING | |
if TYPE_CHECKING: | |
from typing import Any | |
_SENTINEL = object() | |
class LRUCache: | |
def __init__(self, max_size): | |
# type: (int) -> None | |
if max_size <= 0: | |
raise AssertionError(f"invalid max_size: {max_size}") | |
self.max_size = max_size | |
self._data = {} # type: dict[Any, Any] | |
self.hits = self.misses = 0 | |
self.full = False | |
def set(self, key, value): | |
# type: (Any, Any) -> None | |
current = self._data.pop(key, _SENTINEL) | |
if current is not _SENTINEL: | |
self._data[key] = value | |
elif self.full: | |
self._data.pop(next(iter(self._data))) | |
self._data[key] = value | |
else: | |
self._data[key] = value | |
self.full = len(self._data) >= self.max_size | |
def get(self, key, default=None): | |
# type: (Any, Any) -> Any | |
try: | |
ret = self._data.pop(key) | |
except KeyError: | |
self.misses += 1 | |
ret = default | |
else: | |
self.hits += 1 | |
self._data[key] = ret | |
return ret | |
def get_all(self): | |
# type: () -> list[tuple[Any, Any]] | |
return list(self._data.items()) | |