| 
									
										
										
										
											2021-04-13 23:33:05 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							|  |  |  | 		/** @private @type {any} */ | 
					
						
							|  |  |  | 		this.v = undefined; | 
					
						
							|  |  |  | 		/** @private @type {Map<object, WeakTupleMap<T, V>> | undefined} */ | 
					
						
							|  |  |  | 		this.m = undefined; | 
					
						
							|  |  |  | 		/** @private @type {WeakMap<object, WeakTupleMap<T, V>> | undefined} */ | 
					
						
							|  |  |  | 		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) { | 
					
						
							| 
									
										
										
										
											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; 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 | 
					
						
							|  |  |  | 	 * @returns {V} the value | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	get(...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; 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) { | 
					
						
							| 
									
										
										
										
											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; 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; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_setValue(v) { | 
					
						
							|  |  |  | 		this.f |= 1; | 
					
						
							|  |  |  | 		this.v = v; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_deleteValue() { | 
					
						
							|  |  |  | 		this.f &= 6; | 
					
						
							|  |  |  | 		this.v = undefined; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_peek(thing) { | 
					
						
							|  |  |  | 		if (isWeakKey(thing)) { | 
					
						
							|  |  |  | 			if ((this.f & 4) !== 4) return undefined; | 
					
						
							|  |  |  | 			return this.w.get(thing); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			if ((this.f & 2) !== 2) return undefined; | 
					
						
							|  |  |  | 			return this.m.get(thing); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_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 = this.w.get(thing); | 
					
						
							|  |  |  | 			if (entry !== undefined) { | 
					
						
							|  |  |  | 				return entry; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			const newNode = new WeakTupleMap(); | 
					
						
							|  |  |  | 			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 = this.m.get(thing); | 
					
						
							|  |  |  | 			if (entry !== undefined) { | 
					
						
							|  |  |  | 				return entry; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			const newNode = new WeakTupleMap(); | 
					
						
							|  |  |  | 			this.m.set(thing, newNode); | 
					
						
							|  |  |  | 			return newNode; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-04-13 23:33:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = WeakTupleMap; |