62 lines
2.4 KiB
Python
62 lines
2.4 KiB
Python
import bisect, time
|
|
|
|
class CacheDict(dict):
|
|
"""This class works like a basic dictionary except that you can put
|
|
constraints on its size. Once that size is reached, the key that was
|
|
inserted or accessed the least recently is removed every time a new key
|
|
is added."""
|
|
def __init__(self, max_size=10000):
|
|
'''build a cache'''
|
|
# once max_size is reached, the oldest cache entry will be pushed out to
|
|
# make room for each new one.
|
|
self.max_size = max_size
|
|
dict.__init__(self)
|
|
# _times_dict will map keys to timestamps.
|
|
self._times_dict = {}
|
|
# _times_list will store (timestamp, key) pairs, sorted oldest first.
|
|
self._times_list = []
|
|
|
|
def _timestamp_index(self, key):
|
|
'''find the index in the list of timestamps for the given key'''
|
|
assert key in self
|
|
item = (self._times_dict[key], key)
|
|
# look for the item in the (sorted) list
|
|
i = bisect.bisect_left(self._times_list, item)
|
|
# make sure the index we are returning really is valid
|
|
if item != self._times_list[i]:
|
|
raise LookupError("key %r was not found" % key)
|
|
return i
|
|
|
|
def __getitem__(self, key):
|
|
'''implements d[key]'''
|
|
# find the value in the dict
|
|
value = dict.__getitem__(self, key)
|
|
# do this to update the timestamp on this key
|
|
self[key] = value
|
|
return value
|
|
|
|
def __setitem__(self, key, value):
|
|
'''implements d[key] = value'''
|
|
# delete any old instance of the key to make way for the new
|
|
if key in self:
|
|
del self._times_list[self._timestamp_index(key)]
|
|
# remove old keys until we have enough space to add this one
|
|
while len(self._times_list) >= self.max_size:
|
|
key = self._times_list[0][1]
|
|
del self[key]
|
|
# add this key, create a timestamp, and update our other data
|
|
# structures accordingly
|
|
t = time.time()
|
|
dict.__setitem__(self, key, value)
|
|
self._times_dict[key] = t
|
|
# make sure we keep the list sorted
|
|
bisect.insort_left(self._times_list, (t, key))
|
|
|
|
def __delitem__(self, key):
|
|
'''implements del d[key]'''
|
|
# we need to make sure we delete this key out of all three of our data
|
|
# structures
|
|
del self._times_list[self._timestamp_index(key)]
|
|
del self._times_dict[key]
|
|
dict.__delitem__(self, key)
|