Merge dependabot/npm_and_yarn/examples/typescript/websocket-server-pool/ws-cluster...
[poolifier.git] / src / priority-queue.ts
index cf4fb150e1e1caba20ff9e9d579128c110c40e73..8e9c1ae2db52fb4eba012fcc27be33d48b7e2885 100644 (file)
@@ -1,13 +1,18 @@
+// Copyright Jerome Benoit. 2024. All Rights Reserved.
+
 /**
+ * Priority queue node.
+ *
+ * @typeParam T - Type of priority queue node data.
  * @internal
  */
-interface PriorityQueueNode<T> {
+export interface PriorityQueueNode<T> {
   data: T
   priority: number
 }
 
 /**
- * k-priority queue.
+ * Priority queue.
  *
  * @typeParam T - Type of priority queue data.
  * @internal
@@ -15,25 +20,34 @@ interface PriorityQueueNode<T> {
 export class PriorityQueue<T> {
   private nodeArray!: Array<PriorityQueueNode<T>>
   /** Prioritized bucket size. */
-  private readonly k: number
+  private readonly bucketSize: number
   /** The size of the priority queue. */
   public size!: number
   /** The maximum size of the priority queue. */
   public maxSize!: number
 
   /**
-   * Constructs a k-priority queue.
+   * The number of filled prioritized buckets.
+   */
+  public get buckets (): number {
+    return this.bucketSize === Infinity
+      ? 1
+      : Math.trunc(this.nodeArray.length / this.bucketSize)
+  }
+
+  /**
+   * Constructs a priority queue.
    *
-   * @param k - Prioritized bucket size.
+   * @param bucketSize - Prioritized bucket size. @defaultValue Infinity
    */
-  public constructor (k = Infinity) {
-    if (k !== Infinity && !Number.isSafeInteger(k)) {
-      throw new TypeError('k must be an integer')
+  public constructor (bucketSize = Infinity) {
+    if (bucketSize !== Infinity && !Number.isSafeInteger(bucketSize)) {
+      throw new TypeError('bucketSize must be an integer')
     }
-    if (k < 1) {
-      throw new RangeError('k must be greater than or equal to 1')
+    if (bucketSize < 1) {
+      throw new RangeError('bucketSize must be greater than or equal to 1')
     }
-    this.k = k
+    this.bucketSize = bucketSize
     this.clear()
   }
 
@@ -47,9 +61,7 @@ export class PriorityQueue<T> {
   public enqueue (data: T, priority?: number): number {
     priority = priority ?? 0
     const startIndex =
-      this.k === Infinity || this.nodeArray.length / this.k < 1
-        ? 0
-        : Math.trunc(this.nodeArray.length / this.k) * this.k
+      this.bucketSize === Infinity ? 0 : this.buckets * this.bucketSize
     let inserted = false
     for (let index = startIndex; index < this.nodeArray.length; index++) {
       if (this.nodeArray[index].priority > priority) {
@@ -67,12 +79,22 @@ export class PriorityQueue<T> {
   /**
    * Dequeue data from the priority queue.
    *
+   * @param bucket - The prioritized bucket to dequeue from. @defaultValue 0
    * @returns The dequeued data or `undefined` if the priority queue is empty.
    */
-  public dequeue (): T | undefined {
-    if (this.size > 0) {
-      --this.size
+  public dequeue (bucket = 0): T | undefined {
+    if (this.bucketSize !== Infinity && bucket > 0) {
+      while (bucket > 0) {
+        const index = bucket * this.bucketSize
+        // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+        if (this.nodeArray[index] != null) {
+          --this.size
+          return this.nodeArray.splice(index, 1)[0].data
+        }
+        --bucket
+      }
     }
+    this.decrementSize()
     return this.nodeArray.shift()?.data
   }
 
@@ -102,9 +124,35 @@ export class PriorityQueue<T> {
   }
 
   /**
-   * Increments the size of the deque.
+   * Returns an iterator for the priority queue.
    *
-   * @returns The new size of the deque.
+   * @returns An iterator for the priority queue.
+   * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
+   */
+  [Symbol.iterator] (): Iterator<T> {
+    let i = 0
+    return {
+      next: () => {
+        if (i >= this.nodeArray.length) {
+          return {
+            value: undefined,
+            done: true
+          }
+        }
+        const value = this.nodeArray[i].data
+        i++
+        return {
+          value,
+          done: false
+        }
+      }
+    }
+  }
+
+  /**
+   * Increments the size of the priority queue.
+   *
+   * @returns The new size of the priority queue.
    */
   private incrementSize (): number {
     ++this.size
@@ -113,4 +161,16 @@ export class PriorityQueue<T> {
     }
     return this.size
   }
+
+  /**
+   * Decrements the size of the priority queue.
+   *
+   * @returns The new size of the priority queue.
+   */
+  private decrementSize (): number {
+    if (this.size > 0) {
+      --this.size
+    }
+    return this.size
+  }
 }