/Merlin/Main/Runtime/Microsoft.Dynamic/Utils/CacheDict.cs

https://github.com/shri/ironruby · C# · 114 lines · 63 code · 11 blank · 40 comment · 8 complexity · a096170512b887ca7a2af1e908f3ba00 MD5 · raw file

  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  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.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Text;
  18. using System.Diagnostics;
  19. namespace Microsoft.Scripting.Utils {
  20. /// <summary>
  21. /// Provides a dictionary-like object used for caches which holds onto a maximum
  22. /// number of elements specified at construction time.
  23. ///
  24. /// This class is not thread safe.
  25. /// </summary>
  26. public class CacheDict<TKey, TValue> {
  27. private readonly Dictionary<TKey, KeyInfo> _dict = new Dictionary<TKey, KeyInfo>();
  28. private readonly LinkedList<TKey> _list = new LinkedList<TKey>();
  29. private readonly int _maxSize;
  30. /// <summary>
  31. /// Creates a dictionary-like object used for caches.
  32. /// </summary>
  33. /// <param name="maxSize">The maximum number of elements to store.</param>
  34. public CacheDict(int maxSize) {
  35. _maxSize = maxSize;
  36. }
  37. /// <summary>
  38. /// Tries to get the value associated with 'key', returning true if it's found and
  39. /// false if it's not present.
  40. /// </summary>
  41. public bool TryGetValue(TKey key, out TValue value) {
  42. KeyInfo storedValue;
  43. if (_dict.TryGetValue(key, out storedValue)) {
  44. LinkedListNode<TKey> node = storedValue.List;
  45. if (node.Previous != null) {
  46. // move us to the head of the list...
  47. _list.Remove(node);
  48. _list.AddFirst(node);
  49. }
  50. value = storedValue.Value;
  51. return true;
  52. }
  53. value = default(TValue);
  54. return false;
  55. }
  56. /// <summary>
  57. /// Adds a new element to the cache, replacing and moving it to the front if the
  58. /// element is already present.
  59. /// </summary>
  60. public void Add(TKey key, TValue value) {
  61. KeyInfo keyInfo;
  62. if (_dict.TryGetValue(key, out keyInfo)) {
  63. // remove original entry from the linked list
  64. _list.Remove(keyInfo.List);
  65. } else if (_list.Count == _maxSize) {
  66. // we've reached capacity, remove the last used element...
  67. LinkedListNode<TKey> node = _list.Last;
  68. _list.RemoveLast();
  69. bool res = _dict.Remove(node.Value);
  70. Debug.Assert(res);
  71. }
  72. // add the new entry to the head of the list and into the dictionary
  73. LinkedListNode<TKey> listNode = new LinkedListNode<TKey>(key);
  74. _list.AddFirst(listNode);
  75. _dict[key] = new CacheDict<TKey, TValue>.KeyInfo(value, listNode);
  76. }
  77. /// <summary>
  78. /// Returns the value associated with the given key, or throws KeyNotFoundException
  79. /// if the key is not present.
  80. /// </summary>
  81. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")]
  82. public TValue this[TKey key] {
  83. get {
  84. TValue res;
  85. if (TryGetValue(key, out res)) {
  86. return res;
  87. }
  88. throw new KeyNotFoundException();
  89. }
  90. set {
  91. Add(key, value);
  92. }
  93. }
  94. private struct KeyInfo {
  95. internal readonly TValue Value;
  96. internal readonly LinkedListNode<TKey> List;
  97. internal KeyInfo(TValue value, LinkedListNode<TKey> list) {
  98. Value = value;
  99. List = list;
  100. }
  101. }
  102. }
  103. }