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

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

Fix frontend appearance

  • Property mode set to 100644
File size: 6.2 KB
Line 
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 * Strong-key child map used for tuple elements that cannot be stored in a
10 * `WeakMap`.
11 * @template {EXPECTED_ANY[]} T
12 * @template V
13 * @typedef {Map<EXPECTED_ANY, WeakTupleMap<T, V>>} M
14 */
15
16/**
17 * Weak-key child map used for tuple elements that are objects and can be held
18 * without preventing garbage collection.
19 * @template {EXPECTED_ANY[]} T
20 * @template V
21 * @typedef {WeakMap<EXPECTED_OBJECT, WeakTupleMap<T, V>>} W
22 */
23
24/**
25 * Reports whether a tuple element can be stored in a `WeakMap`.
26 * @param {EXPECTED_ANY} thing thing
27 * @returns {boolean} true if is weak
28 */
29const isWeakKey = (thing) => typeof thing === "object" && thing !== null;
30
31/**
32 * Extracts the element type from a tuple-like array.
33 * @template {unknown[]} T
34 * @typedef {T extends ReadonlyArray<infer ElementType> ? ElementType : never} ArrayElement
35 */
36
37/**
38 * Stores values by tuple keys while using `WeakMap` for object elements so the
39 * cache can release entries when those objects are collected.
40 * @template {EXPECTED_ANY[]} K
41 * @template V
42 */
43class WeakTupleMap {
44 /**
45 * Initializes an empty tuple trie node with optional value and child maps.
46 */
47 constructor() {
48 /** @private */
49 this.f = 0;
50 /**
51 * @private
52 * @type {V | undefined}
53 */
54 this.v = undefined;
55 /**
56 * @private
57 * @type {M<K, V> | undefined}
58 */
59 this.m = undefined;
60 /**
61 * @private
62 * @type {W<K, V> | undefined}
63 */
64 this.w = undefined;
65 }
66
67 /**
68 * Stores a value at the node identified by the provided tuple key.
69 * @param {[...K, V]} args tuple
70 * @returns {void}
71 */
72 set(...args) {
73 /** @type {WeakTupleMap<K, V>} */
74 let node = this;
75 for (let i = 0; i < args.length - 1; i++) {
76 node = node._get(/** @type {ArrayElement<K>} */ (args[i]));
77 }
78 node._setValue(/** @type {V} */ (args[args.length - 1]));
79 }
80
81 /**
82 * Checks whether the exact tuple key has a stored value.
83 * @param {K} args tuple
84 * @returns {boolean} true, if the tuple is in the Set
85 */
86 has(...args) {
87 /** @type {WeakTupleMap<K, V> | undefined} */
88 let node = this;
89 for (let i = 0; i < args.length; i++) {
90 node = node._peek(/** @type {ArrayElement<K>} */ (args[i]));
91 if (node === undefined) return false;
92 }
93 return node._hasValue();
94 }
95
96 /**
97 * Returns the value stored for the exact tuple key, if any.
98 * @param {K} args tuple
99 * @returns {V | undefined} the value
100 */
101 get(...args) {
102 /** @type {WeakTupleMap<K, V> | undefined} */
103 let node = this;
104 for (let i = 0; i < args.length; i++) {
105 node = node._peek(/** @type {ArrayElement<K>} */ (args[i]));
106 if (node === undefined) return;
107 }
108 return node._getValue();
109 }
110
111 /**
112 * Returns an existing value for the tuple or computes, stores, and returns a
113 * new one when the tuple is missing.
114 * @param {[...K, (...args: K) => V]} args tuple
115 * @returns {V} the value
116 */
117 provide(...args) {
118 /** @type {WeakTupleMap<K, V>} */
119 let node = this;
120 for (let i = 0; i < args.length - 1; i++) {
121 node = node._get(/** @type {ArrayElement<K>} */ (args[i]));
122 }
123 if (node._hasValue()) return /** @type {V} */ (node._getValue());
124 const fn = /** @type {(...args: K) => V} */ (args[args.length - 1]);
125 const newValue = fn(.../** @type {K} */ (args.slice(0, -1)));
126 node._setValue(newValue);
127 return newValue;
128 }
129
130 /**
131 * Removes the value stored for the tuple key without pruning the trie.
132 * @param {K} args tuple
133 * @returns {void}
134 */
135 delete(...args) {
136 /** @type {WeakTupleMap<K, V> | undefined} */
137 let node = this;
138 for (let i = 0; i < args.length; i++) {
139 node = node._peek(/** @type {ArrayElement<K>} */ (args[i]));
140 if (node === undefined) return;
141 }
142 node._deleteValue();
143 }
144
145 /**
146 * Clears the stored value and all strong and weak child maps from this node.
147 * @returns {void}
148 */
149 clear() {
150 this.f = 0;
151 this.v = undefined;
152 this.w = undefined;
153 this.m = undefined;
154 }
155
156 /**
157 * Returns the value stored directly on this trie node.
158 * @returns {V | undefined} stored value
159 */
160 _getValue() {
161 return this.v;
162 }
163
164 /**
165 * Reports whether this trie node currently stores a value.
166 * @returns {boolean} true when a value is present
167 */
168 _hasValue() {
169 return (this.f & 1) === 1;
170 }
171
172 /**
173 * Stores a value directly on this trie node.
174 * @param {V} v value
175 * @private
176 */
177 _setValue(v) {
178 this.f |= 1;
179 this.v = v;
180 }
181
182 /**
183 * Removes the value stored directly on this trie node.
184 */
185 _deleteValue() {
186 this.f &= 6;
187 this.v = undefined;
188 }
189
190 /**
191 * Returns the child node for a tuple element without creating one.
192 * @param {ArrayElement<K>} thing thing
193 * @returns {WeakTupleMap<K, V> | undefined} thing
194 * @private
195 */
196 _peek(thing) {
197 if (isWeakKey(thing)) {
198 if ((this.f & 4) !== 4) return;
199 return /** @type {WeakMap<ArrayElement<K>, WeakTupleMap<K, V>>} */ (
200 this.w
201 ).get(thing);
202 }
203 if ((this.f & 2) !== 2) return;
204 return /** @type {Map<ArrayElement<K>, WeakTupleMap<K, V>>} */ (this.m).get(
205 thing
206 );
207 }
208
209 /**
210 * Returns the child node for a tuple element, creating and storing it when
211 * necessary.
212 * @private
213 * @param {ArrayElement<K>} thing thing
214 * @returns {WeakTupleMap<K, V>} value
215 */
216 _get(thing) {
217 if (isWeakKey(thing)) {
218 if ((this.f & 4) !== 4) {
219 /** @type {W<K, V>} */
220 const newMap = new WeakMap();
221 this.f |= 4;
222 /** @type {WeakTupleMap<K, V>} */
223 const newNode = new WeakTupleMap();
224 (this.w = newMap).set(thing, newNode);
225 return newNode;
226 }
227 const entry = /** @type {W<K, V>} */ (this.w).get(thing);
228 if (entry !== undefined) {
229 return entry;
230 }
231 /** @type {WeakTupleMap<K, V>} */
232 const newNode = new WeakTupleMap();
233 /** @type {W<K, V>} */
234 (this.w).set(thing, newNode);
235 return newNode;
236 }
237 if ((this.f & 2) !== 2) {
238 /** @type {M<K, V>} */
239 const newMap = new Map();
240 this.f |= 2;
241 /** @type {WeakTupleMap<K, V>} */
242 const newNode = new WeakTupleMap();
243 (this.m = newMap).set(thing, newNode);
244 return newNode;
245 }
246 const entry =
247 /** @type {M<K, V>} */
248 (this.m).get(thing);
249 if (entry !== undefined) {
250 return entry;
251 }
252 /** @type {WeakTupleMap<K, V>} */
253 const newNode = new WeakTupleMap();
254 /** @type {M<K, V>} */
255 (this.m).set(thing, newNode);
256 return newNode;
257 }
258}
259
260module.exports = WeakTupleMap;
Note: See TracBrowser for help on using the repository browser.