-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
/
multi-map.ts
108 lines (80 loc) · 2.26 KB
/
multi-map.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import uniq from 'lodash/uniq.js';
import { EMPTY_ARRAY } from '../consts.js';
import type { Entry, MapLike } from '../types.js';
export class MultiMap<K, V> implements MapLike<K, readonly V[]> {
readonly #internalMap = new Map<K, readonly V[]>();
constructor(entries?: Iterable<readonly [K, readonly V[]]>) {
if (entries) {
for (const [key, values] of entries) {
this.set(key, values);
}
}
}
get size() {
return this.#internalMap.size;
}
clear() {
this.#internalMap.clear();
}
append(key: K, value: V): this {
const valueSet = this.#internalMap.get(key);
if (valueSet?.includes(value)) {
return this;
}
const newValue = valueSet ? [...valueSet, value] : [value];
Object.freeze(newValue);
this.#internalMap.set(key, newValue);
return this;
}
deleteValue(key: K, value: V): boolean {
const valueSet = this.#internalMap.get(key);
if (valueSet == null) {
return false;
}
const newValueSet = valueSet.filter(val => val !== value);
if (newValueSet.length === valueSet.length) {
return false;
}
if (newValueSet.length === 0) {
this.#internalMap.delete(key);
return true;
}
Object.freeze(newValueSet);
this.#internalMap.set(key, newValueSet);
return true;
}
delete(key: K): boolean {
return this.#internalMap.delete(key);
}
keys(): IterableIterator<K> {
return this.#internalMap.keys();
}
count(key: K): number {
const values = this.#internalMap.get(key);
return values?.length ?? 0;
}
[Symbol.iterator](): IterableIterator<Entry<K, readonly V[]>> {
return this.#internalMap[Symbol.iterator]();
}
entries(): IterableIterator<Entry<K, readonly V[]>> {
return this.#internalMap.entries();
}
get(key: K): readonly V[] {
return this.#internalMap.get(key) ?? EMPTY_ARRAY;
}
has(key: K): boolean {
return this.#internalMap.has(key);
}
set(key: K, values: readonly V[]): this {
if (values.length === 0) {
this.#internalMap.delete(key);
return this;
}
const uniqueValues = Object.freeze(uniq(values));
this.#internalMap.set(key, uniqueValues);
return this;
}
values(): IterableIterator<readonly V[]> {
return this.#internalMap.values();
}
}