refactor: refine circular buffer error message
[poolifier.git] / src / fixed-priority-queue.ts
CommitLineData
f8d5d8fd
JB
1/**
2 * Default buffer size.
3 */
4export const defaultQueueSize = 2048
5
6/**
7 * Priority queue node.
8 *
9 * @typeParam T - Type of priority queue node data.
10 * @internal
11 */
12export interface PriorityQueueNode<T> {
13 data: T
14 priority: number
15}
16
eadb37e2
JB
17/**
18 * Fixed priority queue.
19 *
20 * @typeParam T - Type of fixed priority queue data.
21 * @internal
22 */
f8d5d8fd
JB
23export class FixedPriorityQueue<T> {
24 private start!: number
25 private readonly nodeArray: Array<PriorityQueueNode<T>>
26 public size!: number
27 public maxSize!: number
28
29 constructor (size: number = defaultQueueSize) {
30 this.checkSize(size)
31 this.nodeArray = new Array<PriorityQueueNode<T>>(size)
32 this.clear()
33 }
34
35 public empty (): boolean {
36 return this.size === 0
37 }
38
39 public full (): boolean {
40 return this.size === this.nodeArray.length
41 }
42
43 public enqueue (data: T, priority?: number): number {
44 if (this.full()) {
45 throw new Error('Priority queue is full')
46 }
47 priority = priority ?? 0
eadb37e2 48 const nodeArrayLength = this.nodeArray.length
f8d5d8fd 49 let inserted = false
eadb37e2 50 for (let index = this.start; index < nodeArrayLength; index++) {
f8d5d8fd
JB
51 if (this.nodeArray[index]?.priority > priority) {
52 this.nodeArray.splice(index, 0, { data, priority })
53 inserted = true
54 break
55 }
56 }
eadb37e2
JB
57 this.nodeArray.length !== nodeArrayLength &&
58 (this.nodeArray.length = nodeArrayLength)
f8d5d8fd
JB
59 if (!inserted) {
60 let index = this.start + this.size
eadb37e2
JB
61 if (index >= nodeArrayLength) {
62 index -= nodeArrayLength
f8d5d8fd
JB
63 }
64 this.nodeArray[index] = { data, priority }
65 }
66 return this.incrementSize()
67 }
68
69 public dequeue (): T | undefined {
70 if (this.empty()) {
71 return undefined
72 }
73 const index = this.start
74 --this.size
75 ++this.start
76 if (this.start === this.nodeArray.length) {
77 this.start = 0
78 }
79 return this.nodeArray[index].data
80 }
81
82 /**
83 * Clears the fixed priority queue.
84 */
85 public clear (): void {
86 this.start = 0
87 this.size = 0
88 this.maxSize = 0
89 }
90
91 /**
92 * Returns an iterator for the fixed priority queue.
93 *
94 * @returns An iterator for the fixed priority queue.
95 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
96 */
97 [Symbol.iterator] (): Iterator<T> {
98 let i = this.start
99 return {
100 next: () => {
101 if (i >= this.size) {
102 return {
103 value: undefined,
104 done: true
105 }
106 }
107 const value = this.nodeArray[i].data
108 i++
109 return {
110 value,
111 done: false
112 }
113 }
114 }
115 }
116
117 /**
118 * Increments the size of the fixed priority queue.
119 *
120 * @returns The new size of the fixed priority queue.
121 */
122 private incrementSize (): number {
123 ++this.size
124 if (this.size > this.maxSize) {
125 this.maxSize = this.size
126 }
127 return this.size
128 }
129
130 private checkSize (size: number): void {
131 if (!Number.isSafeInteger(size)) {
132 throw new TypeError(
f45a8925 133 `Invalid fixed priority queue size: '${size}' is not an integer`
f8d5d8fd
JB
134 )
135 }
136 if (size < 0) {
137 throw new RangeError(`Invalid fixed priority queue size: ${size} < 0`)
138 }
139 }
140}