2023-10-14 04:07:27 +01:00
|
|
|
from time import monotonic
|
|
|
|
|
2023-10-14 23:29:50 +01:00
|
|
|
|
2023-10-14 04:07:27 +01:00
|
|
|
class LRUCache:
|
|
|
|
def __init__(self, open: callable, *, capacity: int, maxage: float):
|
|
|
|
self.open = open
|
|
|
|
self.capacity = capacity
|
|
|
|
self.maxage = maxage
|
|
|
|
self.cache = [] # Each item is a tuple: (key, handle, timestamp), recent items first
|
|
|
|
|
|
|
|
def __contains__(self, key):
|
|
|
|
return any(rec[0] == key for rec in self.cache)
|
|
|
|
|
|
|
|
def __getitem__(self, key):
|
|
|
|
# Take from cache or open a new one
|
|
|
|
for i, (k, f, ts) in enumerate(self.cache):
|
|
|
|
if k == key:
|
|
|
|
self.cache.pop(i)
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
f = self.open(key)
|
|
|
|
# Add/restore to end of cache
|
|
|
|
self.cache.append((key, f, monotonic()))
|
|
|
|
self.expire_items()
|
|
|
|
return f
|
|
|
|
|
|
|
|
def expire_items(self):
|
|
|
|
ts = monotonic() - self.maxage
|
|
|
|
while len(self.cache) > self.capacity or self.cache and self.cache[-1][2] < ts:
|
|
|
|
self.cache.pop()[1].close()
|
2023-10-14 23:29:50 +01:00
|
|
|
|
|
|
|
def close(self):
|
|
|
|
self.capacity = 0
|
|
|
|
self.expire_items()
|