Guest User

Untitled

a guest
May 23rd, 2018
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.08 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. namespace UndauntedTK.Utility
  4. {
  5.     public class LFUCache<TKey, TValue>
  6.     {
  7.         private readonly int _agePolicy;
  8.  
  9.         private readonly Dictionary<TKey, LinkedListNode<CacheNode>> _cache =
  10.             new Dictionary<TKey, LinkedListNode<CacheNode>>();
  11.  
  12.         private readonly LinkedList<CacheNode> _lfuList = new LinkedList<CacheNode>();
  13.  
  14.         private readonly int _size;
  15.         private int _age;
  16.  
  17.         public LFUCache(int size)
  18.             : this(size, 1000)
  19.         {
  20.         }
  21.  
  22.  
  23.         /// <summary>
  24.         ///
  25.         /// </summary>
  26.         /// <param name="size"></param>
  27.         /// <param name="agePolicy">after this number of gets the cache will take 1 off all UseCounts, forcing old stuff to expire.</param>
  28.         public LFUCache(int size, int agePolicy)
  29.         {
  30.             _agePolicy = agePolicy;
  31.             _size = size;
  32.         }
  33.  
  34.         private IEnumerable<LinkedListNode<CacheNode>> Nodes
  35.         {
  36.             get
  37.             {
  38.                 LinkedListNode<CacheNode> node = _lfuList.First;
  39.                 while (node != null)
  40.                 {
  41.                     yield return node;
  42.                     node = node.Next;
  43.                 }
  44.             }
  45.         }
  46.  
  47.         private void Remove(TKey key)
  48.         {
  49.             _lfuList.Remove(_cache[key]);
  50.             _cache.Remove(key);
  51.         }
  52.  
  53.         public void Add(TKey key, TValue val)
  54.         {
  55.             TValue existing;
  56.             if (!TryGet(key, out existing))
  57.             {
  58.                 var node = new CacheNode { Key = key, Data = val, UseCount = 1 };
  59.                 if (_lfuList.Count == _size)
  60.                 {
  61.                     _cache.Remove(_lfuList.First.Value.Key);
  62.                     _lfuList.RemoveFirst();
  63.                 }
  64.  
  65.                 LinkedListNode<CacheNode> insertionPoint = Nodes.LastOrDefault(n => n.Value.UseCount < 2);
  66.  
  67.                 LinkedListNode<CacheNode> inserted;
  68.  
  69.                 inserted = insertionPoint == null ? _lfuList.AddFirst(node) : _lfuList.AddAfter(insertionPoint, node);
  70.                 _cache[key] = inserted;
  71.             }
  72.             else
  73.             {
  74.                 Remove(key);
  75.                 Add(key, val);
  76.             }
  77.         }
  78.  
  79.         private static IEnumerable<LinkedListNode<CacheNode>> IterateFrom(LinkedListNode<CacheNode> node)
  80.         {
  81.             while (node != null)
  82.             {
  83.                 yield return node;
  84.                 node = node.Next;
  85.             }
  86.         }
  87.  
  88.         public TValue GetOrDefault(TKey key)
  89.         {
  90.             TValue val;
  91.             TryGet(key, out val);
  92.             return val;
  93.         }
  94.  
  95.         public bool TryGet(TKey key, out TValue val)
  96.         {
  97.             _age++;
  98.             if (_age > _agePolicy)
  99.             {
  100.                 _age = 0;
  101.                 foreach (var node in _cache.Values)
  102.                 {
  103.                     CacheNode v = node.Value;
  104.                     v.UseCount--;
  105.                 }
  106.             }
  107.  
  108.             LinkedListNode<CacheNode> data;
  109.             bool success = false;
  110.  
  111.             if (_cache.TryGetValue(key, out data))
  112.             {
  113.                 CacheNode cacheNode = data.Value;
  114.                 val = cacheNode.Data;
  115.                 cacheNode.UseCount++;
  116.                 success = true;
  117.                 LinkedListNode<CacheNode> insertionPoint =
  118.                     IterateFrom(data).Last(n => n.Value.UseCount <= cacheNode.UseCount);
  119.  
  120.                 if (insertionPoint != data)
  121.                 {
  122.                     _lfuList.Remove(data);
  123.                     _lfuList.AddAfter(insertionPoint, data);
  124.                 }
  125.             }
  126.             else
  127.             {
  128.                 val = default(TValue);
  129.             }
  130.  
  131.             return success;
  132.         }
  133.  
  134.         #region Nested type: CacheNode
  135.  
  136.         private class CacheNode
  137.         {
  138.             public TKey Key { get; set; }
  139.             public TValue Data { get; set; }
  140.             public int UseCount { get; set; }
  141.         }
  142.  
  143.         #endregion
  144.     }
  145. }
Add Comment
Please, Sign In to add comment