StackedCacheMap.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. /**
  7. * @template K
  8. * @template V
  9. */
  10. class StackedCacheMap {
  11. constructor() {
  12. /** @type {Map<K, V>} */
  13. this.map = new Map();
  14. /** @type {ReadonlyMap<K, V>[]} */
  15. this.stack = [];
  16. }
  17. /**
  18. * @param {ReadonlyMap<K, V>} map map to add
  19. * @param {boolean} immutable if 'map' is immutable and StackedCacheMap can keep referencing it
  20. */
  21. addAll(map, immutable) {
  22. if (immutable) {
  23. this.stack.push(map);
  24. // largest map should go first
  25. for (let i = this.stack.length - 1; i > 0; i--) {
  26. const beforeLast = this.stack[i - 1];
  27. if (beforeLast.size >= map.size) break;
  28. this.stack[i] = beforeLast;
  29. this.stack[i - 1] = map;
  30. }
  31. } else {
  32. for (const [key, value] of map) {
  33. this.map.set(key, value);
  34. }
  35. }
  36. }
  37. /**
  38. * @param {K} item the key of the element to add
  39. * @param {V} value the value of the element to add
  40. * @returns {void}
  41. */
  42. set(item, value) {
  43. this.map.set(item, value);
  44. }
  45. /**
  46. * @param {K} item the item to delete
  47. * @returns {void}
  48. */
  49. delete(item) {
  50. throw new Error("Items can't be deleted from a StackedCacheMap");
  51. }
  52. /**
  53. * @param {K} item the item to test
  54. * @returns {boolean} true if the item exists in this set
  55. */
  56. has(item) {
  57. throw new Error(
  58. "Checking StackedCacheMap.has before reading is inefficient, use StackedCacheMap.get and check for undefined"
  59. );
  60. }
  61. /**
  62. * @param {K} item the key of the element to return
  63. * @returns {V} the value of the element
  64. */
  65. get(item) {
  66. for (const map of this.stack) {
  67. const value = map.get(item);
  68. if (value !== undefined) return value;
  69. }
  70. return this.map.get(item);
  71. }
  72. clear() {
  73. this.stack.length = 0;
  74. this.map.clear();
  75. }
  76. get size() {
  77. let size = this.map.size;
  78. for (const map of this.stack) {
  79. size += map.size;
  80. }
  81. return size;
  82. }
  83. [Symbol.iterator]() {
  84. const iterators = this.stack.map(map => map[Symbol.iterator]());
  85. let current = this.map[Symbol.iterator]();
  86. return {
  87. next() {
  88. let result = current.next();
  89. while (result.done && iterators.length > 0) {
  90. current = iterators.pop();
  91. result = current.next();
  92. }
  93. return result;
  94. }
  95. };
  96. }
  97. }
  98. module.exports = StackedCacheMap;