From bc62437fb6832e57b96f76b66307cc4332c241d1 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 5 May 2017 11:04:20 +0200 Subject: [PATCH] assert: improve deepEqual perf for large input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a Map instead of an array for checking previously found cyclic references. This reduces complexity for an array-of-objects case from O(n²) to O(n·log n). Fixes: https://github.com/nodejs/node/issues/12842 PR-URL: https://github.com/nodejs/node/pull/12849 Reviewed-By: Colin Ihrig Reviewed-By: Joyee Cheung Reviewed-By: James M Snell Reviewed-By: Jeremiah Senkpiel Reviewed-By: Refael Ackermann Reviewed-By: Rich Trott --- lib/assert.js | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/assert.js b/lib/assert.js index 28eb2fcf20cd8f..a1631ff2e6f428 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -285,15 +285,24 @@ function _deepEqual(actual, expected, strict, memos) { // Note: this accounts for both named and indexed properties on Arrays. // Use memos to handle cycles. - memos = memos || { actual: [], expected: [] }; - const actualIndex = memos.actual.indexOf(actual); - if (actualIndex !== -1) { - if (actualIndex === memos.expected.indexOf(expected)) { + if (!memos) { + memos = { + actual: { map: new Map(), position: 0 }, + expected: { map: new Map(), position: 0 } + }; + } + + const actualPosition = memos.actual.map.get(actual); + if (actualPosition !== undefined) { + if (actualPosition === memos.expected.map.get(expected)) { return true; } + } else { + memos.actual.map.set(actual, memos.actual.position++); + } + if (!memos.expected.map.has(expected)) { + memos.expected.map.set(expected, memos.expected.position++); } - memos.actual.push(actual); - memos.expected.push(expected); return objEquiv(actual, expected, strict, memos); }