sync
This commit is contained in:
@@ -1,11 +0,0 @@
|
||||
export function looseEquals<T>(a: T, b: T) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
export function strictEquals<T>(a: T, b: T) {
|
||||
return a === b;
|
||||
}
|
||||
|
||||
export function sameValue<T>(a: T, b: T) {
|
||||
return Object.is(a, b);
|
||||
}
|
||||
167
src/equality-comparer/sync.ts
Normal file
167
src/equality-comparer/sync.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
import { Converter } from "../types.js";
|
||||
import { Nullable } from "../utils.js";
|
||||
import { EqualityComparer, EqualityComparison, EqualityComparisonOrComparer } from "./types.js";
|
||||
|
||||
export function looseEquals<T>(a: T, b: T) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
export function strictEquals<T>(a: T, b: T) {
|
||||
return a === b;
|
||||
}
|
||||
|
||||
export function sameValue<T>(a: T, b: T) {
|
||||
return Object.is(a, b);
|
||||
}
|
||||
|
||||
export function isEqualityComparer<T>(obj: any): obj is EqualityComparer<T> {
|
||||
return obj instanceof BaseEqualityComparer;
|
||||
}
|
||||
|
||||
export function asEqualityComparer<T>(equalityComparer: EqualityComparisonOrComparer<T>) {
|
||||
return typeof equalityComparer === "function" ? createEqualityComparer(equalityComparer) : equalityComparer;
|
||||
}
|
||||
|
||||
export function asEqualityComparison<T>(equalityComparer: EqualityComparisonOrComparer<T>) {
|
||||
return typeof equalityComparer === "function" ? equalityComparer : equalityComparer.equalityComparison();
|
||||
}
|
||||
|
||||
export function createEqualityComparer<T = any>(equalityComparison: EqualityComparison<T>): EqualityComparer<T> {
|
||||
return new SimpleEqualityComparer(equalityComparison);
|
||||
}
|
||||
|
||||
export function createEqualityComparerUsing<T = any, U = any>(projection: Converter<T, U>, equalityComparison?: EqualityComparisonOrComparer<U>): EqualityComparer<T> {
|
||||
return new MappedEqualityComparer(projection, equalityComparison);
|
||||
}
|
||||
|
||||
export function oppositeEqualityComparison<T>(equalityComparison: EqualityComparison<T>): EqualityComparison<T> {
|
||||
return (a, b) => !equalityComparison(a, b);
|
||||
}
|
||||
|
||||
export function combineNullableEqualityComparers<T>(equalityComparers: Nullable<EqualityComparisonOrComparer<T>>[]) {
|
||||
let result = defaultEqualityComparer;
|
||||
|
||||
for (const equalityComparer of equalityComparers) {
|
||||
if (!equalityComparer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = result.then(asEqualityComparer(equalityComparer));
|
||||
}
|
||||
|
||||
return result === defaultEqualityComparer ? undefined : result;
|
||||
}
|
||||
|
||||
export abstract class BaseEqualityComparer<T> implements EqualityComparer<T> {
|
||||
#cachedBoundEqualityComparison: EqualityComparison<T> | undefined;
|
||||
|
||||
public abstract equals(a: T, b: T): boolean;
|
||||
|
||||
public equalityComparison(): EqualityComparison<T> {
|
||||
return this.#cachedBoundEqualityComparison ??= this.equals.bind(this);
|
||||
}
|
||||
|
||||
public opposite(): EqualityComparer<T> {
|
||||
return new OppositeEqualityComparer(this);
|
||||
}
|
||||
|
||||
public then(equalityComparer: EqualityComparer<T>): EqualityComparer<T> {
|
||||
return new ThenEqualityComparer(this, equalityComparer);
|
||||
}
|
||||
|
||||
public thenEquals(equalityComparison: EqualityComparison<T>): EqualityComparer<T> {
|
||||
return this.then(createEqualityComparer(equalityComparison));
|
||||
}
|
||||
|
||||
public thenEqualsUsing<U>(projection: Converter<T, U>, equalityComparison?: EqualityComparisonOrComparer<U>): EqualityComparer<T> {
|
||||
return this.then(createEqualityComparerUsing(projection, equalityComparison));
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleEqualityComparer<T> extends BaseEqualityComparer<T> {
|
||||
readonly #equalityComparison: EqualityComparison<T>;
|
||||
|
||||
public constructor(equalityComparison: EqualityComparison<T>) {
|
||||
super();
|
||||
|
||||
this.#equalityComparison = equalityComparison;
|
||||
}
|
||||
|
||||
public override equals(a: T, b: T): boolean {
|
||||
return this.#equalityComparison(a, b);
|
||||
}
|
||||
|
||||
public override equalityComparison() {
|
||||
return this.#equalityComparison;
|
||||
}
|
||||
}
|
||||
|
||||
class MappedEqualityComparer<T, U> extends BaseEqualityComparer<T> {
|
||||
readonly #projection: Converter<T, U>;
|
||||
readonly #equalityComparison: EqualityComparer<U>;
|
||||
|
||||
public constructor(projection: Converter<T, U>, equalityComparison?: EqualityComparisonOrComparer<U>) {
|
||||
super();
|
||||
|
||||
this.#projection = projection;
|
||||
this.#equalityComparison = equalityComparison ? asEqualityComparer(equalityComparison) : defaultEqualityComparer;
|
||||
}
|
||||
|
||||
public override equals(a: T, b: T): boolean {
|
||||
return this.#equalityComparison.equals(this.#projection(a), this.#projection(b));
|
||||
}
|
||||
}
|
||||
|
||||
class OppositeEqualityComparer<T> extends BaseEqualityComparer<T> {
|
||||
readonly #base: EqualityComparer<T>;
|
||||
|
||||
public constructor(base: EqualityComparer<T>) {
|
||||
super();
|
||||
|
||||
this.#base = base;
|
||||
}
|
||||
|
||||
public override equals(a: T, b: T): boolean {
|
||||
return !this.#base.equals(a, b);
|
||||
}
|
||||
|
||||
public override opposite(): EqualityComparer<T> {
|
||||
return this.#base;
|
||||
}
|
||||
}
|
||||
|
||||
class ThenEqualityComparer<T> extends BaseEqualityComparer<T> {
|
||||
readonly #base: EqualityComparer<T>;
|
||||
readonly #equalityComparer: EqualityComparer<T>;
|
||||
|
||||
public constructor(base: EqualityComparer<T>, equalityComparer: EqualityComparer<T>) {
|
||||
super();
|
||||
|
||||
this.#base = base;
|
||||
this.#equalityComparer = equalityComparer;
|
||||
}
|
||||
|
||||
public override equals(a: T, b: T) {
|
||||
return this.#base.equals(a, b) && this.#equalityComparer.equals(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
export const defaultEqualityComparer: EqualityComparer<any> = new class DefaultEqualityComparer extends BaseEqualityComparer<any> {
|
||||
public override equals(a: any, b: any): boolean {
|
||||
return a === b;
|
||||
}
|
||||
};
|
||||
|
||||
export function getDefaultComparer<T>(): EqualityComparer<T> {
|
||||
return defaultEqualityComparer;
|
||||
}
|
||||
|
||||
export const dateComparer: EqualityComparer<Date> = new class DateEqualityComparer extends BaseEqualityComparer<Date> {
|
||||
public override equals(a: Date, b: Date): boolean {
|
||||
return a.getTime() === b.getTime();
|
||||
}
|
||||
};
|
||||
|
||||
export const looseEqualsComparer: EqualityComparer<any> = new SimpleEqualityComparer<any>(looseEquals);
|
||||
export const strictEqualsComparer: EqualityComparer<any> = new SimpleEqualityComparer<any>(strictEquals);
|
||||
export const sameValueComparer: EqualityComparer<any> = new SimpleEqualityComparer<any>(sameValue);
|
||||
@@ -1,6 +1,15 @@
|
||||
import { AsyncFunction, MaybeAsyncFunction } from "../types.js";
|
||||
import { Converter, MaybeAsyncFunction } from "../types.js";
|
||||
|
||||
export interface EqualityComparer<T> {
|
||||
equals(a: T, b: T): boolean;
|
||||
equalityComparison(): EqualityComparison<T>;
|
||||
opposite(): EqualityComparer<T>;
|
||||
then(equalityComparer: EqualityComparer<T>): EqualityComparer<T>;
|
||||
thenEquals(equalityComparison: EqualityComparison<T>): EqualityComparer<T>;
|
||||
thenEqualsUsing<U>(projection: Converter<T, U>, equalityComparison?: EqualityComparisonOrComparer<U>): EqualityComparer<T>;
|
||||
}
|
||||
|
||||
export type EqualityComparison<T> = (first: T, second: T) => boolean;
|
||||
export type EqualityComparisonOrComparer<T> = EqualityComparison<T> | EqualityComparer<T>;
|
||||
|
||||
export type AsyncEqualityComparison<T> = AsyncFunction<EqualityComparison<T>>;
|
||||
export type MaybeAsyncEqualityComparison<T> = MaybeAsyncFunction<EqualityComparison<T>>;
|
||||
|
||||
Reference in New Issue
Block a user