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;
|