Files
Webklar.com/node_modules/fast-equals/src/equals.ts
Basilosaurusrex f027651f9b main repo
2025-11-24 18:09:40 +01:00

301 lines
6.1 KiB
TypeScript

import { getStrictProperties, hasOwn, sameValueZeroEqual } from './utils';
import type {
Dictionary,
PrimitiveWrapper,
State,
TypedArray,
} from './internalTypes';
const OWNER = '_owner';
const { getOwnPropertyDescriptor, keys } = Object;
/**
* Whether the arrays are equal in value.
*/
export function areArraysEqual(a: any[], b: any[], state: State<any>) {
let index = a.length;
if (b.length !== index) {
return false;
}
while (index-- > 0) {
if (!state.equals(a[index], b[index], index, index, a, b, state)) {
return false;
}
}
return true;
}
/**
* Whether the dates passed are equal in value.
*/
export function areDatesEqual(a: Date, b: Date): boolean {
return sameValueZeroEqual(a.getTime(), b.getTime());
}
/**
* Whether the `Map`s are equal in value.
*/
export function areMapsEqual(
a: Map<any, any>,
b: Map<any, any>,
state: State<any>,
): boolean {
if (a.size !== b.size) {
return false;
}
const matchedIndices: Record<number, true> = {};
const aIterable = a.entries();
let index = 0;
let aResult: IteratorResult<[any, any]>;
let bResult: IteratorResult<[any, any]>;
while ((aResult = aIterable.next())) {
if (aResult.done) {
break;
}
const bIterable = b.entries();
let hasMatch = false;
let matchIndex = 0;
while ((bResult = bIterable.next())) {
if (bResult.done) {
break;
}
const [aKey, aValue] = aResult.value;
const [bKey, bValue] = bResult.value;
if (
!hasMatch &&
!matchedIndices[matchIndex] &&
(hasMatch =
state.equals(aKey, bKey, index, matchIndex, a, b, state) &&
state.equals(aValue, bValue, aKey, bKey, a, b, state))
) {
matchedIndices[matchIndex] = true;
}
matchIndex++;
}
if (!hasMatch) {
return false;
}
index++;
}
return true;
}
/**
* Whether the objects are equal in value.
*/
export function areObjectsEqual(
a: Dictionary,
b: Dictionary,
state: State<any>,
): boolean {
const properties = keys(a);
let index = properties.length;
if (keys(b).length !== index) {
return false;
}
let property: string;
// Decrementing `while` showed faster results than either incrementing or
// decrementing `for` loop and than an incrementing `while` loop. Declarative
// methods like `some` / `every` were not used to avoid incurring the garbage
// cost of anonymous callbacks.
while (index-- > 0) {
property = properties[index]!;
if (
property === OWNER &&
(a.$$typeof || b.$$typeof) &&
a.$$typeof !== b.$$typeof
) {
return false;
}
if (
!hasOwn(b, property) ||
!state.equals(a[property], b[property], property, property, a, b, state)
) {
return false;
}
}
return true;
}
/**
* Whether the objects are equal in value with strict property checking.
*/
export function areObjectsEqualStrict(
a: Dictionary,
b: Dictionary,
state: State<any>,
): boolean {
const properties = getStrictProperties(a);
let index = properties.length;
if (getStrictProperties(b).length !== index) {
return false;
}
let property: string | symbol;
let descriptorA: ReturnType<typeof getOwnPropertyDescriptor>;
let descriptorB: ReturnType<typeof getOwnPropertyDescriptor>;
// Decrementing `while` showed faster results than either incrementing or
// decrementing `for` loop and than an incrementing `while` loop. Declarative
// methods like `some` / `every` were not used to avoid incurring the garbage
// cost of anonymous callbacks.
while (index-- > 0) {
property = properties[index]!;
if (
property === OWNER &&
(a.$$typeof || b.$$typeof) &&
a.$$typeof !== b.$$typeof
) {
return false;
}
if (!hasOwn(b, property)) {
return false;
}
if (
!state.equals(a[property], b[property], property, property, a, b, state)
) {
return false;
}
descriptorA = getOwnPropertyDescriptor(a, property);
descriptorB = getOwnPropertyDescriptor(b, property);
if (
(descriptorA || descriptorB) &&
(!descriptorA ||
!descriptorB ||
descriptorA.configurable !== descriptorB.configurable ||
descriptorA.enumerable !== descriptorB.enumerable ||
descriptorA.writable !== descriptorB.writable)
) {
return false;
}
}
return true;
}
/**
* Whether the primitive wrappers passed are equal in value.
*/
export function arePrimitiveWrappersEqual(
a: PrimitiveWrapper,
b: PrimitiveWrapper,
): boolean {
return sameValueZeroEqual(a.valueOf(), b.valueOf());
}
/**
* Whether the regexps passed are equal in value.
*/
export function areRegExpsEqual(a: RegExp, b: RegExp): boolean {
return a.source === b.source && a.flags === b.flags;
}
/**
* Whether the `Set`s are equal in value.
*/
export function areSetsEqual(
a: Set<any>,
b: Set<any>,
state: State<any>,
): boolean {
if (a.size !== b.size) {
return false;
}
const matchedIndices: Record<number, true> = {};
const aIterable = a.values();
let aResult: IteratorResult<any>;
let bResult: IteratorResult<any>;
while ((aResult = aIterable.next())) {
if (aResult.done) {
break;
}
const bIterable = b.values();
let hasMatch = false;
let matchIndex = 0;
while ((bResult = bIterable.next())) {
if (bResult.done) {
break;
}
if (
!hasMatch &&
!matchedIndices[matchIndex] &&
(hasMatch = state.equals(
aResult.value,
bResult.value,
aResult.value,
bResult.value,
a,
b,
state,
))
) {
matchedIndices[matchIndex] = true;
}
matchIndex++;
}
if (!hasMatch) {
return false;
}
}
return true;
}
/**
* Whether the TypedArray instances are equal in value.
*/
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;
}