iterator.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /**
  2. * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. /**
  7. * "Idiomatic" usage:
  8. *
  9. * const it = ...;
  10. * while (it.hasNext) { const v = it.move(); ... }
  11. */
  12. interface Iterator<T> {
  13. readonly hasNext: boolean,
  14. move(): T
  15. }
  16. class ArrayIteratorImpl<T> implements Iterator<T> {
  17. private xs: ArrayLike<T> = [];
  18. private index: number = -1;
  19. private length: number = 0;
  20. private lastValue: T;
  21. hasNext: boolean = false;
  22. move() {
  23. ++this.index;
  24. this.lastValue = this.xs[this.index];
  25. this.hasNext = this.index < this.length - 1;
  26. return this.lastValue;
  27. }
  28. constructor(xs: ArrayLike<T>) {
  29. this.length = xs.length;
  30. this.hasNext = xs.length > 0;
  31. this.xs = xs;
  32. this.index = -1;
  33. // try to avoid deoptimization with undefined values
  34. this.lastValue = xs.length > 0 ? xs[0] : void 0 as any;
  35. }
  36. }
  37. class RangeIteratorImpl implements Iterator<number> {
  38. private value: number = 0;
  39. hasNext: boolean = false;
  40. move() {
  41. ++this.value;
  42. this.hasNext = this.value < this.max;
  43. return this.value;
  44. }
  45. constructor(min: number, private max: number) {
  46. this.value = min - 1;
  47. this.hasNext = max >= min;
  48. }
  49. }
  50. class ValueIterator<T> implements Iterator<T> {
  51. hasNext = true;
  52. move() { this.hasNext = false; return this.value; }
  53. constructor(private value: T) { }
  54. }
  55. class MapIteratorImpl<T, R> implements Iterator<R> {
  56. hasNext: boolean = false;
  57. move() {
  58. const v = this.f(this.base.move());
  59. this.hasNext = this.base.hasNext;
  60. return v;
  61. }
  62. constructor(private base: Iterator<T>, private f: (v: T) => R) {
  63. this.hasNext = base.hasNext;
  64. }
  65. }
  66. class FilterIteratorImpl<T> implements Iterator<T> {
  67. private next: T;
  68. hasNext: boolean;
  69. move() {
  70. const ret = this.next;
  71. this.hasNext = this.findNext();
  72. return ret;
  73. }
  74. private findNext() {
  75. while (this.base.hasNext) {
  76. this.next = this.base.move();
  77. if (this.p(this.next)) return true;
  78. }
  79. return false;
  80. }
  81. constructor(private base: Iterator<T>, private p: (v: T) => boolean) {
  82. this.hasNext = this.findNext();
  83. }
  84. }
  85. namespace Iterator {
  86. export const Empty: Iterator<any> = new RangeIteratorImpl(0, -1);
  87. export function Array<T>(xs: ArrayLike<T>): Iterator<T> { return new ArrayIteratorImpl<T>(xs); }
  88. export function Value<T>(value: T): Iterator<T> { return new ValueIterator(value); }
  89. export function Range(min: number, max: number): Iterator<number> { return new RangeIteratorImpl(min, max); }
  90. export function map<T, R>(base: Iterator<T>, f: (v: T) => R): Iterator<R> { return new MapIteratorImpl(base, f); }
  91. export function filter<T>(base: Iterator<T>, p: (v: T) => boolean): Iterator<T> { return new FilterIteratorImpl(base, p); }
  92. // Iterate until first truthy value is returned.
  93. export function forEach<T, Ctx>(it: Iterator<T>, f: (v: T, ctx: Ctx) => any, ctx: Ctx): Ctx {
  94. while (it.hasNext) {
  95. const c = f(it.move(), ctx);
  96. if (c) return ctx;
  97. }
  98. return ctx;
  99. }
  100. }
  101. export default Iterator