Added ExtendedCache
parent
12f733d6f0
commit
2f31a6cd06
|
@ -0,0 +1,149 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ln.collections
|
||||
{
|
||||
public delegate bool CacheMayForget<K,V>(ExtendedCache<K,V> cache,V item);
|
||||
|
||||
public class ExtendedCache<K,V>
|
||||
{
|
||||
public event CacheMayForget<K, V> OnCacheMayForget;
|
||||
|
||||
private MappingBTree<K, ExtendedCacheItem<K, V>> cacheItems =
|
||||
new MappingBTree<K, ExtendedCacheItem<K, V>>((i) => i.Key);
|
||||
|
||||
private BTreeValueSet<DateTime, ExtendedCacheItem<K, V>> cacheAges =
|
||||
new BTreeValueSet<DateTime, ExtendedCacheItem<K, V>>();
|
||||
|
||||
private int _targetSize = 4096;
|
||||
public int TargetSize
|
||||
{
|
||||
get => _targetSize;
|
||||
set
|
||||
{
|
||||
_targetSize = value;
|
||||
if (Count > _targetSize) Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public int Count => cacheItems.Count;
|
||||
|
||||
|
||||
public ExtendedCache()
|
||||
{
|
||||
}
|
||||
|
||||
public ExtendedCache(int targetSize) : this()
|
||||
{
|
||||
TargetSize = targetSize;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
cacheItems.Clear();
|
||||
cacheAges.Clear();
|
||||
}
|
||||
|
||||
public void Invalidate()
|
||||
{
|
||||
if (Count <= _targetSize)
|
||||
return;
|
||||
|
||||
foreach (ExtendedCache<K,V>.ExtendedCacheItem<K,V> eci in cacheAges.Values)
|
||||
{
|
||||
if (MayForget(eci.Value))
|
||||
Invalidate(eci);
|
||||
|
||||
if (Count <= _targetSize)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private bool MayForget(V item)
|
||||
{
|
||||
foreach (CacheMayForget<K,V> mayForget in OnCacheMayForget.GetInvocationList() ?? new CacheMayForget<K, V>[0])
|
||||
{
|
||||
if (!mayForget(this, item))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public V this[K key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (TryGet(key, out V value))
|
||||
return value;
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGet(K key, out V value)
|
||||
{
|
||||
if (cacheItems.TryGet(key, out ExtendedCacheItem<K, V> eci))
|
||||
{
|
||||
value = eci.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = default(V);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UpdateCacheItem(ExtendedCacheItem<K, V> eci)
|
||||
{
|
||||
cacheAges.Remove(eci.Timestamp, eci);
|
||||
eci.Timestamp = DateTime.Now;
|
||||
cacheAges.Add(eci.Timestamp, eci);
|
||||
}
|
||||
|
||||
public bool Ensure(K key, V value)
|
||||
{
|
||||
if (cacheItems.TryGet(key, out ExtendedCacheItem<K, V> eci))
|
||||
{
|
||||
if (!Object.ReferenceEquals(eci.Value, value))
|
||||
return false;
|
||||
UpdateCacheItem(eci);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
eci = new ExtendedCacheItem<K, V>(key, value);
|
||||
cacheItems.Add(eci);
|
||||
cacheAges.Add(eci.Timestamp, eci);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Invalidate(K key)
|
||||
{
|
||||
if (cacheItems.TryGet(key, out ExtendedCacheItem<K, V> eci))
|
||||
{
|
||||
Invalidate(eci);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Invalidate(ExtendedCacheItem<K, V> eci)
|
||||
{
|
||||
cacheAges.Remove(eci.Timestamp, eci);
|
||||
cacheItems.RemoveKey(eci.Key);
|
||||
}
|
||||
|
||||
public class ExtendedCacheItem<TK, TV>
|
||||
{
|
||||
public DateTime Timestamp;
|
||||
public TK Key;
|
||||
public TV Value;
|
||||
|
||||
public ExtendedCacheItem(TK key, TV value)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
Timestamp = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue