Untitled
unknown
plain_text
10 days ago
3.0 kB
3
Indexable
Never
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)
Leave a Comment