89 lines
2.2 KiB
Python
89 lines
2.2 KiB
Python
from .abc import DefaultMapping
|
|
|
|
|
|
class _DefaultSize(object):
|
|
def __getitem__(self, _):
|
|
return 1
|
|
|
|
def __setitem__(self, _, value):
|
|
assert value == 1
|
|
|
|
def pop(self, _):
|
|
return 1
|
|
|
|
|
|
class Cache(DefaultMapping):
|
|
"""Mutable mapping to serve as a simple cache or cache base class."""
|
|
|
|
__size = _DefaultSize()
|
|
|
|
def __init__(self, maxsize, getsizeof=None):
|
|
if getsizeof:
|
|
self.getsizeof = getsizeof
|
|
if self.getsizeof is not Cache.getsizeof:
|
|
self.__size = dict()
|
|
self.__data = dict()
|
|
self.__currsize = 0
|
|
self.__maxsize = maxsize
|
|
|
|
def __repr__(self):
|
|
return '%s(%r, maxsize=%r, currsize=%r)' % (
|
|
self.__class__.__name__,
|
|
list(self.__data.items()),
|
|
self.__maxsize,
|
|
self.__currsize,
|
|
)
|
|
|
|
def __getitem__(self, key):
|
|
try:
|
|
return self.__data[key]
|
|
except KeyError:
|
|
return self.__missing__(key)
|
|
|
|
def __setitem__(self, key, value):
|
|
maxsize = self.__maxsize
|
|
size = self.getsizeof(value)
|
|
if size > maxsize:
|
|
raise ValueError('value too large')
|
|
if key not in self.__data or self.__size[key] < size:
|
|
while self.__currsize + size > maxsize:
|
|
self.popitem()
|
|
if key in self.__data:
|
|
diffsize = size - self.__size[key]
|
|
else:
|
|
diffsize = size
|
|
self.__data[key] = value
|
|
self.__size[key] = size
|
|
self.__currsize += diffsize
|
|
|
|
def __delitem__(self, key):
|
|
size = self.__size.pop(key)
|
|
del self.__data[key]
|
|
self.__currsize -= size
|
|
|
|
def __contains__(self, key):
|
|
return key in self.__data
|
|
|
|
def __missing__(self, key):
|
|
raise KeyError(key)
|
|
|
|
def __iter__(self):
|
|
return iter(self.__data)
|
|
|
|
def __len__(self):
|
|
return len(self.__data)
|
|
|
|
@property
|
|
def maxsize(self):
|
|
"""The maximum size of the cache."""
|
|
return self.__maxsize
|
|
|
|
@property
|
|
def currsize(self):
|
|
"""The current size of the cache."""
|
|
return self.__currsize
|
|
|
|
@staticmethod
|
|
def getsizeof(value):
|
|
"""Return the size of a cache element's value."""
|
|
return 1
|