1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
4 namespace System.Runtime
6 using System.Collections.Generic;
8 class MruCache<TKey, TValue>
12 LinkedList<TKey> mruList;
13 Dictionary<TKey, CacheEntry> items;
18 public MruCache(int watermark)
19 : this(watermark * 4 / 5, watermark)
24 // The cache will grow until the high watermark. At which point, the least recently used items
25 // will be purge until the cache's size is reduced to low watermark
27 public MruCache(int lowWatermark, int highWatermark)
28 : this(lowWatermark, highWatermark, null)
32 public MruCache(int lowWatermark, int highWatermark, IEqualityComparer<TKey> comparer)
34 Fx.Assert(lowWatermark < highWatermark, "");
35 Fx.Assert(lowWatermark >= 0, "");
37 this.lowWatermark = lowWatermark;
38 this.highWatermark = highWatermark;
39 this.mruList = new LinkedList<TKey>();
42 this.items = new Dictionary<TKey, CacheEntry>();
46 this.items = new Dictionary<TKey, CacheEntry>(comparer);
54 return this.items.Count;
58 public void Add(TKey key, TValue value)
60 Fx.Assert(null != key, "");
62 // if anything goes wrong (duplicate entry, etc) we should
63 // clear our caches so that we don't get out of sync
67 if (this.items.Count == this.highWatermark)
69 // If the cache is full, purge enough LRU items to shrink the
70 // cache down to the low watermark
71 int countToPurge = this.highWatermark - this.lowWatermark;
72 for (int i = 0; i < countToPurge; i++)
74 TKey keyRemove = this.mruList.Last.Value;
75 this.mruList.RemoveLast();
76 TValue item = this.items[keyRemove].value;
77 this.items.Remove(keyRemove);
78 OnSingleItemRemoved(item);
79 OnItemAgedOutOfCache(item);
82 // Add the new entry to the cache and make it the MRU element
84 entry.node = this.mruList.AddFirst(key);
86 this.items.Add(key, entry);
87 this.mruEntry = entry;
101 this.mruList.Clear();
103 this.mruEntry.value = null;
104 this.mruEntry.node = null;
107 public bool Remove(TKey key)
109 Fx.Assert(null != key, "");
112 if (this.items.TryGetValue(key, out entry))
114 this.items.Remove(key);
115 OnSingleItemRemoved(entry.value);
116 this.mruList.Remove(entry.node);
117 if (object.ReferenceEquals(this.mruEntry.node, entry.node))
119 this.mruEntry.value = null;
120 this.mruEntry.node = null;
128 protected virtual void OnSingleItemRemoved(TValue item)
132 protected virtual void OnItemAgedOutOfCache(TValue item)
137 // If found, make the entry most recently used
139 public bool TryGetValue(TKey key, out TValue value)
141 // first check our MRU item
142 if (this.mruEntry.node != null && key != null && key.Equals(this.mruEntry.node.Value))
144 value = this.mruEntry.value;
150 bool found = this.items.TryGetValue(key, out entry);
153 // Move the node to the head of the MRU list if it's not already there
154 if (found && this.mruList.Count > 1
155 && !object.ReferenceEquals(this.mruList.First, entry.node))
157 this.mruList.Remove(entry.node);
158 this.mruList.AddFirst(entry.node);
159 this.mruEntry = entry;
167 internal TValue value;
168 internal LinkedListNode<TKey> node;