| 
									
										
										
										
											2021-07-16 19:05:18 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-24 22:43:58 +08:00
										 |  |  | new Map().entries(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-16 19:05:18 +08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2023-06-22 00:09:01 +08:00
										 |  |  |  * The StackedCacheMap is a data structure designed as an alternative to a Map | 
					
						
							|  |  |  |  * in situations where you need to handle multiple item additions and | 
					
						
							|  |  |  |  * frequently access the largest map. | 
					
						
							| 
									
										
										
										
											2023-06-21 23:57:19 +08:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2023-06-22 00:09:01 +08:00
										 |  |  |  * It is particularly optimized for efficiently adding multiple items | 
					
						
							|  |  |  |  * at once, which can be achieved using the `addAll` method. | 
					
						
							| 
									
										
										
										
											2023-06-21 23:57:19 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * It has a fallback Map that is used when the map to be added is mutable. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2023-06-22 00:09:01 +08:00
										 |  |  |  * Note: `delete` and `has` are not supported for performance reasons. | 
					
						
							| 
									
										
										
										
											2023-06-22 00:05:39 +08:00
										 |  |  |  * @example | 
					
						
							|  |  |  |  * ```js
 | 
					
						
							|  |  |  |  * const map = new StackedCacheMap(); | 
					
						
							|  |  |  |  * map.addAll(new Map([["a", 1], ["b", 2]]), true); | 
					
						
							|  |  |  |  * map.addAll(new Map([["c", 3], ["d", 4]]), true); | 
					
						
							|  |  |  |  * map.get("a"); // 1
 | 
					
						
							|  |  |  |  * map.get("d"); // 4
 | 
					
						
							|  |  |  |  * for (const [key, value] of map) { | 
					
						
							|  |  |  |  * 		console.log(key, value); | 
					
						
							|  |  |  |  * } | 
					
						
							|  |  |  |  * ```
 | 
					
						
							| 
									
										
										
										
											2024-07-30 21:48:58 +08:00
										 |  |  |  * @template K | 
					
						
							|  |  |  |  * @template V | 
					
						
							| 
									
										
										
										
											2021-07-16 19:05:18 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | class StackedCacheMap { | 
					
						
							|  |  |  | 	constructor() { | 
					
						
							|  |  |  | 		/** @type {Map<K, V>} */ | 
					
						
							|  |  |  | 		this.map = new Map(); | 
					
						
							|  |  |  | 		/** @type {ReadonlyMap<K, V>[]} */ | 
					
						
							|  |  |  | 		this.stack = []; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2023-06-21 23:57:19 +08:00
										 |  |  | 	 * If `immutable` is true, the map can be referenced by the StackedCacheMap | 
					
						
							|  |  |  | 	 * and should not be changed afterwards. If the map is mutable, all items | 
					
						
							|  |  |  | 	 * are copied into a fallback Map. | 
					
						
							| 
									
										
										
										
											2021-07-16 19:05:18 +08:00
										 |  |  | 	 * @param {ReadonlyMap<K, V>} map map to add | 
					
						
							| 
									
										
										
										
											2023-06-22 05:55:05 +08:00
										 |  |  | 	 * @param {boolean=} immutable if 'map' is immutable and StackedCacheMap can keep referencing it | 
					
						
							| 
									
										
										
										
											2021-07-16 19:05:18 +08:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	addAll(map, immutable) { | 
					
						
							|  |  |  | 		if (immutable) { | 
					
						
							|  |  |  | 			this.stack.push(map); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// largest map should go first
 | 
					
						
							|  |  |  | 			for (let i = this.stack.length - 1; i > 0; i--) { | 
					
						
							|  |  |  | 				const beforeLast = this.stack[i - 1]; | 
					
						
							|  |  |  | 				if (beforeLast.size >= map.size) break; | 
					
						
							|  |  |  | 				this.stack[i] = beforeLast; | 
					
						
							|  |  |  | 				this.stack[i - 1] = map; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			for (const [key, value] of map) { | 
					
						
							|  |  |  | 				this.map.set(key, value); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {K} item the key of the element to add | 
					
						
							|  |  |  | 	 * @param {V} value the value of the element to add | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	set(item, value) { | 
					
						
							|  |  |  | 		this.map.set(item, value); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {K} item the item to delete | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	delete(item) { | 
					
						
							|  |  |  | 		throw new Error("Items can't be deleted from a StackedCacheMap"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {K} item the item to test | 
					
						
							|  |  |  | 	 * @returns {boolean} true if the item exists in this set | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	has(item) { | 
					
						
							|  |  |  | 		throw new Error( | 
					
						
							|  |  |  | 			"Checking StackedCacheMap.has before reading is inefficient, use StackedCacheMap.get and check for undefined" | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {K} item the key of the element to return | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 	 * @returns {V | undefined} the value of the element | 
					
						
							| 
									
										
										
										
											2021-07-16 19:05:18 +08:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	get(item) { | 
					
						
							|  |  |  | 		for (const map of this.stack) { | 
					
						
							|  |  |  | 			const value = map.get(item); | 
					
						
							|  |  |  | 			if (value !== undefined) return value; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return this.map.get(item); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-16 19:07:56 +08:00
										 |  |  | 	clear() { | 
					
						
							|  |  |  | 		this.stack.length = 0; | 
					
						
							|  |  |  | 		this.map.clear(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-01 04:51:59 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @returns {number} size of the map | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2021-07-16 19:05:18 +08:00
										 |  |  | 	get size() { | 
					
						
							|  |  |  | 		let size = this.map.size; | 
					
						
							|  |  |  | 		for (const map of this.stack) { | 
					
						
							|  |  |  | 			size += map.size; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return size; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-01 04:51:59 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @returns {Iterator<[K, V]>} iterator | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2021-07-16 19:05:18 +08:00
										 |  |  | 	[Symbol.iterator]() { | 
					
						
							|  |  |  | 		const iterators = this.stack.map(map => map[Symbol.iterator]()); | 
					
						
							|  |  |  | 		let current = this.map[Symbol.iterator](); | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			next() { | 
					
						
							|  |  |  | 				let result = current.next(); | 
					
						
							|  |  |  | 				while (result.done && iterators.length > 0) { | 
					
						
							| 
									
										
										
										
											2025-06-24 22:43:58 +08:00
										 |  |  | 					current = /** @type {MapIterator<[K, V]>} */ (iterators.pop()); | 
					
						
							| 
									
										
										
										
											2021-07-16 19:05:18 +08:00
										 |  |  | 					result = current.next(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return result; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = StackedCacheMap; |