UNPKG

ts-data-forge

Version:

[![npm version](https://img.shields.io/npm/v/ts-data-forge.svg)](https://www.npmjs.com/package/ts-data-forge) [![npm downloads](https://img.shields.io/npm/dm/ts-data-forge.svg)](https://www.npmjs.com/package/ts-data-forge) [![License](https://img.shields.

224 lines (221 loc) 8.66 kB
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