size

Benchmark created on


Setup

class DeepMapO {
  map = {};
  keyMap = {};

  constructor(serialize, initialValues) {
    this.serialize = serialize;
    if (initialValues?.[Symbol.iterator]) {
      for (const [key, value] of initialValues) this.set(key, value);
    }
  }

  set(key, value) {
    const keyStr = this.serialize(key);
    this.keyMap[keyStr] = key;
    this.map[keyStr] = value;
    return this;
  }

  get(key) {
    return this.map[this.serialize(key)];
  }

  has(key) {
    return this.map.hasOwnProperty(this.serialize(key));
  }

  delete(key) {
    const keyStr = this.serialize(key);
    const hasKey = this.map.hasOwnProperty(keyStr);
    delete this.keyMap[hasKey];
    delete this.map[keyStr];
    return hasKey;
  }

  clear() {
    this.map = {};
    this.keyMap = {};
  }

  get size() {
    return Object.keys(this.map).length;
  }

  *keys() {
    for (let keyStr in this.keyMap) yield this.keyMap[keyStr];
  }

  *values() {
    for (let keyStr in this.keyMap) yield this.map[keyStr];
  }

  *entries() {
    for (let keyStr in this.keyMap) yield [this.keyMap[keyStr], this.map[keyStr]];
  }

  forEach(cb, thisArg) {
    for (let keyStr in this.keyMap) cb.call(thisArg, this.map[keyStr], this.keyMap[keyStr], this);
  }

  copy() {
    const newMap = new DeepMapO(this.serialize);
    // directly copying the map and keymap (instead of passing it to the constructor), avoids having to recalculate each key hash
    newMap.map = { ...this.map };
    newMap.keyMap = { ...this.keyMap };
    return newMap;
  }

  [Symbol.iterator]() {
    return this.entries();
  }
}

class DeepMapSO {
  map = {};
  _size = 0;

  constructor(serialize, initialValues) {
    this.serialize = serialize;
    if (initialValues?.[Symbol.iterator]) {
      for (const [key, value] of initialValues) this.set(key, value);
    }
  }

  set(key, value) {
    const keyStr = this.serialize(key);
    this.map[keyStr] = [key, value];
    this._size++;
    return this;
  }

  get(key) {
    return this.map[this.serialize(key)]?.[1];
  }

  has(key) {
    return this.map.hasOwnProperty(this.serialize(key));
  }

  delete(key) {
    const keyStr = this.serialize(key);
    const hasKey = this.map.hasOwnProperty(keyStr);
    delete this.map[keyStr];
    if (hasKey) this._size--;
    return hasKey;
  }

  clear() {
    this.map = {};
    this._size = 0;
  }

  get size() {
    return this._size;
  }

  *keys() {
    for (let keyStr in this.map) yield this.map[keyStr][0];
  }

  *values() {
    for (let keyStr in this.map) yield this.map[keyStr][1];
  }

  *entries() {
    for (let keyStr in this.map) yield this.map[keyStr];
  }

  forEach(cb, thisArg) {
    for (let keyStr in this.map) cb.call(thisArg, this.map[keyStr][1], this.map[keyStr][0], this);
  }

  copy() {
    const newMap = new DeepMapSO(this.serialize);
    // directly copying the map and map (instead of passing it to the constructor), avoids having to recalculate each key hash
    newMap.map = { ...this.map };
    newMap._size = this._size;
    return newMap;
  }

  [Symbol.iterator]() {
    return this.entries();
  }
}

    const serialize = k => `${k.chain}}_{${k.joint}`;
    const deSerialize = str => {
      const parts = str.split('}_{');
      return { chain: parts[0], joint: parts[1] };
    };

    const map = new Map();
    const obj = {};
    const deepMapObj = new DeepMapO(serialize);
	const deepMapSingleObj = new DeepMapSO(serialize);

    for (let chain = 0; chain < 5; chain++) {
      for (let joint = 0; joint < 10; joint++) {
        const key = {
          chain: `cf221f55-957c-43bf-be45-f5be6d2cebe4-${chain}`,
          joint: `dc7d8abf-871c-4980-84ed-c7049a67558d-${joint}`
        };
        const value = `value-${chain}-${joint}`;
        map.set(serialize(key), value);
        obj[serialize(key)] = value;
    	deepMapObj.set(key, value);
    	deepMapSingleObj.set(key, value);
      }
    }

    const testKey = {
      chain: `cf221f55-957c-43bf-be45-f5be6d2cebe4-${4}`,
      joint: `dc7d8abf-871c-4980-84ed-c7049a67558d-${8}`
    };

Test runner

Ready to run.

Testing in
TestOps/sec
native map
return map.size
ready
native object
return Object.keys(obj).length
ready
deepMap obj
return deepMapObj.size
ready
deepMap single obj
return deepMapSingleObj.size
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.