source: frontend/node_modules/webpack/lib/util/TupleSet.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 13 days ago

Fix frontend appearance

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