sync
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import { Collector } from "../collector/types.js";
|
||||
import { asAsyncComparer, combineNullableAsyncComparers, createAsyncComparerUsing, defaultAsyncComparer } from "../comparer/async.js";
|
||||
import { MaybeAsyncComparisonOrComparer, AsyncComparer } from "../comparer/types.js";
|
||||
import { strictEquals } from "../equality-comparer/index.js";
|
||||
import { strictEquals } from "../equality-comparer/sync.js";
|
||||
import { MaybeAsyncEqualityComparison } from "../equality-comparer/types.js";
|
||||
import { createAsyncEqualityMap } from "../equality-map.js";
|
||||
import { createAsyncEqualitySet } from "../equality-set.js";
|
||||
import { createAsyncEqualityMap } from "../equality-map/index.js";
|
||||
import { createAsyncEqualitySet } from "../equality-set/index.js";
|
||||
import { createQueue } from "../queue.js";
|
||||
import { getRandomElementAsync } from "../random/index.js";
|
||||
import { AsyncRandomOptions } from "../random/types.js";
|
||||
|
||||
@@ -15,11 +15,11 @@ export function asComparison<T>(comparer: ComparisonOrComparer<T>) {
|
||||
return typeof comparer === "function" ? comparer : comparer.comparison();
|
||||
}
|
||||
|
||||
export function createComparer<T>(comparison: Comparison<T>): Comparer<T> {
|
||||
export function createComparer<T = any>(comparison: Comparison<T>): Comparer<T> {
|
||||
return new SimpleComparer(comparison);
|
||||
}
|
||||
|
||||
export function createComparerUsing<T, U>(projection: Converter<T, U>, comparison?: ComparisonOrComparer<U>): Comparer<T> {
|
||||
export function createComparerUsing<T = any, U = any>(projection: Converter<T, U>, comparison?: ComparisonOrComparer<U>): Comparer<T> {
|
||||
return new MappedComparer(projection, comparison);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,12 +24,9 @@ export interface AsyncComparer<T> {
|
||||
|
||||
export type Comparison<T> = (first: T, second: T) => number;
|
||||
export type ComparisonOrComparer<T> = Comparison<T> | Comparer<T>;
|
||||
export type Equater<T> = (first: T, second: T) => boolean;
|
||||
|
||||
export type AsyncComparison<T> = AsyncFunction<Comparison<T>>;
|
||||
export type MaybeAsyncComparison<T> = MaybeAsyncFunction<Comparison<T>>;
|
||||
export type AsyncComparisonOrComparer<T> = AsyncComparison<T> | AsyncComparer<T>;
|
||||
export type MaybeAsyncComparisonOrComparer<T> = MaybeAsyncComparison<T> | Comparer<T> | AsyncComparer<T>;
|
||||
export type AsyncEquater<T> = AsyncFunction<Equater<T>>;
|
||||
export type MaybeAsyncEquater<T> = MaybeAsyncFunction<Equater<T>>;
|
||||
|
||||
|
||||
@@ -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>>;
|
||||
|
||||
@@ -1,22 +1,9 @@
|
||||
import { EqualityComparison, MaybeAsyncEqualityComparison } from "./equality-comparer/types.js";
|
||||
import { MaybeAsyncIterable } from "./types.js";
|
||||
import { asEqualityComparer } from "../equality-comparer/sync.js";
|
||||
import { EqualityComparer, EqualityComparisonOrComparer, MaybeAsyncEqualityComparison } from "../equality-comparer/types.js";
|
||||
import { MaybeAsyncIterable } from "../types.js";
|
||||
import { AsyncEqualityMap, EqualityMap, EqualityMapEntry } from "./types.js";
|
||||
|
||||
export type Entry<K, V> = [key: K, value: V];
|
||||
|
||||
export interface EqualityMap<K, V> extends Iterable<Entry<K, V>> {
|
||||
readonly size: number;
|
||||
get(key: K): V | undefined;
|
||||
set(key: K, value: V): V | undefined;
|
||||
setAll(entries: Iterable<Entry<K, V>>): void;
|
||||
contains(key: K): boolean;
|
||||
remove(key: K): V | undefined;
|
||||
clear(): void;
|
||||
keys(): IterableIterator<K>;
|
||||
values(): IterableIterator<V>;
|
||||
entries(): IterableIterator<Entry<K, V>>;
|
||||
}
|
||||
|
||||
class NativeEqualityMap<K, V> implements EqualityMap<K, V> {
|
||||
export class NativeEqualityMap<K, V> implements EqualityMap<K, V> {
|
||||
readonly #map = new Map<K, V>();
|
||||
|
||||
get size() {
|
||||
@@ -33,7 +20,7 @@ class NativeEqualityMap<K, V> implements EqualityMap<K, V> {
|
||||
return existing;
|
||||
}
|
||||
|
||||
setAll(entries: Iterable<Entry<K, V>>) {
|
||||
setAll(entries: Iterable<EqualityMapEntry<K, V>>) {
|
||||
for (const [key, value] of entries) {
|
||||
this.set(key, value);
|
||||
}
|
||||
@@ -70,12 +57,12 @@ class NativeEqualityMap<K, V> implements EqualityMap<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
|
||||
readonly #list: Entry<K, V>[] = [];
|
||||
readonly #keyComparer: EqualityComparison<K>;
|
||||
export class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
|
||||
readonly #list: EqualityMapEntry<K, V>[] = [];
|
||||
readonly #keyComparer: EqualityComparer<K>;
|
||||
|
||||
constructor(keyComparer: EqualityComparison<K>) {
|
||||
this.#keyComparer = keyComparer;
|
||||
constructor(keyComparer: EqualityComparisonOrComparer<K>) {
|
||||
this.#keyComparer = asEqualityComparer(keyComparer);
|
||||
}
|
||||
|
||||
get size() {
|
||||
@@ -84,7 +71,7 @@ class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
|
||||
|
||||
get(key: K) {
|
||||
for (const entry of this.#list) {
|
||||
if (this.#keyComparer(key, entry[0])) {
|
||||
if (this.#keyComparer.equals(key, entry[0])) {
|
||||
return entry[1];
|
||||
}
|
||||
}
|
||||
@@ -94,7 +81,7 @@ class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
|
||||
|
||||
set(key: K, value: V) {
|
||||
for (const entry of this.#list) {
|
||||
if (this.#keyComparer(key, entry[0])) {
|
||||
if (this.#keyComparer.equals(key, entry[0])) {
|
||||
const previous = entry[1];
|
||||
entry[1] = value;
|
||||
return previous;
|
||||
@@ -106,7 +93,7 @@ class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
setAll(entries: Iterable<Entry<K, V>>) {
|
||||
setAll(entries: Iterable<EqualityMapEntry<K, V>>) {
|
||||
for (const [key, value] of entries) {
|
||||
this.set(key, value);
|
||||
}
|
||||
@@ -114,7 +101,7 @@ class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
|
||||
|
||||
contains(key: K) {
|
||||
for (const entry of this.#list) {
|
||||
if (this.#keyComparer(key, entry[0])) {
|
||||
if (this.#keyComparer.equals(key, entry[0])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -124,7 +111,7 @@ class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
|
||||
|
||||
remove(key: K) {
|
||||
for (let i = 0; i < this.#list.length; i++) {
|
||||
if (this.#keyComparer(key, this.#list[i][0])) {
|
||||
if (this.#keyComparer.equals(key, this.#list[i][0])) {
|
||||
const removed = this.#list.splice(i, 1);
|
||||
return removed[0][1];
|
||||
}
|
||||
@@ -155,29 +142,12 @@ class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
|
||||
|
||||
*[Symbol.iterator]() {
|
||||
for (const entry of this.#list) {
|
||||
yield entry.slice() as Entry<K, V>; // no entry mutation allowed!
|
||||
yield entry.slice() as EqualityMapEntry<K, V>; // no entry mutation allowed!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createEqualityMap<K, V>(keyComparer?: EqualityComparison<K>): EqualityMap<K, V> {
|
||||
return keyComparer ? new CustomEqualityMap<K, V>(keyComparer) : new NativeEqualityMap<K, V>();
|
||||
}
|
||||
|
||||
export interface AsyncEqualityMap<K, V> extends Iterable<Entry<K, V>> {
|
||||
readonly size: number;
|
||||
get(key: K): Promise<V | undefined>;
|
||||
set(key: K, value: V): Promise<V | undefined>;
|
||||
setAll(entries: MaybeAsyncIterable<Entry<K, V>>): Promise<void>;
|
||||
contains(key: K): Promise<boolean>;
|
||||
remove(key: K): Promise<V | undefined>;
|
||||
clear(): void;
|
||||
keys(): IterableIterator<K>;
|
||||
values(): IterableIterator<V>;
|
||||
entries(): IterableIterator<Entry<K, V>>;
|
||||
}
|
||||
|
||||
class NativeAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
|
||||
export class NativeAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
|
||||
readonly #map = new Map<K, V>();
|
||||
|
||||
get size() {
|
||||
@@ -194,7 +164,7 @@ class NativeAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
|
||||
return existing;
|
||||
}
|
||||
|
||||
async setAll(entries: MaybeAsyncIterable<Entry<K, V>>) {
|
||||
async setAll(entries: MaybeAsyncIterable<EqualityMapEntry<K, V>>) {
|
||||
for await (const [key, value] of entries) {
|
||||
await this.set(key, value);
|
||||
}
|
||||
@@ -231,8 +201,8 @@ class NativeAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
class CustomAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
|
||||
readonly #list: Entry<K, V>[] = [];
|
||||
export class CustomAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
|
||||
readonly #list: EqualityMapEntry<K, V>[] = [];
|
||||
readonly #keyComparer: MaybeAsyncEqualityComparison<K>;
|
||||
|
||||
constructor(keyComparer: MaybeAsyncEqualityComparison<K>) {
|
||||
@@ -267,7 +237,7 @@ class CustomAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async setAll(entries: MaybeAsyncIterable<Entry<K, V>>) {
|
||||
async setAll(entries: MaybeAsyncIterable<EqualityMapEntry<K, V>>) {
|
||||
for await (const [key, value] of entries) {
|
||||
await this.set(key, value);
|
||||
}
|
||||
@@ -316,11 +286,7 @@ class CustomAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
|
||||
|
||||
*[Symbol.iterator]() {
|
||||
for (const entry of this.#list) {
|
||||
yield entry.slice() as Entry<K, V>; // no entry mutation allowed!
|
||||
yield entry.slice() as EqualityMapEntry<K, V>; // no entry mutation allowed!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createAsyncEqualityMap<K, V>(keyComparer?: MaybeAsyncEqualityComparison<K>): AsyncEqualityMap<K, V> {
|
||||
return keyComparer ? new CustomAsyncEqualityMap<K, V>(keyComparer) : new NativeAsyncEqualityMap<K, V>();
|
||||
}
|
||||
11
src/equality-map/index.ts
Normal file
11
src/equality-map/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { EqualityComparisonOrComparer, MaybeAsyncEqualityComparison } from "../equality-comparer/types.js";
|
||||
import { CustomAsyncEqualityMap, CustomEqualityMap, NativeAsyncEqualityMap, NativeEqualityMap } from "./impl.js";
|
||||
import { AsyncEqualityMap, EqualityMap } from "./types.js";
|
||||
|
||||
export function createEqualityMap<K, V>(keyComparer?: EqualityComparisonOrComparer<K>): EqualityMap<K, V> {
|
||||
return keyComparer ? new CustomEqualityMap<K, V>(keyComparer) : new NativeEqualityMap<K, V>();
|
||||
}
|
||||
|
||||
export function createAsyncEqualityMap<K, V>(keyComparer?: MaybeAsyncEqualityComparison<K>): AsyncEqualityMap<K, V> {
|
||||
return keyComparer ? new CustomAsyncEqualityMap<K, V>(keyComparer) : new NativeAsyncEqualityMap<K, V>();
|
||||
}
|
||||
29
src/equality-map/types.ts
Normal file
29
src/equality-map/types.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { MaybeAsyncIterable } from "../types.js";
|
||||
|
||||
export type EqualityMapEntry<K, V> = [key: K, value: V];
|
||||
|
||||
export interface EqualityMap<K, V> extends Iterable<EqualityMapEntry<K, V>> {
|
||||
readonly size: number;
|
||||
get(key: K): V | undefined;
|
||||
set(key: K, value: V): V | undefined;
|
||||
setAll(entries: Iterable<EqualityMapEntry<K, V>>): void;
|
||||
contains(key: K): boolean;
|
||||
remove(key: K): V | undefined;
|
||||
clear(): void;
|
||||
keys(): IterableIterator<K>;
|
||||
values(): IterableIterator<V>;
|
||||
entries(): IterableIterator<EqualityMapEntry<K, V>>;
|
||||
}
|
||||
|
||||
export interface AsyncEqualityMap<K, V> extends Iterable<EqualityMapEntry<K, V>> {
|
||||
readonly size: number;
|
||||
get(key: K): Promise<V | undefined>;
|
||||
set(key: K, value: V): Promise<V | undefined>;
|
||||
setAll(entries: MaybeAsyncIterable<EqualityMapEntry<K, V>>): Promise<void>;
|
||||
contains(key: K): Promise<boolean>;
|
||||
remove(key: K): Promise<V | undefined>;
|
||||
clear(): void;
|
||||
keys(): IterableIterator<K>;
|
||||
values(): IterableIterator<V>;
|
||||
entries(): IterableIterator<EqualityMapEntry<K, V>>;
|
||||
}
|
||||
@@ -1,17 +1,9 @@
|
||||
import { EqualityComparison, MaybeAsyncEqualityComparison } from "./equality-comparer/types.js";
|
||||
import { MaybeAsyncIterable } from "./types.js";
|
||||
import { asEqualityComparer } from "../equality-comparer/sync.js";
|
||||
import { EqualityComparer, EqualityComparisonOrComparer, MaybeAsyncEqualityComparison } from "../equality-comparer/types.js";
|
||||
import { MaybeAsyncIterable } from "../types.js";
|
||||
import { AsyncEqualitySet, EqualitySet } from "./types.js";
|
||||
|
||||
export interface EqualitySet<T> extends Iterable<T> {
|
||||
readonly size: number;
|
||||
add(value: T): boolean;
|
||||
addAll(values: Iterable<T>): number;
|
||||
contains(value: T): boolean;
|
||||
remove(value: T): boolean;
|
||||
clear(): void;
|
||||
values(): IterableIterator<T>;
|
||||
}
|
||||
|
||||
class NativeEqualitySet<T> implements EqualitySet<T> {
|
||||
export class NativeEqualitySet<T> implements EqualitySet<T> {
|
||||
readonly #set = new Set<T>();
|
||||
|
||||
get size() {
|
||||
@@ -57,12 +49,12 @@ class NativeEqualitySet<T> implements EqualitySet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
class CustomEqualitySet<T> implements EqualitySet<T> {
|
||||
export class CustomEqualitySet<T> implements EqualitySet<T> {
|
||||
readonly #list: T[] = [];
|
||||
readonly #equater: EqualityComparison<T>;
|
||||
readonly #equater: EqualityComparer<T>;
|
||||
|
||||
constructor(equater: EqualityComparison<T>) {
|
||||
this.#equater = equater;
|
||||
constructor(equater: EqualityComparisonOrComparer<T>) {
|
||||
this.#equater = asEqualityComparer(equater);
|
||||
}
|
||||
|
||||
get size() {
|
||||
@@ -93,7 +85,7 @@ class CustomEqualitySet<T> implements EqualitySet<T> {
|
||||
|
||||
contains(value: T) {
|
||||
for (const val of this.#list) {
|
||||
if (this.#equater(value, val)) {
|
||||
if (this.#equater.equals(value, val)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -105,7 +97,7 @@ class CustomEqualitySet<T> implements EqualitySet<T> {
|
||||
const length = this.#list.length;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (this.#equater(value, this.#list[i])) {
|
||||
if (this.#equater.equals(value, this.#list[i])) {
|
||||
this.#list.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
@@ -127,21 +119,7 @@ class CustomEqualitySet<T> implements EqualitySet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
export function createEqualitySet<T>(equater?: EqualityComparison<T>): EqualitySet<T> {
|
||||
return equater ? new CustomEqualitySet(equater) : new NativeEqualitySet<T>();
|
||||
}
|
||||
|
||||
export interface AsyncEqualitySet<T> extends Iterable<T> {
|
||||
readonly size: number;
|
||||
add(value: T): Promise<boolean>;
|
||||
addAll(values: MaybeAsyncIterable<T>): Promise<number>;
|
||||
contains(value: T): Promise<boolean>;
|
||||
remove(value: T): Promise<boolean>;
|
||||
clear(): void;
|
||||
values(): IterableIterator<T>;
|
||||
}
|
||||
|
||||
class NativeAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
|
||||
export class NativeAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
|
||||
readonly #set = new Set<T>();
|
||||
|
||||
get size() {
|
||||
@@ -187,7 +165,7 @@ class NativeAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
class CustomAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
|
||||
export class CustomAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
|
||||
readonly #list: T[] = [];
|
||||
readonly #equater: MaybeAsyncEqualityComparison<T>;
|
||||
|
||||
@@ -256,7 +234,3 @@ class CustomAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
|
||||
return this.#list[Symbol.iterator]();
|
||||
}
|
||||
}
|
||||
|
||||
export function createAsyncEqualitySet<T>(equater?: MaybeAsyncEqualityComparison<T>): AsyncEqualitySet<T> {
|
||||
return equater ? new CustomAsyncEqualitySet(equater) : new NativeAsyncEqualitySet<T>();
|
||||
}
|
||||
11
src/equality-set/index.ts
Normal file
11
src/equality-set/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { EqualityComparisonOrComparer, MaybeAsyncEqualityComparison } from "../equality-comparer/types.js";
|
||||
import { CustomAsyncEqualitySet, CustomEqualitySet, NativeAsyncEqualitySet, NativeEqualitySet } from "./impl.js";
|
||||
import { AsyncEqualitySet, EqualitySet } from "./types.js";
|
||||
|
||||
export function createEqualitySet<T>(equater?: EqualityComparisonOrComparer<T>): EqualitySet<T> {
|
||||
return equater ? new CustomEqualitySet(equater) : new NativeEqualitySet<T>();
|
||||
}
|
||||
|
||||
export function createAsyncEqualitySet<T>(equater?: MaybeAsyncEqualityComparison<T>): AsyncEqualitySet<T> {
|
||||
return equater ? new CustomAsyncEqualitySet(equater) : new NativeAsyncEqualitySet<T>();
|
||||
}
|
||||
21
src/equality-set/types.ts
Normal file
21
src/equality-set/types.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { MaybeAsyncIterable } from "../types.js";
|
||||
|
||||
export interface EqualitySet<T> extends Iterable<T> {
|
||||
readonly size: number;
|
||||
add(value: T): boolean;
|
||||
addAll(values: Iterable<T>): number;
|
||||
contains(value: T): boolean;
|
||||
remove(value: T): boolean;
|
||||
clear(): void;
|
||||
values(): IterableIterator<T>;
|
||||
}
|
||||
|
||||
export interface AsyncEqualitySet<T> extends Iterable<T> {
|
||||
readonly size: number;
|
||||
add(value: T): Promise<boolean>;
|
||||
addAll(values: MaybeAsyncIterable<T>): Promise<number>;
|
||||
contains(value: T): Promise<boolean>;
|
||||
remove(value: T): Promise<boolean>;
|
||||
clear(): void;
|
||||
values(): IterableIterator<T>;
|
||||
}
|
||||
@@ -15,5 +15,9 @@ export * as Comparers from "./comparer/sync.js";
|
||||
export { BaseAsyncComparer } from "./comparer/async.js";
|
||||
export * as AsyncComparers from "./comparer/async.js";
|
||||
export * from "./comparer/types.js";
|
||||
export * as EqualityComparers from "./equality-comparer/index.js";
|
||||
export * as EqualityComparers from "./equality-comparer/sync.js";
|
||||
export * from "./equality-comparer/types.js";
|
||||
export * as EqualityMaps from "./equality-map/index.js";
|
||||
export * from "./equality-map/types.js";
|
||||
export * as EqualitySets from "./equality-set/index.js";
|
||||
export * from "./equality-set/types.js";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BitArray } from "../bitarray/index.js";
|
||||
import { asArray } from "../utils.js";
|
||||
import { AsyncRandomOptions, ElementPredicate, ElementWeight, RandomGenerator, RandomOptions } from "./types.js";
|
||||
import { AsyncRandomOptions, ElementPredicate, ElementWeight, RandomElement, RandomGenerator, RandomOptions } from "./types.js";
|
||||
|
||||
export const alwaysTrue: ElementPredicate = () => true;
|
||||
export const weightOfOne: ElementWeight = () => 1.0;
|
||||
@@ -45,9 +45,10 @@ function withDefaultOptions<T>(options: RandomOptions<T> | AsyncRandomOptions<T>
|
||||
};
|
||||
}
|
||||
|
||||
function _getRandomElement<T>(sequence: Iterable<T>, options: Required<RandomOptions<T>>) {
|
||||
function _getRandomElement<T>(sequence: Iterable<T>, options: Required<RandomOptions<T>>): RandomElement<T> {
|
||||
const { predicate, weight, random } = options;
|
||||
|
||||
let found = false;
|
||||
let result: T | undefined = undefined;
|
||||
let resultIndex = -1;
|
||||
let index = 0;
|
||||
@@ -66,22 +67,24 @@ function _getRandomElement<T>(sequence: Iterable<T>, options: Required<RandomOpt
|
||||
weightAcc += w;
|
||||
|
||||
if (random() * weightAcc < w) {
|
||||
found = true;
|
||||
result = element;
|
||||
resultIndex = currentIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { element: result, index: resultIndex };
|
||||
return { found, element: result, index: resultIndex } as RandomElement<T>;
|
||||
}
|
||||
|
||||
export function getRandomElement<T>(sequence: Iterable<T>, options?: RandomOptions<T>) {
|
||||
return _getRandomElement(sequence, withDefaultOptions(options));
|
||||
}
|
||||
|
||||
async function _getRandomElementAsync<T>(sequence: AsyncIterable<T>, options: Required<AsyncRandomOptions<T>>) {
|
||||
async function _getRandomElementAsync<T>(sequence: AsyncIterable<T>, options: Required<AsyncRandomOptions<T>>): Promise<RandomElement<T>> {
|
||||
const { predicate, weight, random } = options;
|
||||
|
||||
let found = false;
|
||||
let result: T | undefined = undefined;
|
||||
let resultIndex = -1;
|
||||
let index = 0;
|
||||
@@ -100,13 +103,14 @@ async function _getRandomElementAsync<T>(sequence: AsyncIterable<T>, options: Re
|
||||
weightAcc += w;
|
||||
|
||||
if (random() * weightAcc < w) {
|
||||
found = true;
|
||||
result = element;
|
||||
resultIndex = currentIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { element: result, index: resultIndex };
|
||||
return { found, element: result, index: resultIndex } as RandomElement<T>;
|
||||
}
|
||||
|
||||
export async function getRandomElementAsync<T>(sequence: AsyncIterable<T>, options?: AsyncRandomOptions<T>) {
|
||||
|
||||
@@ -4,7 +4,7 @@ export type ElementPredicate<T = any> = (index: number, obj: T) => boolean;
|
||||
export type ElementWeight<T = any> = (index: number, obj: T) => number;
|
||||
export type RandomGenerator = () => number;
|
||||
|
||||
export interface RandomOptions<T = any> {
|
||||
export type RandomOptions<T = any> = {
|
||||
predicate?: ElementPredicate<T>;
|
||||
weight?: ElementWeight<T>;
|
||||
random?: RandomGenerator;
|
||||
@@ -13,8 +13,20 @@ export interface RandomOptions<T = any> {
|
||||
export type MaybeAsyncElementPredicate<T = any> = MaybeAsyncFunction<ElementPredicate<T>>;
|
||||
export type MaybeAsyncElementWeight<T = any> = MaybeAsyncFunction<ElementWeight<T>>;
|
||||
|
||||
export interface AsyncRandomOptions<T = any> {
|
||||
export type AsyncRandomOptions<T = any> = {
|
||||
predicate?: MaybeAsyncElementPredicate<T>;
|
||||
weight?: MaybeAsyncElementWeight<T>;
|
||||
random?: RandomGenerator;
|
||||
};
|
||||
|
||||
type RandomElementFound<T> = {
|
||||
found: true;
|
||||
element: T;
|
||||
index: number;
|
||||
};
|
||||
type RandomElementNotFound = {
|
||||
found: false;
|
||||
element: undefined;
|
||||
index: -1;
|
||||
};
|
||||
export type RandomElement<T> = RandomElementFound<T> | RandomElementNotFound;
|
||||
|
||||
@@ -3,10 +3,10 @@ import { AsyncSequence } from "../async/types.js";
|
||||
import { Collector } from "../collector/types.js";
|
||||
import { asComparer, combineNullableComparers, createComparerUsing, defaultComparer } from "../comparer/sync.js";
|
||||
import { ComparisonOrComparer, Comparer } from "../comparer/types.js";
|
||||
import { strictEquals } from "../equality-comparer/index.js";
|
||||
import { strictEquals } from "../equality-comparer/sync.js";
|
||||
import { EqualityComparison } from "../equality-comparer/types.js";
|
||||
import { createEqualityMap } from "../equality-map.js";
|
||||
import { createEqualitySet } from "../equality-set.js";
|
||||
import { createEqualityMap } from "../equality-map/index.js";
|
||||
import { createEqualitySet } from "../equality-set/index.js";
|
||||
import { createQueue } from "../queue.js";
|
||||
import { getRandomElement } from "../random/index.js";
|
||||
import { RandomOptions } from "../random/types.js";
|
||||
|
||||
@@ -9,7 +9,7 @@ export function wrap<T = any>(iterable: Iterable<T>): Sequence<T> {
|
||||
}
|
||||
|
||||
if (Array.isArray(iterable)) {
|
||||
return array(iterable);
|
||||
return array<T>(iterable);
|
||||
}
|
||||
|
||||
if (iterable instanceof Set) {
|
||||
@@ -20,7 +20,7 @@ export function wrap<T = any>(iterable: Iterable<T>): Sequence<T> {
|
||||
return map(iterable) as unknown as Sequence<T>;
|
||||
}
|
||||
|
||||
return sequence(iterable);
|
||||
return sequence<T>(iterable);
|
||||
}
|
||||
|
||||
export function sequence<T = any>(iterable: Iterable<T>): Sequence<T> {
|
||||
@@ -86,9 +86,9 @@ export function generator<T>(generator: () => Iterable<T>): Sequence<T> {
|
||||
return new GeneratorSequence(generator);
|
||||
}
|
||||
|
||||
export function range(max: number): Sequence<number>
|
||||
export function range(min: number, max: number): Sequence<number>
|
||||
export function range(min: number, max: number, step: number): Sequence<number>
|
||||
export function range(max: number): Sequence<number>;
|
||||
export function range(min: number, max: number): Sequence<number>;
|
||||
export function range(min: number, max: number, step: number): Sequence<number>;
|
||||
export function range(a: number, b?: number, c?: number): Sequence<number> {
|
||||
if (b === undefined) {
|
||||
b = a;
|
||||
@@ -102,9 +102,9 @@ export function range(a: number, b?: number, c?: number): Sequence<number> {
|
||||
return new RangeSequence(a, b, c);
|
||||
}
|
||||
|
||||
export function bigintRange(max: bigint): Sequence<bigint>
|
||||
export function bigintRange(min: bigint, max: bigint): Sequence<bigint>
|
||||
export function bigintRange(min: bigint, max: bigint, step: bigint): Sequence<bigint>
|
||||
export function bigintRange(max: bigint): Sequence<bigint>;
|
||||
export function bigintRange(min: bigint, max: bigint): Sequence<bigint>;
|
||||
export function bigintRange(min: bigint, max: bigint, step: bigint): Sequence<bigint>;
|
||||
export function bigintRange(a: bigint, b?: bigint, c?: bigint): Sequence<bigint> {
|
||||
if (b === undefined) {
|
||||
b = a;
|
||||
|
||||
Reference in New Issue
Block a user