@@ -3,12 +3,6 @@ import { StringSet } from './globals';
33
44const BOXABLE_TYPES = new StringSet ( [ 'boolean' , 'number' , 'string' ] ) ;
55
6- // Memory for previously seen containers (object, array, map, set).
7- // Used for recursion detection, and to avoid repeated comparison.
8- //
9- // Elements are { a: val, b: val }.
10- let memory = [ ] ;
11-
126function useStrictEquality ( a , b ) {
137 return a === b ;
148}
@@ -69,14 +63,14 @@ const objTypeCallbacks = {
6963 // identical reference only
7064 function : useStrictEquality ,
7165
72- array ( a , b ) {
66+ array ( a , b , memory ) {
7367 if ( a . length !== b . length ) {
7468 // Safe and faster
7569 return false ;
7670 }
7771
7872 for ( let i = 0 ; i < a . length ; i ++ ) {
79- if ( ! typeEquiv ( a [ i ] , b [ i ] ) ) {
73+ if ( ! typeEquiv ( a [ i ] , b [ i ] , memory ) ) {
8074 return false ;
8175 }
8276 }
@@ -88,7 +82,7 @@ const objTypeCallbacks = {
8882 // repetitions are not counted, so these are equivalent:
8983 // a = new Set( [ X={}, Y=[], Y ] );
9084 // b = new Set( [ Y, X, X ] );
91- set ( a , b ) {
85+ set ( a , b , memory ) {
9286 if ( a . size !== b . size ) {
9387 // This optimization has certain quirks because of the lack of
9488 // repetition counting. For instance, adding the same
@@ -116,14 +110,11 @@ const objTypeCallbacks = {
116110 return ;
117111 }
118112
119- // Swap out the global memory, as nested typeEquiv() would clobber it
120- const originalMemory = memory ;
121- memory = [ ] ;
113+ // Don't pass memory, as this nested typeEquiv() must operate
114+ // independently and would otherwise clobber it
122115 if ( typeEquiv ( bVal , aVal ) ) {
123116 innerEq = true ;
124117 }
125- // Restore
126- memory = originalMemory ;
127118 } ) ;
128119
129120 if ( ! innerEq ) {
@@ -168,14 +159,11 @@ const objTypeCallbacks = {
168159 return ;
169160 }
170161
171- // Swap out the global memory, as nested typeEquiv() would clobber it
172- const originalMemory = memory ;
173- memory = [ ] ;
174- if ( objTypeCallbacks . array ( [ bVal , bKey ] , [ aVal , aKey ] ) ) {
162+ // Don't memory main memory, as nested typeEquiv() would clobber it
163+ const localMemory = [ ] ;
164+ if ( objTypeCallbacks . array ( [ bVal , bKey ] , [ aVal , aKey ] , localMemory ) ) {
175165 innerEq = true ;
176166 }
177- // Restore
178- memory = originalMemory ;
179167 } ) ;
180168
181169 if ( ! innerEq ) {
@@ -200,7 +188,7 @@ const entryTypeCallbacks = {
200188 symbol : useStrictEquality ,
201189
202190 function : useStrictEquality ,
203- object ( a , b ) {
191+ object ( a , b , memory ) {
204192 // Handle memory (skip recursion)
205193 if ( memory . some ( ( pair ) => pair . a === a && pair . b === b ) ) {
206194 return true ;
@@ -212,7 +200,7 @@ const entryTypeCallbacks = {
212200 if ( aObjType !== 'object' || bObjType !== 'object' ) {
213201 // Handle literal `null`
214202 // Handle: Array, Map/Set, Date, Regxp/Function, boxed primitives
215- return aObjType === bObjType && objTypeCallbacks [ aObjType ] ( a , b ) ;
203+ return aObjType === bObjType && objTypeCallbacks [ aObjType ] ( a , b , memory ) ;
216204 }
217205
218206 // NOTE: Literal null must not make it here as it would throw
@@ -238,7 +226,7 @@ const entryTypeCallbacks = {
238226 ) {
239227 continue ;
240228 }
241- if ( ! typeEquiv ( a [ i ] , b [ i ] ) ) {
229+ if ( ! typeEquiv ( a [ i ] , b [ i ] , memory ) ) {
242230 return false ;
243231 }
244232 }
@@ -248,11 +236,16 @@ const entryTypeCallbacks = {
248236 bProperties . push ( i ) ;
249237 }
250238
251- return objTypeCallbacks . array ( aProperties . sort ( ) , bProperties . sort ( ) ) ;
239+ return objTypeCallbacks . array ( aProperties . sort ( ) , bProperties . sort ( ) , memory ) ;
252240 }
253241} ;
254242
255- function typeEquiv ( a , b ) {
243+
244+ // Memory for previously seen containers (object, array, map, set).
245+ // Used for recursion detection, and to avoid repeated comparison.
246+ //
247+ // Elements are { a: val, b: val }.
248+ function typeEquiv ( a , b , memory = [ ] ) {
256249 // Optimization: Only perform type-specific comparison when pairs are not strictly equal.
257250 if ( a === b ) {
258251 return true ;
@@ -267,14 +260,7 @@ function typeEquiv (a, b) {
267260 ( bType === 'object' && BOXABLE_TYPES . has ( objectType ( b ) ) ? b . valueOf ( ) : b ) ;
268261 }
269262
270- return entryTypeCallbacks [ aType ] ( a , b ) ;
271- }
272-
273- function innerEquiv ( a , b ) {
274- const res = typeEquiv ( a , b ) ;
275- // Release any retained objects and reset recursion detection for next call
276- memory = [ ] ;
277- return res ;
263+ return entryTypeCallbacks [ aType ] ( a , b , memory ) ;
278264}
279265
280266/**
@@ -285,14 +271,14 @@ function innerEquiv (a, b) {
285271 */
286272export default function equiv ( a , b ) {
287273 if ( arguments . length === 2 ) {
288- return ( a === b ) || innerEquiv ( a , b ) ;
274+ return ( a === b ) || typeEquiv ( a , b ) ;
289275 }
290276
291277 // Given 0 or 1 arguments, just return true (nothing to compare).
292278 // Given (A,B,C,D) compare C,D then B,C then A,B.
293279 let i = arguments . length - 1 ;
294280 while ( i > 0 ) {
295- if ( ! innerEquiv ( arguments [ i - 1 ] , arguments [ i ] ) ) {
281+ if ( ! typeEquiv ( arguments [ i - 1 ] , arguments [ i ] ) ) {
296282 return false ;
297283 }
298284 i -- ;
0 commit comments