1
0
Files
sequence-js/src/equality-set.ts

212 lines
3.7 KiB
TypeScript

import { Equater, MaybeAsyncEquater } from "./types.js";
export interface EqualitySet<T> extends Iterable<T> {
readonly size: number;
add(obj: T): boolean;
contains(obj: T): boolean;
remove(obj: T): boolean;
clear(): void;
values(): IterableIterator<T>;
}
class NativeEqualitySet<T> implements EqualitySet<T> {
readonly #set = new Set<T>();
get size() {
return this.#set.size;
}
add(obj: T) {
const exists = this.contains(obj);
this.#set.add(obj);
return !exists;
}
contains(obj: T) {
return this.#set.has(obj);
}
remove(obj: T) {
return this.#set.delete(obj);
}
clear() {
this.#set.clear();
}
values() {
return this.#set.values();
}
[Symbol.iterator]() {
return this.#set[Symbol.iterator]();
}
}
class CustomEqualitySet<T> implements EqualitySet<T> {
readonly #list: T[] = [];
readonly #equater: Equater<T>;
constructor(equater: Equater<T>) {
this.#equater = equater;
}
get size() {
return this.#list.length;
}
add(obj: T) {
if (this.contains(obj)) {
return false;
}
this.#list.push(obj);
return true;
}
contains(obj: T) {
for (const val of this.#list) {
if (this.#equater(obj, val)) {
return true;
}
}
return false;
}
remove(obj: T) {
const length = this.#list.length;
for (let i = 0; i < length; i++) {
if (this.#equater(obj, this.#list[i])) {
this.#list.splice(i, 1);
return true;
}
}
return false;
}
clear() {
this.#list.length = 0;
}
values() {
return this[Symbol.iterator]();
}
[Symbol.iterator]() {
return this.#list[Symbol.iterator]();
}
}
export function createEqualitySet<T>(equater?: Equater<T>): EqualitySet<T> {
return equater ? new CustomEqualitySet(equater) : new NativeEqualitySet<T>();
}
export interface AsyncEqualitySet<T> extends Iterable<T> {
readonly size: number;
add(obj: T): Promise<boolean>;
contains(obj: T): Promise<boolean>;
remove(obj: T): Promise<boolean>;
clear(): void;
values(): IterableIterator<T>;
}
class NativeAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
readonly #set = new Set<T>();
get size() {
return this.#set.size;
}
async add(obj: T) {
const exists = await this.contains(obj);
this.#set.add(obj);
return !exists;
}
async contains(obj: T) {
return this.#set.has(obj);
}
async remove(obj: T) {
return this.#set.delete(obj);
}
clear() {
this.#set.clear();
}
values() {
return this.#set.values();
}
[Symbol.iterator]() {
return this.#set[Symbol.iterator]();
}
}
class CustomAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
readonly #list: T[] = [];
readonly #equater: MaybeAsyncEquater<T>;
constructor(equater: MaybeAsyncEquater<T>) {
this.#equater = equater;
}
get size() {
return this.#list.length;
}
async add(obj: T) {
if (await this.contains(obj)) {
return false;
}
this.#list.push(obj);
return true;
}
async contains(obj: T) {
for (const val of this.#list) {
if (await this.#equater(obj, val)) {
return true;
}
}
return false;
}
async remove(obj: T) {
const length = this.#list.length;
for (let i = 0; i < length; i++) {
if (await this.#equater(obj, this.#list[i])) {
this.#list.splice(i, 1);
return true;
}
}
return false;
}
clear() {
this.#list.length = 0;
}
values() {
return this[Symbol.iterator]();
}
[Symbol.iterator]() {
return this.#list[Symbol.iterator]();
}
}
export function createAsyncEqualitySet<T>(equater?: MaybeAsyncEquater<T>): AsyncEqualitySet<T> {
return equater ? new CustomAsyncEqualitySet(equater) : new NativeAsyncEqualitySet<T>();
}