webpack/lib/util/WeakTupleMap.js

228 lines
4.7 KiB
JavaScript
Raw Normal View History

/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
2024-02-22 22:20:17 +08:00
/**
2025-04-16 22:04:11 +08:00
* @template {EXPECTED_ANY[]} T
2024-02-22 22:20:17 +08:00
* @template V
2025-04-16 22:04:11 +08:00
* @typedef {Map<EXPECTED_ANY, WeakTupleMap<T, V>>} M
2024-02-22 22:20:17 +08:00
*/
2025-04-04 21:38:51 +08:00
2024-02-22 22:20:17 +08:00
/**
2025-04-16 22:04:11 +08:00
* @template {EXPECTED_ANY[]} T
2024-02-22 22:20:17 +08:00
* @template V
2025-04-16 22:04:11 +08:00
* @typedef {WeakMap<EXPECTED_OBJECT, WeakTupleMap<T, V>>} W
2024-02-22 22:20:17 +08:00
*/
/**
2025-03-07 21:12:22 +08:00
* @param {EXPECTED_ANY} thing thing
2024-02-22 22:20:17 +08:00
* @returns {boolean} true if is weak
*/
const isWeakKey = (thing) => typeof thing === "object" && thing !== null;
/**
2025-04-16 22:04:11 +08:00
* @template {unknown[]} T
2025-09-10 19:38:19 +08:00
* @typedef {T extends ReadonlyArray<infer ElementType> ? ElementType : never} ArrayElement
2025-04-16 22:04:11 +08:00
*/
/**
* @template {EXPECTED_ANY[]} K
* @template V
*/
class WeakTupleMap {
constructor() {
2021-09-27 22:31:42 +08:00
/** @private */
this.f = 0;
2024-02-22 22:20:17 +08:00
/**
* @private
* @type {V | undefined}
2024-06-11 20:32:02 +08:00
*/
2021-09-27 22:31:42 +08:00
this.v = undefined;
2024-02-22 22:20:17 +08:00
/**
* @private
2025-04-16 22:04:11 +08:00
* @type {M<K, V> | undefined}
2024-06-11 20:32:02 +08:00
*/
2021-09-27 22:31:42 +08:00
this.m = undefined;
2024-02-22 22:20:17 +08:00
/**
* @private
2025-04-16 22:04:11 +08:00
* @type {W<K, V> | undefined}
2024-06-11 20:32:02 +08:00
*/
2021-09-27 22:31:42 +08:00
this.w = undefined;
}
/**
2025-04-16 22:04:11 +08:00
* @param {[...K, V]} args tuple
* @returns {void}
*/
set(...args) {
2025-04-16 22:04:11 +08:00
/** @type {WeakTupleMap<K, V>} */
2021-09-27 22:31:42 +08:00
let node = this;
for (let i = 0; i < args.length - 1; i++) {
2025-04-16 22:04:11 +08:00
node = node._get(/** @type {ArrayElement<K>} */ (args[i]));
}
2025-04-16 22:04:11 +08:00
node._setValue(/** @type {V} */ (args[args.length - 1]));
}
/**
2025-04-16 22:04:11 +08:00
* @param {K} args tuple
* @returns {boolean} true, if the tuple is in the Set
*/
has(...args) {
2025-04-16 22:04:11 +08:00
/** @type {WeakTupleMap<K, V> | undefined} */
2021-09-27 22:31:42 +08:00
let node = this;
for (let i = 0; i < args.length; i++) {
2025-04-16 22:04:11 +08:00
node = node._peek(/** @type {ArrayElement<K>} */ (args[i]));
if (node === undefined) return false;
}
2021-09-27 22:31:42 +08:00
return node._hasValue();
}
/**
2025-04-16 22:04:11 +08:00
* @param {K} args tuple
2024-02-22 22:20:17 +08:00
* @returns {V | undefined} the value
*/
get(...args) {
2025-04-16 22:04:11 +08:00
/** @type {WeakTupleMap<K, V> | undefined} */
2021-09-27 22:31:42 +08:00
let node = this;
for (let i = 0; i < args.length; i++) {
2025-04-16 22:04:11 +08:00
node = node._peek(/** @type {ArrayElement<K>} */ (args[i]));
2024-08-02 02:36:27 +08:00
if (node === undefined) return;
}
2021-09-27 22:31:42 +08:00
return node._getValue();
}
/**
2025-04-16 22:04:11 +08:00
* @param {[...K, (...args: K) => V]} args tuple
* @returns {V} the value
*/
provide(...args) {
2025-04-16 22:04:11 +08:00
/** @type {WeakTupleMap<K, V>} */
2021-09-27 22:31:42 +08:00
let node = this;
for (let i = 0; i < args.length - 1; i++) {
2025-04-16 22:04:11 +08:00
node = node._get(/** @type {ArrayElement<K>} */ (args[i]));
}
if (node._hasValue()) return /** @type {V} */ (node._getValue());
2025-04-16 22:04:11 +08:00
const fn = /** @type {(...args: K) => V} */ (args[args.length - 1]);
const newValue = fn(.../** @type {K} */ (args.slice(0, -1)));
2021-09-27 22:31:42 +08:00
node._setValue(newValue);
return newValue;
}
/**
2025-04-16 22:04:11 +08:00
* @param {K} args tuple
* @returns {void}
*/
delete(...args) {
2025-04-16 22:04:11 +08:00
/** @type {WeakTupleMap<K, V> | undefined} */
2021-09-27 22:31:42 +08:00
let node = this;
for (let i = 0; i < args.length; i++) {
2025-04-16 22:04:11 +08:00
node = node._peek(/** @type {ArrayElement<K>} */ (args[i]));
if (node === undefined) return;
}
2021-09-27 22:31:42 +08:00
node._deleteValue();
}
/**
* @returns {void}
*/
clear() {
2021-09-27 22:31:42 +08:00
this.f = 0;
this.v = undefined;
this.w = undefined;
this.m = undefined;
}
_getValue() {
return this.v;
}
_hasValue() {
return (this.f & 1) === 1;
}
2024-02-22 22:20:17 +08:00
/**
* @param {V} v value
2024-02-22 22:20:17 +08:00
* @private
*/
2021-09-27 22:31:42 +08:00
_setValue(v) {
this.f |= 1;
this.v = v;
}
_deleteValue() {
this.f &= 6;
this.v = undefined;
}
2024-02-22 22:20:17 +08:00
/**
2025-04-16 22:04:11 +08:00
* @param {ArrayElement<K>} thing thing
* @returns {WeakTupleMap<K, V> | undefined} thing
2024-02-22 22:20:17 +08:00
* @private
*/
2021-09-27 22:31:42 +08:00
_peek(thing) {
if (isWeakKey(thing)) {
2024-08-02 02:36:27 +08:00
if ((this.f & 4) !== 4) return;
2025-04-16 22:04:11 +08:00
return /** @type {WeakMap<ArrayElement<K>, WeakTupleMap<K, V>>} */ (
this.w
).get(thing);
2021-09-27 22:31:42 +08:00
}
2024-08-02 02:36:27 +08:00
if ((this.f & 2) !== 2) return;
2025-04-16 22:04:11 +08:00
return /** @type {Map<ArrayElement<K>, WeakTupleMap<K, V>>} */ (this.m).get(
thing
);
2021-09-27 22:31:42 +08:00
}
2024-02-22 22:20:17 +08:00
/**
* @private
2025-04-16 22:04:11 +08:00
* @param {ArrayElement<K>} thing thing
* @returns {WeakTupleMap<K, V>} value
2024-02-22 22:20:17 +08:00
*/
2021-09-27 22:31:42 +08:00
_get(thing) {
if (isWeakKey(thing)) {
if ((this.f & 4) !== 4) {
2025-04-16 22:04:11 +08:00
/** @type {W<K, V>} */
2021-09-27 22:31:42 +08:00
const newMap = new WeakMap();
this.f |= 4;
2025-04-16 22:04:11 +08:00
/** @type {WeakTupleMap<K, V>} */
2021-09-27 22:31:42 +08:00
const newNode = new WeakTupleMap();
(this.w = newMap).set(thing, newNode);
return newNode;
}
2025-04-16 22:04:11 +08:00
const entry = /** @type {W<K, V>} */ (this.w).get(thing);
2021-09-27 22:31:42 +08:00
if (entry !== undefined) {
return entry;
}
2025-04-16 22:04:11 +08:00
/** @type {WeakTupleMap<K, V>} */
2021-09-27 22:31:42 +08:00
const newNode = new WeakTupleMap();
2025-04-16 22:04:11 +08:00
/** @type {W<K, V>} */
2024-02-22 22:20:17 +08:00
(this.w).set(thing, newNode);
2021-09-27 22:31:42 +08:00
return newNode;
2024-07-31 04:21:27 +08:00
}
if ((this.f & 2) !== 2) {
2025-04-16 22:04:11 +08:00
/** @type {M<K, V>} */
2024-07-31 04:21:27 +08:00
const newMap = new Map();
this.f |= 2;
2025-04-16 22:04:11 +08:00
/** @type {WeakTupleMap<K, V>} */
2021-09-27 22:31:42 +08:00
const newNode = new WeakTupleMap();
2024-07-31 04:21:27 +08:00
(this.m = newMap).set(thing, newNode);
2021-09-27 22:31:42 +08:00
return newNode;
}
2024-07-31 04:21:27 +08:00
const entry =
2025-04-16 22:04:11 +08:00
/** @type {M<K, V>} */
2024-07-31 04:21:27 +08:00
(this.m).get(thing);
if (entry !== undefined) {
return entry;
}
2025-04-16 22:04:11 +08:00
/** @type {WeakTupleMap<K, V>} */
2024-07-31 04:21:27 +08:00
const newNode = new WeakTupleMap();
2025-04-16 22:04:11 +08:00
/** @type {M<K, V>} */
2024-07-31 04:21:27 +08:00
(this.m).set(thing, newNode);
return newNode;
}
}
module.exports = WeakTupleMap;