import { DoublyLinkedList } from "./DoublyLinkedList"; export interface MutableQueue { /** * The '''maximum''' number of elements that a queue can hold. * * @note that unbounded queues can still implement this interface * with `capacity = MAX_NUMBER`. */ readonly capacity: number; /** * A non-blocking enqueue. * * @return whether the enqueue was successful or not. */ readonly offer: (a: A) => boolean; /** * A non-blocking dequeue. * * @return either an element from the queue, or the `default` * param. * * @note that if there's no meaningful default for your type, you * can always use `poll(undefined)`. Not the best, but reasonable price * to pay for lower heap churn. */ readonly poll: (a: A | undefined) => A | undefined; /** * @return the '''current''' number of elements inside the queue. * * @note that this method can be non-atomic and return the * approximate number in a concurrent setting. */ readonly size: number; /** * @return if the queue is empty */ readonly isEmpty: boolean; /** * @return if the queue is full */ readonly isFull: boolean; } export class Unbounded implements MutableQueue { private queue = new DoublyLinkedList(); get size() { return this.queue.length; } get isEmpty() { return this.size === 0; } get isFull() { return false; } get capacity() { return Number.MAX_SAFE_INTEGER; } offer(a: A) { this.queue.add(a); return true; } poll(a: A | undefined) { if (this.isEmpty) { return a; } return this.queue.shift(); } } export class Bounded implements MutableQueue { private queue = new DoublyLinkedList(); private n: number; constructor(n: number) { this.n = n; } get size() { return this.queue.length; } get isEmpty() { return this.size === 0; } get isFull() { return this.size === this.capacity; } get capacity() { return this.n; } offer(a: A) { if (this.isFull) { return false; } this.queue.add(a); return true; } poll(a: A | undefined) { if (this.isEmpty) { return a; } return this.queue.shift(); } }