export default class MultiMap {
constructor(items = []) {
this._map = new Map;
for (let [key, value] of items)
this.set(key, value);
}
// Public
get size() {
return this._map.size;
}
has(key, value) {
let valueSet = this._map.get(key);
if (!valueSet)
return false;
return arguments.length === 1 || valueSet.has(value);
}
get(key) {
return this._map.get(key) || new Set;
}
set(key, value) {
let valueSet = this._map.get(key);
if (!valueSet) {
valueSet = new Set;
this._map.set(key, valueSet);
}
valueSet.add(value);
return this;
}
delete(key, value) {
if (arguments.length === 1)
return this._map.delete(key);
let valueSet = this._map.get(key);
if (!valueSet)
return false;
let deletedValue = valueSet.delete(value);
if (!valueSet.size) {
let deletedKey = this._map.delete(key);
console.assert(deletedKey === deletedValue, this);
}
return deletedValue;
}
take(key, value) {
let valueSet = this._map.get(key);
if (arguments.length === 1) {
this._map.delete(key);
return valueSet;
}
let deletedValue = valueSet.delete(value);
if (!valueSet.size) {
let deletedKey = this._map.delete(key);
console.assert(deletedKey === deletedValue, this);
}
return deletedValue ? value : undefined;
}
clear() {
this._map.clear();
}
keys() {
return this._map.keys();
}
*values() {
for (let valueSet of this.sets()) {
for (let value of valueSet)
yield value;
}
}
*entries() {
for (let [key, valueSet] of this._map) {
for (let value of valueSet)
yield [key, value];
}
}
[Symbol.iterator]() {
return this.entries();
}
toJSON() {
return Array.from(this);
}
}