From a6539ece2c713b8ad610cccc5cbd1502fc6a08ae Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Wed, 26 Jul 2017 08:58:26 -0400 Subject: [PATCH] assert: optimize code path for deepEqual Maps PR-URL: https://github.com/nodejs/node/pull/14501 Reviewed-By: James M Snell Reviewed-By: Refael Ackermann --- lib/assert.js | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/lib/assert.js b/lib/assert.js index d306adce316ccc..6e4b9effbe5549 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -349,10 +349,6 @@ function setEquiv(a, b, strict, memo) { // This is a lazily initiated Set of entries which have to be compared // pairwise. var set = null; - // When the sets contain only value types (eg, lots of numbers), and we're in - // strict mode or if all entries strictly match, we don't need to match the - // entries in a pairwise way. In that case this initialization is done lazily - // to avoid the allocation & bookkeeping cost. for (const val of a) { // Note: Checking for the objects first improves the performance for object // heavy sets but it is a minor slow down for primitives. As they are fast @@ -373,7 +369,7 @@ function setEquiv(a, b, strict, memo) { if (set !== null) { for (const val of b) { - // In non-strict-mode we have to check if a primitive value is already + // We have to check if a primitive value is already // matching and only if it's not, go hunting for it. if (typeof val === 'object' && val !== null) { if (!setHasEqualElement(set, val, strict, memo)) @@ -449,10 +445,13 @@ function mapHasLoosePrim(a, b, key1, memo, item1, item2) { return false; for (const val of setA) { - if (!setHasEqualElement(setB, val, false, memo)) + if (typeof val === 'object' && val !== null) { + if (!setHasEqualElement(setB, val, false, memo)) + return false; + } else if (!setB.has(val) && !setHasLoosePrim(setA, setB, val)) { return false; + } } - return true; } @@ -472,34 +471,26 @@ function mapHasEqualEntry(set, map, key1, item1, strict, memo) { } function mapEquiv(a, b, strict, memo) { - // Caveat: In non-strict mode, this implementation does not handle cases - // where maps contain two equivalent-but-not-reference-equal keys. if (a.size !== b.size) return false; var set = null; for (const [key, item1] of a) { - // By directly retrieving the value we prevent another b.has(key) check in - // almost all possible cases. - const item2 = b.get(key); - if (item2 === undefined) { - // Just like setEquiv above but in addition we have to make sure the - // values are also equal. - if (typeof key === 'object' && key !== null) { - if (set === null) { - set = new Set(); - } - set.add(key); - // Note: we do not have to pass memo in this case as at least one item - // is undefined. - } else if ((!innerDeepEqual(item1, item2, strict) || !b.has(key)) && - (strict || !mapHasLoosePrim(a, b, key, memo, item1))) { + if (typeof key === 'object' && key !== null) { + if (set === null) { + set = new Set(); + } + set.add(key); + } else { + // By directly retrieving the value we prevent another b.has(key) check in + // almost all possible cases. + const item2 = b.get(key); + if ((item2 === undefined && !b.has(key) || + !innerDeepEqual(item1, item2, strict, memo)) && + (strict || !mapHasLoosePrim(a, b, key, memo, item1, item2))) { return false; } - } else if (!innerDeepEqual(item1, item2, strict, memo) && - (strict || !mapHasLoosePrim(a, b, key, memo, item1, item2))) { - return false; } }