/** @inheritdoc */
public delete (data: T): boolean {
+ if (this.empty()) return false
let currentPhysicalIndex = this.start
let logicalIndex = -1
for (let i = 0; i < this.size; i++) {
`Invalid fixed queue size: '${size.toString()}' is not an integer`
)
}
- if (size < 0) {
- throw new RangeError(`Invalid fixed queue size: ${size.toString()} < 0`)
+ if (size <= 0) {
+ throw new RangeError(`Invalid fixed queue size: ${size.toString()} <= 0`)
}
}
}
export class FixedPriorityQueue<T>
extends AbstractFixedQueue<T>
implements IFixedQueue<T> {
+ private readonly agingFactor: number
+
+ /**
+ * Constructs a FixedPriorityQueue.
+ * @param size - Fixed queue size. @defaultValue defaultQueueSize
+ * @param agingFactor - Aging factor to apply to items in priority points per millisecond. A higher value makes items age faster.
+ * @returns IFixedQueue.
+ */
+ public constructor (size?: number, agingFactor = 0.001) {
+ super(size)
+ this.agingFactor = agingFactor
+ }
+
/** @inheritdoc */
public enqueue (data: T, priority?: number): number {
if (this.full()) {
throw new Error('Fixed priority queue is full')
}
priority = priority ?? 0
+ const now = performance.now()
let insertionPhysicalIndex = -1
let currentPhysicalIndex = this.start
for (let i = 0; i < this.size; i++) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- if (this.nodeArray[currentPhysicalIndex]!.priority > priority) {
+ const node = this.nodeArray[currentPhysicalIndex]!
+ const nodeEffectivePriority =
+ node.priority - (now - node.timestamp) * this.agingFactor
+ if (nodeEffectivePriority > priority) {
insertionPhysicalIndex = currentPhysicalIndex
break
}
shiftPhysicalIndex = previousPhysicalIndex
}
}
- this.nodeArray[insertionPhysicalIndex] = { data, priority }
+ this.nodeArray[insertionPhysicalIndex] = { data, priority, timestamp: now }
return ++this.size
}
}
if (index >= this.capacity) {
index -= this.capacity
}
- this.nodeArray[index] = { data, priority: priority ?? 0 }
+ this.nodeArray[index] = {
+ data,
+ priority: priority ?? 0,
+ timestamp: performance.now(),
+ }
return ++this.size
}
}
export interface FixedQueueNode<T> {
data: T
priority: number
+ timestamp: number
}
/**
new TypeError("Invalid fixed queue size: '' is not an integer")
)
expect(() => new FixedPriorityQueue(-1)).toThrow(
- new RangeError('Invalid fixed queue size: -1 < 0')
+ new RangeError('Invalid fixed queue size: -1 <= 0')
)
const fixedPriorityQueue = new FixedPriorityQueue()
expect(fixedPriorityQueue.start).toBe(0)
expect(fixedPriorityQueue.size).toBe(2)
expect(rtSize).toBe(fixedPriorityQueue.size)
expect(fixedPriorityQueue.nodeArray).toMatchObject([
- { data: 1, priority: 0 },
- { data: 2, priority: 0 },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 2, priority: 0, timestamp: expect.any(Number) },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
rtSize = fixedPriorityQueue.enqueue(3)
expect(fixedPriorityQueue.size).toBe(3)
expect(rtSize).toBe(fixedPriorityQueue.size)
expect(fixedPriorityQueue.nodeArray).toMatchObject([
- { data: 1, priority: 0 },
- { data: 2, priority: 0 },
- { data: 3, priority: 0 },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 2, priority: 0, timestamp: expect.any(Number) },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
rtSize = fixedPriorityQueue.enqueue(3, -1)
expect(fixedPriorityQueue.size).toBe(4)
expect(rtSize).toBe(fixedPriorityQueue.size)
expect(fixedPriorityQueue.nodeArray).toMatchObject([
- { data: 3, priority: -1 },
- { data: 1, priority: 0 },
- { data: 2, priority: 0 },
- { data: 3, priority: 0 },
+ { data: 3, priority: -1, timestamp: expect.any(Number) },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 2, priority: 0, timestamp: expect.any(Number) },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
rtSize = fixedPriorityQueue.enqueue(1, 1)
expect(fixedPriorityQueue.size).toBe(5)
expect(rtSize).toBe(fixedPriorityQueue.size)
expect(fixedPriorityQueue.nodeArray).toMatchObject([
- { data: 3, priority: -1 },
- { data: 1, priority: 0 },
- { data: 2, priority: 0 },
- { data: 3, priority: 0 },
- { data: 1, priority: 1 },
+ { data: 3, priority: -1, timestamp: expect.any(Number) },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 2, priority: 0, timestamp: expect.any(Number) },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
+ { data: 1, priority: 1, timestamp: expect.any(Number) },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
expect(() => fixedPriorityQueue.enqueue(4)).toThrow(
expect(rtItem).toBe(2)
expect(fixedPriorityQueue.nodeArray).toMatchObject([
undefined,
- { data: 1, priority: 0 },
- { data: 3, priority: 0 },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
rtItem = fixedPriorityQueue.dequeue()
expect(fixedPriorityQueue.nodeArray).toMatchObject([
undefined,
undefined,
- { data: 3, priority: 0 },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
rtItem = fixedPriorityQueue.dequeue()
expect(fixedPriorityQueue.start).toBe(0)
expect(fixedPriorityQueue.size).toBe(3)
expect(fixedPriorityQueue.nodeArray).toMatchObject([
- { data: 2, priority: -1 },
- { data: 1, priority: 0 },
- { data: 3, priority: 0 },
+ { data: 2, priority: -1, timestamp: expect.any(Number) },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
])
expect(fixedPriorityQueue.delete(2)).toBe(true)
expect(fixedPriorityQueue.start).toBe(0)
expect(fixedPriorityQueue.size).toBe(2)
expect(fixedPriorityQueue.nodeArray).toMatchObject([
- { data: 1, priority: 0 },
- { data: 3, priority: 0 },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
])
expect(fixedPriorityQueue.delete(3)).toBe(true)
expect(fixedPriorityQueue.start).toBe(0)
expect(fixedPriorityQueue.size).toBe(1)
expect(fixedPriorityQueue.nodeArray).toMatchObject([
- { data: 1, priority: 0 },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
])
expect(fixedPriorityQueue.delete(1)).toBe(true)
expect(fixedPriorityQueue.start).toBe(0)
})
it('Verify clear() behavior', () => {
- const fixedPriorityQueue = new FixedPriorityQueue(2)
- fixedPriorityQueue.start = 1
- fixedPriorityQueue.size = 2
- fixedPriorityQueue.nodeArray = [
- { data: 2, priority: 0 },
- { data: 3, priority: 0 },
- ]
+ const queueSize = 3
+ const fixedPriorityQueue = new FixedPriorityQueue(queueSize)
+ fixedPriorityQueue.enqueue(1)
+ fixedPriorityQueue.enqueue(2, -1)
+ fixedPriorityQueue.enqueue(3)
+ expect(fixedPriorityQueue.size).toBe(queueSize)
+ expect(fixedPriorityQueue.nodeArray).toMatchObject([
+ { data: 2, priority: -1, timestamp: expect.any(Number) },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
+ ])
fixedPriorityQueue.clear()
- expect(fixedPriorityQueue.start).toBe(0)
expect(fixedPriorityQueue.size).toBe(0)
- expect(fixedPriorityQueue.nodeArray).toStrictEqual([undefined, undefined])
+ expect(fixedPriorityQueue.start).toBe(0)
+ expect(fixedPriorityQueue.nodeArray).toStrictEqual([
+ undefined,
+ undefined,
+ undefined,
+ ])
})
})
new TypeError("Invalid fixed queue size: '' is not an integer")
)
expect(() => new FixedQueue(-1)).toThrow(
- new RangeError('Invalid fixed queue size: -1 < 0')
+ new RangeError('Invalid fixed queue size: -1 <= 0')
)
const fixedQueue = new FixedQueue()
expect(fixedQueue.start).toBe(0)
expect(fixedQueue.start).toBe(0)
expect(fixedQueue.size).toBe(1)
expect(rtSize).toBe(fixedQueue.size)
- expect(fixedQueue.nodeArray).toMatchObject([{ data: 1, priority: 0 }])
+ expect(fixedQueue.nodeArray).toMatchObject([
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ ])
expect(fixedQueue.capacity).toBe(queueSize)
rtSize = fixedQueue.enqueue(2)
expect(fixedQueue.start).toBe(0)
expect(fixedQueue.size).toBe(2)
expect(rtSize).toBe(fixedQueue.size)
expect(fixedQueue.nodeArray).toMatchObject([
- { data: 1, priority: 0 },
- { data: 2, priority: 0 },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 2, priority: 0, timestamp: expect.any(Number) },
])
expect(fixedQueue.capacity).toBe(queueSize)
rtSize = fixedQueue.enqueue(3)
expect(fixedQueue.size).toBe(3)
expect(rtSize).toBe(fixedQueue.size)
expect(fixedQueue.nodeArray).toMatchObject([
- { data: 1, priority: 0 },
- { data: 2, priority: 0 },
- { data: 3, priority: 0 },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 2, priority: 0, timestamp: expect.any(Number) },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
])
expect(fixedQueue.capacity).toBe(queueSize)
rtSize = fixedQueue.enqueue(3, -1)
expect(fixedQueue.size).toBe(4)
expect(rtSize).toBe(fixedQueue.size)
expect(fixedQueue.nodeArray).toMatchObject([
- { data: 1, priority: 0 },
- { data: 2, priority: 0 },
- { data: 3, priority: 0 },
- { data: 3, priority: -1 },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 2, priority: 0, timestamp: expect.any(Number) },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
+ { data: 3, priority: -1, timestamp: expect.any(Number) },
])
expect(fixedQueue.capacity).toBe(queueSize)
rtSize = fixedQueue.enqueue(1, 1)
expect(fixedQueue.size).toBe(5)
expect(rtSize).toBe(fixedQueue.size)
expect(fixedQueue.nodeArray).toMatchObject([
- { data: 1, priority: 0 },
- { data: 2, priority: 0 },
- { data: 3, priority: 0 },
- { data: 3, priority: -1 },
- { data: 1, priority: 1 },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 2, priority: 0, timestamp: expect.any(Number) },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
+ { data: 3, priority: -1, timestamp: expect.any(Number) },
+ { data: 1, priority: 1, timestamp: expect.any(Number) },
])
expect(fixedQueue.capacity).toBe(queueSize)
expect(() => fixedQueue.enqueue(4)).toThrow(
expect(rtItem).toBe(1)
expect(fixedQueue.nodeArray).toMatchObject([
undefined,
- { data: 2, priority: -1 },
- { data: 3, priority: 0 },
+ { data: 2, priority: -1, timestamp: expect.any(Number) },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
])
expect(fixedQueue.capacity).toBe(queueSize)
rtItem = fixedQueue.dequeue()
expect(fixedQueue.nodeArray).toMatchObject([
undefined,
undefined,
- { data: 3, priority: 0 },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
])
expect(fixedQueue.capacity).toBe(queueSize)
rtItem = fixedQueue.dequeue()
expect(fixedQueue.start).toBe(0)
expect(fixedQueue.size).toBe(3)
expect(fixedQueue.nodeArray).toMatchObject([
- { data: 1, priority: 0 },
- { data: 2, priority: -1 },
- { data: 3, priority: 0 },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 2, priority: -1, timestamp: expect.any(Number) },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
])
expect(fixedQueue.delete(2)).toBe(true)
expect(fixedQueue.start).toBe(0)
expect(fixedQueue.size).toBe(2)
expect(fixedQueue.nodeArray).toMatchObject([
- { data: 1, priority: 0 },
- { data: 3, priority: 0 },
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
])
expect(fixedQueue.delete(3)).toBe(true)
expect(fixedQueue.start).toBe(0)
expect(fixedQueue.size).toBe(1)
- expect(fixedQueue.nodeArray).toMatchObject([{ data: 1, priority: 0 }])
+ expect(fixedQueue.nodeArray).toMatchObject([
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ ])
expect(fixedQueue.delete(1)).toBe(true)
expect(fixedQueue.start).toBe(0)
expect(fixedQueue.size).toBe(0)
})
it('Verify clear() behavior', () => {
- const fixedQueue = new FixedQueue(2)
- fixedQueue.start = 1
- fixedQueue.size = 2
- fixedQueue.nodeArray = [
- { data: 2, priority: 0 },
- { data: 3, priority: 0 },
- ]
+ const queueSize = 3
+ const fixedQueue = new FixedQueue(queueSize)
+ fixedQueue.enqueue(1)
+ fixedQueue.enqueue(2, -1)
+ fixedQueue.enqueue(3)
+ expect(fixedQueue.size).toBe(queueSize)
+ expect(fixedQueue.nodeArray).toMatchObject([
+ { data: 1, priority: 0, timestamp: expect.any(Number) },
+ { data: 2, priority: -1, timestamp: expect.any(Number) },
+ { data: 3, priority: 0, timestamp: expect.any(Number) },
+ ])
fixedQueue.clear()
- expect(fixedQueue.start).toBe(0)
expect(fixedQueue.size).toBe(0)
- expect(fixedQueue.nodeArray).toStrictEqual([undefined, undefined])
+ expect(fixedQueue.start).toBe(0)
+ expect(fixedQueue.nodeArray).toStrictEqual([
+ undefined,
+ undefined,
+ undefined,
+ ])
})
})