/**
* @license
* Copyright Larry Diamond 2018 All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/larrydiamond/typescriptcollectionsframework/blob/master/LICENSE
*/
import {BasicIteratorResult} from "./BasicIteratorResult";
import {BasicMapEntry} from "./BasicMapEntry";
import {Collections} from "./Collections";
import {Comparator} from "./Comparator";
import {Consumer} from "./Consumer";
import {ImmutableMap} from "./ImmutableMap";
import {ImmutableSet} from "./ImmutableSet";
import {JIterator} from "./JIterator";
import {JMap} from "./JMap";
import {MapEntry} from "./MapEntry";
import {NavigableMap} from "./NavigableMap";
/**
* A binary tree based NavigableMap implementation. The map is sorted according to a Comparator provided at map creation time.
* This implementation provides guaranteed log(n) time cost for the containsKey, get, put and remove operations.
*
* Note that the ordering maintained by a tree map must be consistent with equals if this sorted map is to correctly implement the Map interface.
* (See Comparator for a precise definition of consistent with equals.)
* This is so because the Map interface is defined in terms of the equals operation,
* but a sorted map performs all key comparisons using its Comparator,
* so two keys that are deemed equal by this method are, from the standpoint of the sorted map, equal.
* The behavior of a navigable map is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Map interface.
*
* This class corresponds to java.util.TreeMap
*/
export class TreeMap implements NavigableMap {
private topNode:TreeMapNode = null;
private mapComparator:Comparator = null;
constructor(iComparator:Comparator, private initialElements:ImmutableMap = null) {
this.mapComparator = iComparator;
if ((initialElements !== null) && (initialElements !== undefined)) {
for (const iter = initialElements.entrySet().iterator(); iter.hasNext(); ) {
const t:MapEntry = iter.next ();
this.put (t.getKey(), t.getValue());
}
}
}
/* Debugging code
public printMap() : void {
if (this.topNode === null) {
console.log ("top node is null");
return;
}
if (this.topNode === undefined) {
console.log ("top node is undefined");
return;
}
console.log ("");
console.log ("Tree size = " + this.size());
this.printMapNode (this.topNode);
console.log ("End of Tree");
console.log ("");
}
private printMapNode (node:TreeMapNode) : void {
console.log ("New Node: key = " + node.getKey() + " value = " + node.getValue());
if (node.getParentNode() !== null) {
console.log ("Parent key = " + node.getParentNode().getKey());
} else {
console.log ("Parent node is null");
}
if (node.getLeftNode() !== null) {
console.log ("Left key = " + node.getLeftNode().getKey());
} else {
console.log ("Left node is null");
}
if (node.getRightNode() !== null) {
console.log ("Right key = " + node.getRightNode().getKey());
} else {
console.log ("Right node is null");
}
if (node.getLeftNode() !== null) {
this.printMapNode (node.getLeftNode());
}
if (node.getRightNode() !== null) {
this.printMapNode (node.getRightNode());
}
}
/* */
public validateMap() : boolean {
if ((this.topNode === null) || (this.topNode === undefined)) {
return true;
}
return this.validateNode (this.topNode);
}
private validateNode(node:TreeMapNode) : boolean {
const left:TreeMapNode = node.getLeftNode();
const right:TreeMapNode = node.getRightNode();
const thiskey:K = node.getKey();
if (left !== null) {
const leftkey:K = left.getKey();
const comp:number = this.mapComparator.compare(thiskey, leftkey);
if (comp < 0) // the key on the left should be either on the right or is this key
return false;
return this.validateNode (left);
}
if (right !== null) {
const rightkey:K = right.getKey();
const comp:number = this.mapComparator.compare(thiskey, rightkey);
if (comp > 0) // the key on the right should be either on the left or is this key
return false;
return this.validateNode (right);
}
return true;
}
/**
* Returns an iterator over the entire entry set
* @return {Iterator} an iterator for the entry set
*/
public [Symbol.iterator] ():Iterator {
return this.entrySet[Symbol.iterator]();
}
/**
* Removes all of the mappings from this map. The map will be empty after this call returns.
*/
public clear () : void {
// if only this was enough :(
// JavaScript memory management has problems when two objects have pointers to one another
// In that case, the mark and sweep garbage collector is unable to collect either object
// and we wind up with out of memory errors :(
while ((this.topNode !== null) && (this.topNode !== undefined)) {
this.remove (this.topNode.getKey());
}
this.topNode = null;
}
/**
* Returns the comparator used to order the keys in this map
* @return {Comparator} the comparator used to order the keys in this map
*/
public comparator () : Comparator {
return this.mapComparator;
}
/**
* Returns the number of key-value mappings in this map.
* @return {number} the number of key-value mappings in this map
*/
public size () : number {
if ((this.topNode === null) || (this.topNode === undefined))
return 0;
return this.sizeTree (this.topNode.getLeftNode()) + this.sizeTree (this.topNode.getRightNode()) + 1;
}
/**
* Returns true if this map contains no key-value mappings.
* @return {boolean} true if this map contains no key-value mappings
*/
public isEmpty () : boolean {
if (this.size() < 1) return true;
return false;
}
private sizeTree (n:TreeMapNode):number {
if ((n === null) || (n === undefined))
return 0;
return this.sizeTree (n.getLeftNode()) + this.sizeTree (n.getRightNode()) + 1;
}
/**
* Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced.
* @param {K} key key with which the specified value is to be associated
* @param {V} value value to be associated with the specified key
* @return {V} the previous value associated with key, or undefined if there was no mapping for key. (An undefined return can also indicate that the map previously associated undefined with key.)
*/
public put (key:K, value:V) : V {
if ((this.topNode === null) || (this.topNode === undefined)) {
const newNode:TreeMapNode = new TreeMapNode(key, value, null);
this.topNode = newNode;
return undefined;
}
return this.putNode (this.topNode, key, value);
}
private putNode (node:TreeMapNode, key:K, value:V) : V {
const comp:number = this.mapComparator.compare(key, node.getKey());
if (comp === 0) {
const tmpV:V = node.getValue();
node.setValue(value);
return tmpV;
}
if (comp < 0) { // This means that the new value is lower than the current node and belongs someplace on the left of the current node
const nextNode: TreeMapNode = node.getLeftNode();
if (nextNode === null) {
const newNode:TreeMapNode = new TreeMapNode(key, value, node);
// Can we do a minor rebalance of the bottom nodes of the tree?
// if we are about to place a new node below a parent with no current children,
// check to see if the the "grandparent" only has the one child and if so do a local rebalance
if (node.getRightNode() === null) { // parent currently has no children
const grandparent:TreeMapNode = node.getParentNode();
if (grandparent !== null) {
if ((grandparent.getLeftNode () === node) && (grandparent.getRightNode () === null)) { // rebalance to make node parent of both grandparent and new node - left left left
node.setLeftNode (newNode);
node.setRightNode(grandparent);
node.setParentNode(grandparent.getParentNode());
grandparent.setLeftNode (null);
grandparent.setRightNode (null);
grandparent.setParentNode (node);
if (grandparent === this.topNode) { // reorg top of tree
// make node new parent with newnode as left node and grandparent as right node
this.topNode = node;
} else { // we're really checking the grandparent's parents but we already remapped above
if (node.getParentNode().getLeftNode() === grandparent) node.getParentNode().setLeftNode(node);
if (node.getParentNode().getRightNode() === grandparent) node.getParentNode().setRightNode(node);
}
} else { // TODO check to see if we have a right left left rebalance opportunity
node.setLeftNode(newNode);
}
} else { // oh well we looked we tried
node.setLeftNode(newNode);
}
} else { // oh well we looked we tried
node.setLeftNode(newNode);
}
return undefined;
} else {
return this.putNode (nextNode, key, value);
}
} else { // This means that the new value is higher than the current node and belongs someplace on the right of the current node
const nextNode: TreeMapNode = node.getRightNode();
if (nextNode === null) {
const newNode:TreeMapNode = new TreeMapNode(key, value, node);
if (node.getLeftNode() === null) { // parent currently has no children
const grandparent:TreeMapNode = node.getParentNode();
if (grandparent !== null) {
if ((grandparent.getRightNode () === node) && (grandparent.getLeftNode () === null)) { // rebalance to make node parent of both grandparent and new node - right right right
node.setRightNode (newNode);
node.setLeftNode(grandparent);
node.setParentNode(grandparent.getParentNode());
grandparent.setRightNode (null);
grandparent.setLeftNode (null);
grandparent.setParentNode (node);
if (grandparent === this.topNode) { // reorg top of tree
// make node new parent with newnode as left node and grandparent as right node
this.topNode = node;
} else { // we're really checking the grandparent's parents but we already remapped above
if (node.getParentNode().getLeftNode() === grandparent) node.getParentNode().setLeftNode(node);
if (node.getParentNode().getRightNode() === grandparent) node.getParentNode().setRightNode(node);
}
} else { // TODO check to see if we have a left right right rebalance opportunity
node.setRightNode(newNode);
}
} else { // oh well we looked we tried
node.setRightNode(newNode);
}
} else { // oh well we looked we tried
node.setRightNode(newNode);
}
node.setRightNode(newNode);
return undefined;
} else {
return this.putNode (nextNode, key, value);
}
}
}
/**
* Needed For Iterator
* @param {K} key the given key
* @return {K} the least key greater than key, or null if there is no such key
*/
public getNextHigherKey (key:K) : K {
if ((this.topNode === null) || (this.topNode === undefined)) {
return null;
}
const thisnode = this.getNode(this.topNode, key);
if ((thisnode === undefined) || (thisnode === null)) return null;
const tmp:TreeMapNode = this.nextHigherNode(thisnode);
if (tmp === null) return null;
return tmp.getKey();
}
/**
* Returns true if this map maps one or more keys to the specified value.
* @param value value whose presence in this map is to be tested
*/
public containsValue (value: V) : boolean {
return Collections.containsValue (this, value);
}
private nextHigherNode (node:TreeMapNode) : TreeMapNode {
// if there is a right child to this node, return the leftmost child of that node
// If there is no parent node and no right child node then there's no next node and return null
// If I am the left child of my parent node and I have no right child then my parent node is the next node
// If I am the right child of my parent node, keep recursing up nodes until null or I find a node of which I am a left child of and return that node
// Got all that?
// if there is a right child to this node, return the leftmost child of that node
if (node.getRightNode() !== null) {
let child:TreeMapNode = node.getRightNode();
while (child.getLeftNode() !== null) {
child = child.getLeftNode();
}
return child;
}
// If there is no parent node and no right child node then there's no next node and return null
if (node.getParentNode() === null) { // if there's a right child that was handled above
return null;
}
// If I am the left child of my parent node and I have no right child then my parent node is the next node
if (node.getParentNode().getLeftNode() === node) {
return node.getParentNode();
}
// If I am the right child of my parent node, keep recursing up nodes until null or I find a node of which I am a left child of and return that node
let tmp:TreeMapNode = node.getParentNode();
while ((tmp !== null) && (tmp.getParentNode() !== null) && (tmp.getParentNode().getRightNode() === tmp)) {
tmp = tmp.getParentNode();
}
if (tmp.getParentNode() === null) return null;
return tmp.getParentNode();
}
/**
* Returns true if this map contains a mapping for the specified key. This method uses the comparator for the map to find the specified key
* @param {K} key key whose presence in this map is to be tested
* @return {boolean} true if this map contains a mapping for the specified key
*/
public containsKey (key:K) : boolean {
if ((this.topNode === null) || (this.topNode === undefined))
return false;
if (this.getNode (this.topNode, key) === null)
return false;
return true;
}
private getNode (node:TreeMapNode, key:K) : TreeMapNode {
const comp:number = this.mapComparator.compare(key, node.getKey());
if (comp === 0)
return node;
if (comp < 0) { // This means that the new value is higher than the current node and belongs someplace on the right of the current node
const nextNode: TreeMapNode = node.getLeftNode();
if (nextNode === null) {
return null;
} else {
return this.getNode (nextNode, key);
}
} else { // This means that the new value is lower than the current node and belongs someplace on the left of the current node
const nextNode: TreeMapNode = node.getRightNode();
if (nextNode === null) {
return null;
} else {
return this.getNode (nextNode, key);
}
}
}
/**
* Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
* @param {K} key the key whose associated value is to be returned
* @return {V} the value to which the specified key is mapped, or null if this map contains no mapping for the key
*/
public get (key:K) : V {
if ((this.topNode === null) || (this.topNode === undefined))
return undefined;
const tmp:TreeMapNode = this.getNode (this.topNode, key);
if ((tmp === null) || (tmp === undefined))
return undefined;
return tmp.getValue();
}
/**
* Removes the mapping for this key from this TreeMap if present.
* @param {K} key key for which mapping should be removed
* @return {V} the previous value associated with key, or null if there was no mapping for key. (A null return can also indicate that the map previously associated null with key.)
*/
public remove (key:K) : V {
if ((this.topNode === null) || (this.topNode === undefined))
return null;
const tmp:TreeMapNode = this.getNode (this.topNode, key);
if (tmp === null) {
return null;
}
const parent:TreeMapNode = tmp.getParentNode();
const left:TreeMapNode = tmp.getLeftNode();
const right:TreeMapNode = tmp.getRightNode();
if (tmp.getLeftNode() === null) { // nothing to the left
if (tmp.getRightNode() === null) { // nothing to the right
// close up this wing of the tree, nothing to see here
if (parent === null) { // if theres no parent then this is the root node of the Tree
this.topNode = null;
} else {
if (parent.getLeftNode() === tmp) {
parent.setLeftNode(null);
} else {
parent.setRightNode(null);
}
}
} else { // there are nodes to the right but not to the left
right.setParentNode(parent);
if (parent === null) {
this.topNode = right;
} else {
if (parent.getLeftNode() === tmp) {
parent.setLeftNode(right);
} else {
parent.setRightNode(right);
}
}
}
} else { // there are nodes to the left
if (right === null) { // there are nodes to the left but not to the right
left.setParentNode(parent);
if (parent === null) {
this.topNode = left;
} else {
if (parent.getLeftNode() === tmp) {
parent.setLeftNode(left);
} else {
parent.setRightNode(left);
}
}
} else { // there are nodes to the left and to the right
// Horrific unbalancing about to occur here, please avert your eyes until the Red Black stuff comes
// Make the Left node the new parent
// Move the right node to the right of the rightmost node under the left node
if (parent === null) {
this.topNode = left;
} else {
if (parent.getLeftNode() === tmp) {
parent.setLeftNode(left);
} else {
parent.setRightNode(left);
}
}
left.setParentNode(parent);
let parentOfRight:TreeMapNode = tmp.getLeftNode();
while (parentOfRight.getRightNode() !== null)
parentOfRight = parentOfRight.getRightNode();
parentOfRight.setRightNode(right);
right.setParentNode(parentOfRight);
}
}
tmp.setParentNode(null); // clear pointers to help memory collection
tmp.setLeftNode(null); // clear pointers to help memory collection
tmp.setRightNode(null); // clear pointers to help memory collection
return tmp.getValue();
}
/**
* Returns a key-value mapping associated with the least key greater than or equal to the given key, or null if there is no such key.
* @param {K} key the key
* @return {MapEntry} an entry with the least key greater than or equal to key, or null if there is no such key
*/
public ceilingEntry (key:K) : MapEntry {
if ((this.topNode === null) || (this.topNode === undefined)) return null;
const tmp = this.ceilingNode(this.topNode, key, null);
if (tmp === null) return null;
return tmp.getMapEntry();
}
/**
* Returns the least key greater than or equal to the given key, or null if there is no such key.
* @param {K} key the key
* @return {K} the least key greater than or equal to key, or null if there is no such key
*/
public ceilingKey (key:K) : K {
if ((this.topNode === null) || (this.topNode === undefined)) return null;
const tmp = this.ceilingNode(this.topNode, key, null);
if (tmp === null) return null;
return tmp.getKey();
}
/**
* Returns the least key greater than the given key, or null if there is no such key.
* @param {K} key the key
* @return {K} the least key greater than key, or null if there is no such key
*/
public higherKey (key:K) : K {
if ((this.topNode === null) || (this.topNode === undefined)) return null;
const tmp = this.higherNode(this.topNode, key, null);
if (tmp === null) return null;
return tmp.getKey();
}
/**
* Returns a key-value mapping associated with the least key greater than the given key, or null if there is no such key.
* @param {K} key the key
* @return {MapEntry} an entry with the least key greater than key, or null if there is no such key
*/
public higherEntry (key:K) : MapEntry {
if ((this.topNode === null) || (this.topNode === undefined)) return null;
const tmp = this.higherNode(this.topNode, key, null);
if (tmp === null) return null;
return tmp.getMapEntry();
}
/**
* Returns the highest key lower than the given key, or null if there is no such key.
* @param {K} key the key
* @return {K} the highest key lower than key, or null if there is no such key
*/
public lowerKey (key:K) : K {
if ((this.topNode === null) || (this.topNode === undefined)) return null;
const tmp = this.lowerNode(this.topNode, key, null);
if (tmp === null) return null;
return tmp.getKey();
}
/**
* Returns a key-value mapping associated with the highest key lower than the given key, or null if there is no such key.
* @param {K} key the key
* @return {MapEntry} an entry with the highest key lower than key, or null if there is no such key
*/
public lowerEntry (key:K) : MapEntry {
if ((this.topNode === null) || (this.topNode === undefined)) return null;
const tmp = this.lowerNode(this.topNode, key, null);
if (tmp === null) return null;
return tmp.getMapEntry();
}
/**
* Returns the greatest key less than or equal to the given key, or null if there is no such key.
* @param {K} key the key
* @return {K} the greatest key less than or equal to key, or null if there is no such key
*/
public floorKey (key:K) : K {
if ((this.topNode === null) || (this.topNode === undefined)) return null;
const tmp = this.floorNode(this.topNode, key, null);
if (tmp === null) return null;
return tmp.getKey();
}
/**
* Returns a key-value mapping associated with the greatest key less than or equal to the given key, or null if there is no such key.
* @param {K} key the key
* @return {MapEntry} an entry with the greatest key less than or equal to key, or null if there is no such key
*/
public floorEntry (key:K) : MapEntry {
if ((this.topNode === null) || (this.topNode === undefined)) return null;
const tmp = this.floorNode(this.topNode, key, null);
if (tmp === null) return null;
return tmp.getMapEntry();
}
private ceilingNode (node:TreeMapNode, key:K, currentBest:TreeMapNode) : TreeMapNode {
if ((node === null) || (node === undefined)) {
return currentBest;
}
let tmp = this.mapComparator.compare(node.getKey(), key);
if (tmp === 0) {
return node;
}
if (tmp < 0) { // too low, below key
return this.ceilingNode(node.getRightNode(), key, currentBest);
}
// above key
if (currentBest === null) { // no best node found yet
return this.ceilingNode (node.getLeftNode(), key, node);
}
tmp = this.mapComparator.compare (node.getKey(), currentBest.getKey());
if (tmp > 0) { // this node is higher than the current best
return this.ceilingNode (node.getLeftNode(), key, currentBest);
} else {
return this.ceilingNode (node.getLeftNode(), key, node);
}
}
private higherNode (node:TreeMapNode, key:K, currentBest:TreeMapNode) : TreeMapNode {
if ((node === null) || (node === undefined)) {
return currentBest;
}
let tmp = this.mapComparator.compare(node.getKey(), key);
if (tmp === 0) { // looking for a higher key
return this.higherNode(node.getRightNode(), key, currentBest);
}
if (tmp < 0) { // too low, below key
return this.higherNode(node.getRightNode(), key, currentBest);
}
// above key
if (currentBest === null) { // no best node found yet
return this.higherNode (node.getLeftNode(), key, node);
}
tmp = this.mapComparator.compare (node.getKey(), currentBest.getKey());
if (tmp > 0) { // this node is higher than the current best
return this.higherNode (node.getLeftNode(), key, currentBest);
} else {
return this.higherNode (node.getLeftNode(), key, node);
}
}
private lowerNode (node:TreeMapNode, key:K, currentBest:TreeMapNode) : TreeMapNode {
if ((node === null) || (node === undefined)) {
return currentBest;
}
let tmp = this.mapComparator.compare(node.getKey(), key);
if (tmp === 0) { // looking for a lower key
return this.lowerNode(node.getLeftNode(), key, currentBest);
}
if (tmp > 0) { // too high, above key
return this.lowerNode(node.getLeftNode(), key, currentBest);
}
// above key
if (currentBest === null) { // no best node found yet
return this.lowerNode (node.getRightNode(), key, node);
}
tmp = this.mapComparator.compare (node.getKey(), currentBest.getKey());
if (tmp > 0) { // this node is lower than the current best
return this.lowerNode (node.getRightNode(), key, node);
} else {
return this.lowerNode (node.getRightNode(), key, currentBest);
}
}
private floorNode (node:TreeMapNode, key:K, currentBest:TreeMapNode) : TreeMapNode {
if ((node === null) || (node === undefined)) {
return currentBest;
}
let tmp = this.mapComparator.compare(node.getKey(), key);
if (tmp === 0) {
return node;
}
if (tmp > 0) { // too high, above key
return this.floorNode(node.getLeftNode(), key, currentBest);
}
// above key
if (currentBest === null) { // no best node found yet
return this.floorNode (node.getRightNode(), key, node);
}
tmp = this.mapComparator.compare (node.getKey(), currentBest.getKey());
if (tmp > 0) { // this node is lower than the current best
return this.floorNode (node.getRightNode(), key, node);
} else {
return this.floorNode (node.getRightNode(), key, currentBest);
}
}
/**
* Returns the first (lowest) node currently in this map.
* @return {TreeMapNode} the first (lowest) node currently in this map, returns null if the Map is empty
*/
private firstMapNode () : TreeMapNode {
if ((this.topNode === null) || (this.topNode === undefined))
return null;
let node:TreeMapNode = this.topNode;
while ((node.getLeftNode() !== null) && (node.getLeftNode() !== undefined)) {
node = node.getLeftNode();
}
return node;
}
/**
* Returns the first (lowest) key currently in this map.
* @return {K} the first (lowest) key currently in this map, returns null if the Map is empty
*/
public firstKey () : K {
const node:TreeMapNode = this.firstMapNode();
if ((node === null) || (node === undefined))
return null;
return node.getKey();
}
/**
* Returns a key-value mapping associated with the least key in this map, or null if the map is empty.
* @return {MapEntry} an entry with the least key, or null if this map is empty
*/
public firstEntry () : MapEntry {
const node:TreeMapNode = this.firstMapNode();
if ((node === null) || (node === undefined))
return null;
return node.getMapEntry();
}
/**
* Returns the last (highest) node currently in this map.
* @return {TreeMapNode} the last (highest) node currently in this map, returns null if the Map is empty
*/
private lastMapNode () : TreeMapNode {
if ((this.topNode === null) || (this.topNode === undefined))
return null;
let node:TreeMapNode = this.topNode;
while ((node.getRightNode() !== null) && (node.getRightNode() !== undefined)) {
node = node.getRightNode();
}
return node;
}
/**
* Returns the last (highest) key currently in this map.
* @return {K} the last (highest) key currently in this map, returns null if the Map is empty
*/
public lastKey () : K {
const node:TreeMapNode = this.lastMapNode();
if ((node === null) || (node === undefined))
return null;
return node.getKey();
}
/**
* Returns a key-value mapping associated with the least key in this map, or null if the map is empty.
* @return {MapEntry} an entry with the greatest key, or null if this map is empty
*/
public lastEntry () : MapEntry {
const node:TreeMapNode = this.lastMapNode();
if ((node === null) || (node === undefined))
return null;
return node.getMapEntry();
}
/**
* Returns an ImmutableSet view of the keys contained in this map.
* The set's iterator returns the keys in ascending order.
* The set is backed by the map, so changes to the map are reflected in the set.
* If the map is modified while an iteration over the set is in progress the results of the iteration are undefined.
* @return {MapEntry} an entry with the greatest key, or null if this map is empty
*/
public keySet () : ImmutableSet {
return new ImmutableKeySetForTreeMap (this);
}
/**
* Returns an ImmutableSet view of the mappings contained in this map.
* The set's iterator returns the mappings in ascending key order.
* The set is backed by the map, so changes to the map are reflected in the set.
* If the map is modified while an iteration over the set is in progress the results of the iteration are undefined.
* The contains method on this entrySet will only compare keys not values.
* @return {MapEntry} an entry with the greatest key, or null if this map is empty
*/
public entrySet () : ImmutableSet> {
return new ImmutableEntrySetForTreeMap(this);
}
/**
* Returns an ImmutableMap backed by Map
*/
public immutableMap () : ImmutableMap {
return this;
}
/**
* Override JSON.stringify handling
*/
public toJSON () : Array> {
const tmp = Collections.asArrayMap(this);
return tmp;
}
}
export class TreeMapNode {
private key:K;
private value:V;
private leftNode:TreeMapNode;
private rightNode:TreeMapNode;
private parentNode:TreeMapNode;
public constructor(iKey:K, iValue:V, iParent:TreeMapNode) {
this.key = iKey;
this.value = iValue;
this.leftNode = null;
this.rightNode = null;
this.parentNode = iParent;
}
public getKey ():K {
return this.key;
}
public getValue ():V {
return this.value;
}
public setValue (v:V): void {
this.value = v;
}
public getLeftNode(): TreeMapNode {
return this.leftNode;
}
public setLeftNode(n:TreeMapNode): void {
this.leftNode = n;
}
public getRightNode(): TreeMapNode {
return this.rightNode;
}
public setRightNode(n:TreeMapNode): void {
this.rightNode = n;
}
public getParentNode(): TreeMapNode {
return this.parentNode;
}
public setParentNode(n:TreeMapNode): void {
this.parentNode = n;
}
public getMapEntry(): MapEntry {
return new BasicMapEntry(this.key, this.value);
}
}
export class ImmutableKeySetForTreeMap implements ImmutableSet {
private treeMap:TreeMap;
constructor(iTreeMap:TreeMap) {
this.treeMap = iTreeMap;
}
public size():number { return this.treeMap.size(); }
public isEmpty():boolean { return this.treeMap.isEmpty(); }
public contains(item:K) : boolean { return this.treeMap.containsKey (item); }
public iterator():JIterator { return new TreeMapKeySetJIterator(this.treeMap); }
public [Symbol.iterator] ():Iterator { return new TreeMapKeySetIterator (this.treeMap); }
public forEach(consumer:Consumer) : void {
for (const iter:JIterator = this.iterator(); iter.hasNext(); ) {
const t:K = iter.next();
consumer.accept(t);
}
}
}
/* Java style iterator */
export class TreeMapKeySetJIterator implements JIterator {
private location:K;
private treeMap:TreeMap;
constructor(iTreeMap:TreeMap) {
this.treeMap = iTreeMap;
}
public hasNext():boolean {
if (this.location === undefined) { // first time caller
const first:K = this.treeMap.firstKey();
if (first === undefined)
return false;
if (first === null)
return false;
return true;
} else { // we've already called this iterator before
const tmp:K = this.treeMap.getNextHigherKey(this.location);
if (tmp === null) {
return false;
} else {
return true;
}
}
}
public next():K {
if (this.location === undefined) { // first time caller
const first:K = this.treeMap.firstKey();
if (first === undefined) {
return null;
} else {
this.location = first;
return first;
}
} else { // we've already called this iterator before
const tmp:K = this.treeMap.getNextHigherKey(this.location);
if (tmp === null) {
return null;
} else {
this.location = tmp;
return tmp;
}
}
}
}
/* TypeScript iterator */
export class TreeMapKeySetIterator implements Iterator {
private location:K;
private treeMap:TreeMap;
constructor(iTreeMap:TreeMap) {
this.treeMap = iTreeMap;
this.location = this.treeMap.firstKey();
}
// tslint:disable-next-line:no-any
public next(value?: any): IteratorResult {
if (this.location === null) {
return new BasicIteratorResult(true, null);
}
if (this.location === undefined) {
return new BasicIteratorResult(true, null);
}
const tmp:BasicIteratorResult = new BasicIteratorResult (false, this.location);
this.location = this.treeMap.getNextHigherKey(this.location);
return tmp;
}
}
export class ImmutableEntrySetForTreeMap implements ImmutableSet> {
private treeMap:TreeMap;
constructor(iTreeMap:TreeMap) {
this.treeMap = iTreeMap;
}
public size():number { return this.treeMap.size(); }
public isEmpty():boolean { return this.treeMap.isEmpty(); }
public contains(item:MapEntry) : boolean { return this.treeMap.containsKey (item.getKey()); }
public iterator():JIterator> { return new TreeMapEntrySetJIterator(this.treeMap); }
public [Symbol.iterator] ():Iterator> { return new TreeMapEntrySetIterator (this.treeMap); }
public forEach(consumer:Consumer>) : void {
for (const iter:JIterator> = this.iterator(); iter.hasNext(); ) {
const t:MapEntry = iter.next();
consumer.accept(t);
}
}
}
/* Java style iterator */
export class TreeMapEntrySetJIterator implements JIterator> {
private location:MapEntry;
private treeMap:TreeMap;
constructor(iTreeMap:TreeMap) {
this.treeMap = iTreeMap;
}
public hasNext():boolean {
if (this.location === undefined) { // first time caller
const first:MapEntry = this.treeMap.firstEntry();
if (first === undefined)
return false;
if (first === null)
return false;
return true;
} else { // we've already called this iterator before
const tmp:MapEntry = this.treeMap.higherEntry(this.location.getKey());
if (tmp === null) {
return false;
} else {
return true;
}
}
}
public next():MapEntry {
if (this.location === undefined) { // first time caller
const first:MapEntry = this.treeMap.firstEntry();
if (first === undefined) {
return null;
} else {
this.location = first;
return first;
}
} else { // we've already called this iterator before
const tmp:MapEntry = this.treeMap.higherEntry(this.location.getKey());
if (tmp === null) {
return null;
} else {
this.location = tmp;
return tmp;
}
}
}
}
/* TypeScript iterator */
export class TreeMapEntrySetIterator implements Iterator> {
private location:MapEntry;
private treeMap:TreeMap;
constructor(iTreeMap:TreeMap) {
this.treeMap = iTreeMap;
this.location = this.treeMap.firstEntry();
}
// tslint:disable-next-line:no-any
public next(value?: any): IteratorResult> {
if (this.location === null) {
return new BasicIteratorResult(true, null);
}
if (this.location === undefined) {
return new BasicIteratorResult(true, null);
}
const tmp:BasicIteratorResult> = new BasicIteratorResult (false, this.location);
this.location = this.treeMap.higherEntry(this.location.getKey());
return tmp;
}
}