Home Reference Source

src/core/Queue.js

/**
 * A FIFO queue.
 *
 * Elements are added to the end of the queue and removed from the front.
 *
 * Based on:
 *  http://code.stephenmorley.org/javascript/queues/
 */

export class Queue {

	/**
	 * Constructs a new queue.
	 */

	constructor() {

		/**
		 * A list of elements.
		 *
		 * @type {Array}
		 */

		this.elements = [];

		/**
		 * The head of the queue.
		 *
		 * @type {Number}
		 */

		this.head = 0;

	}

	/**
	 * The current size of the queue.
	 *
	 * @type {Number}
	 */

	get size() {

		return (this.elements.length - this.head);

	}

	/**
	 * Returns true if the queue is empty, and false otherwise.
	 *
	 * @type {Boolean}
	 */

	get empty() {

		return (this.elements.length === 0);

	}

	/**
	 * Copies the given queue.
	 *
	 * @param {Queue} queue - A queue.
	 * @return {Queue} This queue.
	 */

	copy(queue) {

		this.elements = Array.from(queue.elements);
		this.head = queue.head;

		return this;

	}

	/**
	 * Clones this queue.
	 *
	 * @return {Queue} Th cloned queue.
	 */

	clone() {

		return new this.constructor().copy(this);

	}

	/**
	 * Adds an element to the queue.
	 *
	 * @param {Object} element - An arbitrary object.
	 */

	add(element) {

		this.elements.push(element);

	}

	/**
	 * Retrieves, but does not remove, the head of the queue.
	 *
	 * @return {Object} The head of the queue, or undefined if the queue is empty.
	 */

	peek() {

		return (this.elements.length > 0) ? this.elements[this.head] : undefined;

	}

	/**
	 * Retrieves and removes the head of the queue.
	 *
	 * @return {Object} The head of the queue, or undefined if the queue is empty.
	 */

	poll() {

		const elements = this.elements;
		const length = elements.length;

		let element;

		if(length > 0) {

			element = elements[this.head++];

			// Remove free space if necessary.
			if(this.head * 2 >= length) {

				this.elements = elements.slice(this.head);
				this.head = 0;

			}

		}

		return element;

	}

	/**
	 * Resets this queue.
	 */

	clear() {

		this.elements = [];
		this.head = 0;

	}

}