-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpriority-queue.js
90 lines (80 loc) · 2.63 KB
/
priority-queue.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/* PriorityQueue
* https://github.com/pjfreeze/queues/priority-queue.js
*
* This is free and unencumbered software released into the public domain.
*/
(function (global) {
'use strict';
/**
* Lazily sorted queue, ordered based on priority score & time enqueued.
*/
class PriorityQueue {
constructor () {
this._queue = [];
this._isSortOutOfDate = false;
}
/**
* @private
* Sort the queue based on priority and enqueue time. Mark itself as up-to-date
* to prevent additional sort iterations.
*/
_sort () {
this._queue.sort(priorityAndEnqueuedTime);
this._isSortOutOfDate = false;
}
/**
* @param {*} item - The item to add to the queue
* @param {number} [priority] - Larger number == higher priority
*/
enqueue (item, opts = {}) {
const defaultOptions = { enqueuedTime: Date.now(), priority: 0 };
const options = Object.assign(defaultOptions, opts);
this._queue.push({ item, options });
this._isSortOutOfDate = true;
}
/**
* Sort queue if out-of-date, then release the first item in the queue.
* @returns {*} Whatever the first parameter of the enqueue call was.
*/
dequeue () {
this._isSortOutOfDate && this._sort();
const hasAtLeastOneItem = this.size > 0;
return hasAtLeastOneItem ? this._queue.shift().item : undefined;
}
get size () {
return this._queue.length;
}
}
const sort = {
doNotMove: 0,
moveCloserToStart: -1,
moveCloserToEnd: 1,
};
const higherMovesTowardsFront = (a, b) => {
if (a == b) { return sort.doNotMove; }
return a > b ? sort.moveCloserToFront : sort.moveCloserToEnd;
};
const lowerMovesTowardsFront = (a, b) => {
if (a == b) { return sort.doNotMove; }
return a < b ? sort.moveCloserToFront : sort.moveCloserToEnd;
};
const priorityAndEnqueuedTime = ({ options: itemA }, { options: itemB }) => {
if (itemA.priority != itemB.priority) {
// Higher priorities ahead of lower priorities
return higherMovesTowardsFront(itemA.priority, itemB.priority);
} else {
// Earlier times ahead of later times
return lowerMovesTowardsFront(itemA.enqueuedTime, itemB.enqueuedTime);
}
};
if (typeof define == 'function' && define.amd) {
define(function () { return PriorityQueue; });
} else if (typeof exports == 'object') {
if (typeof module == 'object' && typeof module.exports == 'object') {
exports = module.exports = PriorityQueue;
}
exports.PriorityQueue = PriorityQueue;
} else {
global.PriorityQueue = PriorityQueue;
}
}(typeof window == 'undefined' ? this : window));