export interface IteratorDefinedResult < T > { readonly done : false ; readonly value : T ; } export interface IteratorUndefinedResult { readonly done : true ; readonly value : undefined ; } export const FIN = { done : true , value : undefined } ; export type IteratorResult < T > = IteratorDefinedResult < T > | IteratorUndefinedResult ; export interface Iterator < T > { next ( ) : IteratorResult < T > ; } export module Iterator { const _empty = { next ( ) { return FIN ; } , } ; export function empty < T > ( ) { return _empty ; } export function fromArray < T > ( array , index = 0 , length = array . length ) { return { next ( ) { if ( index >= length ) { return FIN ; } return { done : false , value : array [ index ++ ] } ; } , } ; } export function from < T > ( elements ) { if ( ! elements ) { return Iterator . empty ( ) ; } else if ( Array . isArray ( elements ) ) { return Iterator . fromArray ( elements ) ; } else { return elements ; } } export function map < T , R > ( iterator , fn ) { return { next ( ) { const element = iterator . next ( ) ; if ( element . done ) { return FIN ; } else { return { done : false , value : fn ( element . value ) } ; } } , } ; } export function filter < T > ( iterator , fn ) { return { next ( ) { while ( true ) { const element = iterator . next ( ) ; if ( element . done ) { return FIN ; } if ( fn ( element . value ) ) { return { done : false , value : element . value } ; } } } , } ; } export function forEach < T > ( iterator , fn ) { for ( let next = iterator . next ( ) ; ! next . done ; next = iterator . next ( ) ) { fn ( next . value ) ; } } export function collect < T > ( iterator ) { const result = [ ] ; forEach ( iterator , ( value ) => result . push ( value ) ) ; return result ; } } export type ISequence < T > = Iterator < T > | T [ ] ; export function getSequenceIterator < T > ( arg ) { if ( Array . isArray ( arg ) ) { return Iterator . fromArray ( arg ) ; } else { return arg ; } } export interface INextIterator < T > { next ( ) : T | null ; } export class ArrayIterator < T > implements INextIterator < T > { private items : T [ ] ; protected start : number ; protected end : number ; protected index : number ; constructor ( items , start = 0 , end = items . length , index = start - 1 ) { this . items = items ; this . start = start ; this . end = end ; this . index = index ; } public first ( ) { this . index = this . start ; return this . current ( ) ; } public next ( ) { this . index = Math . min ( this . index + 1 , this . end ) ; return this . current ( ) ; } protected current ( ) { if ( this . index === this . start - 1 || this . index === this . end ) { return null ; } return this . items [ this . index ] ; } } export class ArrayNavigator < T > extends ArrayIterator < T > implements INavigator < T > { constructor ( items , start = 0 , end = items . length , index = start - 1 ) { super ( items , start , end , index ) ; } public current ( ) { return super . current ( ) ; } public previous ( ) { this . index = Math . max ( this . index - 1 , this . start - 1 ) ; return this . current ( ) ; } public first ( ) { this . index = this . start ; return this . current ( ) ; } public last ( ) { this . index = this . end - 1 ; return this . current ( ) ; } public parent ( ) { return null ; } } export class MappedIterator < T , R > implements INextIterator < R > { constructor ( protected iterator , protected fn ) { } next ( ) { return this . fn ( this . iterator . next ( ) ) ; } } export interface INavigator < T > extends INextIterator < T > { current ( ) : T | null ; previous ( ) : T | null ; parent ( ) : T | null ; first ( ) : T | null ; last ( ) : T | null ; next ( ) : T | null ; } export class MappedNavigator < T , R > extends MappedIterator < T , R > implements INavigator < R > { constructor ( protected navigator , fn ) { super ( navigator , fn as any ) ; } current ( ) { return this . fn ( this . navigator . current ( ) ) ; } previous ( ) { return this . fn ( this . navigator . previous ( ) ) ; } parent ( ) { return this . fn ( this . navigator . parent ( ) ) ; } first ( ) { return this . fn ( this . navigator . first ( ) ) ; } last ( ) { return this . fn ( this . navigator . last ( ) ) ; } next ( ) { return this . fn ( this . navigator . next ( ) ) ; } }