All files / src/iterators danMatrixElementsIterator.ts

97.05% Statements 33/34
93.75% Branches 15/16
100% Functions 8/8
97.05% Lines 33/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 1205x         5x                             12x 6x   6x 6x             8x 8x                 165x 3x   162x 162x 162x     162x         162x                 125x 5x   120x 5x 5x 115x 90x   25x 25x   120x               169x             2x                 3x   3x   81x 81x 3x         78x                  
import { MatrixIterator, DanMatrix, DanMatrixElement, Coordinates } from '..';
 
/**
 * The class DanMatrixElementsIterator implements MatrixIterator interface and Iterable interface
 */
export class DanMatrixElementsIterator<T>
  implements MatrixIterator<DanMatrixElement<T>>, Iterable<DanMatrixElement<T>>
{
  // the matrix
  private _matrix: DanMatrix<T>;
  // index of the current row, or -1 if the iterator was not yet started
  private _rowIndex: number;
  // index of the current column, or -1 if the iterator was not yet started
  private _columnIndex: number;
 
  /**
   * The public class constructor
   * @param {DanMatrix<T>} matrix the DanMatrix object
   */
  public constructor(matrix: DanMatrix<T>) {
    if (!(matrix instanceof DanMatrix)) {
      throw new Error('Wrong input');
    }
    this._matrix = matrix;
    this._initFields();
  }
 
  /**
   * Init the class fields
   */
  private _initFields(): void {
    this._rowIndex = -1;
    this._columnIndex = -1;
  }
 
  /**
   * Get the current row, or return undefined if the iterator was not yet started
   * @returns {DanMatrixElement<T>|undefined}
   */
  current(): DanMatrixElement<T> | undefined {
    // the iterator was not yet started
    if (this._rowIndex < 0) {
      return undefined;
    }
    const currCoordinates = Coordinates.fromArrayCoords([this._rowIndex, this._columnIndex]);
    const currVal = this._matrix.get(currCoordinates);
    Iif (currVal === undefined) {
      return undefined;
    }
    const element: DanMatrixElement<T> = {
      coordinates: currCoordinates,
      danMatrix: this._matrix,
      val: currVal
    };
    return element;
  }
 
  /**
   * Get the next element, or return undefined if the iterator's end was reached
   * @returns {DanMatrixElement<T>|undefined}
   */
  next(): DanMatrixElement<T> | undefined {
    // return undefined if there are no elements left
    if (!this.hasNext()) {
      return undefined;
    }
    if (this._rowIndex < 0) {
      this._rowIndex = 0;
      this._columnIndex = 0;
    } else if (this._columnIndex < this._matrix.colsNum() - 1) {
      ++this._columnIndex;
    } else {
      ++this._rowIndex;
      this._columnIndex = 0;
    }
    return this.current();
  }
 
  /**
   * Check if the iterator can return more elements
   * @returns {boolean} true if the iterator can return more elements, false if there are no elements left
   */
  hasNext(): boolean {
    return this._rowIndex < this._matrix.rowsNum() - 1 || this._columnIndex < this._matrix.colsNum() - 1;
  }
 
  /**
   * Restart the iterator
   */
  rewind(): void {
    this._initFields();
  }
 
  /**
   * A zero-argument function that returns an object, conforming to the [Iterator Protocol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol).
   * In Javascript/Typescript in order to be iterable, an object must implement the "@@iterator" method
   * @returns {Iterator<DanMatrixElement<T>>} an iterator object.
   */
  [Symbol.iterator](): Iterator<DanMatrixElement<T>> {
    const iteratorInstance: DanMatrixElementsIterator<T> = this;
 
    return {
      next() {
        const nextElement = iteratorInstance.next();
        if (nextElement === undefined) {
          return {
            value: undefined,
            done: true
          };
        } else {
          return {
            value: nextElement,
            done: false
          };
        }
      }
    };
  }
}