◐ Shell
clean mode source ↗

url: optimize URLSearchParams set/delete duplicate handling · nodejs/node@7bd08ff

Original file line numberDiff line numberDiff line change

@@ -0,0 +1,43 @@

1+

'use strict';

2+

const common = require('../common.js');

3+
4+

const bench = common.createBenchmark(main, {

5+

method: ['set', 'delete'],

6+

type: ['unique', 'duplicates'],

7+

count: [10, 1000],

8+

n: [1e4],

9+

});

10+
11+

function buildSeed(type, count) {

12+

const parts = new Array(count);

13+
14+

if (type === 'duplicates') {

15+

for (let i = 0; i < count; i++) {

16+

parts[i] = `dup=${i}`;

17+

}

18+

} else {

19+

for (let i = 0; i < count; i++) {

20+

parts[i] = `k${i}=${i}`;

21+

}

22+

}

23+
24+

return new URLSearchParams(parts.join('&'));

25+

}

26+
27+

function main({ method, type, count, n }) {

28+

const seed = buildSeed(type, count);

29+

const key = type === 'duplicates' ? 'dup' : 'k0';

30+

const mutate = method === 'set' ?

31+

(params) => params.set(key, 'updated') :

32+

(params) => params.delete(key);

33+
34+

for (let i = 0; i < 1e3; i++) {

35+

mutate(new URLSearchParams(seed));

36+

}

37+
38+

bench.start();

39+

for (let i = 0; i < n; i++) {

40+

mutate(new URLSearchParams(seed));

41+

}

42+

bench.end(n);

43+

}

Original file line numberDiff line numberDiff line change

@@ -495,26 +495,37 @@ class URLSearchParams {

495495
496496

const list = this.#searchParams;

497497

name = StringPrototypeToWellFormed(`${name}`);

498+

const { length } = list;

499+

let write = 0;

498500
499501

if (value !== undefined) {

500502

value = StringPrototypeToWellFormed(`${value}`);

501-

for (let i = 0; i < list.length;) {

503+

for (let i = 0; i < length; i += 2) {

502504

if (list[i] === name && list[i + 1] === value) {

503-

list.splice(i, 2);

504-

} else {

505-

i += 2;

505+

continue;

506+

}

507+

if (write !== i) {

508+

list[write] = list[i];

509+

list[write + 1] = list[i + 1];

506510

}

511+

write += 2;

507512

}

508513

} else {

509-

for (let i = 0; i < list.length;) {

514+

for (let i = 0; i < length; i += 2) {

510515

if (list[i] === name) {

511-

list.splice(i, 2);

512-

} else {

513-

i += 2;

516+

continue;

517+

}

518+

if (write !== i) {

519+

list[write] = list[i];

520+

list[write + 1] = list[i + 1];

514521

}

522+

write += 2;

515523

}

516524

}

517525
526+

if (write !== length)

527+

list.length = write;

528+
518529

if (this.#context) {

519530

setURLSearchParamsModified(this.#context);

520531

}

@@ -594,24 +605,34 @@ class URLSearchParams {

594605

const list = this.#searchParams;

595606

name = StringPrototypeToWellFormed(`${name}`);

596607

value = StringPrototypeToWellFormed(`${value}`);

608+

const { length } = list;

597609
598610

// If there are any name-value pairs whose name is `name`, in `list`, set

599611

// the value of the first such name-value pair to `value` and remove the

600612

// others.

601613

let found = false;

602-

for (let i = 0; i < list.length;) {

614+

let write = 0;

615+

for (let i = 0; i < length; i += 2) {

603616

const cur = list[i];

617+

let keep = true;

604618

if (cur === name) {

605619

if (!found) {

606-

list[i + 1] = value;

620+

list[write] = cur;

621+

list[write + 1] = value;

607622

found = true;

608-

i += 2;

609623

} else {

610-

list.splice(i, 2);

624+

keep = false;

611625

}

612-

} else {

613-

i += 2;

626+

} else if (write !== i) {

627+

list[write] = cur;

628+

list[write + 1] = list[i + 1];

614629

}

630+

if (keep)

631+

write += 2;

632+

}

633+
634+

if (found && write !== length) {

635+

list.length = write;

615636

}

616637
617638

// Otherwise, append a new name-value pair whose name is `name` and value