export function objectValues < T > ( obj ) { const items = [ ] ; for ( const key in obj ) { if ( ! Object . prototype . hasOwnProperty . call ( obj , key ) ) { continue ; } items . push ( obj [ key ] ) ; } return items ; } export function isEmptyMap ( map ) { for ( const key in map ) { if ( Object . prototype . hasOwnProperty . call ( map , key ) ) { return false ; } } return true ; } /**
 * Clones Map collection. Required due to IE11 not supporing `new Map(map)`.
 */ export function cloneMap < K , V > ( map ) { const clone = new Map < K , V > ( ) ; map . forEach ( ( value , key ) => clone . set ( key , value ) ) ; return clone ; } /**
 * Clones Set collection. Required due to IE11 not supporing `new Set(set)`.
 */ export function cloneSet < T > ( set ) { const clone = new Set < T > ( ) ; set . forEach ( item => clone . add ( item ) ) ; return clone ; } export function getOrCreateArrayInMap < K , V > ( map , key ) { let values = map . get ( key ) ; if ( ! values ) { values = [ ] ; map . set ( key , values ) ; } return values ; } export function getOrCreateSetInMap < K , V > ( map , key ) { let values = map . get ( key ) ; if ( ! values ) { values = new Set ( ) ; map . set ( key , values ) ; } return values ; } export class OrderedMap < V > { private mapping = new Map < string , V > ( ) ; private ordered : V [ ] = [ ] ; reorder ( compare ) { this . ordered . sort ( compare ) ; } get items ( ) : ReadonlyArray < V > { return this . ordered ; } get ( key ) { return this . mapping . get ( key ) ; } push ( key , value ) { if ( this . mapping . has ( key ) ) { const previous = this . mapping . get ( key ) ; if ( previous === value ) { return ; } const index = this . ordered . indexOf ( previous ) ; this . ordered . splice ( index , 1 ) ; } this . mapping . set ( key , value ) ; this . ordered . push ( value ) ; } delete ( key ) { if ( ! this . mapping . has ( key ) ) { return undefined ; } const previous = this . mapping . get ( key ) ; const index = this . ordered . indexOf ( previous ) ; this . ordered . splice ( index , 1 ) ; this . mapping . delete ( key ) ; return previous ; } } export interface ReadonlyHashMap < K , V > { readonly size : number ; has ( key ) : boolean ; get ( key ) : V | undefined ; forEach ( callback ) : void ; clone ( ) : HashMap < K , V > ; } export class HashMap < K , V > implements ReadonlyHashMap < K , V > { private readonly map = new Map < number , Array < { key : K ; value : V ; } > > ( ) ; private _size = 0 ; constructor ( private hashCode , private equals ) { } get size ( ) { return this . _size ; } has ( key ) { const items = this . map . get ( this . hashCode ( key ) ) ; if ( ! items ) { return false ; } return Boolean ( items . find ( p => this . equals ( p . key , key ) ) ) ; } get ( key ) { const items = this . map . get ( this . hashCode ( key ) ) ; if ( ! items ) { return undefined ; } const pair = items . find ( p => this . equals ( p . key , key ) ) ; return pair ? pair . value : undefined ; } set ( key , value ) { const hash = this . hashCode ( key ) ; let items = this . map . get ( hash ) ; if ( items ) { const index = items . findIndex ( p => this . equals ( p . key , key ) ) ; if ( index >= 0 ) { items . splice ( index , 1 ) ; } else { this . _size ++ ; } items . push ( { key , value } ) ; } else { items = [ { key , value } ] ; this . map . set ( hash , items ) ; this . _size ++ ; } return this ; } delete ( key ) { const items = this . map . get ( this . hashCode ( key ) ) ; if ( ! items ) { return false ; } const index = items . findIndex ( p => this . equals ( p . key , key ) ) ; if ( index >= 0 ) { items . splice ( index , 1 ) ; this . _size -- ; return true ; } else { return false ; } } clear ( ) { this . map . clear ( ) ; this . _size = 0 ; } forEach ( callback ) { this . map . forEach ( items => { for ( const { key , value } of items ) { callback ( value , key , this ) ; } } ) ; } clone ( ) { const clone = new HashMap < K , V > ( this . hashCode , this . equals ) ; clone . _size = this . size ; this . map . forEach ( ( value , key ) => clone . map . set ( key , [ ... value ] ) ) ; return clone ; } } export enum MoveDirection { ToStart = - 1 , ToEnd = 1 } export function makeMoveComparator < T > ( items , selected , moveDirection ) { const orderMap = new Map < T , number > ( ) ; const selectionIndexOffset = moveDirection * items . length ; items . forEach ( ( item , index ) => { orderMap . set ( item , index ) ; } ) ; for ( const selectedItem of selected ) { orderMap . set ( selectedItem , selectionIndexOffset + orderMap . get ( selectedItem ) ) ; } return ( a , b ) => { const orderA = orderMap . get ( a ) ; const orderB = orderMap . get ( b ) ; return ( orderA > orderB ? 1 : orderA < orderB ? - 1 : 0 ) ; } ; }