@@ -559,6 +559,35 @@ function partialObjectSetEquiv(a, b, mode, set, memo) {
559559 }
560560}
561561
562+ function setObjectEquiv ( a , b , mode , set , memo ) {
563+ if ( mode === kPartial ) {
564+ return partialObjectSetEquiv ( a , b , mode , set , memo ) ;
565+ }
566+ // Fast path for objects only
567+ if ( mode === kStrict && set . size === a . size ) {
568+ for ( const val of a ) {
569+ if ( ! setHasEqualElement ( set , val , mode , memo ) ) {
570+ return false ;
571+ }
572+ }
573+ return true ;
574+ }
575+
576+ for ( const val of a ) {
577+ // Primitive values have already been handled above.
578+ if ( typeof val === 'object' ) {
579+ if ( ! b . has ( val ) && ! setHasEqualElement ( set , val , mode , memo ) ) {
580+ return false ;
581+ }
582+ } else if ( mode === kLoose &&
583+ ! b . has ( val ) &&
584+ ! setHasEqualElement ( set , val , mode , memo ) ) {
585+ return false ;
586+ }
587+ }
588+ return set . size === 0 ;
589+ }
590+
562591function setEquiv ( a , b , mode , memo ) {
563592 // This is a lazily initiated Set of entries which have to be compared
564593 // pairwise.
@@ -584,22 +613,7 @@ function setEquiv(a, b, mode, memo) {
584613 }
585614
586615 if ( set !== null ) {
587- if ( mode === kPartial ) {
588- return partialObjectSetEquiv ( a , b , mode , set , memo ) ;
589- }
590- for ( const val of a ) {
591- // Primitive values have already been handled above.
592- if ( typeof val === 'object' && val !== null ) {
593- if ( ! b . has ( val ) && ! setHasEqualElement ( set , val , mode , memo ) ) {
594- return false ;
595- }
596- } else if ( mode === kLoose &&
597- ! b . has ( val ) &&
598- ! setHasEqualElement ( set , val , mode , memo ) ) {
599- return false ;
600- }
601- }
602- return set . size === 0 ;
616+ return setObjectEquiv ( a , b , mode , set , memo ) ;
603617 }
604618
605619 return true ;
@@ -640,6 +654,35 @@ function partialObjectMapEquiv(a, b, mode, set, memo) {
640654 }
641655}
642656
657+ function mapObjectEquivalence ( a , b , mode , set , memo ) {
658+ if ( mode === kPartial ) {
659+ return partialObjectMapEquiv ( a , b , mode , set , memo ) ;
660+ }
661+ // Fast path for objects only
662+ if ( mode === kStrict && set . size === a . size ) {
663+ for ( const { 0 : key1 , 1 : item1 } of a ) {
664+ if ( ! mapHasEqualEntry ( set , b , key1 , item1 , mode , memo ) ) {
665+ return false ;
666+ }
667+ }
668+ return true ;
669+ }
670+ for ( const { 0 : key1 , 1 : item1 } of a ) {
671+ if ( typeof key1 === 'object' && key1 !== null ) {
672+ if ( ! mapHasEqualEntry ( set , b , key1 , item1 , mode , memo ) )
673+ return false ;
674+ } else if ( set . size === 0 ) {
675+ return true ;
676+ } else if ( mode === kLoose &&
677+ ( ! b . has ( key1 ) ||
678+ ! innerDeepEqual ( item1 , b . get ( key1 ) , mode , memo ) ) &&
679+ ! mapHasEqualEntry ( set , b , key1 , item1 , mode , memo ) ) {
680+ return false ;
681+ }
682+ }
683+ return set . size === 0 ;
684+ }
685+
643686function mapEquiv ( a , b , mode , memo ) {
644687 let set = null ;
645688
@@ -675,21 +718,7 @@ function mapEquiv(a, b, mode, memo) {
675718 }
676719
677720 if ( set !== null ) {
678- if ( mode === kPartial ) {
679- return partialObjectMapEquiv ( a , b , mode , set , memo ) ;
680- }
681- for ( const { 0 : key1 , 1 : item1 } of a ) {
682- if ( typeof key1 === 'object' && key1 !== null ) {
683- if ( ! mapHasEqualEntry ( set , b , key1 , item1 , mode , memo ) )
684- return false ;
685- } else if ( mode === kLoose &&
686- ( ! b . has ( key1 ) ||
687- ! innerDeepEqual ( item1 , b . get ( key1 ) , mode , memo ) ) &&
688- ! mapHasEqualEntry ( set , b , key1 , item1 , mode , memo ) ) {
689- return false ;
690- }
691- }
692- return set . size === 0 ;
721+ return mapObjectEquivalence ( a , b , mode , set , memo ) ;
693722 }
694723
695724 return true ;
@@ -737,6 +766,24 @@ function partialArrayEquiv(a, b, mode, memos) {
737766 return true ;
738767}
739768
769+ function sparseArrayEquiv ( a , b , mode , memos , i ) {
770+ // TODO(BridgeAR): Use internal method to only get index properties. The
771+ // same applies to the partial implementation.
772+ const keysA = ObjectKeys ( a ) ;
773+ const keysB = ObjectKeys ( b ) ;
774+ if ( keysA . length !== keysB . length ) {
775+ return false ;
776+ }
777+ for ( ; i < keysA . length ; i ++ ) {
778+ const key = keysA [ i ] ;
779+ if ( ! ObjectPrototypeHasOwnProperty ( b , key ) ||
780+ ! innerDeepEqual ( a [ key ] , b [ key ] , mode , memos ) ) {
781+ return false ;
782+ }
783+ }
784+ return true ;
785+ }
786+
740787function objEquiv ( a , b , mode , keys2 , memos , iterationType ) {
741788 // The pair must have equivalent values for every corresponding key.
742789 if ( keys2 . length > 0 ) {
@@ -755,23 +802,13 @@ function objEquiv(a, b, mode, keys2, memos, iterationType) {
755802 if ( ! innerDeepEqual ( a [ i ] , b [ i ] , mode , memos ) ) {
756803 return false ;
757804 }
758- const isOwnProperty = ObjectPrototypeHasOwnProperty ( a , i ) ;
759- if ( isOwnProperty !== ObjectPrototypeHasOwnProperty ( b , i ) ) {
805+ const isSparseA = a [ i ] === undefined && ! ObjectPrototypeHasOwnProperty ( a , i ) ;
806+ const isSparseB = b [ i ] === undefined && ! ObjectPrototypeHasOwnProperty ( b , i ) ;
807+ if ( isSparseA !== isSparseB ) {
760808 return false ;
761809 }
762- if ( ! isOwnProperty ) {
763- // Array is sparse.
764- // TODO(BridgeAR): Use internal method to only get index properties. The
765- // same applies to the partial implementation.
766- const keysA = ObjectKeys ( a ) ;
767- for ( ; i < keysA . length ; i ++ ) {
768- const key = keysA [ i ] ;
769- if ( ! ObjectPrototypeHasOwnProperty ( b , key ) ||
770- ! innerDeepEqual ( a [ key ] , b [ key ] , mode , memos ) ) {
771- return false ;
772- }
773- }
774- return keysA . length === ObjectKeys ( b ) . length ;
810+ if ( isSparseA ) {
811+ return sparseArrayEquiv ( a , b , mode , memos , i ) ;
775812 }
776813 }
777814 } else if ( iterationType === kIsSet ) {
0 commit comments