export class MultiMap < K extends Object , V > { private _allowDuplicates : boolean ; readonly [ Symbol . toStringTag ] = "MultiMap" ; private store : Map < K , V [ ] | Set < V > > ; private _size : number ; param allowDuplicates constructor ( allowDuplicates = true ) { this . _allowDuplicates = allowDuplicates ; this . store = new Map ( ) ; this . _size = 0 ; } get allowDuplicates ( ) : boolean { return this . _allowDuplicates ; } /** Alias for `sizeOfKeys()`. */ get size ( ) : number { return this . store . size ; } get sizeOfKeys ( ) : number { return this . store . size ; } get sizeOfValues ( ) : number { return this . _size ; } returns get ( key ) { let res = this . store . get ( key ) ; if ( res === undefined ) { return [ ] ; } return this . copyValueList ( res ) ; } private copyValueList ( values ) { return [ ... values ] ; } private isSet ( v ) { return v instanceof Set ; } set ( key , ... values ) { if ( values . length === 0 ) return this ; let res = this . store . get ( key ) ; let originalSize ; if ( res ) { if ( this . isSet ( res ) ) { originalSize = res . size ; for ( let v of values ) { res . add ( v ) ; } } else { originalSize = res . length ; res . push ( ... values ) ; } } else { originalSize = 0 ; if ( this . allowDuplicates ) { res = [ ... values ] ; this . store . set ( key , res ) ; } else { res = new Set ( values ) ; this . store . set ( key , res ) ; } } this . _size += ( this . isSet ( res ) ? res . size : res . length ) - originalSize ; return this ; } /**
     * set all values from a MultiMap of the same type into this MultiMap.
     */ setAll ( other ) { for ( let [ key1 , values ] of other . entries ( ) ) { this . set ( key1 , ... values ) ; } } clear ( ) { this . store . clear ( ) ; this . _size = 0 ; } /**
     * Deletes all values for a given key.
     */ delete ( key ) { let hasValue = this . store . has ( key ) ; if ( ! hasValue ) return false ; let valuesForKey = this . store . get ( key ) ! ; this . _size -= this . isSet ( valuesForKey ) ? valuesForKey . size : valuesForKey . length ; this . store . delete ( key ) ; return hasValue ; } returns deleteValue ( key , ... valuesToDelete ) { let found = new Array < V > ( ) ; if ( ! this . store . has ( key ) ) return found ; for ( let value of valuesToDelete ) { let valuesForKey = this . store . get ( key ) ! ; if ( ! valuesForKey ) continue ; if ( this . isSet ( valuesForKey ) ) { if ( valuesForKey . delete ( value ) ) { this . _size -= 1 ; found . push ( value ) ; if ( valuesForKey . size === 0 ) { this . store . delete ( key ) ; } } } else { let start = valuesForKey . indexOf ( value ) ; while ( start >= 0 ) { this . _size -= 1 ; valuesForKey . splice ( start , 1 ) ; found . push ( value ) ; if ( valuesForKey . length === 0 ) { this . store . delete ( key ) ; return found ; } start = valuesForKey . indexOf ( value ) ; } } } return found ; } forEach ( callback , thisArg ? ) { this . store . forEach ( ( ( values , key ) => { callback . call ( thisArg , this . copyValueList ( values ) , key , this ) ; } ) ) ; } forEachValue ( callback , thisArg ? ) { this . store . forEach ( ( ( values , key ) => { for ( let value of values ) { callback . call ( thisArg , value , key , this ) ; } } ) ) ; } /**
     * checks if the MultiMap has at least one value for the key.
     */ has ( key ) { return this . store . has ( key ) ; } /**
     * checks if the MultiMap has the specified value for the key.
     */ hasValue ( key , value ) { let values = this . store . get ( key ) ; if ( values ) { if ( this . isSet ( values ) ) { return values . has ( value ) ; } else { return values . indexOf ( value ) >= 0 ; } } else { return false ; } } /**
     *  iterate over all keys and values in this MultiMap.
     */ [ Symbol . iterator ] ( ) { return this . entries ( ) ; } * entries ( ) { for ( let entry of this . store . entries ( ) ) { yield [ entry [ 0 ] , this . copyValueList ( entry [ 1 ] ) ] ; } } /** iterates over each value of each key providing both key and value. */ * individualEntries ( ) { for ( let [ key , values ] of this . store . entries ( ) ) { for ( let value of values ) { yield [ key , value ] ; } } } keys ( ) { return this . store . keys ( ) ; } /** iterates over each set of values that are stored in the MultiMap. */ * values ( ) { for ( let values of this . store . values ( ) ) { yield this . copyValueList ( values ) ; } } /** iterates over each value individually that stored in the MultiMap. */ * individualValues ( ) { for ( let values of this . store . values ( ) ) { for ( let value of values ) { yield value ; } } } }