Skip to content

Commit 2628004

Browse files
authored
Merge pull request #9 from jsonjoy-com/equality
Equality support for `Uint8Array`
2 parents 7f0f546 + 0350a8a commit 2628004

File tree

10 files changed

+118
-19
lines changed

10 files changed

+118
-19
lines changed

src/json-equal/__bench__/bench.deepEqual.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {deepEqual as deepEqualV2} from '../deepEqual/v2';
88
import {deepEqual as deepEqualV3} from '../deepEqual/v3';
99
import {deepEqual as deepEqualV4} from '../deepEqual/v4';
1010
import {deepEqual as deepEqualV5} from '../deepEqual/v5';
11-
import {$$deepEqual} from '../$$deepEqual';
11+
import {deepEqual as deepEqualV6} from '../deepEqual/v6';
12+
import {deepEqualCodegen} from '../deepEqualCodegen';
1213

1314
const json1 = {
1415
foo: 'bar',
@@ -22,7 +23,7 @@ const json2 = {
2223
};
2324

2425
// tslint:disable-next-line no-eval eval ban
25-
const equalGenerated1 = eval($$deepEqual(json1));
26+
const equalGenerated1 = eval(deepEqualCodegen(json1));
2627

2728
const suite = new Benchmark.Suite();
2829

@@ -42,12 +43,15 @@ suite
4243
.add(`json-joy/json-equal (v5)`, () => {
4344
deepEqualV5(json1, json2);
4445
})
46+
.add(`json-joy/json-equal (v6)`, () => {
47+
deepEqualV6(json1, json2);
48+
})
4549
.add(`json-joy/json-equal/$$deepEqual`, () => {
4650
equalGenerated1(json2);
4751
})
4852
.add(`json-joy/json-equal/$$deepEqual (with codegen)`, () => {
4953
// tslint:disable-next-line no-eval eval ban
50-
const equalGenerated1 = eval($$deepEqual(json1));
54+
const equalGenerated1 = eval(deepEqualCodegen(json1));
5155
equalGenerated1(json2);
5256
})
5357
.on('cycle', (event: any) => {

src/json-equal/deepEqual/__tests__/tests.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import {b} from '../../../buffers/b';
2+
13
interface Test {
24
description: string;
35
value1: unknown;
@@ -251,6 +253,42 @@ export const tests: Suite[] = [
251253
],
252254
},
253255

256+
{
257+
description: 'binary',
258+
tests: [
259+
{
260+
description: 'two empty blobs',
261+
value1: new Uint8Array(0),
262+
value2: new Uint8Array(0),
263+
equal: true,
264+
},
265+
{
266+
description: 'two single char blobs',
267+
value1: b(0),
268+
value2: b(0),
269+
equal: true,
270+
},
271+
{
272+
description: 'small blobs',
273+
value1: b(1, 2, 3),
274+
value2: b(1, 2, 3),
275+
equal: true,
276+
},
277+
{
278+
description: 'empty blob not equal to empty array',
279+
value1: b(),
280+
value2: [],
281+
equal: false,
282+
},
283+
{
284+
description: 'empty blob not equal to non-empty blob',
285+
value1: b(),
286+
value2: b(1),
287+
equal: false,
288+
},
289+
],
290+
},
291+
254292
{
255293
description: 'sample objects',
256294
tests: [

src/json-equal/deepEqual/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export * from './v5';
1+
export * from './v6';

src/json-equal/deepEqual/v6.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
const isArray = Array.isArray;
2+
const OBJ_PROTO = Object.prototype;
3+
4+
export const deepEqual = (a: unknown, b: unknown): boolean => {
5+
// Primitives
6+
if (a === b) return true;
7+
8+
let length: number = 0,
9+
i: number = 0;
10+
11+
// Arrays
12+
if (isArray(a)) {
13+
if (!isArray(b)) return false;
14+
length = a.length;
15+
if (length !== (b as Array<unknown>).length) return false;
16+
for (i = length; i-- !== 0; ) if (!deepEqual(a[i], (b as Array<unknown>)[i])) return false;
17+
return true;
18+
}
19+
20+
// Objects
21+
if (a && b && typeof a === 'object' && typeof b === 'object') {
22+
specific: {
23+
if ((<any>a).__proto__ === OBJ_PROTO) break specific;
24+
if (a instanceof Uint8Array) {
25+
if (!(b instanceof Uint8Array)) return false;
26+
const length = a.length;
27+
if (length !== b.length) return false;
28+
for (let i = 0; i < length; i++) if (a[i] !== b[i]) return false;
29+
return true;
30+
}
31+
}
32+
const keys = Object.keys(a);
33+
length = keys.length;
34+
if (length !== Object.keys(b).length) return false;
35+
if (isArray(b)) return false;
36+
for (i = length; i-- !== 0; ) {
37+
const key = keys[i];
38+
if (!deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])) return false;
39+
}
40+
return true;
41+
}
42+
43+
return false;
44+
};

src/json-equal/$$deepEqual/__tests__/deepEqual.fuzzing.spec.ts renamed to src/json-equal/deepEqualCodegen/__tests__/deepEqual.fuzzing.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import {$$deepEqual} from '..';
1+
import {deepEqualCodegen} from '..';
22
import {RandomJson} from '../../../json-random/RandomJson';
33

44
const deepEqual = (a: unknown, b: unknown) => {
5-
const js = $$deepEqual(a);
5+
const js = deepEqualCodegen(a);
66
const fn = eval(js); // tslint:disable-line
77
return fn(b);
88
};

src/json-equal/$$deepEqual/__tests__/deepEqual.spec.ts renamed to src/json-equal/deepEqualCodegen/__tests__/deepEqual.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import {$$deepEqual} from '..';
1+
import {deepEqualCodegen} from '..';
22
import {runDeepEqualTestSuite} from '../../deepEqual/__tests__/runDeepEqualTestSuite';
33

44
const deepEqual = (a: unknown, b: unknown) => {
5-
const js = $$deepEqual(a);
5+
const js = deepEqualCodegen(a);
6+
// console.log(js);
67
const fn = eval(js); // tslint:disable-line
78
return fn(b);
89
};

src/json-equal/$$deepEqual/__tests__/deepEqualCodegen.spec.ts renamed to src/json-equal/deepEqualCodegen/__tests__/deepEqualCodegen.spec.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import {$$deepEqual} from '..';
1+
import {deepEqualCodegen} from '..';
22

33
test('generates a deep equal comparator', () => {
4-
const js = $$deepEqual([1, true, false, 'sdf', {foo: 123, null: null}, [null, true, 'asdf'], 3, {}]);
4+
const js = deepEqualCodegen([1, true, false, 'sdf', {foo: 123, null: null}, [null, true, 'asdf'], 3, {}]);
55
const deepEqual = eval(js); // tslint:disable-line
66

77
const res1 = deepEqual([1, true, false, 'sdf', {foo: 123, null: null}, [null, true, 'asdf'], 3, {}]);
@@ -17,12 +17,12 @@ test('generates a deep equal comparator', () => {
1717

1818
test('generates a deep equal comparator for primitives', () => {
1919
/* tslint:disable */
20-
const equal1 = eval($$deepEqual('asdf'));
21-
const equal2 = eval($$deepEqual(123));
22-
const equal3 = eval($$deepEqual(true));
23-
const equal4 = eval($$deepEqual(null));
24-
const equal5 = eval($$deepEqual(false));
25-
const equal6 = eval($$deepEqual(4.4));
20+
const equal1 = eval(deepEqualCodegen('asdf'));
21+
const equal2 = eval(deepEqualCodegen(123));
22+
const equal3 = eval(deepEqualCodegen(true));
23+
const equal4 = eval(deepEqualCodegen(null));
24+
const equal5 = eval(deepEqualCodegen(false));
25+
const equal6 = eval(deepEqualCodegen(4.4));
2626
/* tslint:enable */
2727

2828
expect(equal1('asdf')).toBe(true);
@@ -48,7 +48,7 @@ test('generates a deep equal comparator for primitives', () => {
4848
});
4949

5050
test('undefined is not an empty object', () => {
51-
const js = $$deepEqual(undefined);
51+
const js = deepEqualCodegen(undefined);
5252
const deepEqual = eval(js); // tslint:disable-line
5353
const res = deepEqual({});
5454
expect(res).toBe(false);

src/json-equal/$$deepEqual/v1.ts renamed to src/json-equal/deepEqualCodegen/v1.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ const codegenValue = (doc: unknown, code: string[], r: number): number => {
2828
return rr;
2929
}
3030

31+
// Uint8Array
32+
if (doc instanceof Uint8Array) {
33+
const length = doc.length;
34+
code.push(`if(!(r${r} instanceof Uint8Array) || r${r}.length !== ${length})return false;`);
35+
let condition = '';
36+
for (let i = 0; i < length; i++) condition += (condition ? '||' : '') + `(r${r}[${i}]!==${doc[i]})`;
37+
if (condition) code.push(`if(${condition})return false;`);
38+
return rr;
39+
}
40+
3141
// Objects
3242
if (type === 'object' && doc) {
3343
const obj = doc as Record<string, unknown>;
@@ -40,6 +50,7 @@ const codegenValue = (doc: unknown, code: string[], r: number): number => {
4050
code.push(`var r${rr}=r${r}[${JSON.stringify(key)}];`);
4151
rr = codegenValue(obj[key], code, rr);
4252
}
53+
return rr;
4354
}
4455

4556
// Undefined
@@ -51,7 +62,7 @@ const codegenValue = (doc: unknown, code: string[], r: number): number => {
5162
return rr;
5263
};
5364

54-
export const $$deepEqual = (a: unknown): JavaScript<(b: unknown) => boolean> => {
65+
export const deepEqualCodegen = (a: unknown): JavaScript<(b: unknown) => boolean> => {
5566
const code: string[] = [];
5667
codegenValue(a, code, 0);
5768

tslint.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"no-angle-bracket-type-assertion": false,
1515
"ban-comma-operator": false,
1616
"no-unused-expression": false,
17-
"no-implicit-dependencies": false
17+
"no-implicit-dependencies": false,
18+
"label-position": false
1819
}
1920
}

0 commit comments

Comments
 (0)