Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: improve setDottedPath #11264

Merged
merged 1 commit into from Jan 24, 2022
Merged

perf: improve setDottedPath #11264

merged 1 commit into from Jan 24, 2022

Conversation

Uzlopak
Copy link
Collaborator

@Uzlopak Uzlopak commented Jan 24, 2022

Improve perf of setDottetPath

var0 = old
var1 = new

authorizationResponse
var0 x 30,093,641 ops/sec ±1.66% (86 runs sampled)
var1 x 123,402,415 ops/sec ±0.42% (95 runs sampled)
authorizationResponse.stan
var0 x 4,020,169 ops/sec ±0.43% (90 runs sampled)
var1 x 5,329,115 ops/sec ±0.50% (91 runs sampled)

benchmark:

'use strict';

const Bench = require('benchmark');
const { expect } = require('chai');

function setDottedPathVar0(obj, path, val) {
  const parts = path.indexOf('.') === -1 ? [path] : path.split('.');
  let cur = obj;
  for (const part of parts.slice(0, -1)) {
    if (cur[part] == null) {
      cur[part] = {};
    }

    cur = cur[part];
  }

  const last = parts[parts.length - 1];
  cur[last] = val;
};
function setDottedPathVar1(obj, path, val) {
  if (path.indexOf('.') === -1) {
    obj[path] = val;
    return;
  }
  const parts = path.split('.');
  const last = parts.pop();
  let cur = obj;
  for (const part of parts) {
    if (cur[part] == null) {
      cur[part] = {};
    }

    cur = cur[part];
  }

  cur[last] = val;
};

const validate = (path, value, expected) => {
  let obj = {
    clearingInstituteName: 'Our local bank',
    'transaction.receipt': 'I am a transaction receipt',
    'transaction.authorizationCode': 'ABCDEF',
    'transaction.acquirer.settlementDate': 'February 2021',
    'sourceOfFunds.provided.card.issuer': 'Big bank corporation',
    nonExistentField: 'I should not be present'
  };
  setDottedPathVar0(obj, path, value);
  expect(obj, "var0").to.be.eql(expected);
  obj = {
    clearingInstituteName: 'Our local bank',
    'transaction.receipt': 'I am a transaction receipt',
    'transaction.authorizationCode': 'ABCDEF',
    'transaction.acquirer.settlementDate': 'February 2021',
    'sourceOfFunds.provided.card.issuer': 'Big bank corporation',
    nonExistentField: 'I should not be present'
  };
  setDottedPathVar1(obj, path, value);
  expect(obj, "var1").to.be.eql(expected);
}

validate('authorizationResponse.stan', '123456', {
  clearingInstituteName: 'Our local bank',
  'transaction.receipt': 'I am a transaction receipt',
  'transaction.authorizationCode': 'ABCDEF',
  'transaction.acquirer.settlementDate': 'February 2021',
  'sourceOfFunds.provided.card.issuer': 'Big bank corporation',
  nonExistentField: 'I should not be present',
  authorizationResponse: { stan: '123456' }
});
validate('authorizationResponse', '123456', {
  clearingInstituteName: 'Our local bank',
  'transaction.receipt': 'I am a transaction receipt',
  'transaction.authorizationCode': 'ABCDEF',
  'transaction.acquirer.settlementDate': 'February 2021',
  'sourceOfFunds.provided.card.issuer': 'Big bank corporation',
  nonExistentField: 'I should not be present',
  authorizationResponse: '123456'
});
// validate('first.second', ['first', 'first.second']);
// validate('', ['']);

const bench = (path, value) => {
  console.log(path)
  new Bench.Suite()
    .add('var0', function () {

      const obj = {
        clearingInstituteName: 'Our local bank',
        'transaction.receipt': 'I am a transaction receipt',
        'transaction.authorizationCode': 'ABCDEF',
        'transaction.acquirer.settlementDate': 'February 2021',
        'sourceOfFunds.provided.card.issuer': 'Big bank corporation',
        nonExistentField: 'I should not be present'
      };
      setDottedPathVar0(obj, path, value);
    })
    .add('var1', function () {

      const obj = {
        clearingInstituteName: 'Our local bank',
        'transaction.receipt': 'I am a transaction receipt',
        'transaction.authorizationCode': 'ABCDEF',
        'transaction.acquirer.settlementDate': 'February 2021',
        'sourceOfFunds.provided.card.issuer': 'Big bank corporation',
        nonExistentField: 'I should not be present'
      };
      setDottedPathVar1(obj, path, value);
    })
    .on('cycle', function (e) {
      const s = String(e.target);
      console.log(s);
    })
    .run();
}


bench('authorizationResponse', '123456');
bench('authorizationResponse.stan', '123456');

@Uzlopak Uzlopak changed the title improve perf of setDottedPath perf: improve setDottedPath Jan 24, 2022
@Uzlopak
Copy link
Collaborator Author

Uzlopak commented Jan 24, 2022

probably could be also realized by using mpath?

@vkarpov15
Copy link
Collaborator

It cannot unfortunately, because mpath explicitly avoids creating intermediate paths. So mpath setting a.b.c.d won't create intermediate a.b, a.c if a.b is undefined.

In theory, we could add that to mpath somehow. But this function exists specifically to work around that limitation in mpath.

@vkarpov15 vkarpov15 added this to the 6.1.8 milestone Jan 24, 2022
@vkarpov15 vkarpov15 merged commit abcdb8e into Automattic:master Jan 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants