Skip to content

Commit

Permalink
Merge pull request #8 from jsonjoy-com/equal
Browse files Browse the repository at this point in the history
Improve perf and use Array.isArray() in deep equal
  • Loading branch information
streamich authored Oct 6, 2024
2 parents 05f9719 + d1bbeba commit 7f0f546
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 25 deletions.
30 changes: 12 additions & 18 deletions src/json-equal/__bench__/bench.deepEqual.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// npx ts-node src/json-equal/__bench__/bench.deepEqual.ts

/* tslint:disable no-console */

import * as Benchmark from 'benchmark';
import {deepEqual as deepEqualV1} from '../deepEqual/v1';
import {deepEqual as deepEqualV2} from '../deepEqual/v2';
import {deepEqual as deepEqualV3} from '../deepEqual/v3';
import {deepEqual as deepEqualV4} from '../deepEqual/v3';
import {deepEqual as deepEqualV4} from '../deepEqual/v4';
import {deepEqual as deepEqualV5} from '../deepEqual/v5';
import {$$deepEqual} from '../$$deepEqual';
const fastDeepEqual = require('fast-deep-equal/es6');
const fastEquals = require('fast-equals').deepEqual;
const lodashIsEqual = require('lodash').isEqual;

const json1 = {
foo: 'bar',
Expand All @@ -27,31 +27,25 @@ const equalGenerated1 = eval($$deepEqual(json1));
const suite = new Benchmark.Suite();

suite
.add(`json-equal (v1)`, () => {
.add(`json-joy/json-equal (v1)`, () => {
deepEqualV1(json1, json2);
})
.add(`json-equal (v2)`, () => {
.add(`json-joy/json-equal (v2)`, () => {
deepEqualV2(json1, json2);
})
.add(`json-equal (v3)`, () => {
.add(`json-joy/json-equal (v3)`, () => {
deepEqualV3(json1, json2);
})
.add(`json-equal (v4)`, () => {
.add(`json-joy/json-equal (v4)`, () => {
deepEqualV4(json1, json2);
})
.add(`fast-deep-equal`, () => {
fastDeepEqual(json1, json2);
})
.add(`fast-equals`, () => {
fastEquals(json1, json2);
})
.add(`lodash.isEqual`, () => {
lodashIsEqual(json1, json2);
.add(`json-joy/json-equal (v5)`, () => {
deepEqualV5(json1, json2);
})
.add(`json-equal/$$deepEqual`, () => {
.add(`json-joy/json-equal/$$deepEqual`, () => {
equalGenerated1(json2);
})
.add(`json-equal/$$deepEqual (with codegen)`, () => {
.add(`json-joy/json-equal/$$deepEqual (with codegen)`, () => {
// tslint:disable-next-line no-eval eval ban
const equalGenerated1 = eval($$deepEqual(json1));
equalGenerated1(json2);
Expand Down
12 changes: 9 additions & 3 deletions src/json-equal/deepEqual/__tests__/deepEqual.fuzzing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@ for (let i = 0; i < 100; i++) {
const res1 = deepEqual(json1, json1);
const res2 = deepEqual(json1, json2);
const res3 = deepEqual(json2, json1);
expect(res1).toBe(true);
expect(res2).toBe(true);
expect(res3).toBe(true);
try {
expect(res1).toBe(true);
expect(res2).toBe(true);
expect(res3).toBe(true);
} catch (error) {
// tslint:disable-next-line no-console
console.log({json1, json2});
throw error;
}
});
}
10 changes: 7 additions & 3 deletions src/json-equal/deepEqual/__tests__/runDeepEqualTestSuite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ export const runDeepEqualTestSuite = (deepEqual: (a: unknown, b: unknown) => boo
for (const t of s.tests) {
test(t.description, () => {
const res1 = deepEqual(t.value1, t.value2);
const res2 = deepEqual(t.value1, t.value2);
expect(res1).toBe(t.equal);
expect(res2).toBe(t.equal);
const res2 = deepEqual(t.value2, t.value1);
try {
expect(res1).toBe(t.equal);
expect(res2).toBe(t.equal);
} catch (error) {
throw error;
}
});
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/json-equal/deepEqual/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './v1';
export * from './v5';
31 changes: 31 additions & 0 deletions src/json-equal/deepEqual/v5.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const isArray = Array.isArray;

export const deepEqual = (a: unknown, b: unknown): boolean => {
// Primitives
if (a === b) return true;

// Arrays
let length, i, keys;
if (isArray(a)) {
if (!isArray(b)) return false;
length = a.length;
if (length !== (b as Array<unknown>).length) return false;
for (i = length; i-- !== 0; ) if (!deepEqual(a[i], (b as Array<unknown>)[i])) return false;
return true;
}

// Objects
if (a && b && typeof a === 'object' && typeof b === 'object') {
keys = Object.keys(a);
length = keys.length;
if (length !== Object.keys(b).length) return false;
if (isArray(b)) return false;
for (i = length; i-- !== 0; ) {
const key = keys[i];
if (!deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])) return false;
}
return true;
}

return false;
};

0 comments on commit 7f0f546

Please sign in to comment.