TupleSet.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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. */
  9. class TupleSet {
  10. /**
  11. * @param {Iterable<T>=} init init
  12. */
  13. constructor(init) {
  14. /** @type {Map<T, TODO>} */
  15. this._map = new Map();
  16. this.size = 0;
  17. if (init) {
  18. for (const tuple of init) {
  19. this.add(...tuple);
  20. }
  21. }
  22. }
  23. /**
  24. * @param {T} args tuple
  25. * @returns {void}
  26. */
  27. add(...args) {
  28. let map = this._map;
  29. for (let i = 0; i < args.length - 2; i++) {
  30. const arg = args[i];
  31. const innerMap = map.get(arg);
  32. if (innerMap === undefined) {
  33. map.set(arg, (map = new Map()));
  34. } else {
  35. map = innerMap;
  36. }
  37. }
  38. const beforeLast = args[args.length - 2];
  39. let set = map.get(beforeLast);
  40. if (set === undefined) {
  41. map.set(beforeLast, (set = new Set()));
  42. }
  43. const last = args[args.length - 1];
  44. this.size -= set.size;
  45. set.add(last);
  46. this.size += set.size;
  47. }
  48. /**
  49. * @param {T} args tuple
  50. * @returns {boolean} true, if the tuple is in the Set
  51. */
  52. has(...args) {
  53. let map = this._map;
  54. for (let i = 0; i < args.length - 2; i++) {
  55. const arg = args[i];
  56. map = map.get(arg);
  57. if (map === undefined) {
  58. return false;
  59. }
  60. }
  61. const beforeLast = args[args.length - 2];
  62. const set = map.get(beforeLast);
  63. if (set === undefined) {
  64. return false;
  65. }
  66. const last = args[args.length - 1];
  67. return set.has(last);
  68. }
  69. /**
  70. * @param {T} args tuple
  71. * @returns {void}
  72. */
  73. delete(...args) {
  74. let map = this._map;
  75. for (let i = 0; i < args.length - 2; i++) {
  76. const arg = args[i];
  77. map = map.get(arg);
  78. if (map === undefined) {
  79. return;
  80. }
  81. }
  82. const beforeLast = args[args.length - 2];
  83. const set = map.get(beforeLast);
  84. if (set === undefined) {
  85. return;
  86. }
  87. const last = args[args.length - 1];
  88. this.size -= set.size;
  89. set.delete(last);
  90. this.size += set.size;
  91. }
  92. /**
  93. * @returns {Iterator<T>} iterator
  94. */
  95. [Symbol.iterator]() {
  96. /** @type {TODO[]} */
  97. const iteratorStack = [];
  98. /** @type {T[]} */
  99. const tuple = [];
  100. /** @type {Iterator<T> | undefined} */
  101. let currentSetIterator;
  102. /**
  103. * @param {TODO} it iterator
  104. * @returns {boolean} result
  105. */
  106. const next = it => {
  107. const result = it.next();
  108. if (result.done) {
  109. if (iteratorStack.length === 0) return false;
  110. tuple.pop();
  111. return next(iteratorStack.pop());
  112. }
  113. const [key, value] = result.value;
  114. iteratorStack.push(it);
  115. tuple.push(key);
  116. if (value instanceof Set) {
  117. currentSetIterator = value[Symbol.iterator]();
  118. return true;
  119. }
  120. return next(value[Symbol.iterator]());
  121. };
  122. next(this._map[Symbol.iterator]());
  123. return {
  124. next() {
  125. while (currentSetIterator) {
  126. const result = currentSetIterator.next();
  127. if (result.done) {
  128. tuple.pop();
  129. if (!next(iteratorStack.pop())) {
  130. currentSetIterator = undefined;
  131. }
  132. } else {
  133. return {
  134. done: false,
  135. value: /** @type {T} */ (tuple.concat(result.value))
  136. };
  137. }
  138. }
  139. return { done: true, value: undefined };
  140. }
  141. };
  142. }
  143. }
  144. module.exports = TupleSet;