Merge pull request #4033 from ntherning/no-stdcall-for-icalls-on-windows-32-bit
[mono.git] / mcs / class / System.Web / System.Web.Configuration_2.0 / LruCache.cs
1 //
2 // A simple LRU cache
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@gnome.org)
6 //   Andres G. Aragoneses (andres@7digital.com)
7 //
8 // Copyright 2010 Miguel de Icaza
9 // Copyright 2013 7digital Media Ltd.
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28 //
29
30 using System;
31 using System.Collections.Generic;
32
33 namespace System.Web.Configuration {
34
35         class LruCache<TKey, TValue> {
36                 Dictionary<TKey, LinkedListNode <TValue>> dict;
37                 Dictionary<LinkedListNode<TValue>, TKey> revdict;
38                 LinkedList<TValue> list;
39                 int entry_limit;
40
41                 bool eviction_warning_shown;
42                 int evictions;
43
44                 internal string EvictionWarning { set; private get; }
45
46                 public LruCache (int entryLimit)
47                 {
48                         entry_limit = entryLimit;
49                         dict = new Dictionary<TKey, LinkedListNode<TValue>> ();
50                         revdict = new Dictionary<LinkedListNode<TValue>, TKey> ();
51                         list = new LinkedList<TValue> ();
52                 }
53
54                 //for debugging: public int Count { get { return dict.Count; } }
55
56                 void Evict ()
57                 {
58                         var last = list.Last;
59                         if (last == null)
60                                 return;
61
62                         var key = revdict [last];
63
64                         dict.Remove (key);
65                         revdict.Remove (last);
66                         list.RemoveLast ();
67                         DisposeValue (last.Value);
68                         evictions++;
69
70                         if (!String.IsNullOrEmpty (EvictionWarning) && !eviction_warning_shown && (evictions >= entry_limit)) {
71                                 Console.Error.WriteLine ("WARNING: " + EvictionWarning);
72                                 eviction_warning_shown = true;
73                         }
74                 }
75
76                 public void Clear ()
77                 {
78                         foreach (var element in list) {
79                                 DisposeValue (element);
80                         }
81
82                         dict.Clear ();
83                         revdict.Clear ();
84                         list.Clear ();
85                         eviction_warning_shown = false;
86                         evictions = 0;
87                 }
88
89                 void DisposeValue (TValue value)
90                 {
91                         if (value is IDisposable) {
92                                 ((IDisposable)value).Dispose ();
93                         }
94                 }
95
96                 public bool TryGetValue (TKey key, out TValue value)
97                 {
98                         LinkedListNode<TValue> node;
99
100                         if (dict.TryGetValue (key, out node)){
101                                 list.Remove (node);
102                                 list.AddFirst (node);
103
104                                 value = node.Value;
105                                 return true;
106                         }
107                         value = default (TValue);
108                         return false;
109                 }
110
111                 public void Add (TKey key, TValue value)
112                 {
113                         LinkedListNode<TValue> node;
114
115                         if (dict.TryGetValue (key, out node)){
116
117                                 // If we already have a key, move it to the front
118                                 list.Remove (node);
119                                 list.AddFirst (node);
120
121                                 // Remove the old value
122                                 DisposeValue (node.Value);
123
124                                 node.Value = value;
125                                 return;
126                         }
127
128                         if (dict.Count >= entry_limit)
129                                 Evict ();
130
131                         // Adding new node
132                         node = new LinkedListNode<TValue> (value);
133                         list.AddFirst (node);
134                         dict [key] = node;
135                         revdict [node] = key;
136                 }
137
138                 public override string ToString ()
139                 {
140                         return "LRUCache dict={0} revdict={1} list={2}";
141                 }
142         }
143 }