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