UNPKG

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
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(); } }