cache.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /**
  2. * A doubly linked list-based Least Recently Used (LRU)
  3. * cache. Will keep most recently used items while
  4. * discarding least recently used items when its limit is
  5. * reached. This is a bare-bone version of
  6. * Rasmus Andersson's js-lru:
  7. *
  8. * https://github.com/rsms/js-lru
  9. *
  10. * @param {Number} limit
  11. * @constructor
  12. */
  13. function Cache (limit) {
  14. this.size = 0
  15. this.limit = limit
  16. this.head = this.tail = undefined
  17. this._keymap = Object.create(null)
  18. }
  19. var p = Cache.prototype
  20. /**
  21. * Put <value> into the cache associated with <key>.
  22. * Returns the entry which was removed to make room for
  23. * the new entry. Otherwise undefined is returned.
  24. * (i.e. if there was enough room already).
  25. *
  26. * @param {String} key
  27. * @param {*} value
  28. * @return {Entry|undefined}
  29. */
  30. p.put = function (key, value) {
  31. var entry = {
  32. key: key,
  33. value: value
  34. }
  35. this._keymap[key] = entry
  36. if (this.tail) {
  37. this.tail.newer = entry
  38. entry.older = this.tail
  39. } else {
  40. this.head = entry
  41. }
  42. this.tail = entry
  43. if (this.size === this.limit) {
  44. return this.shift()
  45. } else {
  46. this.size++
  47. }
  48. }
  49. /**
  50. * Purge the least recently used (oldest) entry from the
  51. * cache. Returns the removed entry or undefined if the
  52. * cache was empty.
  53. */
  54. p.shift = function () {
  55. var entry = this.head
  56. if (entry) {
  57. this.head = this.head.newer
  58. this.head.older = undefined
  59. entry.newer = entry.older = undefined
  60. this._keymap[entry.key] = undefined
  61. }
  62. return entry
  63. }
  64. /**
  65. * Get and register recent use of <key>. Returns the value
  66. * associated with <key> or undefined if not in cache.
  67. *
  68. * @param {String} key
  69. * @param {Boolean} returnEntry
  70. * @return {Entry|*}
  71. */
  72. p.get = function (key, returnEntry) {
  73. var entry = this._keymap[key]
  74. if (entry === undefined) return
  75. if (entry === this.tail) {
  76. return returnEntry
  77. ? entry
  78. : entry.value
  79. }
  80. // HEAD--------------TAIL
  81. // <.older .newer>
  82. // <--- add direction --
  83. // A B C <D> E
  84. if (entry.newer) {
  85. if (entry === this.head) {
  86. this.head = entry.newer
  87. }
  88. entry.newer.older = entry.older // C <-- E.
  89. }
  90. if (entry.older) {
  91. entry.older.newer = entry.newer // C. --> E
  92. }
  93. entry.newer = undefined // D --x
  94. entry.older = this.tail // D. --> E
  95. if (this.tail) {
  96. this.tail.newer = entry // E. <-- D
  97. }
  98. this.tail = entry
  99. return returnEntry
  100. ? entry
  101. : entry.value
  102. }
  103. module.exports = Cache