Untitled
unknown
python
a year ago
3.0 kB
6
Indexable
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Generic, TypeVar, Optional, Callable
from threading import Lock
from collections import deque
K = TypeVar('K')
V = TypeVar('V')
class Cache(Generic[K, V], ABC):
@abstractmethod
def get(self, key: K) -> Optional[V]:
pass
@abstractmethod
def put(self, key: K, value: V) -> None:
pass
class CacheEvictionStrategy(Generic[K],ABC):
@abstractmethod
def get_key(self, key: K) -> None:
pass
@abstractmethod
def put_key(self, key: K) -> None:
pass
@abstractmethod
def evict_key(self) -> K:
pass
@dataclass
class CacheSet(Generic[K, V]):
mapping: dict[K,V]
key_eviction_strategy: CacheEvictionStrategy[K]
lock: Lock = field(default_factory=Lock)
class NWaySetAssociativeCache(Cache[K, V]):
def __init__(self, set_count: int, set_limit: int, cache_eviction_strategy_provider: Callable[[], CacheEvictionStrategy]) -> None:
self.cache_sets = [CacheSet(dict(), cache_eviction_strategy_provider(), Lock()) for _ in range(set_count)]
self.set_limit = set_limit
def _get_set_index(self, key: K) -> int:
return hash(key) % len(self.cache_sets)
def get(self, key: K) -> Optional[V]:
set_index = self._get_set_index(key)
cache_set = self.cache_sets[set_index]
if key in cache_set.mapping:
cache_set.key_eviction_strategy.get_key(key)
return cache_set.mapping[key]
return None
def put(self, key: K, value: V) -> None:
set_index = self._get_set_index(key)
cache_set = self.cache_sets[set_index]
if key in cache_set.mapping:
cache_set.key_eviction_strategy.get_key(key)
return cache_set.mapping[key]
if len(cache_set.mapping) == self.set_limit:
eviction_key = cache_set.key_eviction_strategy.evict_key()
cache_set.mapping.pop(eviction_key)
cache_set.mapping[key] = value
cache_set.key_eviction_strategy.put_key(key)
def __str__(self) -> str:
return ','.join([str(set_.mapping) for set_ in self.cache_sets])
class FIFOCacheEvictionStrategy(CacheEvictionStrategy, Generic[K]):
def __init__(self) -> None:
self.key_queue = deque()
def get_key(self, key: K) -> None:
pass
def put_key(self, key: K) -> None:
self.key_queue.append(key)
def evict_key(self) -> K:
return self.key_queue.popleft()
lru_nway = NWaySetAssociativeCache(1, 3, lambda: FIFOCacheEvictionStrategy())
print(lru_nway)
lru_nway.put('a', 1)
print(lru_nway)
lru_nway.put('b', 2)
lru_nway.get('b')
print(lru_nway)
lru_nway.put('c', 3)
print(lru_nway)
lru_nway.put('d', 4)
print(lru_nway)
lru_nway.get('a')
print(lru_nway)
lru_nway.put('e', 4)
print(lru_nway)
lru_nway.put('f', 4)
print(lru_nway)
lru_nway.put('g', 4)
print(lru_nway)
lru_nway.get('b')
print(lru_nway)
lru_nway.get('b')
print(lru_nway)
lru_nway.get('b')
print(lru_nway)Editor is loading...
Leave a Comment