TupleSet.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. /**
  7. * Nested map structure used to index tuple prefixes until the final tuple
  8. * element can be stored in a `Set`.
  9. * @template K
  10. * @template V
  11. * @typedef {Map<K, InnerMap<K, V> | Set<V>>} InnerMap
  12. */
  13. /**
  14. * Stores tuples of arbitrary length while preserving efficient prefix lookups
  15. * through a tree of maps that ends in a set of final values.
  16. * @template T
  17. * @template V
  18. */
  19. class TupleSet {
  20. /**
  21. * Seeds the tuple set with an optional iterable of tuples.
  22. * @param {Iterable<[T, V, ...EXPECTED_ANY]>=} init init
  23. */
  24. constructor(init) {
  25. /** @type {InnerMap<T, V>} */
  26. this._map = new Map();
  27. /** @type {number} */
  28. this.size = 0;
  29. if (init) {
  30. for (const tuple of init) {
  31. this.add(...tuple);
  32. }
  33. }
  34. }
  35. /**
  36. * Adds a tuple to the set, creating any missing prefix maps along the way.
  37. * @param {[T, V, ...EXPECTED_ANY]} args tuple
  38. * @returns {void}
  39. */
  40. add(...args) {
  41. let map = this._map;
  42. for (let i = 0; i < args.length - 2; i++) {
  43. const arg = args[i];
  44. const innerMap = map.get(arg);
  45. if (innerMap === undefined) {
  46. map.set(arg, (map = new Map()));
  47. } else {
  48. map = /** @type {InnerMap<T, V>} */ (innerMap);
  49. }
  50. }
  51. const beforeLast = args[args.length - 2];
  52. let set = /** @type {Set<V>} */ (map.get(beforeLast));
  53. if (set === undefined) {
  54. map.set(beforeLast, (set = new Set()));
  55. }
  56. const last = args[args.length - 1];
  57. this.size -= set.size;
  58. set.add(last);
  59. this.size += set.size;
  60. }
  61. /**
  62. * Checks whether the exact tuple is already present in the set.
  63. * @param {[T, V, ...EXPECTED_ANY]} args tuple
  64. * @returns {boolean} true, if the tuple is in the Set
  65. */
  66. has(...args) {
  67. let map = this._map;
  68. for (let i = 0; i < args.length - 2; i++) {
  69. const arg = args[i];
  70. map = /** @type {InnerMap<T, V>} */ (map.get(arg));
  71. if (map === undefined) {
  72. return false;
  73. }
  74. }
  75. const beforeLast = args[args.length - 2];
  76. const set = map.get(beforeLast);
  77. if (set === undefined) {
  78. return false;
  79. }
  80. const last = args[args.length - 1];
  81. return set.has(last);
  82. }
  83. /**
  84. * Removes a tuple from the set when it is present.
  85. * @param {[T, V, ...EXPECTED_ANY]} args tuple
  86. * @returns {void}
  87. */
  88. delete(...args) {
  89. let map = this._map;
  90. for (let i = 0; i < args.length - 2; i++) {
  91. const arg = args[i];
  92. map = /** @type {InnerMap<T, V>} */ (map.get(arg));
  93. if (map === undefined) {
  94. return;
  95. }
  96. }
  97. const beforeLast = args[args.length - 2];
  98. const set = map.get(beforeLast);
  99. if (set === undefined) {
  100. return;
  101. }
  102. const last = args[args.length - 1];
  103. this.size -= set.size;
  104. set.delete(last);
  105. this.size += set.size;
  106. }
  107. /**
  108. * Iterates over every stored tuple by walking the nested map structure and
  109. * yielding each complete prefix plus its terminal set value.
  110. * @returns {Iterator<[T, V, ...EXPECTED_ANY]>} iterator
  111. */
  112. [Symbol.iterator]() {
  113. /**
  114. * Iterator type used while traversing nested tuple-prefix maps.
  115. * @template T, V
  116. * @typedef {MapIterator<[T, InnerMap<T, V> | Set<V>]>} IteratorStack
  117. */
  118. // This is difficult to type because we can have a map inside a map inside a map, etc. where the end is a set (each key is an argument)
  119. // But in basic use we only have 2 arguments in our methods, so we have `Map<K, Set<V>>`
  120. /** @type {IteratorStack<T, V>[]} */
  121. const iteratorStack = [];
  122. /** @type {[T?, V?, ...EXPECTED_ANY]} */
  123. const tuple = [];
  124. /** @type {SetIterator<V> | undefined} */
  125. let currentSetIterator;
  126. /**
  127. * Advances through nested maps until a terminal value set is reached or
  128. * every remaining branch has been exhausted.
  129. * @param {IteratorStack<T, V>} it iterator
  130. * @returns {boolean} result
  131. */
  132. const next = (it) => {
  133. const result = it.next();
  134. if (result.done) {
  135. if (iteratorStack.length === 0) return false;
  136. tuple.pop();
  137. return next(
  138. /** @type {IteratorStack<T, V>} */
  139. (iteratorStack.pop())
  140. );
  141. }
  142. const [key, value] = result.value;
  143. iteratorStack.push(it);
  144. tuple.push(key);
  145. if (value instanceof Set) {
  146. currentSetIterator = value[Symbol.iterator]();
  147. return true;
  148. }
  149. return next(value[Symbol.iterator]());
  150. };
  151. next(this._map[Symbol.iterator]());
  152. return {
  153. next() {
  154. while (currentSetIterator) {
  155. const result = currentSetIterator.next();
  156. if (result.done) {
  157. tuple.pop();
  158. if (
  159. !next(
  160. /** @type {IteratorStack<T, V>} */
  161. (iteratorStack.pop())
  162. )
  163. ) {
  164. currentSetIterator = undefined;
  165. }
  166. } else {
  167. return {
  168. done: false,
  169. value:
  170. /* eslint-disable unicorn/prefer-spread */
  171. /** @type {[T, V, ...EXPECTED_ANY]} */
  172. (tuple.concat(result.value))
  173. };
  174. }
  175. }
  176. return { done: true, value: undefined };
  177. }
  178. };
  179. }
  180. }
  181. module.exports = TupleSet;