TupleSet.js 2.8 KB

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