Skip to content

Instantly share code, notes, and snippets.

@julien-f
Created December 20, 2021 13:56
Show Gist options
  • Save julien-f/86de5dd69a240d803a6772f7f6180558 to your computer and use it in GitHub Desktop.
Save julien-f/86de5dd69a240d803a6772f7f6180558 to your computer and use it in GitHub Desktop.
MultiKeyMap using serialization
const ensureArray = (value) =>
Array.isArray(value) ? value : value === undefined ? [] : [value];
exports.MultiKeyMap = class MultiKeyMap {
#data = new Map();
#objects = new WeakMap();
get size() {
return this.#data.size;
}
constructor(iterable) {
if (iterable !== undefined) {
for (const [key, value] of iterable) {
this.set(key, value);
}
}
}
clear() {
this.#data.clear();
this.#objects.clear();
}
delete(key) {
return this.#data.delete(this.#computeKey(key));
}
get(key) {
return this.#data.get(this.#computeKey(key));
}
has(key) {
return this.#data.has(this.#computeKey(key));
}
set(key, value) {
this.#data.set(this.#computeKey(key), value);
}
#computeKey(parts) {
const key = [];
for (const part of ensureArray(parts)) {
const type = typeof part;
if (part == null) {
key.push(String(part));
} else if (type === "object" || type === "function") {
const objects = this.#objects;
let id = objects.get(part);
if (id === undefined) {
id = Math.random().toString(36).slice(2);
this.#objects.set(part, id);
}
key.push("~ref~" + id);
} else if (type === "bigint") {
key.push(String(part) + "n");
} else if (type === "symbol") {
throw new TypeError(
"Symbols as part of keys are not supported in this implementation"
);
} else {
key.push(JSON.stringify(part));
}
}
return key.join();
}
};
const assert = require("assert").strict;
const { MultiKeyMap } = require("./MultiKeyMap.js");
const map = new MultiKeyMap();
const test = (key) => {
const value = {};
const size = map.size;
map.set(key, value);
assert.equal(map.size, size + 1);
assert(map.has(key));
assert.equal(map.get(key), value);
assert(map.delete(key));
assert.equal(map.size, size);
assert(!map.has(key));
assert.equal(map.get(key), undefined);
assert(!map.delete(key));
};
test([1, 2n, new Date(), /.*/, {}, Function.prototype]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment