fix: add missing exports
[poolifier.git] / src / priority-queue.ts
CommitLineData
95d1a734
JB
1// Copyright Jerome Benoit. 2024. All Rights Reserved.
2
9df282a0
JB
3import { FixedPriorityQueue } from './fixed-priority-queue.js'
4
5/**
6 * Default bucket size.
7 */
8export const defaultBucketSize = 2048
9
bcfb06ce 10/**
95d1a734
JB
11 * Priority queue node.
12 *
13 * @typeParam T - Type of priority queue node data.
bcfb06ce
JB
14 * @internal
15 */
9df282a0
JB
16export interface PriorityQueueNode<T> extends FixedPriorityQueue<T> {
17 next?: FixedPriorityQueue<T>
bcfb06ce
JB
18}
19
20/**
95d1a734 21 * Priority queue.
bcfb06ce
JB
22 *
23 * @typeParam T - Type of priority queue data.
24 * @internal
25 */
26export class PriorityQueue<T> {
9df282a0
JB
27 private head!: PriorityQueueNode<T>
28 private tail!: PriorityQueueNode<T>
2107bc57 29 private readonly bucketSize: number
bcfb06ce
JB
30 public maxSize!: number
31
bd8b441c 32 /**
95d1a734 33 * Constructs a priority queue.
bd8b441c 34 *
9df282a0
JB
35 * @param bucketSize - Prioritized bucket size. @defaultValue defaultBucketSize
36 * @returns PriorityQueue.
bd8b441c 37 */
9df282a0 38 public constructor (bucketSize: number = defaultBucketSize) {
e75373e6
JB
39 if (!Number.isSafeInteger(bucketSize)) {
40 throw new TypeError('bucketSize must be an integer')
41 }
42 if (bucketSize < 1) {
43 throw new RangeError('bucketSize must be greater than or equal to 1')
44 }
2107bc57 45 this.bucketSize = bucketSize
e41b0271 46 this.clear()
bcfb06ce
JB
47 }
48
e75373e6
JB
49 /**
50 * The size of the priority queue.
51 */
9df282a0
JB
52 public get size (): number {
53 let node: PriorityQueueNode<T> | undefined = this.tail
54 let size = 0
55 while (node != null) {
56 size += node.size
57 node = node.next
58 }
59 return size
60 }
61
e75373e6
JB
62 /**
63 * The number of filled prioritized buckets.
64 */
65 public get buckets (): number {
66 return Math.trunc(this.size / this.bucketSize)
67 }
68
bcfb06ce
JB
69 /**
70 * Enqueue data into the priority queue.
71 *
72 * @param data - Data to enqueue.
73 * @param priority - Priority of the data. Lower values have higher priority.
74 * @returns The new size of the priority queue.
75 */
76 public enqueue (data: T, priority?: number): number {
9df282a0
JB
77 if (this.head.full()) {
78 this.head = this.head.next = new FixedPriorityQueue(this.bucketSize)
bcfb06ce 79 }
9df282a0
JB
80 this.head.enqueue(data, priority)
81 const size = this.size
82 if (size > this.maxSize) {
83 this.maxSize = size
bcfb06ce 84 }
9df282a0 85 return size
bcfb06ce
JB
86 }
87
88 /**
89 * Dequeue data from the priority queue.
90 *
9df282a0 91 * @param bucket - The prioritized bucket to dequeue from.
bcfb06ce
JB
92 * @returns The dequeued data or `undefined` if the priority queue is empty.
93 */
9df282a0
JB
94 public dequeue (bucket?: number): T | undefined {
95 let tail: PriorityQueueNode<T> | undefined = this.tail
96 if (bucket != null) {
97 let currentBucket = 0
98 while (tail != null) {
99 ++currentBucket
100 if (currentBucket === bucket) {
101 break
95d1a734 102 }
9df282a0 103 tail = tail.next
95d1a734
JB
104 }
105 }
9df282a0
JB
106 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
107 const data = tail!.dequeue()
108 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
109 if (tail!.empty() && tail!.next != null) {
110 if (tail === this.tail) {
111 this.tail = tail.next
112 } else {
113 let node: PriorityQueueNode<T> | undefined = this.tail
114 while (node != null) {
115 if (node.next === tail) {
116 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
117 node.next = tail!.next
118 break
119 }
120 node = node.next
121 }
122 }
123 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
124 delete tail!.next
125 }
126 return data
bcfb06ce
JB
127 }
128
129 /**
130 * Clears the priority queue.
131 */
132 public clear (): void {
9df282a0 133 this.head = this.tail = new FixedPriorityQueue(this.bucketSize)
bcfb06ce
JB
134 this.maxSize = 0
135 }
136
137 /**
95d1a734
JB
138 * Returns an iterator for the priority queue.
139 *
2be9b405 140 * @returns An iterator for the priority queue.
95d1a734
JB
141 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
142 */
9df282a0 143 public [Symbol.iterator] (): Iterator<T> {
95d1a734 144 let i = 0
9df282a0 145 let node = this.tail
95d1a734
JB
146 return {
147 next: () => {
9df282a0 148 if (node.empty() || (i >= node.capacity && node.next == null)) {
95d1a734
JB
149 return {
150 value: undefined,
151 done: true
152 }
153 }
9df282a0
JB
154 const value = node.dequeue() as T
155 ++i
156 if (i === node.capacity && node.next != null) {
157 node = node.next
158 i = 0
159 }
95d1a734
JB
160 return {
161 value,
162 done: false
163 }
164 }
165 }
166 }
bcfb06ce 167}