Skip to content

Commit

Permalink
add TypedArray support
Browse files Browse the repository at this point in the history
  • Loading branch information
planttheidea committed Feb 26, 2023
1 parent 1425f2f commit 6ff9a7a
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 2 deletions.
18 changes: 18 additions & 0 deletions __tests__/__helpers__/dataTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ export const primitiveValues = {
export const mainValues = {
...primitiveValues,
array: ['foo', { bar: 'baz' }],
float32Array: new Float32Array([31, 21]),
float64Array: new Float64Array([31, 21]),
fn() {
return 'foo';
},
int8Array: new Int8Array([31, 21]),
int16Array: new Int16Array([31, 21]),
int32Array: new Int32Array([31, 21]),
map: new Map().set('foo', { bar: 'baz' }),
object: { foo: { bar: 'baz' } },
promise: Promise.resolve('foo'),
Expand All @@ -35,19 +40,32 @@ export const mainValues = {
),
regexp: /foo/,
set: new Set().add('foo').add({ bar: 'baz' }),
uint8Array: new Uint8Array([31, 21]),
uint8ClampedArray: new Uint8ClampedArray([31, 21]),
uint16Array: new Uint16Array([31, 21]),
uint32Array: new Uint32Array([31, 21]),
};

export const alternativeValues = {
array: [123, /foo/],
boolean: false,
float32Array: new Float32Array([21, 31]),
float64Array: new Float64Array([21, 31]),
fn() {
return 123;
},
int8Array: new Int8Array([21, 31]),
int16Array: new Int16Array([21, 31]),
int32Array: new Int32Array([21, 31]),
map: new Map().set({ bar: 'baz' }, 'foo'),
number: 234,
object: { bar: { baz: 'foo' } },
react: React.createElement('div', {}, 'foo'),
regexp: /bar/gi,
set: new Set().add({ bar: 'baz' }).add('foo'),
string: 'bar',
uint8Array: new Uint8Array([21, 31]),
uint8ClampedArray: new Uint8ClampedArray([21, 31]),
uint16Array: new Uint16Array([21, 31]),
uint32Array: new Uint32Array([21, 31]),
};
195 changes: 195 additions & 0 deletions __tests__/__helpers__/testSuites.js
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,201 @@ export default [
},
],
},
{
description: 'typed arrays',
tests: [
{
deepEqual: true,
description: 'equal Float32Array objects',
shallowEqual: true,
value1: new Float32Array([21, 31]),
value2: new Float32Array([21, 31]),
},
{
deepEqual: false,
description: 'not equal Float32Array objects (different value)',
shallowEqual: false,
value1: new Float32Array([21, 31]),
value2: new Float32Array([31, 21]),
},
{
deepEqual: false,
description: 'Float32Array and a different TypedArray are not equal',
shallowEqual: false,
value1: new Float32Array([21, 31]),
value2: new Float64Array([21, 31]),
},
{
deepEqual: true,
description: 'equal Float64Array objects',
shallowEqual: true,
value1: new Float64Array([21, 31]),
value2: new Float64Array([21, 31]),
},
{
deepEqual: false,
description: 'not equal Float32Array objects (different value)',
shallowEqual: false,
value1: new Float64Array([21, 31]),
value2: new Float64Array([31, 21]),
},
{
deepEqual: false,
description: 'Float64Array and a different TypedArray are not equal',
shallowEqual: false,
value1: new Float64Array([21, 31]),
value2: new Float32Array([21, 31]),
},
{
deepEqual: true,
description: 'equal Int8Array objects',
shallowEqual: true,
value1: new Int8Array([21, 31]),
value2: new Int8Array([21, 31]),
},
{
deepEqual: false,
description: 'not equal Int8Array objects (different value)',
shallowEqual: false,
value1: new Int8Array([21, 31]),
value2: new Int8Array([31, 21]),
},
{
deepEqual: false,
description: 'Int8Array and a different TypedArray are not equal',
shallowEqual: false,
value1: new Int8Array([21, 31]),
value2: new Int16Array([21, 31]),
},
{
deepEqual: true,
description: 'equal Int16Array objects',
shallowEqual: true,
value1: new Int16Array([21, 31]),
value2: new Int16Array([21, 31]),
},
{
deepEqual: false,
description: 'not equal Int16Array objects (different value)',
shallowEqual: false,
value1: new Int16Array([21, 31]),
value2: new Int16Array([31, 21]),
},
{
deepEqual: false,
description: 'Int16Array and a different TypedArray are not equal',
shallowEqual: false,
value1: new Int16Array([21, 31]),
value2: new Int32Array([21, 31]),
},
{
deepEqual: true,
description: 'equal Int32Array objects',
shallowEqual: true,
value1: new Int32Array([21, 31]),
value2: new Int32Array([21, 31]),
},
{
deepEqual: false,
description: 'not equal Int32Array objects (different value)',
shallowEqual: false,
value1: new Int32Array([21, 31]),
value2: new Int32Array([31, 21]),
},
{
deepEqual: false,
description: 'Int32Array and a different TypedArray are not equal',
shallowEqual: false,
value1: new Int32Array([21, 31]),
value2: new Int8Array([21, 31]),
},
{
deepEqual: true,
description: 'equal Uint8Array objects',
shallowEqual: true,
value1: new Uint8Array([21, 31]),
value2: new Uint8Array([21, 31]),
},
{
deepEqual: false,
description: 'not equal Uint8Array objects (different value)',
shallowEqual: false,
value1: new Uint8Array([21, 31]),
value2: new Uint8Array([31, 21]),
},
{
deepEqual: false,
description: 'Uint8Array and a different TypedArray are not equal',
shallowEqual: false,
value1: new Uint8Array([21, 31]),
value2: new Uint8ClampedArray([21, 31]),
},
{
deepEqual: true,
description: 'equal Uint8ClampedArray objects',
shallowEqual: true,
value1: new Uint8ClampedArray([21, 31]),
value2: new Uint8ClampedArray([21, 31]),
},
{
deepEqual: false,
description: 'not equal Uint8ClampedArray objects (different value)',
shallowEqual: false,
value1: new Uint8ClampedArray([21, 31]),
value2: new Uint8ClampedArray([31, 21]),
},
{
deepEqual: false,
description:
'Uint8ClampedArray and a different TypedArray are not equal',
shallowEqual: false,
value1: new Uint8ClampedArray([21, 31]),
value2: new Uint16Array([21, 31]),
},
{
deepEqual: true,
description: 'equal Uint16Array objects',
shallowEqual: true,
value1: new Uint16Array([21, 31]),
value2: new Uint16Array([21, 31]),
},
{
deepEqual: false,
description: 'not equal Uint16Array objects (different value)',
shallowEqual: false,
value1: new Uint16Array([21, 31]),
value2: new Uint16Array([31, 21]),
},
{
deepEqual: false,
description: 'Uint16Array and a different TypedArray are not equal',
shallowEqual: false,
value1: new Uint16Array([21, 31]),
value2: new Uint32Array([21, 31]),
},
{
deepEqual: true,
description: 'equal Uint32Array objects',
shallowEqual: true,
value1: new Uint32Array([21, 31]),
value2: new Uint32Array([21, 31]),
},
{
deepEqual: false,
description: 'not equal Uint32Array objects (different value)',
shallowEqual: false,
value1: new Uint32Array([21, 31]),
value2: new Uint32Array([31, 21]),
},
{
deepEqual: false,
description: 'Uint32Array and a different TypedArray are not equal',
shallowEqual: false,
value1: new Uint32Array([21, 31]),
value2: new Uint8Array([21, 31]),
},
],
},
{
description: 'mixed objects equal',
tests: [
Expand Down
2 changes: 2 additions & 0 deletions __tests__/comparator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
arePrimitiveWrappersEqual,
areRegExpsEqual,
areSetsEqual,
areTypedArraysEqual,
} from '../src/equals';
import { createInternalComparator, createIsCircular } from '../src/utils';

Expand All @@ -20,6 +21,7 @@ const STANDARD_COMPARATOR_OPTIONS = {
arePrimitiveWrappersEqual,
areRegExpsEqual,
areSetsEqual,
areTypedArraysEqual,
};
const CIRCULAR_COMPARATOR_OPTIONS = {
...STANDARD_COMPARATOR_OPTIONS,
Expand Down
42 changes: 41 additions & 1 deletion src/comparator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
arePrimitiveWrappersEqual as arePrimitiveWrappersEqualDefault,
areRegExpsEqual as areRegExpsEqualDefault,
areSetsEqual as areSetsEqualDefault,
areTypedArraysEqual,
} from './equals';
import { combineComparators, createIsCircular } from './utils';
import type {
Expand All @@ -19,12 +20,43 @@ import type {
const ARGUMENTS_TAG = '[object Arguments]';
const BOOLEAN_TAG = '[object Boolean]';
const DATE_TAG = '[object Date]';
const BIG_INT_64_ARRAY_TAG = '[object BigInt64Array]';
const BIG_UINT_64_ARRAY_TAG = '[object BigUint64Array]';
const FLOAT_32_ARRAY_TAG = '[object Float32Array]';
const FLOAT_64_ARRAY_TAG = '[object Float64Array]';
const INT_8_ARRAY_TAG = '[object Int8Array]';
const INT_16_ARRAY_TAG = '[object Int16Array]';
const INT_32_ARRAY_TAG = '[object Int32Array]';
const MAP_TAG = '[object Map]';
const NUMBER_TAG = '[object Number]';
const OBJECT_TAG = '[object Object]';
const REG_EXP_TAG = '[object RegExp]';
const SET_TAG = '[object Set]';
const STRING_TAG = '[object String]';
const UINT_8_ARRAY_TAG = '[object Uint8Array]';
const UINT_8_CLAMPED_ARRAY_TAG = '[object Uint8ClampedArray]';
const UINT_16_ARRAY_TAG = '[object Uint16Array]';
const UINT_32_ARRAY_TAG = '[object Uint32Array]';

const PRIMITIVE_WRAPPER: Record<string, true | undefined> = {
[BOOLEAN_TAG]: true,
[NUMBER_TAG]: true,
[STRING_TAG]: true,
};

const TYPED_ARRAY: Record<string, true | undefined> = {
[BIG_INT_64_ARRAY_TAG]: true,
[BIG_UINT_64_ARRAY_TAG]: true,
[FLOAT_32_ARRAY_TAG]: true,
[FLOAT_64_ARRAY_TAG]: true,
[INT_8_ARRAY_TAG]: true,
[INT_16_ARRAY_TAG]: true,
[INT_32_ARRAY_TAG]: true,
[UINT_8_ARRAY_TAG]: true,
[UINT_8_CLAMPED_ARRAY_TAG]: true,
[UINT_16_ARRAY_TAG]: true,
[UINT_32_ARRAY_TAG]: true,
};

const { isArray } = Array;
const { assign } = Object;
Expand All @@ -43,6 +75,7 @@ export function createComparator<Meta>({
arePrimitiveWrappersEqual,
areRegExpsEqual,
areSetsEqual,
areTypedArraysEqual,
}: ComparatorConfig<Meta>): EqualityComparator<Meta> {
/**
* compare the value of the two objects and return true if they are equivalent in values
Expand Down Expand Up @@ -131,10 +164,14 @@ export function createComparator<Meta>({
return areObjectsEqual(a, b, state);
}

if (TYPED_ARRAY[tag]) {
return areTypedArraysEqual(a, b, state);
}

// As the penultimate fallback, check if the values passed are primitive wrappers. This
// is very rare in modern JS, which is why it is deprioritized compared to all other object
// types.
if (tag === BOOLEAN_TAG || tag === NUMBER_TAG || tag === STRING_TAG) {
if (PRIMITIVE_WRAPPER[tag]) {
return arePrimitiveWrappersEqual(a, b, state);
}

Expand Down Expand Up @@ -177,6 +214,9 @@ export function createComparatorConfig<Meta>({
areSetsEqual: strict
? combineComparators(areSetsEqualDefault, areObjectsEqualStrictDefault)
: areSetsEqualDefault,
areTypedArraysEqual: strict
? combineComparators(areTypedArraysEqual, areObjectsEqualStrictDefault)
: areTypedArraysEqual,
};

if (createCustomConfig) {
Expand Down
18 changes: 17 additions & 1 deletion src/equals.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getStrictProperties, hasOwn, sameValueZeroEqual } from './utils';
import type { Dictionary, State } from './internalTypes';
import type { Dictionary, State, TypedArray } from './internalTypes';

const OWNER = '_owner';

Expand Down Expand Up @@ -248,3 +248,19 @@ export function areSetsEqual(

return isValueEqual;
}

export function areTypedArraysEqual(a: TypedArray, b: TypedArray) {
let index = a.length;

if (b.length !== index) {
return false;
}

while (index-- > 0) {
if (a[index] !== b[index]) {
return false;
}
}

return true;
}
Loading

0 comments on commit 6ff9a7a

Please sign in to comment.