refactor: silence linter
[poolifier.git] / src / fixed-priority-queue.ts
CommitLineData
f8d5d8fd
JB
1/**
2 * Default buffer size.
3 */
4export const defaultQueueSize = 2048
5
6/**
65c178f1 7 * Fixed priority queue node.
f8d5d8fd
JB
8 * @typeParam T - Type of priority queue node data.
9 * @internal
10 */
65c178f1 11export interface FixedPriorityQueueNode<T> {
f8d5d8fd
JB
12 data: T
13 priority: number
14}
15
eadb37e2
JB
16/**
17 * Fixed priority queue.
eadb37e2
JB
18 * @typeParam T - Type of fixed priority queue data.
19 * @internal
20 */
f8d5d8fd
JB
21export class FixedPriorityQueue<T> {
22 private start!: number
3a502712 23 private readonly nodeArray: FixedPriorityQueueNode<T>[]
10b1b252 24 /** The fixed priority queue capacity. */
9df282a0 25 public readonly capacity: number
fcfc3353 26 /** The fixed priority queue size. */
f8d5d8fd 27 public size!: number
fcfc3353
JB
28 /** Whether to enable priority. */
29 public enablePriority: boolean
f8d5d8fd 30
9df282a0
JB
31 /**
32 * Constructs a fixed priority queue.
9df282a0 33 * @param size - Fixed priority queue size. @defaultValue defaultQueueSize
fcfc3353 34 * @param enablePriority - Whether to enable priority. @defaultValue false
9df282a0
JB
35 * @returns FixedPriorityQueue.
36 */
fcfc3353 37 constructor (size: number = defaultQueueSize, enablePriority = false) {
f8d5d8fd 38 this.checkSize(size)
9df282a0 39 this.capacity = size
fcfc3353 40 this.enablePriority = enablePriority
65c178f1 41 this.nodeArray = new Array<FixedPriorityQueueNode<T>>(this.capacity)
f8d5d8fd
JB
42 this.clear()
43 }
44
e75373e6
JB
45 /**
46 * Checks if the fixed priority queue is empty.
e75373e6
JB
47 * @returns `true` if the fixed priority queue is empty, `false` otherwise.
48 */
f8d5d8fd
JB
49 public empty (): boolean {
50 return this.size === 0
51 }
52
e75373e6
JB
53 /**
54 * Checks if the fixed priority queue is full.
e75373e6
JB
55 * @returns `true` if the fixed priority queue is full, `false` otherwise.
56 */
f8d5d8fd 57 public full (): boolean {
9df282a0 58 return this.size === this.capacity
f8d5d8fd
JB
59 }
60
e75373e6
JB
61 /**
62 * Enqueue data into the fixed priority queue.
e75373e6
JB
63 * @param data - Data to enqueue.
64 * @param priority - Priority of the data. Lower values have higher priority.
65 * @returns The new size of the priority queue.
13ed544a 66 * @throws If the fixed priority queue is full.
e75373e6 67 */
f8d5d8fd
JB
68 public enqueue (data: T, priority?: number): number {
69 if (this.full()) {
70 throw new Error('Priority queue is full')
71 }
72 priority = priority ?? 0
73 let inserted = false
fcfc3353
JB
74 if (this.enablePriority) {
75 let index = this.start
76 for (let i = 0; i < this.size; i++) {
77 if (this.nodeArray[index].priority > priority) {
78 this.nodeArray.splice(index, 0, { data, priority })
79 this.nodeArray.length !== this.capacity &&
80 (this.nodeArray.length = this.capacity)
81 inserted = true
82 break
83 }
84 ++index
85 if (index === this.capacity) {
86 index = 0
87 }
3451940f 88 }
f8d5d8fd
JB
89 }
90 if (!inserted) {
91 let index = this.start + this.size
9df282a0
JB
92 if (index >= this.capacity) {
93 index -= this.capacity
f8d5d8fd
JB
94 }
95 this.nodeArray[index] = { data, priority }
96 }
10b1b252 97 return ++this.size
f8d5d8fd
JB
98 }
99
1d98bad2
JB
100 /**
101 * Gets data from the fixed priority queue.
1d98bad2
JB
102 * @param index - The index of the data to get.
103 * @returns The data at the index or `undefined` if the fixed priority queue is empty or the index is out of bounds.
104 */
105 public get (index: number): T | undefined {
106 if (this.empty() || index >= this.size) {
107 return undefined
108 }
109 index += this.start
110 if (index >= this.capacity) {
111 index -= this.capacity
112 }
113 return this.nodeArray[index].data
114 }
115
e75373e6
JB
116 /**
117 * Dequeue data from the fixed priority queue.
e75373e6
JB
118 * @returns The dequeued data or `undefined` if the priority queue is empty.
119 */
f8d5d8fd
JB
120 public dequeue (): T | undefined {
121 if (this.empty()) {
122 return undefined
123 }
124 const index = this.start
125 --this.size
126 ++this.start
9df282a0 127 if (this.start === this.capacity) {
f8d5d8fd
JB
128 this.start = 0
129 }
130 return this.nodeArray[index].data
131 }
132
133 /**
134 * Clears the fixed priority queue.
135 */
136 public clear (): void {
137 this.start = 0
138 this.size = 0
f8d5d8fd
JB
139 }
140
141 /**
142 * Returns an iterator for the fixed priority queue.
f8d5d8fd
JB
143 * @returns An iterator for the fixed priority queue.
144 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
145 */
9df282a0 146 public [Symbol.iterator] (): Iterator<T> {
3451940f
JB
147 let index = this.start
148 let i = 0
f8d5d8fd
JB
149 return {
150 next: () => {
151 if (i >= this.size) {
152 return {
153 value: undefined,
3a502712 154 done: true,
f8d5d8fd
JB
155 }
156 }
3451940f 157 const value = this.nodeArray[index].data
02c769d0
JB
158 ++index
159 ++i
9df282a0 160 if (index === this.capacity) {
3451940f
JB
161 index = 0
162 }
f8d5d8fd
JB
163 return {
164 value,
3a502712 165 done: false,
f8d5d8fd 166 }
3a502712 167 },
f8d5d8fd
JB
168 }
169 }
170
e75373e6 171 /**
fcfc3353 172 * Checks the queue size.
fcfc3353 173 * @param size - Queue size.
e75373e6 174 */
f8d5d8fd
JB
175 private checkSize (size: number): void {
176 if (!Number.isSafeInteger(size)) {
177 throw new TypeError(
6e5d7052 178 `Invalid fixed priority queue size: '${size.toString()}' is not an integer`
f8d5d8fd
JB
179 )
180 }
181 if (size < 0) {
6e5d7052
JB
182 throw new RangeError(
183 `Invalid fixed priority queue size: ${size.toString()} < 0`
184 )
f8d5d8fd
JB
185 }
186 }
187}