WeakTupleMap.js 4.1 KB

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