c8cb84f02bd083feb856dce5a2c9de759f307fea
1 // Copyright Jerome Benoit. 2024. All Rights Reserved.
3 import { FixedPriorityQueue
} from
'./fixed-priority-queue.js'
4 import { FixedQueue
} from
'./fixed-queue.js'
9 type PriorityQueueNode
,
10 } from
'./queue-types.js'
14 * @typeParam T - Type of priority queue data.
17 export class PriorityQueue
<T
> {
18 private readonly bucketSize
: number
19 private head
!: PriorityQueueNode
<T
>
20 private priorityEnabled
: boolean
21 private tail
!: PriorityQueueNode
<T
>
22 /** The priority queue maximum size. */
23 public maxSize
!: number
26 * Constructs a priority queue.
27 * @param bucketSize - Prioritized bucket size. @defaultValue defaultBucketSize
28 * @param enablePriority - Whether to enable priority. @defaultValue false
29 * @returns PriorityQueue.
32 bucketSize
: number = defaultBucketSize
,
33 enablePriority
= false
35 if (!Number.isSafeInteger(bucketSize
)) {
37 `Invalid bucket size: '${bucketSize.toString()}' is not an integer`
41 throw new RangeError(`Invalid bucket size: ${bucketSize.toString()} < 0`)
43 this.bucketSize
= bucketSize
44 this.priorityEnabled
= enablePriority
48 private getPriorityQueueNode (
49 nodeArray
?: FixedQueueNode
<T
>[]
50 ): PriorityQueueNode
<T
> {
51 let fixedQueue
: IFixedQueue
<T
>
52 if (this.priorityEnabled
) {
53 fixedQueue
= new FixedPriorityQueue(this.bucketSize
)
55 fixedQueue
= new FixedQueue(this.bucketSize
)
57 if (nodeArray
!= null) {
58 fixedQueue
.nodeArray
= nodeArray
64 * Clears the priority queue.
66 public clear (): void {
67 this.head
= this.tail
= this.getPriorityQueueNode()
72 * Dequeue data from the priority queue.
73 * @param bucket - The prioritized bucket to dequeue from.
74 * @returns The dequeued data or `undefined` if the priority queue is empty.
76 public dequeue (bucket
?: number): T
| undefined {
77 let tail
: PriorityQueueNode
<T
> | undefined = this.tail
78 let tailChanged
= false
79 if (bucket
!= null && bucket
> 0) {
81 while (tail
!= null) {
82 if (currentBucket
=== bucket
) {
88 tailChanged
= tail
!== this.tail
90 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
91 const data
= tail
!.dequeue()
92 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
94 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
95 if (!tailChanged
&& tail
!.next
!= null) {
96 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
97 this.tail
= tail
!.next
98 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
100 } else if (tailChanged
) {
101 let node
: PriorityQueueNode
<T
> | undefined = this.tail
102 while (node
!= null) {
103 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
104 if (node
.next
=== tail
&& tail
!.next
!= null) {
105 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
106 node
.next
= tail
!.next
107 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
110 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
111 } else if (node
.next
=== tail
&& tail
!.next
== null) {
124 * Enqueue data into the priority queue.
125 * @param data - Data to enqueue.
126 * @param priority - Priority of the data. Lower values have higher priority.
127 * @returns The new size of the priority queue.
129 public enqueue (data
: T
, priority
?: number): number {
130 if (this.head
.full()) {
131 this.head
= this.head
.next
= this.getPriorityQueueNode()
133 this.head
.enqueue(data
, priority
)
134 const size
= this.size
135 if (size
> this.maxSize
) {
142 * Returns an iterator for the priority queue.
143 * @returns An iterator for the priority queue.
144 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
146 public [Symbol
.iterator
] (): Iterator
<T
> {
151 const value
= node
.get(index
) as T
159 if (index
=== node
.capacity
&& node
.next
!= null) {
172 * The number of filled prioritized buckets.
173 * @returns The number of filled prioritized buckets.
175 public get
buckets (): number {
176 return Math.trunc(this.size
/ this.bucketSize
)
180 * Whether priority is enabled.
181 * @returns Whether priority is enabled.
183 public get
enablePriority (): boolean {
184 return this.priorityEnabled
188 * Enables/disables priority.
189 * @param enablePriority - Whether to enable priority.
191 public set
enablePriority (enablePriority
: boolean) {
192 if (this.priorityEnabled
=== enablePriority
) {
195 this.priorityEnabled
= enablePriority
196 let head
: PriorityQueueNode
<T
>
197 let tail
: PriorityQueueNode
<T
>
198 let prev
: PriorityQueueNode
<T
> | undefined
199 let node
: PriorityQueueNode
<T
> | undefined = this.tail
201 while (node
!= null) {
202 const currentNode
= this.getPriorityQueueNode(node
.nodeArray
)
207 prev
.next
= currentNode
210 if (node
.next
== null) {
216 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
218 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
223 * The priority queue size.
224 * @returns The priority queue size.
226 public get
size (): number {
227 let node
: PriorityQueueNode
<T
> | undefined = this.tail
229 while (node
!= null) {