173 lines
4.7 KiB
Python
173 lines
4.7 KiB
Python
import json
|
|
from datetime import datetime
|
|
import os
|
|
|
|
|
|
class Node:
|
|
def __init__(self, key, value):
|
|
self.key = key
|
|
self.value = value
|
|
self.prev = None
|
|
self.next = None
|
|
|
|
class LRUCache:
|
|
def __init__(self, capacity):
|
|
self.capacity = capacity
|
|
self.cache = {} # key → Node
|
|
self.head = None
|
|
self.tail = None
|
|
|
|
def _remove(self, node):
|
|
if node.prev:
|
|
node.prev.next = node.next
|
|
else:
|
|
self.head = node.next # node was head
|
|
if node.next:
|
|
node.next.prev = node.prev
|
|
else:
|
|
self.tail = node.prev # node was tail
|
|
|
|
def _add_to_front(self, node):
|
|
node.next = self.head
|
|
node.prev = None
|
|
if self.head:
|
|
self.head.prev = node
|
|
self.head = node
|
|
if not self.tail:
|
|
self.tail = node
|
|
|
|
def get(self, key):
|
|
if key not in self.cache:
|
|
return -1
|
|
node = self.cache[key]
|
|
self._remove(node)
|
|
self._add_to_front(node)
|
|
return node.value
|
|
|
|
def put(self, key, value):
|
|
if key in self.cache:
|
|
self._remove(self.cache[key])
|
|
elif len(self.cache) >= self.capacity:
|
|
del self.cache[self.tail.key]
|
|
self._remove(self.tail)
|
|
new_node = Node(key, value)
|
|
self._add_to_front(new_node)
|
|
self.cache[key] = new_node
|
|
|
|
def display(self):
|
|
current = self.head
|
|
print("Cache (MRU → LRU): ", end="")
|
|
while current:
|
|
print(f"[{current.key}: {current.value}]", end=" ⇄ ")
|
|
current = current.next
|
|
print("None")
|
|
|
|
def display_reverse(self):
|
|
current = self.tail
|
|
print("Cache (LRU → MRU): ", end="")
|
|
while current:
|
|
print(f"[{current.key}: {current.value}]", end=" ⇄ ")
|
|
current = current.prev
|
|
print("None")
|
|
|
|
def to_dict(self):
|
|
result = {}
|
|
current = self.head
|
|
while current:
|
|
result[current.key] = current.value
|
|
current = current.next
|
|
return result
|
|
|
|
def from_dict(self, data_dict):
|
|
self.cache.clear()
|
|
self.head = None
|
|
self.tail = None
|
|
|
|
for key, value in data_dict.items():
|
|
if len(self.cache) >= self.capacity:
|
|
break # Respect capacity limit
|
|
new_node = Node(key, value)
|
|
self._add_to_front(new_node)
|
|
self.cache[key] = new_node
|
|
|
|
|
|
def save_to_file(self, filename=None, version="1.0"):
|
|
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
|
if not filename:
|
|
filename = f"cache_{timestamp}.json"
|
|
|
|
data = {
|
|
"version": version,
|
|
"timestamp": datetime.now().isoformat(),
|
|
"cache": self.to_dict()
|
|
}
|
|
|
|
with open(filename, 'w') as f:
|
|
json.dump(data, f, indent=2)
|
|
|
|
print(f"Cache saved to {filename}")
|
|
|
|
|
|
def load_from_file(self, filename):
|
|
try:
|
|
with open(filename, 'r') as f:
|
|
data = json.load(f)
|
|
version = data.get("version", "unknown")
|
|
timestamp = data.get("timestamp", "unknown")
|
|
print(f"Loaded cache version {version} from {timestamp}")
|
|
self.from_dict(data.get("cache", {}))
|
|
except (FileNotFoundError, json.JSONDecodeError) as e:
|
|
print(f"Failed to load cache: {e}")
|
|
|
|
def load_latest_cache(self, directory=".", prefix="cache_", extension=".json"):
|
|
files = [
|
|
f for f in os.listdir(directory)
|
|
if f.startswith(prefix) and f.endswith(extension)
|
|
]
|
|
if not files:
|
|
print("No saved cache files found.")
|
|
return
|
|
|
|
latest_file = max(files) # Lexicographic sort works with timestamped names
|
|
print(f"Loading latest cache: {latest_file}")
|
|
self.load_from_file(os.path.join(directory, latest_file))
|
|
|
|
@staticmethod
|
|
def list_saved_caches(directory=".", prefix="cache_", extension=".json"):
|
|
files = []
|
|
for filename in os.listdir(directory):
|
|
if filename.startswith(prefix) and filename.endswith(extension):
|
|
files.append(filename)
|
|
files.sort() # Sort by name (timestamped)
|
|
print("Saved cache files:")
|
|
for f in files:
|
|
print(" •", f)
|
|
return files
|
|
|
|
|
|
|
|
|
|
lru = LRUCache(3)
|
|
lru.put("A", 1)
|
|
lru.put("B", 2)
|
|
lru.put("C", 3)
|
|
lru.save_to_file("cache.json")
|
|
|
|
# Later or in another session
|
|
new_lru = LRUCache(3)
|
|
new_lru.load_from_file("cache.json")
|
|
new_lru.display()
|
|
|
|
|
|
lru = LRUCache(4)
|
|
lru.put("A", 1)
|
|
lru.put("B", 2)
|
|
lru.put("C", 3)
|
|
lru.put("D", 4)
|
|
lru.save_to_file() # Automatically names file like cache_2025-09-27_09-09-00.json
|
|
|
|
list_saved_caches()
|
|
|
|
lru = LRUCache(3)
|
|
lru.load_latest_cache()
|
|
lru.display() |