@@ -285,9 +285,12 @@ function _deepEqual(actual, expected, strict, memos) {
285
285
return areEq ;
286
286
}
287
287
288
- function setHasSimilarElement ( set , val1 , strict , memo ) {
289
- if ( set . has ( val1 ) )
288
+ function setHasSimilarElement ( set , val1 , usedEntries , strict , memo ) {
289
+ if ( set . has ( val1 ) ) {
290
+ if ( usedEntries )
291
+ usedEntries . add ( val1 ) ;
290
292
return true ;
293
+ }
291
294
292
295
// In strict mode the only things which can match a primitive or a function
293
296
// will already be detected by set.has(val1).
@@ -296,8 +299,14 @@ function setHasSimilarElement(set, val1, strict, memo) {
296
299
297
300
// Otherwise go looking.
298
301
for ( const val2 of set ) {
299
- if ( _deepEqual ( val1 , val2 , strict , memo ) )
302
+ if ( usedEntries && usedEntries . has ( val2 ) )
303
+ continue ;
304
+
305
+ if ( _deepEqual ( val1 , val2 , strict , memo ) ) {
306
+ if ( usedEntries )
307
+ usedEntries . add ( val2 ) ;
300
308
return true ;
309
+ }
301
310
}
302
311
303
312
return false ;
@@ -314,21 +323,33 @@ function setEquiv(a, b, strict, memo) {
314
323
if ( a . size !== b . size )
315
324
return false ;
316
325
326
+ // This is a set of the entries in b which have been consumed in our pairwise
327
+ // comparison.
328
+ //
329
+ // When the sets contain only value types (eg, lots of numbers), and we're in
330
+ // strict mode, we don't need to match off the entries in a pairwise way. In
331
+ // that case this initialization is done lazily to avoid the allocation &
332
+ // bookkeeping cost. Unfortunately, we can't get away with that in non-strict
333
+ // mode.
334
+ let usedEntries = null ;
335
+
317
336
for ( const val1 of a ) {
337
+ if ( usedEntries == null && ( ! strict || typeof val1 === 'object' ) )
338
+ usedEntries = new Set ( ) ;
339
+
318
340
// If the value doesn't exist in the second set by reference, and its an
319
341
// object or an array we'll need to go hunting for something thats
320
342
// deep-equal to it. Note that this is O(n^2) complexity, and will get
321
343
// slower if large, very similar sets / maps are nested inside.
322
344
// Unfortunately there's no real way around this.
323
- if ( ! setHasSimilarElement ( b , val1 , strict , memo ) ) {
345
+ if ( ! setHasSimilarElement ( b , val1 , usedEntries , strict , memo ) )
324
346
return false ;
325
- }
326
347
}
327
348
328
349
return true ;
329
350
}
330
351
331
- function mapHasSimilarEntry ( map , key1 , item1 , strict , memo ) {
352
+ function mapHasSimilarEntry ( map , key1 , item1 , usedEntries , strict , memo ) {
332
353
// To be able to handle cases like:
333
354
// Map([[1, 'a'], ['1', 'b']]) vs Map([['1', 'a'], [1, 'b']])
334
355
// or:
@@ -338,8 +359,11 @@ function mapHasSimilarEntry(map, key1, item1, strict, memo) {
338
359
// This check is not strictly necessary. The loop performs this check, but
339
360
// doing it here improves performance of the common case when reference-equal
340
361
// keys exist (which includes all primitive-valued keys).
341
- if ( map . has ( key1 ) && _deepEqual ( item1 , map . get ( key1 ) , strict , memo ) )
362
+ if ( map . has ( key1 ) && _deepEqual ( item1 , map . get ( key1 ) , strict , memo ) ) {
363
+ if ( usedEntries )
364
+ usedEntries . add ( key1 ) ;
342
365
return true ;
366
+ }
343
367
344
368
if ( strict && ( util . isPrimitive ( key1 ) || util . isFunction ( key1 ) ) )
345
369
return false ;
@@ -349,8 +373,13 @@ function mapHasSimilarEntry(map, key1, item1, strict, memo) {
349
373
if ( key2 === key1 )
350
374
continue ;
351
375
376
+ if ( usedEntries && usedEntries . has ( key2 ) )
377
+ continue ;
378
+
352
379
if ( _deepEqual ( key1 , key2 , strict , memo ) &&
353
380
_deepEqual ( item1 , item2 , strict , memo ) ) {
381
+ if ( usedEntries )
382
+ usedEntries . add ( key2 ) ;
354
383
return true ;
355
384
}
356
385
}
@@ -366,10 +395,15 @@ function mapEquiv(a, b, strict, memo) {
366
395
if ( a . size !== b . size )
367
396
return false ;
368
397
398
+ let usedEntries = null ;
399
+
369
400
for ( const [ key1 , item1 ] of a ) {
401
+ if ( usedEntries == null && ( ! strict || typeof key1 === 'object' ) )
402
+ usedEntries = new Set ( ) ;
403
+
370
404
// Just like setEquiv above, this hunt makes this function O(n^2) when
371
405
// using objects and lists as keys
372
- if ( ! mapHasSimilarEntry ( b , key1 , item1 , strict , memo ) )
406
+ if ( ! mapHasSimilarEntry ( b , key1 , item1 , usedEntries , strict , memo ) )
373
407
return false ;
374
408
}
375
409
0 commit comments