Untitled
unknown
plain_text
a year ago
3.0 kB
10
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