From fd6b0f61b0417df57932046ab6894e70c0445019 Mon Sep 17 00:00:00 2001 From: stereobooster Date: Sun, 6 Dec 2020 07:07:14 +0100 Subject: [PATCH 1/3] Support cyclic objects --- build.js | 8 ++++---- src/index.jst | 14 ++++++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/build.js b/build.js index e236a9a..8352dc2 100644 --- a/build.js +++ b/build.js @@ -5,8 +5,8 @@ var doT = require('dot'); doT.templateSettings.strip = false; var jst = doT.compile(fs.readFileSync('./src/index.jst', 'utf8')); -fs.writeFileSync('./index.js', jst({es6: false})); -fs.writeFileSync('./react.js', jst({es6: false, react: true})); +fs.writeFileSync('./index.js', jst({es6: false, cycles: false })); +fs.writeFileSync('./react.js', jst({es6: false, react: true, cycles: true })); try { fs.mkdirSync('./es6'); } catch(e) {} -fs.writeFileSync('./es6/index.js', jst({es6: true})); -fs.writeFileSync('./es6/react.js', jst({es6: true, react: true})); +fs.writeFileSync('./es6/index.js', jst({es6: true, cycles: false })); +fs.writeFileSync('./es6/react.js', jst({es6: true, react: true, cycles: false })); diff --git a/src/index.jst b/src/index.jst index 5d4ee2f..acb84a5 100644 --- a/src/index.jst +++ b/src/index.jst @@ -6,18 +6,24 @@ var envHasBigInt64Array = typeof BigInt64Array !== 'undefined'; {{?}} -module.exports = function equal(a, b) { +module.exports = function equal(a, b, compared) { if (a === b) return true; if (a && b && typeof a == 'object' && typeof b == 'object') { if (a.constructor !== b.constructor) return false; +{{? it.es6 && it.cycles }} + if (!compared) compared = new WeakMap(); + if (compared.has(a)) return compared.get(a) === b; + compared.set(a, b); +{{?}} + var length, i, keys; if (Array.isArray(a)) { length = a.length; if (length != b.length) return false; for (i = length; i-- !== 0;) - if (!equal(a[i], b[i])) return false; + if (!equal(a[i], b[i], compared)) return false; return true; } @@ -27,7 +33,7 @@ module.exports = function equal(a, b) { for (i of a.entries()) if (!b.has(i[0])) return false; for (i of a.entries()) - if (!equal(i[1], b.get(i[0]))) return false; + if (!equal(i[1], b.get(i[0]), compared)) return false; return true; } @@ -68,7 +74,7 @@ module.exports = function equal(a, b) { continue; } {{?}} - if (!equal(a[key], b[key])) return false; + if (!equal(a[key], b[key], compared)) return false; } return true; From 9f141123869b03674913a4a43e954eb15cd5700a Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Sun, 7 Jul 2019 19:17:52 +0100 Subject: [PATCH 2/3] support objects with cycles --- benchmark/index.js | 1 + build.js | 11 +++-- spec/cycle_tests.js | 105 ++++++++++++++++++++++++++++++++++++++++++++ spec/index.spec.js | 4 ++ src/index.jst | 7 +-- 5 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 spec/cycle_tests.js diff --git a/benchmark/index.js b/benchmark/index.js index 537a144..88c8e47 100644 --- a/benchmark/index.js +++ b/benchmark/index.js @@ -9,6 +9,7 @@ const suite = new Benchmark.Suite; const equalPackages = { 'fast-deep-equal': require('..'), 'fast-deep-equal/es6': require('../es6'), + 'fast-deep-equal/es6cycles': require('../es6cycles'), 'fast-equals': require('fast-equals').deepEqual, 'nano-equal': true, 'shallow-equal-fuzzy': true, diff --git a/build.js b/build.js index 8352dc2..43f82b1 100644 --- a/build.js +++ b/build.js @@ -5,8 +5,11 @@ var doT = require('dot'); doT.templateSettings.strip = false; var jst = doT.compile(fs.readFileSync('./src/index.jst', 'utf8')); -fs.writeFileSync('./index.js', jst({es6: false, cycles: false })); -fs.writeFileSync('./react.js', jst({es6: false, react: true, cycles: true })); +fs.writeFileSync('./index.js', jst({es6: false })); +fs.writeFileSync('./react.js', jst({es6: false, react: true })); try { fs.mkdirSync('./es6'); } catch(e) {} -fs.writeFileSync('./es6/index.js', jst({es6: true, cycles: false })); -fs.writeFileSync('./es6/react.js', jst({es6: true, react: true, cycles: false })); +fs.writeFileSync('./es6/index.js', jst({es6: true })); +fs.writeFileSync('./es6/react.js', jst({es6: true, react: true })); +try { fs.mkdirSync('./es6cycles'); } catch(e) {} +fs.writeFileSync('./es6cycles/index.js', jst({es6: true, cycles: true})); +fs.writeFileSync('./es6cycles/react.js', jst({es6: true, react: true, cycles: true })); diff --git a/spec/cycle_tests.js b/spec/cycle_tests.js new file mode 100644 index 0000000..edb8021 --- /dev/null +++ b/spec/cycle_tests.js @@ -0,0 +1,105 @@ +'use strict'; + +var obj1 = {a: 1, b: 2}; +var obj2 = {a: 1, b: 2}; +var obj3 = {a: 1, b: 2}; +obj1.c = obj2; +obj2.c = obj3; +obj3.c = obj3; + +var obj4 = {e: 3, f: 4}; +var obj5 = {a: 1, b: 2}; +var obj6 = {a: 1, b: 2}; +obj4.c = obj4; +obj5.c = obj4; +obj6.c = obj6; + +var obj7 = {a: 1, b: 2}; +var obj8 = {a: 1, b: 2}; +var obj9 = {a: 1, b: 2}; +obj7.c = obj7; +obj8.c = obj9; +obj9.c = obj8; + +var arr1 = [1, 2]; +var arr2 = [1, 2]; +var arr3 = [1, 2]; +arr1.push(arr2); +arr2.push(arr3); +arr3.push(arr3); + +var arr4 = [3, 4]; +var arr5 = [1, 2]; +var arr6 = [1, 2]; +arr4.push(arr4); +arr5.push(arr4); +arr6.push(arr6); + + +module.exports = [ + { + description: 'cyclic objects', + tests: [ + { + description: 'equal cyclic objects #1', + value1: obj1, + value2: obj2, + equal: true + }, + { + description: 'equal cyclic objects #2', + value1: obj1, + value2: obj3, + equal: true + }, + { + description: 'equal cyclic objects #3', + value1: obj2, + value2: obj3, + equal: true + }, + { + description: 'equal cyclic objects #4', + value1: obj7, + value2: obj8, + equal: true + }, + { + description: 'not equal cyclic objects', + value1: obj5, + value2: obj6, + equal: false + } + ] + }, + + { + description: 'cyclic arrays', + tests: [ + { + description: 'equal cyclic arrays #1', + value1: arr1, + value2: arr2, + equal: true + }, + { + description: 'equal cyclic arrays #2', + value1: arr1, + value2: arr3, + equal: true + }, + { + description: 'equal cyclic arrays #3', + value1: arr2, + value2: arr3, + equal: true + }, + { + description: 'not equal cyclic arrays', + value1: arr5, + value2: arr6, + equal: false + } + ] + }, +]; diff --git a/spec/index.spec.js b/spec/index.spec.js index 7ef1c54..5489f13 100644 --- a/spec/index.spec.js +++ b/spec/index.spec.js @@ -4,11 +4,15 @@ var equal = require('..'); var equalReact = require('../react'); var es6equal = require('../es6'); var es6equalReact = require('../es6/react'); +var es6cyclesEqual = require('../es6cycles'); var assert = require('assert'); testCases(equal, 'equal - standard tests', require('./tests')); testCases(es6equal, 'es6 equal - standard tests', require('./tests')); testCases(es6equal, 'es6 equal - es6 tests', require('./es6tests')); +testCases(es6cyclesEqual, 'es6 cycles equal - standard tests', require('./tests')); +testCases(es6cyclesEqual, 'es6 cycles equal - es6 tests', require('./es6tests')); +testCases(es6cyclesEqual, 'es6 cycles equal - cycle tests', require('./cycle_tests')); testCases(equalReact, 'equal react - standard tests', require('./tests')); testCases(es6equalReact, 'es6 equal react - standard tests', require('./tests')); diff --git a/src/index.jst b/src/index.jst index acb84a5..b9e023d 100644 --- a/src/index.jst +++ b/src/index.jst @@ -13,9 +13,10 @@ module.exports = function equal(a, b, compared) { if (a.constructor !== b.constructor) return false; {{? it.es6 && it.cycles }} - if (!compared) compared = new WeakMap(); - if (compared.has(a)) return compared.get(a) === b; - compared.set(a, b); + if (!compared) compared = { a: new WeakMap(), b: new WeakMap() }; + if (compared.a.has(a) && compared.b.has(b)) return true; + if (!compared.a.has(a)) compared.a.set(a, true); + if (!compared.b.has(b)) compared.b.set(b, true); {{?}} var length, i, keys; From 2f6ddd658a517d9a3a7ccb710e23a9b7f74561c3 Mon Sep 17 00:00:00 2001 From: stereobooster Date: Sun, 6 Dec 2020 08:58:20 +0100 Subject: [PATCH 3/3] Use Set instead of WeakMap --- src/index.jst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.jst b/src/index.jst index b9e023d..0a4ef01 100644 --- a/src/index.jst +++ b/src/index.jst @@ -13,10 +13,10 @@ module.exports = function equal(a, b, compared) { if (a.constructor !== b.constructor) return false; {{? it.es6 && it.cycles }} - if (!compared) compared = { a: new WeakMap(), b: new WeakMap() }; + if (!compared) compared = { a: new Set(), b: new Set() }; if (compared.a.has(a) && compared.b.has(b)) return true; - if (!compared.a.has(a)) compared.a.set(a, true); - if (!compared.b.has(b)) compared.b.set(b, true); + if (!compared.a.has(a)) compared.a.add(a); + if (!compared.b.has(b)) compared.b.add(b); {{?}} var length, i, keys;