import * as assert from "@esfx/internal-assert" ; import { Equaler , Comparer , Comparison , EqualityComparison } from "@esfx/equatable" ; import { IndexedCollection } from '@esfx/collection-core' ; import { HashSet } from "@esfx/collections-hashset" ; import { HashMap } from "@esfx/collections-hashmap" ; import { Lookup } from "@esfx/iter-lookup" ; import { identity , T } from '@esfx/fn' ; import { consume , empty , ConsumeOptions } from './queries' ; import { prepend , takeRight } from './subqueries' ; import { createGroupings , flowHierarchy } from './internal/utils' ; import { HierarchyIterable } from '@esfx/iter-hierarchy' ; import { Index } from "@esfx/interval" ; param source param accumulator category export function reduce < T > ( source , accumulator ) ; param source param accumulator param seed category export function reduce < T , U > ( source , accumulator , seed , resultSelector ? ) ; param source param accumulator param seed param resultSelector category export function reduce < T , U , R > ( source , accumulator , seed , resultSelector ) ; export function reduce < T > ( source , accumulator , seed ? , resultSelector = identity ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( accumulator , "accumulator" ) ; assert . mustBeFunction ( resultSelector , "resultSelector" ) ; let hasCurrent = arguments . length > 2 ; let current = seed ; let count = 0 ; for ( const value of source ) { if ( ! hasCurrent ) { hasCurrent = true ; current = value ; } else { current = accumulator ( current ! , value , count ) ; } count ++ ; } return resultSelector ( current ! , count ) ; } param source param accumulator category export function reduceRight < T > ( source , accumulator ) ; param source param accumulator param seed category export function reduceRight < T , U > ( source , accumulator , seed , resultSelector ? ) ; param source param accumulator param seed param resultSelector category export function reduceRight < T , U , R > ( source , accumulator , seed , resultSelector ) ; export function reduceRight < T > ( source , accumulator , seed ? , resultSelector = identity ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( accumulator , "accumulator" ) ; assert . mustBeFunction ( resultSelector , "resultSelector" ) ; const sourceArray = toArray < T > ( source ) ; let hasCurrent = arguments . length > 2 ; let current = seed ; let count = 0 ; for ( let offset = sourceArray . length - 1 ; offset >= 0 ; offset -- ) { const value = sourceArray [ offset ] ; if ( ! hasCurrent ) { current = value ; hasCurrent = true ; } else { current = accumulator ( current ! , value , offset ) ; } count ++ ; } return resultSelector ( current ! , count ) ; } param source param predicate category export function count < T > ( source , predicate = T ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; if ( predicate === T ) { if ( Array . isArray ( source ) ) return source . length ; if ( source instanceof Set || source instanceof Map ) return source . size ; } let count = 0 ; for ( const element of source ) { if ( predicate ( element ) ) { count ++ ; } } return count ; } param source param predicate category export function first < T , U extends T > ( source , predicate ) ; param source param predicate category export function first < T > ( source , predicate ? ) ; export function first < T > ( source , predicate = T ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; for ( const element of source ) { if ( predicate ( element ) ) { return element ; } } return undefined ; } param source param predicate category export function last < T , U extends T > ( source , predicate ) ; param source param predicate category export function last < T > ( source , predicate ? ) ; export function last < T > ( source , predicate = T ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; let result ; for ( const element of source ) { if ( predicate ( element ) ) { result = element ; } } return result ; } param source param predicate category export function single < T , U extends T > ( source , predicate ) ; param source param predicate category export function single < T > ( source , predicate ? ) ; export function single < T > ( source , predicate = T ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; let hasResult = false ; let result ; for ( const element of source ) { if ( predicate ( element ) ) { if ( hasResult ) { return undefined ; } hasResult = true ; result = element ; } } return hasResult ? result : undefined ; } param source param keySelector param keyComparer category export function minBy < T , K > ( source , keySelector , keyComparer = Comparer . defaultComparer ) { if ( typeof keyComparer === "function" ) keyComparer = Comparer . create ( keyComparer ) ; assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( keySelector , "keySelector" ) ; assert . mustBeType ( Comparer . hasInstance , keyComparer , "keyComparer" ) ; let hasResult = false ; let result ; let resultKey ; for ( const element of source ) { const key = keySelector ( element ) ; if ( ! hasResult ) { result = element ; resultKey = key ; hasResult = true ; } else if ( keyComparer . compare ( key , resultKey ! ) < 0 ) { result = element ; resultKey = key ; } } return result ; } param source param comparer category export function min < T > ( source , comparer = Comparer . defaultComparer ) { if ( typeof comparer === "function" ) comparer = Comparer . create ( comparer ) ; assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeType ( Comparer . hasInstance , comparer , "comparer" ) ; return minBy ( source , identity , comparer ) ; } param source param keySelector param keyComparer category export function maxBy < T , K > ( source , keySelector , keyComparer = Comparer . defaultComparer ) { if ( typeof keyComparer === "function" ) keyComparer = Comparer . create ( keyComparer ) ; assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( keySelector , "keySelector" ) ; assert . mustBeType ( Comparer . hasInstance , keyComparer , "keyComparer" ) ; let hasResult = false ; let result ; let resultKey ; for ( const element of source ) { const key = keySelector ( element ) ; if ( ! hasResult ) { result = element ; resultKey = key ; hasResult = true ; } else if ( keyComparer . compare ( key , resultKey ! ) > 0 ) { result = element ; resultKey = key ; } } return result ; } param source param comparer category export function max < T > ( source , comparer = Comparer . defaultComparer ) { if ( typeof comparer === "function" ) comparer = Comparer . create ( comparer ) ; assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeType ( Comparer . hasInstance , comparer , "comparer" ) ; return maxBy ( source , identity , comparer ) ; } param source param predicate category export function some < T > ( source , predicate = T ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; for ( const element of source ) { if ( predicate ( element ) ) { return true ; } } return false ; } param source param predicate category export function every < T , U extends T > ( source , predicate ) ; param source param predicate category export function every < T > ( source , predicate ) ; export function every < T > ( source , predicate ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; let hasMatchingElements = false ; for ( const element of source ) { if ( ! predicate ( element ) ) { return false ; } hasMatchingElements = true ; } return hasMatchingElements ; } param source category export function unzip < T extends readonly any [ ] | [ ] > ( source ) ; param source param partSelector category export function unzip < T , U extends readonly any [ ] | [ ] > ( source , partSelector ) ; export function unzip < T extends readonly any [ ] | [ ] > ( source , partSelector = identity ) { const result = [ ] ; let length = - 1 ; for ( const element of source ) { const row = partSelector ( element ) ; if ( length === - 1 ) { length = row . length ; for ( let i = 0 ; i < length ; i ++ ) { result . push ( [ ] ) ; } } for ( let i = 0 ; i < length ; i ++ ) { result [ i ] . push ( row [ i ] ) ; } } return result ; } param source param callback category export function forEach < T > ( source , callback ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( callback , "callback" ) ; let offset = 0 ; for ( const element of source ) { callback ( element , offset ++ ) ; } } param source param keySelector category export function toMap < T , K > ( source , keySelector ) ; param source param keySelector param elementSelector category export function toMap < T , K , V > ( source , keySelector , elementSelector ) ; export function toMap < T , K , V > ( source , keySelector , elementSelector = identity ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( keySelector , "keySelector" ) ; assert . mustBeFunction ( elementSelector , "elementSelector" ) ; const map = new Map < K , T | V > ( ) ; for ( const item of source ) { const key = keySelector ( item ) ; const element = elementSelector ( item ) ; map . set ( key , element ) ; } return map ; } param source param keySelector param keyEqualer category export function toHashMap < T , K > ( source , keySelector , keyEqualer ? ) ; param source param keySelector param elementSelector param keyEqualer category export function toHashMap < T , K , V > ( source , keySelector , elementSelector , keyEqualer ? ) ; export function toHashMap < T , K , V > ( source , keySelector , elementSelector = identity , keyEqualer ? ) { if ( typeof elementSelector === "object" ) { keyEqualer = elementSelector ; elementSelector = identity ; } assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( keySelector , "keySelector" ) ; assert . mustBeFunction ( elementSelector , "elementSelector" ) ; assert . mustBeTypeOrUndefined ( Equaler . hasInstance , keyEqualer , "keyEqualer" ) ; const map = new HashMap < K , T | V > ( keyEqualer ) ; for ( const item of source ) { const key = keySelector ( item ) ; const element = elementSelector ( item ) ; map . set ( key , element ) ; } return map ; } param source category export function toSet < T > ( source ) ; param source param elementSelector category export function toSet < T , V > ( source , elementSelector ) ; export function toSet < T , V > ( source , elementSelector = identity ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( elementSelector , "elementSelector" ) ; const set = new Set < T | V > ( ) ; for ( const item of source ) { const element = elementSelector ( item ) ; set . add ( element ) ; } return set ; } param source param equaler category export function toHashSet < T > ( source , equaler ? ) ; param source param elementSelector param equaler category export function toHashSet < T , V > ( source , elementSelector , equaler ? ) ; export function toHashSet < T > ( source , elementSelector = identity , equaler ? ) { if ( typeof elementSelector !== "function" ) { equaler = elementSelector ; elementSelector = identity ; } assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( elementSelector , "elementSelector" ) ; assert . mustBeTypeOrUndefined ( Equaler . hasInstance , equaler , "equaler" ) ; const set = new HashSet < T > ( equaler ) ; for ( const item of source ) { const element = elementSelector ( item ) ; set . add ( element ) ; } return set ; } param source category export function toArray < T > ( source ) ; param source param elementSelector category export function toArray < T , V > ( source , elementSelector ) ; export function toArray < T > ( source , elementSelector = identity ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( elementSelector , "elementSelector" ) ; const result = [ ] ; for ( const element of source ) { result . push ( elementSelector ( element ) ) ; } return result ; } function makeDescriptor < K , V > ( _key , value ) { return { enumerable : true , configurable : true , writable : true , value } ; } param source param prototype param keySelector category export function toObject < T , TProto extends object , K extends PropertyKey > ( source , prototype , keySelector ) ; param source param prototype param keySelector category export function toObject < T , TProto extends object > ( source , prototype , keySelector ) ; param source param prototype param keySelector category export function toObject < T , K extends PropertyKey > ( source , prototype , keySelector ) ; param source param prototype param keySelector category export function toObject < T > ( source , prototype , keySelector ) ; param source param prototype param keySelector param elementSelector param descriptorSelector category export function toObject < T , TProto extends object , K extends PropertyKey , V > ( source , prototype , keySelector , elementSelector , descriptorSelector ? ) ; param source param prototype param keySelector param elementSelector param descriptorSelector category export function toObject < T , TProto extends object , V > ( source , prototype , keySelector , elementSelector , descriptorSelector ? ) ; param source param prototype param keySelector param elementSelector param descriptorSelector category export function toObject < T , K extends PropertyKey , V > ( source , prototype , keySelector , elementSelector , descriptorSelector ? ) ; param source param prototype param keySelector param elementSelector param descriptorSelector category export function toObject < T , V > ( source , prototype , keySelector , elementSelector , descriptorSelector ? ) ; param source param prototype param keySelector param elementSelector param descriptorSelector category export function toObject < T , V > ( source , prototype , keySelector , elementSelector , descriptorSelector ? ) ; export function toObject < T > ( source , prototype = Object . prototype , keySelector , elementSelector = identity , descriptorSelector = makeDescriptor ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeObjectOrNull ( prototype , "prototype" ) ; assert . mustBeFunction ( keySelector , "keySelector" ) ; assert . mustBeFunction ( elementSelector , "elementSelector" ) ; assert . mustBeFunction ( descriptorSelector , "descriptorSelector" ) ; const obj = prototype === Object . prototype ? { } : Object . create ( prototype ) ; for ( const item of source ) { const key = keySelector ( item ) ; const element = elementSelector ( item ) ; const descriptor = descriptorSelector ( key , element ) ; Object . defineProperty ( obj , key , descriptor ) ; } return obj ; } param source param keySelector param keyEqualer category export function toLookup < T , K > ( source , keySelector , keyEqualer ? ) ; param source param keySelector param elementSelector param keyEqualer category export function toLookup < T , K , V > ( source , keySelector , elementSelector , keyEqualer ? ) ; export function toLookup < T , K , V > ( source , keySelector , elementSelector = identity , keyEqualer = Equaler . defaultEqualer ) { if ( typeof elementSelector === "object" ) { keyEqualer = elementSelector ; elementSelector = identity ; } assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( keySelector , "keySelector" ) ; assert . mustBeFunction ( elementSelector , "elementSelector" ) ; assert . mustBeTypeOrUndefined ( Equaler . hasInstance , keyEqualer , "keyEqualer" ) ; return new Lookup ( createGroupings ( source , keySelector , elementSelector , keyEqualer ) , keyEqualer ) ; } param source param callback category export function into < T , S extends Iterable < T > , R > ( source , callback ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( callback , "callback" ) ; return callback ( source ) ; } param source category export function sum ( source ) ; param source param elementSelector category export function sum < T > ( source , elementSelector ) ; export function sum ( source , elementSelector = identity ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( elementSelector , "elementSelector" ) ; let sum = 0 ; for ( const value of source ) { const result = elementSelector ( value ) ; if ( typeof result !== "number" ) throw new TypeError ( ) ; sum += result ; } return sum ; } param source category export function average ( source ) ; param source param elementSelector category export function average < T > ( source , elementSelector ) ; export function average ( source , elementSelector = identity ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunctionOrUndefined ( elementSelector , "elementSelector" ) ; let sum = 0 ; let count = 0 ; for ( const value of source ) { const result = elementSelector ( value ) ; if ( typeof result !== "number" ) throw new TypeError ( ) ; sum += result ; count ++ ; } return count > 0 ? sum / count : 0 ; } const noCacheAndLeaveOpen = { cacheElements : false , leaveOpen : true } ; const cacheAndClose = { cacheElements : true , leaveOpen : false } ; param source param predicate category export function span < TNode , T extends TNode , U extends T > ( source , predicate ) ; param source param predicate category export function span < TNode , T extends TNode > ( source , predicate ) ; param source param predicate category export function span < T , U extends T > ( source , predicate ) ; param source param predicate category export function span < T > ( source , predicate ) ; export function span < T > ( source , predicate ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; const prefix = [ ] ; const iterator = source [ Symbol . iterator ] ( ) ; let offset = 0 ; for ( const value of consume ( iterator , noCacheAndLeaveOpen ) ) { if ( ! predicate ( value , offset ++ ) ) { const remaining = prepend ( consume ( iterator , cacheAndClose ) , value ) ; return [ flowHierarchy ( { [ Symbol . iterator ] ( ) { return prefix [ Symbol . iterator ] ( ) ; } } , source ) , flowHierarchy ( remaining , source ) ] ; } prefix . push ( value ) ; } return [ flowHierarchy ( { [ Symbol . iterator ] ( ) { return prefix [ Symbol . iterator ] ( ) ; } } , source ) , flowHierarchy ( empty < T > ( ) , source ) ] ; } param source param predicate category export function spanUntil < T > ( source , predicate ) ; param source param predicate category export function spanUntil < T > ( source , predicate ) ; export function spanUntil < T > ( source , predicate ) { assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; const prefix = [ ] ; const iterator = source [ Symbol . iterator ] ( ) ; let offset = 0 ; for ( const value of consume ( iterator , noCacheAndLeaveOpen ) ) { if ( predicate ( value , offset ++ ) ) { const remaining = prepend ( consume ( iterator , cacheAndClose ) , value ) ; return [ flowHierarchy ( { [ Symbol . iterator ] ( ) { return prefix [ Symbol . iterator ] ( ) ; } } , source ) , flowHierarchy ( remaining , source ) ] ; } prefix . push ( value ) ; } return [ flowHierarchy ( { [ Symbol . iterator ] ( ) { return prefix [ Symbol . iterator ] ( ) ; } } , source ) , flowHierarchy ( empty < T > ( ) , source ) ] ; } param left param right param keySelector category export function correspondsBy < T , K > ( left , right , keySelector , keyEqualer ? ) ; param left param right param leftKeySelector param rightKeySelector param keyEqualer category export function correspondsBy < T , U , K > ( left , right , leftKeySelector , rightKeySelector , keyEqualer ? ) ; export function correspondsBy < T , K > ( left , right , leftKeySelector , rightKeySelector = leftKeySelector , keyEqualer = Equaler . defaultEqualer ) { if ( typeof rightKeySelector === "object" ) { keyEqualer = rightKeySelector ; rightKeySelector = leftKeySelector ; } if ( typeof keyEqualer === "function" ) { keyEqualer = Equaler . create ( keyEqualer ) ; } assert . mustBeIterableObject ( left , "left" ) ; assert . mustBeIterableObject ( right , "right" ) ; assert . mustBeFunction ( leftKeySelector , "leftKeySelector" ) ; assert . mustBeFunction ( rightKeySelector , "rightKeySelector" ) ; assert . mustBeType ( Equaler . hasInstance , keyEqualer , "keyEqualer" ) ; const leftIterator = left [ Symbol . iterator ] ( ) ; let leftResult ; try { const rightIterator = right [ Symbol . iterator ] ( ) ; let rightResult ; try { for ( ; ; ) { leftResult = leftIterator . next ( ) ; rightResult = rightIterator . next ( ) ; if ( leftResult . done && rightResult . done ) return true ; if ( Boolean ( leftResult . done ) !== Boolean ( rightResult . done ) || ! keyEqualer . equals ( leftKeySelector ( leftResult . value ) , rightKeySelector ( rightResult . value ) ) ) return false ; } } finally { if ( rightResult && ! rightResult . done ) rightIterator . return ?. ( ) ; } } finally { if ( leftResult && ! leftResult . done ) leftIterator . return ?. ( ) ; } } param left param right param equaler category export function corresponds < T > ( left , right , equaler ? ) ; param left param right param equaler category export function corresponds < T , U > ( left , right , equaler ) ; export function corresponds < T , U > ( left , right , equaler = Equaler . defaultEqualer ) { assert . mustBeIterableObject ( left , "left" ) ; assert . mustBeIterableObject ( right , "right" ) ; assert . mustBeObject ( equaler , "equaler" ) ; return correspondsBy ( left , right , identity , identity , equaler ) ; } param source param offset category export function elementAt < T > ( source , offset ) { assert . mustBeIterableObject ( source , "source" ) ; let isFromEnd = false ; if ( typeof offset === "number" ) { assert . mustBeInteger ( offset , "offset" ) ; isFromEnd = offset < 0 ; if ( isFromEnd ) offset = - offset ; } else { assert . mustBeInstanceOf ( Index , offset , "offset" ) ; isFromEnd = offset . isFromEnd ; offset = offset . value ; } if ( isFromEnd ) { if ( offset === 0 ) { return undefined ; } if ( offset === 1 ) { return last ( source ) ; } const array = [ ] ; for ( const element of source ) { if ( array . length >= offset ) { array . shift ( ) ; } array . push ( element ) ; } return array . length - offset >= 0 ? array [ array . length - offset ] : undefined ; } for ( const element of source ) { if ( offset === 0 ) { return element ; } offset -- ; } return undefined ; } export { elementAt as nth } ; param left param right param equaler category export function startsWith < T > ( left , right , equaler ? ) ; param left param right param equaler category export function startsWith < T , U > ( left , right , equaler ) ; export function startsWith < T > ( left , right , equaler = Equaler . defaultEqualer ) { if ( typeof equaler === "function" ) equaler = Equaler . create ( equaler ) ; assert . mustBeIterableObject ( left , "left" ) ; assert . mustBeIterableObject ( right , "right" ) ; assert . mustBeType ( Equaler . hasInstance , equaler , "equaler" ) ; const leftIterator = left [ Symbol . iterator ] ( ) ; let leftResult ; try { const rightIterator = right [ Symbol . iterator ] ( ) ; let rightResult ; try { for ( ; ; ) { leftResult = leftIterator . next ( ) ; rightResult = rightIterator . next ( ) ; if ( rightResult . done ) return true ; if ( leftResult . done || ! equaler . equals ( leftResult . value , rightResult . value ) ) return false ; } } finally { if ( rightResult && ! rightResult . done ) rightIterator . return ?. ( ) ; } } finally { if ( leftResult && ! leftResult . done ) leftIterator . return ?. ( ) ; } } param left param right param equaler category export function endsWith < T > ( left , right , equaler ? ) ; param left param right param equaler category export function endsWith < T , U > ( left , right , equaler ) ; export function endsWith < T > ( left , right , equaler = Equaler . defaultEqualer ) { if ( typeof equaler === "function" ) equaler = Equaler . create ( equaler ) ; assert . mustBeIterableObject ( left , "left" ) ; assert . mustBeIterableObject ( right , "right" ) ; assert . mustBeType ( Equaler . hasInstance , equaler , "equaler" ) ; const rightArray = toArray ( right ) ; const numElements = rightArray . length ; if ( numElements <= 0 ) { return true ; } const leftArray = toArray ( takeRight ( left , numElements ) ) ; if ( leftArray . length < numElements ) { return false ; } for ( let i = 0 ; i < numElements ; i ++ ) { if ( ! equaler . equals ( leftArray [ i ] , rightArray [ i ] ) ) { return false ; } } return true ; } param source param value param equaler category export function includes < T > ( source , value , equaler ? ) ; param source param value param equaler category export function includes < T , U > ( source , value , equaler ) ; export function includes < T > ( source , value , equaler = Equaler . defaultEqualer ) { if ( typeof equaler === "function" ) equaler = Equaler . create ( equaler ) ; assert . mustBeIterableObject ( source , "source" ) ; assert . mustBeType ( Equaler . hasInstance , equaler , "equaler" ) ; for ( const element of source ) { if ( equaler . equals ( value , element ) ) { return true ; } } return false ; } param left param right param equaler category export function includesSequence < T > ( left , right , equaler ? ) ; param left param right param equaler category export function includesSequence < T , U > ( left , right , equaler ) ; export function includesSequence < T > ( left , right , equaler = Equaler . defaultEqualer ) { if ( typeof equaler === "function" ) equaler = Equaler . create ( equaler ) ; assert . mustBeIterableObject ( left , "source" ) ; assert . mustBeIterableObject ( right , "other" ) ; assert . mustBeType ( Equaler . hasInstance , equaler , "equaler" ) ; const rightArray = toArray ( right ) ; const numRightElements = rightArray . length ; if ( numRightElements <= 0 ) { return true ; } const span = [ ] ; for ( const leftValue of left ) { for ( ; ; ) { const rightValue = rightArray [ span . length ] ; if ( equaler . equals ( leftValue , rightValue ) ) { if ( span . length + 1 >= numRightElements ) { return true ; } span . push ( leftValue ) ; } else if ( span . length > 0 ) { span . shift ( ) ; continue ; } break ; } } return false ; } class ArrayWrapper < T > { constructor ( private array ) { } get [ IndexedCollection . size ] ( ) : number { return this . array . length ; } [ IndexedCollection . setAt ] ( index , value ) { this . array [ index ] = value ; return true ; } } param source param collection param start param count category export function copyTo < T , U extends IndexedCollection < T > | T [ ] > ( source , collection , start = 0 , count ? ) { const target = IndexedCollection . hasInstance ( collection ) ? collection : Array . isArray ( collection ) ? new ArrayWrapper < T > ( collection ) : undefined ; assert . mustBeIterableObject ( source , "source" ) ; assert . assertType ( target !== undefined , "dest" , undefined ) ; assert . mustBePositiveInteger ( start , "start" ) ; const size = target [ IndexedCollection . size ] ; if ( count !== undefined ) { assert . mustBePositiveInteger ( count , "count" ) ; } else { count = size - start ; } assert . assertRange ( start + count <= size , "count" ) ; if ( count > 0 ) { for ( const element of source ) { if ( count > 0 ) { target [ IndexedCollection . setAt ] ( start ++ , element ) ; count -- ; } else { break ; } } } return collection ; }