Priority queues have essentially the same interface as ordinary
queues, except that a) there is an in/3
that takes a priority, and
b) we have only implemented the core API we need.
Priorities should be integers - the higher the value the higher the priority - but we don't actually check that.
in/2
inserts items with priority 0.
We optimise the case where a priority queue is being used just like
an ordinary queue. When that is the case we represent the priority
queue as an ordinary queue. We could just call into the queue
module for that, but for efficiency we implement the relevant
functions directly in here, thus saving on inter-module calls and
eliminating a level of boxing.
When the queue contains items with non-zero priorities, it is represented as a sorted kv list with the inverted priority as the key and an ordinary queue as the value. Here again we use our own ordinary queue implemention for efficiency, often making recursive calls into the same function knowing that ordinary queues represent a base case.
pqueue() = squeue() | {pqueue, [{priority(), squeue()}]}
priority() = integer() | infinity
q() = pqueue()
squeue() = {queue, [any()], [any()], non_neg_integer()}
filter/2 | |
fold/3 | |
from_list/1 | |
highest/1 | |
in/2 | |
in/3 | |
is_empty/1 | |
is_queue/1 | |
join/2 | |
len/1 | |
new/0 | |
out/1 | |
out_p/1 | |
to_list/1 |
fold(Fun::fun((any(), priority(), A) -> A), A, Q::pqueue()) -> A
from_list(L::[{priority(), any()}]) -> pqueue()
highest(X1::pqueue()) -> priority() | empty
in(X::any(), Priority::priority(), Q::pqueue()) -> pqueue()
is_empty(X1::pqueue()) -> boolean()
is_queue(X1::any()) -> boolean()
len(X1::pqueue()) -> non_neg_integer()
new() -> pqueue()
out_p(Q::pqueue()) -> {empty | {value, any(), priority()}, pqueue()}
to_list(X1::pqueue()) -> [{priority(), any()}]