initial commit
This commit is contained in:
Executable
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Defines the collection interface.
|
||||
*/
|
||||
|
||||
goog.provide('goog.structs.Collection');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An interface for a collection of values.
|
||||
* @interface
|
||||
* @template T
|
||||
*/
|
||||
goog.structs.Collection = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @param {T} value Value to add to the collection.
|
||||
*/
|
||||
goog.structs.Collection.prototype.add;
|
||||
|
||||
|
||||
/**
|
||||
* @param {T} value Value to remove from the collection.
|
||||
*/
|
||||
goog.structs.Collection.prototype.remove;
|
||||
|
||||
|
||||
/**
|
||||
* @param {T} value Value to find in the collection.
|
||||
* @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;
|
||||
Executable
+348
@@ -0,0 +1,348 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @template K, V
|
||||
*/
|
||||
goog.structs.Heap = function(opt_heap) {
|
||||
'use strict';
|
||||
/**
|
||||
* 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 {K} key The key.
|
||||
* @param {V} value The value.
|
||||
*/
|
||||
goog.structs.Heap.prototype.insert = function(key, value) {
|
||||
'use strict';
|
||||
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) {
|
||||
'use strict';
|
||||
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 rely on the fact
|
||||
// that the keys/values are in the correct order to put in the underlying
|
||||
// structure.
|
||||
if (this.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 {V} The value removed from the root of the heap. Returns
|
||||
* undefined if the heap is empty.
|
||||
*/
|
||||
goog.structs.Heap.prototype.remove = function() {
|
||||
'use strict';
|
||||
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 {V} The value at the root of the heap. Returns
|
||||
* undefined if the heap is empty.
|
||||
*/
|
||||
goog.structs.Heap.prototype.peek = function() {
|
||||
'use strict';
|
||||
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 {K} The key at the root of the heap. Returns undefined if the
|
||||
* heap is empty.
|
||||
*/
|
||||
goog.structs.Heap.prototype.peekKey = function() {
|
||||
'use strict';
|
||||
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) {
|
||||
'use strict';
|
||||
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) {
|
||||
'use strict';
|
||||
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) {
|
||||
'use strict';
|
||||
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) {
|
||||
'use strict';
|
||||
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) {
|
||||
'use strict';
|
||||
return (index - 1) >> 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the values of the heap.
|
||||
* @return {!Array<V>} The values in the heap.
|
||||
*/
|
||||
goog.structs.Heap.prototype.getValues = function() {
|
||||
'use strict';
|
||||
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<K>} The keys in the heap.
|
||||
*/
|
||||
goog.structs.Heap.prototype.getKeys = function() {
|
||||
'use strict';
|
||||
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 {V} val The value to check for.
|
||||
* @return {boolean} Whether the heap contains the value.
|
||||
*/
|
||||
goog.structs.Heap.prototype.containsValue = function(val) {
|
||||
'use strict';
|
||||
return goog.array.some(this.nodes_, function(node) {
|
||||
'use strict';
|
||||
return node.getValue() == val;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the heap contains the given key.
|
||||
* @param {K} key The key to check for.
|
||||
* @return {boolean} Whether the heap contains the key.
|
||||
*/
|
||||
goog.structs.Heap.prototype.containsKey = function(key) {
|
||||
'use strict';
|
||||
return goog.array.some(this.nodes_, function(node) {
|
||||
'use strict';
|
||||
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() {
|
||||
'use strict';
|
||||
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() {
|
||||
'use strict';
|
||||
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() {
|
||||
'use strict';
|
||||
return this.nodes_.length === 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all elements from the heap.
|
||||
*/
|
||||
goog.structs.Heap.prototype.clear = function() {
|
||||
'use strict';
|
||||
goog.array.clear(this.nodes_);
|
||||
};
|
||||
Executable
+560
@@ -0,0 +1,560 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: Hash Map.
|
||||
*
|
||||
*
|
||||
* 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 consider using the lighter-weight utilities in goog.object.
|
||||
* @deprecated goog.structs.Map is deprecated in favour of ES6 Maps.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs.Map');
|
||||
|
||||
goog.require('goog.collections.iters');
|
||||
goog.require('goog.iter.Iterator');
|
||||
goog.require('goog.iter.StopIteration');
|
||||
goog.require('goog.iter.es6');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @template K, V
|
||||
* @deprecated This type is misleading: use ES6 Map instead.
|
||||
*/
|
||||
goog.structs.Map = function(opt_map, var_args) {
|
||||
'use strict';
|
||||
/**
|
||||
* Underlying JS object used to implement the map.
|
||||
* @private {!Object}
|
||||
*/
|
||||
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).
|
||||
* @private {!Array<string>}
|
||||
*/
|
||||
this.keys_ = [];
|
||||
|
||||
/**
|
||||
* The number of key value pairs in the map.
|
||||
* @const {number}
|
||||
*/
|
||||
this.size = 0;
|
||||
|
||||
/**
|
||||
* Version used to detect changes while iterating.
|
||||
* @private {number}
|
||||
*/
|
||||
this.version_ = 0;
|
||||
|
||||
var argLength = arguments.length;
|
||||
|
||||
if (argLength > 1) {
|
||||
if (argLength % 2) {
|
||||
throw new 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));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The number of key-value pairs in the map.
|
||||
* @deprecated Use the `size` property instead, for alignment with ES6 Map.
|
||||
*/
|
||||
goog.structs.Map.prototype.getCount = function() {
|
||||
'use strict';
|
||||
return this.size;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the values of the map.
|
||||
* @return {!Array<V>} The values in the map.
|
||||
* @deprecated Use `Array.from(map.values())` instead, for alignment with ES6
|
||||
* Map.
|
||||
*/
|
||||
goog.structs.Map.prototype.getValues = function() {
|
||||
'use strict';
|
||||
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.
|
||||
* @deprecated Use `Array.from(map.keys())` instead, for alignment with ES6 Map.
|
||||
*/
|
||||
goog.structs.Map.prototype.getKeys = function() {
|
||||
'use strict';
|
||||
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.
|
||||
* @deprecated Use `has` instead, for alignment with ES6 Map.
|
||||
*/
|
||||
goog.structs.Map.prototype.containsKey = function(key) {
|
||||
'use strict';
|
||||
return this.has(key);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.has = function(key) {
|
||||
'use strict';
|
||||
return goog.structs.Map.hasKey_(this.map_, key);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the map contains the given value. This is O(n).
|
||||
* @param {V} val The value to check for.
|
||||
* @return {boolean} Whether the map contains the value.
|
||||
*/
|
||||
goog.structs.Map.prototype.containsValue = function(val) {
|
||||
'use strict';
|
||||
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(V, V): 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.
|
||||
* @deprecated Use goog.collections.maps.equals(thisMap, otherMap,
|
||||
* opt_equalityFn) instead, for alignment with ES6 Map.
|
||||
*/
|
||||
goog.structs.Map.prototype.equals = function(otherMap, opt_equalityFn) {
|
||||
'use strict';
|
||||
if (this === otherMap) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.size != 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) {
|
||||
'use strict';
|
||||
return a === b;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the map is empty.
|
||||
* @deprecated Use the size property and compare against 0, for alignment with
|
||||
* ES6 Map.
|
||||
*/
|
||||
goog.structs.Map.prototype.isEmpty = function() {
|
||||
'use strict';
|
||||
return this.size == 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all key-value pairs from the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.clear = function() {
|
||||
'use strict';
|
||||
this.map_ = {};
|
||||
this.keys_.length = 0;
|
||||
this.setSizeInternal_(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.
|
||||
* @deprecated Use `delete` instead, for alignment with ES6 Map.
|
||||
*/
|
||||
goog.structs.Map.prototype.remove = function(key) {
|
||||
return this.delete(key);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.delete = function(key) {
|
||||
'use strict';
|
||||
if (goog.structs.Map.hasKey_(this.map_, key)) {
|
||||
delete this.map_[key];
|
||||
this.setSizeInternal_(this.size - 1);
|
||||
this.version_++;
|
||||
|
||||
// clean up the keys array if the threshold is hit
|
||||
if (this.keys_.length > 2 * this.size) {
|
||||
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() {
|
||||
'use strict';
|
||||
if (this.size != 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.size != 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 `undefined`.
|
||||
* @param {*} key The key to get the value for.
|
||||
* @param {DEFAULT=} opt_val The value to return if no item is found for the
|
||||
* given key, defaults to undefined.
|
||||
* @return {V|DEFAULT} The value for the given key.
|
||||
* @template DEFAULT
|
||||
*/
|
||||
goog.structs.Map.prototype.get = function(key, opt_val) {
|
||||
'use strict';
|
||||
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 {V} value The value to add.
|
||||
*/
|
||||
goog.structs.Map.prototype.set = function(key, value) {
|
||||
'use strict';
|
||||
if (!(goog.structs.Map.hasKey_(this.map_, key))) {
|
||||
this.setSizeInternal_(this.size + 1);
|
||||
// TODO(johnlenz): This class lies, it claims to return an array of string
|
||||
// keys, but instead returns the original object used.
|
||||
this.keys_.push(/** @type {?} */ (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.
|
||||
* @deprecated Use goog.collections.maps.setAll(thisMap, map.entries()) if map
|
||||
* is an ES6 or goog.structs Map, or
|
||||
* goog.collections.maps.setAll(thisMap, Object.entries(map)) otherwise.
|
||||
*/
|
||||
goog.structs.Map.prototype.addAll = function(map) {
|
||||
'use strict';
|
||||
if (map instanceof goog.structs.Map) {
|
||||
var keys = map.getKeys();
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
this.set(keys[i], map.get(keys[i]));
|
||||
}
|
||||
} else {
|
||||
for (var key in map) {
|
||||
this.set(key, map[key]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls the given function on each entry in the map.
|
||||
* @param {function(this:T, V, K, goog.structs.Map<K,V>)} f
|
||||
* @param {T=} opt_obj The value of "this" inside f.
|
||||
* @template T
|
||||
* @deprecated Use ES6 Iteration instead.
|
||||
*/
|
||||
goog.structs.Map.prototype.forEach = function(f, opt_obj) {
|
||||
'use strict';
|
||||
var keys = this.getKeys();
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var key = keys[i];
|
||||
var value = this.get(key);
|
||||
f.call(opt_obj, value, key, this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clones a map and returns a new map.
|
||||
* @return {!goog.structs.Map} A new map with the same key-value pairs.
|
||||
* @deprecated Use `new Map(thisMap.entries())` instead, for alignment with
|
||||
* ES6 Map.
|
||||
*/
|
||||
goog.structs.Map.prototype.clone = function() {
|
||||
'use strict';
|
||||
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.
|
||||
* @deprecated Use goog.collections.maps.transpose instead, for alignment with
|
||||
* ES6 Maps.
|
||||
*/
|
||||
goog.structs.Map.prototype.transpose = function() {
|
||||
'use strict';
|
||||
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.
|
||||
* @deprecated Use goog.collections.maps.toObject(thisMap) instead, for aligment
|
||||
* with ES6 Maps.
|
||||
*/
|
||||
goog.structs.Map.prototype.toObject = function() {
|
||||
'use strict';
|
||||
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.
|
||||
* @deprecated Use `keys()` with native iteration protocols, for alignment
|
||||
* with ES6 Map.
|
||||
*/
|
||||
goog.structs.Map.prototype.getKeyIterator = function() {
|
||||
'use strict';
|
||||
return this.__iterator__(true);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {!IteratorIterable<K>} An ES6 Iterator that iterates over the maps
|
||||
* keys.
|
||||
*/
|
||||
goog.structs.Map.prototype.keys = function() {
|
||||
'use strict';
|
||||
return goog.iter.es6.ShimIterable.of(this.getKeyIterator()).toEs6();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @deprecated Use `values()` with native iteration protocols, for alignment
|
||||
* with ES6 Map.
|
||||
*/
|
||||
goog.structs.Map.prototype.getValueIterator = function() {
|
||||
'use strict';
|
||||
return this.__iterator__(false);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {!IteratorIterable<V>} An ES6 Iterator that iterates over the maps
|
||||
* values.
|
||||
*/
|
||||
goog.structs.Map.prototype.values = function() {
|
||||
'use strict';
|
||||
return goog.iter.es6.ShimIterable.of(this.getValueIterator()).toEs6();
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {!IteratorIterable<!Array<K|V>>} An iterator of entries in this map.
|
||||
* The type is actually Array<[K,V]> but this is not representable in the
|
||||
* Closure Type System.
|
||||
*/
|
||||
goog.structs.Map.prototype.entries = function() {
|
||||
const self = this;
|
||||
return goog.collections.iters.map(this.keys(), function(key) {
|
||||
return [key, self.get(key)];
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @deprecated Call either `keys` or `values` and use native iteration, for
|
||||
* alignment with ES6 Map.
|
||||
*/
|
||||
goog.structs.Map.prototype.__iterator__ = function(opt_keys) {
|
||||
'use strict';
|
||||
// Clean up keys to minimize the risk of iterating over dead keys.
|
||||
this.cleanupKeysArray_();
|
||||
|
||||
var i = 0;
|
||||
var version = this.version_;
|
||||
var selfObj = this;
|
||||
|
||||
var newIter = new goog.iter.Iterator;
|
||||
newIter.nextValueOrThrow = function() {
|
||||
'use strict';
|
||||
if (version != selfObj.version_) {
|
||||
throw new Error('The map has changed since the iterator was created');
|
||||
}
|
||||
if (i >= selfObj.keys_.length) {
|
||||
throw goog.iter.StopIteration;
|
||||
}
|
||||
var key = selfObj.keys_[i++];
|
||||
return opt_keys ? key : selfObj.map_[key];
|
||||
};
|
||||
|
||||
return newIter;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Assigns to the size property to isolate supressions of const assignment to
|
||||
* only where they are needed.
|
||||
* @param {number} newSize The size to update to.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Map.prototype.setSizeInternal_ = function(newSize) {
|
||||
/** @suppress {const} */
|
||||
this.size = newSize;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
'use strict';
|
||||
return Object.prototype.hasOwnProperty.call(obj, key);
|
||||
};
|
||||
Executable
+68
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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 {K} key Key.
|
||||
* @param {V} value Value.
|
||||
* @constructor
|
||||
* @template K, V
|
||||
*/
|
||||
goog.structs.Node = function(key, value) {
|
||||
'use strict';
|
||||
/**
|
||||
* The key.
|
||||
* @private {K}
|
||||
*/
|
||||
this.key_ = key;
|
||||
|
||||
/**
|
||||
* The value.
|
||||
* @private {V}
|
||||
*/
|
||||
this.value_ = value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the key.
|
||||
* @return {K} The key.
|
||||
*/
|
||||
goog.structs.Node.prototype.getKey = function() {
|
||||
'use strict';
|
||||
return this.key_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the value.
|
||||
* @return {V} The value.
|
||||
*/
|
||||
goog.structs.Node.prototype.getValue = function() {
|
||||
'use strict';
|
||||
return this.value_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clones a node and returns a new node.
|
||||
* @return {!goog.structs.Node<K, V>} A new goog.structs.Node with the same
|
||||
* key value pair.
|
||||
*/
|
||||
goog.structs.Node.prototype.clone = function() {
|
||||
'use strict';
|
||||
return new goog.structs.Node(this.key_, this.value_);
|
||||
};
|
||||
Executable
+380
@@ -0,0 +1,380 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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: 0).
|
||||
* @param {number=} opt_maxCount Max. number of objects (Default: 10).
|
||||
* @constructor
|
||||
* @extends {goog.Disposable}
|
||||
* @template T
|
||||
*/
|
||||
goog.structs.Pool = function(opt_minCount, opt_maxCount) {
|
||||
'use strict';
|
||||
goog.Disposable.call(this);
|
||||
|
||||
/**
|
||||
* Minimum number of objects allowed
|
||||
* @private {number}
|
||||
*/
|
||||
this.minCount_ = opt_minCount || 0;
|
||||
|
||||
/**
|
||||
* Maximum number of objects allowed
|
||||
* @private {number}
|
||||
*/
|
||||
this.maxCount_ = opt_maxCount || 10;
|
||||
|
||||
// Make sure that the max and min constraints are valid.
|
||||
if (this.minCount_ > this.maxCount_) {
|
||||
throw new Error(goog.structs.Pool.ERROR_MIN_MAX_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set used to store objects that are currently in the pool and available
|
||||
* to be used.
|
||||
* @private {goog.structs.Queue<T>}
|
||||
*/
|
||||
this.freeQueue_ = new goog.structs.Queue();
|
||||
|
||||
/**
|
||||
* Set used to store objects that are currently in the pool and in use.
|
||||
* @private {goog.structs.Set<T>}
|
||||
*/
|
||||
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.
|
||||
* @protected {number}
|
||||
*/
|
||||
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.
|
||||
* @protected {number?}
|
||||
*/
|
||||
this.lastAccess = null;
|
||||
|
||||
// Make sure that the minCount constraint is satisfied.
|
||||
this.adjustForMinMax();
|
||||
};
|
||||
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) {
|
||||
'use strict';
|
||||
// Check count constraints.
|
||||
if (min > this.maxCount_) {
|
||||
throw new 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 min count of the pool, an error is thrown.
|
||||
* @param {number} max The maximum count of the pool.
|
||||
*/
|
||||
goog.structs.Pool.prototype.setMaximumCount = function(max) {
|
||||
'use strict';
|
||||
// Check count constraints.
|
||||
if (max < this.minCount_) {
|
||||
throw new 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) {
|
||||
'use strict';
|
||||
this.delay = delay;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {T|undefined} A new object from the pool if there is one available,
|
||||
* otherwise undefined.
|
||||
*/
|
||||
goog.structs.Pool.prototype.getObject = function() {
|
||||
'use strict';
|
||||
var time = Date.now();
|
||||
if (this.lastAccess != null && 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 {T} 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) {
|
||||
'use strict';
|
||||
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 {T|undefined} The object removed from the free collection, if there
|
||||
* is one available. Otherwise, undefined.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Pool.prototype.removeFreeObject_ = function() {
|
||||
'use strict';
|
||||
var obj;
|
||||
while (this.getFreeCount() > 0) {
|
||||
obj = 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 {T} obj The object to add to collection of free objects.
|
||||
*/
|
||||
goog.structs.Pool.prototype.addFreeObject = function(obj) {
|
||||
'use strict';
|
||||
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() {
|
||||
'use strict';
|
||||
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(freeQueue.dequeue());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Should be overridden by sub-classes to return an instance of the object type
|
||||
* that is expected in the pool.
|
||||
* @return {T} The created object.
|
||||
*/
|
||||
goog.structs.Pool.prototype.createObject = function() {
|
||||
'use strict';
|
||||
return {};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Should be overridden to dispose of an object. Default implementation is to
|
||||
* remove all its members, which should render it useless. Calls the object's
|
||||
* `dispose()` method, if available.
|
||||
* @param {T} obj The object to dispose.
|
||||
*/
|
||||
goog.structs.Pool.prototype.disposeObject = function(obj) {
|
||||
'use strict';
|
||||
if (typeof obj.dispose == 'function') {
|
||||
obj.dispose();
|
||||
} else {
|
||||
for (var i in obj) {
|
||||
obj[i] = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Should be overridden to determine whether an object has become unusable and
|
||||
* should not be returned by getObject(). Calls the object's
|
||||
* `canBeReused()` method, if available.
|
||||
* @param {T} obj The object to test.
|
||||
* @return {boolean} Whether the object can be reused.
|
||||
*/
|
||||
goog.structs.Pool.prototype.objectCanBeReused = function(obj) {
|
||||
'use strict';
|
||||
if (typeof obj.canBeReused == 'function') {
|
||||
return obj.canBeReused();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the given object is in the pool.
|
||||
* @param {T} obj The object to check the pool for.
|
||||
* @return {boolean} Whether the pool contains the object.
|
||||
*/
|
||||
goog.structs.Pool.prototype.contains = function(obj) {
|
||||
'use strict';
|
||||
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() {
|
||||
'use strict';
|
||||
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() {
|
||||
'use strict';
|
||||
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() {
|
||||
'use strict';
|
||||
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() {
|
||||
'use strict';
|
||||
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() {
|
||||
'use strict';
|
||||
goog.structs.Pool.superClass_.disposeInternal.call(this);
|
||||
if (this.getInUseCount() > 0) {
|
||||
throw new 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(freeQueue.dequeue());
|
||||
}
|
||||
delete this.freeQueue_;
|
||||
};
|
||||
Executable
+181
@@ -0,0 +1,181 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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 min is greater than max, an error is thrown.
|
||||
* @param {number=} opt_minCount Min. number of objects (Default: 0).
|
||||
* @param {number=} opt_maxCount Max. number of objects (Default: 10).
|
||||
* @constructor
|
||||
* @extends {goog.structs.Pool<VALUE>}
|
||||
* @template VALUE
|
||||
*/
|
||||
goog.structs.PriorityPool = function(opt_minCount, opt_maxCount) {
|
||||
'use strict';
|
||||
/**
|
||||
* The key for the most recent timeout created.
|
||||
* @private {number|undefined}
|
||||
*/
|
||||
this.delayTimeout_ = undefined;
|
||||
|
||||
/**
|
||||
* Queue of requests for pool objects.
|
||||
* @private {goog.structs.PriorityQueue<VALUE>}
|
||||
*/
|
||||
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);
|
||||
|
||||
|
||||
/**
|
||||
* Default priority for pool objects requests.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.structs.PriorityPool.DEFAULT_PRIORITY_ = 100;
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.structs.PriorityPool.prototype.setDelay = function(delay) {
|
||||
'use strict';
|
||||
goog.structs.PriorityPool.base(this, 'setDelay', delay);
|
||||
|
||||
// If the pool hasn't been accessed yet, no need to do anything.
|
||||
if (this.lastAccess == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
goog.global.clearTimeout(this.delayTimeout_);
|
||||
this.delayTimeout_ = goog.global.setTimeout(
|
||||
goog.bind(this.handleQueueRequests_, this),
|
||||
this.delay + this.lastAccess - Date.now());
|
||||
|
||||
// Handle all requests.
|
||||
this.handleQueueRequests_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get a new object from 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 {number=} opt_priority The priority of the request. A smaller value
|
||||
* means a higher priority.
|
||||
* @return {VALUE|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) {
|
||||
'use strict';
|
||||
if (!opt_callback) {
|
||||
var result = goog.structs.PriorityPool.base(this, 'getObject');
|
||||
if (result && this.delay) {
|
||||
this.delayTimeout_ = goog.global.setTimeout(
|
||||
goog.bind(this.handleQueueRequests_, this), this.delay);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
var priority = (opt_priority !== undefined) ?
|
||||
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() {
|
||||
'use strict';
|
||||
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 {VALUE} obj The object to add to the collection of free objects.
|
||||
* @override
|
||||
*/
|
||||
goog.structs.PriorityPool.prototype.addFreeObject = function(obj) {
|
||||
'use strict';
|
||||
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() {
|
||||
'use strict';
|
||||
goog.structs.PriorityPool.superClass_.adjustForMinMax.call(this);
|
||||
|
||||
// Handle all requests.
|
||||
this.handleQueueRequests_();
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.structs.PriorityPool.prototype.disposeInternal = function() {
|
||||
'use strict';
|
||||
goog.structs.PriorityPool.superClass_.disposeInternal.call(this);
|
||||
goog.global.clearTimeout(this.delayTimeout_);
|
||||
this.requestQueue_.clear();
|
||||
this.requestQueue_ = null;
|
||||
};
|
||||
Executable
+61
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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<number, VALUE>}
|
||||
* @template VALUE
|
||||
* @final
|
||||
*/
|
||||
goog.structs.PriorityQueue = function() {
|
||||
'use strict';
|
||||
goog.structs.Heap.call(this);
|
||||
};
|
||||
goog.inherits(goog.structs.PriorityQueue, goog.structs.Heap);
|
||||
|
||||
|
||||
/**
|
||||
* Puts the specified value in the queue.
|
||||
* @param {number} priority The priority of the value. A smaller value here
|
||||
* means a higher priority.
|
||||
* @param {VALUE} value The value.
|
||||
*/
|
||||
goog.structs.PriorityQueue.prototype.enqueue = function(priority, value) {
|
||||
'use strict';
|
||||
this.insert(priority, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves and removes the head of this queue.
|
||||
* @return {VALUE} The element at the head of this queue. Returns undefined if
|
||||
* the queue is empty.
|
||||
*/
|
||||
goog.structs.PriorityQueue.prototype.dequeue = function() {
|
||||
'use strict';
|
||||
return this.remove();
|
||||
};
|
||||
Executable
+183
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: Queue.
|
||||
*
|
||||
*
|
||||
* This file provides the implementation of a FIFO Queue structure.
|
||||
* API is similar to that of com.google.common.collect.IntQueue
|
||||
*
|
||||
* The implementation is a classic 2-stack queue.
|
||||
* There's a "front" stack and a "back" stack.
|
||||
* Items are pushed onto "back" and popped from "front".
|
||||
* When "front" is empty, we replace "front" with reverse(back).
|
||||
*
|
||||
* Example:
|
||||
* front back op
|
||||
* [] [] enqueue 1
|
||||
* [] [1] enqueue 2
|
||||
* [] [1,2] enqueue 3
|
||||
* [] [1,2,3] dequeue -> ...
|
||||
* [3,2,1] [] ... -> 1
|
||||
* [3,2] [] enqueue 4
|
||||
* [3,2] [4] dequeue -> 2
|
||||
* [3] [4]
|
||||
*
|
||||
* Front and back are simple javascript arrays. We rely on
|
||||
* Array.push and Array.pop being O(1) amortized.
|
||||
*
|
||||
* Note: In V8, queues, up to a certain size, can be implemented
|
||||
* just fine using Array.push and Array.shift, but other JavaScript
|
||||
* engines do not have the optimization of Array.shift.
|
||||
*/
|
||||
|
||||
goog.provide('goog.structs.Queue');
|
||||
|
||||
goog.require('goog.array');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for FIFO Queue data structure.
|
||||
*
|
||||
* @constructor
|
||||
* @template T
|
||||
*/
|
||||
goog.structs.Queue = function() {
|
||||
'use strict';
|
||||
/**
|
||||
* @private {!Array<T>} Front stack. Items are pop()'ed from here.
|
||||
*/
|
||||
this.front_ = [];
|
||||
/**
|
||||
* @private {!Array<T>} Back stack. Items are push()'ed here.
|
||||
*/
|
||||
this.back_ = [];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Flips the back stack onto the front stack if front is empty,
|
||||
* to prepare for peek() or dequeue().
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Queue.prototype.maybeFlip_ = function() {
|
||||
'use strict';
|
||||
if (this.front_.length === 0) {
|
||||
this.front_ = this.back_;
|
||||
this.front_.reverse();
|
||||
this.back_ = [];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Puts the specified element on this queue.
|
||||
* @param {T} element The element to be added to the queue.
|
||||
*/
|
||||
goog.structs.Queue.prototype.enqueue = function(element) {
|
||||
'use strict';
|
||||
this.back_.push(element);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves and removes the head of this queue.
|
||||
* @return {T} The element at the head of this queue. Returns undefined if the
|
||||
* queue is empty.
|
||||
*/
|
||||
goog.structs.Queue.prototype.dequeue = function() {
|
||||
'use strict';
|
||||
this.maybeFlip_();
|
||||
return this.front_.pop();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves but does not remove the head of this queue.
|
||||
* @return {T} The element at the head of this queue. Returns undefined if the
|
||||
* queue is empty.
|
||||
*/
|
||||
goog.structs.Queue.prototype.peek = function() {
|
||||
'use strict';
|
||||
this.maybeFlip_();
|
||||
return goog.array.peek(this.front_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of elements in this queue.
|
||||
* @return {number} The number of elements in this queue.
|
||||
*/
|
||||
goog.structs.Queue.prototype.getCount = function() {
|
||||
'use strict';
|
||||
return this.front_.length + this.back_.length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if this queue contains no elements.
|
||||
* @return {boolean} true if this queue contains no elements.
|
||||
*/
|
||||
goog.structs.Queue.prototype.isEmpty = function() {
|
||||
'use strict';
|
||||
return this.front_.length === 0 && this.back_.length === 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all elements from the queue.
|
||||
*/
|
||||
goog.structs.Queue.prototype.clear = function() {
|
||||
'use strict';
|
||||
this.front_ = [];
|
||||
this.back_ = [];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the given value is in the queue.
|
||||
* @param {T} obj The value to look for.
|
||||
* @return {boolean} Whether the object is in the queue.
|
||||
*/
|
||||
goog.structs.Queue.prototype.contains = function(obj) {
|
||||
'use strict';
|
||||
return goog.array.contains(this.front_, obj) ||
|
||||
goog.array.contains(this.back_, obj);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the first occurrence of a particular value from the queue.
|
||||
* @param {T} obj Object to remove.
|
||||
* @return {boolean} True if an element was removed.
|
||||
*/
|
||||
goog.structs.Queue.prototype.remove = function(obj) {
|
||||
'use strict';
|
||||
return goog.array.removeLast(this.front_, obj) ||
|
||||
goog.array.remove(this.back_, obj);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns all the values in the queue.
|
||||
* @return {!Array<T>} An array of the values in the queue.
|
||||
*/
|
||||
goog.structs.Queue.prototype.getValues = function() {
|
||||
'use strict';
|
||||
var res = [];
|
||||
// Add the front array in reverse, then the back array.
|
||||
for (var i = this.front_.length - 1; i >= 0; --i) {
|
||||
res.push(this.front_[i]);
|
||||
}
|
||||
var len = this.back_.length;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
res.push(this.back_[i]);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
Executable
+381
@@ -0,0 +1,381 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Datastructure: Set.
|
||||
*
|
||||
*
|
||||
* 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');
|
||||
goog.requireType('goog.iter.Iterator');
|
||||
|
||||
/**
|
||||
* 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<T>|Object<?,T>=} opt_values Initial values to start with.
|
||||
* @constructor
|
||||
* @implements {goog.structs.Collection<T>}
|
||||
* @implements {Iterable<T>}
|
||||
* @final
|
||||
* @template T
|
||||
* @deprecated This type is misleading: use ES6 Set instead.
|
||||
*/
|
||||
goog.structs.Set = function(opt_values) {
|
||||
'use strict';
|
||||
this.map_ = new goog.structs.Map();
|
||||
|
||||
|
||||
/**
|
||||
* The number of items in this set.
|
||||
* @const {number}
|
||||
*/
|
||||
this.size = 0;
|
||||
|
||||
if (opt_values) {
|
||||
this.addAll(opt_values);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A function that returns a unique id.
|
||||
* @private @const {function(?Object): number}
|
||||
*/
|
||||
goog.structs.Set.getUid_ = goog.getUid;
|
||||
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
'use strict';
|
||||
var type = typeof val;
|
||||
if (type == 'object' && val || type == 'function') {
|
||||
return 'o' + goog.structs.Set.getUid_(/** @type {Object} */ (val));
|
||||
} else {
|
||||
return type.substr(0, 1) + val;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The number of elements in the set.
|
||||
* @override
|
||||
* @deprecated Use the `size` property instead, for alignment with ES6 Set.
|
||||
*/
|
||||
goog.structs.Set.prototype.getCount = function() {
|
||||
'use strict';
|
||||
return this.map_.size;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add a primitive or an object to the set.
|
||||
* @param {T} element The primitive or object to add.
|
||||
* @override
|
||||
*/
|
||||
goog.structs.Set.prototype.add = function(element) {
|
||||
'use strict';
|
||||
this.map_.set(goog.structs.Set.getKey_(element), element);
|
||||
this.setSizeInternal_(this.map_.size);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds all the values in the given collection to this set.
|
||||
* @param {Array<T>|goog.structs.Collection<T>|Object<?,T>} col A collection
|
||||
* containing the elements to add.
|
||||
* @deprecated Use `goog.collections.sets.addAll(thisSet, col)` instead,
|
||||
* converting Objects to their values using `Object.values`, for alignment
|
||||
* with ES6 Set.
|
||||
*/
|
||||
goog.structs.Set.prototype.addAll = function(col) {
|
||||
'use strict';
|
||||
var values = goog.structs.getValues(col);
|
||||
var l = values.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
this.add(values[i]);
|
||||
}
|
||||
this.setSizeInternal_(this.map_.size);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all values in the given collection from this set.
|
||||
* @param {Array<T>|goog.structs.Collection<T>|Object<?,T>} col A collection
|
||||
* containing the elements to remove.
|
||||
* @deprecated Use `goog.collections.sets.removeAll(thisSet, col)` instead,
|
||||
* converting Objects to their values using `Object.values`, for alignment
|
||||
* with ES6 Set.
|
||||
*/
|
||||
goog.structs.Set.prototype.removeAll = function(col) {
|
||||
'use strict';
|
||||
var values = goog.structs.getValues(col);
|
||||
var l = values.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
this.remove(values[i]);
|
||||
}
|
||||
this.setSizeInternal_(this.map_.size);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the given element from this set.
|
||||
* @param {T} element The primitive or object to remove.
|
||||
* @return {boolean} Whether the element was found and removed.
|
||||
*/
|
||||
goog.structs.Set.prototype.delete = function(element) {
|
||||
'use strict';
|
||||
const rv = this.map_.remove(goog.structs.Set.getKey_(element));
|
||||
this.setSizeInternal_(this.map_.size);
|
||||
return rv;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the given element from this set.
|
||||
* @param {T} element The primitive or object to remove.
|
||||
* @return {boolean} Whether the element was found and removed.
|
||||
* @override
|
||||
* @deprecated Use `delete`, for alignment with ES6 Set.
|
||||
*/
|
||||
goog.structs.Set.prototype.remove = function(element) {
|
||||
'use strict';
|
||||
return this.delete(element);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all elements from this set.
|
||||
*/
|
||||
goog.structs.Set.prototype.clear = function() {
|
||||
'use strict';
|
||||
this.map_.clear();
|
||||
this.setSizeInternal_(0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether this set is empty.
|
||||
* @return {boolean} True if there are no elements in this set.
|
||||
* @deprecated Use the size property and compare against 0, for alignment with
|
||||
* ES6 Set.
|
||||
*/
|
||||
goog.structs.Set.prototype.isEmpty = function() {
|
||||
'use strict';
|
||||
return this.map_.size === 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether this set contains the given element.
|
||||
* @param {T} element The primitive or object to test for.
|
||||
* @return {boolean} True if this set contains the given element.
|
||||
*/
|
||||
goog.structs.Set.prototype.has = function(element) {
|
||||
'use strict';
|
||||
return this.map_.containsKey(goog.structs.Set.getKey_(element));
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests whether this set contains the given element.
|
||||
* @param {T} element The primitive or object to test for.
|
||||
* @return {boolean} True if this set contains the given element.
|
||||
* @override
|
||||
* @deprecated Use `has` instead, for alignment with ES6 Set.
|
||||
*/
|
||||
goog.structs.Set.prototype.contains = function(element) {
|
||||
'use strict';
|
||||
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 {goog.structs.Collection<T>|Object} col A collection-like object.
|
||||
* @return {boolean} True if the set contains all elements.
|
||||
* @deprecated Use `goog.collections.sets.hasAll(thisSet, col)`, converting
|
||||
* Objects to arrays using Object.values, for alignment with ES6 Set.
|
||||
*/
|
||||
goog.structs.Set.prototype.containsAll = function(col) {
|
||||
'use strict';
|
||||
return goog.structs.every(col, this.contains, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Finds all values that are present in both this set and the given collection.
|
||||
* @param {Array<S>|Object<?,S>} col A collection.
|
||||
* @return {!goog.structs.Set<T|S>} A new set containing all the values
|
||||
* (primitives or objects) present in both this set and the given
|
||||
* collection.
|
||||
* @template S
|
||||
* @deprecated Use `goog.collections.sets.intersection(thisSet, col)`,
|
||||
* converting Objects to arrays using Object.values, instead for alignment
|
||||
* with ES6 Set.
|
||||
*/
|
||||
goog.structs.Set.prototype.intersection = function(col) {
|
||||
'use strict';
|
||||
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<T>|goog.structs.Collection<T>|Object<?,T>} 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) {
|
||||
'use strict';
|
||||
var result = this.clone();
|
||||
result.removeAll(col);
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array containing all the elements in this set.
|
||||
* @return {!Array<T>} An array containing all the elements in this set.
|
||||
* @deprecated Use `Array.from(set.values())` instead, for alignment with ES6
|
||||
* Set.
|
||||
*/
|
||||
goog.structs.Set.prototype.getValues = function() {
|
||||
'use strict';
|
||||
return this.map_.getValues();
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {!IteratorIterable<T>} An ES6 Iterator that iterates over the values
|
||||
* in the set.
|
||||
*/
|
||||
goog.structs.Set.prototype.values = function() {
|
||||
'use strict';
|
||||
return this.map_.values();
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a shallow clone of this set.
|
||||
* @return {!goog.structs.Set<T>} A new set containing all the same elements as
|
||||
* this set.
|
||||
* @deprecated Use `new Set(thisSet.values())` for alignment with ES6 Set.
|
||||
*/
|
||||
goog.structs.Set.prototype.clone = function() {
|
||||
'use strict';
|
||||
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 {goog.structs.Collection<T>|Object} col A collection.
|
||||
* @return {boolean} True if the given collection consists of the same elements
|
||||
* as this set, regardless of order, without repetition.
|
||||
* @deprecated Use `goog.collections.equals(thisSet, col)`, converting Objects
|
||||
* to arrays using Object.values, instead for alignment with ES6 Set.
|
||||
*/
|
||||
goog.structs.Set.prototype.equals = function(col) {
|
||||
'use strict';
|
||||
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 {goog.structs.Collection<T>|Object} col A collection.
|
||||
* @return {boolean} True if this set is a subset of the given collection.
|
||||
* @deprecated Use `goog.collections.isSubsetOf(thisSet, col)`, converting
|
||||
* Objects to arrays using Object.values, instead for alignment with ES6
|
||||
* Set.
|
||||
*/
|
||||
goog.structs.Set.prototype.isSubsetOf = function(col) {
|
||||
'use strict';
|
||||
var colCount = goog.structs.getCount(col);
|
||||
if (this.getCount() > colCount) {
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
'use strict';
|
||||
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.
|
||||
* @deprecated Call `values` and use native iteration, for alignment with ES6
|
||||
* Set.
|
||||
*/
|
||||
goog.structs.Set.prototype.__iterator__ = function(opt_keys) {
|
||||
'use strict';
|
||||
return this.map_.__iterator__(false);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {!IteratorIterable<T>} An ES6 Iterator that iterates over the values
|
||||
* in the set.
|
||||
*/
|
||||
goog.structs.Set.prototype[Symbol.iterator] = function() {
|
||||
return this.values();
|
||||
};
|
||||
|
||||
/**
|
||||
* Assigns to the size property to isolate supressions of const assignment
|
||||
* to only where they are needed.
|
||||
* @param {number} newSize The size to update to.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Set.prototype.setSizeInternal_ = function(newSize) {
|
||||
/** @suppress {const} */
|
||||
this.size = newSize;
|
||||
};
|
||||
Executable
+380
@@ -0,0 +1,380 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Generics method for collection-like classes and objects.
|
||||
*
|
||||
*
|
||||
* This file contains functions to work with collections. It supports using
|
||||
* Map, Set, Array and Object and other classes that implement collection-like
|
||||
* methods.
|
||||
* @suppress {strictMissingProperties}
|
||||
*/
|
||||
|
||||
|
||||
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) {
|
||||
'use strict';
|
||||
if (col.getCount && typeof col.getCount == 'function') {
|
||||
return col.getCount();
|
||||
}
|
||||
if (goog.isArrayLike(col) || typeof col === 'string') {
|
||||
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) {
|
||||
'use strict';
|
||||
if (col.getValues && typeof col.getValues == 'function') {
|
||||
return col.getValues();
|
||||
}
|
||||
// ES6 Map and Set both define a values function that returns an iterator.
|
||||
// The typeof check allows the compiler to remove the Map and Set polyfills
|
||||
// if they are otherwise unused throughout the entire binary.
|
||||
if ((typeof Map !== 'undefined' && col instanceof Map) ||
|
||||
(typeof Set !== 'undefined' && col instanceof Set)) {
|
||||
return Array.from(col.values());
|
||||
}
|
||||
if (typeof col === 'string') {
|
||||
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) {
|
||||
'use strict';
|
||||
if (col.getKeys && typeof col.getKeys == 'function') {
|
||||
return col.getKeys();
|
||||
}
|
||||
// if we have getValues but no getKeys we know this is a key-less collection
|
||||
if (col.getValues && typeof col.getValues == 'function') {
|
||||
return undefined;
|
||||
}
|
||||
// ES6 Map and Set both define a keys function that returns an iterator. For
|
||||
// Sets this iterates over the same values as the values iterator.
|
||||
// The typeof check allows the compiler to remove the Map and Set polyfills
|
||||
// if they are otherwise unused throughout the entire binary.
|
||||
if (typeof Map !== 'undefined' && col instanceof Map) {
|
||||
return Array.from(col.keys());
|
||||
}
|
||||
// Unlike the native Set, goog.structs.Set does not expose keys as the values.
|
||||
if (typeof Set !== 'undefined' && col instanceof Set) {
|
||||
return undefined;
|
||||
}
|
||||
if (goog.isArrayLike(col) || typeof col === 'string') {
|
||||
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) {
|
||||
'use strict';
|
||||
if (col.contains && typeof col.contains == 'function') {
|
||||
return col.contains(val);
|
||||
}
|
||||
if (col.containsValue && typeof col.containsValue == 'function') {
|
||||
return col.containsValue(val);
|
||||
}
|
||||
if (goog.isArrayLike(col) || typeof col === 'string') {
|
||||
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) {
|
||||
'use strict';
|
||||
if (col.isEmpty && typeof col.isEmpty == 'function') {
|
||||
return col.isEmpty();
|
||||
}
|
||||
|
||||
// We do not use goog.string.isEmptyOrWhitespace because here we treat the
|
||||
// string as
|
||||
// collection and as such even whitespace matters
|
||||
|
||||
if (goog.isArrayLike(col) || typeof col === 'string') {
|
||||
return /** @type {!Array<?>} */ (col).length === 0;
|
||||
}
|
||||
return goog.object.isEmpty(col);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all the elements from the collection.
|
||||
* @param {Object} col The collection-like object.
|
||||
* @return {void}
|
||||
*/
|
||||
goog.structs.clear = function(col) {
|
||||
'use strict';
|
||||
// NOTE(arv): This should not contain strings because strings are immutable
|
||||
if (col.clear && typeof col.clear == 'function') {
|
||||
col.clear();
|
||||
} else if (goog.isArrayLike(col)) {
|
||||
goog.array.clear(/** @type {IArrayLike<?>} */ (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 `f`.
|
||||
* @return {void}
|
||||
* @template T,S
|
||||
* @deprecated Use a more specific method, e.g. native Array.prototype.forEach,
|
||||
* or for-of.
|
||||
*/
|
||||
goog.structs.forEach = function(col, f, opt_obj) {
|
||||
'use strict';
|
||||
if (col.forEach && typeof col.forEach == 'function') {
|
||||
col.forEach(f, opt_obj);
|
||||
} else if (goog.isArrayLike(col) || typeof col === 'string') {
|
||||
Array.prototype.forEach.call(/** @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(/** @type {?} */ (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 `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) {
|
||||
'use strict';
|
||||
if (typeof col.filter == 'function') {
|
||||
return col.filter(f, opt_obj);
|
||||
}
|
||||
if (goog.isArrayLike(col) || typeof col === 'string') {
|
||||
return Array.prototype.filter.call(
|
||||
/** @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(/** @type {?} */ (opt_obj), values[i], keys[i], col)) {
|
||||
rv[keys[i]] = values[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We should not use 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 `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) {
|
||||
'use strict';
|
||||
if (typeof col.map == 'function') {
|
||||
return col.map(f, opt_obj);
|
||||
}
|
||||
if (goog.isArrayLike(col) || typeof col === 'string') {
|
||||
return Array.prototype.map.call(/** @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(/** @type {?} */ (opt_obj), values[i], keys[i], col);
|
||||
}
|
||||
} else {
|
||||
// We should not use 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(/** @type {?} */ (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 `f`.
|
||||
* @return {boolean} True if any value passes the test.
|
||||
* @template T,S
|
||||
*/
|
||||
goog.structs.some = function(col, f, opt_obj) {
|
||||
'use strict';
|
||||
if (typeof col.some == 'function') {
|
||||
return col.some(f, opt_obj);
|
||||
}
|
||||
if (goog.isArrayLike(col) || typeof col === 'string') {
|
||||
return Array.prototype.some.call(
|
||||
/** @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(/** @type {?} */ (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 `f`.
|
||||
* @return {boolean} True if all key-value pairs pass the test.
|
||||
* @template T,S
|
||||
*/
|
||||
goog.structs.every = function(col, f, opt_obj) {
|
||||
'use strict';
|
||||
if (typeof col.every == 'function') {
|
||||
return col.every(f, opt_obj);
|
||||
}
|
||||
if (goog.isArrayLike(col) || typeof col === 'string') {
|
||||
return Array.prototype.every.call(
|
||||
/** @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(/** @type {?} */ (opt_obj), values[i], keys && keys[i], col)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
Reference in New Issue
Block a user