| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 | "use strict";/** * A subset of Set that offers sorting functionality * @template T item type in set * @extends {Set<T>} */class SortableSet extends Set {	/**	 * Create a new sortable set	 * @param {Iterable<T>=} initialIterable The initial iterable value	 * @typedef {function(T, T): number} SortFunction	 * @param {SortFunction=} defaultSort Default sorting function	 */	constructor(initialIterable, defaultSort) {		super(initialIterable);		/** @private @type {function(T, T): number}} */		this._sortFn = defaultSort;		/** @private @type {function(T, T): number} | null} */		this._lastActiveSortFn = null;		/** @private @type {Map<Function, T[]> | undefined} */		this._cache = undefined;		/** @private @type {Map<Function, T[]|string|number> | undefined} */		this._cacheOrderIndependent = undefined;	}	/**	 * @param {T} value value to add to set	 * @returns {this} returns itself	 */	add(value) {		this._lastActiveSortFn = null;		this._invalidateCache();		this._invalidateOrderedCache();		super.add(value);		return this;	}	/**	 * @param {T} value value to delete	 * @returns {boolean} true if value existed in set, false otherwise	 */	delete(value) {		this._invalidateCache();		this._invalidateOrderedCache();		return super.delete(value);	}	/**	 * @returns {void}	 */	clear() {		this._invalidateCache();		this._invalidateOrderedCache();		return super.clear();	}	/**	 * Sort with a comparer function	 * @param {SortFunction} sortFn Sorting comparer function	 * @returns {void}	 */	sortWith(sortFn) {		if (this.size <= 1 || sortFn === this._lastActiveSortFn) {			// already sorted - nothing to do			return;		}		const sortedArray = Array.from(this).sort(sortFn);		super.clear();		for (let i = 0; i < sortedArray.length; i += 1) {			super.add(sortedArray[i]);		}		this._lastActiveSortFn = sortFn;		this._invalidateCache();	}	sort() {		this.sortWith(this._sortFn);	}	/**	 * Get data from cache	 * @param {function(SortableSet<T>): T[]} fn function to calculate value	 * @returns {T[]} returns result of fn(this), cached until set changes	 */	getFromCache(fn) {		if (this._cache === undefined) {			this._cache = new Map();		} else {			const data = this._cache.get(fn);			if (data !== undefined) {				return data;			}		}		const newData = fn(this);		this._cache.set(fn, newData);		return newData;	}	/**	 * @param {function(SortableSet<T>): string|number|T[]} fn function to calculate value	 * @returns {any} returns result of fn(this), cached until set changes	 */	getFromUnorderedCache(fn) {		if (this._cacheOrderIndependent === undefined) {			this._cacheOrderIndependent = new Map();		} else {			const data = this._cacheOrderIndependent.get(fn);			if (data !== undefined) {				return data;			}		}		const newData = fn(this);		this._cacheOrderIndependent.set(fn, newData);		return newData;	}	/**	 * @private	 * @returns {void}	 */	_invalidateCache() {		if (this._cache !== undefined) {			this._cache.clear();		}	}	/**	 * @private	 * @returns {void}	 */	_invalidateOrderedCache() {		if (this._cacheOrderIndependent !== undefined) {			this._cacheOrderIndependent.clear();		}	}}module.exports = SortableSet;
 |