1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
5 * This source code is subject to terms and conditions of the Microsoft Public License. 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 Microsoft Public License, 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 Microsoft Public License.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
19 using System; using Microsoft;
21 using System.Collections.Generic;
23 using System.Diagnostics;
26 namespace System.Dynamic.Utils {
28 namespace Microsoft.Scripting.Utils {
31 /// Provides a dictionary-like object used for caches which holds onto a maximum
32 /// number of elements specified at construction time.
34 /// This class is not thread safe.
36 internal class CacheDict<TKey, TValue> {
37 private readonly Dictionary<TKey, KeyInfo> _dict = new Dictionary<TKey, KeyInfo>();
38 private readonly LinkedList<TKey> _list = new LinkedList<TKey>();
39 private readonly int _maxSize;
42 /// Creates a dictionary-like object used for caches.
44 /// <param name="maxSize">The maximum number of elements to store.</param>
45 internal CacheDict(int maxSize) {
50 /// Tries to get the value associated with 'key', returning true if it's found and
51 /// false if it's not present.
53 internal bool TryGetValue(TKey key, out TValue value) {
55 if (_dict.TryGetValue(key, out storedValue)) {
56 LinkedListNode<TKey> node = storedValue.List;
57 if (node.Previous != null) {
58 // move us to the head of the list...
63 value = storedValue.Value;
67 value = default(TValue);
72 /// Adds a new element to the cache, replacing and moving it to the front if the
73 /// element is already present.
75 internal void Add(TKey key, TValue value) {
77 if (_dict.TryGetValue(key, out keyInfo)) {
78 // remove original entry from the linked list
79 _list.Remove(keyInfo.List);
80 } else if (_list.Count == _maxSize) {
81 // we've reached capacity, remove the last used element...
82 LinkedListNode<TKey> node = _list.Last;
84 bool res = _dict.Remove(node.Value);
88 // add the new entry to the head of the list and into the dictionary
89 LinkedListNode<TKey> listNode = new LinkedListNode<TKey>(key);
90 _list.AddFirst(listNode);
91 _dict[key] = new CacheDict<TKey, TValue>.KeyInfo(value, listNode);
95 /// Returns the value associated with the given key, or throws KeyNotFoundException
96 /// if the key is not present.
98 internal TValue this[TKey key] {
101 if (TryGetValue(key, out res)) {
104 throw new KeyNotFoundException();
111 private struct KeyInfo {
112 internal readonly TValue Value;
113 internal readonly LinkedListNode<TKey> List;
115 internal KeyInfo(TValue value, LinkedListNode<TKey> list) {