|
- cdef object _LRU_MARKER = object()
-
-
- @cython.final
- cdef class LruCache:
-
- cdef:
- object _dict
- int _maxsize
- object _dict_move_to_end
- object _dict_get
-
- # We use an OrderedDict for LRU implementation. Operations:
- #
- # * We use a simple `__setitem__` to push a new entry:
- # `entries[key] = new_entry`
- # That will push `new_entry` to the *end* of the entries dict.
- #
- # * When we have a cache hit, we call
- # `entries.move_to_end(key, last=True)`
- # to move the entry to the *end* of the entries dict.
- #
- # * When we need to remove entries to maintain `max_size`, we call
- # `entries.popitem(last=False)`
- # to remove an entry from the *beginning* of the entries dict.
- #
- # So new entries and hits are always promoted to the end of the
- # entries dict, whereas the unused one will group in the
- # beginning of it.
-
- def __init__(self, *, maxsize):
- if maxsize <= 0:
- raise ValueError(
- f'maxsize is expected to be greater than 0, got {maxsize}')
-
- self._dict = col_OrderedDict()
- self._dict_move_to_end = self._dict.move_to_end
- self._dict_get = self._dict.get
- self._maxsize = maxsize
-
- cdef get(self, key, default):
- o = self._dict_get(key, _LRU_MARKER)
- if o is _LRU_MARKER:
- return default
- self._dict_move_to_end(key) # last=True
- return o
-
- cdef inline needs_cleanup(self):
- return len(self._dict) > self._maxsize
-
- cdef inline cleanup_one(self):
- k, _ = self._dict.popitem(last=False)
- return k
-
- def __getitem__(self, key):
- o = self._dict[key]
- self._dict_move_to_end(key) # last=True
- return o
-
- def __setitem__(self, key, o):
- if key in self._dict:
- self._dict[key] = o
- self._dict_move_to_end(key) # last=True
- else:
- self._dict[key] = o
- while self.needs_cleanup():
- self.cleanup_one()
-
- def __delitem__(self, key):
- del self._dict[key]
-
- def __contains__(self, key):
- return key in self._dict
-
- def __len__(self):
- return len(self._dict)
-
- def __iter__(self):
- return iter(self._dict)
|