'use strict' ; export namespace vscMockArrays { param array param n export function tail < T > ( array , n = 0 ) { return array [ array . length - ( 1 + n ) ] ; } export function equals < T > ( one , other , itemEquals = ( a , b ) => a === b ) { if ( one . length !== other . length ) { return false ; } for ( let i = 0 , len = one . length ; i < len ; i ++ ) { if ( ! itemEquals ( one [ i ] , other [ i ] ) ) { return false ; } } return true ; } export function binarySearch < T > ( array , key , comparator ) { let low = 0 , high = array . length - 1 ; while ( low <= high ) { let mid = ( ( low + high ) / 2 ) | 0 ; let comp = comparator ( array [ mid ] , key ) ; if ( comp < 0 ) { low = mid + 1 ; } else if ( comp > 0 ) { high = mid - 1 ; } else { return mid ; } } return - ( low + 1 ) ; } returns export function findFirst < T > ( array , p ) { let low = 0 , high = array . length ; if ( high === 0 ) { return 0 ; } while ( low < high ) { let mid = Math . floor ( ( low + high ) / 2 ) ; if ( p ( array [ mid ] ) ) { high = mid ; } else { low = mid + 1 ; } } return low ; } /**
     * Like `Array#sort` but always stable. Usually runs a little slower `than Array#sort`
     * so only use this when actually needing stable sort.
     */ export function mergeSort < T > ( data , compare ) { _divideAndMerge ( data , compare ) ; return data ; } function _divideAndMerge < T > ( data , compare ) { if ( data . length <= 1 ) { return ; } const p = ( data . length / 2 ) | 0 ; const left = data . slice ( 0 , p ) ; const right = data . slice ( p ) ; _divideAndMerge ( left , compare ) ; _divideAndMerge ( right , compare ) ; let leftIdx = 0 ; let rightIdx = 0 ; let i = 0 ; while ( leftIdx < left . length && rightIdx < right . length ) { let ret = compare ( left [ leftIdx ] , right [ rightIdx ] ) ; if ( ret <= 0 ) { data [ i ++ ] = left [ leftIdx ++ ] ; } else { data [ i ++ ] = right [ rightIdx ++ ] ; } } while ( leftIdx < left . length ) { data [ i ++ ] = left [ leftIdx ++ ] ; } while ( rightIdx < right . length ) { data [ i ++ ] = right [ rightIdx ++ ] ; } } export function groupBy < T > ( data , compare ) { const result = [ ] ; let currentGroup ; for ( const element of mergeSort ( data . slice ( 0 ) , compare ) ) { if ( ! currentGroup || compare ( currentGroup [ 0 ] , element ) !== 0 ) { currentGroup = [ element ] ; result . push ( currentGroup ) ; } else { currentGroup . push ( element ) ; } } return result ; } type IMutableSplice < T > = Array < T > & any & { deleteCount : number ; } ; type ISplice < T > = Array < T > & any ; /**
     * Diffs two *sorted* arrays and computes the splices which apply the diff.
     */ export function sortedDiff < T > ( before , after , compare ) { const result = [ ] ; function pushSplice ( start , deleteCount , toInsert ) { if ( deleteCount === 0 && toInsert . length === 0 ) { return ; } const latest = result [ result . length - 1 ] ; if ( latest && latest . start + latest . deleteCount === start ) { latest . deleteCount += deleteCount ; latest . toInsert . push ( ... toInsert ) ; } else { result . push ( { start , deleteCount , toInsert } ) ; } } let beforeIdx = 0 ; let afterIdx = 0 ; while ( true ) { if ( beforeIdx === before . length ) { pushSplice ( beforeIdx , 0 , after . slice ( afterIdx ) ) ; break ; } if ( afterIdx === after . length ) { pushSplice ( beforeIdx , before . length - beforeIdx , [ ] ) ; break ; } const beforeElement = before [ beforeIdx ] ; const afterElement = after [ afterIdx ] ; const n = compare ( beforeElement , afterElement ) ; if ( n === 0 ) { beforeIdx += 1 ; afterIdx += 1 ; } else if ( n < 0 ) { pushSplice ( beforeIdx , 1 , [ ] ) ; beforeIdx += 1 ; } else if ( n > 0 ) { pushSplice ( beforeIdx , 0 , [ afterElement ] ) ; afterIdx += 1 ; } } return result ; } param before param after param compare export function delta < T > ( before , after , compare ) { const splices = sortedDiff ( before , after , compare ) ; const removed = [ ] ; const added = [ ] ; for ( const splice of splices ) { removed . push ( ... before . slice ( splice . start , splice . start + splice . deleteCount ) ) ; added . push ( ... splice . toInsert ) ; } return { removed , added } ; } param array param compare param n return export function top < T > ( array , compare , n ) { if ( n === 0 ) { return [ ] ; } const result = array . slice ( 0 , n ) . sort ( compare ) ; topStep ( array , compare , result , n , array . length ) ; return result ; } function topStep < T > ( array , compare , result , i , m ) { for ( const n = result . length ; i < m ; i ++ ) { const element = array [ i ] ; if ( compare ( element , result [ n - 1 ] ) < 0 ) { result . pop ( ) ; const j = findFirst ( result , e => compare ( element , e ) < 0 ) ; result . splice ( j , 0 , element ) ; } } } returns export function coalesce < T > ( array ) { if ( ! array ) { return array ; } return array . filter ( e => ! ! e ) ; } /**
     * Moves the element in the array for the provided positions.
     */ export function move ( array , from , to ) { array . splice ( to , 0 , array . splice ( from , 1 ) [ 0 ] ) ; } returns { { false } } export function isFalsyOrEmpty ( obj ) { return ! Array . isArray ( obj ) || ( < Array < any > > obj ) . length === 0 ; } /**
     * Removes duplicates from the given array. The optional keyFn allows to specify
     * how elements are checked for equalness by returning a unique string for each.
     */ export function distinct < T > ( array , keyFn ? ) { if ( ! keyFn ) { return array . filter ( ( element , position ) => { return array . indexOf ( element ) === position ; } ) ; } const seen = Object . create ( null ) ; return array . filter ( elem => { const key = keyFn ( elem ) ; if ( seen [ key ] ) { return false ; } seen [ key ] = true ; return true ; } ) ; } export function uniqueFilter < T > ( keyFn ) { const seen = Object . create ( null ) ; return element => { const key = keyFn ( element ) ; if ( seen [ key ] ) { return false ; } seen [ key ] = true ; return true ; } ; } export function firstIndex < T > ( array , fn ) { for ( let i = 0 ; i < array . length ; i ++ ) { const element = array [ i ] ; if ( fn ( element ) ) { return i ; } } return - 1 ; } export function first < T > ( array , fn , notFoundValue = null ) { const index = firstIndex ( array , fn ) ; return index < 0 ? notFoundValue : array [ index ] ; } export function commonPrefixLength < T > ( one , other , equals = ( a , b ) => a === b ) { let result = 0 ; for ( let i = 0 , len = Math . min ( one . length , other . length ) ; i < len && equals ( one [ i ] , other [ i ] ) ; i ++ ) { result ++ ; } return result ; } export function flatten < T > ( arr ) { return [ ] . concat ( ... arr ) ; } export function range ( to ) ; export function range ( from , to ) ; export function range ( arg , to ? ) { let from = typeof to === 'number' ? arg : 0 ; if ( typeof to === 'number' ) { from = arg ; } else { from = 0 ; to = arg ; } const result = [ ] ; if ( from <= to ) { for ( let i = from ; i < to ; i ++ ) { result . push ( i ) ; } } else { for ( let i = from ; i > to ; i -- ) { result . push ( i ) ; } } return result ; } export function fill < T > ( num , valueFn , arr = [ ] ) { for ( let i = 0 ; i < num ; i ++ ) { arr [ i ] = valueFn ( ) ; } return arr ; } export function index < T > ( array , indexer ) ; export function index < T , R > ( array , indexer , merger ? ) ; export function index < T , R > ( array , indexer , merger = t => t as any ) { return array . reduce ( ( r , t ) => { const key = indexer ( t ) ; r [ key ] = merger ( t , r [ key ] ) ; return r ; } , Object . create ( null ) ) ; } /**
     * Inserts an element into an array. Returns a function which, when
     * called, will remove that element from the array.
     */ export function insert < T > ( array , element ) { array . push ( element ) ; return ( ) => { const index = array . indexOf ( element ) ; if ( index > - 1 ) { array . splice ( index , 1 ) ; } } ; } /**
     * Insert `insertArr` inside `target` at `insertIndex`.
     * Please don't touch unless you understand https://jsperf.com/inserting-an-array-within-an-array
     */ export function arrayInsert < T > ( target , insertIndex , insertArr ) { const before = target . slice ( 0 , insertIndex ) ; const after = target . slice ( insertIndex ) ; return before . concat ( insertArr , after ) ; } }