123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- "use strict";
- /* global module, define */
- function mapEach(map, operation){
- var keys = map.keys();
- var next;
- while(!(next = keys.next()).done) {
- operation(map.get(next.value), next.value, map);
- }
- }
- var Multimap = (function() {
- var mapCtor;
- if (typeof Map !== 'undefined') {
- mapCtor = Map;
- if (!Map.prototype.keys) {
- Map.prototype.keys = function() {
- var keys = [];
- this.forEach(function(item, key) {
- keys.push(key);
- });
- return keys;
- };
- }
- }
- function Multimap(iterable) {
- var self = this;
- self._map = mapCtor;
- if (Multimap.Map) {
- self._map = Multimap.Map;
- }
- self._ = self._map ? new self._map() : {};
- if (iterable) {
- iterable.forEach(function(i) {
- self.set(i[0], i[1]);
- });
- }
- }
- /**
- * @param {Object} key
- * @return {Array} An array of values, undefined if no such a key;
- */
- Multimap.prototype.get = function(key) {
- return this._map ? this._.get(key) : this._[key];
- };
- /**
- * @param {Object} key
- * @param {Object} val...
- */
- Multimap.prototype.set = function(key, val) {
- var args = Array.prototype.slice.call(arguments);
- key = args.shift();
- var entry = this.get(key);
- if (!entry) {
- entry = [];
- if (this._map)
- this._.set(key, entry);
- else
- this._[key] = entry;
- }
- Array.prototype.push.apply(entry, args);
- return this;
- };
- /**
- * @param {Object} key
- * @param {Object=} val
- * @return {boolean} true if any thing changed
- */
- Multimap.prototype.delete = function(key, val) {
- if (!this.has(key))
- return false;
- if (arguments.length == 1) {
- this._map ? (this._.delete(key)) : (delete this._[key]);
- return true;
- } else {
- var entry = this.get(key);
- var idx = entry.indexOf(val);
- if (idx != -1) {
- entry.splice(idx, 1);
- return true;
- }
- }
- return false;
- };
- /**
- * @param {Object} key
- * @param {Object=} val
- * @return {boolean} whether the map contains 'key' or 'key=>val' pair
- */
- Multimap.prototype.has = function(key, val) {
- var hasKey = this._map ? this._.has(key) : this._.hasOwnProperty(key);
- if (arguments.length == 1 || !hasKey)
- return hasKey;
- var entry = this.get(key) || [];
- return entry.indexOf(val) != -1;
- };
- /**
- * @return {Array} all the keys in the map
- */
- Multimap.prototype.keys = function() {
- if (this._map)
- return makeIterator(this._.keys());
- return makeIterator(Object.keys(this._));
- };
- /**
- * @return {Array} all the values in the map
- */
- Multimap.prototype.values = function() {
- var vals = [];
- this.forEachEntry(function(entry) {
- Array.prototype.push.apply(vals, entry);
- });
- return makeIterator(vals);
- };
- /**
- *
- */
- Multimap.prototype.forEachEntry = function(iter) {
- mapEach(this, iter);
- };
- Multimap.prototype.forEach = function(iter) {
- var self = this;
- self.forEachEntry(function(entry, key) {
- entry.forEach(function(item) {
- iter(item, key, self);
- });
- });
- };
- Multimap.prototype.clear = function() {
- if (this._map) {
- this._.clear();
- } else {
- this._ = {};
- }
- };
- Object.defineProperty(
- Multimap.prototype,
- "size", {
- configurable: false,
- enumerable: true,
- get: function() {
- var total = 0;
- mapEach(this, function(value){
- total += value.length;
- });
- return total;
- }
- });
- Object.defineProperty(
- Multimap.prototype,
- "count", {
- configurable: false,
- enumerable: true,
- get: function() {
- return this._.size;
- }
- });
- var safariNext;
- try{
- safariNext = new Function('iterator', 'makeIterator', 'var keysArray = []; for(var key of iterator){keysArray.push(key);} return makeIterator(keysArray).next;');
- }catch(error){
- // for of not implemented;
- }
- function makeIterator(iterator){
- if(Array.isArray(iterator)){
- var nextIndex = 0;
- return {
- next: function(){
- return nextIndex < iterator.length ?
- {value: iterator[nextIndex++], done: false} :
- {done: true};
- }
- };
- }
- // Only an issue in safari
- if(!iterator.next && safariNext){
- iterator.next = safariNext(iterator, makeIterator);
- }
- return iterator;
- }
- return Multimap;
- })();
- if(typeof exports === 'object' && module && module.exports)
- module.exports = Multimap;
- else if(typeof define === 'function' && define.amd)
- define(function() { return Multimap; });
|