typescript-collections
Version:
A complete, fully tested data structure library written in TypeScript.
1,381 lines (1,375 loc) • 296 kB
JavaScript
(function(f) {
if (typeof exports === "object" && typeof module !== "undefined") {
module.exports = f()
} else if (typeof define === "function" && define.amd) {
define([], f)
} else {
var g;
if (typeof window !== "undefined") {
g = window
} else if (typeof global !== "undefined") {
g = global
} else if (typeof self !== "undefined") {
g = self
} else {
g = this
}
g.listComponent = f()
}
})(function() {
var define, module, exports;
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var BSTreeKV_1 = require("./BSTreeKV");
/**
* Special-case of the binary search tree in which the search key is equal to the element type.
* This definition is suitable when the element type can not be split between what defines its order
* and what does not (eg. primitive types as opposed to indexed records).
*
* The table below shows some use-case examples for both interfaces:
*
* element type | most suitable interface
* ------------------------------------|----------------------------
* number | BSTree<number>
* string | BSTree<string>
* { order: number, data: string } | BSTreeKV<{order: number}, {order: number, data: string}>
*
* @see BSTreeKV
*/
var BSTree = /** @class */ (function (_super) {
__extends(BSTree, _super);
function BSTree() {
return _super !== null && _super.apply(this, arguments) || this;
}
return BSTree;
}(BSTreeKV_1.default));
exports.default = BSTree;
},{"./BSTreeKV":2}],2:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var util = require("./util");
var Queue_1 = require("./Queue");
/**
* General binary search tree implementation.
*
* This interface allows one to search elements using a subset of their attributes (thus the
* tree can be used as an index for complex objects).
* The attributes required to define an ordering in the tree must be defined in the type K.
* Any additional attribute must be defined in the type V.
*
* @see BSTree
*/
var BSTreeKV = /** @class */ (function () {
/**
* Creates an empty binary search tree.
* @class <p>A binary search tree is a binary tree in which each
* internal node stores an element such that the elements stored in the
* left subtree are less than it and the elements
* stored in the right subtree are greater.</p>
* <p>Formally, a binary search tree is a node-based binary tree data structure which
* has the following properties:</p>
* <ul>
* <li>The left subtree of a node contains only nodes with elements less
* than the node's element</li>
* <li>The right subtree of a node contains only nodes with elements greater
* than the node's element</li>
* <li>Both the left and right subtrees must also be binary search trees.</li>
* </ul>
* <p>If the inserted elements are custom objects a compare function must
* be provided at construction time, otherwise the <=, === and >= operators are
* used to compare elements. Example:</p>
* <pre>
* function compare(a, b) {
* if (a is less than b by some ordering criterion) {
* return -1;
* } if (a is greater than b by the ordering criterion) {
* return 1;
* }
* // a must be equal to b
* return 0;
* }
* </pre>
* @constructor
* @param {function(Object,Object):number=} compareFunction optional
* function used to compare two elements. Must return a negative integer,
* zero, or a positive integer as the first argument is less than, equal to,
* or greater than the second.
*/
function BSTreeKV(compareFunction) {
this.root = null;
this.compare = compareFunction || util.defaultCompare;
this.nElements = 0;
}
/**
* Adds the specified element to this tree if it is not already present.
* @param {Object} element the element to insert.
* @return {boolean} true if this tree did not already contain the specified element.
*/
BSTreeKV.prototype.add = function (element) {
if (util.isUndefined(element)) {
return false;
}
if (this.insertNode(this.createNode(element)) !== null) {
this.nElements++;
return true;
}
return false;
};
/**
* Removes all of the elements from this tree.
*/
BSTreeKV.prototype.clear = function () {
this.root = null;
this.nElements = 0;
};
/**
* Returns true if this tree contains no elements.
* @return {boolean} true if this tree contains no elements.
*/
BSTreeKV.prototype.isEmpty = function () {
return this.nElements === 0;
};
/**
* Returns the number of elements in this tree.
* @return {number} the number of elements in this tree.
*/
BSTreeKV.prototype.size = function () {
return this.nElements;
};
/**
* Returns true if this tree contains the specified element.
* @param {Object} element element to search for.
* @return {boolean} true if this tree contains the specified element,
* false otherwise.
*/
BSTreeKV.prototype.contains = function (element) {
if (util.isUndefined(element)) {
return false;
}
return this.searchNode(this.root, element) !== null;
};
/**
* Looks for the value with the provided search key.
* @param {Object} element The key to look for
* @return {Object} The value found or undefined if it was not found.
*/
BSTreeKV.prototype.search = function (element) {
var ret = this.searchNode(this.root, element);
if (ret === null) {
return undefined;
}
return ret.element;
};
/**
* Removes the specified element from this tree if it is present.
* @return {boolean} true if this tree contained the specified element.
*/
BSTreeKV.prototype.remove = function (element) {
var node = this.searchNode(this.root, element);
if (node === null) {
return false;
}
this.removeNode(node);
this.nElements--;
return true;
};
/**
* Executes the provided function once for each element present in this tree in
* in-order.
* @param {function(Object):*} callback function to execute, it is invoked with one
* argument: the element value, to break the iteration you can optionally return false.
*/
BSTreeKV.prototype.inorderTraversal = function (callback) {
this.inorderTraversalAux(this.root, callback, {
stop: false
});
};
/**
* Executes the provided function once for each element present in this tree in pre-order.
* @param {function(Object):*} callback function to execute, it is invoked with one
* argument: the element value, to break the iteration you can optionally return false.
*/
BSTreeKV.prototype.preorderTraversal = function (callback) {
this.preorderTraversalAux(this.root, callback, {
stop: false
});
};
/**
* Executes the provided function once for each element present in this tree in post-order.
* @param {function(Object):*} callback function to execute, it is invoked with one
* argument: the element value, to break the iteration you can optionally return false.
*/
BSTreeKV.prototype.postorderTraversal = function (callback) {
this.postorderTraversalAux(this.root, callback, {
stop: false
});
};
/**
* Executes the provided function once for each element present in this tree in
* level-order.
* @param {function(Object):*} callback function to execute, it is invoked with one
* argument: the element value, to break the iteration you can optionally return false.
*/
BSTreeKV.prototype.levelTraversal = function (callback) {
this.levelTraversalAux(this.root, callback);
};
/**
* Returns the minimum element of this tree.
* @return {*} the minimum element of this tree or undefined if this tree is
* is empty.
*/
BSTreeKV.prototype.minimum = function () {
if (this.isEmpty() || this.root === null) {
return undefined;
}
return this.minimumAux(this.root).element;
};
/**
* Returns the maximum element of this tree.
* @return {*} the maximum element of this tree or undefined if this tree is
* is empty.
*/
BSTreeKV.prototype.maximum = function () {
if (this.isEmpty() || this.root === null) {
return undefined;
}
return this.maximumAux(this.root).element;
};
/**
* Executes the provided function once for each element present in this tree in inorder.
* Equivalent to inorderTraversal.
* @param {function(Object):*} callback function to execute, it is
* invoked with one argument: the element value, to break the iteration you can
* optionally return false.
*/
BSTreeKV.prototype.forEach = function (callback) {
this.inorderTraversal(callback);
};
/**
* Returns an array containing all of the elements in this tree in in-order.
* @return {Array} an array containing all of the elements in this tree in in-order.
*/
BSTreeKV.prototype.toArray = function () {
var array = [];
this.inorderTraversal(function (element) {
array.push(element);
return true;
});
return array;
};
/**
* Returns the height of this tree.
* @return {number} the height of this tree or -1 if is empty.
*/
BSTreeKV.prototype.height = function () {
return this.heightAux(this.root);
};
/**
* @private
*/
BSTreeKV.prototype.searchNode = function (node, element) {
var cmp = 1;
while (node !== null && cmp !== 0) {
cmp = this.compare(element, node.element);
if (cmp < 0) {
node = node.leftCh;
}
else if (cmp > 0) {
node = node.rightCh;
}
}
return node;
};
/**
* @private
*/
BSTreeKV.prototype.transplant = function (n1, n2) {
if (n1.parent === null) {
this.root = n2;
}
else if (n1 === n1.parent.leftCh) {
n1.parent.leftCh = n2;
}
else {
n1.parent.rightCh = n2;
}
if (n2 !== null) {
n2.parent = n1.parent;
}
};
/**
* @private
*/
BSTreeKV.prototype.removeNode = function (node) {
if (node.leftCh === null) {
this.transplant(node, node.rightCh);
}
else if (node.rightCh === null) {
this.transplant(node, node.leftCh);
}
else {
var y = this.minimumAux(node.rightCh);
if (y.parent !== node) {
this.transplant(y, y.rightCh);
y.rightCh = node.rightCh;
y.rightCh.parent = y;
}
this.transplant(node, y);
y.leftCh = node.leftCh;
y.leftCh.parent = y;
}
};
/**
* @private
*/
BSTreeKV.prototype.inorderTraversalAux = function (node, callback, signal) {
if (node === null || signal.stop) {
return;
}
this.inorderTraversalAux(node.leftCh, callback, signal);
if (signal.stop) {
return;
}
signal.stop = callback(node.element) === false;
if (signal.stop) {
return;
}
this.inorderTraversalAux(node.rightCh, callback, signal);
};
/**
* @private
*/
BSTreeKV.prototype.levelTraversalAux = function (node, callback) {
var queue = new Queue_1.default();
if (node !== null) {
queue.enqueue(node);
}
node = queue.dequeue() || null;
while (node != null) {
if (callback(node.element) === false) {
return;
}
if (node.leftCh !== null) {
queue.enqueue(node.leftCh);
}
if (node.rightCh !== null) {
queue.enqueue(node.rightCh);
}
node = queue.dequeue() || null;
}
};
/**
* @private
*/
BSTreeKV.prototype.preorderTraversalAux = function (node, callback, signal) {
if (node === null || signal.stop) {
return;
}
signal.stop = callback(node.element) === false;
if (signal.stop) {
return;
}
this.preorderTraversalAux(node.leftCh, callback, signal);
if (signal.stop) {
return;
}
this.preorderTraversalAux(node.rightCh, callback, signal);
};
/**
* @private
*/
BSTreeKV.prototype.postorderTraversalAux = function (node, callback, signal) {
if (node === null || signal.stop) {
return;
}
this.postorderTraversalAux(node.leftCh, callback, signal);
if (signal.stop) {
return;
}
this.postorderTraversalAux(node.rightCh, callback, signal);
if (signal.stop) {
return;
}
signal.stop = callback(node.element) === false;
};
BSTreeKV.prototype.minimumAux = function (node) {
while (node != null && node.leftCh !== null) {
node = node.leftCh;
}
return node;
};
BSTreeKV.prototype.maximumAux = function (node) {
while (node != null && node.rightCh !== null) {
node = node.rightCh;
}
return node;
};
/**
* @private
*/
BSTreeKV.prototype.heightAux = function (node) {
if (node === null) {
return -1;
}
return Math.max(this.heightAux(node.leftCh), this.heightAux(node.rightCh)) + 1;
};
/*
* @private
*/
BSTreeKV.prototype.insertNode = function (node) {
var parent = null;
var position = this.root;
while (position !== null) {
var cmp = this.compare(node.element, position.element);
if (cmp === 0) {
return null;
}
else if (cmp < 0) {
parent = position;
position = position.leftCh;
}
else {
parent = position;
position = position.rightCh;
}
}
node.parent = parent;
if (parent === null) {
// tree is empty
this.root = node;
}
else if (this.compare(node.element, parent.element) < 0) {
parent.leftCh = node;
}
else {
parent.rightCh = node;
}
return node;
};
/**
* @private
*/
BSTreeKV.prototype.createNode = function (element) {
return {
element: element,
leftCh: null,
rightCh: null,
parent: null
};
};
return BSTreeKV;
}());
exports.default = BSTreeKV;
},{"./Queue":12,"./util":16}],3:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var util = require("./util");
var Dictionary_1 = require("./Dictionary");
var Set_1 = require("./Set");
var Bag = /** @class */ (function () {
/**
* Creates an empty bag.
* @class <p>A bag is a special kind of set in which members are
* allowed to appear more than once.</p>
* <p>If the inserted elements are custom objects a function
* which converts elements to unique strings must be provided. Example:</p>
*
* <pre>
* function petToString(pet) {
* return pet.name;
* }
* </pre>
*
* @constructor
* @param {function(Object):string=} toStrFunction optional function used
* to convert elements to strings. If the elements aren't strings or if toString()
* is not appropriate, a custom function which receives an object and returns a
* unique string must be provided.
*/
function Bag(toStrFunction) {
this.toStrF = toStrFunction || util.defaultToString;
this.dictionary = new Dictionary_1.default(this.toStrF);
this.nElements = 0;
}
/**
* Adds nCopies of the specified object to this bag.
* @param {Object} element element to add.
* @param {number=} nCopies the number of copies to add, if this argument is
* undefined 1 copy is added.
* @return {boolean} true unless element is undefined.
*/
Bag.prototype.add = function (element, nCopies) {
if (nCopies === void 0) { nCopies = 1; }
if (util.isUndefined(element) || nCopies <= 0) {
return false;
}
if (!this.contains(element)) {
var node = {
value: element,
copies: nCopies
};
this.dictionary.setValue(element, node);
}
else {
this.dictionary.getValue(element).copies += nCopies;
}
this.nElements += nCopies;
return true;
};
/**
* Counts the number of copies of the specified object in this bag.
* @param {Object} element the object to search for..
* @return {number} the number of copies of the object, 0 if not found
*/
Bag.prototype.count = function (element) {
if (!this.contains(element)) {
return 0;
}
else {
return this.dictionary.getValue(element).copies;
}
};
/**
* Returns true if this bag contains the specified element.
* @param {Object} element element to search for.
* @return {boolean} true if this bag contains the specified element,
* false otherwise.
*/
Bag.prototype.contains = function (element) {
return this.dictionary.containsKey(element);
};
/**
* Removes nCopies of the specified object to this bag.
* If the number of copies to remove is greater than the actual number
* of copies in the Bag, all copies are removed.
* @param {Object} element element to remove.
* @param {number=} nCopies the number of copies to remove, if this argument is
* undefined 1 copy is removed.
* @return {boolean} true if at least 1 element was removed.
*/
Bag.prototype.remove = function (element, nCopies) {
if (nCopies === void 0) { nCopies = 1; }
if (util.isUndefined(element) || nCopies <= 0) {
return false;
}
if (!this.contains(element)) {
return false;
}
else {
var node = this.dictionary.getValue(element);
if (nCopies > node.copies) {
this.nElements -= node.copies;
}
else {
this.nElements -= nCopies;
}
node.copies -= nCopies;
if (node.copies <= 0) {
this.dictionary.remove(element);
}
return true;
}
};
/**
* Returns an array containing all of the elements in this big in arbitrary order,
* including multiple copies.
* @return {Array} an array containing all of the elements in this bag.
*/
Bag.prototype.toArray = function () {
var a = [];
var values = this.dictionary.values();
for (var _i = 0, values_1 = values; _i < values_1.length; _i++) {
var node = values_1[_i];
var element = node.value;
var copies = node.copies;
for (var j = 0; j < copies; j++) {
a.push(element);
}
}
return a;
};
/**
* Returns a set of unique elements in this bag.
* @return {collections.Set<T>} a set of unique elements in this bag.
*/
Bag.prototype.toSet = function () {
var toret = new Set_1.default(this.toStrF);
var elements = this.dictionary.values();
for (var _i = 0, elements_1 = elements; _i < elements_1.length; _i++) {
var ele = elements_1[_i];
var value = ele.value;
toret.add(value);
}
return toret;
};
/**
* Executes the provided function once for each element
* present in this bag, including multiple copies.
* @param {function(Object):*} callback function to execute, it is
* invoked with one argument: the element. To break the iteration you can
* optionally return false.
*/
Bag.prototype.forEach = function (callback) {
this.dictionary.forEach(function (k, v) {
var value = v.value;
var copies = v.copies;
for (var i = 0; i < copies; i++) {
if (callback(value) === false) {
return false;
}
}
return true;
});
};
/**
* Returns the number of elements in this bag.
* @return {number} the number of elements in this bag.
*/
Bag.prototype.size = function () {
return this.nElements;
};
/**
* Returns true if this bag contains no elements.
* @return {boolean} true if this bag contains no elements.
*/
Bag.prototype.isEmpty = function () {
return this.nElements === 0;
};
/**
* Removes all of the elements from this bag.
*/
Bag.prototype.clear = function () {
this.nElements = 0;
this.dictionary.clear();
};
return Bag;
}()); // End of bag
exports.default = Bag;
},{"./Dictionary":4,"./Set":13,"./util":16}],4:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var util = require("./util");
var Dictionary = /** @class */ (function () {
/**
* Creates an empty dictionary.
* @class <p>Dictionaries map keys to values; each key can map to at most one value.
* This implementation accepts any kind of objects as keys.</p>
*
* <p>If the keys are custom objects a function which converts keys to unique
* strings must be provided. Example:</p>
* <pre>
* function petToString(pet) {
* return pet.name;
* }
* </pre>
* @constructor
* @param {function(Object):string=} toStrFunction optional function used
* to convert keys to strings. If the keys aren't strings or if toString()
* is not appropriate, a custom function which receives a key and returns a
* unique string must be provided.
*/
function Dictionary(toStrFunction) {
this.table = {};
this.nElements = 0;
this.toStr = toStrFunction || util.defaultToString;
}
/**
* Returns the value to which this dictionary maps the specified key.
* Returns undefined if this dictionary contains no mapping for this key.
* @param {Object} key key whose associated value is to be returned.
* @return {*} the value to which this dictionary maps the specified key or
* undefined if the map contains no mapping for this key.
*/
Dictionary.prototype.getValue = function (key) {
var pair = this.table['$' + this.toStr(key)];
if (util.isUndefined(pair)) {
return undefined;
}
return pair.value;
};
/**
* Associates the specified value with the specified key in this dictionary.
* If the dictionary previously contained a mapping for this key, the old
* value is replaced by the specified value.
* @param {Object} key key with which the specified value is to be
* associated.
* @param {Object} value value to be associated with the specified key.
* @return {*} previous value associated with the specified key, or undefined if
* there was no mapping for the key or if the key/value are undefined.
*/
Dictionary.prototype.setValue = function (key, value) {
if (util.isUndefined(key) || util.isUndefined(value)) {
return undefined;
}
var ret;
var k = '$' + this.toStr(key);
var previousElement = this.table[k];
if (util.isUndefined(previousElement)) {
this.nElements++;
ret = undefined;
}
else {
ret = previousElement.value;
}
this.table[k] = {
key: key,
value: value
};
return ret;
};
/**
* Removes the mapping for this key from this dictionary if it is present.
* @param {Object} key key whose mapping is to be removed from the
* dictionary.
* @return {*} previous value associated with specified key, or undefined if
* there was no mapping for key.
*/
Dictionary.prototype.remove = function (key) {
var k = '$' + this.toStr(key);
var previousElement = this.table[k];
if (!util.isUndefined(previousElement)) {
delete this.table[k];
this.nElements--;
return previousElement.value;
}
return undefined;
};
/**
* Returns an array containing all of the keys in this dictionary.
* @return {Array} an array containing all of the keys in this dictionary.
*/
Dictionary.prototype.keys = function () {
var array = [];
for (var name_1 in this.table) {
if (util.has(this.table, name_1)) {
var pair = this.table[name_1];
array.push(pair.key);
}
}
return array;
};
/**
* Returns an array containing all of the values in this dictionary.
* @return {Array} an array containing all of the values in this dictionary.
*/
Dictionary.prototype.values = function () {
var array = [];
for (var name_2 in this.table) {
if (util.has(this.table, name_2)) {
var pair = this.table[name_2];
array.push(pair.value);
}
}
return array;
};
/**
* Executes the provided function once for each key-value pair
* present in this dictionary.
* @param {function(Object,Object):*} callback function to execute, it is
* invoked with two arguments: key and value. To break the iteration you can
* optionally return false.
*/
Dictionary.prototype.forEach = function (callback) {
for (var name_3 in this.table) {
if (util.has(this.table, name_3)) {
var pair = this.table[name_3];
var ret = callback(pair.key, pair.value);
if (ret === false) {
return;
}
}
}
};
/**
* Returns true if this dictionary contains a mapping for the specified key.
* @param {Object} key key whose presence in this dictionary is to be
* tested.
* @return {boolean} true if this dictionary contains a mapping for the
* specified key.
*/
Dictionary.prototype.containsKey = function (key) {
return !util.isUndefined(this.getValue(key));
};
/**
* Removes all mappings from this dictionary.
* @this {collections.Dictionary}
*/
Dictionary.prototype.clear = function () {
this.table = {};
this.nElements = 0;
};
/**
* Returns the number of keys in this dictionary.
* @return {number} the number of key-value mappings in this dictionary.
*/
Dictionary.prototype.size = function () {
return this.nElements;
};
/**
* Returns true if this dictionary contains no mappings.
* @return {boolean} true if this dictionary contains no mappings.
*/
Dictionary.prototype.isEmpty = function () {
return this.nElements <= 0;
};
Dictionary.prototype.toString = function () {
var toret = '{';
this.forEach(function (k, v) {
toret += "\n\t" + k + " : " + v;
});
return toret + '\n}';
};
return Dictionary;
}()); // End of dictionary
exports.default = Dictionary;
},{"./util":16}],5:[function(require,module,exports){
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Dictionary_1 = require("./Dictionary");
var util = require("./util");
var FactoryDictionary = /** @class */ (function (_super) {
__extends(FactoryDictionary, _super);
/**
* Creates an empty dictionary.
* @class <p>Dictionaries map keys to values; each key can map to at most one value.
* This implementation accepts any kind of objects as keys.</p>
*
* <p>The default factory function should return a new object of the provided
* type. Example:</p>
* <pre>
* function petFactory() {
* return new Pet();
* }
* </pre>
*
* <p>If the keys are custom objects a function which converts keys to unique
* strings must be provided. Example:</p>
* <pre>
* function petToString(pet) {
* return pet.name;
* }
* </pre>
* @constructor
* @param {function():V=} defaultFactoryFunction function used to create a
* default object.
* @param {function(Object):string=} toStrFunction optional function used
* to convert keys to strings. If the keys aren't strings or if toString()
* is not appropriate, a custom function which receives a key and returns a
* unique string must be provided.
*/
function FactoryDictionary(defaultFactoryFunction, toStrFunction) {
var _this = _super.call(this, toStrFunction) || this;
_this.defaultFactoryFunction = defaultFactoryFunction;
return _this;
}
/**
* Associates the specified default value with the specified key in this dictionary,
* if it didn't contain the key yet. If the key existed, the existing value will be used.
* @param {Object} key key with which the specified value is to be
* associated.
* @param {Object} defaultValue default value to be associated with the specified key.
* @return {*} previous value associated with the specified key, or the default value,
* if the key didn't exist yet.
*/
FactoryDictionary.prototype.setDefault = function (key, defaultValue) {
var currentValue = _super.prototype.getValue.call(this, key);
if (util.isUndefined(currentValue)) {
this.setValue(key, defaultValue);
return defaultValue;
}
return currentValue;
};
/**
* Returns the value to which this dictionary maps the specified key.
* Returns a default value created by the factory passed in the constructor,
* if this dictionary contains no mapping for this key. The missing key will
* automatically be added to the dictionary.
* @param {Object} key key whose associated value is to be returned.
* @return {*} the value to which this dictionary maps the specified key or
* a default value if the map contains no mapping for this key.
*/
FactoryDictionary.prototype.getValue = function (key) {
return this.setDefault(key, this.defaultFactoryFunction());
};
return FactoryDictionary;
}(Dictionary_1.default));
exports.default = FactoryDictionary;
},{"./Dictionary":4,"./util":16}],6:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var collections = require("./util");
var arrays = require("./arrays");
var Heap = /** @class */ (function () {
/**
* Creates an empty Heap.
* @class
* <p>A heap is a binary tree, where the nodes maintain the heap property:
* each node is smaller than each of its children and therefore a MinHeap
* This implementation uses an array to store elements.</p>
* <p>If the inserted elements are custom objects a compare function must be provided,
* at construction time, otherwise the <=, === and >= operators are
* used to compare elements. Example:</p>
*
* <pre>
* function compare(a, b) {
* if (a is less than b by some ordering criterion) {
* return -1;
* } if (a is greater than b by the ordering criterion) {
* return 1;
* }
* // a must be equal to b
* return 0;
* }
* </pre>
*
* <p>If a Max-Heap is wanted (greater elements on top) you can a provide a
* reverse compare function to accomplish that behavior. Example:</p>
*
* <pre>
* function reverseCompare(a, b) {
* if (a is less than b by some ordering criterion) {
* return 1;
* } if (a is greater than b by the ordering criterion) {
* return -1;
* }
* // a must be equal to b
* return 0;
* }
* </pre>
*
* @constructor
* @param {function(Object,Object):number=} compareFunction optional
* function used to compare two elements. Must return a negative integer,
* zero, or a positive integer as the first argument is less than, equal to,
* or greater than the second.
*/
function Heap(compareFunction) {
/**
* Array used to store the elements of the heap.
* @type {Array.<Object>}
* @private
*/
this.data = [];
this.compare = compareFunction || collections.defaultCompare;
}
/**
* Returns the index of the left child of the node at the given index.
* @param {number} nodeIndex The index of the node to get the left child
* for.
* @return {number} The index of the left child.
* @private
*/
Heap.prototype.leftChildIndex = function (nodeIndex) {
return (2 * nodeIndex) + 1;
};
/**
* Returns the index of the right child of the node at the given index.
* @param {number} nodeIndex The index of the node to get the right child
* for.
* @return {number} The index of the right child.
* @private
*/
Heap.prototype.rightChildIndex = function (nodeIndex) {
return (2 * nodeIndex) + 2;
};
/**
* Returns the index of the parent of the node at the given index.
* @param {number} nodeIndex The index of the node to get the parent for.
* @return {number} The index of the parent.
* @private
*/
Heap.prototype.parentIndex = function (nodeIndex) {
return Math.floor((nodeIndex - 1) / 2);
};
/**
* Returns the index of the smaller child node (if it exists).
* @param {number} leftChild left child index.
* @param {number} rightChild right child index.
* @return {number} the index with the minimum value or -1 if it doesn't
* exists.
* @private
*/
Heap.prototype.minIndex = function (leftChild, rightChild) {
if (rightChild >= this.data.length) {
if (leftChild >= this.data.length) {
return -1;
}
else {
return leftChild;
}
}
else {
if (this.compare(this.data[leftChild], this.data[rightChild]) <= 0) {
return leftChild;
}
else {
return rightChild;
}
}
};
/**
* Moves the node at the given index up to its proper place in the heap.
* @param {number} index The index of the node to move up.
* @private
*/
Heap.prototype.siftUp = function (index) {
var parent = this.parentIndex(index);
while (index > 0 && this.compare(this.data[parent], this.data[index]) > 0) {
arrays.swap(this.data, parent, index);
index = parent;
parent = this.parentIndex(index);
}
};
/**
* Moves the node at the given index down to its proper place in the heap.
* @param {number} nodeIndex The index of the node to move down.
* @private
*/
Heap.prototype.siftDown = function (nodeIndex) {
//smaller child index
var min = this.minIndex(this.leftChildIndex(nodeIndex), this.rightChildIndex(nodeIndex));
while (min >= 0 && this.compare(this.data[nodeIndex], this.data[min]) > 0) {
arrays.swap(this.data, min, nodeIndex);
nodeIndex = min;
min = this.minIndex(this.leftChildIndex(nodeIndex), this.rightChildIndex(nodeIndex));
}
};
/**
* Retrieves but does not remove the root element of this heap.
* @return {*} The value at the root of the heap. Returns undefined if the
* heap is empty.
*/
Heap.prototype.peek = function () {
if (this.data.length > 0) {
return this.data[0];
}
else {
return undefined;
}
};
/**
* Adds the given element into the heap.
* @param {*} element the element.
* @return true if the element was added or fals if it is undefined.
*/
Heap.prototype.add = function (element) {
if (collections.isUndefined(element)) {
return false;
}
this.data.push(element);
this.siftUp(this.data.length - 1);
return true;
};
/**
* Retrieves and removes the root element of this heap.
* @return {*} The value removed from the root of the heap. Returns
* undefined if the heap is empty.
*/
Heap.prototype.removeRoot = function () {
if (this.data.length > 0) {
var obj = this.data[0];
this.data[0] = this.data[this.data.length - 1];
this.data.splice(this.data.length - 1, 1);
if (this.data.length > 0) {
this.siftDown(0);
}
return obj;
}
return undefined;
};
/**
* Returns true if this heap contains the specified element.
* @param {Object} element element to search for.
* @return {boolean} true if this Heap contains the specified element, false
* otherwise.
*/
Heap.prototype.contains = function (element) {
var equF = collections.compareToEquals(this.compare);
return arrays.contains(this.data, element, equF);
};
/**
* Returns the number of elements in this heap.
* @return {number} the number of elements in this heap.
*/
Heap.prototype.size = function () {
return this.data.length;
};
/**
* Checks if this heap is empty.
* @return {boolean} true if and only if this heap contains no items; false
* otherwise.
*/
Heap.prototype.isEmpty = function () {
return this.data.length <= 0;
};
/**
* Removes all of the elements from this heap.
*/
Heap.prototype.clear = function () {
this.data.length = 0;
};
/**
* Executes the provided function once for each element present in this heap in
* no particular order.
* @param {function(Object):*} callback function to execute, it is
* invoked with one argument: the element value, to break the iteration you can
* optionally return false.
*/
Heap.prototype.forEach = function (callback) {
arrays.forEach(this.data, callback);
};
return Heap;
}());
exports.default = Heap;
},{"./arrays":15,"./util":16}],7:[function(require,module,exports){
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Dictionary_1 = require("./Dictionary");
var util = require("./util");
/**
* This class is used by the LinkedDictionary Internally
* Has to be a class, not an interface, because it needs to have
* the 'unlink' function defined.
*/
var LinkedDictionaryPair = /** @class */ (function () {
function LinkedDictionaryPair(key, value) {
this.key = key;
this.value = value;
}
LinkedDictionaryPair.prototype.unlink = function () {
this.prev.next = this.next;
this.next.prev = this.prev;
};
return LinkedDictionaryPair;
}());
/**
* The head and tail elements of the list have null key and value properties but they
* usually link to normal nodes.
*/
var HeadOrTailLinkedDictionaryPair = /** @class */ (function () {
function HeadOrTailLinkedDictionaryPair() {
this.key = null;
this.value = null;
}
HeadOrTailLinkedDictionaryPair.prototype.unlink = function () {
this.prev.next = this.next;
this.next.prev = this.prev;
};
return HeadOrTailLinkedDictionaryPair;
}());
function isHeadOrTailLinkedDictionaryPair(p) {
return !p.next;
}
var LinkedDictionary = /** @class */ (function (_super) {
__extends(LinkedDictionary, _super);
function LinkedDictionary(toStrFunction) {
var _this = _super.call(this, toStrFunction) || this;
_this.head = new HeadOrTailLinkedDictionaryPair();
_this.tail = new HeadOrTailLinkedDictionaryPair();
_this.head.next = _this.tail;
_this.tail.prev = _this.head;
return _this;
}
/**
* Inserts the new node to the 'tail' of the list, updating the
* neighbors, and moving 'this.tail' (the End of List indicator) that
* to the end.
*/
LinkedDictionary.prototype.appendToTail = function (entry) {
var lastNode = this.tail.prev;
lastNode.next = entry;
entry.prev = lastNode;
entry.next = this.tail;
this.tail.prev = entry;
};
/**
* Retrieves a linked dictionary from the table internally
*/
LinkedDictionary.prototype.getLinkedDictionaryPair = function (key) {
if (util.isUndefined(key)) {
return undefined;
}
var k = '$' + this.toStr(key);
var pair = (this.table[k]);
return pair;
};
/**
* Returns the value to which this dictionary maps the specified key.
* Returns undefined if this dictionary contains no mapping for this key.
* @param {Object} key key whose associated value is to be returned.
* @return {*} the value to which this dictionary maps the specified key or
* undefined if the map contains no mapping for this key.
*/
LinkedDictionary.prototype.getValue = function (key) {
var pair = this.getLinkedDictionaryPair(key);
if (!util.isUndefined(pair)) {
return pair.value;
}
return undefined;
};
/**
* Removes the mapping for this key from this dictionary if it is present.
* Also, if a value is present for this key, the entry is removed from the
* insertion ordering.
* @param {Object} key key whose mapping is to be removed from the
* dictionary.
* @return {*} previous value associated with specified key, or undefined if
* there was no mapping for key.
*/
LinkedDictionary.prototype.remove = function (key) {
var pair = this.getLinkedDictionaryPair(key);
if (!util.isUndefined(pair)) {
_super.prototype.remove.call(this, key); // This will remove it from the table
pair.unlink(); // This will unlink it from the chain
return pair.value;
}
return undefined;
};
/**
* Removes all mappings from this LinkedDictionary.
* @this {collections.LinkedDictionary}
*/
LinkedDictionary.prototype.clear = function () {
_super.prototype.clear.call(this);
this.head.next = this.tail;
this.tail.prev = this.head;
};
/**
* Internal function used when updating an existing KeyValue pair.
* It places the new value indexed by key into the table, but maintains
* its place in the linked ordering.
*/
LinkedDictionary.prototype.replace = function (oldPair, newPair) {
var k = '$' + this.toStr(newPair.key);
// set the new Pair's links to existingPair's links
newPair.next = oldPair.next;
newPair.prev = oldPair.prev;
// Delete Existing Pair from the table, unlink it from chain.
// As a result, the nElements gets decremented by this operation
this.remove(oldPair.key);
// Link new Pair in place of where oldPair was,
// by pointing the old pair's neighbors to it.
newPair.prev.next = newPair;
newPair.next.prev = newPair;
this.table[k] = newPair;
// To make up for the fact that the number of elements was decremented,
// We need to increase it by one.
++this.nElements;
};
/**
* Associates the specified value with the specified key in this dictionary.
* If the dictionary previously contained a mapping for this key, the old
* value is replaced by the specified value.
* Updating of a key that already exists maintains its place in the
* insertion order into the map.
* @param {Object} key key with which the specified value is to be
* associated.
* @param {Object} value value to be associated with the specified key.
* @return {*} previous value associated with the specified key, or undefined if
* there was no mapping for the key or if the key/value are undefined.
*/
LinkedDictionary.prototype.setValue = function (key, value) {
if (util.isUndefined(key) || util.isUndefined(value)) {
return undefined;
}
var existingPair = this.getLinkedDictionaryPair(key);
var newPair = new LinkedDictionaryPair(key, value);
var k = '$' + this.toStr(key);
// If there is already an element for that key, we
// keep it's place in the LinkedList
if (!util.isUndefined(existingPair)) {
this.replace(existingPair, newPair);
return existingPair.value;
}
else {
this.appendToTail(newPair);
this.table[k] = newPair;
++this.nElements;
return undefined;
}
};
/**
* Returns an array containing all of the keys in this LinkedDictionary, ordered
* by insertion order.
* @return {Array} an array containing all of the keys in this LinkedDictionary,
* ordered by insertion order.
*/
LinkedDictionary.prototype.keys = function () {
var array = [];
this.forEach(function (key, value) {
array.push(key);
});
return array;
};
/**
* Returns an array containing all of the values in this LinkedDictionary, ordered by
* insertion order.
* @return {Array} an array containing all of the values in this LinkedDictionary,
* ordered by insertion order.
*/
LinkedDictionary.prototype.values = function () {
var array = [];
this.forEach(function (key, value) {
array.push(value);
});
return array;
};
/**
* Executes the provided function once for each key-value pair
* present in this LinkedDictionary. It is done in the order of insertion
* into the LinkedDictionary
* @param {function(Object,Object):*} callback function to execute, it is
* invoked with two arguments: key and value. To break the iteration you can
* optionally return false.
*/
LinkedDictionary.prototype.forEach = function (callback) {
var crawlNode = this.head.next;
while (!isHeadOrTailLinkedDictionaryPair(crawlNode)) {
var ret = callback(crawlNode.key, crawlNode.value);
if (ret === false) {
return;
}
crawlNode = crawlNode.next;
}
};
return LinkedDictionary;
}(Dictionary_1.default)); // End of LinkedDictionary
exports.default = LinkedDictionary;
// /**
// * Returns true if this dictionary is equal to the given dictionary.
// * Two dictionaries are equal if they contain the same mappings.
// * @param {collections.Dictionary} other the other dictionary.
// * @param {function(Object,Object):boolean=} valuesEqualFunction optional
// * function used to check if two values are equal.
// * @return {boolean} true if this dictionary is equal