/// <summary> /// Looks for a value for the matching <paramref name="key"/>. If not found, /// calls <paramref name="valueGenerator"/> to retrieve the value and add it to /// the cache. /// </summary> /// <param name="key"> /// The key of the value to look up. /// </param> /// <param name="valueGenerator"> /// Generates a value if one isn't found. /// </param> /// <returns> /// The requested value. /// </returns> public TValue Get(TKey key, Func <TValue> valueGenerator) { lock (this.cacheMap) { LinkedListNode <LRUNode> node; TValue value; if (this.cacheMap.TryGetValue(key, out node)) { value = node.Value.Value; this.lruList.Remove(node); this.lruList.AddLast(node); } else { value = valueGenerator(); if (this.cacheMap.Count >= this.Capacity) { this.RemoveFirst(); } LRUNode cacheItem = new LRUNode(key, value); node = new LinkedListNode <LRUNode>(cacheItem); this.lruList.AddLast(node); this.cacheMap.Add(key, node); } return(value); } }
public void Put(int key, int value) { if (_capacity == 0) { return; } if (_cache.TryGetValue(key, out var node)) { RemoveNode(node); AddToHead(node); node.Value = value; } else { if (_capacity == _cache.Count) { node = PopTail(); _cache.Remove(node.Key); } node = new LRUNode { Key = key, Value = value }; _cache[key] = node; AddToHead(node); } }
public int Get(int key) { if (!map.ContainsKey(key)) return -1; LRUNode node = map[key]; doubleLinkedList.RemoveNode(node); doubleLinkedList.AddToTop(node); return node.Value; }
public LRUNode RemoveLRUNode() { LRUNode target = Tail.Previous; RemoveNode(target); return(target); }
public LRUDoubleLinkedList() { Head = new LRUNode(); Tail = new LRUNode(); Head.Next = Tail; Tail.Previous = Head; }
public void RemoveNode(LRUNode node) { node.Previous.Next = node.Next; node.Next.Previous = node.Previous; node.Next = null; node.Previous = null; }
public void AddToTop(LRUNode node) { node.Next = Head.Next; Head.Next.Previous = node; node.Previous = Head; Head.Next = node; }
private void AddToHead(LRUNode node) { _head.Next.Prev = node; node.Next = _head.Next; node.Prev = _head; _head.Next = node; }
public void Add(int key, int value) { // just need to update value and move it to the top if (map.ContainsKey(key)) { LRUNode node = map[key]; doubleLinkedList.RemoveNode(node); node.Value = value; doubleLinkedList.AddToTop(node); } else { // if cache is full, then remove the least recently used node if (count == capacity) { LRUNode lru = doubleLinkedList.RemoveLRUNode(); map.Remove(lru.Key); count--; } // add a new node LRUNode node = new LRUNode(key, value); doubleLinkedList.AddToTop(node); map[key] = node; count++; } }
public TValue this[TKey key] { get { LRUNode node = FindNode(key) ?? throw new KeyNotFoundException(); return(node.Value); } set => AddOrSet(key, value);
public LRULinkedMap(int capacity, IEqualityComparer <TKey> comparer) { m_Buckets = new LRUNode[HashUtility.GetPrimeCapacity(capacity)]; m_Comparer = comparer ?? EqualityComparer <TKey> .Default; m_Count = 0; m_Version = 0; m_Head = null; m_Tail = null; m_FreeList = null; }
/// <summary> /// Retrieves the key within the cache if contained. /// </summary> /// <param name="key"></param> /// <returns></returns> public V get(K key) { if (map.ContainsKey(key)) { LRUNode node = map[key]; remove(node); add(node); return(node.value); } return(default(V)); }
public override string ToString() { StringBuilder sb = new StringBuilder(); LRUNode iter = head; while (iter != null) { sb.Append("[" + iter.value.ToString() + "]"); iter = iter.next; } return(sb.ToString()); }
public void Add(K key, V val) { while (total >= capacity) { remove(); } LRUNode cacheItem = new LRUNode(key, val); LinkedListNode <LRUNode> node = new LinkedListNode <LRUNode>(cacheItem); lruList.AddLast(node); cacheMap.Add(key, node); total += ItemCount(val); }
/// <summary> /// Retrieves the given value at the given index in the list /// </summary> /// <param name="index"></param> /// <returns></returns> public V get(int index) { if (index > map.Count) { return(default(V)); } LRUNode iter = head; while (iter != null && index > 0) { iter = iter.next; index--; } return(iter.value); }
/// <summary> /// Adds the specified key and value to the dictionary. /// </summary> /// <param name="key"> /// The key of the element to add. /// </param> /// <param name="value"> /// The value of the element to add. The value can be null for reference types. /// </param> public void Add(TKey key, TValue value) { lock (this.cacheMap) { if (this.cacheMap.Count >= this.Capacity) { this.RemoveFirst(); } LRUNode cacheItem = new LRUNode(key, value); LinkedListNode <LRUNode> node = new LinkedListNode <LRUNode>(cacheItem); this.lruList.AddLast(node); this.cacheMap.Add(key, node); } }
// Sets the head of the cache private void add(LRUNode node) { if (head == null || tail == null) { head = node; tail = node; map.Add(node.key, node); } else { node.previous = null; node.next = head; head.previous = node; head = node; map.Add(node.key, node); } }
public void Set(K key, V value) { if (itemMap.TryGetValue(key, out LRUNode <K, V> existingNode)) { LRUNode <K, V> node = existingNode; node.value = value; if (existingNode == head) { return; } else if (existingNode == tail) { node = EvictTail(key, value); } else { node.prev.next = node.next; node.next.prev = node.prev; } Promote(node); } else if (Size == 0) { LRUNode <K, V> headNode = new LRUNode <K, V>(key, value); head = tail = headNode; itemMap.TryAdd(key, headNode); Size++; } else if (Size == Capacity) { itemMap.TryRemove(tail.key, out LRUNode <K, V> _); LRUNode <K, V> oldTail = EvictTail(key, value); Promote(oldTail); itemMap.TryAdd(key, oldTail); } else { LRUNode <K, V> node = new LRUNode <K, V>(key, value); itemMap.TryAdd(key, node); Size++; Promote(node); } }
public void Get_ShouldTakeANonLeafNode_AndPromoteIt_When_Called() { subject.Set(1, 10); subject.Set(2, 20); subject.Set(3, 30); subject.Set(4, 40); subject.Get(2); LoadInternalPointers(); int[] expectedItemOrder = { 20, 40, 30, 10 }; int index = 0; LRUNode <int, int> node = head; while (node != null) { Assert.Equal(expectedItemOrder[index++], node.value); node = node.next; } }
public void Set_ShouldEnsureProperOrdering_Even_When_WeAreOverCapacity() { int[] items = { 10, 50, 40, 30, 5, 10, 20, 44, 25, 29, 90, 84, 33, 22, 5 }; int[] expectedItemOrder = items.Reverse().Distinct().Take(PreferredCapacity).ToArray(); foreach (int item in items) { subject.Set(item, item); } LoadInternalPointers(); int index = 0; LRUNode <int, int> node = head; while (node != null) { Assert.Equal(expectedItemOrder[index++], node.value); node = node.next; } }
public void Put(int key, int value) { if (map.ContainsKey(key)) { LRUNode node = map[key]; doubleLinkedList.RemoveNode(node); node.Value = value; doubleLinkedList.AddToTop(node); } else { if (count==capacity) { LRUNode lru = doubleLinkedList.RemoveLRUNode(); map.Remove(lru.Key); count--; } LRUNode node = new LRUNode(key, value); doubleLinkedList.AddToTop(node); map[key] = node; count++; } }
/// <summary> /// Adds the key value pair to the cache, returns true if key is precent in the cache /// and returns false if there is no mapping and the key was to be inserted /// false if the /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public bool put(K key, V value) { if (map.ContainsKey(key)) { LRUNode old = map[key]; old.value = value; remove(old); add(old); return(true); } else { // if adding one would put it over limit, dont add if (map.Count + 1 > limit) { remove(tail); } if (map.Count < limit) { add(new LRUNode(key, value)); } return(false); } }
public void Set_ShouldAddItemsAsTheyArrive_And_PromoteAsNecessary_When_Called() { int[] items = new int[] { 10, 20, 5, 6, 10, 60 }; foreach (int item in items) { subject.Set(item, item); } LoadInternalPointers(); int[] expectedItemOrder = new int[] { 60, 10, 6, 5, 20 }; int index = 0; Assert.Equal(expectedItemOrder.Length, itemMap.Count); LRUNode <int, int> node = head; while (node != null) { Assert.Equal(expectedItemOrder[index++], node.value); node = node.next; } }
// removes all references of the given node within private void remove(LRUNode node) { if (node == null) { return; } if (node.previous != null) { node.previous.next = node.next; } if (node.next != null) { node.next.previous = node.previous; } if (node == tail) { tail = tail.previous; } if (node == head) { head = head.next; } map.Remove(node.key); }
private void LoadInternalPointers() { itemMap = TestHelper.Helper.GetFieldValueFromInstance <ConcurrentDictionary <int, LRUNode <int, int> > >("itemMap", false, false, subject); head = TestHelper.Helper.GetFieldValueFromInstance <LRUNode <int, int> >("head", false, false, subject); tail = TestHelper.Helper.GetFieldValueFromInstance <LRUNode <int, int> >("tail", false, false, subject); }
private void RemoveNode(LRUNode node) { node.Prev.Next = node.Next; node.Next.Prev = node.Prev; }