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