Update wmts-hidpi, add nicer-api-docs
This commit is contained in:
835
nicer-api-docs/closure-library/closure/goog/structs/avltree.js
Normal file
835
nicer-api-docs/closure-library/closure/goog/structs/avltree.js
Normal file
@@ -0,0 +1,835 @@
|
||||
// Copyright 2007 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: AvlTree.
|
||||
*
|
||||
*
|
||||
* This file provides the implementation of an AVL-Tree datastructure. The tree
|
||||
* maintains a set of unique values in a sorted order. The values can be
|
||||
* accessed efficiently in their sorted order since the tree enforces an O(logn)
|
||||
* maximum height. See http://en.wikipedia.org/wiki/Avl_tree for more detail.
|
||||
*
|
||||
* The big-O notation for all operations are below:
|
||||
* <pre>
|
||||
* Method big-O
|
||||
* ----------------------------------------------------------------------------
|
||||
* - add O(logn)
|
||||
* - remove O(logn)
|
||||
* - clear O(1)
|
||||
* - contains O(logn)
|
||||
* - getCount O(1)
|
||||
* - getMinimum O(1), or O(logn) when optional root is specified
|
||||
* - getMaximum O(1), or O(logn) when optional root is specified
|
||||
* - getHeight O(1)
|
||||
* - getValues O(n)
|
||||
* - inOrderTraverse O(logn + k), where k is number of traversed nodes
|
||||
* - reverseOrderTraverse O(logn + k), where k is number of traversed nodes
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs.AvlTree');
|
||||
goog.provide('goog.structs.AvlTree.Node');
|
||||
|
||||
goog.require('goog.structs.Collection');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs an AVL-Tree, which uses the specified comparator to order its
|
||||
* values. The values can be accessed efficiently in their sorted order since
|
||||
* the tree enforces a O(logn) maximum height.
|
||||
*
|
||||
* @param {Function=} opt_comparator Function used to order the tree's nodes.
|
||||
* @constructor
|
||||
* @implements {goog.structs.Collection}
|
||||
*/
|
||||
goog.structs.AvlTree = function(opt_comparator) {
|
||||
this.comparator_ = opt_comparator ||
|
||||
goog.structs.AvlTree.DEFAULT_COMPARATOR_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* String comparison function used to compare values in the tree. This function
|
||||
* is used by default if no comparator is specified in the tree's constructor.
|
||||
*
|
||||
* @param {string} a The first string.
|
||||
* @param {string} b The second string.
|
||||
* @return {number} -1 if a < b, 1 if a > b, 0 if a = b.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.AvlTree.DEFAULT_COMPARATOR_ = function(a, b) {
|
||||
if (String(a) < String(b)) {
|
||||
return -1;
|
||||
} else if (String(a) > String(b)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Pointer to the root node of the tree.
|
||||
*
|
||||
* @type {goog.structs.AvlTree.Node}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.root_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Comparison function used to compare values in the tree. This function should
|
||||
* take two values, a and b, and return x where:
|
||||
* <pre>
|
||||
* x < 0 if a < b,
|
||||
* x > 0 if a > b,
|
||||
* x = 0 otherwise
|
||||
* </pre>
|
||||
*
|
||||
* @type {Function}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.comparator_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Pointer to the node with the smallest value in the tree.
|
||||
*
|
||||
* @type {goog.structs.AvlTree.Node}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.minNode_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Pointer to the node with the largest value in the tree.
|
||||
*
|
||||
* @type {goog.structs.AvlTree.Node}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.maxNode_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Inserts a node into the tree with the specified value if the tree does
|
||||
* not already contain a node with the specified value. If the value is
|
||||
* inserted, the tree is balanced to enforce the AVL-Tree height property.
|
||||
*
|
||||
* @param {*} value Value to insert into the tree.
|
||||
* @return {boolean} Whether value was inserted into the tree.
|
||||
* @override
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.add = function(value) {
|
||||
// If the tree is empty, create a root node with the specified value
|
||||
if (this.root_ == null) {
|
||||
this.root_ = new goog.structs.AvlTree.Node(value);
|
||||
this.minNode_ = this.root_;
|
||||
this.maxNode_ = this.root_;
|
||||
return true;
|
||||
}
|
||||
|
||||
// This will be set to the new node if a new node is added.
|
||||
var newNode = null;
|
||||
|
||||
// Depth traverse the tree and insert the value if we reach a null node
|
||||
this.traverse_(function(node) {
|
||||
var retNode = null;
|
||||
if (this.comparator_(node.value, value) > 0) {
|
||||
retNode = node.left;
|
||||
if (node.left == null) {
|
||||
newNode = new goog.structs.AvlTree.Node(value, node);
|
||||
node.left = newNode;
|
||||
if (node == this.minNode_) {
|
||||
this.minNode_ = newNode;
|
||||
}
|
||||
}
|
||||
} else if (this.comparator_(node.value, value) < 0) {
|
||||
retNode = node.right;
|
||||
if (node.right == null) {
|
||||
newNode = new goog.structs.AvlTree.Node(value, node);
|
||||
node.right = newNode;
|
||||
if (node == this.maxNode_) {
|
||||
this.maxNode_ = newNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retNode; // If null, we'll stop traversing the tree
|
||||
});
|
||||
|
||||
// If a node was added, increment counts and balance tree.
|
||||
if (newNode) {
|
||||
this.traverse_(
|
||||
function(node) {
|
||||
node.count++;
|
||||
return node.parent;
|
||||
},
|
||||
newNode.parent);
|
||||
this.balance_(newNode.parent); // Maintain the AVL-tree balance
|
||||
}
|
||||
|
||||
// Return true if a node was added, false otherwise
|
||||
return !!newNode;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a node from the tree with the specified value if the tree contains a
|
||||
* node with this value. If a node is removed the tree is balanced to enforce
|
||||
* the AVL-Tree height property. The value of the removed node is returned.
|
||||
*
|
||||
* @param {*} value Value to find and remove from the tree.
|
||||
* @return {*} The value of the removed node or null if the value was not in
|
||||
* the tree.
|
||||
* @override
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.remove = function(value) {
|
||||
// Assume the value is not removed and set the value when it is removed
|
||||
var retValue = null;
|
||||
|
||||
// Depth traverse the tree and remove the value if we find it
|
||||
this.traverse_(function(node) {
|
||||
var retNode = null;
|
||||
if (this.comparator_(node.value, value) > 0) {
|
||||
retNode = node.left;
|
||||
} else if (this.comparator_(node.value, value) < 0) {
|
||||
retNode = node.right;
|
||||
} else {
|
||||
retValue = node.value;
|
||||
this.removeNode_(node);
|
||||
}
|
||||
return retNode; // If null, we'll stop traversing the tree
|
||||
});
|
||||
|
||||
// Return the value that was removed, null if the value was not in the tree
|
||||
return retValue;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all nodes from the tree.
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.clear = function() {
|
||||
this.root_ = null;
|
||||
this.minNode_ = null;
|
||||
this.maxNode_ = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the tree contains a node with the specified value, false
|
||||
* otherwise.
|
||||
*
|
||||
* @param {*} value Value to find in the tree.
|
||||
* @return {boolean} Whether the tree contains a node with the specified value.
|
||||
* @override
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.contains = function(value) {
|
||||
// Assume the value is not in the tree and set this value if it is found
|
||||
var isContained = false;
|
||||
|
||||
// Depth traverse the tree and set isContained if we find the node
|
||||
this.traverse_(function(node) {
|
||||
var retNode = null;
|
||||
if (this.comparator_(node.value, value) > 0) {
|
||||
retNode = node.left;
|
||||
} else if (this.comparator_(node.value, value) < 0) {
|
||||
retNode = node.right;
|
||||
} else {
|
||||
isContained = true;
|
||||
}
|
||||
return retNode; // If null, we'll stop traversing the tree
|
||||
});
|
||||
|
||||
// Return true if the value is contained in the tree, false otherwise
|
||||
return isContained;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of values stored in the tree.
|
||||
*
|
||||
* @return {number} The number of values stored in the tree.
|
||||
* @override
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.getCount = function() {
|
||||
return this.root_ ? this.root_.count : 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a k-th smallest value, based on the comparator, where 0 <= k <
|
||||
* this.getCount().
|
||||
* @param {number} k The number k.
|
||||
* @return {*} The k-th smallest value.
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.getKthValue = function(k) {
|
||||
if (k < 0 || k >= this.getCount()) {
|
||||
return null;
|
||||
}
|
||||
return this.getKthNode_(k).value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value u, such that u is contained in the tree and u < v, for all
|
||||
* values v in the tree where v != u.
|
||||
*
|
||||
* @return {*} The minimum value contained in the tree.
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.getMinimum = function() {
|
||||
return this.getMinNode_().value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value u, such that u is contained in the tree and u > v, for all
|
||||
* values v in the tree where v != u.
|
||||
*
|
||||
* @return {*} The maximum value contained in the tree.
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.getMaximum = function() {
|
||||
return this.getMaxNode_().value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the height of the tree (the maximum depth). This height should
|
||||
* always be <= 1.4405*(Math.log(n+2)/Math.log(2))-1.3277, where n is the
|
||||
* number of nodes in the tree.
|
||||
*
|
||||
* @return {number} The height of the tree.
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.getHeight = function() {
|
||||
return this.root_ ? this.root_.height : 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Inserts the values stored in the tree into a new Array and returns the Array.
|
||||
*
|
||||
* @return {Array} An array containing all of the trees values in sorted order.
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.getValues = function() {
|
||||
var ret = [];
|
||||
this.inOrderTraverse(function(value) {
|
||||
ret.push(value);
|
||||
});
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an in-order traversal of the tree and calls {@code func} with each
|
||||
* traversed node, optionally starting from the smallest node with a value >= to
|
||||
* the specified start value. The traversal ends after traversing the tree's
|
||||
* maximum node or when {@code func} returns a value that evaluates to true.
|
||||
*
|
||||
* @param {Function} func Function to call on each traversed node.
|
||||
* @param {Object=} opt_startValue If specified, traversal will begin on the
|
||||
* node with the smallest value >= opt_startValue.
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.inOrderTraverse =
|
||||
function(func, opt_startValue) {
|
||||
// If our tree is empty, return immediately
|
||||
if (!this.root_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Depth traverse the tree to find node to begin in-order traversal from
|
||||
var startNode;
|
||||
if (opt_startValue) {
|
||||
this.traverse_(function(node) {
|
||||
var retNode = null;
|
||||
if (this.comparator_(node.value, opt_startValue) > 0) {
|
||||
retNode = node.left;
|
||||
startNode = node;
|
||||
} else if (this.comparator_(node.value, opt_startValue) < 0) {
|
||||
retNode = node.right;
|
||||
} else {
|
||||
startNode = node;
|
||||
}
|
||||
return retNode; // If null, we'll stop traversing the tree
|
||||
});
|
||||
} else {
|
||||
startNode = this.getMinNode_();
|
||||
}
|
||||
|
||||
// Traverse the tree and call func on each traversed node's value
|
||||
var node = startNode, prev = startNode.left ? startNode.left : startNode;
|
||||
while (node != null) {
|
||||
if (node.left != null && node.left != prev && node.right != prev) {
|
||||
node = node.left;
|
||||
} else {
|
||||
if (node.right != prev) {
|
||||
if (func(node.value)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var temp = node;
|
||||
node = node.right != null && node.right != prev ?
|
||||
node.right :
|
||||
node.parent;
|
||||
prev = temp;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs a reverse-order traversal of the tree and calls {@code func} with
|
||||
* each traversed node, optionally starting from the largest node with a value
|
||||
* <= to the specified start value. The traversal ends after traversing the
|
||||
* tree's minimum node or when func returns a value that evaluates to true.
|
||||
*
|
||||
* @param {Function} func Function to call on each traversed node.
|
||||
* @param {Object=} opt_startValue If specified, traversal will begin on the
|
||||
* node with the largest value <= opt_startValue.
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.reverseOrderTraverse =
|
||||
function(func, opt_startValue) {
|
||||
// If our tree is empty, return immediately
|
||||
if (!this.root_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Depth traverse the tree to find node to begin reverse-order traversal from
|
||||
var startNode;
|
||||
if (opt_startValue) {
|
||||
this.traverse_(goog.bind(function(node) {
|
||||
var retNode = null;
|
||||
if (this.comparator_(node.value, opt_startValue) > 0) {
|
||||
retNode = node.left;
|
||||
} else if (this.comparator_(node.value, opt_startValue) < 0) {
|
||||
retNode = node.right;
|
||||
startNode = node;
|
||||
} else {
|
||||
startNode = node;
|
||||
}
|
||||
return retNode; // If null, we'll stop traversing the tree
|
||||
}, this));
|
||||
} else {
|
||||
startNode = this.getMaxNode_();
|
||||
}
|
||||
|
||||
// Traverse the tree and call func on each traversed node's value
|
||||
var node = startNode, prev = startNode.right ? startNode.right : startNode;
|
||||
while (node != null) {
|
||||
if (node.right != null && node.right != prev && node.left != prev) {
|
||||
node = node.right;
|
||||
} else {
|
||||
if (node.left != prev) {
|
||||
if (func(node.value)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var temp = node;
|
||||
node = node.left != null && node.left != prev ?
|
||||
node.left :
|
||||
node.parent;
|
||||
prev = temp;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs a traversal defined by the supplied {@code traversalFunc}. The first
|
||||
* call to {@code traversalFunc} is passed the root or the optionally specified
|
||||
* startNode. After that, calls {@code traversalFunc} with the node returned
|
||||
* by the previous call to {@code traversalFunc} until {@code traversalFunc}
|
||||
* returns null or the optionally specified endNode. The first call to
|
||||
* traversalFunc is passed the root or the optionally specified startNode.
|
||||
*
|
||||
* @param {Function} traversalFunc Function used to traverse the tree. Takes a
|
||||
* node as a parameter and returns a node.
|
||||
* @param {goog.structs.AvlTree.Node=} opt_startNode The node at which the
|
||||
* traversal begins.
|
||||
* @param {goog.structs.AvlTree.Node=} opt_endNode The node at which the
|
||||
* traversal ends.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.traverse_ =
|
||||
function(traversalFunc, opt_startNode, opt_endNode) {
|
||||
var node = opt_startNode ? opt_startNode : this.root_;
|
||||
var endNode = opt_endNode ? opt_endNode : null;
|
||||
while (node && node != endNode) {
|
||||
node = traversalFunc.call(this, node);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Ensures that the specified node and all its ancestors are balanced. If they
|
||||
* are not, performs left and right tree rotations to achieve a balanced
|
||||
* tree. This method assumes that at most 2 rotations are necessary to balance
|
||||
* the tree (which is true for AVL-trees that are balanced after each node is
|
||||
* added or removed).
|
||||
*
|
||||
* @param {goog.structs.AvlTree.Node} node Node to begin balance from.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.balance_ = function(node) {
|
||||
|
||||
this.traverse_(function(node) {
|
||||
// Calculate the left and right node's heights
|
||||
var lh = node.left ? node.left.height : 0;
|
||||
var rh = node.right ? node.right.height : 0;
|
||||
|
||||
// Rotate tree rooted at this node if it is not AVL-tree balanced
|
||||
if (lh - rh > 1) {
|
||||
if (node.left.right && (!node.left.left ||
|
||||
node.left.left.height < node.left.right.height)) {
|
||||
this.leftRotate_(node.left);
|
||||
}
|
||||
this.rightRotate_(node);
|
||||
} else if (rh - lh > 1) {
|
||||
if (node.right.left && (!node.right.right ||
|
||||
node.right.right.height < node.right.left.height)) {
|
||||
this.rightRotate_(node.right);
|
||||
}
|
||||
this.leftRotate_(node);
|
||||
}
|
||||
|
||||
// Recalculate the left and right node's heights
|
||||
lh = node.left ? node.left.height : 0;
|
||||
rh = node.right ? node.right.height : 0;
|
||||
|
||||
// Set this node's height
|
||||
node.height = Math.max(lh, rh) + 1;
|
||||
|
||||
// Traverse up tree and balance parent
|
||||
return node.parent;
|
||||
}, node);
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs a left tree rotation on the specified node.
|
||||
*
|
||||
* @param {goog.structs.AvlTree.Node} node Pivot node to rotate from.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.leftRotate_ = function(node) {
|
||||
// Re-assign parent-child references for the parent of the node being removed
|
||||
if (node.isLeftChild()) {
|
||||
node.parent.left = node.right;
|
||||
node.right.parent = node.parent;
|
||||
} else if (node.isRightChild()) {
|
||||
node.parent.right = node.right;
|
||||
node.right.parent = node.parent;
|
||||
} else {
|
||||
this.root_ = node.right;
|
||||
this.root_.parent = null;
|
||||
}
|
||||
|
||||
// Re-assign parent-child references for the child of the node being removed
|
||||
var temp = node.right;
|
||||
node.right = node.right.left;
|
||||
if (node.right != null) node.right.parent = node;
|
||||
temp.left = node;
|
||||
node.parent = temp;
|
||||
|
||||
// Update counts.
|
||||
temp.count = node.count;
|
||||
node.count -= (temp.right ? temp.right.count : 0) + 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs a right tree rotation on the specified node.
|
||||
*
|
||||
* @param {goog.structs.AvlTree.Node} node Pivot node to rotate from.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.rightRotate_ = function(node) {
|
||||
// Re-assign parent-child references for the parent of the node being removed
|
||||
if (node.isLeftChild()) {
|
||||
node.parent.left = node.left;
|
||||
node.left.parent = node.parent;
|
||||
} else if (node.isRightChild()) {
|
||||
node.parent.right = node.left;
|
||||
node.left.parent = node.parent;
|
||||
} else {
|
||||
this.root_ = node.left;
|
||||
this.root_.parent = null;
|
||||
}
|
||||
|
||||
// Re-assign parent-child references for the child of the node being removed
|
||||
var temp = node.left;
|
||||
node.left = node.left.right;
|
||||
if (node.left != null) node.left.parent = node;
|
||||
temp.right = node;
|
||||
node.parent = temp;
|
||||
|
||||
// Update counts.
|
||||
temp.count = node.count;
|
||||
node.count -= (temp.left ? temp.left.count : 0) + 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the specified node from the tree and ensures the tree still
|
||||
* maintains the AVL-tree balance.
|
||||
*
|
||||
* @param {goog.structs.AvlTree.Node} node The node to be removed.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.removeNode_ = function(node) {
|
||||
// Perform normal binary tree node removal, but balance the tree, starting
|
||||
// from where we removed the node
|
||||
if (node.left != null || node.right != null) {
|
||||
var b = null; // Node to begin balance from
|
||||
var r; // Node to replace the node being removed
|
||||
if (node.left != null) {
|
||||
r = this.getMaxNode_(node.left);
|
||||
|
||||
// Update counts.
|
||||
this.traverse_(function(node) {
|
||||
node.count--;
|
||||
return node.parent;
|
||||
}, r);
|
||||
|
||||
if (r != node.left) {
|
||||
r.parent.right = r.left;
|
||||
if (r.left) r.left.parent = r.parent;
|
||||
r.left = node.left;
|
||||
r.left.parent = r;
|
||||
b = r.parent;
|
||||
}
|
||||
r.parent = node.parent;
|
||||
r.right = node.right;
|
||||
if (r.right) r.right.parent = r;
|
||||
if (node == this.maxNode_) this.maxNode_ = r;
|
||||
r.count = node.count;
|
||||
} else {
|
||||
r = this.getMinNode_(node.right);
|
||||
|
||||
// Update counts.
|
||||
this.traverse_(function(node) {
|
||||
node.count--;
|
||||
return node.parent;
|
||||
}, r);
|
||||
|
||||
if (r != node.right) {
|
||||
r.parent.left = r.right;
|
||||
if (r.right) r.right.parent = r.parent;
|
||||
r.right = node.right;
|
||||
r.right.parent = r;
|
||||
b = r.parent;
|
||||
}
|
||||
r.parent = node.parent;
|
||||
r.left = node.left;
|
||||
if (r.left) r.left.parent = r;
|
||||
if (node == this.minNode_) this.minNode_ = r;
|
||||
r.count = node.count;
|
||||
}
|
||||
|
||||
// Update the parent of the node being removed to point to its replace
|
||||
if (node.isLeftChild()) {
|
||||
node.parent.left = r;
|
||||
} else if (node.isRightChild()) {
|
||||
node.parent.right = r;
|
||||
} else {
|
||||
this.root_ = r;
|
||||
}
|
||||
|
||||
// Balance the tree
|
||||
this.balance_(b ? b : r);
|
||||
} else {
|
||||
// Update counts.
|
||||
this.traverse_(function(node) {
|
||||
node.count--;
|
||||
return node.parent;
|
||||
}, node.parent);
|
||||
|
||||
// If the node is a leaf, remove it and balance starting from its parent
|
||||
if (node.isLeftChild()) {
|
||||
this.special = 1;
|
||||
node.parent.left = null;
|
||||
if (node == this.minNode_) this.minNode_ = node.parent;
|
||||
this.balance_(node.parent);
|
||||
} else if (node.isRightChild()) {
|
||||
node.parent.right = null;
|
||||
if (node == this.maxNode_) this.maxNode_ = node.parent;
|
||||
this.balance_(node.parent);
|
||||
} else {
|
||||
this.clear();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the node in the tree that has k nodes before it in an in-order
|
||||
* traversal, optionally rooted at {@code opt_rootNode}.
|
||||
*
|
||||
* @param {number} k The number of nodes before the node to be returned in an
|
||||
* in-order traversal, where 0 <= k < root.count.
|
||||
* @param {goog.structs.AvlTree.Node=} opt_rootNode Optional root node.
|
||||
* @return {goog.structs.AvlTree.Node} The node at the specified index.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.getKthNode_ = function(k, opt_rootNode) {
|
||||
var root = opt_rootNode || this.root_;
|
||||
var numNodesInLeftSubtree = root.left ? root.left.count : 0;
|
||||
|
||||
if (k < numNodesInLeftSubtree) {
|
||||
return this.getKthNode_(k, root.left);
|
||||
} else if (k == numNodesInLeftSubtree) {
|
||||
return root;
|
||||
} else {
|
||||
return this.getKthNode_(k - numNodesInLeftSubtree - 1, root.right);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the node with the smallest value in tree, optionally rooted at
|
||||
* {@code opt_rootNode}.
|
||||
*
|
||||
* @param {goog.structs.AvlTree.Node=} opt_rootNode Optional root node.
|
||||
* @return {goog.structs.AvlTree.Node} The node with the smallest value in
|
||||
* the tree.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.getMinNode_ = function(opt_rootNode) {
|
||||
if (!opt_rootNode) {
|
||||
return this.minNode_;
|
||||
}
|
||||
|
||||
var minNode = opt_rootNode;
|
||||
this.traverse_(function(node) {
|
||||
var retNode = null;
|
||||
if (node.left) {
|
||||
minNode = node.left;
|
||||
retNode = node.left;
|
||||
}
|
||||
return retNode; // If null, we'll stop traversing the tree
|
||||
}, opt_rootNode);
|
||||
|
||||
return minNode;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the node with the largest value in tree, optionally rooted at
|
||||
* opt_rootNode.
|
||||
*
|
||||
* @param {goog.structs.AvlTree.Node=} opt_rootNode Optional root node.
|
||||
* @return {goog.structs.AvlTree.Node} The node with the largest value in
|
||||
* the tree.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.AvlTree.prototype.getMaxNode_ = function(opt_rootNode) {
|
||||
if (!opt_rootNode) {
|
||||
return this.maxNode_;
|
||||
}
|
||||
|
||||
var maxNode = opt_rootNode;
|
||||
this.traverse_(function(node) {
|
||||
var retNode = null;
|
||||
if (node.right) {
|
||||
maxNode = node.right;
|
||||
retNode = node.right;
|
||||
}
|
||||
return retNode; // If null, we'll stop traversing the tree
|
||||
}, opt_rootNode);
|
||||
|
||||
return maxNode;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs an AVL-Tree node with the specified value. If no parent is
|
||||
* specified, the node's parent is assumed to be null. The node's height
|
||||
* defaults to 1 and its children default to null.
|
||||
*
|
||||
* @param {*} value Value to store in the node.
|
||||
* @param {goog.structs.AvlTree.Node=} opt_parent Optional parent node.
|
||||
* @constructor
|
||||
*/
|
||||
goog.structs.AvlTree.Node = function(value, opt_parent) {
|
||||
/**
|
||||
* The value stored by the node.
|
||||
*
|
||||
* @type {*}
|
||||
*/
|
||||
this.value = value;
|
||||
|
||||
/**
|
||||
* The node's parent. Null if the node is the root.
|
||||
*
|
||||
* @type {goog.structs.AvlTree.Node}
|
||||
*/
|
||||
this.parent = opt_parent ? opt_parent : null;
|
||||
|
||||
/**
|
||||
* The number of nodes in the subtree rooted at this node.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
this.count = 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The node's left child. Null if the node does not have a left child.
|
||||
*
|
||||
* @type {goog.structs.AvlTree.Node?}
|
||||
*/
|
||||
goog.structs.AvlTree.Node.prototype.left = null;
|
||||
|
||||
|
||||
/**
|
||||
* The node's right child. Null if the node does not have a right child.
|
||||
*
|
||||
* @type {goog.structs.AvlTree.Node?}
|
||||
*/
|
||||
goog.structs.AvlTree.Node.prototype.right = null;
|
||||
|
||||
|
||||
/**
|
||||
* The height of the tree rooted at this node.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
goog.structs.AvlTree.Node.prototype.height = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Returns true iff the specified node has a parent and is the right child of
|
||||
* its parent.
|
||||
*
|
||||
* @return {boolean} Whether the specified node has a parent and is the right
|
||||
* child of its parent.
|
||||
*/
|
||||
goog.structs.AvlTree.Node.prototype.isRightChild = function() {
|
||||
return !!this.parent && this.parent.right == this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true iff the specified node has a parent and is the left child of
|
||||
* its parent.
|
||||
*
|
||||
* @return {boolean} Whether the specified node has a parent and is the left
|
||||
* child of its parent.
|
||||
*/
|
||||
goog.structs.AvlTree.Node.prototype.isLeftChild = function() {
|
||||
return !!this.parent && this.parent.left == this;
|
||||
};
|
||||
@@ -0,0 +1,223 @@
|
||||
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: Circular Buffer.
|
||||
*
|
||||
* Implements a buffer with a maximum size. New entries override the oldest
|
||||
* entries when the maximum size has been reached.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs.CircularBuffer');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for CircularBuffer.
|
||||
* @param {number=} opt_maxSize The maximum size of the buffer.
|
||||
* @constructor
|
||||
*/
|
||||
goog.structs.CircularBuffer = function(opt_maxSize) {
|
||||
/**
|
||||
* Maximum size of the the circular array structure.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.maxSize_ = opt_maxSize || 100;
|
||||
|
||||
/**
|
||||
* Underlying array for the CircularBuffer.
|
||||
* @type {Array}
|
||||
* @private
|
||||
*/
|
||||
this.buff_ = [];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Index of the next element in the circular array structure.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.CircularBuffer.prototype.nextPtr_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Adds an item to the buffer. May remove the oldest item if the buffer is at
|
||||
* max size.
|
||||
* @param {*} item The item to add.
|
||||
* @return {*} The removed old item, if the buffer is at max size.
|
||||
* Return undefined, otherwise.
|
||||
*/
|
||||
goog.structs.CircularBuffer.prototype.add = function(item) {
|
||||
var previousItem = this.buff_[this.nextPtr_];
|
||||
this.buff_[this.nextPtr_] = item;
|
||||
this.nextPtr_ = (this.nextPtr_ + 1) % this.maxSize_;
|
||||
return previousItem;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the item at the specified index.
|
||||
* @param {number} index The index of the item. The index of an item can change
|
||||
* after calls to {@code add()} if the buffer is at maximum size.
|
||||
* @return {*} The item at the specified index.
|
||||
*/
|
||||
goog.structs.CircularBuffer.prototype.get = function(index) {
|
||||
index = this.normalizeIndex_(index);
|
||||
return this.buff_[index];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the item at the specified index.
|
||||
* @param {number} index The index of the item. The index of an item can change
|
||||
* after calls to {@code add()} if the buffer is at maximum size.
|
||||
* @param {*} item The item to add.
|
||||
*/
|
||||
goog.structs.CircularBuffer.prototype.set = function(index, item) {
|
||||
index = this.normalizeIndex_(index);
|
||||
this.buff_[index] = item;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current number of items in the buffer.
|
||||
* @return {number} The current number of items in the buffer.
|
||||
*/
|
||||
goog.structs.CircularBuffer.prototype.getCount = function() {
|
||||
return this.buff_.length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the buffer is empty.
|
||||
*/
|
||||
goog.structs.CircularBuffer.prototype.isEmpty = function() {
|
||||
return this.buff_.length == 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Empties the current buffer.
|
||||
*/
|
||||
goog.structs.CircularBuffer.prototype.clear = function() {
|
||||
this.buff_.length = 0;
|
||||
this.nextPtr_ = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array} The values in the buffer.
|
||||
*/
|
||||
goog.structs.CircularBuffer.prototype.getValues = function() {
|
||||
// getNewestValues returns all the values if the maxCount parameter is the
|
||||
// count
|
||||
return this.getNewestValues(this.getCount());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the newest values in the buffer up to {@code count}.
|
||||
* @param {number} maxCount The maximum number of values to get. Should be a
|
||||
* positive number.
|
||||
* @return {Array} The newest values in the buffer up to {@code count}.
|
||||
*/
|
||||
goog.structs.CircularBuffer.prototype.getNewestValues = function(maxCount) {
|
||||
var l = this.getCount();
|
||||
var start = this.getCount() - maxCount;
|
||||
var rv = [];
|
||||
for (var i = start; i < l; i++) {
|
||||
rv[i] = this.get(i);
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array} The indexes in the buffer.
|
||||
*/
|
||||
goog.structs.CircularBuffer.prototype.getKeys = function() {
|
||||
var rv = [];
|
||||
var l = this.getCount();
|
||||
for (var i = 0; i < l; i++) {
|
||||
rv[i] = i;
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the buffer contains the key/index.
|
||||
* @param {number} key The key/index to check for.
|
||||
* @return {boolean} Whether the buffer contains the key/index.
|
||||
*/
|
||||
goog.structs.CircularBuffer.prototype.containsKey = function(key) {
|
||||
return key < this.getCount();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the buffer contains the given value.
|
||||
* @param {*} value The value to check for.
|
||||
* @return {boolean} Whether the buffer contains the given value.
|
||||
*/
|
||||
goog.structs.CircularBuffer.prototype.containsValue = function(value) {
|
||||
var l = this.getCount();
|
||||
for (var i = 0; i < l; i++) {
|
||||
if (this.get(i) == value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the last item inserted into the buffer.
|
||||
* @return {*} The last item inserted into the buffer, or null if the buffer is
|
||||
* empty.
|
||||
*/
|
||||
goog.structs.CircularBuffer.prototype.getLast = function() {
|
||||
if (this.getCount() == 0) {
|
||||
return null;
|
||||
}
|
||||
return this.get(this.getCount() - 1);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to convert an index in the number space of oldest to
|
||||
* newest items in the array to the position that the element will be at in the
|
||||
* underlying array.
|
||||
* @param {number} index The index of the item in a list ordered from oldest to
|
||||
* newest.
|
||||
* @return {number} The index of the item in the CircularBuffer's underlying
|
||||
* array.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.CircularBuffer.prototype.normalizeIndex_ = function(index) {
|
||||
if (index >= this.buff_.length) {
|
||||
throw Error('Out of bounds exception');
|
||||
}
|
||||
|
||||
if (this.buff_.length < this.maxSize_) {
|
||||
return index;
|
||||
}
|
||||
|
||||
return (this.nextPtr_ + Number(index)) % this.maxSize_;
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Defines the collection interface.
|
||||
*
|
||||
* @author nnaze@google.com (Nathan Naze)
|
||||
*/
|
||||
|
||||
goog.provide('goog.structs.Collection');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An interface for a collection of values.
|
||||
* @interface
|
||||
*/
|
||||
goog.structs.Collection = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @param {*} value Value to add to the collection.
|
||||
*/
|
||||
goog.structs.Collection.prototype.add;
|
||||
|
||||
|
||||
/**
|
||||
* @param {*} value Value to remove from the collection.
|
||||
*/
|
||||
goog.structs.Collection.prototype.remove;
|
||||
|
||||
|
||||
/**
|
||||
* @param {*} value Value to find in the tree.
|
||||
* @return {boolean} Whether the collection contains the specified value.
|
||||
*/
|
||||
goog.structs.Collection.prototype.contains;
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The number of values stored in the collection.
|
||||
*/
|
||||
goog.structs.Collection.prototype.getCount;
|
||||
|
||||
333
nicer-api-docs/closure-library/closure/goog/structs/heap.js
Normal file
333
nicer-api-docs/closure-library/closure/goog/structs/heap.js
Normal file
@@ -0,0 +1,333 @@
|
||||
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: Heap.
|
||||
*
|
||||
*
|
||||
* This file provides the implementation of a Heap datastructure. Smaller keys
|
||||
* rise to the top.
|
||||
*
|
||||
* The big-O notation for all operations are below:
|
||||
* <pre>
|
||||
* Method big-O
|
||||
* ----------------------------------------------------------------------------
|
||||
* - insert O(logn)
|
||||
* - remove O(logn)
|
||||
* - peek O(1)
|
||||
* - contains O(n)
|
||||
* </pre>
|
||||
*/
|
||||
// TODO(user): Should this rely on natural ordering via some Comparable
|
||||
// interface?
|
||||
|
||||
|
||||
goog.provide('goog.structs.Heap');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.object');
|
||||
goog.require('goog.structs.Node');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for a Heap datastructure.
|
||||
*
|
||||
* @param {goog.structs.Heap|Object=} opt_heap Optional goog.structs.Heap or
|
||||
* Object to initialize heap with.
|
||||
* @constructor
|
||||
*/
|
||||
goog.structs.Heap = function(opt_heap) {
|
||||
/**
|
||||
* The nodes of the heap.
|
||||
* @private
|
||||
* @type {Array.<goog.structs.Node>}
|
||||
*/
|
||||
this.nodes_ = [];
|
||||
|
||||
if (opt_heap) {
|
||||
this.insertAll(opt_heap);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Insert the given value into the heap with the given key.
|
||||
* @param {*} key The key.
|
||||
* @param {*} value The value.
|
||||
*/
|
||||
goog.structs.Heap.prototype.insert = function(key, value) {
|
||||
var node = new goog.structs.Node(key, value);
|
||||
var nodes = this.nodes_;
|
||||
nodes.push(node);
|
||||
this.moveUp_(nodes.length - 1);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds multiple key-value pairs from another goog.structs.Heap or Object
|
||||
* @param {goog.structs.Heap|Object} heap Object containing the data to add.
|
||||
*/
|
||||
goog.structs.Heap.prototype.insertAll = function(heap) {
|
||||
var keys, values;
|
||||
if (heap instanceof goog.structs.Heap) {
|
||||
keys = heap.getKeys();
|
||||
values = heap.getValues();
|
||||
|
||||
// If it is a heap and the current heap is empty, I can realy on the fact
|
||||
// that the keys/values are in the correct order to put in the underlying
|
||||
// structure.
|
||||
if (heap.getCount() <= 0) {
|
||||
var nodes = this.nodes_;
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
nodes.push(new goog.structs.Node(keys[i], values[i]));
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
keys = goog.object.getKeys(heap);
|
||||
values = goog.object.getValues(heap);
|
||||
}
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
this.insert(keys[i], values[i]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves and removes the root value of this heap.
|
||||
* @return {*} The value removed from the root of the heap. Returns
|
||||
* undefined if the heap is empty.
|
||||
*/
|
||||
goog.structs.Heap.prototype.remove = function() {
|
||||
var nodes = this.nodes_;
|
||||
var count = nodes.length;
|
||||
var rootNode = nodes[0];
|
||||
if (count <= 0) {
|
||||
return undefined;
|
||||
} else if (count == 1) {
|
||||
goog.array.clear(nodes);
|
||||
} else {
|
||||
nodes[0] = nodes.pop();
|
||||
this.moveDown_(0);
|
||||
}
|
||||
return rootNode.getValue();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves but does not remove the root value of this heap.
|
||||
* @return {*} The value at the root of the heap. Returns
|
||||
* undefined if the heap is empty.
|
||||
*/
|
||||
goog.structs.Heap.prototype.peek = function() {
|
||||
var nodes = this.nodes_;
|
||||
if (nodes.length == 0) {
|
||||
return undefined;
|
||||
}
|
||||
return nodes[0].getValue();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves but does not remove the key of the root node of this heap.
|
||||
* @return {*} The key at the root of the heap. Returns undefined if the
|
||||
* heap is empty.
|
||||
*/
|
||||
goog.structs.Heap.prototype.peekKey = function() {
|
||||
return this.nodes_[0] && this.nodes_[0].getKey();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Moves the node at the given index down to its proper place in the heap.
|
||||
* @param {number} index The index of the node to move down.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Heap.prototype.moveDown_ = function(index) {
|
||||
var nodes = this.nodes_;
|
||||
var count = nodes.length;
|
||||
|
||||
// Save the node being moved down.
|
||||
var node = nodes[index];
|
||||
// While the current node has a child.
|
||||
while (index < (count >> 1)) {
|
||||
var leftChildIndex = this.getLeftChildIndex_(index);
|
||||
var rightChildIndex = this.getRightChildIndex_(index);
|
||||
|
||||
// Determine the index of the smaller child.
|
||||
var smallerChildIndex = rightChildIndex < count &&
|
||||
nodes[rightChildIndex].getKey() < nodes[leftChildIndex].getKey() ?
|
||||
rightChildIndex : leftChildIndex;
|
||||
|
||||
// If the node being moved down is smaller than its children, the node
|
||||
// has found the correct index it should be at.
|
||||
if (nodes[smallerChildIndex].getKey() > node.getKey()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If not, then take the smaller child as the current node.
|
||||
nodes[index] = nodes[smallerChildIndex];
|
||||
index = smallerChildIndex;
|
||||
}
|
||||
nodes[index] = node;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
goog.structs.Heap.prototype.moveUp_ = function(index) {
|
||||
var nodes = this.nodes_;
|
||||
var node = nodes[index];
|
||||
|
||||
// While the node being moved up is not at the root.
|
||||
while (index > 0) {
|
||||
// If the parent is less than the node being moved up, move the parent down.
|
||||
var parentIndex = this.getParentIndex_(index);
|
||||
if (nodes[parentIndex].getKey() > node.getKey()) {
|
||||
nodes[index] = nodes[parentIndex];
|
||||
index = parentIndex;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
nodes[index] = node;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the index of the left child of the node at the given index.
|
||||
* @param {number} index The index of the node to get the left child for.
|
||||
* @return {number} The index of the left child.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Heap.prototype.getLeftChildIndex_ = function(index) {
|
||||
return index * 2 + 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the index of the right child of the node at the given index.
|
||||
* @param {number} index The index of the node to get the right child for.
|
||||
* @return {number} The index of the right child.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Heap.prototype.getRightChildIndex_ = function(index) {
|
||||
return index * 2 + 2;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the index of the parent of the node at the given index.
|
||||
* @param {number} index The index of the node to get the parent for.
|
||||
* @return {number} The index of the parent.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Heap.prototype.getParentIndex_ = function(index) {
|
||||
return (index - 1) >> 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the values of the heap.
|
||||
* @return {Array} The values in the heap.
|
||||
*/
|
||||
goog.structs.Heap.prototype.getValues = function() {
|
||||
var nodes = this.nodes_;
|
||||
var rv = [];
|
||||
var l = nodes.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
rv.push(nodes[i].getValue());
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the keys of the heap.
|
||||
* @return {Array} The keys in the heap.
|
||||
*/
|
||||
goog.structs.Heap.prototype.getKeys = function() {
|
||||
var nodes = this.nodes_;
|
||||
var rv = [];
|
||||
var l = nodes.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
rv.push(nodes[i].getKey());
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the heap contains the given value.
|
||||
* @param {Object} val The value to check for.
|
||||
* @return {boolean} Whether the heap contains the value.
|
||||
*/
|
||||
goog.structs.Heap.prototype.containsValue = function(val) {
|
||||
return goog.array.some(this.nodes_, function(node) {
|
||||
return node.getValue() == val;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the heap contains the given key.
|
||||
* @param {Object} key The key to check for.
|
||||
* @return {boolean} Whether the heap contains the key.
|
||||
*/
|
||||
goog.structs.Heap.prototype.containsKey = function(key) {
|
||||
return goog.array.some(this.nodes_, function(node) {
|
||||
return node.getKey() == key;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clones a heap and returns a new heap
|
||||
* @return {goog.structs.Heap} A new goog.structs.Heap with the same key-value
|
||||
* pairs.
|
||||
*/
|
||||
goog.structs.Heap.prototype.clone = function() {
|
||||
return new goog.structs.Heap(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The number of key-value pairs in the map
|
||||
* @return {number} The number of pairs.
|
||||
*/
|
||||
goog.structs.Heap.prototype.getCount = function() {
|
||||
return this.nodes_.length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if this heap contains no elements.
|
||||
* @return {boolean} Whether this heap contains no elements.
|
||||
*/
|
||||
goog.structs.Heap.prototype.isEmpty = function() {
|
||||
return goog.array.isEmpty(this.nodes_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all elements from the heap.
|
||||
*/
|
||||
goog.structs.Heap.prototype.clear = function() {
|
||||
goog.array.clear(this.nodes_);
|
||||
};
|
||||
@@ -0,0 +1,159 @@
|
||||
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Provides inversion and inversion map functionality for storing
|
||||
* integer ranges and corresponding values.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.structs.InversionMap');
|
||||
|
||||
goog.require('goog.array');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Maps ranges to values using goog.structs.Inversion.
|
||||
* @param {Array.<number>} rangeArray An array of monotonically
|
||||
* increasing integer values, with at least one instance.
|
||||
* @param {Array.<*>} valueArray An array of corresponding values.
|
||||
* Length must be the same as rangeArray.
|
||||
* @param {boolean=} opt_delta If true, saves only delta from previous value.
|
||||
* @constructor
|
||||
*/
|
||||
goog.structs.InversionMap = function(rangeArray, valueArray, opt_delta) {
|
||||
if (rangeArray.length != valueArray.length) {
|
||||
// rangeArray and valueArray has to match in number of entries.
|
||||
return null;
|
||||
}
|
||||
this.storeInversion_(rangeArray, opt_delta);
|
||||
|
||||
/**
|
||||
* @type {Array}
|
||||
* @protected
|
||||
*/
|
||||
this.values = valueArray;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @type {Array}
|
||||
* @protected
|
||||
*/
|
||||
goog.structs.InversionMap.prototype.rangeArray;
|
||||
|
||||
|
||||
/**
|
||||
* Stores the integers as ranges (half-open).
|
||||
* If delta is true, the integers are delta from the previous value and
|
||||
* will be restored to the absolute value.
|
||||
* When used as a set, even indices are IN, and odd are OUT.
|
||||
* @param {Array.<number?>} rangeArray An array of monotonically
|
||||
* increasing integer values, with at least one instance.
|
||||
* @param {boolean=} opt_delta If true, saves only delta from previous value.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.InversionMap.prototype.storeInversion_ = function(rangeArray,
|
||||
opt_delta) {
|
||||
this.rangeArray = rangeArray;
|
||||
|
||||
for (var i = 1; i < rangeArray.length; i++) {
|
||||
if (rangeArray[i] == null) {
|
||||
rangeArray[i] = rangeArray[i - 1] + 1;
|
||||
} else if (opt_delta) {
|
||||
rangeArray[i] += rangeArray[i - 1];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Splices a range -> value map into this inversion map.
|
||||
* @param {Array.<number>} rangeArray An array of monotonically
|
||||
* increasing integer values, with at least one instance.
|
||||
* @param {Array.<*>} valueArray An array of corresponding values.
|
||||
* Length must be the same as rangeArray.
|
||||
* @param {boolean=} opt_delta If true, saves only delta from previous value.
|
||||
*/
|
||||
goog.structs.InversionMap.prototype.spliceInversion = function(
|
||||
rangeArray, valueArray, opt_delta) {
|
||||
// By building another inversion map, we build the arrays that we need
|
||||
// to splice in.
|
||||
var otherMap = new goog.structs.InversionMap(
|
||||
rangeArray, valueArray, opt_delta);
|
||||
|
||||
// Figure out where to splice those arrays.
|
||||
var startRange = otherMap.rangeArray[0];
|
||||
var endRange =
|
||||
/** @type {number} */ (goog.array.peek(otherMap.rangeArray));
|
||||
var startSplice = this.getLeast(startRange);
|
||||
var endSplice = this.getLeast(endRange);
|
||||
|
||||
// The inversion map works by storing the start points of ranges...
|
||||
if (startRange != this.rangeArray[startSplice]) {
|
||||
// ...if we're splicing in a start point that isn't already here,
|
||||
// then we need to insert it after the insertion point.
|
||||
startSplice++;
|
||||
} // otherwise we overwrite the insertion point.
|
||||
|
||||
var spliceLength = endSplice - startSplice + 1;
|
||||
goog.partial(goog.array.splice, this.rangeArray, startSplice,
|
||||
spliceLength).apply(null, otherMap.rangeArray);
|
||||
goog.partial(goog.array.splice, this.values, startSplice,
|
||||
spliceLength).apply(null, otherMap.values);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the value corresponding to a number from the inversion map.
|
||||
* @param {number} intKey The number for which value needs to be retrieved
|
||||
* from inversion map.
|
||||
* @return {*} Value retrieved from inversion map; null if not found.
|
||||
*/
|
||||
goog.structs.InversionMap.prototype.at = function(intKey) {
|
||||
var index = this.getLeast(intKey);
|
||||
if (index < 0) {
|
||||
return null;
|
||||
}
|
||||
return this.values[index];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the largest index such that rangeArray[index] <= intKey from the
|
||||
* inversion map.
|
||||
* @param {number} intKey The probe for which rangeArray is searched.
|
||||
* @return {number} Largest index such that rangeArray[index] <= intKey.
|
||||
* @protected
|
||||
*/
|
||||
goog.structs.InversionMap.prototype.getLeast = function(intKey) {
|
||||
var arr = this.rangeArray;
|
||||
var low = 0;
|
||||
var high = arr.length;
|
||||
while (high - low > 8) {
|
||||
var mid = (high + low) >> 1;
|
||||
if (arr[mid] <= intKey) {
|
||||
low = mid;
|
||||
} else {
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
for (; low < high; ++low) {
|
||||
if (intKey < arr[low]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return low - 1;
|
||||
};
|
||||
473
nicer-api-docs/closure-library/closure/goog/structs/linkedmap.js
Normal file
473
nicer-api-docs/closure-library/closure/goog/structs/linkedmap.js
Normal file
@@ -0,0 +1,473 @@
|
||||
// Copyright 2007 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview A LinkedMap data structure that is accessed using key/value
|
||||
* pairs like an ordinary Map, but which guarantees a consistent iteration
|
||||
* order over its entries. The iteration order is either insertion order (the
|
||||
* default) or ordered from most recent to least recent use. By setting a fixed
|
||||
* size, the LRU version of the LinkedMap makes an effective object cache. This
|
||||
* data structure is similar to Java's LinkedHashMap.
|
||||
*
|
||||
* @author brenneman@google.com (Shawn Brenneman)
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs.LinkedMap');
|
||||
|
||||
goog.require('goog.structs.Map');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for a LinkedMap datastructure, which combines O(1) map access for
|
||||
* key/value pairs with a linked list for a consistent iteration order. Sample
|
||||
* usage:
|
||||
*
|
||||
* <pre>
|
||||
* var m = new LinkedMap();
|
||||
* m.set('param1', 'A');
|
||||
* m.set('param2', 'B');
|
||||
* m.set('param3', 'C');
|
||||
* alert(m.getKeys()); // param1, param2, param3
|
||||
*
|
||||
* var c = new LinkedMap(5, true);
|
||||
* for (var i = 0; i < 10; i++) {
|
||||
* c.set('entry' + i, false);
|
||||
* }
|
||||
* alert(c.getKeys()); // entry9, entry8, entry7, entry6, entry5
|
||||
*
|
||||
* c.set('entry5', true);
|
||||
* c.set('entry1', false);
|
||||
* alert(c.getKeys()); // entry1, entry5, entry9, entry8, entry7
|
||||
* </pre>
|
||||
*
|
||||
* @param {number=} opt_maxCount The maximum number of objects to store in the
|
||||
* LinkedMap. If unspecified or 0, there is no maximum.
|
||||
* @param {boolean=} opt_cache When set, the LinkedMap stores items in order
|
||||
* from most recently used to least recently used, instead of insertion
|
||||
* order.
|
||||
* @constructor
|
||||
*/
|
||||
goog.structs.LinkedMap = function(opt_maxCount, opt_cache) {
|
||||
/**
|
||||
* The maximum number of entries to allow, or null if there is no limit.
|
||||
* @type {?number}
|
||||
* @private
|
||||
*/
|
||||
this.maxCount_ = opt_maxCount || null;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.cache_ = !!opt_cache;
|
||||
|
||||
this.map_ = new goog.structs.Map();
|
||||
|
||||
this.head_ = new goog.structs.LinkedMap.Node_('', undefined);
|
||||
this.head_.next = this.head_.prev = this.head_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Finds a node and updates it to be the most recently used.
|
||||
* @param {string} key The key of the node.
|
||||
* @return {goog.structs.LinkedMap.Node_} The node or null if not found.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.findAndMoveToTop_ = function(key) {
|
||||
var node = /** @type {goog.structs.LinkedMap.Node_} */ (this.map_.get(key));
|
||||
if (node) {
|
||||
if (this.cache_) {
|
||||
node.remove();
|
||||
this.insert_(node);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the value for a given key. If this is a caching LinkedMap, the
|
||||
* entry will become the most recently used.
|
||||
* @param {string} key The key to retrieve the value for.
|
||||
* @param {*=} opt_val A default value that will be returned if the key is
|
||||
* not found, defaults to undefined.
|
||||
* @return {*} The retrieved value.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.get = function(key, opt_val) {
|
||||
var node = this.findAndMoveToTop_(key);
|
||||
return node ? node.value : opt_val;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the value for a given key without updating the entry to be the
|
||||
* most recently used.
|
||||
* @param {string} key The key to retrieve the value for.
|
||||
* @param {*=} opt_val A default value that will be returned if the key is
|
||||
* not found.
|
||||
* @return {*} The retrieved value.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.peekValue = function(key, opt_val) {
|
||||
var node = this.map_.get(key);
|
||||
return node ? node.value : opt_val;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets a value for a given key. If this is a caching LinkedMap, this entry
|
||||
* will become the most recently used.
|
||||
* @param {string} key The key to retrieve the value for.
|
||||
* @param {*} value A default value that will be returned if the key is
|
||||
* not found.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.set = function(key, value) {
|
||||
var node = this.findAndMoveToTop_(key);
|
||||
if (node) {
|
||||
node.value = value;
|
||||
} else {
|
||||
node = new goog.structs.LinkedMap.Node_(key, value);
|
||||
this.map_.set(key, node);
|
||||
this.insert_(node);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of the first node without making any modifications.
|
||||
* @return {*} The value of the first node or undefined if the map is empty.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.peek = function() {
|
||||
return this.head_.next.value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of the last node without making any modifications.
|
||||
* @return {*} The value of the last node or undefined if the map is empty.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.peekLast = function() {
|
||||
return this.head_.prev.value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the first node from the list and returns its value.
|
||||
* @return {*} The value of the popped node, or undefined if the map was empty.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.shift = function() {
|
||||
return this.popNode_(this.head_.next);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the last node from the list and returns its value.
|
||||
* @return {*} The value of the popped node, or undefined if the map was empty.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.pop = function() {
|
||||
return this.popNode_(this.head_.prev);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a value from the LinkedMap based on its key.
|
||||
* @param {string} key The key to remove.
|
||||
* @return {boolean} True if the entry was removed, false if the key was not
|
||||
* found.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.remove = function(key) {
|
||||
var node = /** @type {goog.structs.LinkedMap.Node_} */ (this.map_.get(key));
|
||||
if (node) {
|
||||
this.removeNode(node);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a node from the {@code LinkedMap}. It can be overridden to do
|
||||
* further cleanup such as disposing of the node value.
|
||||
* @param {!goog.structs.LinkedMap.Node_} node The node to remove.
|
||||
* @protected
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.removeNode = function(node) {
|
||||
node.remove();
|
||||
this.map_.remove(node.key);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The number of items currently in the LinkedMap.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.getCount = function() {
|
||||
return this.map_.getCount();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} True if the cache is empty, false if it contains any items.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.isEmpty = function() {
|
||||
return this.map_.isEmpty();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the maximum number of entries allowed in this object, truncating any
|
||||
* excess objects if necessary.
|
||||
* @param {number} maxCount The new maximum number of entries to allow.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.setMaxCount = function(maxCount) {
|
||||
this.maxCount_ = maxCount || null;
|
||||
if (this.maxCount_ != null) {
|
||||
this.truncate_(this.maxCount_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!Array.<string>} The list of the keys in the appropriate order for
|
||||
* this LinkedMap.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.getKeys = function() {
|
||||
return this.map(function(val, key) {
|
||||
return key;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!Array} The list of the values in the appropriate order for
|
||||
* this LinkedMap.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.getValues = function() {
|
||||
return this.map(function(val, key) {
|
||||
return val;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether a provided value is currently in the LinkedMap. This does not
|
||||
* affect item ordering in cache-style LinkedMaps.
|
||||
* @param {Object} value The value to check for.
|
||||
* @return {boolean} Whether the value is in the LinkedMap.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.contains = function(value) {
|
||||
return this.some(function(el) {
|
||||
return el == value;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether a provided key is currently in the LinkedMap. This does not
|
||||
* affect item ordering in cache-style LinkedMaps.
|
||||
* @param {string} key The key to check for.
|
||||
* @return {boolean} Whether the key is in the LinkedMap.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.containsKey = function(key) {
|
||||
return this.map_.containsKey(key);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all entries in this object.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.clear = function() {
|
||||
this.truncate_(0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function on each item in the LinkedMap.
|
||||
*
|
||||
* @see goog.structs.forEach
|
||||
* @param {Function} f The function to call for each item. The function takes
|
||||
* three arguments: the value, the key, and the LinkedMap.
|
||||
* @param {Object=} opt_obj The object context to use as "this" for the
|
||||
* function.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.forEach = function(f, opt_obj) {
|
||||
for (var n = this.head_.next; n != this.head_; n = n.next) {
|
||||
f.call(opt_obj, n.value, n.key, this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function on each item in the LinkedMap and returns the results of
|
||||
* those calls in an array.
|
||||
*
|
||||
* @see goog.structs.map
|
||||
* @param {!Function} f The function to call for each item. The function takes
|
||||
* three arguments: the value, the key, and the LinkedMap.
|
||||
* @param {Object=} opt_obj The object context to use as "this" for the
|
||||
* function.
|
||||
* @return {!Array} The results of the function calls for each item in the
|
||||
* LinkedMap.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.map = function(f, opt_obj) {
|
||||
var rv = [];
|
||||
for (var n = this.head_.next; n != this.head_; n = n.next) {
|
||||
rv.push(f.call(opt_obj, n.value, n.key, this));
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function on each item in the LinkedMap and returns true if any of
|
||||
* those function calls returns a true-like value.
|
||||
*
|
||||
* @see goog.structs.some
|
||||
* @param {Function} f The function to call for each item. The function takes
|
||||
* three arguments: the value, the key, and the LinkedMap, and returns a
|
||||
* boolean.
|
||||
* @param {Object=} opt_obj The object context to use as "this" for the
|
||||
* function.
|
||||
* @return {boolean} Whether f evaluates to true for at least one item in the
|
||||
* LinkedMap.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.some = function(f, opt_obj) {
|
||||
for (var n = this.head_.next; n != this.head_; n = n.next) {
|
||||
if (f.call(opt_obj, n.value, n.key, this)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function on each item in the LinkedMap and returns true only if every
|
||||
* function call returns a true-like value.
|
||||
*
|
||||
* @see goog.structs.some
|
||||
* @param {Function} f The function to call for each item. The function takes
|
||||
* three arguments: the value, the key, and the Cache, and returns a
|
||||
* boolean.
|
||||
* @param {Object=} opt_obj The object context to use as "this" for the
|
||||
* function.
|
||||
* @return {boolean} Whether f evaluates to true for every item in the Cache.
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.every = function(f, opt_obj) {
|
||||
for (var n = this.head_.next; n != this.head_; n = n.next) {
|
||||
if (!f.call(opt_obj, n.value, n.key, this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Appends a node to the list. LinkedMap in cache mode adds new nodes to
|
||||
* the head of the list, otherwise they are appended to the tail. If there is a
|
||||
* maximum size, the list will be truncated if necessary.
|
||||
*
|
||||
* @param {goog.structs.LinkedMap.Node_} node The item to insert.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.insert_ = function(node) {
|
||||
if (this.cache_) {
|
||||
node.next = this.head_.next;
|
||||
node.prev = this.head_;
|
||||
|
||||
this.head_.next = node;
|
||||
node.next.prev = node;
|
||||
} else {
|
||||
node.prev = this.head_.prev;
|
||||
node.next = this.head_;
|
||||
|
||||
this.head_.prev = node;
|
||||
node.prev.next = node;
|
||||
}
|
||||
|
||||
if (this.maxCount_ != null) {
|
||||
this.truncate_(this.maxCount_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes elements from the LinkedMap if the given count has been exceeded.
|
||||
* In cache mode removes nodes from the tail of the list. Otherwise removes
|
||||
* nodes from the head.
|
||||
* @param {number} count Number of elements to keep.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.truncate_ = function(count) {
|
||||
for (var i = this.map_.getCount(); i > count; i--) {
|
||||
this.removeNode(this.cache_ ? this.head_.prev : this.head_.next);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the node from the LinkedMap if it is not the head, and returns
|
||||
* the node's value.
|
||||
* @param {!goog.structs.LinkedMap.Node_} node The item to remove.
|
||||
* @return {*} The value of the popped node.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.LinkedMap.prototype.popNode_ = function(node) {
|
||||
if (this.head_ != node) {
|
||||
this.removeNode(node);
|
||||
}
|
||||
return node.value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Internal class for a doubly-linked list node containing a key/value pair.
|
||||
* @param {string} key The key.
|
||||
* @param {*} value The value.
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
goog.structs.LinkedMap.Node_ = function(key, value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The next node in the list.
|
||||
* @type {!goog.structs.LinkedMap.Node_}
|
||||
*/
|
||||
goog.structs.LinkedMap.Node_.prototype.next;
|
||||
|
||||
|
||||
/**
|
||||
* The previous node in the list.
|
||||
* @type {!goog.structs.LinkedMap.Node_}
|
||||
*/
|
||||
goog.structs.LinkedMap.Node_.prototype.prev;
|
||||
|
||||
|
||||
/**
|
||||
* Causes this node to remove itself from the list.
|
||||
*/
|
||||
goog.structs.LinkedMap.Node_.prototype.remove = function() {
|
||||
this.prev.next = this.next;
|
||||
this.next.prev = this.prev;
|
||||
|
||||
delete this.prev;
|
||||
delete this.next;
|
||||
};
|
||||
449
nicer-api-docs/closure-library/closure/goog/structs/map.js
Normal file
449
nicer-api-docs/closure-library/closure/goog/structs/map.js
Normal file
@@ -0,0 +1,449 @@
|
||||
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: Hash Map.
|
||||
*
|
||||
* @author arv@google.com (Erik Arvidsson)
|
||||
* @author jonp@google.com (Jon Perlow) Optimized for IE6
|
||||
*
|
||||
* This file contains an implementation of a Map structure. It implements a lot
|
||||
* of the methods used in goog.structs so those functions work on hashes. This
|
||||
* is best suited for complex key types. For simple keys such as numbers and
|
||||
* strings, and where special names like __proto__ are not a concern, consider
|
||||
* using the lighter-weight utilities in goog.object.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs.Map');
|
||||
|
||||
goog.require('goog.iter.Iterator');
|
||||
goog.require('goog.iter.StopIteration');
|
||||
goog.require('goog.object');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for Hash Map datastructure.
|
||||
* @param {*=} opt_map Map or Object to initialize the map with.
|
||||
* @param {...*} var_args If 2 or more arguments are present then they
|
||||
* will be used as key-value pairs.
|
||||
* @constructor
|
||||
*/
|
||||
goog.structs.Map = function(opt_map, var_args) {
|
||||
|
||||
/**
|
||||
* Underlying JS object used to implement the map.
|
||||
* @type {!Object}
|
||||
* @private
|
||||
*/
|
||||
this.map_ = {};
|
||||
|
||||
/**
|
||||
* An array of keys. This is necessary for two reasons:
|
||||
* 1. Iterating the keys using for (var key in this.map_) allocates an
|
||||
* object for every key in IE which is really bad for IE6 GC perf.
|
||||
* 2. Without a side data structure, we would need to escape all the keys
|
||||
* as that would be the only way we could tell during iteration if the
|
||||
* key was an internal key or a property of the object.
|
||||
*
|
||||
* This array can contain deleted keys so it's necessary to check the map
|
||||
* as well to see if the key is still in the map (this doesn't require a
|
||||
* memory allocation in IE).
|
||||
* @type {!Array.<string>}
|
||||
* @private
|
||||
*/
|
||||
this.keys_ = [];
|
||||
|
||||
var argLength = arguments.length;
|
||||
|
||||
if (argLength > 1) {
|
||||
if (argLength % 2) {
|
||||
throw Error('Uneven number of arguments');
|
||||
}
|
||||
for (var i = 0; i < argLength; i += 2) {
|
||||
this.set(arguments[i], arguments[i + 1]);
|
||||
}
|
||||
} else if (opt_map) {
|
||||
this.addAll(/** @type {Object} */ (opt_map));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The number of key value pairs in the map.
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
goog.structs.Map.prototype.count_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Version used to detect changes while iterating.
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
goog.structs.Map.prototype.version_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The number of key-value pairs in the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.getCount = function() {
|
||||
return this.count_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the values of the map.
|
||||
* @return {!Array} The values in the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.getValues = function() {
|
||||
this.cleanupKeysArray_();
|
||||
|
||||
var rv = [];
|
||||
for (var i = 0; i < this.keys_.length; i++) {
|
||||
var key = this.keys_[i];
|
||||
rv.push(this.map_[key]);
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the keys of the map.
|
||||
* @return {!Array.<string>} Array of string values.
|
||||
*/
|
||||
goog.structs.Map.prototype.getKeys = function() {
|
||||
this.cleanupKeysArray_();
|
||||
return /** @type {!Array.<string>} */ (this.keys_.concat());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the map contains the given key.
|
||||
* @param {*} key The key to check for.
|
||||
* @return {boolean} Whether the map contains the key.
|
||||
*/
|
||||
goog.structs.Map.prototype.containsKey = function(key) {
|
||||
return goog.structs.Map.hasKey_(this.map_, key);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the map contains the given value. This is O(n).
|
||||
* @param {*} val The value to check for.
|
||||
* @return {boolean} Whether the map contains the value.
|
||||
*/
|
||||
goog.structs.Map.prototype.containsValue = function(val) {
|
||||
for (var i = 0; i < this.keys_.length; i++) {
|
||||
var key = this.keys_[i];
|
||||
if (goog.structs.Map.hasKey_(this.map_, key) && this.map_[key] == val) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether this map is equal to the argument map.
|
||||
* @param {goog.structs.Map} otherMap The map against which to test equality.
|
||||
* @param {function(?, ?) : boolean=} opt_equalityFn Optional equality function
|
||||
* to test equality of values. If not specified, this will test whether
|
||||
* the values contained in each map are identical objects.
|
||||
* @return {boolean} Whether the maps are equal.
|
||||
*/
|
||||
goog.structs.Map.prototype.equals = function(otherMap, opt_equalityFn) {
|
||||
if (this === otherMap) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.count_ != otherMap.getCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var equalityFn = opt_equalityFn || goog.structs.Map.defaultEquals;
|
||||
|
||||
this.cleanupKeysArray_();
|
||||
for (var key, i = 0; key = this.keys_[i]; i++) {
|
||||
if (!equalityFn(this.get(key), otherMap.get(key))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Default equality test for values.
|
||||
* @param {*} a The first value.
|
||||
* @param {*} b The second value.
|
||||
* @return {boolean} Whether a and b reference the same object.
|
||||
*/
|
||||
goog.structs.Map.defaultEquals = function(a, b) {
|
||||
return a === b;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the map is empty.
|
||||
*/
|
||||
goog.structs.Map.prototype.isEmpty = function() {
|
||||
return this.count_ == 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all key-value pairs from the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.clear = function() {
|
||||
this.map_ = {};
|
||||
this.keys_.length = 0;
|
||||
this.count_ = 0;
|
||||
this.version_ = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a key-value pair based on the key. This is O(logN) amortized due to
|
||||
* updating the keys array whenever the count becomes half the size of the keys
|
||||
* in the keys array.
|
||||
* @param {*} key The key to remove.
|
||||
* @return {boolean} Whether object was removed.
|
||||
*/
|
||||
goog.structs.Map.prototype.remove = function(key) {
|
||||
if (goog.structs.Map.hasKey_(this.map_, key)) {
|
||||
delete this.map_[key];
|
||||
this.count_--;
|
||||
this.version_++;
|
||||
|
||||
// clean up the keys array if the threshhold is hit
|
||||
if (this.keys_.length > 2 * this.count_) {
|
||||
this.cleanupKeysArray_();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up the temp keys array by removing entries that are no longer in the
|
||||
* map.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Map.prototype.cleanupKeysArray_ = function() {
|
||||
if (this.count_ != this.keys_.length) {
|
||||
// First remove keys that are no longer in the map.
|
||||
var srcIndex = 0;
|
||||
var destIndex = 0;
|
||||
while (srcIndex < this.keys_.length) {
|
||||
var key = this.keys_[srcIndex];
|
||||
if (goog.structs.Map.hasKey_(this.map_, key)) {
|
||||
this.keys_[destIndex++] = key;
|
||||
}
|
||||
srcIndex++;
|
||||
}
|
||||
this.keys_.length = destIndex;
|
||||
}
|
||||
|
||||
if (this.count_ != this.keys_.length) {
|
||||
// If the count still isn't correct, that means we have duplicates. This can
|
||||
// happen when the same key is added and removed multiple times. Now we have
|
||||
// to allocate one extra Object to remove the duplicates. This could have
|
||||
// been done in the first pass, but in the common case, we can avoid
|
||||
// allocating an extra object by only doing this when necessary.
|
||||
var seen = {};
|
||||
var srcIndex = 0;
|
||||
var destIndex = 0;
|
||||
while (srcIndex < this.keys_.length) {
|
||||
var key = this.keys_[srcIndex];
|
||||
if (!(goog.structs.Map.hasKey_(seen, key))) {
|
||||
this.keys_[destIndex++] = key;
|
||||
seen[key] = 1;
|
||||
}
|
||||
srcIndex++;
|
||||
}
|
||||
this.keys_.length = destIndex;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value for the given key. If the key is not found and the default
|
||||
* value is not given this will return {@code undefined}.
|
||||
* @param {*} key The key to get the value for.
|
||||
* @param {*=} opt_val The value to return if no item is found for the given
|
||||
* key, defaults to undefined.
|
||||
* @return {*} The value for the given key.
|
||||
*/
|
||||
goog.structs.Map.prototype.get = function(key, opt_val) {
|
||||
if (goog.structs.Map.hasKey_(this.map_, key)) {
|
||||
return this.map_[key];
|
||||
}
|
||||
return opt_val;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a key-value pair to the map.
|
||||
* @param {*} key The key.
|
||||
* @param {*} value The value to add.
|
||||
* @return {*} Some subclasses return a value.
|
||||
*/
|
||||
goog.structs.Map.prototype.set = function(key, value) {
|
||||
if (!(goog.structs.Map.hasKey_(this.map_, key))) {
|
||||
this.count_++;
|
||||
this.keys_.push(key);
|
||||
// Only change the version if we add a new key.
|
||||
this.version_++;
|
||||
}
|
||||
this.map_[key] = value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds multiple key-value pairs from another goog.structs.Map or Object.
|
||||
* @param {Object} map Object containing the data to add.
|
||||
*/
|
||||
goog.structs.Map.prototype.addAll = function(map) {
|
||||
var keys, values;
|
||||
if (map instanceof goog.structs.Map) {
|
||||
keys = map.getKeys();
|
||||
values = map.getValues();
|
||||
} else {
|
||||
keys = goog.object.getKeys(map);
|
||||
values = goog.object.getValues(map);
|
||||
}
|
||||
// we could use goog.array.forEach here but I don't want to introduce that
|
||||
// dependency just for this.
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
this.set(keys[i], values[i]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clones a map and returns a new map.
|
||||
* @return {!goog.structs.Map} A new map with the same key-value pairs.
|
||||
*/
|
||||
goog.structs.Map.prototype.clone = function() {
|
||||
return new goog.structs.Map(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new map in which all the keys and values are interchanged
|
||||
* (keys become values and values become keys). If multiple keys map to the
|
||||
* same value, the chosen transposed value is implementation-dependent.
|
||||
*
|
||||
* It acts very similarly to {goog.object.transpose(Object)}.
|
||||
*
|
||||
* @return {!goog.structs.Map} The transposed map.
|
||||
*/
|
||||
goog.structs.Map.prototype.transpose = function() {
|
||||
var transposed = new goog.structs.Map();
|
||||
for (var i = 0; i < this.keys_.length; i++) {
|
||||
var key = this.keys_[i];
|
||||
var value = this.map_[key];
|
||||
transposed.set(value, key);
|
||||
}
|
||||
|
||||
return transposed;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!Object} Object representation of the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.toObject = function() {
|
||||
this.cleanupKeysArray_();
|
||||
var obj = {};
|
||||
for (var i = 0; i < this.keys_.length; i++) {
|
||||
var key = this.keys_[i];
|
||||
obj[key] = this.map_[key];
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator that iterates over the keys in the map. Removal of keys
|
||||
* while iterating might have undesired side effects.
|
||||
* @return {!goog.iter.Iterator} An iterator over the keys in the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.getKeyIterator = function() {
|
||||
return this.__iterator__(true);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator that iterates over the values in the map. Removal of
|
||||
* keys while iterating might have undesired side effects.
|
||||
* @return {!goog.iter.Iterator} An iterator over the values in the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.getValueIterator = function() {
|
||||
return this.__iterator__(false);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator that iterates over the values or the keys in the map.
|
||||
* This throws an exception if the map was mutated since the iterator was
|
||||
* created.
|
||||
* @param {boolean=} opt_keys True to iterate over the keys. False to iterate
|
||||
* over the values. The default value is false.
|
||||
* @return {!goog.iter.Iterator} An iterator over the values or keys in the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.__iterator__ = function(opt_keys) {
|
||||
// Clean up keys to minimize the risk of iterating over dead keys.
|
||||
this.cleanupKeysArray_();
|
||||
|
||||
var i = 0;
|
||||
var keys = this.keys_;
|
||||
var map = this.map_;
|
||||
var version = this.version_;
|
||||
var selfObj = this;
|
||||
|
||||
var newIter = new goog.iter.Iterator;
|
||||
newIter.next = function() {
|
||||
while (true) {
|
||||
if (version != selfObj.version_) {
|
||||
throw Error('The map has changed since the iterator was created');
|
||||
}
|
||||
if (i >= keys.length) {
|
||||
throw goog.iter.StopIteration;
|
||||
}
|
||||
var key = keys[i++];
|
||||
return opt_keys ? key : map[key];
|
||||
}
|
||||
};
|
||||
return newIter;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Safe way to test for hasOwnProperty. It even allows testing for
|
||||
* 'hasOwnProperty'.
|
||||
* @param {Object} obj The object to test for presence of the given key.
|
||||
* @param {*} key The key to check for.
|
||||
* @return {boolean} Whether the object has the key.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Map.hasKey_ = function(obj, key) {
|
||||
return Object.prototype.hasOwnProperty.call(obj, key);
|
||||
};
|
||||
74
nicer-api-docs/closure-library/closure/goog/structs/node.js
Normal file
74
nicer-api-docs/closure-library/closure/goog/structs/node.js
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Generic immutable node object to be used in collections.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs.Node');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A generic immutable node. This can be used in various collections that
|
||||
* require a node object for its item (such as a heap).
|
||||
* @param {*} key Key.
|
||||
* @param {*} value Vaue.
|
||||
* @constructor
|
||||
*/
|
||||
goog.structs.Node = function(key, value) {
|
||||
/**
|
||||
* The key.
|
||||
* @type {*}
|
||||
* @private
|
||||
*/
|
||||
this.key_ = key;
|
||||
|
||||
/**
|
||||
* The value.
|
||||
* @type {*}
|
||||
* @private
|
||||
*/
|
||||
this.value_ = value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the key.
|
||||
* @return {*} The key.
|
||||
*/
|
||||
goog.structs.Node.prototype.getKey = function() {
|
||||
return this.key_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the value.
|
||||
* @return {*} The value.
|
||||
*/
|
||||
goog.structs.Node.prototype.getValue = function() {
|
||||
return this.value_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clones a node and returns a new node.
|
||||
* @return {goog.structs.Node} A new goog.structs.Node with the same key value
|
||||
* pair.
|
||||
*/
|
||||
goog.structs.Node.prototype.clone = function() {
|
||||
return new goog.structs.Node(this.key_, this.value_);
|
||||
};
|
||||
381
nicer-api-docs/closure-library/closure/goog/structs/pool.js
Normal file
381
nicer-api-docs/closure-library/closure/goog/structs/pool.js
Normal file
@@ -0,0 +1,381 @@
|
||||
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: Pool.
|
||||
*
|
||||
*
|
||||
* A generic class for handling pools of objects.
|
||||
* When an object is released, it is attempted to be reused.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs.Pool');
|
||||
|
||||
goog.require('goog.Disposable');
|
||||
goog.require('goog.structs.Queue');
|
||||
goog.require('goog.structs.Set');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A generic pool class. If min is greater than max, an error is thrown.
|
||||
* @param {number=} opt_minCount Min. number of objects (Default: 1).
|
||||
* @param {number=} opt_maxCount Max. number of objects (Default: 10).
|
||||
* @constructor
|
||||
* @extends {goog.Disposable}
|
||||
*/
|
||||
goog.structs.Pool = function(opt_minCount, opt_maxCount) {
|
||||
goog.Disposable.call(this);
|
||||
|
||||
/**
|
||||
* Minimum number of objects allowed
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.minCount_ = opt_minCount || 0;
|
||||
|
||||
/**
|
||||
* Maximum number of objects allowed
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.maxCount_ = opt_maxCount || 10;
|
||||
|
||||
// Make sure that the max and min constraints are valid.
|
||||
if (this.minCount_ > this.maxCount_) {
|
||||
throw Error(goog.structs.Pool.ERROR_MIN_MAX_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set used to store objects that are currently in the pool and available
|
||||
* to be used.
|
||||
* @type {goog.structs.Queue}
|
||||
* @private
|
||||
*/
|
||||
this.freeQueue_ = new goog.structs.Queue();
|
||||
|
||||
/**
|
||||
* Set used to store objects that are currently in the pool and in use.
|
||||
* @type {goog.structs.Set}
|
||||
* @private
|
||||
*/
|
||||
this.inUseSet_ = new goog.structs.Set();
|
||||
|
||||
/**
|
||||
* The minimum delay between objects being made available, in milliseconds. If
|
||||
* this is 0, no minimum delay is enforced.
|
||||
* @type {number}
|
||||
* @protected
|
||||
*/
|
||||
this.delay = 0;
|
||||
|
||||
/**
|
||||
* The time of the last object being made available, in milliseconds since the
|
||||
* epoch (i.e., the result of Date#toTime). If this is null, no access has
|
||||
* occurred yet.
|
||||
* @type {number?}
|
||||
* @protected
|
||||
*/
|
||||
this.lastAccess = null;
|
||||
|
||||
// Make sure that the minCount constraint is satisfied.
|
||||
this.adjustForMinMax();
|
||||
|
||||
|
||||
// TODO(user): Remove once JSCompiler's undefined properties warnings
|
||||
// don't error for guarded properties.
|
||||
var magicProps = {canBeReused: 0};
|
||||
};
|
||||
goog.inherits(goog.structs.Pool, goog.Disposable);
|
||||
|
||||
|
||||
/**
|
||||
* Error to throw when the max/min constraint is attempted to be invalidated.
|
||||
* I.e., when it is attempted for maxCount to be less than minCount.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Pool.ERROR_MIN_MAX_ =
|
||||
'[goog.structs.Pool] Min can not be greater than max';
|
||||
|
||||
|
||||
/**
|
||||
* Error to throw when the Pool is attempted to be disposed and it is asked to
|
||||
* make sure that there are no objects that are in use (i.e., haven't been
|
||||
* released).
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Pool.ERROR_DISPOSE_UNRELEASED_OBJS_ =
|
||||
'[goog.structs.Pool] Objects not released';
|
||||
|
||||
|
||||
/**
|
||||
* Sets the minimum count of the pool.
|
||||
* If min is greater than the max count of the pool, an error is thrown.
|
||||
* @param {number} min The minimum count of the pool.
|
||||
*/
|
||||
goog.structs.Pool.prototype.setMinimumCount = function(min) {
|
||||
// Check count constraints.
|
||||
if (min > this.maxCount_) {
|
||||
throw Error(goog.structs.Pool.ERROR_MIN_MAX_);
|
||||
}
|
||||
this.minCount_ = min;
|
||||
|
||||
// Adjust the objects in the pool as needed.
|
||||
this.adjustForMinMax();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the maximum count of the pool.
|
||||
* If max is less than the max count of the pool, an error is thrown.
|
||||
* @param {number} max The maximium count of the pool.
|
||||
*/
|
||||
goog.structs.Pool.prototype.setMaximumCount = function(max) {
|
||||
// Check count constraints.
|
||||
if (max < this.minCount_) {
|
||||
throw Error(goog.structs.Pool.ERROR_MIN_MAX_);
|
||||
}
|
||||
this.maxCount_ = max;
|
||||
|
||||
// Adjust the objects in the pool as needed.
|
||||
this.adjustForMinMax();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the minimum delay between objects being returned by getObject, in
|
||||
* milliseconds. This defaults to zero, meaning that no minimum delay is
|
||||
* enforced and objects may be used as soon as they're available.
|
||||
* @param {number} delay The minimum delay, in milliseconds.
|
||||
*/
|
||||
goog.structs.Pool.prototype.setDelay = function(delay) {
|
||||
this.delay = delay;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Object|undefined} A new object from the pool if there is one
|
||||
* available, otherwise undefined.
|
||||
*/
|
||||
goog.structs.Pool.prototype.getObject = function() {
|
||||
var time = goog.now();
|
||||
if (goog.isDefAndNotNull(this.lastAccess) &&
|
||||
time - this.lastAccess < this.delay) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var obj = this.removeFreeObject_();
|
||||
if (obj) {
|
||||
this.lastAccess = time;
|
||||
this.inUseSet_.add(obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an object to the pool of available objects so that it can be reused.
|
||||
* @param {Object} obj The object to return to the pool of free objects.
|
||||
* @return {boolean} Whether the object was found in the Pool's set of in-use
|
||||
* objects (in other words, whether any action was taken).
|
||||
*/
|
||||
goog.structs.Pool.prototype.releaseObject = function(obj) {
|
||||
if (this.inUseSet_.remove(obj)) {
|
||||
this.addFreeObject(obj);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a free object from the collection of objects that are free so that it
|
||||
* can be used.
|
||||
*
|
||||
* NOTE: This method does not mark the returned object as in use.
|
||||
*
|
||||
* @return {Object|undefined} The object removed from the free collection, if
|
||||
* there is one available. Otherwise, undefined.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Pool.prototype.removeFreeObject_ = function() {
|
||||
var obj;
|
||||
while (this.getFreeCount() > 0) {
|
||||
obj = /** @type {Object} */(this.freeQueue_.dequeue());
|
||||
|
||||
if (!this.objectCanBeReused(obj)) {
|
||||
this.adjustForMinMax();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!obj && this.getCount() < this.maxCount_) {
|
||||
obj = this.createObject();
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an object to the collection of objects that are free. If the object can
|
||||
* not be added, then it is disposed.
|
||||
*
|
||||
* @param {Object} obj The object to add to collection of free objects.
|
||||
*/
|
||||
goog.structs.Pool.prototype.addFreeObject = function(obj) {
|
||||
this.inUseSet_.remove(obj);
|
||||
if (this.objectCanBeReused(obj) && this.getCount() < this.maxCount_) {
|
||||
this.freeQueue_.enqueue(obj);
|
||||
} else {
|
||||
this.disposeObject(obj);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adjusts the objects held in the pool to be within the min/max constraints.
|
||||
*
|
||||
* NOTE: It is possible that the number of objects in the pool will still be
|
||||
* greater than the maximum count of objects allowed. This will be the case
|
||||
* if no more free objects can be disposed of to get below the minimum count
|
||||
* (i.e., all objects are in use).
|
||||
*/
|
||||
goog.structs.Pool.prototype.adjustForMinMax = function() {
|
||||
var freeQueue = this.freeQueue_;
|
||||
|
||||
// Make sure the at least the minimum number of objects are created.
|
||||
while (this.getCount() < this.minCount_) {
|
||||
freeQueue.enqueue(this.createObject());
|
||||
}
|
||||
|
||||
// Make sure no more than the maximum number of objects are created.
|
||||
while (this.getCount() > this.maxCount_ && this.getFreeCount() > 0) {
|
||||
this.disposeObject(/** @type {Object} */(freeQueue.dequeue()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Should be overriden by sub-classes to return an instance of the object type
|
||||
* that is expected in the pool.
|
||||
* @return {Object} The created object.
|
||||
*/
|
||||
goog.structs.Pool.prototype.createObject = function() {
|
||||
return {};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Should be overriden to dispose of an object. Default implementation is to
|
||||
* remove all its members, which should render it useless. Calls the object's
|
||||
* {@code dispose()} method, if available.
|
||||
* @param {Object} obj The object to dispose.
|
||||
*/
|
||||
goog.structs.Pool.prototype.disposeObject = function(obj) {
|
||||
if (typeof obj.dispose == 'function') {
|
||||
obj.dispose();
|
||||
} else {
|
||||
for (var i in obj) {
|
||||
obj[i] = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Should be overriden to determine whether an object has become unusable and
|
||||
* should not be returned by getObject(). Calls the object's
|
||||
* {@code canBeReused()} method, if available.
|
||||
* @param {Object} obj The object to test.
|
||||
* @return {boolean} Whether the object can be reused.
|
||||
*/
|
||||
goog.structs.Pool.prototype.objectCanBeReused = function(obj) {
|
||||
if (typeof obj.canBeReused == 'function') {
|
||||
return obj.canBeReused();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the given object is in the pool.
|
||||
* @param {Object} obj The object to check the pool for.
|
||||
* @return {boolean} Whether the pool contains the object.
|
||||
*/
|
||||
goog.structs.Pool.prototype.contains = function(obj) {
|
||||
return this.freeQueue_.contains(obj) || this.inUseSet_.contains(obj);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of objects currently in the pool.
|
||||
* @return {number} Number of objects currently in the pool.
|
||||
*/
|
||||
goog.structs.Pool.prototype.getCount = function() {
|
||||
return this.freeQueue_.getCount() + this.inUseSet_.getCount();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of objects currently in use in the pool.
|
||||
* @return {number} Number of objects currently in use in the pool.
|
||||
*/
|
||||
goog.structs.Pool.prototype.getInUseCount = function() {
|
||||
return this.inUseSet_.getCount();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of objects currently free in the pool.
|
||||
* @return {number} Number of objects currently free in the pool.
|
||||
*/
|
||||
goog.structs.Pool.prototype.getFreeCount = function() {
|
||||
return this.freeQueue_.getCount();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determines if the pool contains no objects.
|
||||
* @return {boolean} Whether the pool contains no objects.
|
||||
*/
|
||||
goog.structs.Pool.prototype.isEmpty = function() {
|
||||
return this.freeQueue_.isEmpty() && this.inUseSet_.isEmpty();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Disposes of the pool and all objects currently held in the pool.
|
||||
* @override
|
||||
* @protected
|
||||
*/
|
||||
goog.structs.Pool.prototype.disposeInternal = function() {
|
||||
goog.structs.Pool.superClass_.disposeInternal.call(this);
|
||||
if (this.getInUseCount() > 0) {
|
||||
throw Error(goog.structs.Pool.ERROR_DISPOSE_UNRELEASED_OBJS_);
|
||||
}
|
||||
delete this.inUseSet_;
|
||||
|
||||
// Call disposeObject on each object held by the pool.
|
||||
var freeQueue = this.freeQueue_;
|
||||
while (!freeQueue.isEmpty()) {
|
||||
this.disposeObject(/** @type {Object} */ (freeQueue.dequeue()));
|
||||
}
|
||||
delete this.freeQueue_;
|
||||
};
|
||||
@@ -0,0 +1,184 @@
|
||||
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: Priority Pool.
|
||||
*
|
||||
*
|
||||
* An extending of Pool that handles queueing and prioritization.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs.PriorityPool');
|
||||
|
||||
goog.require('goog.structs.Pool');
|
||||
goog.require('goog.structs.PriorityQueue');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A generic pool class. If max is greater than min, an error is thrown.
|
||||
* @param {number=} opt_minCount Min. number of objects (Default: 1).
|
||||
* @param {number=} opt_maxCount Max. number of objects (Default: 10).
|
||||
* @constructor
|
||||
* @extends {goog.structs.Pool}
|
||||
*/
|
||||
goog.structs.PriorityPool = function(opt_minCount, opt_maxCount) {
|
||||
/**
|
||||
* Queue of requests for pool objects.
|
||||
* @type {goog.structs.PriorityQueue}
|
||||
* @private
|
||||
*/
|
||||
this.requestQueue_ = new goog.structs.PriorityQueue();
|
||||
|
||||
// Must break convention of putting the super-class's constructor first. This
|
||||
// is because the super-class constructor calls adjustForMinMax, which this
|
||||
// class overrides. In this class's implementation, it assumes that there
|
||||
// is a requestQueue_, and will error if not present.
|
||||
goog.structs.Pool.call(this, opt_minCount, opt_maxCount);
|
||||
};
|
||||
goog.inherits(goog.structs.PriorityPool, goog.structs.Pool);
|
||||
|
||||
|
||||
/**
|
||||
* The key for the most recent timeout created.
|
||||
* @type {number|undefined}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.PriorityPool.prototype.delayTimeout_;
|
||||
|
||||
|
||||
/**
|
||||
* Default priority for pool objects requests.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.PriorityPool.DEFAULT_PRIORITY_ = 100;
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.structs.PriorityPool.prototype.setDelay = function(delay) {
|
||||
goog.base(this, 'setDelay', delay);
|
||||
|
||||
// If the pool hasn't been accessed yet, no need to do anything.
|
||||
if (!goog.isDefAndNotNull(this.lastAccess)) {
|
||||
return;
|
||||
}
|
||||
|
||||
goog.global.clearTimeout(this.delayTimeout_);
|
||||
this.delayTimeout_ = goog.global.setTimeout(
|
||||
goog.bind(this.handleQueueRequests_, this),
|
||||
this.delay + this.lastAccess - goog.now());
|
||||
|
||||
// Handle all requests.
|
||||
this.handleQueueRequests_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get a new object from the the pool, if there is one available, otherwise
|
||||
* return undefined.
|
||||
* @param {Function=} opt_callback The function to callback when an object is
|
||||
* available. This could be immediately. If this is not present, then an
|
||||
* object is immediately returned if available, or undefined if not.
|
||||
* @param {*=} opt_priority The priority of the request. A smaller value means a
|
||||
* higher priority.
|
||||
* @return {Object|undefined} The new object from the pool if there is one
|
||||
* available and a callback is not given. Otherwise, undefined.
|
||||
* @override
|
||||
*/
|
||||
goog.structs.PriorityPool.prototype.getObject = function(opt_callback,
|
||||
opt_priority) {
|
||||
if (!opt_callback) {
|
||||
var result = goog.base(this, 'getObject');
|
||||
if (result && this.delay) {
|
||||
this.delayTimeout_ = goog.global.setTimeout(
|
||||
goog.bind(this.handleQueueRequests_, this),
|
||||
this.delay);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
var priority = goog.isDef(opt_priority) ? opt_priority :
|
||||
goog.structs.PriorityPool.DEFAULT_PRIORITY_;
|
||||
this.requestQueue_.enqueue(priority, opt_callback);
|
||||
|
||||
// Handle all requests.
|
||||
this.handleQueueRequests_();
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handles the request queue. Tries to fires off as many queued requests as
|
||||
* possible.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.PriorityPool.prototype.handleQueueRequests_ = function() {
|
||||
var requestQueue = this.requestQueue_;
|
||||
while (requestQueue.getCount() > 0) {
|
||||
var obj = this.getObject();
|
||||
|
||||
if (!obj) {
|
||||
return;
|
||||
} else {
|
||||
var requestCallback = requestQueue.dequeue();
|
||||
requestCallback.apply(this, [obj]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an object to the collection of objects that are free. If the object can
|
||||
* not be added, then it is disposed.
|
||||
*
|
||||
* NOTE: This method does not remove the object from the in use collection.
|
||||
*
|
||||
* @param {Object} obj The object to add to the collection of free objects.
|
||||
* @override
|
||||
*/
|
||||
goog.structs.PriorityPool.prototype.addFreeObject = function(obj) {
|
||||
goog.structs.PriorityPool.superClass_.addFreeObject.call(this, obj);
|
||||
|
||||
// Handle all requests.
|
||||
this.handleQueueRequests_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adjusts the objects held in the pool to be within the min/max constraints.
|
||||
*
|
||||
* NOTE: It is possible that the number of objects in the pool will still be
|
||||
* greater than the maximum count of objects allowed. This will be the case
|
||||
* if no more free objects can be disposed of to get below the minimum count
|
||||
* (i.e., all objects are in use).
|
||||
* @override
|
||||
*/
|
||||
goog.structs.PriorityPool.prototype.adjustForMinMax = function() {
|
||||
goog.structs.PriorityPool.superClass_.adjustForMinMax.call(this);
|
||||
|
||||
// Handle all requests.
|
||||
this.handleQueueRequests_();
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.structs.PriorityPool.prototype.disposeInternal = function() {
|
||||
goog.structs.PriorityPool.superClass_.disposeInternal.call(this);
|
||||
goog.global.clearTimeout(this.delayTimeout_);
|
||||
this.requestQueue_.clear();
|
||||
this.requestQueue_ = null;
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: Priority Queue.
|
||||
*
|
||||
*
|
||||
* This file provides the implementation of a Priority Queue. Smaller priorities
|
||||
* move to the front of the queue. If two values have the same priority,
|
||||
* it is arbitrary which value will come to the front of the queue first.
|
||||
*/
|
||||
|
||||
// TODO(user): Should this rely on natural ordering via some Comparable
|
||||
// interface?
|
||||
|
||||
|
||||
goog.provide('goog.structs.PriorityQueue');
|
||||
|
||||
goog.require('goog.structs.Heap');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for Priority Queue datastructure.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {goog.structs.Heap}
|
||||
*/
|
||||
goog.structs.PriorityQueue = function() {
|
||||
goog.structs.Heap.call(this);
|
||||
};
|
||||
goog.inherits(goog.structs.PriorityQueue, goog.structs.Heap);
|
||||
|
||||
|
||||
/**
|
||||
* Puts the specified value in the queue.
|
||||
* @param {*} priority The priority of the value. A smaller value here means a
|
||||
* higher priority.
|
||||
* @param {*} value The value.
|
||||
*/
|
||||
goog.structs.PriorityQueue.prototype.enqueue = function(priority, value) {
|
||||
this.insert(priority, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves and removes the head of this queue.
|
||||
* @return {*} The element at the head of this queue. Returns
|
||||
* undefined if the queue is empty.
|
||||
*/
|
||||
goog.structs.PriorityQueue.prototype.dequeue = function() {
|
||||
return this.remove();
|
||||
};
|
||||
571
nicer-api-docs/closure-library/closure/goog/structs/quadtree.js
Normal file
571
nicer-api-docs/closure-library/closure/goog/structs/quadtree.js
Normal file
@@ -0,0 +1,571 @@
|
||||
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: A point Quad Tree for representing 2D data. Each
|
||||
* region has the same ratio as the bounds for the tree.
|
||||
*
|
||||
* The implementation currently requires pre-determined bounds for data as it
|
||||
* can not rebalance itself to that degree.
|
||||
*
|
||||
* @see ../demos/quadtree.html
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs.QuadTree');
|
||||
goog.provide('goog.structs.QuadTree.Node');
|
||||
goog.provide('goog.structs.QuadTree.Point');
|
||||
|
||||
goog.require('goog.math.Coordinate');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new quad tree.
|
||||
* @param {number} minX Minimum x-value that can be held in tree.
|
||||
* @param {number} minY Minimum y-value that can be held in tree.
|
||||
* @param {number} maxX Maximum x-value that can be held in tree.
|
||||
* @param {number} maxY Maximum y-value that can be held in tree.
|
||||
* @constructor
|
||||
*/
|
||||
goog.structs.QuadTree = function(minX, minY, maxX, maxY) {
|
||||
|
||||
/**
|
||||
* The root node for the quad tree.
|
||||
* @type {goog.structs.QuadTree.Node}
|
||||
* @private
|
||||
*/
|
||||
this.root_ = new goog.structs.QuadTree.Node(
|
||||
minX, minY, maxX - minX, maxY - minY);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Count of the number of items in the tree.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.count_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a reference to the tree's root node. Callers shouldn't modify nodes,
|
||||
* directly. This is a convenience for visualization and debugging purposes.
|
||||
* @return {goog.structs.QuadTree.Node} The root node.
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.getRootNode = function() {
|
||||
return this.root_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the value of an (x, y) point within the quad-tree.
|
||||
* @param {number} x The x-coordinate.
|
||||
* @param {number} y The y-coordinate.
|
||||
* @param {*} value The value associated with the point.
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.set = function(x, y, value) {
|
||||
var root = this.root_;
|
||||
if (x < root.x || y < root.y || x > root.x + root.w || y > root.y + root.h) {
|
||||
throw Error('Out of bounds : (' + x + ', ' + y + ')');
|
||||
}
|
||||
if (this.insert_(root, new goog.structs.QuadTree.Point(x, y, value))) {
|
||||
this.count_++;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the value of the point at (x, y) or null if the point is empty.
|
||||
* @param {number} x The x-coordinate.
|
||||
* @param {number} y The y-coordinate.
|
||||
* @param {*=} opt_default The default value to return if the node doesn't
|
||||
* exist.
|
||||
* @return {*} The value of the node, the default value if the node
|
||||
* doesn't exist, or undefined if the node doesn't exist and no default
|
||||
* has been provided.
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.get = function(x, y, opt_default) {
|
||||
var node = this.find_(this.root_, x, y);
|
||||
return node ? node.point.value : opt_default;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a point from (x, y) if it exists.
|
||||
* @param {number} x The x-coordinate.
|
||||
* @param {number} y The y-coordinate.
|
||||
* @return {*} The value of the node that was removed, or null if the
|
||||
* node doesn't exist.
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.remove = function(x, y) {
|
||||
var node = this.find_(this.root_, x, y);
|
||||
if (node) {
|
||||
var value = node.point.value;
|
||||
node.point = null;
|
||||
node.nodeType = goog.structs.QuadTree.NodeType.EMPTY;
|
||||
this.balance_(node);
|
||||
this.count_--;
|
||||
return value;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the point at (x, y) exists in the tree.
|
||||
* @param {number} x The x-coordinate.
|
||||
* @param {number} y The y-coordinate.
|
||||
* @return {boolean} Whether the tree contains a point at (x, y).
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.contains = function(x, y) {
|
||||
return this.get(x, y) != null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the tree is empty.
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.isEmpty = function() {
|
||||
return this.root_.nodeType == goog.structs.QuadTree.NodeType.EMPTY;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The number of items in the tree.
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.getCount = function() {
|
||||
return this.count_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all items from the tree.
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.clear = function() {
|
||||
this.root_.nw = this.root_.ne = this.root_.sw = this.root_.se = null;
|
||||
this.root_.nodeType = goog.structs.QuadTree.NodeType.EMPTY;
|
||||
this.root_.point = null;
|
||||
this.count_ = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array containing the coordinates of each point stored in the tree.
|
||||
* @return {Array.<goog.math.Coordinate?>} Array of coordinates.
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.getKeys = function() {
|
||||
var arr = [];
|
||||
this.traverse_(this.root_, function(node) {
|
||||
arr.push(new goog.math.Coordinate(node.point.x, node.point.y));
|
||||
});
|
||||
return arr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array containing all values stored within the tree.
|
||||
* @return {Array.<Object>} The values stored within the tree.
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.getValues = function() {
|
||||
var arr = [];
|
||||
this.traverse_(this.root_, function(node) {
|
||||
// Must have a point because it's a leaf.
|
||||
arr.push(node.point.value);
|
||||
});
|
||||
return arr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clones the quad-tree and returns the new instance.
|
||||
* @return {goog.structs.QuadTree} A clone of the tree.
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.clone = function() {
|
||||
var x1 = this.root_.x;
|
||||
var y1 = this.root_.y;
|
||||
var x2 = x1 + this.root_.w;
|
||||
var y2 = y1 + this.root_.h;
|
||||
var clone = new goog.structs.QuadTree(x1, y1, x2, y2);
|
||||
// This is inefficient as the clone needs to recalculate the structure of the
|
||||
// tree, even though we know it already. But this is easier and can be
|
||||
// optimized when/if needed.
|
||||
this.traverse_(this.root_, function(node) {
|
||||
clone.set(node.point.x, node.point.y, node.point.value);
|
||||
});
|
||||
return clone;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Traverses the tree and calls a function on each node.
|
||||
* @param {function(?, goog.math.Coordinate, goog.structs.QuadTree)} fn
|
||||
* The function to call for every value. This function takes 3 arguments
|
||||
* (the value, the coordinate, and the tree itself) and the return value is
|
||||
* irrelevant.
|
||||
* @param {Object=} opt_obj The object to be used as the value of 'this'
|
||||
* within {@ code fn}.
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.forEach = function(fn, opt_obj) {
|
||||
this.traverse_(this.root_, function(node) {
|
||||
var coord = new goog.math.Coordinate(node.point.x, node.point.y);
|
||||
fn.call(opt_obj, node.point.value, coord, this);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Traverses the tree depth-first, with quadrants being traversed in clockwise
|
||||
* order (NE, SE, SW, NW). The provided function will be called for each
|
||||
* leaf node that is encountered.
|
||||
* @param {goog.structs.QuadTree.Node} node The current node.
|
||||
* @param {function(goog.structs.QuadTree.Node)} fn The function to call
|
||||
* for each leaf node. This function takes the node as an argument, and its
|
||||
* return value is irrelevant.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.traverse_ = function(node, fn) {
|
||||
switch (node.nodeType) {
|
||||
case goog.structs.QuadTree.NodeType.LEAF:
|
||||
fn.call(this, node);
|
||||
break;
|
||||
|
||||
case goog.structs.QuadTree.NodeType.POINTER:
|
||||
this.traverse_(node.ne, fn);
|
||||
this.traverse_(node.se, fn);
|
||||
this.traverse_(node.sw, fn);
|
||||
this.traverse_(node.nw, fn);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Finds a leaf node with the same (x, y) coordinates as the target point, or
|
||||
* null if no point exists.
|
||||
* @param {goog.structs.QuadTree.Node} node The node to search in.
|
||||
* @param {number} x The x-coordinate of the point to search for.
|
||||
* @param {number} y The y-coordinate of the point to search for.
|
||||
* @return {goog.structs.QuadTree.Node} The leaf node that matches the target,
|
||||
* or null if it doesn't exist.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.find_ = function(node, x, y) {
|
||||
switch (node.nodeType) {
|
||||
case goog.structs.QuadTree.NodeType.EMPTY:
|
||||
return null;
|
||||
|
||||
case goog.structs.QuadTree.NodeType.LEAF:
|
||||
return node.point.x == x && node.point.y == y ? node : null;
|
||||
|
||||
case goog.structs.QuadTree.NodeType.POINTER:
|
||||
return this.find_(this.getQuadrantForPoint_(node, x, y), x, y);
|
||||
|
||||
default:
|
||||
throw Error('Invalid nodeType');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Inserts a point into the tree, updating the tree's structure if necessary.
|
||||
* @param {goog.structs.QuadTree.Node} parent The parent to insert the point
|
||||
* into.
|
||||
* @param {goog.structs.QuadTree.Point} point The point to insert.
|
||||
* @return {boolean} True if a new node was added to the tree; False if a node
|
||||
* already existed with the correpsonding coordinates and had its value
|
||||
* reset.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.insert_ = function(parent, point) {
|
||||
switch (parent.nodeType) {
|
||||
case goog.structs.QuadTree.NodeType.EMPTY:
|
||||
this.setPointForNode_(parent, point);
|
||||
return true;
|
||||
|
||||
case goog.structs.QuadTree.NodeType.LEAF:
|
||||
if (parent.point.x == point.x && parent.point.y == point.y) {
|
||||
this.setPointForNode_(parent, point);
|
||||
return false;
|
||||
} else {
|
||||
this.split_(parent);
|
||||
return this.insert_(parent, point);
|
||||
}
|
||||
|
||||
case goog.structs.QuadTree.NodeType.POINTER:
|
||||
return this.insert_(
|
||||
this.getQuadrantForPoint_(parent, point.x, point.y), point);
|
||||
|
||||
default:
|
||||
throw Error('Invalid nodeType in parent');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts a leaf node to a pointer node and reinserts the node's point into
|
||||
* the correct child.
|
||||
* @param {goog.structs.QuadTree.Node} node The node to split.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.split_ = function(node) {
|
||||
var oldPoint = node.point;
|
||||
node.point = null;
|
||||
|
||||
node.nodeType = goog.structs.QuadTree.NodeType.POINTER;
|
||||
|
||||
var x = node.x;
|
||||
var y = node.y;
|
||||
var hw = node.w / 2;
|
||||
var hh = node.h / 2;
|
||||
|
||||
node.nw = new goog.structs.QuadTree.Node(x, y, hw, hh, node);
|
||||
node.ne = new goog.structs.QuadTree.Node(x + hw, y, hw, hh, node);
|
||||
node.sw = new goog.structs.QuadTree.Node(x, y + hh, hw, hh, node);
|
||||
node.se = new goog.structs.QuadTree.Node(x + hw, y + hh, hw, hh, node);
|
||||
|
||||
this.insert_(node, oldPoint);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to balance a node. A node will need balancing if all its children
|
||||
* are empty or it contains just one leaf.
|
||||
* @param {goog.structs.QuadTree.Node} node The node to balance.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.balance_ = function(node) {
|
||||
switch (node.nodeType) {
|
||||
case goog.structs.QuadTree.NodeType.EMPTY:
|
||||
case goog.structs.QuadTree.NodeType.LEAF:
|
||||
if (node.parent) {
|
||||
this.balance_(node.parent);
|
||||
}
|
||||
break;
|
||||
|
||||
case goog.structs.QuadTree.NodeType.POINTER:
|
||||
var nw = node.nw, ne = node.ne, sw = node.sw, se = node.se;
|
||||
var firstLeaf = null;
|
||||
|
||||
// Look for the first non-empty child, if there is more than one then we
|
||||
// break as this node can't be balanced.
|
||||
if (nw.nodeType != goog.structs.QuadTree.NodeType.EMPTY) {
|
||||
firstLeaf = nw;
|
||||
}
|
||||
if (ne.nodeType != goog.structs.QuadTree.NodeType.EMPTY) {
|
||||
if (firstLeaf) {
|
||||
break;
|
||||
}
|
||||
firstLeaf = ne;
|
||||
}
|
||||
if (sw.nodeType != goog.structs.QuadTree.NodeType.EMPTY) {
|
||||
if (firstLeaf) {
|
||||
break;
|
||||
}
|
||||
firstLeaf = sw;
|
||||
}
|
||||
if (se.nodeType != goog.structs.QuadTree.NodeType.EMPTY) {
|
||||
if (firstLeaf) {
|
||||
break;
|
||||
}
|
||||
firstLeaf = se;
|
||||
}
|
||||
|
||||
if (!firstLeaf) {
|
||||
// All child nodes are empty: so make this node empty.
|
||||
node.nodeType = goog.structs.QuadTree.NodeType.EMPTY;
|
||||
node.nw = node.ne = node.sw = node.se = null;
|
||||
|
||||
} else if (firstLeaf.nodeType == goog.structs.QuadTree.NodeType.POINTER) {
|
||||
// Only child was a pointer, therefore we can't rebalance.
|
||||
break;
|
||||
|
||||
} else {
|
||||
// Only child was a leaf: so update node's point and make it a leaf.
|
||||
node.nodeType = goog.structs.QuadTree.NodeType.LEAF;
|
||||
node.nw = node.ne = node.sw = node.se = null;
|
||||
node.point = firstLeaf.point;
|
||||
}
|
||||
|
||||
// Try and balance the parent as well.
|
||||
if (node.parent) {
|
||||
this.balance_(node.parent);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the child quadrant within a node that contains the given (x, y)
|
||||
* coordinate.
|
||||
* @param {goog.structs.QuadTree.Node} parent The node.
|
||||
* @param {number} x The x-coordinate to look for.
|
||||
* @param {number} y The y-coordinate to look for.
|
||||
* @return {goog.structs.QuadTree.Node} The child quadrant that contains the
|
||||
* point.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.getQuadrantForPoint_ = function(parent, x, y) {
|
||||
var mx = parent.x + parent.w / 2;
|
||||
var my = parent.y + parent.h / 2;
|
||||
if (x < mx) {
|
||||
return y < my ? parent.nw : parent.sw;
|
||||
} else {
|
||||
return y < my ? parent.ne : parent.se;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the point for a node, as long as the node is a leaf or empty.
|
||||
* @param {goog.structs.QuadTree.Node} node The node to set the point for.
|
||||
* @param {goog.structs.QuadTree.Point} point The point to set.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.QuadTree.prototype.setPointForNode_ = function(node, point) {
|
||||
if (node.nodeType == goog.structs.QuadTree.NodeType.POINTER) {
|
||||
throw Error('Can not set point for node of type POINTER');
|
||||
}
|
||||
node.nodeType = goog.structs.QuadTree.NodeType.LEAF;
|
||||
node.point = point;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Enumeration of node types.
|
||||
* @enum {number}
|
||||
*/
|
||||
goog.structs.QuadTree.NodeType = {
|
||||
EMPTY: 0,
|
||||
LEAF: 1,
|
||||
POINTER: 2
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new quad tree node.
|
||||
* @param {number} x X-coordiate of node.
|
||||
* @param {number} y Y-coordinate of node.
|
||||
* @param {number} w Width of node.
|
||||
* @param {number} h Height of node.
|
||||
* @param {goog.structs.QuadTree.Node=} opt_parent Optional parent node.
|
||||
* @constructor
|
||||
*/
|
||||
goog.structs.QuadTree.Node = function(x, y, w, h, opt_parent) {
|
||||
/**
|
||||
* The x-coordinate of the node.
|
||||
* @type {number}
|
||||
*/
|
||||
this.x = x;
|
||||
|
||||
/**
|
||||
* The y-coordinate of the node.
|
||||
* @type {number}
|
||||
*/
|
||||
this.y = y;
|
||||
|
||||
/**
|
||||
* The width of the node.
|
||||
* @type {number}
|
||||
*/
|
||||
this.w = w;
|
||||
|
||||
/**
|
||||
* The height of the node.
|
||||
* @type {number}
|
||||
*/
|
||||
this.h = h;
|
||||
|
||||
/**
|
||||
* The parent node.
|
||||
* @type {goog.structs.QuadTree.Node?}
|
||||
*/
|
||||
this.parent = opt_parent || null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The node's type.
|
||||
* @type {goog.structs.QuadTree.NodeType}
|
||||
*/
|
||||
goog.structs.QuadTree.Node.prototype.nodeType =
|
||||
goog.structs.QuadTree.NodeType.EMPTY;
|
||||
|
||||
|
||||
/**
|
||||
* The child node in the North-West quadrant.
|
||||
* @type {goog.structs.QuadTree.Node?}
|
||||
*/
|
||||
goog.structs.QuadTree.Node.prototype.nw = null;
|
||||
|
||||
|
||||
/**
|
||||
* The child node in the North-East quadrant.
|
||||
* @type {goog.structs.QuadTree.Node?}
|
||||
*/
|
||||
goog.structs.QuadTree.Node.prototype.ne = null;
|
||||
|
||||
|
||||
/**
|
||||
* The child node in the South-West quadrant.
|
||||
* @type {goog.structs.QuadTree.Node?}
|
||||
*/
|
||||
goog.structs.QuadTree.Node.prototype.sw = null;
|
||||
|
||||
|
||||
/**
|
||||
* The child node in the South-East quadrant.
|
||||
* @type {goog.structs.QuadTree.Node?}
|
||||
*/
|
||||
goog.structs.QuadTree.Node.prototype.se = null;
|
||||
|
||||
|
||||
/**
|
||||
* The point for the node, if it is a leaf node.
|
||||
* @type {goog.structs.QuadTree.Point?}
|
||||
*/
|
||||
goog.structs.QuadTree.Node.prototype.point = null;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new point object.
|
||||
* @param {number} x The x-coordinate of the point.
|
||||
* @param {number} y The y-coordinate of the point.
|
||||
* @param {*=} opt_value Optional value associated with the point.
|
||||
* @constructor
|
||||
*/
|
||||
goog.structs.QuadTree.Point = function(x, y, opt_value) {
|
||||
/**
|
||||
* The x-coordinate for the point.
|
||||
* @type {number}
|
||||
*/
|
||||
this.x = x;
|
||||
|
||||
/**
|
||||
* The y-coordinate for the point.
|
||||
* @type {number}
|
||||
*/
|
||||
this.y = y;
|
||||
|
||||
/**
|
||||
* Optional value associated with the point.
|
||||
* @type {*}
|
||||
*/
|
||||
this.value = goog.isDef(opt_value) ? opt_value : null;
|
||||
};
|
||||
157
nicer-api-docs/closure-library/closure/goog/structs/queue.js
Normal file
157
nicer-api-docs/closure-library/closure/goog/structs/queue.js
Normal file
@@ -0,0 +1,157 @@
|
||||
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: Queue.
|
||||
*
|
||||
*
|
||||
* This file provides the implementation of a FIFO Queue structure.
|
||||
* API is similar to that of com.google.common.collect.IntQueue
|
||||
*/
|
||||
|
||||
goog.provide('goog.structs.Queue');
|
||||
|
||||
goog.require('goog.array');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for FIFO Queue data structure.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
goog.structs.Queue = function() {
|
||||
this.elements_ = [];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The index of the next element to be removed from the queue.
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
goog.structs.Queue.prototype.head_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* The index at which the next element would be added to the queue.
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
goog.structs.Queue.prototype.tail_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Puts the specified element on this queue.
|
||||
* @param {*} element The element to be added to the queue.
|
||||
*/
|
||||
goog.structs.Queue.prototype.enqueue = function(element) {
|
||||
this.elements_[this.tail_++] = element;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves and removes the head of this queue.
|
||||
* @return {*} The element at the head of this queue. Returns undefined if the
|
||||
* queue is empty.
|
||||
*/
|
||||
goog.structs.Queue.prototype.dequeue = function() {
|
||||
if (this.head_ == this.tail_) {
|
||||
return undefined;
|
||||
}
|
||||
var result = this.elements_[this.head_];
|
||||
delete this.elements_[this.head_];
|
||||
this.head_++;
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves but does not remove the head of this queue.
|
||||
* @return {*} The element at the head of this queue. Returns undefined if the
|
||||
* queue is empty.
|
||||
*/
|
||||
goog.structs.Queue.prototype.peek = function() {
|
||||
if (this.head_ == this.tail_) {
|
||||
return undefined;
|
||||
}
|
||||
return this.elements_[this.head_];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of elements in this queue.
|
||||
* @return {number} The number of elements in this queue.
|
||||
*/
|
||||
goog.structs.Queue.prototype.getCount = function() {
|
||||
return this.tail_ - this.head_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if this queue contains no elements.
|
||||
* @return {boolean} true if this queue contains no elements.
|
||||
*/
|
||||
goog.structs.Queue.prototype.isEmpty = function() {
|
||||
return this.tail_ - this.head_ == 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all elements from the queue.
|
||||
*/
|
||||
goog.structs.Queue.prototype.clear = function() {
|
||||
this.elements_.length = 0;
|
||||
this.head_ = 0;
|
||||
this.tail_ = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the given value is in the queue.
|
||||
* @param {*} obj The value to look for.
|
||||
* @return {boolean} Whether the object is in the queue.
|
||||
*/
|
||||
goog.structs.Queue.prototype.contains = function(obj) {
|
||||
return goog.array.contains(this.elements_, obj);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the first occurrence of a particular value from the queue.
|
||||
* @param {*} obj Object to remove.
|
||||
* @return {boolean} True if an element was removed.
|
||||
*/
|
||||
goog.structs.Queue.prototype.remove = function(obj) {
|
||||
var index = goog.array.indexOf(this.elements_, obj);
|
||||
if (index < 0) {
|
||||
return false;
|
||||
}
|
||||
if (index == this.head_) {
|
||||
this.dequeue();
|
||||
} else {
|
||||
goog.array.removeAt(this.elements_, index);
|
||||
this.tail_--;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns all the values in the queue.
|
||||
* @return {Array} An array of the values in the queue.
|
||||
*/
|
||||
goog.structs.Queue.prototype.getValues = function() {
|
||||
return this.elements_.slice(this.head_, this.tail_);
|
||||
};
|
||||
274
nicer-api-docs/closure-library/closure/goog/structs/set.js
Normal file
274
nicer-api-docs/closure-library/closure/goog/structs/set.js
Normal file
@@ -0,0 +1,274 @@
|
||||
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: Set.
|
||||
*
|
||||
* @author arv@google.com (Erik Arvidsson)
|
||||
* @author pallosp@google.com (Peter Pallos)
|
||||
*
|
||||
* This class implements a set data structure. Adding and removing is O(1). It
|
||||
* supports both object and primitive values. Be careful because you can add
|
||||
* both 1 and new Number(1), because these are not the same. You can even add
|
||||
* multiple new Number(1) because these are not equal.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs.Set');
|
||||
|
||||
goog.require('goog.structs');
|
||||
goog.require('goog.structs.Collection');
|
||||
goog.require('goog.structs.Map');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A set that can contain both primitives and objects. Adding and removing
|
||||
* elements is O(1). Primitives are treated as identical if they have the same
|
||||
* type and convert to the same string. Objects are treated as identical only
|
||||
* if they are references to the same object. WARNING: A goog.structs.Set can
|
||||
* contain both 1 and (new Number(1)), because they are not the same. WARNING:
|
||||
* Adding (new Number(1)) twice will yield two distinct elements, because they
|
||||
* are two different objects. WARNING: Any object that is added to a
|
||||
* goog.structs.Set will be modified! Because goog.getUid() is used to
|
||||
* identify objects, every object in the set will be mutated.
|
||||
* @param {Array|Object=} opt_values Initial values to start with.
|
||||
* @constructor
|
||||
* @implements {goog.structs.Collection}
|
||||
*/
|
||||
goog.structs.Set = function(opt_values) {
|
||||
this.map_ = new goog.structs.Map;
|
||||
if (opt_values) {
|
||||
this.addAll(opt_values);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Obtains a unique key for an element of the set. Primitives will yield the
|
||||
* same key if they have the same type and convert to the same string. Object
|
||||
* references will yield the same key only if they refer to the same object.
|
||||
* @param {*} val Object or primitive value to get a key for.
|
||||
* @return {string} A unique key for this value/object.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Set.getKey_ = function(val) {
|
||||
var type = typeof val;
|
||||
if (type == 'object' && val || type == 'function') {
|
||||
return 'o' + goog.getUid(/** @type {Object} */ (val));
|
||||
} else {
|
||||
return type.substr(0, 1) + val;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The number of elements in the set.
|
||||
* @override
|
||||
*/
|
||||
goog.structs.Set.prototype.getCount = function() {
|
||||
return this.map_.getCount();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add a primitive or an object to the set.
|
||||
* @param {*} element The primitive or object to add.
|
||||
* @override
|
||||
*/
|
||||
goog.structs.Set.prototype.add = function(element) {
|
||||
this.map_.set(goog.structs.Set.getKey_(element), element);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds all the values in the given collection to this set.
|
||||
* @param {Array|Object} col A collection containing the elements to add.
|
||||
*/
|
||||
goog.structs.Set.prototype.addAll = function(col) {
|
||||
var values = goog.structs.getValues(col);
|
||||
var l = values.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
this.add(values[i]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all values in the given collection from this set.
|
||||
* @param {Array|Object} col A collection containing the elements to remove.
|
||||
*/
|
||||
goog.structs.Set.prototype.removeAll = function(col) {
|
||||
var values = goog.structs.getValues(col);
|
||||
var l = values.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
this.remove(values[i]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the given element from this set.
|
||||
* @param {*} element The primitive or object to remove.
|
||||
* @return {boolean} Whether the element was found and removed.
|
||||
* @override
|
||||
*/
|
||||
goog.structs.Set.prototype.remove = function(element) {
|
||||
return this.map_.remove(goog.structs.Set.getKey_(element));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all elements from this set.
|
||||
*/
|
||||
goog.structs.Set.prototype.clear = function() {
|
||||
this.map_.clear();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether this set is empty.
|
||||
* @return {boolean} True if there are no elements in this set.
|
||||
*/
|
||||
goog.structs.Set.prototype.isEmpty = function() {
|
||||
return this.map_.isEmpty();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether this set contains the given element.
|
||||
* @param {*} element The primitive or object to test for.
|
||||
* @return {boolean} True if this set contains the given element.
|
||||
* @override
|
||||
*/
|
||||
goog.structs.Set.prototype.contains = function(element) {
|
||||
return this.map_.containsKey(goog.structs.Set.getKey_(element));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether this set contains all the values in a given collection.
|
||||
* Repeated elements in the collection are ignored, e.g. (new
|
||||
* goog.structs.Set([1, 2])).containsAll([1, 1]) is True.
|
||||
* @param {Object} col A collection-like object.
|
||||
* @return {boolean} True if the set contains all elements.
|
||||
*/
|
||||
goog.structs.Set.prototype.containsAll = function(col) {
|
||||
return goog.structs.every(col, this.contains, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Finds all values that are present in both this set and the given collection.
|
||||
* @param {Array|Object} col A collection.
|
||||
* @return {!goog.structs.Set} A new set containing all the values (primitives
|
||||
* or objects) present in both this set and the given collection.
|
||||
*/
|
||||
goog.structs.Set.prototype.intersection = function(col) {
|
||||
var result = new goog.structs.Set();
|
||||
|
||||
var values = goog.structs.getValues(col);
|
||||
for (var i = 0; i < values.length; i++) {
|
||||
var value = values[i];
|
||||
if (this.contains(value)) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Finds all values that are present in this set and not in the given
|
||||
* collection.
|
||||
* @param {Array|Object} col A collection.
|
||||
* @return {!goog.structs.Set} A new set containing all the values
|
||||
* (primitives or objects) present in this set but not in the given
|
||||
* collection.
|
||||
*/
|
||||
goog.structs.Set.prototype.difference = function(col) {
|
||||
var result = this.clone();
|
||||
result.removeAll(col);
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array containing all the elements in this set.
|
||||
* @return {!Array} An array containing all the elements in this set.
|
||||
*/
|
||||
goog.structs.Set.prototype.getValues = function() {
|
||||
return this.map_.getValues();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a shallow clone of this set.
|
||||
* @return {!goog.structs.Set} A new set containing all the same elements as
|
||||
* this set.
|
||||
*/
|
||||
goog.structs.Set.prototype.clone = function() {
|
||||
return new goog.structs.Set(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether the given collection consists of the same elements as this set,
|
||||
* regardless of order, without repetition. Primitives are treated as equal if
|
||||
* they have the same type and convert to the same string; objects are treated
|
||||
* as equal if they are references to the same object. This operation is O(n).
|
||||
* @param {Object} col A collection.
|
||||
* @return {boolean} True if the given collection consists of the same elements
|
||||
* as this set, regardless of order, without repetition.
|
||||
*/
|
||||
goog.structs.Set.prototype.equals = function(col) {
|
||||
return this.getCount() == goog.structs.getCount(col) && this.isSubsetOf(col);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether the given collection contains all the elements in this set.
|
||||
* Primitives are treated as equal if they have the same type and convert to the
|
||||
* same string; objects are treated as equal if they are references to the same
|
||||
* object. This operation is O(n).
|
||||
* @param {Object} col A collection.
|
||||
* @return {boolean} True if this set is a subset of the given collection.
|
||||
*/
|
||||
goog.structs.Set.prototype.isSubsetOf = function(col) {
|
||||
var colCount = goog.structs.getCount(col);
|
||||
if (this.getCount() > colCount) {
|
||||
return false;
|
||||
}
|
||||
// TODO(user) Find the minimal collection size where the conversion makes
|
||||
// the contains() method faster.
|
||||
if (!(col instanceof goog.structs.Set) && colCount > 5) {
|
||||
// Convert to a goog.structs.Set so that goog.structs.contains runs in
|
||||
// O(1) time instead of O(n) time.
|
||||
col = new goog.structs.Set(col);
|
||||
}
|
||||
return goog.structs.every(this, function(value) {
|
||||
return goog.structs.contains(col, value);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator that iterates over the elements in this set.
|
||||
* @param {boolean=} opt_keys This argument is ignored.
|
||||
* @return {!goog.iter.Iterator} An iterator over the elements in this set.
|
||||
*/
|
||||
goog.structs.Set.prototype.__iterator__ = function(opt_keys) {
|
||||
return this.map_.__iterator__(false);
|
||||
};
|
||||
@@ -0,0 +1,205 @@
|
||||
// Copyright 2007 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: Pool.
|
||||
*
|
||||
*
|
||||
* A generic class for handling pools of objects that is more efficient than
|
||||
* goog.structs.Pool because it doesn't maintain a list of objects that are in
|
||||
* use. See constructor comment.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs.SimplePool');
|
||||
|
||||
goog.require('goog.Disposable');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A generic pool class. Simpler and more efficient than goog.structs.Pool
|
||||
* because it doesn't maintain a list of objects that are in use. This class
|
||||
* has constant overhead and doesn't create any additional objects as part of
|
||||
* the pool management after construction time.
|
||||
*
|
||||
* IMPORTANT: If the objects being pooled are arrays or maps that can have
|
||||
* unlimited number of properties, they need to be cleaned before being
|
||||
* returned to the pool.
|
||||
*
|
||||
* Also note that {@see goog.object.clean} actually allocates an array to clean
|
||||
* the object passed to it, so simply using this function would defy the
|
||||
* purpose of using the pool.
|
||||
*
|
||||
* @param {number} initialCount Initial number of objects to populate the
|
||||
* free pool at construction time.
|
||||
* @param {number} maxCount Maximum number of objects to keep in the free pool.
|
||||
* @constructor
|
||||
* @extends {goog.Disposable}
|
||||
*/
|
||||
goog.structs.SimplePool = function(initialCount, maxCount) {
|
||||
goog.Disposable.call(this);
|
||||
|
||||
/**
|
||||
* Maximum number of objects allowed
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.maxCount_ = maxCount;
|
||||
|
||||
/**
|
||||
* Queue used to store objects that are currently in the pool and available
|
||||
* to be used.
|
||||
* @type {Array}
|
||||
* @private
|
||||
*/
|
||||
this.freeQueue_ = [];
|
||||
|
||||
this.createInitial_(initialCount);
|
||||
};
|
||||
goog.inherits(goog.structs.SimplePool, goog.Disposable);
|
||||
|
||||
|
||||
/**
|
||||
* Function for overriding createObject. The avoids a common case requiring
|
||||
* subclassing this class.
|
||||
* @type {Function}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.SimplePool.prototype.createObjectFn_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Function for overriding disposeObject. The avoids a common case requiring
|
||||
* subclassing this class.
|
||||
* @type {Function}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.SimplePool.prototype.disposeObjectFn_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the {@code createObject} function which is used for creating a new
|
||||
* object in the pool.
|
||||
* @param {Function} createObjectFn Create object function which returns the
|
||||
* newly createrd object.
|
||||
*/
|
||||
goog.structs.SimplePool.prototype.setCreateObjectFn = function(createObjectFn) {
|
||||
this.createObjectFn_ = createObjectFn;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the {@code disposeObject} function which is used for disposing of an
|
||||
* object in the pool.
|
||||
* @param {Function} disposeObjectFn Dispose object function which takes the
|
||||
* object to dispose as a parameter.
|
||||
*/
|
||||
goog.structs.SimplePool.prototype.setDisposeObjectFn = function(
|
||||
disposeObjectFn) {
|
||||
this.disposeObjectFn_ = disposeObjectFn;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets an unused object from the the pool, if there is one available,
|
||||
* otherwise creates a new one.
|
||||
* @return {*} An object from the pool or a new one if necessary.
|
||||
*/
|
||||
goog.structs.SimplePool.prototype.getObject = function() {
|
||||
if (this.freeQueue_.length) {
|
||||
return this.freeQueue_.pop();
|
||||
}
|
||||
return this.createObject();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an object to the pool so that it can be reused. If the pool is
|
||||
* already full, the object is disposed instead.
|
||||
* @param {*} obj The object to release.
|
||||
*/
|
||||
goog.structs.SimplePool.prototype.releaseObject = function(obj) {
|
||||
if (this.freeQueue_.length < this.maxCount_) {
|
||||
this.freeQueue_.push(obj);
|
||||
} else {
|
||||
this.disposeObject(obj);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Populates the pool with initialCount objects.
|
||||
* @param {number} initialCount The number of objects to add to the pool.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.SimplePool.prototype.createInitial_ = function(initialCount) {
|
||||
if (initialCount > this.maxCount_) {
|
||||
throw Error('[goog.structs.SimplePool] Initial cannot be greater than max');
|
||||
}
|
||||
for (var i = 0; i < initialCount; i++) {
|
||||
this.freeQueue_.push(this.createObject());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Should be overriden by sub-classes to return an instance of the object type
|
||||
* that is expected in the pool.
|
||||
* @return {*} The created object.
|
||||
*/
|
||||
goog.structs.SimplePool.prototype.createObject = function() {
|
||||
if (this.createObjectFn_) {
|
||||
return this.createObjectFn_();
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Should be overriden to dispose of an object. Default implementation is to
|
||||
* remove all of the object's members, which should render it useless. Calls the
|
||||
* object's dispose method, if available.
|
||||
* @param {*} obj The object to dispose.
|
||||
*/
|
||||
goog.structs.SimplePool.prototype.disposeObject = function(obj) {
|
||||
if (this.disposeObjectFn_) {
|
||||
this.disposeObjectFn_(obj);
|
||||
} else if (goog.isObject(obj)) {
|
||||
if (goog.isFunction(obj.dispose)) {
|
||||
obj.dispose();
|
||||
} else {
|
||||
for (var i in obj) {
|
||||
delete obj[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Disposes of the pool and all objects currently held in the pool.
|
||||
* @override
|
||||
* @protected
|
||||
*/
|
||||
goog.structs.SimplePool.prototype.disposeInternal = function() {
|
||||
goog.structs.SimplePool.superClass_.disposeInternal.call(this);
|
||||
// Call disposeObject on each object held by the pool.
|
||||
var freeQueue = this.freeQueue_;
|
||||
while (freeQueue.length) {
|
||||
this.disposeObject(freeQueue.pop());
|
||||
}
|
||||
delete this.freeQueue_;
|
||||
};
|
||||
403
nicer-api-docs/closure-library/closure/goog/structs/stringset.js
Normal file
403
nicer-api-docs/closure-library/closure/goog/structs/stringset.js
Normal file
@@ -0,0 +1,403 @@
|
||||
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Data structure for set of strings.
|
||||
*
|
||||
*
|
||||
* This class implements a set data structure for strings. Adding and removing
|
||||
* is O(1). It doesn't contain any bloat from {@link goog.structs.Set}, i.e.
|
||||
* it isn't optimized for IE6 garbage collector (see the description of
|
||||
* {@link goog.structs.Map#keys_} for details), and it distinguishes its
|
||||
* elements by their string value not by hash code.
|
||||
* The implementation assumes that no new keys are added to Object.prototype.
|
||||
*/
|
||||
|
||||
goog.provide('goog.structs.StringSet');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.iter');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a set of strings.
|
||||
* @param {!Array=} opt_elements Elements to add to the set. The non-string
|
||||
* items will be converted to strings, so 15 and '15' will mean the same.
|
||||
* @constructor
|
||||
*/
|
||||
goog.structs.StringSet = function(opt_elements) {
|
||||
/**
|
||||
* An object storing the escaped elements of the set in its keys.
|
||||
* @type {!Object}
|
||||
* @private
|
||||
*/
|
||||
this.elements_ = {};
|
||||
|
||||
if (opt_elements) {
|
||||
for (var i = 0; i < opt_elements.length; i++) {
|
||||
this.elements_[this.encode(opt_elements[i])] = null;
|
||||
}
|
||||
}
|
||||
|
||||
goog.asserts.assertObjectPrototypeIsIntact();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Empty object. Referring to it is faster than creating a new empty object in
|
||||
* {@link #encode}.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.StringSet.EMPTY_OBJECT_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* The '__proto__' and the '__count__' keys aren't enumerable in Firefox, and
|
||||
* 'toString', 'valueOf', 'constructor', etc. aren't enumerable in IE so they
|
||||
* have to be escaped before they are added to the internal object.
|
||||
* NOTE: When a new set is created, 50-80% of the CPU time is spent in encode.
|
||||
* @param {*} element The element to escape.
|
||||
* @return {*} The escaped element or the element itself if it doesn't have to
|
||||
* be escaped.
|
||||
* @protected
|
||||
*/
|
||||
goog.structs.StringSet.prototype.encode = function(element) {
|
||||
return element in goog.structs.StringSet.EMPTY_OBJECT_ ||
|
||||
String(element).charCodeAt(0) == 32 ? ' ' + element : element;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Inverse function of {@link #encode}.
|
||||
* NOTE: forEach would be 30% faster in FF if the compiler inlined decode.
|
||||
* @param {string} key The escaped element used as the key of the internal
|
||||
* object.
|
||||
* @return {string} The unescaped element.
|
||||
* @protected
|
||||
*/
|
||||
goog.structs.StringSet.prototype.decode = function(key) {
|
||||
return key.charCodeAt(0) == 32 ? key.substr(1) : key;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a single element to the set.
|
||||
* @param {*} element The element to add. It will be converted to string.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.add = function(element) {
|
||||
this.elements_[this.encode(element)] = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a the elements of an array to this set.
|
||||
* @param {!Array} arr The array to add the elements of.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.addArray = function(arr) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
this.elements_[this.encode(arr[i])] = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds the elements which are in {@code set1} but not in {@code set2} to this
|
||||
* set.
|
||||
* @param {!goog.structs.StringSet} set1 First set.
|
||||
* @param {!goog.structs.StringSet} set2 Second set.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.StringSet.prototype.addDifference_ = function(set1, set2) {
|
||||
for (var key in set1.elements_) {
|
||||
if (!(key in set2.elements_)) {
|
||||
this.elements_[key] = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a the elements of a set to this set.
|
||||
* @param {!goog.structs.StringSet} stringSet The set to add the elements of.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.addSet = function(stringSet) {
|
||||
for (var key in stringSet.elements_) {
|
||||
this.elements_[key] = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all elements of the set.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.clear = function() {
|
||||
this.elements_ = {};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.structs.StringSet} Clone of the set.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.clone = function() {
|
||||
var ret = new goog.structs.StringSet;
|
||||
ret.addSet(this);
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tells if the set contains the given element.
|
||||
* @param {*} element The element to check.
|
||||
* @return {boolean} Whether it is in the set.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.contains = function(element) {
|
||||
return this.encode(element) in this.elements_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tells if the set contains all elements of the array.
|
||||
* @param {!Array} arr The elements to check.
|
||||
* @return {boolean} Whether they are in the set.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.containsArray = function(arr) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (!(this.encode(arr[i]) in this.elements_)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tells if this set has the same elements as the given set.
|
||||
* @param {!goog.structs.StringSet} stringSet The other set.
|
||||
* @return {boolean} Whether they have the same elements.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.equals = function(stringSet) {
|
||||
return this.isSubsetOf(stringSet) && stringSet.isSubsetOf(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function for each element in the set.
|
||||
* @param {function(string, undefined, !goog.structs.StringSet)} f The function
|
||||
* to call for every element. It takes the element, undefined (because sets
|
||||
* have no notion of keys), and the set.
|
||||
* @param {Object=} opt_obj The object to be used as the value of 'this'
|
||||
* within {@code f}.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.forEach = function(f, opt_obj) {
|
||||
for (var key in this.elements_) {
|
||||
f.call(opt_obj, this.decode(key), undefined, this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Counts the number of elements in the set in linear time.
|
||||
* NOTE: getCount is always called at most once per set instance in google3.
|
||||
* If this usage pattern won't change, the linear getCount implementation is
|
||||
* better, because
|
||||
* <li>populating a set and getting the number of elements in it takes the same
|
||||
* amount of time as keeping a count_ member up to date and getting its value;
|
||||
* <li>if getCount is not called, adding and removing elements have no overhead.
|
||||
* @return {number} The number of elements in the set.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.getCount = Object.keys ?
|
||||
function() {
|
||||
return Object.keys(this.elements_).length;
|
||||
} :
|
||||
function() {
|
||||
var count = 0;
|
||||
for (var key in this.elements_) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the difference of two sets.
|
||||
* @param {!goog.structs.StringSet} stringSet The set to subtract from this set.
|
||||
* @return {!goog.structs.StringSet} {@code this} minus {@code stringSet}.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.getDifference = function(stringSet) {
|
||||
var ret = new goog.structs.StringSet;
|
||||
ret.addDifference_(this, stringSet);
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the intersection of this set with another set.
|
||||
* @param {!goog.structs.StringSet} stringSet The set to take the intersection
|
||||
* with.
|
||||
* @return {!goog.structs.StringSet} A new set with the common elements.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.getIntersection = function(stringSet) {
|
||||
var ret = new goog.structs.StringSet;
|
||||
for (var key in this.elements_) {
|
||||
if (key in stringSet.elements_) {
|
||||
ret.elements_[key] = null;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the symmetric difference of two sets.
|
||||
* @param {!goog.structs.StringSet} stringSet The other set.
|
||||
* @return {!goog.structs.StringSet} A new set with the elements in exactly one
|
||||
* of {@code this} and {@code stringSet}.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.getSymmetricDifference = function(stringSet) {
|
||||
var ret = new goog.structs.StringSet;
|
||||
ret.addDifference_(this, stringSet);
|
||||
ret.addDifference_(stringSet, this);
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the union of this set and another set.
|
||||
* @param {!goog.structs.StringSet} stringSet The set to take the union with.
|
||||
* @return {!goog.structs.StringSet} A new set with the union of elements.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.getUnion = function(stringSet) {
|
||||
var ret = this.clone();
|
||||
ret.addSet(stringSet);
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!Array.<string>} The elements of the set.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.getValues = Object.keys ?
|
||||
function() {
|
||||
// Object.keys was introduced in JavaScript 1.8.5, Array#map in 1.6.
|
||||
return Object.keys(this.elements_).map(this.decode, this);
|
||||
} :
|
||||
function() {
|
||||
var ret = [];
|
||||
for (var key in this.elements_) {
|
||||
ret.push(this.decode(key));
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tells if this set and the given set are disjoint.
|
||||
* @param {!goog.structs.StringSet} stringSet The other set.
|
||||
* @return {boolean} True iff they don't have common elements.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.isDisjoint = function(stringSet) {
|
||||
for (var key in this.elements_) {
|
||||
if (key in stringSet.elements_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the set is empty.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.isEmpty = function() {
|
||||
for (var key in this.elements_) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tells if this set is the subset of the given set.
|
||||
* @param {!goog.structs.StringSet} stringSet The other set.
|
||||
* @return {boolean} Whether this set if the subset of that.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.isSubsetOf = function(stringSet) {
|
||||
for (var key in this.elements_) {
|
||||
if (!(key in stringSet.elements_)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tells if this set is the superset of the given set.
|
||||
* @param {!goog.structs.StringSet} stringSet The other set.
|
||||
* @return {boolean} Whether this set if the superset of that.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.isSupersetOf = function(stringSet) {
|
||||
return stringSet.isSubsetOf(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a single element from the set.
|
||||
* @param {*} element The element to remove.
|
||||
* @return {boolean} Whether the element was in the set.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.remove = function(element) {
|
||||
var key = this.encode(element);
|
||||
if (key in this.elements_) {
|
||||
delete this.elements_[key];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all elements of the given array from this set.
|
||||
* @param {!Array} arr The elements to remove.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.removeArray = function(arr) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
delete this.elements_[this.encode(arr[i])];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all elements of the given set from this set.
|
||||
* @param {!goog.structs.StringSet} stringSet The set of elements to remove.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.removeSet = function(stringSet) {
|
||||
for (var key in stringSet.elements_) {
|
||||
delete this.elements_[key];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator that iterates over the elements in the set.
|
||||
* NOTE: creating the iterator copies the whole set so use {@link #forEach} when
|
||||
* possible.
|
||||
* @param {boolean=} opt_keys Ignored for sets.
|
||||
* @return {!goog.iter.Iterator} An iterator over the elements in the set.
|
||||
*/
|
||||
goog.structs.StringSet.prototype.__iterator__ = function(opt_keys) {
|
||||
return goog.iter.toIterator(this.getValues());
|
||||
};
|
||||
351
nicer-api-docs/closure-library/closure/goog/structs/structs.js
Normal file
351
nicer-api-docs/closure-library/closure/goog/structs/structs.js
Normal file
@@ -0,0 +1,351 @@
|
||||
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Generics method for collection-like classes and objects.
|
||||
*
|
||||
* @author arv@google.com (Erik Arvidsson)
|
||||
*
|
||||
* This file contains functions to work with collections. It supports using
|
||||
* Map, Set, Array and Object and other classes that implement collection-like
|
||||
* methods.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.object');
|
||||
|
||||
|
||||
// We treat an object as a dictionary if it has getKeys or it is an object that
|
||||
// isn't arrayLike.
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of values in the collection-like object.
|
||||
* @param {Object} col The collection-like object.
|
||||
* @return {number} The number of values in the collection-like object.
|
||||
*/
|
||||
goog.structs.getCount = function(col) {
|
||||
if (typeof col.getCount == 'function') {
|
||||
return col.getCount();
|
||||
}
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
return col.length;
|
||||
}
|
||||
return goog.object.getCount(col);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the values of the collection-like object.
|
||||
* @param {Object} col The collection-like object.
|
||||
* @return {!Array} The values in the collection-like object.
|
||||
*/
|
||||
goog.structs.getValues = function(col) {
|
||||
if (typeof col.getValues == 'function') {
|
||||
return col.getValues();
|
||||
}
|
||||
if (goog.isString(col)) {
|
||||
return col.split('');
|
||||
}
|
||||
if (goog.isArrayLike(col)) {
|
||||
var rv = [];
|
||||
var l = col.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
rv.push(col[i]);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
return goog.object.getValues(col);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the keys of the collection. Some collections have no notion of
|
||||
* keys/indexes and this function will return undefined in those cases.
|
||||
* @param {Object} col The collection-like object.
|
||||
* @return {!Array|undefined} The keys in the collection.
|
||||
*/
|
||||
goog.structs.getKeys = function(col) {
|
||||
if (typeof col.getKeys == 'function') {
|
||||
return col.getKeys();
|
||||
}
|
||||
// if we have getValues but no getKeys we know this is a key-less collection
|
||||
if (typeof col.getValues == 'function') {
|
||||
return undefined;
|
||||
}
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
var rv = [];
|
||||
var l = col.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
rv.push(i);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
return goog.object.getKeys(col);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the collection contains the given value. This is O(n) and uses
|
||||
* equals (==) to test the existence.
|
||||
* @param {Object} col The collection-like object.
|
||||
* @param {*} val The value to check for.
|
||||
* @return {boolean} True if the map contains the value.
|
||||
*/
|
||||
goog.structs.contains = function(col, val) {
|
||||
if (typeof col.contains == 'function') {
|
||||
return col.contains(val);
|
||||
}
|
||||
if (typeof col.containsValue == 'function') {
|
||||
return col.containsValue(val);
|
||||
}
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
return goog.array.contains(/** @type {Array} */ (col), val);
|
||||
}
|
||||
return goog.object.containsValue(col, val);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the collection is empty.
|
||||
* @param {Object} col The collection-like object.
|
||||
* @return {boolean} True if empty.
|
||||
*/
|
||||
goog.structs.isEmpty = function(col) {
|
||||
if (typeof col.isEmpty == 'function') {
|
||||
return col.isEmpty();
|
||||
}
|
||||
|
||||
// We do not use goog.string.isEmpty because here we treat the string as
|
||||
// collection and as such even whitespace matters
|
||||
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
return goog.array.isEmpty(/** @type {Array} */ (col));
|
||||
}
|
||||
return goog.object.isEmpty(col);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all the elements from the collection.
|
||||
* @param {Object} col The collection-like object.
|
||||
*/
|
||||
goog.structs.clear = function(col) {
|
||||
// NOTE(arv): This should not contain strings because strings are immutable
|
||||
if (typeof col.clear == 'function') {
|
||||
col.clear();
|
||||
} else if (goog.isArrayLike(col)) {
|
||||
goog.array.clear(/** @type {goog.array.ArrayLike} */ (col));
|
||||
} else {
|
||||
goog.object.clear(col);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function for each value in a collection. The function takes
|
||||
* three arguments; the value, the key and the collection.
|
||||
*
|
||||
* @param {S} col The collection-like object.
|
||||
* @param {function(this:T,?,?,S):?} f The function to call for every value.
|
||||
* This function takes
|
||||
* 3 arguments (the value, the key or undefined if the collection has no
|
||||
* notion of keys, and the collection) and the return value is irrelevant.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this'
|
||||
* within {@code f}.
|
||||
* @template T,S
|
||||
*/
|
||||
goog.structs.forEach = function(col, f, opt_obj) {
|
||||
if (typeof col.forEach == 'function') {
|
||||
col.forEach(f, opt_obj);
|
||||
} else if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
goog.array.forEach(/** @type {Array} */ (col), f, opt_obj);
|
||||
} else {
|
||||
var keys = goog.structs.getKeys(col);
|
||||
var values = goog.structs.getValues(col);
|
||||
var l = values.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
f.call(opt_obj, values[i], keys && keys[i], col);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function for every value in the collection. When a call returns true,
|
||||
* adds the value to a new collection (Array is returned by default).
|
||||
*
|
||||
* @param {S} col The collection-like object.
|
||||
* @param {function(this:T,?,?,S):boolean} f The function to call for every
|
||||
* value. This function takes
|
||||
* 3 arguments (the value, the key or undefined if the collection has no
|
||||
* notion of keys, and the collection) and should return a Boolean. If the
|
||||
* return value is true the value is added to the result collection. If it
|
||||
* is false the value is not included.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this'
|
||||
* within {@code f}.
|
||||
* @return {!Object|!Array} A new collection where the passed values are
|
||||
* present. If col is a key-less collection an array is returned. If col
|
||||
* has keys and values a plain old JS object is returned.
|
||||
* @template T,S
|
||||
*/
|
||||
goog.structs.filter = function(col, f, opt_obj) {
|
||||
if (typeof col.filter == 'function') {
|
||||
return col.filter(f, opt_obj);
|
||||
}
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
return goog.array.filter(/** @type {!Array} */ (col), f, opt_obj);
|
||||
}
|
||||
|
||||
var rv;
|
||||
var keys = goog.structs.getKeys(col);
|
||||
var values = goog.structs.getValues(col);
|
||||
var l = values.length;
|
||||
if (keys) {
|
||||
rv = {};
|
||||
for (var i = 0; i < l; i++) {
|
||||
if (f.call(opt_obj, values[i], keys[i], col)) {
|
||||
rv[keys[i]] = values[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We should not use goog.array.filter here since we want to make sure that
|
||||
// the index is undefined as well as make sure that col is passed to the
|
||||
// function.
|
||||
rv = [];
|
||||
for (var i = 0; i < l; i++) {
|
||||
if (f.call(opt_obj, values[i], undefined, col)) {
|
||||
rv.push(values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function for every value in the collection and adds the result into a
|
||||
* new collection (defaults to creating a new Array).
|
||||
*
|
||||
* @param {S} col The collection-like object.
|
||||
* @param {function(this:T,?,?,S):V} f The function to call for every value.
|
||||
* This function takes 3 arguments (the value, the key or undefined if the
|
||||
* collection has no notion of keys, and the collection) and should return
|
||||
* something. The result will be used as the value in the new collection.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this'
|
||||
* within {@code f}.
|
||||
* @return {!Object.<V>|!Array.<V>} A new collection with the new values. If
|
||||
* col is a key-less collection an array is returned. If col has keys and
|
||||
* values a plain old JS object is returned.
|
||||
* @template T,S,V
|
||||
*/
|
||||
goog.structs.map = function(col, f, opt_obj) {
|
||||
if (typeof col.map == 'function') {
|
||||
return col.map(f, opt_obj);
|
||||
}
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
return goog.array.map(/** @type {!Array} */ (col), f, opt_obj);
|
||||
}
|
||||
|
||||
var rv;
|
||||
var keys = goog.structs.getKeys(col);
|
||||
var values = goog.structs.getValues(col);
|
||||
var l = values.length;
|
||||
if (keys) {
|
||||
rv = {};
|
||||
for (var i = 0; i < l; i++) {
|
||||
rv[keys[i]] = f.call(opt_obj, values[i], keys[i], col);
|
||||
}
|
||||
} else {
|
||||
// We should not use goog.array.map here since we want to make sure that
|
||||
// the index is undefined as well as make sure that col is passed to the
|
||||
// function.
|
||||
rv = [];
|
||||
for (var i = 0; i < l; i++) {
|
||||
rv[i] = f.call(opt_obj, values[i], undefined, col);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls f for each value in a collection. If any call returns true this returns
|
||||
* true (without checking the rest). If all returns false this returns false.
|
||||
*
|
||||
* @param {S} col The collection-like object.
|
||||
* @param {function(this:T,?,?,S):boolean} f The function to call for every
|
||||
* value. This function takes 3 arguments (the value, the key or undefined
|
||||
* if the collection has no notion of keys, and the collection) and should
|
||||
* return a boolean.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this'
|
||||
* within {@code f}.
|
||||
* @return {boolean} True if any value passes the test.
|
||||
* @template T,S
|
||||
*/
|
||||
goog.structs.some = function(col, f, opt_obj) {
|
||||
if (typeof col.some == 'function') {
|
||||
return col.some(f, opt_obj);
|
||||
}
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
return goog.array.some(/** @type {!Array} */ (col), f, opt_obj);
|
||||
}
|
||||
var keys = goog.structs.getKeys(col);
|
||||
var values = goog.structs.getValues(col);
|
||||
var l = values.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
if (f.call(opt_obj, values[i], keys && keys[i], col)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls f for each value in a collection. If all calls return true this return
|
||||
* true this returns true. If any returns false this returns false at this point
|
||||
* and does not continue to check the remaining values.
|
||||
*
|
||||
* @param {S} col The collection-like object.
|
||||
* @param {function(this:T,?,?,S):boolean} f The function to call for every
|
||||
* value. This function takes 3 arguments (the value, the key or
|
||||
* undefined if the collection has no notion of keys, and the collection)
|
||||
* and should return a boolean.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this'
|
||||
* within {@code f}.
|
||||
* @return {boolean} True if all key-value pairs pass the test.
|
||||
* @template T,S
|
||||
*/
|
||||
goog.structs.every = function(col, f, opt_obj) {
|
||||
if (typeof col.every == 'function') {
|
||||
return col.every(f, opt_obj);
|
||||
}
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
return goog.array.every(/** @type {!Array} */ (col), f, opt_obj);
|
||||
}
|
||||
var keys = goog.structs.getKeys(col);
|
||||
var values = goog.structs.getValues(col);
|
||||
var l = values.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
if (!f.call(opt_obj, values[i], keys && keys[i], col)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
428
nicer-api-docs/closure-library/closure/goog/structs/treenode.js
Normal file
428
nicer-api-docs/closure-library/closure/goog/structs/treenode.js
Normal file
@@ -0,0 +1,428 @@
|
||||
// Copyright 2010 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Generic tree node data structure with arbitrary number of child
|
||||
* nodes.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.structs.TreeNode');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.structs.Node');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generic tree node data structure with arbitrary number of child nodes.
|
||||
* It is possible to create a dynamic tree structure by overriding
|
||||
* {@link #getParent} and {@link #getChildren} in a subclass. All other getters
|
||||
* will automatically work.
|
||||
*
|
||||
* @param {*} key Key.
|
||||
* @param {*} value Value.
|
||||
* @constructor
|
||||
* @extends {goog.structs.Node}
|
||||
*/
|
||||
goog.structs.TreeNode = function(key, value) {
|
||||
goog.structs.Node.call(this, key, value);
|
||||
};
|
||||
goog.inherits(goog.structs.TreeNode, goog.structs.Node);
|
||||
|
||||
|
||||
/**
|
||||
* Constant for empty array to avoid unnecessary allocations.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.TreeNode.EMPTY_ARRAY_ = [];
|
||||
|
||||
|
||||
/**
|
||||
* Reference to the parent node or null if it has no parent.
|
||||
* @type {goog.structs.TreeNode}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.parent_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Child nodes or null in case of leaf node.
|
||||
* @type {Array.<!goog.structs.TreeNode>}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.children_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.structs.TreeNode} Clone of the tree node without its parent
|
||||
* and child nodes. The key and the value are copied by reference.
|
||||
* @override
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.clone = function() {
|
||||
return new goog.structs.TreeNode(this.getKey(), this.getValue());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.structs.TreeNode} Clone of the subtree with this node as root.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.deepClone = function() {
|
||||
var clone = this.clone();
|
||||
this.forEachChild(function(child) {
|
||||
clone.addChild(child.deepClone());
|
||||
});
|
||||
return clone;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {goog.structs.TreeNode} Parent node or null if it has no parent.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.getParent = function() {
|
||||
return this.parent_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the node is a leaf node.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.isLeaf = function() {
|
||||
return !this.getChildCount();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tells if the node is the last child of its parent. This method helps how to
|
||||
* connect the tree nodes with lines: L shapes should be used before the last
|
||||
* children and |- shapes before the rest. Schematic tree visualization:
|
||||
*
|
||||
* <pre>
|
||||
* Node1
|
||||
* |-Node2
|
||||
* | L-Node3
|
||||
* | |-Node4
|
||||
* | L-Node5
|
||||
* L-Node6
|
||||
* </pre>
|
||||
*
|
||||
* @return {boolean} Whether the node has parent and is the last child of it.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.isLastChild = function() {
|
||||
var parent = this.getParent();
|
||||
return Boolean(parent && this == goog.array.peek(parent.getChildren()));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!Array.<!goog.structs.TreeNode>} Immutable child nodes.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.getChildren = function() {
|
||||
return this.children_ || goog.structs.TreeNode.EMPTY_ARRAY_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the child node of this node at the given index.
|
||||
* @param {number} index Child index.
|
||||
* @return {goog.structs.TreeNode} The node at the given index or null if not
|
||||
* found.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.getChildAt = function(index) {
|
||||
return this.getChildren()[index] || null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The number of children.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.getChildCount = function() {
|
||||
return this.getChildren().length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The number of ancestors of the node.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.getDepth = function() {
|
||||
var depth = 0;
|
||||
var node = this;
|
||||
while (node.getParent()) {
|
||||
depth++;
|
||||
node = node.getParent();
|
||||
}
|
||||
return depth;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!Array.<!goog.structs.TreeNode>} All ancestor nodes in bottom-up
|
||||
* order.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.getAncestors = function() {
|
||||
var ancestors = [];
|
||||
var node = this.getParent();
|
||||
while (node) {
|
||||
ancestors.push(node);
|
||||
node = node.getParent();
|
||||
}
|
||||
return ancestors;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.structs.TreeNode} The root of the tree structure, i.e. the
|
||||
* farthest ancestor of the node or the node itself if it has no parents.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.getRoot = function() {
|
||||
var root = this;
|
||||
while (root.getParent()) {
|
||||
root = root.getParent();
|
||||
}
|
||||
return root;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Builds a nested array structure from the node keys in this node's subtree to
|
||||
* facilitate testing tree operations that change the hierarchy.
|
||||
* @return {!Array} The structure of this node's descendants as nested array
|
||||
* of node keys. The number of unclosed opening brackets up to a particular
|
||||
* node is proportional to the indentation of that node in the graphical
|
||||
* representation of the tree. Example:
|
||||
* <pre>
|
||||
* this
|
||||
* |- child1
|
||||
* | L- grandchild
|
||||
* L- child2
|
||||
* </pre>
|
||||
* is represented as ['child1', ['grandchild'], 'child2'].
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.getSubtreeKeys = function() {
|
||||
var ret = [];
|
||||
this.forEachChild(function(child) {
|
||||
ret.push(child.getKey());
|
||||
if (!child.isLeaf()) {
|
||||
ret.push(child.getSubtreeKeys());
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tells whether this node is the ancestor of the given node.
|
||||
* @param {!goog.structs.TreeNode} node A node.
|
||||
* @return {boolean} Whether this node is the ancestor of {@code node}.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.contains = function(node) {
|
||||
var current = node;
|
||||
do {
|
||||
current = current.getParent();
|
||||
} while (current && current != this);
|
||||
return Boolean(current);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Finds the deepest common ancestor of the given nodes. The concept of
|
||||
* ancestor is not strict in this case, it includes the node itself.
|
||||
* @param {...!goog.structs.TreeNode} var_args The nodes.
|
||||
* @return {goog.structs.TreeNode} The common ancestor of the nodes or null if
|
||||
* they are from different trees.
|
||||
*/
|
||||
goog.structs.TreeNode.findCommonAncestor = function(var_args) {
|
||||
var ret = arguments[0];
|
||||
if (!ret) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var retDepth = ret.getDepth();
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
var node = arguments[i];
|
||||
var depth = node.getDepth();
|
||||
while (node != ret) {
|
||||
if (depth <= retDepth) {
|
||||
ret = ret.getParent();
|
||||
retDepth--;
|
||||
}
|
||||
if (depth > retDepth) {
|
||||
node = node.getParent();
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Traverses all child nodes.
|
||||
* @param {function(!goog.structs.TreeNode, number,
|
||||
* !Array.<!goog.structs.TreeNode>)} f Callback function. It takes the
|
||||
* node, its index and the array of all child nodes as arguments.
|
||||
* @param {Object=} opt_this The object to be used as the value of {@code this}
|
||||
* within {@code f}.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.forEachChild = function(f, opt_this) {
|
||||
goog.array.forEach(this.getChildren(), f, opt_this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Traverses all child nodes recursively in preorder.
|
||||
* @param {function(!goog.structs.TreeNode)} f Callback function. It takes the
|
||||
* node as argument.
|
||||
* @param {Object=} opt_this The object to be used as the value of {@code this}
|
||||
* within {@code f}.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.forEachDescendant = function(f, opt_this) {
|
||||
goog.array.forEach(this.getChildren(), function(child) {
|
||||
f.call(opt_this, child);
|
||||
child.forEachDescendant(f, opt_this);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Traverses the subtree with the possibility to skip branches. Starts with
|
||||
* this node, and visits the descendant nodes depth-first, in preorder.
|
||||
* @param {function(!goog.structs.TreeNode): (boolean|undefined)} f Callback
|
||||
* function. It takes the node as argument. The children of this node will
|
||||
* be visited if the callback returns true or undefined, and will be
|
||||
* skipped if the callback returns false.
|
||||
* @param {Object=} opt_this The object to be used as the value of {@code this}
|
||||
* within {@code f}.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.traverse = function(f, opt_this) {
|
||||
if (f.call(opt_this, this) !== false) {
|
||||
goog.array.forEach(this.getChildren(), function(child) {
|
||||
child.traverse(f, opt_this);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the parent node of this node. The callers must ensure that the parent
|
||||
* node and only that has this node among its children.
|
||||
* @param {goog.structs.TreeNode} parent The parent to set. If null, the node
|
||||
* will be detached from the tree.
|
||||
* @protected
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.setParent = function(parent) {
|
||||
this.parent_ = parent;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Appends a child node to this node.
|
||||
* @param {!goog.structs.TreeNode} child Orphan child node.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.addChild = function(child) {
|
||||
this.addChildAt(child, this.children_ ? this.children_.length : 0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Inserts a child node at the given index.
|
||||
* @param {!goog.structs.TreeNode} child Orphan child node.
|
||||
* @param {number} index The position to insert at.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.addChildAt = function(child, index) {
|
||||
goog.asserts.assert(!child.getParent());
|
||||
child.setParent(this);
|
||||
this.children_ = this.children_ || [];
|
||||
goog.asserts.assert(index >= 0 && index <= this.children_.length);
|
||||
goog.array.insertAt(this.children_, child, index);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Replaces a child node at the given index.
|
||||
* @param {!goog.structs.TreeNode} newChild Child node to set. It must not have
|
||||
* parent node.
|
||||
* @param {number} index Valid index of the old child to replace.
|
||||
* @return {!goog.structs.TreeNode} The original child node, detached from its
|
||||
* parent.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.replaceChildAt = function(newChild, index) {
|
||||
goog.asserts.assert(!newChild.getParent(),
|
||||
'newChild must not have parent node');
|
||||
var children = this.getChildren();
|
||||
var oldChild = children[index];
|
||||
goog.asserts.assert(oldChild, 'Invalid child or child index is given.');
|
||||
oldChild.setParent(null);
|
||||
children[index] = newChild;
|
||||
newChild.setParent(this);
|
||||
return oldChild;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Replaces the given child node.
|
||||
* @param {!goog.structs.TreeNode} newChild New node to replace
|
||||
* {@code oldChild}. It must not have parent node.
|
||||
* @param {!goog.structs.TreeNode} oldChild Existing child node to be replaced.
|
||||
* @return {!goog.structs.TreeNode} The replaced child node detached from its
|
||||
* parent.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.replaceChild = function(newChild, oldChild) {
|
||||
return this.replaceChildAt(newChild,
|
||||
goog.array.indexOf(this.getChildren(), oldChild));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the child node at the given index.
|
||||
* @param {number} index The position to remove from.
|
||||
* @return {goog.structs.TreeNode} The removed node if any.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.removeChildAt = function(index) {
|
||||
var child = this.children_ && this.children_[index];
|
||||
if (child) {
|
||||
child.setParent(null);
|
||||
goog.array.removeAt(this.children_, index);
|
||||
if (this.children_.length == 0) {
|
||||
delete this.children_;
|
||||
}
|
||||
return child;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the given child node of this node.
|
||||
* @param {goog.structs.TreeNode} child The node to remove.
|
||||
* @return {goog.structs.TreeNode} The removed node if any.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.removeChild = function(child) {
|
||||
return this.removeChildAt(goog.array.indexOf(this.getChildren(), child));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all child nodes of this node.
|
||||
*/
|
||||
goog.structs.TreeNode.prototype.removeChildren = function() {
|
||||
if (this.children_) {
|
||||
goog.array.forEach(this.children_, function(child) {
|
||||
child.setParent(null);
|
||||
});
|
||||
}
|
||||
delete this.children_;
|
||||
};
|
||||
368
nicer-api-docs/closure-library/closure/goog/structs/trie.js
Normal file
368
nicer-api-docs/closure-library/closure/goog/structs/trie.js
Normal file
@@ -0,0 +1,368 @@
|
||||
// Copyright 2007 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: Trie.
|
||||
*
|
||||
*
|
||||
* This file provides the implementation of a trie data structure. A trie is a
|
||||
* data structure that stores key/value pairs in a prefix tree. See:
|
||||
* http://en.wikipedia.org/wiki/Trie
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs.Trie');
|
||||
|
||||
goog.require('goog.object');
|
||||
goog.require('goog.structs');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for a Trie datastructure. Trie data structures are made out of trees
|
||||
* of Trie classes.
|
||||
*
|
||||
* @param {Object=} opt_trie Optional goog.structs.Trie or Object to initialize
|
||||
* trie with.
|
||||
* @constructor
|
||||
*/
|
||||
goog.structs.Trie = function(opt_trie) {
|
||||
/**
|
||||
* This trie's child nodes.
|
||||
* @private
|
||||
* @type {Object.<goog.structs.Trie>}
|
||||
*/
|
||||
this.childNodes_ = {};
|
||||
|
||||
if (opt_trie) {
|
||||
this.setAll(opt_trie);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This trie's value. For the base trie, this will be the value of the
|
||||
* empty key, if defined.
|
||||
* @private
|
||||
* @type {*}
|
||||
*/
|
||||
goog.structs.Trie.prototype.value_ = undefined;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the given key/value pair in the trie. O(L), where L is the length
|
||||
* of the key.
|
||||
* @param {string} key The key.
|
||||
* @param {*} value The value.
|
||||
*/
|
||||
goog.structs.Trie.prototype.set = function(key, value) {
|
||||
this.setOrAdd_(key, value, false);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds the given key/value pair in the trie. Throw an exception if the key
|
||||
* already exists in the trie. O(L), where L is the length of the key.
|
||||
* @param {string} key The key.
|
||||
* @param {*} value The value.
|
||||
*/
|
||||
goog.structs.Trie.prototype.add = function(key, value) {
|
||||
this.setOrAdd_(key, value, true);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for set and add. Adds the given key/value pair to
|
||||
* the trie, or, if the key already exists, sets the value of the key. If
|
||||
* opt_add is true, then throws an exception if the key already has a value in
|
||||
* the trie. O(L), where L is the length of the key.
|
||||
* @param {string} key The key.
|
||||
* @param {*} value The value.
|
||||
* @param {boolean=} opt_add Throw exception if key is already in the trie.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Trie.prototype.setOrAdd_ = function(key, value, opt_add) {
|
||||
var node = this;
|
||||
for (var characterPosition = 0; characterPosition < key.length;
|
||||
characterPosition++) {
|
||||
var currentCharacter = key.charAt(characterPosition);
|
||||
if (!node.childNodes_[currentCharacter]) {
|
||||
node.childNodes_[currentCharacter] = new goog.structs.Trie();
|
||||
}
|
||||
node = node.childNodes_[currentCharacter];
|
||||
}
|
||||
if (opt_add && node.value_ !== undefined) {
|
||||
throw Error('The collection already contains the key "' + key + '"');
|
||||
} else {
|
||||
node.value_ = value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds multiple key/value pairs from another goog.structs.Trie or Object.
|
||||
* O(N) where N is the number of nodes in the trie.
|
||||
* @param {Object|goog.structs.Trie} trie Object containing the data to add.
|
||||
*/
|
||||
goog.structs.Trie.prototype.setAll = function(trie) {
|
||||
var keys = goog.structs.getKeys(trie);
|
||||
var values = goog.structs.getValues(trie);
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
this.set(keys[i], values[i]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves a value from the trie given a key. O(L), where L is the length of
|
||||
* the key.
|
||||
* @param {string} key The key to retrieve from the trie.
|
||||
* @return {*} The value of the key in the trie, or undefined if the trie does
|
||||
* not contain this key.
|
||||
*/
|
||||
goog.structs.Trie.prototype.get = function(key) {
|
||||
var node = this;
|
||||
for (var characterPosition = 0; characterPosition < key.length;
|
||||
characterPosition++) {
|
||||
var currentCharacter = key.charAt(characterPosition);
|
||||
if (!node.childNodes_[currentCharacter]) {
|
||||
return undefined;
|
||||
}
|
||||
node = node.childNodes_[currentCharacter];
|
||||
}
|
||||
return node.value_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves all values from the trie that correspond to prefixes of the given
|
||||
* input key. O(L), where L is the length of the key.
|
||||
*
|
||||
* @param {string} key The key to use for lookup. The given key as well as all
|
||||
* prefixes of the key are retrieved.
|
||||
* @param {?number=} opt_keyStartIndex Optional position in key to start lookup
|
||||
* from. Defaults to 0 if not specified.
|
||||
* @return {Object} Map of end index of matching prefixes and corresponding
|
||||
* values. Empty if no match found.
|
||||
*/
|
||||
goog.structs.Trie.prototype.getKeyAndPrefixes = function(key,
|
||||
opt_keyStartIndex) {
|
||||
var node = this;
|
||||
var matches = {};
|
||||
var characterPosition = opt_keyStartIndex || 0;
|
||||
|
||||
if (node.value_ !== undefined) {
|
||||
matches[characterPosition] = node.value_;
|
||||
}
|
||||
|
||||
for (; characterPosition < key.length; characterPosition++) {
|
||||
var currentCharacter = key.charAt(characterPosition);
|
||||
if (!(currentCharacter in node.childNodes_)) {
|
||||
break;
|
||||
}
|
||||
node = node.childNodes_[currentCharacter];
|
||||
if (node.value_ !== undefined) {
|
||||
matches[characterPosition] = node.value_;
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the values of the trie. Not returned in any reliable order. O(N) where
|
||||
* N is the number of nodes in the trie. Calls getValuesInternal_.
|
||||
* @return {Array} The values in the trie.
|
||||
*/
|
||||
goog.structs.Trie.prototype.getValues = function() {
|
||||
var allValues = [];
|
||||
this.getValuesInternal_(allValues);
|
||||
return allValues;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the values of the trie. Not returned in any reliable order. O(N) where
|
||||
* N is the number of nodes in the trie. Builds the values as it goes.
|
||||
* @param {Array.<string>} allValues Array to place values into.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Trie.prototype.getValuesInternal_ = function(allValues) {
|
||||
if (this.value_ !== undefined) {
|
||||
allValues.push(this.value_);
|
||||
}
|
||||
for (var childNode in this.childNodes_) {
|
||||
this.childNodes_[childNode].getValuesInternal_(allValues);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the keys of the trie. Not returned in any reliable order. O(N) where
|
||||
* N is the number of nodes in the trie (or prefix subtree).
|
||||
* @param {string=} opt_prefix Find only keys with this optional prefix.
|
||||
* @return {Array} The keys in the trie.
|
||||
*/
|
||||
goog.structs.Trie.prototype.getKeys = function(opt_prefix) {
|
||||
var allKeys = [];
|
||||
if (opt_prefix) {
|
||||
// Traverse to the given prefix, then call getKeysInternal_ to dump the
|
||||
// keys below that point.
|
||||
var node = this;
|
||||
for (var characterPosition = 0; characterPosition < opt_prefix.length;
|
||||
characterPosition++) {
|
||||
var currentCharacter = opt_prefix.charAt(characterPosition);
|
||||
if (!node.childNodes_[currentCharacter]) {
|
||||
return [];
|
||||
}
|
||||
node = node.childNodes_[currentCharacter];
|
||||
}
|
||||
node.getKeysInternal_(opt_prefix, allKeys);
|
||||
} else {
|
||||
this.getKeysInternal_('', allKeys);
|
||||
}
|
||||
return allKeys;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Private method to get keys from the trie. Builds the keys as it goes.
|
||||
* @param {string} keySoFar The partial key (prefix) traversed so far.
|
||||
* @param {Array} allKeys The partially built array of keys seen so far.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Trie.prototype.getKeysInternal_ = function(keySoFar, allKeys) {
|
||||
if (this.value_ !== undefined) {
|
||||
allKeys.push(keySoFar);
|
||||
}
|
||||
for (var childNode in this.childNodes_) {
|
||||
this.childNodes_[childNode].getKeysInternal_(keySoFar + childNode, allKeys);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks to see if a certain key is in the trie. O(L), where L is the length
|
||||
* of the key.
|
||||
* @param {string} key A key that may be in the trie.
|
||||
* @return {boolean} Whether the trie contains key.
|
||||
*/
|
||||
goog.structs.Trie.prototype.containsKey = function(key) {
|
||||
return this.get(key) !== undefined;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks to see if a certain value is in the trie. Worst case is O(N) where
|
||||
* N is the number of nodes in the trie.
|
||||
* @param {*} value A value that may be in the trie.
|
||||
* @return {boolean} Whether the trie contains the value.
|
||||
*/
|
||||
goog.structs.Trie.prototype.containsValue = function(value) {
|
||||
if (this.value_ === value) {
|
||||
return true;
|
||||
}
|
||||
for (var childNode in this.childNodes_) {
|
||||
if (this.childNodes_[childNode].containsValue(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Completely empties a trie of all keys and values. ~O(1)
|
||||
*/
|
||||
goog.structs.Trie.prototype.clear = function() {
|
||||
this.childNodes_ = {};
|
||||
this.value_ = undefined;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a key from the trie or throws an exception if the key is not in the
|
||||
* trie. O(L), where L is the length of the key.
|
||||
* @param {string} key A key that should be removed from the trie.
|
||||
* @return {*} The value whose key was removed.
|
||||
*/
|
||||
goog.structs.Trie.prototype.remove = function(key) {
|
||||
var node = this;
|
||||
var parents = [];
|
||||
for (var characterPosition = 0; characterPosition < key.length;
|
||||
characterPosition++) {
|
||||
var currentCharacter = key.charAt(characterPosition);
|
||||
if (!node.childNodes_[currentCharacter]) {
|
||||
throw Error('The collection does not have the key "' + key + '"');
|
||||
}
|
||||
|
||||
// Archive the current parent and child name (key in childNodes_) so that
|
||||
// we may remove the following node and its parents if they are empty.
|
||||
parents.push([node, currentCharacter]);
|
||||
|
||||
node = node.childNodes_[currentCharacter];
|
||||
}
|
||||
var oldValue = node.value_;
|
||||
delete node.value_;
|
||||
|
||||
while (parents.length > 0) {
|
||||
var currentParentAndCharacter = parents.pop();
|
||||
var currentParent = currentParentAndCharacter[0];
|
||||
var currentCharacter = currentParentAndCharacter[1];
|
||||
if (goog.object.isEmpty(
|
||||
currentParent.childNodes_[currentCharacter].childNodes_)) {
|
||||
// If we have no child nodes, then remove this node.
|
||||
delete currentParent.childNodes_[currentCharacter];
|
||||
} else {
|
||||
// No point of traversing back any further, since we can't remove this
|
||||
// path.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return oldValue;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clones a trie and returns a new trie. O(N), where N is the number of nodes
|
||||
* in the trie.
|
||||
* @return {goog.structs.Trie} A new goog.structs.Trie with the same key value
|
||||
* pairs.
|
||||
*/
|
||||
goog.structs.Trie.prototype.clone = function() {
|
||||
return new goog.structs.Trie(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of key value pairs in the trie. O(N), where N is the
|
||||
* number of nodes in the trie.
|
||||
* TODO: This could be optimized by storing a weight (count below) in every
|
||||
* node.
|
||||
* @return {number} The number of pairs.
|
||||
*/
|
||||
goog.structs.Trie.prototype.getCount = function() {
|
||||
return goog.structs.getCount(this.getValues());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if this trie contains no elements. ~O(1).
|
||||
* @return {boolean} True iff this trie contains no elements.
|
||||
*/
|
||||
goog.structs.Trie.prototype.isEmpty = function() {
|
||||
return this.value_ === undefined && goog.structs.isEmpty(this.childNodes_);
|
||||
};
|
||||
Reference in New Issue
Block a user