64 lines
1.7 KiB
C#
64 lines
1.7 KiB
C#
namespace Explorer.Application;
|
|
|
|
public sealed class LruCache<TKey, TValue>
|
|
where TKey : notnull
|
|
{
|
|
private readonly int _capacity;
|
|
private readonly Dictionary<TKey, LinkedListNode<(TKey Key, TValue Value)>> _map;
|
|
private readonly LinkedList<(TKey Key, TValue Value)> _order;
|
|
private readonly object _gate = new();
|
|
|
|
public LruCache(int capacity)
|
|
{
|
|
ArgumentOutOfRangeException.ThrowIfLessThan(capacity, 1);
|
|
_capacity = capacity;
|
|
_map = new Dictionary<TKey, LinkedListNode<(TKey, TValue)>>(capacity);
|
|
_order = new LinkedList<(TKey, TValue)>();
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
get { lock (_gate) return _map.Count; }
|
|
}
|
|
|
|
public bool TryGet(TKey key, out TValue value)
|
|
{
|
|
lock (_gate)
|
|
{
|
|
if (_map.TryGetValue(key, out var node))
|
|
{
|
|
_order.Remove(node);
|
|
_order.AddFirst(node);
|
|
value = node.Value.Value;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
value = default!;
|
|
return false;
|
|
}
|
|
|
|
public void Set(TKey key, TValue value)
|
|
{
|
|
lock (_gate)
|
|
{
|
|
if (_map.TryGetValue(key, out var existing))
|
|
{
|
|
_order.Remove(existing);
|
|
existing.Value = (key, value);
|
|
_order.AddFirst(existing);
|
|
return;
|
|
}
|
|
|
|
var node = _order.AddFirst((key, value));
|
|
_map[key] = node;
|
|
while (_map.Count > _capacity)
|
|
{
|
|
var last = _order.Last!;
|
|
_order.RemoveLast();
|
|
_map.Remove(last.Value.Key);
|
|
}
|
|
}
|
|
}
|
|
}
|