Skip to content

Commit 5f9cc5e

Browse files
BridgeARRafaelGSS
authored andcommitted
assert,util: improve array comparison
Sparse arrays and arrays containing undefined are now compared faster using assert.deepStrictEqual() or util.isDeepStrictEqual(). PR-URL: #57619 Reviewed-By: Jordan Harband <ljharb@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
1 parent 4a47ce5 commit 5f9cc5e

3 files changed

Lines changed: 34 additions & 26 deletions

File tree

‎benchmark/assert/deepequal-simple-array-and-set.js‎

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ const bench = common.createBenchmark(main, {
1111
method: [
1212
'deepEqual_Array',
1313
'notDeepEqual_Array',
14+
'deepEqual_sparseArray',
15+
'notDeepEqual_sparseArray',
1416
'deepEqual_Set',
1517
'notDeepEqual_Set',
1618
],
@@ -25,18 +27,30 @@ function run(fn, n, actual, expected) {
2527
}
2628

2729
functionmain({ n, len, method, strict }){
28-
constactual=[];
29-
constexpected=[];
30+
letactual=Array.from({length: len},(_,i)=>i);
31+
// Contain one undefined value to trigger a specific code path
32+
actual[0]=undefined;
33+
letexpected=actual.slice(0);
3034

31-
for(leti=0;i<len;i++){
32-
actual.push(i);
33-
expected.push(i);
34-
}
3535
if(method.includes('not')){
3636
expected[len-1]+=1;
3737
}
3838

3939
switch(method){
40+
case'deepEqual_sparseArray':
41+
case'notDeepEqual_sparseArray':
42+
actual=newArray(len);
43+
for(leti=0;i<len;i+=2){
44+
actual[i]=i;
45+
}
46+
expected=actual.slice(0);
47+
if(method.includes('not')){
48+
expected[len-2]+=1;
49+
run(strict ? notDeepStrictEqual : notDeepEqual,n,actual,expected);
50+
}else{
51+
run(strict ? deepStrictEqual : deepEqual,n,actual,expected);
52+
}
53+
break;
4054
case'deepEqual_Array':
4155
run(strict ? deepStrictEqual : deepEqual,n,actual,expected);
4256
break;

‎lib/internal/assert/myers_diff.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ function myersDiff(actual, expected, checkCommaDisparity = false) {
2929
constactualLength=actual.length;
3030
constexpectedLength=expected.length;
3131
constmax=actualLength+expectedLength;
32+
// TODO(BridgeAR): Cap the input in case the values go beyond the limit of 2^31 - 1.
3233
constv=newInt32Array(2*max+1);
3334
consttrace=[];
3435

‎lib/internal/util/comparisons.js‎

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,9 @@ function innerDeepEqual(val1, val2, mode, memos) {
196196
}
197197
}else{
198198
if(val1===null||typeofval1!=='object'){
199-
if(val2===null||typeofval2!=='object'){
200-
// eslint-disable-next-line eqeqeq
201-
returnval1==val2||(NumberIsNaN(val1)&&NumberIsNaN(val2));
202-
}
203-
returnfalse;
199+
return(val2===null||typeofval2!=='object')&&
200+
// eslint-disable-next-line eqeqeq
201+
(val1==val2||(NumberIsNaN(val1)&&NumberIsNaN(val2)));
204202
}
205203
if(val2===null||typeofval2!=='object'){
206204
returnfalse;
@@ -384,9 +382,7 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
384382
}
385383
}elseif(keys2.length!==ObjectKeys(val1).length){
386384
returnfalse;
387-
}
388-
389-
if(mode===kStrict){
385+
}elseif(mode===kStrict){
390386
constsymbolKeysA=getOwnSymbols(val1);
391387
if(symbolKeysA.length!==0){
392388
letcount=0;
@@ -761,9 +757,9 @@ function sparseArrayEquiv(a, b, mode, memos, i) {
761757
if(keysA.length!==keysB.length){
762758
returnfalse;
763759
}
764-
for(;i<keysA.length;i++){
765-
constkey=keysA[i];
766-
if(!hasOwn(b,key)||!innerDeepEqual(a[key],b[key],mode,memos)){
760+
for(;i<keysB.length;i++){
761+
constkey=keysB[i];
762+
if((a[key]===undefined&&!hasOwn(a,key))||!innerDeepEqual(a[key],b[key],mode,memos)){
767763
returnfalse;
768764
}
769765
}
@@ -785,17 +781,14 @@ function objEquiv(a, b, mode, keys2, memos, iterationType) {
785781
returnpartialArrayEquiv(a,b,mode,memos);
786782
}
787783
for(leti=0;i<a.length;i++){
788-
if(!innerDeepEqual(a[i],b[i],mode,memos)){
789-
returnfalse;
790-
}
791-
constisSparseA=a[i]===undefined&&!hasOwn(a,i);
792-
constisSparseB=b[i]===undefined&&!hasOwn(b,i);
793-
if(isSparseA!==isSparseB){
784+
if(b[i]===undefined){
785+
if(!hasOwn(b,i))
786+
returnsparseArrayEquiv(a,b,mode,memos,i);
787+
if(a[i]!==undefined||!hasOwn(a,i))
788+
returnfalse;
789+
}elseif(a[i]===undefined||!innerDeepEqual(a[i],b[i],mode,memos)){
794790
returnfalse;
795791
}
796-
if(isSparseA){
797-
returnsparseArrayEquiv(a,b,mode,memos,i);
798-
}
799792
}
800793
}elseif(iterationType===kIsSet){
801794
if(!setEquiv(a,b,mode,memos)){

0 commit comments

Comments
 (0)