UNPKG

3.85 kBJavaScriptView Raw
1"use strict";
2
3/* global module, define */
4
5var Multimap = (function() {
6 var mapCtor;
7 if (typeof Map !== 'undefined') {
8 mapCtor = Map;
9 }
10
11 function Multimap(iterable) {
12 var self = this;
13
14 self._map = mapCtor;
15
16 if (Multimap.Map) {
17 self._map = Multimap.Map;
18 }
19
20 self._ = self._map ? new self._map() : {};
21
22 if (iterable) {
23 iterable.forEach(function(i) {
24 self.set(i[0], i[1]);
25 });
26 }
27 }
28
29 /**
30 * @param {Object} key
31 * @return {Array} An array of values, undefined if no such a key;
32 */
33 Multimap.prototype.get = function(key) {
34 return this._map ? this._.get(key) : this._[key];
35 };
36
37 /**
38 * @param {Object} key
39 * @param {Object} val...
40 */
41 Multimap.prototype.set = function(key, val) {
42 var args = Array.prototype.slice.call(arguments);
43
44 key = args.shift();
45
46 var entry = this.get(key);
47 if (!entry) {
48 entry = [];
49 if (this._map)
50 this._.set(key, entry);
51 else
52 this._[key] = entry;
53 }
54
55 Array.prototype.push.apply(entry, args);
56 return this;
57 };
58
59 /**
60 * @param {Object} key
61 * @param {Object=} val
62 * @return {boolean} true if any thing changed
63 */
64 Multimap.prototype.delete = function(key, val) {
65 if (!this.has(key))
66 return false;
67
68 if (arguments.length == 1) {
69 this._map ? (this._.delete(key)) : (delete this._[key]);
70 return true;
71 } else {
72 var entry = this.get(key);
73 var idx = entry.indexOf(val);
74 if (idx != -1) {
75 entry.splice(idx, 1);
76 return true;
77 }
78 }
79
80 return false;
81 };
82
83 /**
84 * @param {Object} key
85 * @param {Object=} val
86 * @return {boolean} whether the map contains 'key' or 'key=>val' pair
87 */
88 Multimap.prototype.has = function(key, val) {
89 var hasKey = this._map ? this._.has(key) : this._.hasOwnProperty(key);
90
91 if (arguments.length == 1 || !hasKey)
92 return hasKey;
93
94 var entry = this.get(key) || [];
95 return entry.indexOf(val) != -1;
96 };
97
98 /**
99 * @return {Array} all the keys in the map
100 */
101 Multimap.prototype.keys = function() {
102 if (this._map)
103 return this._.keys();
104
105 return makeIterator(Object.keys(this._));
106 };
107
108 /**
109 * @return {Array} all the values in the map
110 */
111 Multimap.prototype.values = function() {
112 var vals = [];
113 this.forEachEntry(function(entry) {
114 Array.prototype.push.apply(vals, entry);
115 });
116
117 return makeIterator(vals);
118 };
119
120 /**
121 *
122 */
123 Multimap.prototype.forEachEntry = function(iter) {
124 var self = this;
125
126 var keys = self.keys();
127 var next;
128 while(!(next = keys.next()).done) {
129 iter(self.get(next.value), next.value, self);
130 }
131 };
132
133 Multimap.prototype.forEach = function(iter) {
134 var self = this;
135 self.forEachEntry(function(entry, key) {
136 entry.forEach(function(item) {
137 iter(item, key, self);
138 });
139 });
140 };
141
142
143 Multimap.prototype.clear = function() {
144 if (this._map) {
145 this._.clear();
146 } else {
147 this._ = {};
148 }
149 };
150
151 Object.defineProperty(
152 Multimap.prototype,
153 "size", {
154 configurable: false,
155 enumerable: true,
156 get: function() {
157 var self = this;
158 var keys = self.keys();
159 var next, total = 0;
160 while(!(next = keys.next()).done) {
161 total += self.get(next.value).length;
162 }
163 return total;
164 }
165 });
166
167
168 function makeIterator(array){
169 var nextIndex = 0;
170
171 return {
172 next: function(){
173 return nextIndex < array.length ?
174 {value: array[nextIndex++], done: false} :
175 {done: true};
176 }
177 };
178 }
179
180 return Multimap;
181})();
182
183
184if(typeof exports === 'object' && module && module.exports)
185 module.exports = Multimap;
186else if(typeof define === 'function' && define.amd)
187 define(function() { return Multimap; });