/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ 'use strict'; export interface IteratorResult { readonly done: boolean; readonly value: T | undefined; } export interface Iterator { next(): IteratorResult; } export module Iterator { const _empty: Iterator = { next() { return { done: true, value: undefined }; } }; export function empty(): Iterator { return _empty; } export function iterate(array: T[], index = 0, length = array.length): Iterator { return { next(): IteratorResult { if (index >= length) { return { done: true, value: undefined }; } return { done: false, value: array[index++] }; } }; } export function map(iterator: Iterator, fn: (t: T) => R): Iterator { return { next() { const { done, value } = iterator.next(); return { done, value: done ? undefined : fn(value) }; } }; } export function filter(iterator: Iterator, fn: (t: T) => boolean): Iterator { return { next() { while (true) { const { done, value } = iterator.next(); if (done) { return { done, value: undefined }; } if (fn(value)) { return { done, value }; } } } }; } export function forEach(iterator: Iterator, fn: (t: T) => void): void { for (let next = iterator.next(); !next.done; next = iterator.next()) { fn(next.value); } } export function collect(iterator: Iterator): T[] { const result: T[] = []; forEach(iterator, value => result.push(value)); return result; } } export type ISequence = Iterator | T[]; export function getSequenceIterator(arg: Iterator | T[]): Iterator { if (Array.isArray(arg)) { return Iterator.iterate(arg); } else { return arg; } } export interface INextIterator { next(): T; } export class ArrayIterator implements INextIterator { private items: T[]; protected start: number; protected end: number; protected index: number; constructor(items: T[], start: number = 0, end: number = items.length, index = start - 1) { this.items = items; this.start = start; this.end = end; this.index = index; } public first(): T { this.index = this.start; return this.current(); } public next(): T { this.index = Math.min(this.index + 1, this.end); return this.current(); } protected current(): T { if (this.index === this.start - 1 || this.index === this.end) { return null; } return this.items[this.index]; } } export class ArrayNavigator extends ArrayIterator implements INavigator { constructor(items: T[], start: number = 0, end: number = items.length, index = start - 1) { super(items, start, end, index); } public current(): T { return super.current(); } public previous(): T { this.index = Math.max(this.index - 1, this.start - 1); return this.current(); } public first(): T { this.index = this.start; return this.current(); } public last(): T { this.index = this.end - 1; return this.current(); } public parent(): T { return null; } } export class MappedIterator implements INextIterator { constructor(protected iterator: INextIterator, protected fn: (item: T) => R) { // noop } next() { return this.fn(this.iterator.next()); } } export interface INavigator extends INextIterator { current(): T; previous(): T; parent(): T; first(): T; last(): T; next(): T; } export class MappedNavigator extends MappedIterator implements INavigator { constructor(protected navigator: INavigator, fn: (item: T) => R) { super(navigator, fn); } 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()); } }