Fix XMM scanning on Mac x86.
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Utils / CacheDict.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
6  * copy of the license can be found in the License.html file at the root of this distribution. If 
7  * you cannot locate the  Apache License, Version 2.0, please send an email to 
8  * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
9  * by the terms of the Apache License, Version 2.0.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15
16 using System;
17 using System.Collections.Generic;
18 using System.Text;
19 using System.Diagnostics;
20
21 namespace System.Dynamic.Utils {
22     /// <summary>
23     /// Provides a dictionary-like object used for caches which holds onto a maximum
24     /// number of elements specified at construction time.
25     /// 
26     /// This class is not thread safe.
27     /// </summary>
28     internal class CacheDict<TKey, TValue> {
29         private readonly Dictionary<TKey, KeyInfo> _dict = new Dictionary<TKey, KeyInfo>();
30         private readonly LinkedList<TKey> _list = new LinkedList<TKey>();
31         private readonly int _maxSize;
32
33         /// <summary>
34         /// Creates a dictionary-like object used for caches.
35         /// </summary>
36         /// <param name="maxSize">The maximum number of elements to store.</param>
37         internal CacheDict(int maxSize) {
38             _maxSize = maxSize;
39         }
40
41         /// <summary>
42         /// Tries to get the value associated with 'key', returning true if it's found and
43         /// false if it's not present.
44         /// </summary>
45         internal bool TryGetValue(TKey key, out TValue value) {
46             KeyInfo storedValue;
47             if (_dict.TryGetValue(key, out storedValue)) {
48                 LinkedListNode<TKey> node = storedValue.List;
49                 if (node.Previous != null) {
50                     // move us to the head of the list...
51                     _list.Remove(node);
52                     _list.AddFirst(node);
53                 }
54
55                 value = storedValue.Value;
56                 return true;
57             }
58
59             value = default(TValue);
60             return false;
61         }
62
63         /// <summary>
64         /// Adds a new element to the cache, replacing and moving it to the front if the
65         /// element is already present.
66         /// </summary>
67         internal void Add(TKey key, TValue value) {
68             KeyInfo keyInfo;
69             if (_dict.TryGetValue(key, out keyInfo)) {
70                 // remove original entry from the linked list
71                 _list.Remove(keyInfo.List);
72             } else if (_list.Count == _maxSize) {
73                 // we've reached capacity, remove the last used element...
74                 LinkedListNode<TKey> node = _list.Last;
75                 _list.RemoveLast();
76                 bool res = _dict.Remove(node.Value);
77                 Debug.Assert(res);
78             }
79
80             // add the new entry to the head of the list and into the dictionary
81             LinkedListNode<TKey> listNode = new LinkedListNode<TKey>(key);
82             _list.AddFirst(listNode);
83             _dict[key] = new CacheDict<TKey, TValue>.KeyInfo(value, listNode);
84         }
85
86         /// <summary>
87         /// Returns the value associated with the given key, or throws KeyNotFoundException
88         /// if the key is not present.
89         /// </summary>
90         internal TValue this[TKey key] {
91             get {
92                 TValue res;
93                 if (TryGetValue(key, out res)) {
94                     return res;
95                 }
96                 throw new KeyNotFoundException();
97             }
98             set {
99                 Add(key, value);
100             }
101         }
102
103         private struct KeyInfo {
104             internal readonly TValue Value;
105             internal readonly LinkedListNode<TKey> List;
106
107             internal KeyInfo(TValue value, LinkedListNode<TKey> list) {
108                 Value = value;
109                 List = list;
110             }
111         }
112     }
113 }