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