UNPKG

event-emitters

Version:
63 lines (55 loc) 1.83 kB
const INITIAL_CAPACITY = 16 /** * An efficient queue implemented with a circular buffer. It implements just enough * interface to be useful to EventEmitterAsyncIterator. */ export class Queue<T> { private buffer: Array<T | undefined> private headIndex = 0 private tailIndex = -1 // writing to this would corrupt the Queue but disallowing it would incur a performance hit length = 0 constructor(capacity = INITIAL_CAPACITY) { this.buffer = new Array(capacity) } enqueue(item: T): void { if (this.length === this.buffer.length) { const prevCapacity = this.buffer.length this.buffer.length *= 2 if (this.headIndex / prevCapacity <= 0.5) { if (this.headIndex !== 0) { // move elements before head after tail for (let i = 0; i < this.headIndex; ++i) { this.buffer[prevCapacity + i] = this.buffer[i] delete this.buffer[i] } this.tailIndex += prevCapacity } } else { for (let i = this.tailIndex + 1; i < prevCapacity; ++i) { this.buffer[prevCapacity + i] = this.buffer[i] delete this.buffer[i] } this.headIndex += prevCapacity } } this.tailIndex = (this.tailIndex + 1) % this.buffer.length this.buffer[this.tailIndex] = item ++this.length } dequeue(): T { if (this.length === 0) { throw new Error('Cannot dequeue from empty Queue') } --this.length // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const item = this.buffer[this.headIndex]! delete this.buffer[this.headIndex] this.headIndex = (this.headIndex + 1) % this.buffer.length return item } // clear the buffer and leave a corrupt useless buggy object remaining destroy(): void { this.buffer.length = 0 } }