LRU.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // Simple LRU cache use doubly linked list
  2. // @module zrender/core/LRU
  3. /**
  4. * Simple double linked list. Compared with array, it has O(1) remove operation.
  5. * @constructor
  6. */
  7. var LinkedList = function () {
  8. /**
  9. * @type {module:zrender/core/LRU~Entry}
  10. */
  11. this.head = null;
  12. /**
  13. * @type {module:zrender/core/LRU~Entry}
  14. */
  15. this.tail = null;
  16. this._len = 0;
  17. };
  18. var linkedListProto = LinkedList.prototype;
  19. /**
  20. * Insert a new value at the tail
  21. * @param {} val
  22. * @return {module:zrender/core/LRU~Entry}
  23. */
  24. linkedListProto.insert = function (val) {
  25. var entry = new Entry(val);
  26. this.insertEntry(entry);
  27. return entry;
  28. };
  29. /**
  30. * Insert an entry at the tail
  31. * @param {module:zrender/core/LRU~Entry} entry
  32. */
  33. linkedListProto.insertEntry = function (entry) {
  34. if (!this.head) {
  35. this.head = this.tail = entry;
  36. } else {
  37. this.tail.next = entry;
  38. entry.prev = this.tail;
  39. entry.next = null;
  40. this.tail = entry;
  41. }
  42. this._len++;
  43. };
  44. /**
  45. * Remove entry.
  46. * @param {module:zrender/core/LRU~Entry} entry
  47. */
  48. linkedListProto.remove = function (entry) {
  49. var prev = entry.prev;
  50. var next = entry.next;
  51. if (prev) {
  52. prev.next = next;
  53. } else {
  54. // Is head
  55. this.head = next;
  56. }
  57. if (next) {
  58. next.prev = prev;
  59. } else {
  60. // Is tail
  61. this.tail = prev;
  62. }
  63. entry.next = entry.prev = null;
  64. this._len--;
  65. };
  66. /**
  67. * @return {number}
  68. */
  69. linkedListProto.len = function () {
  70. return this._len;
  71. };
  72. /**
  73. * Clear list
  74. */
  75. linkedListProto.clear = function () {
  76. this.head = this.tail = null;
  77. this._len = 0;
  78. };
  79. /**
  80. * @constructor
  81. * @param {} val
  82. */
  83. var Entry = function (val) {
  84. /**
  85. * @type {}
  86. */
  87. this.value = val;
  88. /**
  89. * @type {module:zrender/core/LRU~Entry}
  90. */
  91. this.next;
  92. /**
  93. * @type {module:zrender/core/LRU~Entry}
  94. */
  95. this.prev;
  96. };
  97. /**
  98. * LRU Cache
  99. * @constructor
  100. * @alias module:zrender/core/LRU
  101. */
  102. var LRU = function (maxSize) {
  103. this._list = new LinkedList();
  104. this._map = {};
  105. this._maxSize = maxSize || 10;
  106. this._lastRemovedEntry = null;
  107. };
  108. var LRUProto = LRU.prototype;
  109. /**
  110. * @param {string} key
  111. * @param {} value
  112. * @return {} Removed value
  113. */
  114. LRUProto.put = function (key, value) {
  115. var list = this._list;
  116. var map = this._map;
  117. var removed = null;
  118. if (map[key] == null) {
  119. var len = list.len(); // Reuse last removed entry
  120. var entry = this._lastRemovedEntry;
  121. if (len >= this._maxSize && len > 0) {
  122. // Remove the least recently used
  123. var leastUsedEntry = list.head;
  124. list.remove(leastUsedEntry);
  125. delete map[leastUsedEntry.key];
  126. removed = leastUsedEntry.value;
  127. this._lastRemovedEntry = leastUsedEntry;
  128. }
  129. if (entry) {
  130. entry.value = value;
  131. } else {
  132. entry = new Entry(value);
  133. }
  134. entry.key = key;
  135. list.insertEntry(entry);
  136. map[key] = entry;
  137. }
  138. return removed;
  139. };
  140. /**
  141. * @param {string} key
  142. * @return {}
  143. */
  144. LRUProto.get = function (key) {
  145. var entry = this._map[key];
  146. var list = this._list;
  147. if (entry != null) {
  148. // Put the latest used entry in the tail
  149. if (entry !== list.tail) {
  150. list.remove(entry);
  151. list.insertEntry(entry);
  152. }
  153. return entry.value;
  154. }
  155. };
  156. /**
  157. * Clear the cache
  158. */
  159. LRUProto.clear = function () {
  160. this._list.clear();
  161. this._map = {};
  162. };
  163. var _default = LRU;
  164. module.exports = _default;