util_data_chain.js

/**
 * @module Chain
 * @fileoverview Contains Chain class.
 */

/**
 * @class
 * Node for Chain. Represents a single chain link that holds data.
 */
class ChainNode {
    /**
     * Create a new ChainNode.
     * @param {any} val Value of node
     * @param {ChainNode|null} prev (Optional) Previous node in chain
     * @param {ChainNode|null} next (Optional) Next node in chain
     * @constructor
     */
    constructor(val, prev = null, next = null) {
        this.val = val;

        this.prev = prev;
        this.next = next;
    }
}

/**
 * @class
 * Basic chained data structure. Essentially a linked list.
 */
class Chain {
    /**
     * Create a new Chain.
     * @param {any[]} items (Optional) Items to add
     * @constructor
     */
    constructor(items = []) {
        this._front = null;
        this._back = null;

        for (const item of items)
            this.addBack(item);
    }

    /**
     * Add an item to the end of the Chain.
     * @param {any} item Item to add
     */
    addBack(item) {
        const node = new ChainNode(item);

        if (this._front === null) {
            this._front = node;
            this._back = node;
        } else {
            this._back.next = node;
            this._back = node;
        }
    }

    /**
     * Add an item to the beginning of the Chain.
     * @param {any} item Item to add
     */
    addFront(item) {
        const node = new ChainNode(item);

        if (this._front === null) {
            this._front = node;
            this._back = node;
        } else {
            this._front.prev = node;
            this._front = node;
        }
    }

    /**
     * Remove the last item in the Chain.
     */
    removeBack() {
        if (this._front === this._back)
            this._front = null;

        this._back = this._back.prev;
    }

    /**
     * Remove the first item in the Chain.
     */
    removeFront() {
        if (this._front === this._back)
            this._back = null;

        this._front = this._front.next;
    }

    /**
     * Remove and return the last item in the Chain.
     * @returns Removed item
     */
    popBack() {
        const val = this._back.val;
        this.removeBack();

        return val;
    }

    /**
     * Remove and return the first item in the Chain.
     * @returns Removed item
     */
    popFront() {
        const val = this._front.val;
        this.removeFront();

        return val;
    }

    /**
     * Remove all items from the Chain.
     */
    clear() {
        this._front = null;
        this._back = null;
    }
}

export default Chain;