WeakTupleMap.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. /**
  7. * Strong-key child map used for tuple elements that cannot be stored in a
  8. * `WeakMap`.
  9. * @template {EXPECTED_ANY[]} T
  10. * @template V
  11. * @typedef {Map<EXPECTED_ANY, WeakTupleMap<T, V>>} M
  12. */
  13. /**
  14. * Weak-key child map used for tuple elements that are objects and can be held
  15. * without preventing garbage collection.
  16. * @template {EXPECTED_ANY[]} T
  17. * @template V
  18. * @typedef {WeakMap<EXPECTED_OBJECT, WeakTupleMap<T, V>>} W
  19. */
  20. /**
  21. * Reports whether a tuple element can be stored in a `WeakMap`.
  22. * @param {EXPECTED_ANY} thing thing
  23. * @returns {boolean} true if is weak
  24. */
  25. const isWeakKey = (thing) => typeof thing === "object" && thing !== null;
  26. /**
  27. * Extracts the element type from a tuple-like array.
  28. * @template {unknown[]} T
  29. * @typedef {T extends ReadonlyArray<infer ElementType> ? ElementType : never} ArrayElement
  30. */
  31. /**
  32. * Stores values by tuple keys while using `WeakMap` for object elements so the
  33. * cache can release entries when those objects are collected.
  34. * @template {EXPECTED_ANY[]} K
  35. * @template V
  36. */
  37. class WeakTupleMap {
  38. /**
  39. * Initializes an empty tuple trie node with optional value and child maps.
  40. */
  41. constructor() {
  42. /** @private */
  43. this.f = 0;
  44. /**
  45. * @private
  46. * @type {V | undefined}
  47. */
  48. this.v = undefined;
  49. /**
  50. * @private
  51. * @type {M<K, V> | undefined}
  52. */
  53. this.m = undefined;
  54. /**
  55. * @private
  56. * @type {W<K, V> | undefined}
  57. */
  58. this.w = undefined;
  59. }
  60. /**
  61. * Stores a value at the node identified by the provided tuple key.
  62. * @param {[...K, V]} args tuple
  63. * @returns {void}
  64. */
  65. set(...args) {
  66. /** @type {WeakTupleMap<K, V>} */
  67. let node = this;
  68. for (let i = 0; i < args.length - 1; i++) {
  69. node = node._get(/** @type {ArrayElement<K>} */ (args[i]));
  70. }
  71. node._setValue(/** @type {V} */ (args[args.length - 1]));
  72. }
  73. /**
  74. * Checks whether the exact tuple key has a stored value.
  75. * @param {K} args tuple
  76. * @returns {boolean} true, if the tuple is in the Set
  77. */
  78. has(...args) {
  79. /** @type {WeakTupleMap<K, V> | undefined} */
  80. let node = this;
  81. for (let i = 0; i < args.length; i++) {
  82. node = node._peek(/** @type {ArrayElement<K>} */ (args[i]));
  83. if (node === undefined) return false;
  84. }
  85. return node._hasValue();
  86. }
  87. /**
  88. * Returns the value stored for the exact tuple key, if any.
  89. * @param {K} args tuple
  90. * @returns {V | undefined} the value
  91. */
  92. get(...args) {
  93. /** @type {WeakTupleMap<K, V> | undefined} */
  94. let node = this;
  95. for (let i = 0; i < args.length; i++) {
  96. node = node._peek(/** @type {ArrayElement<K>} */ (args[i]));
  97. if (node === undefined) return;
  98. }
  99. return node._getValue();
  100. }
  101. /**
  102. * Returns an existing value for the tuple or computes, stores, and returns a
  103. * new one when the tuple is missing.
  104. * @param {[...K, (...args: K) => V]} args tuple
  105. * @returns {V} the value
  106. */
  107. provide(...args) {
  108. /** @type {WeakTupleMap<K, V>} */
  109. let node = this;
  110. for (let i = 0; i < args.length - 1; i++) {
  111. node = node._get(/** @type {ArrayElement<K>} */ (args[i]));
  112. }
  113. if (node._hasValue()) return /** @type {V} */ (node._getValue());
  114. const fn = /** @type {(...args: K) => V} */ (args[args.length - 1]);
  115. const newValue = fn(.../** @type {K} */ (args.slice(0, -1)));
  116. node._setValue(newValue);
  117. return newValue;
  118. }
  119. /**
  120. * Removes the value stored for the tuple key without pruning the trie.
  121. * @param {K} args tuple
  122. * @returns {void}
  123. */
  124. delete(...args) {
  125. /** @type {WeakTupleMap<K, V> | undefined} */
  126. let node = this;
  127. for (let i = 0; i < args.length; i++) {
  128. node = node._peek(/** @type {ArrayElement<K>} */ (args[i]));
  129. if (node === undefined) return;
  130. }
  131. node._deleteValue();
  132. }
  133. /**
  134. * Clears the stored value and all strong and weak child maps from this node.
  135. * @returns {void}
  136. */
  137. clear() {
  138. this.f = 0;
  139. this.v = undefined;
  140. this.w = undefined;
  141. this.m = undefined;
  142. }
  143. /**
  144. * Returns the value stored directly on this trie node.
  145. * @returns {V | undefined} stored value
  146. */
  147. _getValue() {
  148. return this.v;
  149. }
  150. /**
  151. * Reports whether this trie node currently stores a value.
  152. * @returns {boolean} true when a value is present
  153. */
  154. _hasValue() {
  155. return (this.f & 1) === 1;
  156. }
  157. /**
  158. * Stores a value directly on this trie node.
  159. * @param {V} v value
  160. * @private
  161. */
  162. _setValue(v) {
  163. this.f |= 1;
  164. this.v = v;
  165. }
  166. /**
  167. * Removes the value stored directly on this trie node.
  168. */
  169. _deleteValue() {
  170. this.f &= 6;
  171. this.v = undefined;
  172. }
  173. /**
  174. * Returns the child node for a tuple element without creating one.
  175. * @param {ArrayElement<K>} thing thing
  176. * @returns {WeakTupleMap<K, V> | undefined} thing
  177. * @private
  178. */
  179. _peek(thing) {
  180. if (isWeakKey(thing)) {
  181. if ((this.f & 4) !== 4) return;
  182. return /** @type {WeakMap<ArrayElement<K>, WeakTupleMap<K, V>>} */ (
  183. this.w
  184. ).get(thing);
  185. }
  186. if ((this.f & 2) !== 2) return;
  187. return /** @type {Map<ArrayElement<K>, WeakTupleMap<K, V>>} */ (this.m).get(
  188. thing
  189. );
  190. }
  191. /**
  192. * Returns the child node for a tuple element, creating and storing it when
  193. * necessary.
  194. * @private
  195. * @param {ArrayElement<K>} thing thing
  196. * @returns {WeakTupleMap<K, V>} value
  197. */
  198. _get(thing) {
  199. if (isWeakKey(thing)) {
  200. if ((this.f & 4) !== 4) {
  201. /** @type {W<K, V>} */
  202. const newMap = new WeakMap();
  203. this.f |= 4;
  204. /** @type {WeakTupleMap<K, V>} */
  205. const newNode = new WeakTupleMap();
  206. (this.w = newMap).set(thing, newNode);
  207. return newNode;
  208. }
  209. const entry = /** @type {W<K, V>} */ (this.w).get(thing);
  210. if (entry !== undefined) {
  211. return entry;
  212. }
  213. /** @type {WeakTupleMap<K, V>} */
  214. const newNode = new WeakTupleMap();
  215. /** @type {W<K, V>} */
  216. (this.w).set(thing, newNode);
  217. return newNode;
  218. }
  219. if ((this.f & 2) !== 2) {
  220. /** @type {M<K, V>} */
  221. const newMap = new Map();
  222. this.f |= 2;
  223. /** @type {WeakTupleMap<K, V>} */
  224. const newNode = new WeakTupleMap();
  225. (this.m = newMap).set(thing, newNode);
  226. return newNode;
  227. }
  228. const entry =
  229. /** @type {M<K, V>} */
  230. (this.m).get(thing);
  231. if (entry !== undefined) {
  232. return entry;
  233. }
  234. /** @type {WeakTupleMap<K, V>} */
  235. const newNode = new WeakTupleMap();
  236. /** @type {M<K, V>} */
  237. (this.m).set(thing, newNode);
  238. return newNode;
  239. }
  240. }
  241. module.exports = WeakTupleMap;