serverless-spy
Version:
CDK-based library for writing elegant integration tests on AWS serverless architecture and an additional web console to monitor events in real time.
321 lines (270 loc) • 6.44 kB
JavaScript
/* eslint no-constant-condition: 0 */
/**
* Mnemonist Fibonacci Heap
* =========================
*
* Fibonacci heap implementation.
*/
var comparators = require('./utils/comparators.js'),
forEach = require('obliterator/foreach');
var DEFAULT_COMPARATOR = comparators.DEFAULT_COMPARATOR,
reverseComparator = comparators.reverseComparator;
/**
* Fibonacci Heap.
*
* @constructor
*/
function FibonacciHeap(comparator) {
this.clear();
this.comparator = comparator || DEFAULT_COMPARATOR;
if (typeof this.comparator !== 'function')
throw new Error('mnemonist/FibonacciHeap.constructor: given comparator should be a function.');
}
/**
* Method used to clear the heap.
*
* @return {undefined}
*/
FibonacciHeap.prototype.clear = function() {
// Properties
this.root = null;
this.min = null;
this.size = 0;
};
/**
* Function used to create a node.
*
* @param {any} item - Target item.
* @return {object}
*/
function createNode(item) {
return {
item: item,
degree: 0
};
}
/**
* Function used to merge the given node with the root list.
*
* @param {FibonacciHeap} heap - Target heap.
* @param {Node} node - Target node.
*/
function mergeWithRoot(heap, node) {
if (!heap.root) {
heap.root = node;
}
else {
node.right = heap.root.right;
node.left = heap.root;
heap.root.right.left = node;
heap.root.right = node;
}
}
/**
* Method used to push an item into the heap.
*
* @param {any} item - Item to push.
* @return {number}
*/
FibonacciHeap.prototype.push = function(item) {
var node = createNode(item);
node.left = node;
node.right = node;
mergeWithRoot(this, node);
if (!this.min || this.comparator(node.item, this.min.item) <= 0)
this.min = node;
return ++this.size;
};
/**
* Method used to get the "first" item of the heap.
*
* @return {any}
*/
FibonacciHeap.prototype.peek = function() {
return this.min ? this.min.item : undefined;
};
/**
* Function used to consume the given linked list.
*
* @param {Node} head - Head node.
* @param {array}
*/
function consumeLinkedList(head) {
var nodes = [],
node = head,
flag = false;
while (true) {
if (node === head && flag)
break;
else if (node === head)
flag = true;
nodes.push(node);
node = node.right;
}
return nodes;
}
/**
* Function used to remove the target node from the root list.
*
* @param {FibonacciHeap} heap - Target heap.
* @param {Node} node - Target node.
*/
function removeFromRoot(heap, node) {
if (heap.root === node)
heap.root = node.right;
node.left.right = node.right;
node.right.left = node.left;
}
/**
* Function used to merge the given node with the child list of a root node.
*
* @param {Node} parent - Parent node.
* @param {Node} node - Target node.
*/
function mergeWithChild(parent, node) {
if (!parent.child) {
parent.child = node;
}
else {
node.right = parent.child.right;
node.left = parent.child;
parent.child.right.left = node;
parent.child.right = node;
}
}
/**
* Function used to link one node to another in the root list.
*
* @param {FibonacciHeap} heap - Target heap.
* @param {Node} y - Y node.
* @param {Node} x - X node.
*/
function link(heap, y, x) {
removeFromRoot(heap, y);
y.left = y;
y.right = y;
mergeWithChild(x, y);
x.degree++;
y.parent = x;
}
/**
* Function used to consolidate the heap.
*
* @param {FibonacciHeap} heap - Target heap.
*/
function consolidate(heap) {
var A = new Array(heap.size),
nodes = consumeLinkedList(heap.root),
i, l, x, y, d, t;
for (i = 0, l = nodes.length; i < l; i++) {
x = nodes[i];
d = x.degree;
while (A[d]) {
y = A[d];
if (heap.comparator(x.item, y.item) > 0) {
t = x;
x = y;
y = t;
}
link(heap, y, x);
A[d] = null;
d++;
}
A[d] = x;
}
for (i = 0; i < heap.size; i++) {
if (A[i] && heap.comparator(A[i].item, heap.min.item) <= 0)
heap.min = A[i];
}
}
/**
* Method used to retrieve & remove the "first" item of the heap.
*
* @return {any}
*/
FibonacciHeap.prototype.pop = function() {
if (!this.size)
return undefined;
var z = this.min;
if (z.child) {
var nodes = consumeLinkedList(z.child),
node,
i,
l;
for (i = 0, l = nodes.length; i < l; i++) {
node = nodes[i];
mergeWithRoot(this, node);
delete node.parent;
}
}
removeFromRoot(this, z);
if (z === z.right) {
this.min = null;
this.root = null;
}
else {
this.min = z.right;
consolidate(this);
}
this.size--;
return z.item;
};
/**
* Convenience known methods.
*/
FibonacciHeap.prototype.inspect = function() {
var proxy = {
size: this.size
};
if (this.min && 'item' in this.min)
proxy.top = this.min.item;
// Trick so that node displays the name of the constructor
Object.defineProperty(proxy, 'constructor', {
value: FibonacciHeap,
enumerable: false
});
return proxy;
};
if (typeof Symbol !== 'undefined')
FibonacciHeap.prototype[Symbol.for('nodejs.util.inspect.custom')] = FibonacciHeap.prototype.inspect;
/**
* Fibonacci Maximum Heap.
*
* @constructor
*/
function MaxFibonacciHeap(comparator) {
this.clear();
this.comparator = comparator || DEFAULT_COMPARATOR;
if (typeof this.comparator !== 'function')
throw new Error('mnemonist/FibonacciHeap.constructor: given comparator should be a function.');
this.comparator = reverseComparator(this.comparator);
}
MaxFibonacciHeap.prototype = FibonacciHeap.prototype;
/**
* Static @.from function taking an arbitrary iterable & converting it into
* a heap.
*
* @param {Iterable} iterable - Target iterable.
* @param {function} comparator - Custom comparator function.
* @return {FibonacciHeap}
*/
FibonacciHeap.from = function(iterable, comparator) {
var heap = new FibonacciHeap(comparator);
forEach(iterable, function(value) {
heap.push(value);
});
return heap;
};
MaxFibonacciHeap.from = function(iterable, comparator) {
var heap = new MaxFibonacciHeap(comparator);
forEach(iterable, function(value) {
heap.push(value);
});
return heap;
};
/**
* Exporting.
*/
FibonacciHeap.MinFibonacciHeap = FibonacciHeap;
FibonacciHeap.MaxFibonacciHeap = MaxFibonacciHeap;
module.exports = FibonacciHeap;