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.
		
		
		
		
		
			
		
			
				
					
					
						
							196 lines
						
					
					
						
							3.8 KiB
						
					
					
				
			
		
		
	
	
							196 lines
						
					
					
						
							3.8 KiB
						
					
					
				/**
 | 
						|
 * Mnemonist BiMap
 | 
						|
 * ================
 | 
						|
 *
 | 
						|
 * JavaScript implementation of a BiMap.
 | 
						|
 */
 | 
						|
var forEach = require('obliterator/foreach');
 | 
						|
 | 
						|
/**
 | 
						|
 * Inverse Map.
 | 
						|
 *
 | 
						|
 * @constructor
 | 
						|
 */
 | 
						|
function InverseMap(original) {
 | 
						|
 | 
						|
  this.size = 0;
 | 
						|
  this.items = new Map();
 | 
						|
  this.inverse = original;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * BiMap.
 | 
						|
 *
 | 
						|
 * @constructor
 | 
						|
 */
 | 
						|
function BiMap() {
 | 
						|
 | 
						|
  this.size = 0;
 | 
						|
  this.items = new Map();
 | 
						|
  this.inverse = new InverseMap(this);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Method used to clear the map.
 | 
						|
 *
 | 
						|
 * @return {undefined}
 | 
						|
 */
 | 
						|
function clear() {
 | 
						|
  this.size = 0;
 | 
						|
  this.items.clear();
 | 
						|
  this.inverse.items.clear();
 | 
						|
}
 | 
						|
 | 
						|
BiMap.prototype.clear = clear;
 | 
						|
InverseMap.prototype.clear = clear;
 | 
						|
 | 
						|
/**
 | 
						|
 * Method used to set a relation.
 | 
						|
 *
 | 
						|
 * @param  {any} key - Key.
 | 
						|
 * @param  {any} value - Value.
 | 
						|
 * @return {BiMap|InverseMap}
 | 
						|
 */
 | 
						|
function set(key, value) {
 | 
						|
 | 
						|
  // First we need to attempt to see if the relation is not flawed
 | 
						|
  if (this.items.has(key)) {
 | 
						|
    var currentValue = this.items.get(key);
 | 
						|
 | 
						|
    // The relation already exists, we do nothing
 | 
						|
    if (currentValue === value)
 | 
						|
      return this;
 | 
						|
    else
 | 
						|
      this.inverse.items.delete(currentValue);
 | 
						|
  }
 | 
						|
 | 
						|
  if (this.inverse.items.has(value)) {
 | 
						|
    var currentKey = this.inverse.items.get(value);
 | 
						|
 | 
						|
    if (currentKey === key)
 | 
						|
      return this;
 | 
						|
    else
 | 
						|
      this.items.delete(currentKey);
 | 
						|
  }
 | 
						|
 | 
						|
  // Here we actually add the relation
 | 
						|
  this.items.set(key, value);
 | 
						|
  this.inverse.items.set(value, key);
 | 
						|
 | 
						|
  // Size
 | 
						|
  this.size = this.items.size;
 | 
						|
  this.inverse.size = this.inverse.items.size;
 | 
						|
 | 
						|
  return this;
 | 
						|
}
 | 
						|
 | 
						|
BiMap.prototype.set = set;
 | 
						|
InverseMap.prototype.set = set;
 | 
						|
 | 
						|
/**
 | 
						|
 * Method used to delete a relation.
 | 
						|
 *
 | 
						|
 * @param  {any} key - Key.
 | 
						|
 * @return {boolean}
 | 
						|
 */
 | 
						|
function del(key) {
 | 
						|
  if (this.items.has(key)) {
 | 
						|
    var currentValue = this.items.get(key);
 | 
						|
 | 
						|
    this.items.delete(key);
 | 
						|
    this.inverse.items.delete(currentValue);
 | 
						|
 | 
						|
    // Size
 | 
						|
    this.size = this.items.size;
 | 
						|
    this.inverse.size = this.inverse.items.size;
 | 
						|
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
BiMap.prototype.delete = del;
 | 
						|
InverseMap.prototype.delete = del;
 | 
						|
 | 
						|
/**
 | 
						|
 * Mapping some Map prototype function unto our two classes.
 | 
						|
 */
 | 
						|
var METHODS = ['has', 'get', 'forEach', 'keys', 'values', 'entries'];
 | 
						|
 | 
						|
METHODS.forEach(function(name) {
 | 
						|
  BiMap.prototype[name] = InverseMap.prototype[name] = function() {
 | 
						|
    return Map.prototype[name].apply(this.items, arguments);
 | 
						|
  };
 | 
						|
});
 | 
						|
 | 
						|
/**
 | 
						|
 * Attaching the #.values method to Symbol.iterator if possible.
 | 
						|
 */
 | 
						|
if (typeof Symbol !== 'undefined') {
 | 
						|
  BiMap.prototype[Symbol.iterator] = BiMap.prototype.entries;
 | 
						|
  InverseMap.prototype[Symbol.iterator] = InverseMap.prototype.entries;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Convenience known methods.
 | 
						|
 */
 | 
						|
BiMap.prototype.inspect = function() {
 | 
						|
  var dummy = {
 | 
						|
    left: this.items,
 | 
						|
    right: this.inverse.items
 | 
						|
  };
 | 
						|
 | 
						|
  // Trick so that node displays the name of the constructor
 | 
						|
  Object.defineProperty(dummy, 'constructor', {
 | 
						|
    value: BiMap,
 | 
						|
    enumerable: false
 | 
						|
  });
 | 
						|
 | 
						|
  return dummy;
 | 
						|
};
 | 
						|
 | 
						|
if (typeof Symbol !== 'undefined')
 | 
						|
  BiMap.prototype[Symbol.for('nodejs.util.inspect.custom')] = BiMap.prototype.inspect;
 | 
						|
 | 
						|
InverseMap.prototype.inspect = function() {
 | 
						|
  var dummy = {
 | 
						|
    left: this.inverse.items,
 | 
						|
    right: this.items
 | 
						|
  };
 | 
						|
 | 
						|
  // Trick so that node displays the name of the constructor
 | 
						|
  Object.defineProperty(dummy, 'constructor', {
 | 
						|
    value: InverseMap,
 | 
						|
    enumerable: false
 | 
						|
  });
 | 
						|
 | 
						|
  return dummy;
 | 
						|
};
 | 
						|
 | 
						|
if (typeof Symbol !== 'undefined')
 | 
						|
  InverseMap.prototype[Symbol.for('nodejs.util.inspect.custom')] = InverseMap.prototype.inspect;
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Static @.from function taking an arbitrary iterable & converting it into
 | 
						|
 * a bimap.
 | 
						|
 *
 | 
						|
 * @param  {Iterable} iterable - Target iterable.
 | 
						|
 * @return {BiMap}
 | 
						|
 */
 | 
						|
BiMap.from = function(iterable) {
 | 
						|
  var bimap = new BiMap();
 | 
						|
 | 
						|
  forEach(iterable, function(value, key) {
 | 
						|
    bimap.set(key, value);
 | 
						|
  });
 | 
						|
 | 
						|
  return bimap;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Exporting.
 | 
						|
 */
 | 
						|
module.exports = BiMap;
 |