You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123 lines
2.0 KiB

2 years ago
  1. 'use strict';
  2. class QuickLRU {
  3. constructor(options = {}) {
  4. if (!(options.maxSize && options.maxSize > 0)) {
  5. throw new TypeError('`maxSize` must be a number greater than 0');
  6. }
  7. this.maxSize = options.maxSize;
  8. this.onEviction = options.onEviction;
  9. this.cache = new Map();
  10. this.oldCache = new Map();
  11. this._size = 0;
  12. }
  13. _set(key, value) {
  14. this.cache.set(key, value);
  15. this._size++;
  16. if (this._size >= this.maxSize) {
  17. this._size = 0;
  18. if (typeof this.onEviction === 'function') {
  19. for (const [key, value] of this.oldCache.entries()) {
  20. this.onEviction(key, value);
  21. }
  22. }
  23. this.oldCache = this.cache;
  24. this.cache = new Map();
  25. }
  26. }
  27. get(key) {
  28. if (this.cache.has(key)) {
  29. return this.cache.get(key);
  30. }
  31. if (this.oldCache.has(key)) {
  32. const value = this.oldCache.get(key);
  33. this.oldCache.delete(key);
  34. this._set(key, value);
  35. return value;
  36. }
  37. }
  38. set(key, value) {
  39. if (this.cache.has(key)) {
  40. this.cache.set(key, value);
  41. } else {
  42. this._set(key, value);
  43. }
  44. return this;
  45. }
  46. has(key) {
  47. return this.cache.has(key) || this.oldCache.has(key);
  48. }
  49. peek(key) {
  50. if (this.cache.has(key)) {
  51. return this.cache.get(key);
  52. }
  53. if (this.oldCache.has(key)) {
  54. return this.oldCache.get(key);
  55. }
  56. }
  57. delete(key) {
  58. const deleted = this.cache.delete(key);
  59. if (deleted) {
  60. this._size--;
  61. }
  62. return this.oldCache.delete(key) || deleted;
  63. }
  64. clear() {
  65. this.cache.clear();
  66. this.oldCache.clear();
  67. this._size = 0;
  68. }
  69. * keys() {
  70. for (const [key] of this) {
  71. yield key;
  72. }
  73. }
  74. * values() {
  75. for (const [, value] of this) {
  76. yield value;
  77. }
  78. }
  79. * [Symbol.iterator]() {
  80. for (const item of this.cache) {
  81. yield item;
  82. }
  83. for (const item of this.oldCache) {
  84. const [key] = item;
  85. if (!this.cache.has(key)) {
  86. yield item;
  87. }
  88. }
  89. }
  90. get size() {
  91. let oldCacheSize = 0;
  92. for (const key of this.oldCache.keys()) {
  93. if (!this.cache.has(key)) {
  94. oldCacheSize++;
  95. }
  96. }
  97. return Math.min(this._size + oldCacheSize, this.maxSize);
  98. }
  99. }
  100. module.exports = QuickLRU;