diff --git a/ExtraCollectionSharp/ExtraCollectionSharp.csproj b/ExtraCollectionSharp/ExtraCollectionSharp.csproj new file mode 100644 index 0000000..f208d30 --- /dev/null +++ b/ExtraCollectionSharp/ExtraCollectionSharp.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/ExtraCollectionSharp/LRUCache.cs b/ExtraCollectionSharp/LRUCache.cs new file mode 100644 index 0000000..e9bab3c --- /dev/null +++ b/ExtraCollectionSharp/LRUCache.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace ExtraCollectionSharp +{ +public class LRUCache : IEnumerable + { + private class Node + { + public K key; + public V value; + public Node front; + public Node back; + } + + public int Size {get { return size; } } + public int Count {get { return valueDictionary.Count; } } + private readonly int size; + private Node top; + private Node bottom; + private Dictionary valueDictionary; + private Action cleanupAction; + + public LRUCache(int size = 100, Action cleanup = null) + { + this.size = size; + valueDictionary = new Dictionary(size); + this.cleanupAction = cleanup; + } + + private void MoveToTop(K key) { + Node node = valueDictionary[key]; + if (node != null && top != node) { + node.front.back = node.back; + node.back = top; + node.front = null; + top = node; + } + } + + private Node AddToTop(K key, V value) { + Node node = new Node(); + node.front = null; + node.back = top; + node.value = value; + node.key = key; + top = node; + if (bottom == null) { + bottom = node; + } else if (valueDictionary.Count == Size) { + valueDictionary.Remove(bottom.key); + cleanupAction?.Invoke(bottom.value); + bottom = bottom.front; + } + valueDictionary[key] = node; + return node; + } + + public V Use(K key, Func generate) { + if (generate == null) throw new ArgumentNullException("generate"); + Node value = null; + if (valueDictionary.ContainsKey(key)) { + value = valueDictionary[key]; + MoveToTop(key); + } else { + value = AddToTop(key, generate()); + } + return value.value; + } + + public bool IsCached(K key) { + return valueDictionary.ContainsKey(key); + } + + public void Clear() { + top = null; + bottom = null; + valueDictionary.Clear(); + } + + public IEnumerator GetEnumerator() + { + foreach (Node node in valueDictionary.Values) + { + yield return node.value; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +}