File size: 2,205 Bytes
895e804
 
 
 
 
 
 
1bfc3f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
895e804
1bfc3f0
895e804
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1bfc3f0
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
"""Small per-instance LRU caches; no global references to fitted codecs."""

from collections import OrderedDict
from collections.abc import MutableMapping
from threading import RLock


def cached_prefix_state(key, cache, initial, advance):
    """Extend a cached parent prefix, replaying only when it was evicted."""
    if not key:
        return initial
    missing = object()
    state = cache.get(key, missing)
    if state is not missing:
        return state
    parent = key[:-1]
    state = cache.get(parent, missing)
    if state is missing:
        state = initial
        for token in parent:
            state = advance(state, token)
            if state is None:
                break
        cache[parent] = state
    if state is not None:
        state = advance(state, key[-1])
    cache[key] = state
    return state


class BoundedCache(MutableMapping):
    """Evict least-recently-used entries above a fixed capacity."""

    def __init__(self, capacity):
        if type(capacity) is not int or capacity < 1:
            raise ValueError("cache capacity must be a positive integer")
        self.capacity = capacity
        self._items = OrderedDict()
        self._lock = RLock()

    def __getitem__(self, key):
        with self._lock:
            value = self._items[key]
            self._items.move_to_end(key)
            return value

    def __setitem__(self, key, value):
        with self._lock:
            self._items[key] = value
            self._items.move_to_end(key)
            while len(self._items) > self.capacity:
                self._items.popitem(last=False)

    def __delitem__(self, key):
        with self._lock:
            del self._items[key]

    def __iter__(self):
        with self._lock:
            return iter(tuple(self._items))

    def __len__(self):
        with self._lock:
            return len(self._items)

    def reserve(self, capacity):
        """Raise the capacity so callers with a known working set stop thrashing."""
        if type(capacity) is not int or capacity < 1:
            raise ValueError("cache capacity must be a positive integer")
        with self._lock:
            self.capacity = max(self.capacity, capacity)