UNPKG

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