Home Reference Source

src/public/js-iterators.js

'use strict';

/* Containers are expected to support the following methods:
   jsBegin() - returns the very first node
   jsEnd() - returns the node beyond the last one
   next(node) - returns the next node
   prev(node) - returns the previous node
   valuePolicy - an instance of KeyOnlyPolicy, or KeyValuePolicy */
/**
  * ES6-style forward iterator.
  *
  * @example
  * let m = new TreeMap();
  * ...
  * for (let [key, value] of m) {
  *   console.log(`key: ${key}, value: ${value}`);
  * }
  * // iterate values
  * for (let value of m.values()) {
  *   console.log(`value: ${value}`);
  * }
  */
class JsIterator {
    /**
     * @param {*} container
     */
    constructor(container, valuePolicy = container.valuePolicy) {
        /**
         * @private
         * Internal reference to a container
         */
        this.container = container;
        /**
         * @private
         * valuePolicy implements what members of the node will be returned: key, value, or key and value
         */
        this.valuePolicy = valuePolicy;
        /**
         * @private
         * current node
         */
        this.node = container.jsBegin();
    }

    /**
     * As documented in ES6 iteration protocol. It can be used for manual iteration.
     * Iterators are documented here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
     *
     * @example
     * let m = new TreeMap();
     * ...
     * let jsIt = m.entries();
     * while (true) {
     *   let res = it.next();
     *   if (res.done) {
     *     break;
     *   }
     *   console.log(`key: ${res.value[0]}, value: ${res.value[1]`});
     * }
     */
    next() {
        let res = {};
        res.done = (this.node === this.container.jsEnd());
        if (!res.done) {
            res.value = this.valuePolicy.fetch(this.node);
            this.node = this.container.next(this.node);
        }
        return res;
    }

    /**
     * Support for ES6 for-of loops.
     * @returns {JsIterator}
     */
    [Symbol.iterator]() {
        return this;
    }

    /**
     * A reverse iterator for the same container.
     * @returns {JsReverseIterator}
     * @example
     * let m = new TreeMap();
     * ...
     * // iterate all key-value pairs in reverse order
     * for (let [key, value] of m.backwards()) {
     *   console.log(`key: ${key}, value: ${value}`);
     * }
    */
    backwards() {
        // eslint-disable-next-line no-use-before-define
        return new JsReverseIterator(this.container, this.valuePolicy);
    }
}

/* Containers are expected to support the following methods:
   jsRbegin() - returns the very first node in reverse order (e.g. the very last node)
   jsrEnd() - returns the node beyond the last one in reverse order (e.g. the node before the first one)
   next(node) - returns the next node
   prev(node) - returns the previous node
   valuePolicy - an instance of KeyOnlyPolicy, or KeyValuePolicy */
/**
  * ES6-style backward iterator
  * @example
  * let m = new TreeMap();
  * ...
  * // iterate all key-value pairs in reverse order
  * for (let [key, value] of m.backwards()) {
  *   console.log(`key: ${key}, value: ${value}`);
  * }
  * // iterate keys in reverse order
  * for (let key of m.keys().backwards()) {
  *   console.log(`key: ${key}`);
  * }
 */
class JsReverseIterator {
    /**
     * @param {*} container
     */
    constructor(container, valuePolicy = container.valuePolicy) {
        /**
         * @private
         * Internal reference to a container
         */
        this.container = container;
        /**
         * @private
         * valuePolicy implements what members of the node will be returned: key, value, or key and value
         */
        this.valuePolicy = valuePolicy;
        /**
         * @private
         * current node
         */
        this.node = container.jsRbegin();
    }

    /**
     * As documented in ES6 iteration protocol. It can be used for manual iteration.
     * Iterators are documented here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
     *
     * @example
     * let m = new TreeMap();
     * ...
     * let jsIt = m.entries().backwards();
     * while (true) {
     *   let res = it.next();
     *   if (res.done) {
     *     break;
     *   }
     *   console.log(`key: ${res.value[0]}, value: ${res.value[1]`});
     * }
     */
    next() {
        let res = {};
        res.done = (this.node === this.container.jsRend());
        if (!res.done) {
            res.value = this.valuePolicy.fetch(this.node);
            this.node = this.container.prev(this.node);
        }
        return res;
    }

    /**
     * Support for ES6 for-of loops.
     * @returns {JsReverseIterator}
     */
    [Symbol.iterator]() {
        return this;
    }

    /**
     * A forward iterator for the same container
     * @returns {JsIterator}
     * @example
     * let m = new TreeMap();
     * ...
     * // iterate all key-value pairs in direct order
     * for (let [key, value] of m.backwards().backwards()) {
     *   console.log(`key: ${key}, value: ${value}`);
     */
    backwards() {
        return new JsIterator(this.container, this.valuePolicy);
    }
}

module.exports = {
    JsIterator: JsIterator,
    JsReverseIterator: JsReverseIterator
};