212 lines
3.7 KiB
TypeScript
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>();
|
|
}
|