Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- namespace Cache;
- public class LRUCache<K,V> where K: notnull
- {
- private record struct CacheItem<K, V>(K Key, V Value)
- {
- public K Key { get;} = Key;
- }
- private SemaphoreSlim _lockSync = new SemaphoreSlim(1,1);
- private int _capacity;
- private readonly Dictionary<K, CacheItem<K,V>> _cache;
- private readonly LinkedList<CacheItem<K,V>> _accessOrder;
- public LRUCache(int capacity)
- {
- if (capacity <= 0)
- {
- throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "capacity must be >0");
- }
- _capacity = capacity;
- _cache = new Dictionary<K, CacheItem<K,V>>(capacity);
- _accessOrder = new LinkedList<CacheItem<K, V>>();
- }
- public int Capacity
- {
- get
- {
- return _capacity;
- }
- set
- {
- UpdateCapacity(value);
- }
- }
- private void UpdateCapacity(int newCapacity)
- {
- if (newCapacity <= 0)
- {
- throw new ArgumentOutOfRangeException(nameof(newCapacity), newCapacity, "new capacity must be >0");
- }
- _lockSync.Wait();
- try
- {
- while (_accessOrder.Count > newCapacity)
- {
- var lastNode = _accessOrder.Last;
- _cache.Remove(lastNode.Value.Key);
- _accessOrder.RemoveLast();
- }
- _cache.EnsureCapacity(newCapacity);
- _capacity = newCapacity;
- }
- finally
- {
- _lockSync.Release();
- }
- }
- public V this[K key]
- {
- get
- {
- return this.Get(key);
- }
- set
- {
- this.AddOrUpdate(key,value);
- }
- }
- public V Get(K key)
- {
- _lockSync.Wait();
- try
- {
- if (_cache.TryGetValue(key, out var node))
- {
- _accessOrder.Remove(node);
- _accessOrder.AddFirst(node);
- return node.Value;
- }
- throw new KeyNotFoundException("key is not found");
- }
- finally
- {
- _lockSync.Release();
- }
- }
- public void AddOrUpdate(K key, V value)
- {
- _lockSync.Wait();
- try
- {
- if (_cache.TryGetValue(key, out var node))
- {
- _accessOrder.Remove(node);
- _accessOrder.AddFirst(node);
- node.Value = value;
- _cache[key] = node;
- }
- else
- {
- CacheItem<K, V> newItem = new CacheItem<K, V>(key, value);
- if (_cache.Count == _capacity)
- {
- var lastItem = _accessOrder.Last;
- _cache.Remove(lastItem.Value.Key);
- _accessOrder.RemoveLast();
- }
- _accessOrder.AddFirst(newItem);
- _cache.Add(key, newItem);
- }
- }
- finally
- {
- _lockSync.Release();
- }
- }
- public void Add(K key, V value)
- {
- _lockSync.Wait();
- try
- {
- if (!_cache.ContainsKey(key))
- {
- CacheItem<K, V> newItem = new CacheItem<K, V>(key, value);
- if (_cache.Count == _capacity)
- {
- var lastItem = _accessOrder.Last;
- _cache.Remove(lastItem.Value.Key);
- _accessOrder.RemoveLast();
- }
- _accessOrder.AddFirst(newItem);
- _cache.Add(key, newItem);
- }
- else
- {
- throw new Exception("key already exists");
- }
- }
- finally
- {
- _lockSync.Release();
- }
- }
- public V Remove(K key)
- {
- _lockSync.Wait();
- try
- {
- if (_cache.TryGetValue(key, out var cacheItem))
- {
- _cache.Remove(key);
- _accessOrder.Remove(cacheItem);
- return cacheItem.Value;
- }
- throw new KeyNotFoundException("Key does not exist");
- }
- finally
- {
- _lockSync.Release();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement