more-maps
Version:
A collection of additional map-like data structures. Including a bidirectional map, a multi map, and a bidirectional multi map.
157 lines (156 loc) • 4.29 kB
JavaScript
import keyIndex from "key-index";
import { iterate } from "iterare";
import { LengthLinkedList } from "fast-linked-list";
let reverse = undefined;
export class BidirectionalMap extends Map {
constructor(entries) {
super();
if (reverse !== undefined)
this.reverse = reverse;
else {
reverse = this;
this.reverse = new BidirectionalMap();
reverse = undefined;
}
if (entries !== undefined)
for (const [key, value] of entries)
this.set(key, value);
}
set(k, v) {
Map.prototype.set.call(this.reverse, v, k);
return super.set(k, v);
}
delete(k) {
Map.prototype.delete.call(this.reverse, this.get(k));
return super.delete(k);
}
}
export class MultiMap {
constructor(entries) {
this.index = keyIndex(() => []);
if (entries) {
for (const [key, val] of entries) {
this.index(key).push(...val);
}
}
}
add(key, val) {
this.index(key).push(val);
}
getAll(key) {
return this.index(key);
}
get(key, atIndex = 0) {
return this.getAll(key)[atIndex];
}
delete(key, val) {
if (val) {
const all = this.getAll(key);
const i = all.indexOf(val);
if (i === -1)
return false;
all.splice(i, 1);
return true;
}
else {
return this.index.delete(key);
}
}
keys() {
return this.index.keys();
}
values() {
return iterate(this.index.entries()).map(([key, vals]) => vals).flatten();
}
clear() {
this.index.clear();
}
get size() {
return this.index.size;
}
// accumulated size over all keys and their values
get accSize() {
let len = 0;
for (let [key, val] of this) {
len += val.length;
}
return len;
}
has(key) {
return !!this.getAll(key);
}
forEach(cb) {
for (let e of this) {
cb(...e);
}
}
[Symbol.iterator]() {
return this.index[Symbol.iterator]();
}
entries() {
return this.index.entries();
}
}
export class BidirectionalMultiMap extends MultiMap {
constructor(entries) {
super();
if (reverse !== undefined)
this.reverse = reverse;
else {
reverse = this;
this.reverse = new BidirectionalMultiMap();
reverse = undefined;
}
if (entries !== undefined)
for (const [key, values] of entries)
for (const value of values)
this.add(key, value);
}
add(key, val) {
MultiMap.prototype.add.call(this.reverse, val, key);
return super.add(key, val);
}
delete(key, val) {
if (val) {
MultiMap.prototype.delete.call(this.reverse, val, key);
return super.delete(key, val);
}
else {
for (const val of this.getAll(key))
MultiMap.prototype.delete.call(this.reverse, val, key);
return super.delete(key);
}
}
}
export class Borrow {
get length() {
return this.takenElems.length;
}
constructor(makeElem) {
this.makeElem = makeElem;
this.freeElems = new LengthLinkedList();
this.takenElems = new LengthLinkedList();
}
borrow() {
if (this.freeElems.first === undefined) {
this.freeElems.push(this.makeElem());
}
const token = this.freeElems.popToken();
this.takenElems.pushToken(token);
return { elem: token.value, done: () => {
this.freeElems.pushToken(token);
} };
}
}
export class BorrowMap {
constructor(makeElem) {
this.makeElem = makeElem;
this.map = new Map();
}
borrow(key, makeElem) {
if (!this.map.has(key)) {
this.map.set(key, new Borrow(makeElem !== undefined ? makeElem : this.makeElem !== undefined ? () => this.makeElem(key) : () => { throw new Error("No makeElem function provided"); }));
}
return this.map.get(key).borrow();
}
}