| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-18 08:41:58 +08:00
										 |  |  | "use strict"; | 
					
						
							| 
									
										
										
										
											2018-06-06 12:11:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-07 19:26:35 +08:00
										 |  |  | const NONE = Symbol("not sorted"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 12:11:24 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * A subset of Set that offers sorting functionality | 
					
						
							|  |  |  |  * @template T item type in set | 
					
						
							| 
									
										
										
										
											2018-07-05 13:07:46 +08:00
										 |  |  |  * @extends {Set<T>} | 
					
						
							| 
									
										
										
										
											2018-06-06 12:11:24 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | class SortableSet extends Set { | 
					
						
							| 
									
										
										
										
											2018-06-06 12:11:24 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * Create a new sortable set | 
					
						
							| 
									
										
										
										
											2024-07-30 20:26:24 +08:00
										 |  |  | 	 * @template T | 
					
						
							| 
									
										
										
										
											2018-06-25 22:37:20 +08:00
										 |  |  | 	 * @param {Iterable<T>=} initialIterable The initial iterable value | 
					
						
							| 
									
										
										
										
											2018-06-20 06:35:58 +08:00
										 |  |  | 	 * @typedef {function(T, T): number} SortFunction | 
					
						
							| 
									
										
										
										
											2024-07-30 20:26:24 +08:00
										 |  |  | 	 * @param {SortFunction<T>=} defaultSort Default sorting function | 
					
						
							| 
									
										
										
										
											2018-06-06 12:11:24 +08:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-06-18 08:41:58 +08:00
										 |  |  | 	constructor(initialIterable, defaultSort) { | 
					
						
							|  |  |  | 		super(initialIterable); | 
					
						
							| 
									
										
										
										
											2024-06-11 20:32:02 +08:00
										 |  |  | 		/** | 
					
						
							|  |  |  | 		 * @private | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 		 * @type {undefined | SortFunction<T>} | 
					
						
							| 
									
										
										
										
											2024-06-11 20:32:02 +08:00
										 |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2017-06-18 08:41:58 +08:00
										 |  |  | 		this._sortFn = defaultSort; | 
					
						
							| 
									
										
										
										
											2024-06-11 20:32:02 +08:00
										 |  |  | 		/** | 
					
						
							|  |  |  | 		 * @private | 
					
						
							|  |  |  | 		 * @type {typeof NONE | undefined | function(T, T): number}} | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2018-12-07 19:26:35 +08:00
										 |  |  | 		this._lastActiveSortFn = NONE; | 
					
						
							| 
									
										
										
										
											2024-06-11 20:32:02 +08:00
										 |  |  | 		/** | 
					
						
							|  |  |  | 		 * @private | 
					
						
							|  |  |  | 		 * @type {Map<Function, any> | undefined} | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | 		this._cache = undefined; | 
					
						
							| 
									
										
										
										
											2024-06-11 20:32:02 +08:00
										 |  |  | 		/** | 
					
						
							|  |  |  | 		 * @private | 
					
						
							|  |  |  | 		 * @type {Map<Function, any> | undefined} | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | 		this._cacheOrderIndependent = undefined; | 
					
						
							| 
									
										
										
										
											2017-06-19 20:20:10 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2018-06-06 12:11:24 +08:00
										 |  |  | 	 * @param {T} value value to add to set | 
					
						
							|  |  |  | 	 * @returns {this} returns itself | 
					
						
							| 
									
										
										
										
											2017-06-19 20:20:10 +08:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	add(value) { | 
					
						
							| 
									
										
										
										
											2018-12-07 19:26:35 +08:00
										 |  |  | 		this._lastActiveSortFn = NONE; | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | 		this._invalidateCache(); | 
					
						
							|  |  |  | 		this._invalidateOrderedCache(); | 
					
						
							| 
									
										
										
										
											2017-06-19 20:20:10 +08:00
										 |  |  | 		super.add(value); | 
					
						
							|  |  |  | 		return this; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 12:11:24 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {T} value value to delete | 
					
						
							|  |  |  | 	 * @returns {boolean} true if value existed in set, false otherwise | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-09-22 20:07:28 +08:00
										 |  |  | 	delete(value) { | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | 		this._invalidateCache(); | 
					
						
							|  |  |  | 		this._invalidateOrderedCache(); | 
					
						
							| 
									
										
										
										
											2017-09-22 20:07:28 +08:00
										 |  |  | 		return super.delete(value); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 12:11:24 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-09-22 20:07:28 +08:00
										 |  |  | 	clear() { | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | 		this._invalidateCache(); | 
					
						
							|  |  |  | 		this._invalidateOrderedCache(); | 
					
						
							| 
									
										
										
										
											2017-09-22 20:07:28 +08:00
										 |  |  | 		return super.clear(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 12:11:24 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * Sort with a comparer function | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 	 * @param {SortFunction<T> | undefined} sortFn Sorting comparer function | 
					
						
							| 
									
										
										
										
											2018-06-06 12:11:24 +08:00
										 |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	sortWith(sortFn) { | 
					
						
							| 
									
										
										
										
											2018-04-25 00:21:25 +08:00
										 |  |  | 		if (this.size <= 1 || sortFn === this._lastActiveSortFn) { | 
					
						
							| 
									
										
										
										
											2017-06-19 20:20:10 +08:00
										 |  |  | 			// already sorted - nothing to do
 | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-18 08:41:58 +08:00
										 |  |  | 		const sortedArray = Array.from(this).sort(sortFn); | 
					
						
							| 
									
										
										
										
											2017-06-19 20:20:10 +08:00
										 |  |  | 		super.clear(); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (let i = 0; i < sortedArray.length; i += 1) { | 
					
						
							| 
									
										
										
										
											2017-09-22 23:23:49 +08:00
										 |  |  | 			super.add(sortedArray[i]); | 
					
						
							| 
									
										
										
										
											2017-06-18 08:41:58 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-06-19 20:20:10 +08:00
										 |  |  | 		this._lastActiveSortFn = sortFn; | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | 		this._invalidateCache(); | 
					
						
							| 
									
										
										
										
											2017-06-18 08:41:58 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sort() { | 
					
						
							|  |  |  | 		this.sortWith(this._sortFn); | 
					
						
							| 
									
										
										
										
											2020-07-28 00:09:48 +08:00
										 |  |  | 		return this; | 
					
						
							| 
									
										
										
										
											2017-06-18 08:41:58 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-22 20:07:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2018-06-20 06:32:15 +08:00
										 |  |  | 	 * Get data from cache | 
					
						
							| 
									
										
										
										
											2018-08-07 01:39:43 +08:00
										 |  |  | 	 * @template R | 
					
						
							|  |  |  | 	 * @param {function(SortableSet<T>): R} fn function to calculate value | 
					
						
							|  |  |  | 	 * @returns {R} returns result of fn(this), cached until set changes | 
					
						
							| 
									
										
										
										
											2017-09-22 20:07:28 +08:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-11-06 19:15:23 +08:00
										 |  |  | 	getFromCache(fn) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (this._cache === undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-03 17:17:08 +08:00
										 |  |  | 			this._cache = new Map(); | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2018-08-07 01:39:43 +08:00
										 |  |  | 			const result = this._cache.get(fn); | 
					
						
							|  |  |  | 			const data = /** @type {R} */ (result); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (data !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-03 17:17:08 +08:00
										 |  |  | 				return data; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-09-22 20:07:28 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-11-03 17:17:08 +08:00
										 |  |  | 		const newData = fn(this); | 
					
						
							|  |  |  | 		this._cache.set(fn, newData); | 
					
						
							|  |  |  | 		return newData; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-03 17:17:08 +08:00
										 |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2018-08-07 01:39:43 +08:00
										 |  |  | 	 * Get data from cache (ignoring sorting) | 
					
						
							|  |  |  | 	 * @template R | 
					
						
							|  |  |  | 	 * @param {function(SortableSet<T>): R} fn function to calculate value | 
					
						
							|  |  |  | 	 * @returns {R} returns result of fn(this), cached until set changes | 
					
						
							| 
									
										
										
										
											2017-11-03 17:17:08 +08:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-11-06 19:15:23 +08:00
										 |  |  | 	getFromUnorderedCache(fn) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (this._cacheOrderIndependent === undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-03 17:17:08 +08:00
										 |  |  | 			this._cacheOrderIndependent = new Map(); | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2018-08-07 01:39:43 +08:00
										 |  |  | 			const result = this._cacheOrderIndependent.get(fn); | 
					
						
							|  |  |  | 			const data = /** @type {R} */ (result); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (data !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-03 17:17:08 +08:00
										 |  |  | 				return data; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		const newData = fn(this); | 
					
						
							|  |  |  | 		this._cacheOrderIndependent.set(fn, newData); | 
					
						
							|  |  |  | 		return newData; | 
					
						
							| 
									
										
										
										
											2017-09-22 20:07:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 12:11:24 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @private | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | 	_invalidateCache() { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		if (this._cache !== undefined) { | 
					
						
							|  |  |  | 			this._cache.clear(); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 12:11:24 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @private | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | 	_invalidateOrderedCache() { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		if (this._cacheOrderIndependent !== undefined) { | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | 			this._cacheOrderIndependent.clear(); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-07 01:39:43 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @returns {T[]} the raw array | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	toJSON() { | 
					
						
							|  |  |  | 		return Array.from(this); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-11 03:32:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = SortableSet; |