You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					516 lines
				
				10 KiB
			
		
		
			
		
	
	
					516 lines
				
				10 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								/* eslint no-constant-condition: 0 */
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Mnemonist CritBitTreeMap
							 | 
						||
| 
								 | 
							
								 * =========================
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * JavaScript implementation of a crit-bit tree, also called PATRICIA tree.
							 | 
						||
| 
								 | 
							
								 * This tree is a basically a bitwise radix tree and is supposedly much more
							 | 
						||
| 
								 | 
							
								 * efficient than a standard Trie.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * [References]:
							 | 
						||
| 
								 | 
							
								 * https://cr.yp.to/critbit.html
							 | 
						||
| 
								 | 
							
								 * https://www.imperialviolet.org/binary/critbit.pdf
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								var bitwise = require('./utils/bitwise.js');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Helpers.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Helper returning the direction we need to take given a key and an
							 | 
						||
| 
								 | 
							
								 * encoded critbit.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {string} key     - Target key.
							 | 
						||
| 
								 | 
							
								 * @param  {number} critbit - Packed address of byte + mask.
							 | 
						||
| 
								 | 
							
								 * @return {number}         - 0, left or 1, right.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function getDirection(key, critbit) {
							 | 
						||
| 
								 | 
							
								  var byteIndex = critbit >> 8;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (byteIndex > key.length - 1)
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var byte = key.charCodeAt(byteIndex),
							 | 
						||
| 
								 | 
							
								      mask = critbit & 0xff;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return (1 + (byte | mask)) >> 8;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Helper returning the packed address of byte + mask or -1 if strings
							 | 
						||
| 
								 | 
							
								 * are identical.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {string} a      - First key.
							 | 
						||
| 
								 | 
							
								 * @param  {string} b      - Second key.
							 | 
						||
| 
								 | 
							
								 * @return {number}        - Packed address of byte + mask.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function findCriticalBit(a, b) {
							 | 
						||
| 
								 | 
							
								  var i = 0,
							 | 
						||
| 
								 | 
							
								      tmp;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Swapping so a is the shortest
							 | 
						||
| 
								 | 
							
								  if (a.length > b.length) {
							 | 
						||
| 
								 | 
							
								    tmp = b;
							 | 
						||
| 
								 | 
							
								    b = a;
							 | 
						||
| 
								 | 
							
								    a = tmp;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var l = a.length,
							 | 
						||
| 
								 | 
							
								      mask;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while (i < l) {
							 | 
						||
| 
								 | 
							
								    if (a[i] !== b[i]) {
							 | 
						||
| 
								 | 
							
								      mask = bitwise.criticalBit8Mask(
							 | 
						||
| 
								 | 
							
								        a.charCodeAt(i),
							 | 
						||
| 
								 | 
							
								        b.charCodeAt(i)
							 | 
						||
| 
								 | 
							
								      );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return (i << 8) | mask;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    i++;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Strings are identical
							 | 
						||
| 
								 | 
							
								  if (a.length === b.length)
							 | 
						||
| 
								 | 
							
								    return -1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // NOTE: x ^ 0 is the same as x
							 | 
						||
| 
								 | 
							
								  mask = bitwise.criticalBit8Mask(b.charCodeAt(i));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return (i << 8) | mask;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Class representing a crit-bit tree's internal node.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @constructor
							 | 
						||
| 
								 | 
							
								 * @param {number} critbit - Packed address of byte + mask.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function InternalNode(critbit) {
							 | 
						||
| 
								 | 
							
								  this.critbit = critbit;
							 | 
						||
| 
								 | 
							
								  this.left = null;
							 | 
						||
| 
								 | 
							
								  this.right = null;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Class representing a crit-bit tree's external node.
							 | 
						||
| 
								 | 
							
								 * Note that it is possible to replace those nodes by flat arrays.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @constructor
							 | 
						||
| 
								 | 
							
								 * @param {string} key   - Node's key.
							 | 
						||
| 
								 | 
							
								 * @param {any}    value - Arbitrary value.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function ExternalNode(key, value) {
							 | 
						||
| 
								 | 
							
								  this.key = key;
							 | 
						||
| 
								 | 
							
								  this.value = value;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * CritBitTreeMap.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @constructor
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function CritBitTreeMap() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Properties
							 | 
						||
| 
								 | 
							
								  this.root = null;
							 | 
						||
| 
								 | 
							
								  this.size = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.clear();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to clear the CritBitTreeMap.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @return {undefined}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								CritBitTreeMap.prototype.clear = function() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Properties
							 | 
						||
| 
								 | 
							
								  this.root = null;
							 | 
						||
| 
								 | 
							
								  this.size = 0;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to set the value of the given key in the trie.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {string}         key   - Key to set.
							 | 
						||
| 
								 | 
							
								 * @param  {any}            value - Arbitrary value.
							 | 
						||
| 
								 | 
							
								 * @return {CritBitTreeMap}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								CritBitTreeMap.prototype.set = function(key, value) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Tree is empty
							 | 
						||
| 
								 | 
							
								  if (this.size === 0) {
							 | 
						||
| 
								 | 
							
								    this.root = new ExternalNode(key, value);
							 | 
						||
| 
								 | 
							
								    this.size++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return this;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Walk state
							 | 
						||
| 
								 | 
							
								  var node = this.root,
							 | 
						||
| 
								 | 
							
								      ancestors = [],
							 | 
						||
| 
								 | 
							
								      path = [],
							 | 
						||
| 
								 | 
							
								      ancestor,
							 | 
						||
| 
								 | 
							
								      parent,
							 | 
						||
| 
								 | 
							
								      child,
							 | 
						||
| 
								 | 
							
								      critbit,
							 | 
						||
| 
								 | 
							
								      internal,
							 | 
						||
| 
								 | 
							
								      left,
							 | 
						||
| 
								 | 
							
								      leftPath,
							 | 
						||
| 
								 | 
							
								      best,
							 | 
						||
| 
								 | 
							
								      dir,
							 | 
						||
| 
								 | 
							
								      i,
							 | 
						||
| 
								 | 
							
								      l;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Walking the tree
							 | 
						||
| 
								 | 
							
								  while (true) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Traversing an internal node
							 | 
						||
| 
								 | 
							
								    if (node instanceof InternalNode) {
							 | 
						||
| 
								 | 
							
								      dir = getDirection(key, node.critbit);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // Going left & creating key if not yet there
							 | 
						||
| 
								 | 
							
								      if (dir === 0) {
							 | 
						||
| 
								 | 
							
								        if (!node.left) {
							 | 
						||
| 
								 | 
							
								          node.left = new ExternalNode(key, value);
							 | 
						||
| 
								 | 
							
								          return this;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ancestors.push(node);
							 | 
						||
| 
								 | 
							
								        path.push(true);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        node = node.left;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // Going right & creating key if not yet there
							 | 
						||
| 
								 | 
							
								      else {
							 | 
						||
| 
								 | 
							
								        if (!node.right) {
							 | 
						||
| 
								 | 
							
								          node.right = new ExternalNode(key, value);
							 | 
						||
| 
								 | 
							
								          return this;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ancestors.push(node);
							 | 
						||
| 
								 | 
							
								        path.push(false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        node = node.right;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Reaching an external node
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // 1. Creating a new external node
							 | 
						||
| 
								 | 
							
								      critbit = findCriticalBit(key, node.key);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // Key is identical, we just replace the value
							 | 
						||
| 
								 | 
							
								      if (critbit === -1) {
							 | 
						||
| 
								 | 
							
								        node.value = value;
							 | 
						||
| 
								 | 
							
								        return this;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      this.size++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      internal = new InternalNode(critbit);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      left = getDirection(key, critbit) === 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // TODO: maybe setting opposite pointer is not necessary
							 | 
						||
| 
								 | 
							
								      if (left) {
							 | 
						||
| 
								 | 
							
								        internal.left = new ExternalNode(key, value);
							 | 
						||
| 
								 | 
							
								        internal.right = node;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      else {
							 | 
						||
| 
								 | 
							
								        internal.left = node;
							 | 
						||
| 
								 | 
							
								        internal.right = new ExternalNode(key, value);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // 2. Bubbling up
							 | 
						||
| 
								 | 
							
								      best = -1;
							 | 
						||
| 
								 | 
							
								      l = ancestors.length;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      for (i = l - 1; i >= 0; i--) {
							 | 
						||
| 
								 | 
							
								        ancestor = ancestors[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (ancestor.critbit > critbit)
							 | 
						||
| 
								 | 
							
								          continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        best = i;
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // Do we need to attach to the root?
							 | 
						||
| 
								 | 
							
								      if (best < 0) {
							 | 
						||
| 
								 | 
							
								        this.root = internal;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Need to rewire parent as child?
							 | 
						||
| 
								 | 
							
								        if (l > 0) {
							 | 
						||
| 
								 | 
							
								          parent = ancestors[0];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          if (left)
							 | 
						||
| 
								 | 
							
								            internal.right = parent;
							 | 
						||
| 
								 | 
							
								          else
							 | 
						||
| 
								 | 
							
								            internal.left = parent;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // Simple case without rotation
							 | 
						||
| 
								 | 
							
								      else if (best === l - 1) {
							 | 
						||
| 
								 | 
							
								        parent = ancestors[best];
							 | 
						||
| 
								 | 
							
								        leftPath = path[best];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (leftPath)
							 | 
						||
| 
								 | 
							
								          parent.left = internal;
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								          parent.right = internal;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // Full rotation
							 | 
						||
| 
								 | 
							
								      else {
							 | 
						||
| 
								 | 
							
								        parent = ancestors[best];
							 | 
						||
| 
								 | 
							
								        leftPath = path[best];
							 | 
						||
| 
								 | 
							
								        child = ancestors[best + 1];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (leftPath)
							 | 
						||
| 
								 | 
							
								          parent.left = internal;
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								          parent.right = internal;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (left)
							 | 
						||
| 
								 | 
							
								          internal.right = child;
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								          internal.left = child;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return this;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to get the value attached to the given key in the tree or
							 | 
						||
| 
								 | 
							
								 * undefined if not found.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {string} key   - Key to get.
							 | 
						||
| 
								 | 
							
								 * @return {any}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								CritBitTreeMap.prototype.get = function(key) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Walk state
							 | 
						||
| 
								 | 
							
								  var node = this.root,
							 | 
						||
| 
								 | 
							
								      dir;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Walking the tree
							 | 
						||
| 
								 | 
							
								  while (true) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Dead end
							 | 
						||
| 
								 | 
							
								    if (node === null)
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Traversing an internal node
							 | 
						||
| 
								 | 
							
								    if (node instanceof InternalNode) {
							 | 
						||
| 
								 | 
							
								      dir = getDirection(key, node.critbit);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      node = dir ? node.right : node.left;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Reaching an external node
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								      if (node.key !== key)
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return node.value;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to return whether the given key exists in the tree.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {string} key - Key to test.
							 | 
						||
| 
								 | 
							
								 * @return {boolean}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								CritBitTreeMap.prototype.has = function(key) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Walk state
							 | 
						||
| 
								 | 
							
								  var node = this.root,
							 | 
						||
| 
								 | 
							
								      dir;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Walking the tree
							 | 
						||
| 
								 | 
							
								  while (true) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Dead end
							 | 
						||
| 
								 | 
							
								    if (node === null)
							 | 
						||
| 
								 | 
							
								      return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Traversing an internal node
							 | 
						||
| 
								 | 
							
								    if (node instanceof InternalNode) {
							 | 
						||
| 
								 | 
							
								      dir = getDirection(key, node.critbit);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      node = dir ? node.right : node.left;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Reaching an external node
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								      return node.key === key;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to delete the given key from the tree and return whether the
							 | 
						||
| 
								 | 
							
								 * key did exist or not.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {string} key - Key to delete.
							 | 
						||
| 
								 | 
							
								 * @return {boolean}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								CritBitTreeMap.prototype.delete = function(key) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Walk state
							 | 
						||
| 
								 | 
							
								  var node = this.root,
							 | 
						||
| 
								 | 
							
								      dir;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var parent = null,
							 | 
						||
| 
								 | 
							
								      grandParent = null,
							 | 
						||
| 
								 | 
							
								      wentLeftForParent = false,
							 | 
						||
| 
								 | 
							
								      wentLeftForGrandparent = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Walking the tree
							 | 
						||
| 
								 | 
							
								  while (true) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Dead end
							 | 
						||
| 
								 | 
							
								    if (node === null)
							 | 
						||
| 
								 | 
							
								      return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Traversing an internal node
							 | 
						||
| 
								 | 
							
								    if (node instanceof InternalNode) {
							 | 
						||
| 
								 | 
							
								      dir = getDirection(key, node.critbit);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (dir === 0) {
							 | 
						||
| 
								 | 
							
								        grandParent = parent;
							 | 
						||
| 
								 | 
							
								        wentLeftForGrandparent = wentLeftForParent;
							 | 
						||
| 
								 | 
							
								        parent = node;
							 | 
						||
| 
								 | 
							
								        wentLeftForParent = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        node = node.left;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      else {
							 | 
						||
| 
								 | 
							
								        grandParent = parent;
							 | 
						||
| 
								 | 
							
								        wentLeftForGrandparent = wentLeftForParent;
							 | 
						||
| 
								 | 
							
								        parent = node;
							 | 
						||
| 
								 | 
							
								        wentLeftForParent = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        node = node.right;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Reaching an external node
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								      if (key !== node.key)
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      this.size--;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // Rewiring
							 | 
						||
| 
								 | 
							
								      if (parent === null) {
							 | 
						||
| 
								 | 
							
								        this.root = null;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      else if (grandParent === null) {
							 | 
						||
| 
								 | 
							
								        if (wentLeftForParent)
							 | 
						||
| 
								 | 
							
								          this.root = parent.right;
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								          this.root = parent.left;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      else {
							 | 
						||
| 
								 | 
							
								        if (wentLeftForGrandparent) {
							 | 
						||
| 
								 | 
							
								          if (wentLeftForParent) {
							 | 
						||
| 
								 | 
							
								            grandParent.left = parent.right;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								          else {
							 | 
						||
| 
								 | 
							
								            grandParent.left = parent.left;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else {
							 | 
						||
| 
								 | 
							
								          if (wentLeftForParent) {
							 | 
						||
| 
								 | 
							
								            grandParent.right = parent.right;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								          else {
							 | 
						||
| 
								 | 
							
								            grandParent.right = parent.left;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to iterate over the tree in key order.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {function}  callback - Function to call for each item.
							 | 
						||
| 
								 | 
							
								 * @param  {object}    scope    - Optional scope.
							 | 
						||
| 
								 | 
							
								 * @return {undefined}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								CritBitTreeMap.prototype.forEach = function(callback, scope) {
							 | 
						||
| 
								 | 
							
								  scope = arguments.length > 1 ? scope : this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Inorder traversal of the tree
							 | 
						||
| 
								 | 
							
								  var current = this.root,
							 | 
						||
| 
								 | 
							
								      stack = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while (true) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (current !== null) {
							 | 
						||
| 
								 | 
							
								      stack.push(current);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      current = current instanceof InternalNode ? current.left : null;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								      if (stack.length > 0) {
							 | 
						||
| 
								 | 
							
								        current = stack.pop();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (current instanceof ExternalNode)
							 | 
						||
| 
								 | 
							
								          callback.call(scope, current.value, current.key);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        current = current instanceof InternalNode ? current.right : null;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      else {
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Convenience known methods.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								CritBitTreeMap.prototype.inspect = function() {
							 | 
						||
| 
								 | 
							
								  return this;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if (typeof Symbol !== 'undefined')
							 | 
						||
| 
								 | 
							
								  CritBitTreeMap.prototype[Symbol.for('nodejs.util.inspect.custom')] = CritBitTreeMap.prototype.inspect;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Static @.from function taking an arbitrary iterable & converting it into
							 | 
						||
| 
								 | 
							
								 * a CritBitTreeMap.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {Iterable} iterable - Target iterable.
							 | 
						||
| 
								 | 
							
								 * @return {CritBitTreeMap}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								// CritBitTreeMap.from = function(iterable) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Exporting.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								module.exports = CritBitTreeMap;
							 |