UNPKG

bidi-map

Version:

A library that extends native ES6 Map to bi-directional map.

188 lines (159 loc) 4.33 kB
'use strict'; exports.__esModule = true; exports.default = BidiMap; /** * Copyright 2017 Moshe Simantov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * A Bidirectional Map * @module bidi-map */ var kReverseMap = Symbol('reverseMap'); // Extending Map native class with the following method: // https://stackoverflow.com/a/45312985/518153 /** * Create a new instance of the bidirectional-map * * @param {Iterable.<Array>} [iterable] An iterable object * @template K, V * @constructor * @extends Map * @alias module:bidi-map */ function BidiMap() { var iterable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; if (!(this instanceof BidiMap)) { throw new TypeError("Constructor BidiMap requires 'new'"); } var self = Object.getPrototypeOf(this) === Map.prototype ? this : new Map(); Object.setPrototypeOf(self, BidiMap.prototype); self[kReverseMap] = new Map(); // We want to preserve Map native implementation with for-of loop // eslint-disable-next-line no-restricted-syntax for (var _iterator = iterable, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { var _ref2; if (_isArray) { if (_i >= _iterator.length) break; _ref2 = _iterator[_i++]; } else { _i = _iterator.next(); if (_i.done) break; _ref2 = _i.value; } var _ref = _ref2; var key = _ref[0]; var value = _ref[1]; self.set(key, value); } return self; } BidiMap.prototype = Object.create(Map.prototype); /** * Get the number of differed values in this map * * @member {number} count * @memberOf module:bidi-map# * @readonly */ Object.defineProperty(BidiMap.prototype, 'count', { configurable: true, get: function get() { return this[kReverseMap].size; } }); /** * Inherits from `Map.set` method. * * @param {K} key * @param {V} value * @return {Map.<K, V>} */ BidiMap.prototype.set = function set(key, value) { this.delete(key); Map.prototype.set.call(this, key, value); var lookup = this[kReverseMap].get(value); if (!lookup) { lookup = [key]; this[kReverseMap].set(value, lookup); } else { lookup.push(key); } return this; }; /** * Check if the map has the given value. * * @param {V} value The given value * @return {boolean} */ BidiMap.prototype.exists = function exists(value) { return this[kReverseMap].has(value); }; /** * Get the first key of the given value or `undefined` if not exists. * * @param {V} value * @return {K} */ BidiMap.prototype.getKeyOf = function getKeyOf(value) { var lookup = this[kReverseMap].get(value); return lookup ? lookup[0] : undefined; }; /** * Get the all the keys of the given value. * * @param {V} value * @return {Array<K>} */ BidiMap.prototype.getKeysOf = function getKeysOf(value) { var lookup = this[kReverseMap].get(value); return lookup ? lookup.slice() : []; }; /** * Inherits from `Map.delete` method. * * @param {K} key * @return {boolean} */ BidiMap.prototype.delete = function del(key) { if (!this.has(key)) { return false; } var value = this.get(key); var lookup = this[kReverseMap].get(value); if (lookup.length === 1) { if (lookup[0] !== key) { throw Error('can\'t find property "' + key + '" on the lookup map'); } this[kReverseMap].delete(value); } else { var index = lookup.indexOf(key); if (index === -1) { throw Error('can\'t find property "' + key + '" on the lookup map'); } lookup.splice(index, 1); } Map.prototype.delete.call(this, key); return true; }; /** * Inherits from `Map.clear` method. * * @return {undefined} */ BidiMap.prototype.clear = function clear() { Map.prototype.clear.call(this); this[kReverseMap].clear(); };