WeakTupleMap.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. /**
  7. * @template {EXPECTED_ANY[]} T
  8. * @template V
  9. * @typedef {Map<EXPECTED_ANY, WeakTupleMap<T, V>>} M
  10. */
  11. /**
  12. * @template {EXPECTED_ANY[]} T
  13. * @template V
  14. * @typedef {WeakMap<EXPECTED_OBJECT, WeakTupleMap<T, V>>} W
  15. */
  16. /**
  17. * @param {EXPECTED_ANY} thing thing
  18. * @returns {boolean} true if is weak
  19. */
  20. const isWeakKey = thing => typeof thing === "object" && thing !== null;
  21. /**
  22. * @template {unknown[]} T
  23. * @typedef {T extends readonly (infer ElementType)[] ? ElementType : never} ArrayElement
  24. */
  25. /**
  26. * @template {EXPECTED_ANY[]} K
  27. * @template V
  28. */
  29. class WeakTupleMap {
  30. constructor() {
  31. /** @private */
  32. this.f = 0;
  33. /**
  34. * @private
  35. * @type {V | undefined}
  36. */
  37. this.v = undefined;
  38. /**
  39. * @private
  40. * @type {M<K, V> | undefined}
  41. */
  42. this.m = undefined;
  43. /**
  44. * @private
  45. * @type {W<K, V> | undefined}
  46. */
  47. this.w = undefined;
  48. }
  49. /**
  50. * @param {[...K, V]} args tuple
  51. * @returns {void}
  52. */
  53. set(...args) {
  54. /** @type {WeakTupleMap<K, V>} */
  55. let node = this;
  56. for (let i = 0; i < args.length - 1; i++) {
  57. node = node._get(/** @type {ArrayElement<K>} */ (args[i]));
  58. }
  59. node._setValue(/** @type {V} */ (args[args.length - 1]));
  60. }
  61. /**
  62. * @param {K} args tuple
  63. * @returns {boolean} true, if the tuple is in the Set
  64. */
  65. has(...args) {
  66. /** @type {WeakTupleMap<K, V> | undefined} */
  67. let node = this;
  68. for (let i = 0; i < args.length; i++) {
  69. node = node._peek(/** @type {ArrayElement<K>} */ (args[i]));
  70. if (node === undefined) return false;
  71. }
  72. return node._hasValue();
  73. }
  74. /**
  75. * @param {K} args tuple
  76. * @returns {V | undefined} the value
  77. */
  78. get(...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;
  84. }
  85. return node._getValue();
  86. }
  87. /**
  88. * @param {[...K, (...args: K) => V]} args tuple
  89. * @returns {V} the value
  90. */
  91. provide(...args) {
  92. /** @type {WeakTupleMap<K, V>} */
  93. let node = this;
  94. for (let i = 0; i < args.length - 1; i++) {
  95. node = node._get(/** @type {ArrayElement<K>} */ (args[i]));
  96. }
  97. if (node._hasValue()) return /** @type {V} */ (node._getValue());
  98. const fn = /** @type {(...args: K) => V} */ (args[args.length - 1]);
  99. const newValue = fn(.../** @type {K} */ (args.slice(0, -1)));
  100. node._setValue(newValue);
  101. return newValue;
  102. }
  103. /**
  104. * @param {K} args tuple
  105. * @returns {void}
  106. */
  107. delete(...args) {
  108. /** @type {WeakTupleMap<K, V> | undefined} */
  109. let node = this;
  110. for (let i = 0; i < args.length; i++) {
  111. node = node._peek(/** @type {ArrayElement<K>} */ (args[i]));
  112. if (node === undefined) return;
  113. }
  114. node._deleteValue();
  115. }
  116. /**
  117. * @returns {void}
  118. */
  119. clear() {
  120. this.f = 0;
  121. this.v = undefined;
  122. this.w = undefined;
  123. this.m = undefined;
  124. }
  125. _getValue() {
  126. return this.v;
  127. }
  128. _hasValue() {
  129. return (this.f & 1) === 1;
  130. }
  131. /**
  132. * @param {V} v value
  133. * @private
  134. */
  135. _setValue(v) {
  136. this.f |= 1;
  137. this.v = v;
  138. }
  139. _deleteValue() {
  140. this.f &= 6;
  141. this.v = undefined;
  142. }
  143. /**
  144. * @param {ArrayElement<K>} thing thing
  145. * @returns {WeakTupleMap<K, V> | undefined} thing
  146. * @private
  147. */
  148. _peek(thing) {
  149. if (isWeakKey(thing)) {
  150. if ((this.f & 4) !== 4) return;
  151. return /** @type {WeakMap<ArrayElement<K>, WeakTupleMap<K, V>>} */ (
  152. this.w
  153. ).get(thing);
  154. }
  155. if ((this.f & 2) !== 2) return;
  156. return /** @type {Map<ArrayElement<K>, WeakTupleMap<K, V>>} */ (this.m).get(
  157. thing
  158. );
  159. }
  160. /**
  161. * @private
  162. * @param {ArrayElement<K>} thing thing
  163. * @returns {WeakTupleMap<K, V>} value
  164. */
  165. _get(thing) {
  166. if (isWeakKey(thing)) {
  167. if ((this.f & 4) !== 4) {
  168. /** @type {W<K, V>} */
  169. const newMap = new WeakMap();
  170. this.f |= 4;
  171. /** @type {WeakTupleMap<K, V>} */
  172. const newNode = new WeakTupleMap();
  173. (this.w = newMap).set(thing, newNode);
  174. return newNode;
  175. }
  176. const entry = /** @type {W<K, V>} */ (this.w).get(thing);
  177. if (entry !== undefined) {
  178. return entry;
  179. }
  180. /** @type {WeakTupleMap<K, V>} */
  181. const newNode = new WeakTupleMap();
  182. /** @type {W<K, V>} */
  183. (this.w).set(thing, newNode);
  184. return newNode;
  185. }
  186. if ((this.f & 2) !== 2) {
  187. /** @type {M<K, V>} */
  188. const newMap = new Map();
  189. this.f |= 2;
  190. /** @type {WeakTupleMap<K, V>} */
  191. const newNode = new WeakTupleMap();
  192. (this.m = newMap).set(thing, newNode);
  193. return newNode;
  194. }
  195. const entry =
  196. /** @type {M<K, V>} */
  197. (this.m).get(thing);
  198. if (entry !== undefined) {
  199. return entry;
  200. }
  201. /** @type {WeakTupleMap<K, V>} */
  202. const newNode = new WeakTupleMap();
  203. /** @type {M<K, V>} */
  204. (this.m).set(thing, newNode);
  205. return newNode;
  206. }
  207. }
  208. module.exports = WeakTupleMap;