name:
src/main/js/common/standard/HashSet.ts
-rw-r--r--
1665
1import { Hashable } from "./Hashable";
2
3export class HashableSet<T extends Hashable> extends Set<T> implements Hashable {
4 get hashKey() {
5 return JSON.stringify([...this.values()].map((value) => value.hashKey).sort());
6 }
7
8 equals(other: unknown): boolean {
9 return other instanceof HashableSet && this.hashKey === (other as HashableSet<T>).hashKey;
10 }
11}
12
13export class HashSet<T extends Hashable> extends HashableSet<T> {
14 static readonly EMPTY = Object.freeze(new HashSet());
15 [Symbol.toStringTag]: "Set";
16 private readonly elementMap = new Map<string, T>();
17
18 constructor(iterable?: Iterable<T>) {
19 super();
20 if (iterable) {
21 for (const value of iterable) {
22 this.add(value);
23 }
24 }
25 }
26
27 get size() {
28 return this.elementMap.size;
29 }
30
31 add(value: T): this {
32 this.elementMap.set(value.hashKey, value);
33 return this;
34 }
35
36 clear(): void {
37 this.elementMap.clear();
38 }
39
40 delete(value: T): boolean {
41 return this.elementMap.delete(value.hashKey);
42 }
43
44 forEach(callback: (value: T, value2: T, set: Set<T>) => void, thisArg?: any): void {
45 const self = this;
46 this.elementMap.forEach((value) => {
47 callback.bind(thisArg)(value, value, self);
48 });
49 }
50
51 has(value: T): boolean {
52 return this.elementMap.has(value.hashKey);
53 }
54
55 [Symbol.iterator](): IterableIterator<T> {
56 return this.values();
57 }
58
59 *entries(): IterableIterator<[T, T]> {
60 for (const value of this.elementMap.values()) {
61 yield [value, value];
62 }
63 }
64
65 keys(): IterableIterator<T> {
66 return this.elementMap.values();
67 }
68
69 values(): IterableIterator<T> {
70 return this.elementMap.values();
71 }
72}