LRUCache.cs
1/*
2 UdgerParser - Local parser lib
3
4 UdgerParser class parses useragent strings based on a database downloaded from udger.com
5
6
7 author The Udger.com Team (info@udger.com)
8 copyright Copyright (c) Udger s.r.o.
9 license GNU Lesser General Public License
10 link https://udger.com/products/local_parser
11 */
12
13using System;
14using System.Collections.Generic;
15
16namespace Udger.Parser
17{
18 class LRUCache<TKey,TValue>
19 {
20 private readonly Dictionary<TKey, Node> entries;
21 private readonly int capacity;
22 private Node head;
23 private Node tail;
24
25 private class Node
26 {
27 public Node Next { get; set; }
28 public Node Previous { get; set; }
29 public TKey Key { get; set; }
30 public TValue Value { get; set; }
31 }
32
33 #region Constructor
34 public LRUCache(int capacity)
35 {
36 if (capacity <= 0)
37 throw new ArgumentOutOfRangeException(
38 "capacity",
39 "Capacity should be greater than zero");
40 this.capacity = capacity;
41 entries = new Dictionary<TKey, Node>();
42 head = null;
43 }
44 #endregion
45
46 #region public method
47 public void Set(TKey key, TValue value)
48 {
49 Node entry;
50 if (!entries.TryGetValue(key, out entry))
51 {
52 entry = new Node { Key = key, Value = value };
53 if (entries.Count == capacity)
54 {
55 entries.Remove(tail.Key);
56 tail = tail.Previous;
57 if (tail != null)
58 tail.Next = null;
59 }
60 entries.Add(key, entry);
61 }
62
63 entry.Value = value;
64 MoveToHead(entry);
65 if (tail == null)
66 tail = head;
67 }
68
69 public bool TryGetValue(TKey key, out TValue value)
70 {
71 value = default(TValue);
72 Node entry;
73 if (!entries.TryGetValue(key, out entry))
74 return false;
75
76 MoveToHead(entry);
77 value = entry.Value;
78
79 return true;
80 }
81 #endregion
82
83 #region private method
84 private void MoveToHead(Node entry)
85 {
86 if (entry == head || entry == null)
87 return;
88
89 var next = entry.Next;
90 var previous = entry.Previous;
91
92 if (next != null)
93 next.Previous = entry.Previous;
94
95 if (previous != null)
96 previous.Next = entry.Next;
97
98 entry.Previous = null;
99 entry.Next = head;
100
101 if (head != null)
102 head.Previous = entry;
103
104 head = entry;
105
106 if (tail == entry)
107 tail = previous;
108 }
109 #endregion
110 }
111}