|
| 1 | +from __future__ import annotations |
| 2 | + |
1 | 3 | import sys
|
2 | 4 | from collections import deque
|
| 5 | +from typing import Generic, TypeVar |
| 6 | + |
| 7 | +T = TypeVar("T") |
| 8 | + |
| 9 | + |
| 10 | +class LRUCache(Generic[T]): |
| 11 | + """ |
| 12 | + Page Replacement Algorithm, Least Recently Used (LRU) Caching. |
| 13 | +
|
| 14 | + >>> lru_cache: LRUCache[str | int] = LRUCache(4) |
| 15 | + >>> lru_cache.refer("A") |
| 16 | + >>> lru_cache.refer(2) |
| 17 | + >>> lru_cache.refer(3) |
| 18 | +
|
| 19 | + >>> lru_cache |
| 20 | + LRUCache(4) => [3, 2, 'A'] |
3 | 21 |
|
| 22 | + >>> lru_cache.refer("A") |
| 23 | + >>> lru_cache |
| 24 | + LRUCache(4) => ['A', 3, 2] |
4 | 25 |
|
5 |
| -class LRUCache: |
6 |
| - """Page Replacement Algorithm, Least Recently Used (LRU) Caching.""" |
| 26 | + >>> lru_cache.refer(4) |
| 27 | + >>> lru_cache.refer(5) |
| 28 | + >>> lru_cache |
| 29 | + LRUCache(4) => [5, 4, 'A', 3] |
7 | 30 |
|
8 |
| - dq_store = object() # Cache store of keys |
9 |
| - key_reference_map = object() # References of the keys in cache |
| 31 | + """ |
| 32 | + |
| 33 | + dq_store: deque[T] # Cache store of keys |
| 34 | + key_reference: set[T] # References of the keys in cache |
10 | 35 | _MAX_CAPACITY: int = 10 # Maximum capacity of cache
|
11 | 36 |
|
12 |
| - def __init__(self, n: int): |
| 37 | + def __init__(self, n: int) -> None: |
13 | 38 | """Creates an empty store and map for the keys.
|
14 | 39 | The LRUCache is set the size n.
|
15 | 40 | """
|
16 | 41 | self.dq_store = deque()
|
17 |
| - self.key_reference_map = set() |
| 42 | + self.key_reference = set() |
18 | 43 | if not n:
|
19 | 44 | LRUCache._MAX_CAPACITY = sys.maxsize
|
20 | 45 | elif n < 0:
|
21 | 46 | raise ValueError("n should be an integer greater than 0.")
|
22 | 47 | else:
|
23 | 48 | LRUCache._MAX_CAPACITY = n
|
24 | 49 |
|
25 |
| - def refer(self, x): |
| 50 | + def refer(self, x: T) -> None: |
26 | 51 | """
|
27 | 52 | Looks for a page in the cache store and adds reference to the set.
|
28 | 53 | Remove the least recently used key if the store is full.
|
29 | 54 | Update store to reflect recent access.
|
30 | 55 | """
|
31 |
| - if x not in self.key_reference_map: |
| 56 | + if x not in self.key_reference: |
32 | 57 | if len(self.dq_store) == LRUCache._MAX_CAPACITY:
|
33 | 58 | last_element = self.dq_store.pop()
|
34 |
| - self.key_reference_map.remove(last_element) |
| 59 | + self.key_reference.remove(last_element) |
35 | 60 | else:
|
36 |
| - index_remove = 0 |
37 |
| - for idx, key in enumerate(self.dq_store): |
38 |
| - if key == x: |
39 |
| - index_remove = idx |
40 |
| - break |
41 |
| - self.dq_store.remove(index_remove) |
| 61 | + self.dq_store.remove(x) |
42 | 62 |
|
43 | 63 | self.dq_store.appendleft(x)
|
44 |
| - self.key_reference_map.add(x) |
| 64 | + self.key_reference.add(x) |
45 | 65 |
|
46 |
| - def display(self): |
| 66 | + def display(self) -> None: |
47 | 67 | """
|
48 | 68 | Prints all the elements in the store.
|
49 | 69 | """
|
50 | 70 | for k in self.dq_store:
|
51 | 71 | print(k)
|
52 | 72 |
|
| 73 | + def __repr__(self) -> str: |
| 74 | + return f"LRUCache({self._MAX_CAPACITY}) => {list(self.dq_store)}" |
| 75 | + |
53 | 76 |
|
54 | 77 | if __name__ == "__main__":
|
55 |
| - lru_cache = LRUCache(4) |
56 |
| - lru_cache.refer(1) |
| 78 | + import doctest |
| 79 | + |
| 80 | + doctest.testmod() |
| 81 | + |
| 82 | + lru_cache: LRUCache[str | int] = LRUCache(4) |
| 83 | + lru_cache.refer("A") |
57 | 84 | lru_cache.refer(2)
|
58 | 85 | lru_cache.refer(3)
|
59 |
| - lru_cache.refer(1) |
| 86 | + lru_cache.refer("A") |
60 | 87 | lru_cache.refer(4)
|
61 | 88 | lru_cache.refer(5)
|
62 | 89 | lru_cache.display()
|
| 90 | + |
| 91 | + print(lru_cache) |
| 92 | + assert str(lru_cache) == "LRUCache(4) => [5, 4, 'A', 3]" |
0 commit comments