ts-data-forge
Version:
[](https://www.npmjs.com/package/ts-data-forge) [](https://www.npmjs.com/package/ts-data-forge) [ • 8.66 kB
JavaScript
import { none } from '../functional/optional/impl/optional-none.mjs';
import { some } from '../functional/optional/impl/optional-some.mjs';
import '@sindresorhus/is';
import { range } from '../iterator/range.mjs';
import '../number/branded-types/finite-number.mjs';
import '../number/branded-types/int.mjs';
import '../number/branded-types/int16.mjs';
import '../number/branded-types/int32.mjs';
import '../number/branded-types/non-negative-finite-number.mjs';
import '../number/branded-types/non-negative-int16.mjs';
import '../number/branded-types/non-negative-int32.mjs';
import '../number/branded-types/non-zero-finite-number.mjs';
import '../number/branded-types/non-zero-int.mjs';
import '../number/branded-types/non-zero-int16.mjs';
import '../number/branded-types/non-zero-int32.mjs';
import '../number/branded-types/non-zero-safe-int.mjs';
import '../number/branded-types/non-zero-uint16.mjs';
import '../number/branded-types/non-zero-uint32.mjs';
import '../number/branded-types/positive-finite-number.mjs';
import '../number/branded-types/positive-int.mjs';
import '../number/branded-types/positive-int16.mjs';
import '../number/branded-types/positive-int32.mjs';
import '../number/branded-types/positive-safe-int.mjs';
import '../number/branded-types/positive-uint16.mjs';
import '../number/branded-types/positive-uint32.mjs';
import '../number/branded-types/safe-int.mjs';
import { asSafeUint } from '../number/branded-types/safe-uint.mjs';
import '../number/branded-types/uint.mjs';
import '../number/branded-types/uint16.mjs';
import { asUint32 } from '../number/branded-types/uint32.mjs';
import '../number/enum/int8.mjs';
import '../number/enum/uint8.mjs';
import '../number/num.mjs';
import '../number/refined-number-utils.mjs';
/**
* Class implementation for a queue with FIFO (First-In, First-Out) behavior
* using a circular buffer. This implementation provides O(1) enqueue and
* dequeue operations by using a fixed-size buffer with head and tail pointers
* that wrap around when they reach the buffer boundary.
*
* The circular buffer automatically resizes when it becomes full, ensuring that
* the queue can grow to accommodate any number of elements while maintaining
* efficient operations.
*
* @template T The type of elements in the queue.
* @implements Queue
*/
class QueueClass {
/** @internal Circular buffer to store queue elements. */
#buffer;
/** @internal Index of the first element (front of queue). */
#head;
/** @internal Index where the next element will be added (back of queue). */
#tail;
/** @internal Current number of elements in the queue. */
#mut_size;
/** @internal Current capacity of the buffer. */
#capacity;
/** @internal Initial capacity for new queues. */
static #INITIAL_CAPACITY = 8;
/**
* Constructs a new QueueClass instance.
*
* @param initialValues Optional initial values to populate the queue.
*/
constructor(initialValues = []) {
const initialCapacity = asUint32(Math.max(QueueClass.#INITIAL_CAPACITY, initialValues.length * 2));
this.#buffer = Array.from({ length: initialCapacity }, () => undefined);
this.#head = 0;
this.#tail = 0;
this.#mut_size = 0;
this.#capacity = initialCapacity;
// Add initial values
for (const value of initialValues) {
this.enqueue(value);
}
}
/** @inheritdoc */
get isEmpty() {
return this.#mut_size === 0;
}
/** @inheritdoc */
get size() {
return asUint32(this.#mut_size);
}
/**
* Removes and returns the element at the front of the queue (FIFO).
*
* This operation removes the element that was added earliest (first-in) and
* returns it. If the queue is empty, returns `Optional.none`. The operation
* is guaranteed to be O(1) and does not require any array shifting or
* copying.
*
* **Time Complexity:** O(1) - constant time operation **Space Complexity:**
* O(1) - no additional memory allocation
*
* @returns An Optional containing the removed element, or `Optional.none` if
* the queue is empty.
*/
dequeue() {
if (this.isEmpty) {
return none;
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const element = this.#buffer[this.#head];
this.#buffer[this.#head] = undefined; // Clear reference for garbage collection
this.#head = (this.#head + 1) % this.#capacity;
this.#mut_size -= 1;
return some(element);
}
/**
* Adds an element to the back of the queue (FIFO).
*
* This operation adds the element to the end of the queue, where it will be
* the last to be dequeued (first-in, first-out ordering). The operation is
* amortized O(1), meaning it's O(1) for most operations with occasional O(n)
* when the buffer needs resizing.
*
* **Time Complexity:** O(1) amortized - O(n) only when buffer resize is
* needed **Space Complexity:** O(1) - constant additional memory per element
*
* **Buffer Resizing:** When the internal buffer becomes full, it
* automatically doubles in size and reorganizes elements to maintain the
* circular buffer structure.
*
* @param value The element to add to the back of the queue.
*/
enqueue(value) {
// Resize if buffer is full
if (this.#mut_size === this.#capacity) {
this.#resize();
}
this.#buffer[this.#tail] = value;
this.#tail = (this.#tail + 1) % this.#capacity;
this.#mut_size += 1;
}
/**
* @internal
* Resizes the circular buffer when it becomes full.
* Doubles the capacity and reorganizes elements to maintain queue order.
*/
#resize() {
const newCapacity = asUint32(this.#capacity * 2);
const newBuffer = Array.from({ length: newCapacity }, () => undefined);
// Copy elements in order from head to tail
for (const i of range(asSafeUint(this.#mut_size))) {
const sourceIndex = (this.#head + i) % this.#capacity;
newBuffer[i] = this.#buffer[sourceIndex];
}
this.#buffer = newBuffer;
this.#head = 0;
this.#tail = this.#mut_size;
this.#capacity = newCapacity;
}
}
/**
* Creates a new Queue instance with FIFO (First-In, First-Out) behavior using a
* high-performance circular buffer.
*
* This factory function creates an optimized queue implementation that
* maintains excellent performance characteristics for both enqueue and dequeue
* operations. The underlying circular buffer automatically resizes to
* accommodate growing workloads while providing predictable O(1) operations.
*
* **Implementation Features:**
*
* - **O(1) enqueue operations** (amortized - occasionally O(n) when resizing)
* - **O(1) dequeue operations** (always)
* - **Automatic buffer resizing** - starts at 8 elements, doubles when full
* - **Memory efficient** - garbage collects removed elements immediately
* - **Circular buffer design** - eliminates need for array shifting operations
*
* **Performance Benefits:**
*
* - No array copying during normal operations
* - Minimal memory allocation overhead
* - Predictable performance under high load
* - Efficient memory usage with automatic cleanup
*
* @example
*
* ```ts
* const queue = createQueue<number>();
*
* assert.isTrue(queue.isEmpty);
*
* assert.isTrue(queue.size === 0);
*
* queue.enqueue(1);
*
* queue.enqueue(2);
*
* assert.isFalse(queue.isEmpty);
*
* assert.isTrue(queue.size === 2);
*
* assert.deepStrictEqual(queue.dequeue(), Optional.some(1));
*
* assert.deepStrictEqual(queue.dequeue(), Optional.some(2));
*
* assert.deepStrictEqual(queue.dequeue(), Optional.none);
*
* const seededQueue = createQueue(['first', 'second']);
*
* assert.isTrue(seededQueue.size === 2);
*
* assert.deepStrictEqual(seededQueue.dequeue(), Optional.some('first'));
*
* assert.deepStrictEqual(seededQueue.dequeue(), Optional.some('second'));
* ```
*
* @template T The type of elements stored in the queue.
* @param initialValues Optional array of initial elements to populate the
* queue. Elements will be dequeued in the same order they appear in the
* array. If provided, the initial buffer capacity will be at least twice the
* array length.
* @returns A new Queue instance optimized for high-performance FIFO operations.
*/
const createQueue = (initialValues) => new QueueClass(initialValues);
export { createQueue };
//# sourceMappingURL=queue.mjs.map