using System; using System.Collections.Immutable; namespace OpenTap { /// Cache class which clears when a certain criteria is met. internal class Cache { // using immutable dictionary to avoid issues with race conditions. // note that for caches data races are not that important. ImmutableDictionary dict = ImmutableDictionary.Empty; // this function returns an object which is used for checking if the cache should be cleared. readonly Func clearTrigger; // last object returned by clearTrigger. object currentObj; /// The current number of cached elements. public int Count { get { CheckClear(); return dict.Count; } } public Cache(Func clearTrigger) { this.clearTrigger = clearTrigger; currentObj = clearTrigger(); } void CheckClear() { var clearCheck = clearTrigger(); if (Equals(clearCheck, currentObj) == false) { dict = ImmutableDictionary.Empty; currentObj = clearTrigger(); } } /// tries getting a value for a key. public bool TryGetValue(K key, out V value) { CheckClear(); return dict.TryGetValue(key, out value); } public V AddValue(K key, V value) { CheckClear(); dict = dict.SetItem(key, value); return value; } } class CacheObservable { public event EventHandler Updated; public void OnUpdated() { Updated?.Invoke(this, EventArgs.Empty); } } internal class Cached { readonly Func getValue; K value; bool hasValue; public K GetValue() { if (!hasValue) { value = getValue(); hasValue = true; } return value; } public Cached(CacheObservable cacheState, Func getValue) { this.getValue = getValue; cacheState.Updated += CacheStateOnChange; } void CacheStateOnChange(object sender, EventArgs e) { hasValue = false; } } }