priority-queue-typed 2.0.4 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data-structures/base/iterable-element-base.d.ts +186 -83
- package/dist/data-structures/base/iterable-element-base.js +149 -107
- package/dist/data-structures/base/iterable-entry-base.d.ts +95 -119
- package/dist/data-structures/base/iterable-entry-base.js +59 -116
- package/dist/data-structures/base/linear-base.d.ts +250 -192
- package/dist/data-structures/base/linear-base.js +137 -274
- package/dist/data-structures/binary-tree/avl-tree-counter.d.ts +126 -158
- package/dist/data-structures/binary-tree/avl-tree-counter.js +171 -205
- package/dist/data-structures/binary-tree/avl-tree-multi-map.d.ts +100 -69
- package/dist/data-structures/binary-tree/avl-tree-multi-map.js +135 -87
- package/dist/data-structures/binary-tree/avl-tree.d.ts +138 -149
- package/dist/data-structures/binary-tree/avl-tree.js +208 -195
- package/dist/data-structures/binary-tree/binary-tree.d.ts +476 -632
- package/dist/data-structures/binary-tree/binary-tree.js +612 -879
- package/dist/data-structures/binary-tree/bst.d.ts +258 -306
- package/dist/data-structures/binary-tree/bst.js +505 -481
- package/dist/data-structures/binary-tree/red-black-tree.d.ts +107 -179
- package/dist/data-structures/binary-tree/red-black-tree.js +114 -209
- package/dist/data-structures/binary-tree/tree-counter.d.ts +132 -154
- package/dist/data-structures/binary-tree/tree-counter.js +172 -203
- package/dist/data-structures/binary-tree/tree-multi-map.d.ts +72 -69
- package/dist/data-structures/binary-tree/tree-multi-map.js +105 -85
- package/dist/data-structures/graph/abstract-graph.d.ts +238 -233
- package/dist/data-structures/graph/abstract-graph.js +267 -237
- package/dist/data-structures/graph/directed-graph.d.ts +108 -224
- package/dist/data-structures/graph/directed-graph.js +146 -233
- package/dist/data-structures/graph/map-graph.d.ts +49 -55
- package/dist/data-structures/graph/map-graph.js +56 -59
- package/dist/data-structures/graph/undirected-graph.d.ts +103 -146
- package/dist/data-structures/graph/undirected-graph.js +129 -149
- package/dist/data-structures/hash/hash-map.d.ts +164 -338
- package/dist/data-structures/hash/hash-map.js +270 -457
- package/dist/data-structures/heap/heap.d.ts +214 -289
- package/dist/data-structures/heap/heap.js +340 -349
- package/dist/data-structures/heap/max-heap.d.ts +11 -47
- package/dist/data-structures/heap/max-heap.js +11 -66
- package/dist/data-structures/heap/min-heap.d.ts +12 -47
- package/dist/data-structures/heap/min-heap.js +11 -66
- package/dist/data-structures/linked-list/doubly-linked-list.d.ts +231 -347
- package/dist/data-structures/linked-list/doubly-linked-list.js +368 -494
- package/dist/data-structures/linked-list/singly-linked-list.d.ts +261 -310
- package/dist/data-structures/linked-list/singly-linked-list.js +447 -466
- package/dist/data-structures/linked-list/skip-linked-list.d.ts +0 -107
- package/dist/data-structures/linked-list/skip-linked-list.js +0 -100
- package/dist/data-structures/priority-queue/max-priority-queue.d.ts +12 -56
- package/dist/data-structures/priority-queue/max-priority-queue.js +11 -78
- package/dist/data-structures/priority-queue/min-priority-queue.d.ts +11 -57
- package/dist/data-structures/priority-queue/min-priority-queue.js +10 -79
- package/dist/data-structures/priority-queue/priority-queue.d.ts +2 -61
- package/dist/data-structures/priority-queue/priority-queue.js +8 -83
- package/dist/data-structures/queue/deque.d.ts +227 -254
- package/dist/data-structures/queue/deque.js +309 -348
- package/dist/data-structures/queue/queue.d.ts +180 -201
- package/dist/data-structures/queue/queue.js +265 -248
- package/dist/data-structures/stack/stack.d.ts +124 -102
- package/dist/data-structures/stack/stack.js +181 -125
- package/dist/data-structures/trie/trie.d.ts +164 -165
- package/dist/data-structures/trie/trie.js +189 -172
- package/dist/interfaces/binary-tree.d.ts +56 -6
- package/dist/interfaces/graph.d.ts +16 -0
- package/dist/types/data-structures/base/base.d.ts +1 -1
- package/dist/types/data-structures/graph/abstract-graph.d.ts +4 -0
- package/dist/types/utils/utils.d.ts +6 -6
- package/dist/utils/utils.d.ts +110 -49
- package/dist/utils/utils.js +148 -73
- package/package.json +2 -2
- package/src/data-structures/base/iterable-element-base.ts +238 -115
- package/src/data-structures/base/iterable-entry-base.ts +96 -120
- package/src/data-structures/base/linear-base.ts +271 -277
- package/src/data-structures/binary-tree/avl-tree-counter.ts +198 -216
- package/src/data-structures/binary-tree/avl-tree-multi-map.ts +192 -101
- package/src/data-structures/binary-tree/avl-tree.ts +239 -206
- package/src/data-structures/binary-tree/binary-tree.ts +681 -905
- package/src/data-structures/binary-tree/bst.ts +568 -570
- package/src/data-structures/binary-tree/red-black-tree.ts +161 -222
- package/src/data-structures/binary-tree/tree-counter.ts +199 -218
- package/src/data-structures/binary-tree/tree-multi-map.ts +131 -97
- package/src/data-structures/graph/abstract-graph.ts +339 -264
- package/src/data-structures/graph/directed-graph.ts +146 -236
- package/src/data-structures/graph/map-graph.ts +63 -60
- package/src/data-structures/graph/undirected-graph.ts +129 -152
- package/src/data-structures/hash/hash-map.ts +274 -496
- package/src/data-structures/heap/heap.ts +389 -402
- package/src/data-structures/heap/max-heap.ts +12 -76
- package/src/data-structures/heap/min-heap.ts +13 -76
- package/src/data-structures/linked-list/doubly-linked-list.ts +426 -530
- package/src/data-structures/linked-list/singly-linked-list.ts +495 -517
- package/src/data-structures/linked-list/skip-linked-list.ts +1 -108
- package/src/data-structures/priority-queue/max-priority-queue.ts +12 -87
- package/src/data-structures/priority-queue/min-priority-queue.ts +11 -88
- package/src/data-structures/priority-queue/priority-queue.ts +3 -92
- package/src/data-structures/queue/deque.ts +381 -357
- package/src/data-structures/queue/queue.ts +310 -264
- package/src/data-structures/stack/stack.ts +217 -131
- package/src/data-structures/trie/trie.ts +240 -175
- package/src/interfaces/binary-tree.ts +240 -6
- package/src/interfaces/graph.ts +37 -0
- package/src/types/data-structures/base/base.ts +5 -5
- package/src/types/data-structures/graph/abstract-graph.ts +5 -0
- package/src/types/utils/utils.ts +9 -5
- package/src/utils/utils.ts +152 -86
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
|
|
6
6
|
* @license MIT License
|
|
7
7
|
*/
|
|
8
|
+
|
|
8
9
|
import type {
|
|
9
10
|
EntryCallback,
|
|
10
11
|
HashMapLinkedNode,
|
|
@@ -16,6 +17,11 @@ import { IterableEntryBase } from '../base';
|
|
|
16
17
|
import { isWeakKey, rangeCheck } from '../../utils';
|
|
17
18
|
|
|
18
19
|
/**
|
|
20
|
+
* Hash-based map. Supports object keys and custom hashing; offers O(1) average set/get/has.
|
|
21
|
+
* @remarks Time O(1), Space O(1)
|
|
22
|
+
* @template K
|
|
23
|
+
* @template V
|
|
24
|
+
* @template R
|
|
19
25
|
* 1. Key-Value Pair Storage: HashMap stores key-value pairs. Each key map to a value.
|
|
20
26
|
* 2. Fast Lookup: It's used when you need to quickly find, insert, or delete entries based on a key.
|
|
21
27
|
* 3. Unique Keys: Keys are unique.
|
|
@@ -70,11 +76,11 @@ import { isWeakKey, rangeCheck } from '../../utils';
|
|
|
70
76
|
*/
|
|
71
77
|
export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K, V> {
|
|
72
78
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* @param entryOrRawElements -
|
|
76
|
-
*
|
|
77
|
-
* @
|
|
79
|
+
* Create a HashMap and optionally bulk-insert entries.
|
|
80
|
+
* @remarks Time O(N), Space O(N)
|
|
81
|
+
* @param [entryOrRawElements] - Iterable of entries or raw elements to insert.
|
|
82
|
+
* @param [options] - Options: hash function and optional record-to-entry converter.
|
|
83
|
+
* @returns New HashMap instance.
|
|
78
84
|
*/
|
|
79
85
|
constructor(entryOrRawElements: Iterable<R | [K, V]> = [], options?: HashMapOptions<K, V, R>) {
|
|
80
86
|
super();
|
|
@@ -83,17 +89,15 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
83
89
|
if (hashFn) this._hashFn = hashFn;
|
|
84
90
|
if (toEntryFn) this._toEntryFn = toEntryFn;
|
|
85
91
|
}
|
|
86
|
-
if (entryOrRawElements)
|
|
87
|
-
this.setMany(entryOrRawElements);
|
|
88
|
-
}
|
|
92
|
+
if (entryOrRawElements) this.setMany(entryOrRawElements);
|
|
89
93
|
}
|
|
90
94
|
|
|
91
95
|
protected _store: { [key: string]: HashMapStoreItem<K, V> } = {};
|
|
92
96
|
|
|
93
97
|
/**
|
|
94
|
-
*
|
|
95
|
-
* @
|
|
96
|
-
*
|
|
98
|
+
* Get the internal store for non-object keys.
|
|
99
|
+
* @remarks Time O(1), Space O(1)
|
|
100
|
+
* @returns Internal record of string→{key,value}.
|
|
97
101
|
*/
|
|
98
102
|
get store(): { [p: string]: HashMapStoreItem<K, V> } {
|
|
99
103
|
return this._store;
|
|
@@ -102,9 +106,9 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
102
106
|
protected _objMap: Map<object, V> = new Map();
|
|
103
107
|
|
|
104
108
|
/**
|
|
105
|
-
*
|
|
106
|
-
* @
|
|
107
|
-
*
|
|
109
|
+
* Get the internal Map used for object/function keys.
|
|
110
|
+
* @remarks Time O(1), Space O(1)
|
|
111
|
+
* @returns Map of object→value.
|
|
108
112
|
*/
|
|
109
113
|
get objMap(): Map<object, V> {
|
|
110
114
|
return this._objMap;
|
|
@@ -113,8 +117,9 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
113
117
|
protected _toEntryFn?: (rawElement: R) => [K, V];
|
|
114
118
|
|
|
115
119
|
/**
|
|
116
|
-
*
|
|
117
|
-
* @
|
|
120
|
+
* Get the raw→entry converter function if present.
|
|
121
|
+
* @remarks Time O(1), Space O(1)
|
|
122
|
+
* @returns Converter function or undefined.
|
|
118
123
|
*/
|
|
119
124
|
get toEntryFn() {
|
|
120
125
|
return this._toEntryFn;
|
|
@@ -123,8 +128,9 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
123
128
|
protected _size = 0;
|
|
124
129
|
|
|
125
130
|
/**
|
|
126
|
-
*
|
|
127
|
-
* @
|
|
131
|
+
* Get the number of distinct keys stored.
|
|
132
|
+
* @remarks Time O(1), Space O(1)
|
|
133
|
+
* @returns Current size.
|
|
128
134
|
*/
|
|
129
135
|
get size(): number {
|
|
130
136
|
return this._size;
|
|
@@ -133,268 +139,210 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
133
139
|
protected _hashFn: (key: K) => string = (key: K) => String(key);
|
|
134
140
|
|
|
135
141
|
/**
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* @return The hash function
|
|
142
|
+
* Get the current hash function for non-object keys.
|
|
143
|
+
* @remarks Time O(1), Space O(1)
|
|
144
|
+
* @returns Hash function.
|
|
140
145
|
*/
|
|
141
146
|
get hashFn() {
|
|
142
147
|
return this._hashFn;
|
|
143
148
|
}
|
|
144
149
|
|
|
145
150
|
/**
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* The function checks if a given element is an array with exactly two elements.
|
|
150
|
-
* @param {any} rawElement - The `rawElement` parameter is of type `any`, which means it can be any
|
|
151
|
-
* data type.
|
|
152
|
-
* @returns a boolean value.
|
|
153
|
-
*/
|
|
154
|
-
isEntry(rawElement: any): rawElement is [K, V] {
|
|
155
|
-
return Array.isArray(rawElement) && rawElement.length === 2;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Time Complexity: O(1)
|
|
160
|
-
* Space Complexity: O(1)
|
|
161
|
-
*
|
|
162
|
-
* The function checks if the size of an object is equal to zero and returns a boolean value.
|
|
163
|
-
* @returns A boolean value indicating whether the size of the object is 0 or not.
|
|
151
|
+
* Check whether the map is empty.
|
|
152
|
+
* @remarks Time O(1), Space O(1)
|
|
153
|
+
* @returns True if size is 0.
|
|
164
154
|
*/
|
|
165
155
|
isEmpty(): boolean {
|
|
166
156
|
return this._size === 0;
|
|
167
157
|
}
|
|
168
158
|
|
|
169
159
|
/**
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
* The clear() function resets the state of an object by clearing its internal store, object map, and
|
|
174
|
-
* size.
|
|
160
|
+
* Remove all entries and reset counters.
|
|
161
|
+
* @remarks Time O(N), Space O(1)
|
|
162
|
+
* @returns void
|
|
175
163
|
*/
|
|
176
|
-
clear() {
|
|
164
|
+
clear(): void {
|
|
177
165
|
this._store = {};
|
|
178
166
|
this._objMap.clear();
|
|
179
167
|
this._size = 0;
|
|
180
168
|
}
|
|
181
169
|
|
|
182
170
|
/**
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
*
|
|
171
|
+
* Type guard: check if a raw value is a [key, value] entry.
|
|
172
|
+
* @remarks Time O(1), Space O(1)
|
|
173
|
+
* @returns True if the value is a 2-tuple.
|
|
174
|
+
*/
|
|
175
|
+
isEntry(rawElement: any): rawElement is [K, V] {
|
|
176
|
+
return Array.isArray(rawElement) && rawElement.length === 2;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Insert or replace a single entry.
|
|
181
|
+
* @remarks Time O(1), Space O(1)
|
|
182
|
+
* @param key - Key.
|
|
183
|
+
* @param value - Value.
|
|
184
|
+
* @returns True when the operation succeeds.
|
|
193
185
|
*/
|
|
194
186
|
set(key: K, value: V): boolean {
|
|
195
187
|
if (this._isObjKey(key)) {
|
|
196
|
-
if (!this.objMap.has(key))
|
|
197
|
-
this._size++;
|
|
198
|
-
}
|
|
188
|
+
if (!this.objMap.has(key)) this._size++;
|
|
199
189
|
this.objMap.set(key, value);
|
|
200
190
|
} else {
|
|
201
191
|
const strKey = this._getNoObjKey(key);
|
|
202
|
-
if (this.store[strKey] === undefined)
|
|
203
|
-
this._size++;
|
|
204
|
-
}
|
|
192
|
+
if (this.store[strKey] === undefined) this._size++;
|
|
205
193
|
this._store[strKey] = { key, value };
|
|
206
194
|
}
|
|
207
195
|
return true;
|
|
208
196
|
}
|
|
209
197
|
|
|
210
198
|
/**
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
* pair using a mapping function, and sets each key-value pair in the current object.
|
|
216
|
-
* @param entryOrRawElements - The `entryOrRawElements` parameter is an iterable collection of elements of a type
|
|
217
|
-
* `T`.
|
|
218
|
-
* @returns The `setMany` function is returning an array of booleans.
|
|
199
|
+
* Insert many entries from an iterable.
|
|
200
|
+
* @remarks Time O(N), Space O(N)
|
|
201
|
+
* @param entryOrRawElements - Iterable of entries or raw elements to insert.
|
|
202
|
+
* @returns Array of per-entry results.
|
|
219
203
|
*/
|
|
220
204
|
setMany(entryOrRawElements: Iterable<R | [K, V]>): boolean[] {
|
|
221
205
|
const results: boolean[] = [];
|
|
222
206
|
for (const rawEle of entryOrRawElements) {
|
|
223
207
|
let key: K | undefined, value: V | undefined;
|
|
224
|
-
if (this.isEntry(rawEle))
|
|
225
|
-
|
|
226
|
-
value = rawEle[1];
|
|
227
|
-
} else if (this._toEntryFn) {
|
|
228
|
-
const item = this._toEntryFn(rawEle);
|
|
229
|
-
key = item[0];
|
|
230
|
-
value = item[1];
|
|
231
|
-
}
|
|
232
|
-
|
|
208
|
+
if (this.isEntry(rawEle)) [key, value] = rawEle;
|
|
209
|
+
else if (this._toEntryFn) [key, value] = this._toEntryFn(rawEle);
|
|
233
210
|
if (key !== undefined && value !== undefined) results.push(this.set(key, value));
|
|
234
211
|
}
|
|
235
212
|
return results;
|
|
236
213
|
}
|
|
237
214
|
|
|
238
215
|
/**
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
* a string map.
|
|
244
|
-
* @param {K} key - The `key` parameter is the key used to retrieve a value from the map. It can be
|
|
245
|
-
* of any type, but it should be compatible with the key type used when the map was created.
|
|
246
|
-
* @returns The method `get(key: K)` returns a value of type `V` if the key exists in the `_objMap`
|
|
247
|
-
* or `_store`, otherwise it returns `undefined`.
|
|
216
|
+
* Get the value for a key.
|
|
217
|
+
* @remarks Time O(1), Space O(1)
|
|
218
|
+
* @param key - Key to look up.
|
|
219
|
+
* @returns Value or undefined.
|
|
248
220
|
*/
|
|
249
221
|
override get(key: K): V | undefined {
|
|
250
|
-
if (this._isObjKey(key))
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const strKey = this._getNoObjKey(key);
|
|
254
|
-
return this._store[strKey]?.value;
|
|
255
|
-
}
|
|
222
|
+
if (this._isObjKey(key)) return this.objMap.get(key);
|
|
223
|
+
const strKey = this._getNoObjKey(key);
|
|
224
|
+
return this._store[strKey]?.value;
|
|
256
225
|
}
|
|
257
226
|
|
|
258
227
|
/**
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
* is an object key or not.
|
|
264
|
-
* @param {K} key - The parameter "key" is of type K, which means it can be any type.
|
|
265
|
-
* @returns The `has` method is returning a boolean value.
|
|
228
|
+
* Check if a key exists.
|
|
229
|
+
* @remarks Time O(1), Space O(1)
|
|
230
|
+
* @param key - Key to test.
|
|
231
|
+
* @returns True if present.
|
|
266
232
|
*/
|
|
267
233
|
override has(key: K): boolean {
|
|
268
|
-
if (this._isObjKey(key))
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const strKey = this._getNoObjKey(key);
|
|
272
|
-
return strKey in this.store;
|
|
273
|
-
}
|
|
234
|
+
if (this._isObjKey(key)) return this.objMap.has(key);
|
|
235
|
+
const strKey = this._getNoObjKey(key);
|
|
236
|
+
return strKey in this.store;
|
|
274
237
|
}
|
|
275
238
|
|
|
276
239
|
/**
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
* @param {K} key - The `key` parameter is the key of the element that you want to delete from the
|
|
282
|
-
* data structure.
|
|
283
|
-
* @returns The `delete` method returns a boolean value. It returns `true` if the key was
|
|
284
|
-
* successfully deleted from the map, and `false` if the key was not found in the map.
|
|
240
|
+
* Delete an entry by key.
|
|
241
|
+
* @remarks Time O(1), Space O(1)
|
|
242
|
+
* @param key - Key to delete.
|
|
243
|
+
* @returns True if the key was found and removed.
|
|
285
244
|
*/
|
|
286
245
|
delete(key: K): boolean {
|
|
287
246
|
if (this._isObjKey(key)) {
|
|
288
|
-
if (this.objMap.has(key))
|
|
289
|
-
this._size--;
|
|
290
|
-
}
|
|
291
|
-
|
|
247
|
+
if (this.objMap.has(key)) this._size--;
|
|
292
248
|
return this.objMap.delete(key);
|
|
293
|
-
} else {
|
|
294
|
-
const strKey = this._getNoObjKey(key);
|
|
295
|
-
if (strKey in this.store) {
|
|
296
|
-
delete this.store[strKey];
|
|
297
|
-
this._size--;
|
|
298
|
-
return true;
|
|
299
|
-
}
|
|
300
|
-
return false;
|
|
301
249
|
}
|
|
250
|
+
const strKey = this._getNoObjKey(key);
|
|
251
|
+
if (strKey in this.store) {
|
|
252
|
+
delete this.store[strKey];
|
|
253
|
+
this._size--;
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
return false;
|
|
302
257
|
}
|
|
303
258
|
|
|
304
259
|
/**
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
* this one. The clone function is useful for creating a copy of an existing
|
|
310
|
-
* HashMap, and then modifying that copy without affecting the original.
|
|
311
|
-
*
|
|
312
|
-
* @return A new hashmap with the same values as this one
|
|
260
|
+
* Replace the hash function and rehash the non-object store.
|
|
261
|
+
* @remarks Time O(N), Space O(N)
|
|
262
|
+
* @param fn - New hash function for non-object keys.
|
|
263
|
+
* @returns This map instance.
|
|
313
264
|
*/
|
|
314
|
-
|
|
315
|
-
|
|
265
|
+
setHashFn(fn: (key: K) => string): this {
|
|
266
|
+
if (this._hashFn === fn) return this;
|
|
267
|
+
this._hashFn = fn;
|
|
268
|
+
this._rehashNoObj();
|
|
269
|
+
return this;
|
|
316
270
|
}
|
|
317
271
|
|
|
318
272
|
/**
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
* The `map` function in TypeScript creates a new HashMap by applying a callback function to each
|
|
323
|
-
* key-value pair in the original HashMap.
|
|
324
|
-
* @param callbackfn - The callback function that will be called for each key-value pair in the
|
|
325
|
-
* HashMap. It takes four parameters:
|
|
326
|
-
* @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
|
|
327
|
-
* to be used as `this` when executing the `callbackfn` function. If `thisArg` is provided, it will
|
|
328
|
-
* be passed as the `this` value to the `callbackfn` function. If `thisArg
|
|
329
|
-
* @returns The `map` method is returning a new `HashMap` object with the transformed values based on
|
|
330
|
-
* the provided callback function.
|
|
273
|
+
* Deep clone this map, preserving hashing behavior.
|
|
274
|
+
* @remarks Time O(N), Space O(N)
|
|
275
|
+
* @returns A new map with the same content.
|
|
331
276
|
*/
|
|
332
|
-
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
* @param predicate - The predicate parameter is a function that takes four arguments: value, key,
|
|
348
|
-
* index, and map. It is used to determine whether an element should be included in the filtered map
|
|
349
|
-
* or not. The function should return a boolean value - true if the element should be included, and
|
|
350
|
-
* false otherwise.
|
|
351
|
-
* @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
|
|
352
|
-
* to be used as `this` when executing the `predicate` function. If `thisArg` is provided, it will be
|
|
353
|
-
* passed as the `this` value to the `predicate` function. If `thisArg` is
|
|
354
|
-
* @returns The `filter` method is returning a new `HashMap` object that contains the key-value pairs
|
|
355
|
-
* from the original `HashMap` that pass the provided `predicate` function.
|
|
356
|
-
*/
|
|
357
|
-
filter(predicate: EntryCallback<K, V, boolean>, thisArg?: any): HashMap<K, V> {
|
|
358
|
-
const filteredMap = new HashMap<K, V>();
|
|
277
|
+
clone(): this {
|
|
278
|
+
const opts = { hashFn: this._hashFn, toEntryFn: this._toEntryFn };
|
|
279
|
+
return this._createLike<[K, V], [K, V], [K, V]>(this, opts);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Map values to a new map with the same keys.
|
|
284
|
+
* @remarks Time O(N), Space O(N)
|
|
285
|
+
* @template VM
|
|
286
|
+
* @param callbackfn - Mapping function (key, value, index, map) → newValue.
|
|
287
|
+
* @param [thisArg] - Value for `this` inside the callback.
|
|
288
|
+
* @returns A new map with transformed values.
|
|
289
|
+
*/
|
|
290
|
+
map<VM>(callbackfn: EntryCallback<K, V, VM>, thisArg?: any): any {
|
|
291
|
+
const out = this._createLike<K, VM, [K, VM]>();
|
|
359
292
|
let index = 0;
|
|
360
|
-
for (const [key, value] of this)
|
|
361
|
-
|
|
362
|
-
filteredMap.set(key, value);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
return filteredMap;
|
|
293
|
+
for (const [key, value] of this) out.set(key, callbackfn.call(thisArg, key, value, index++, this));
|
|
294
|
+
return out;
|
|
366
295
|
}
|
|
367
296
|
|
|
368
297
|
/**
|
|
369
|
-
*
|
|
370
|
-
*
|
|
298
|
+
* Filter entries into a new map.
|
|
299
|
+
* @remarks Time O(N), Space O(N)
|
|
300
|
+
* @param predicate - Predicate (key, value, index, map) → boolean.
|
|
301
|
+
* @param [thisArg] - Value for `this` inside the predicate.
|
|
302
|
+
* @returns A new map containing entries that satisfied the predicate.
|
|
371
303
|
*/
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
for (const
|
|
377
|
-
|
|
378
|
-
}
|
|
304
|
+
|
|
305
|
+
filter(predicate: EntryCallback<K, V, boolean>, thisArg?: any): any {
|
|
306
|
+
const out = this._createLike<K, V, [K, V]>();
|
|
307
|
+
let index = 0;
|
|
308
|
+
for (const [key, value] of this) if (predicate.call(thisArg, key, value, index++, this)) out.set(key, value);
|
|
309
|
+
return out;
|
|
379
310
|
}
|
|
380
311
|
|
|
381
312
|
/**
|
|
382
|
-
*
|
|
383
|
-
* @
|
|
384
|
-
* @
|
|
313
|
+
* (Protected) Create a like-kind instance and seed it from an iterable.
|
|
314
|
+
* @remarks Time O(N), Space O(N)
|
|
315
|
+
* @template TK
|
|
316
|
+
* @template TV
|
|
317
|
+
* @template TR
|
|
318
|
+
* @param [entries] - Iterable used to seed the new map.
|
|
319
|
+
* @param [options] - Options forwarded to the constructor.
|
|
320
|
+
* @returns A like-kind map instance.
|
|
385
321
|
*/
|
|
322
|
+
protected _createLike<TK = K, TV = V, TR = [TK, TV]>(entries: Iterable<[TK, TV] | TR> = [], options?: any): any {
|
|
323
|
+
const Ctor = this.constructor as new (e?: Iterable<[TK, TV] | TR>, o?: any) => any;
|
|
324
|
+
return new Ctor(entries, options);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
protected _rehashNoObj(): void {
|
|
328
|
+
const fresh: Record<string, HashMapStoreItem<K, V>> = {};
|
|
329
|
+
for (const { key, value } of Object.values(this._store)) {
|
|
330
|
+
const sk = this._getNoObjKey(key);
|
|
331
|
+
fresh[sk] = { key, value };
|
|
332
|
+
}
|
|
333
|
+
this._store = fresh;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
protected *_getIterator(): IterableIterator<[K, V]> {
|
|
337
|
+
for (const node of Object.values(this.store)) yield [node.key, node.value] as [K, V];
|
|
338
|
+
for (const node of this.objMap) yield node as [K, V];
|
|
339
|
+
}
|
|
340
|
+
|
|
386
341
|
protected _isObjKey(key: any): key is object | ((...args: any[]) => any) {
|
|
387
342
|
const keyType = typeof key;
|
|
388
343
|
return (keyType === 'object' || keyType === 'function') && key !== null;
|
|
389
344
|
}
|
|
390
345
|
|
|
391
|
-
/**
|
|
392
|
-
* The function `_getNoObjKey` takes a key and returns a string representation of the key, handling
|
|
393
|
-
* different types of keys.
|
|
394
|
-
* @param {K} key - The `key` parameter is of type `K`, which represents the type of the key being
|
|
395
|
-
* passed to the `_getNoObjKey` function.
|
|
396
|
-
* @returns a string value.
|
|
397
|
-
*/
|
|
398
346
|
protected _getNoObjKey(key: K): string {
|
|
399
347
|
const keyType = typeof key;
|
|
400
348
|
|
|
@@ -403,7 +351,6 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
403
351
|
strKey = this._hashFn(key);
|
|
404
352
|
} else {
|
|
405
353
|
if (keyType === 'number') {
|
|
406
|
-
// TODO numeric key should has its own hash
|
|
407
354
|
strKey = <string>key;
|
|
408
355
|
} else {
|
|
409
356
|
strKey = <string>key;
|
|
@@ -414,21 +361,22 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
414
361
|
}
|
|
415
362
|
|
|
416
363
|
/**
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
*
|
|
364
|
+
* Hash-based map that preserves insertion order via a doubly-linked list.
|
|
365
|
+
* @remarks Time O(1), Space O(1)
|
|
366
|
+
* @template K
|
|
367
|
+
* @template V
|
|
368
|
+
* @template R
|
|
369
|
+
* @example examples will be generated by unit test
|
|
420
370
|
*/
|
|
421
371
|
export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K, V> {
|
|
422
372
|
protected readonly _sentinel: HashMapLinkedNode<K, V | undefined>;
|
|
423
373
|
|
|
424
374
|
/**
|
|
425
|
-
*
|
|
426
|
-
* @
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
* @param [options] - The `options` parameter is an optional object that can contain the following
|
|
431
|
-
* properties:
|
|
375
|
+
* Create a LinkedHashMap and optionally bulk-insert entries.
|
|
376
|
+
* @remarks Time O(N), Space O(N)
|
|
377
|
+
* @param [entryOrRawElements] - Iterable of entries or raw elements to insert.
|
|
378
|
+
* @param [options] - Options: hash functions and optional record-to-entry converter.
|
|
379
|
+
* @returns New LinkedHashMap instance.
|
|
432
380
|
*/
|
|
433
381
|
constructor(entryOrRawElements: Iterable<R | [K, V]> = [], options?: LinkedHashMapOptions<K, V, R>) {
|
|
434
382
|
super();
|
|
@@ -439,23 +387,13 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
439
387
|
const { hashFn, objHashFn, toEntryFn } = options;
|
|
440
388
|
if (hashFn) this._hashFn = hashFn;
|
|
441
389
|
if (objHashFn) this._objHashFn = objHashFn;
|
|
442
|
-
|
|
443
|
-
if (toEntryFn) {
|
|
444
|
-
this._toEntryFn = toEntryFn;
|
|
445
|
-
}
|
|
390
|
+
if (toEntryFn) this._toEntryFn = toEntryFn;
|
|
446
391
|
}
|
|
447
392
|
|
|
448
|
-
if (entryOrRawElements)
|
|
449
|
-
this.setMany(entryOrRawElements);
|
|
450
|
-
}
|
|
393
|
+
if (entryOrRawElements) this.setMany(entryOrRawElements);
|
|
451
394
|
}
|
|
452
395
|
|
|
453
396
|
protected _hashFn: (key: K) => string = (key: K) => String(key);
|
|
454
|
-
|
|
455
|
-
/**
|
|
456
|
-
* The function returns the hash function used for generating a hash value for a given key.
|
|
457
|
-
* @returns The hash function that takes a key of type K and returns a string.
|
|
458
|
-
*/
|
|
459
397
|
get hashFn(): (key: K) => string {
|
|
460
398
|
return this._hashFn;
|
|
461
399
|
}
|
|
@@ -463,8 +401,9 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
463
401
|
protected _objHashFn: (key: K) => object = (key: K) => <object>key;
|
|
464
402
|
|
|
465
403
|
/**
|
|
466
|
-
*
|
|
467
|
-
* @
|
|
404
|
+
* Get the hash function for object/weak keys.
|
|
405
|
+
* @remarks Time O(1), Space O(1)
|
|
406
|
+
* @returns Object-hash function.
|
|
468
407
|
*/
|
|
469
408
|
get objHashFn(): (key: K) => object {
|
|
470
409
|
return this._objHashFn;
|
|
@@ -473,21 +412,15 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
473
412
|
protected _noObjMap: Record<string, HashMapLinkedNode<K, V | undefined>> = {};
|
|
474
413
|
|
|
475
414
|
/**
|
|
476
|
-
*
|
|
477
|
-
* @
|
|
478
|
-
*
|
|
479
|
-
* values of type V or undefined.
|
|
415
|
+
* Get the internal record for non-object keys.
|
|
416
|
+
* @remarks Time O(1), Space O(1)
|
|
417
|
+
* @returns Record of hash→node.
|
|
480
418
|
*/
|
|
481
419
|
get noObjMap(): Record<string, HashMapLinkedNode<K, V | undefined>> {
|
|
482
420
|
return this._noObjMap;
|
|
483
421
|
}
|
|
484
422
|
|
|
485
423
|
protected _objMap = new WeakMap<object, HashMapLinkedNode<K, V | undefined>>();
|
|
486
|
-
|
|
487
|
-
/**
|
|
488
|
-
* The function returns the WeakMap object used to map objects to HashMapLinkedNode instances.
|
|
489
|
-
* @returns The `objMap` property is being returned.
|
|
490
|
-
*/
|
|
491
424
|
get objMap(): WeakMap<object, HashMapLinkedNode<K, V | undefined>> {
|
|
492
425
|
return this._objMap;
|
|
493
426
|
}
|
|
@@ -495,9 +428,9 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
495
428
|
protected _head: HashMapLinkedNode<K, V | undefined>;
|
|
496
429
|
|
|
497
430
|
/**
|
|
498
|
-
*
|
|
499
|
-
* @
|
|
500
|
-
*
|
|
431
|
+
* Get the head node (first entry) sentinel link.
|
|
432
|
+
* @remarks Time O(1), Space O(1)
|
|
433
|
+
* @returns Head node or sentinel.
|
|
501
434
|
*/
|
|
502
435
|
get head(): HashMapLinkedNode<K, V | undefined> {
|
|
503
436
|
return this._head;
|
|
@@ -506,8 +439,9 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
506
439
|
protected _tail: HashMapLinkedNode<K, V | undefined>;
|
|
507
440
|
|
|
508
441
|
/**
|
|
509
|
-
*
|
|
510
|
-
* @
|
|
442
|
+
* Get the tail node (last entry) sentinel link.
|
|
443
|
+
* @remarks Time O(1), Space O(1)
|
|
444
|
+
* @returns Tail node or sentinel.
|
|
511
445
|
*/
|
|
512
446
|
get tail(): HashMapLinkedNode<K, V | undefined> {
|
|
513
447
|
return this._tail;
|
|
@@ -515,40 +449,25 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
515
449
|
|
|
516
450
|
protected _toEntryFn?: (rawElement: R) => [K, V] = (rawElement: R) => {
|
|
517
451
|
if (this.isEntry(rawElement)) {
|
|
518
|
-
// TODO, For performance optimization, it may be necessary to only inspect the first element traversed.
|
|
519
452
|
return rawElement;
|
|
520
|
-
} else {
|
|
521
|
-
throw new Error(
|
|
522
|
-
"If the provided entryOrRawElements does not adhere to the [key, value] type format, the toEntryFn in the constructor's options parameter needs to specified."
|
|
523
|
-
);
|
|
524
453
|
}
|
|
454
|
+
throw new Error(
|
|
455
|
+
'If `entryOrRawElements` does not adhere to [key,value], provide `options.toEntryFn` to transform raw records.'
|
|
456
|
+
);
|
|
525
457
|
};
|
|
526
|
-
|
|
527
|
-
/**
|
|
528
|
-
* The function returns the value of the _toEntryFn property.
|
|
529
|
-
* @returns The function being returned is `this._toEntryFn`.
|
|
530
|
-
*/
|
|
531
458
|
get toEntryFn() {
|
|
532
459
|
return this._toEntryFn;
|
|
533
460
|
}
|
|
534
461
|
|
|
535
462
|
protected _size = 0;
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
* The function returns the size of an object.
|
|
539
|
-
* @returns The size of the object.
|
|
540
|
-
*/
|
|
541
463
|
get size() {
|
|
542
464
|
return this._size;
|
|
543
465
|
}
|
|
544
466
|
|
|
545
467
|
/**
|
|
546
|
-
*
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
* The function returns the key-value pair at the front of a data structure.
|
|
550
|
-
* @returns The front element of the data structure, represented as a tuple with a key (K) and a
|
|
551
|
-
* value (V).
|
|
468
|
+
* Get the first [key, value] pair.
|
|
469
|
+
* @remarks Time O(1), Space O(1)
|
|
470
|
+
* @returns First entry or undefined when empty.
|
|
552
471
|
*/
|
|
553
472
|
get first() {
|
|
554
473
|
if (this._size === 0) return;
|
|
@@ -556,12 +475,9 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
556
475
|
}
|
|
557
476
|
|
|
558
477
|
/**
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
* The function returns the key-value pair at the end of a data structure.
|
|
563
|
-
* @returns The method is returning an array containing the key-value pair of the tail element in the
|
|
564
|
-
* data structure.
|
|
478
|
+
* Get the last [key, value] pair.
|
|
479
|
+
* @remarks Time O(1), Space O(1)
|
|
480
|
+
* @returns Last entry or undefined when empty.
|
|
565
481
|
*/
|
|
566
482
|
get last() {
|
|
567
483
|
if (this._size === 0) return;
|
|
@@ -569,7 +485,9 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
569
485
|
}
|
|
570
486
|
|
|
571
487
|
/**
|
|
572
|
-
*
|
|
488
|
+
* Iterate from head → tail.
|
|
489
|
+
* @remarks Time O(N), Space O(1)
|
|
490
|
+
* @returns Iterator of [key, value].
|
|
573
491
|
*/
|
|
574
492
|
*begin() {
|
|
575
493
|
let node = this.head;
|
|
@@ -580,8 +498,9 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
580
498
|
}
|
|
581
499
|
|
|
582
500
|
/**
|
|
583
|
-
*
|
|
584
|
-
*
|
|
501
|
+
* Iterate from tail → head.
|
|
502
|
+
* @remarks Time O(N), Space O(1)
|
|
503
|
+
* @returns Iterator of [key, value].
|
|
585
504
|
*/
|
|
586
505
|
*reverseBegin() {
|
|
587
506
|
let node = this.tail;
|
|
@@ -592,53 +511,42 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
592
511
|
}
|
|
593
512
|
|
|
594
513
|
/**
|
|
595
|
-
*
|
|
596
|
-
*
|
|
597
|
-
*
|
|
598
|
-
*
|
|
599
|
-
*
|
|
600
|
-
* @param {K} key - The `key` parameter is the key to be set in the data structure. It can be of any
|
|
601
|
-
* type, but typically it is a string or symbol.
|
|
602
|
-
* @param {V} [value] - The `value` parameter is an optional parameter of type `V`. It represents the
|
|
603
|
-
* value associated with the key being set in the data structure.
|
|
604
|
-
* @returns the size of the data structure after the key-value pair has been set.
|
|
514
|
+
* Insert or replace a single entry; preserves insertion order.
|
|
515
|
+
* @remarks Time O(1), Space O(1)
|
|
516
|
+
* @param key - Key.
|
|
517
|
+
* @param [value] - Value.
|
|
518
|
+
* @returns True when the operation succeeds.
|
|
605
519
|
*/
|
|
606
520
|
set(key: K, value?: V): boolean {
|
|
607
|
-
let node;
|
|
608
|
-
const isNewKey = !this.has(key);
|
|
521
|
+
let node: HashMapLinkedNode<K, V | undefined> | undefined;
|
|
522
|
+
const isNewKey = !this.has(key);
|
|
609
523
|
|
|
610
524
|
if (isWeakKey(key)) {
|
|
611
525
|
const hash = this._objHashFn(key);
|
|
612
526
|
node = this.objMap.get(hash);
|
|
613
|
-
|
|
614
527
|
if (!node && isNewKey) {
|
|
615
|
-
// Create a new node
|
|
616
528
|
node = { key: <K>hash, value, prev: this.tail, next: this._sentinel };
|
|
617
529
|
this.objMap.set(hash, node);
|
|
618
530
|
} else if (node) {
|
|
619
|
-
// Update the value of an existing node
|
|
620
531
|
node.value = value;
|
|
621
532
|
}
|
|
622
533
|
} else {
|
|
623
534
|
const hash = this._hashFn(key);
|
|
624
535
|
node = this.noObjMap[hash];
|
|
625
|
-
|
|
626
536
|
if (!node && isNewKey) {
|
|
627
537
|
this.noObjMap[hash] = node = { key, value, prev: this.tail, next: this._sentinel };
|
|
628
538
|
} else if (node) {
|
|
629
|
-
// Update the value of an existing node
|
|
630
539
|
node.value = value;
|
|
631
540
|
}
|
|
632
541
|
}
|
|
633
542
|
|
|
634
543
|
if (node && isNewKey) {
|
|
635
|
-
// Update the head and tail of the linked list
|
|
636
544
|
if (this._size === 0) {
|
|
637
545
|
this._head = node;
|
|
638
546
|
this._sentinel.next = node;
|
|
639
547
|
} else {
|
|
640
548
|
this.tail.next = node;
|
|
641
|
-
node.prev = this.tail;
|
|
549
|
+
node.prev = this.tail;
|
|
642
550
|
}
|
|
643
551
|
this._tail = node;
|
|
644
552
|
this._sentinel.prev = node;
|
|
@@ -648,274 +556,154 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
648
556
|
return true;
|
|
649
557
|
}
|
|
650
558
|
|
|
651
|
-
/**
|
|
652
|
-
* Time Complexity: O(k)
|
|
653
|
-
* Space Complexity: O(k)
|
|
654
|
-
*
|
|
655
|
-
* The function `setMany` takes an iterable collection, converts each element into a key-value pair
|
|
656
|
-
* using a provided function, and sets each key-value pair in the current object, returning an array
|
|
657
|
-
* of booleans indicating the success of each set operation.
|
|
658
|
-
* @param entryOrRawElements - The entryOrRawElements parameter is an iterable collection of elements of type
|
|
659
|
-
* R.
|
|
660
|
-
* @returns The `setMany` function returns an array of booleans.
|
|
661
|
-
*/
|
|
662
559
|
setMany(entryOrRawElements: Iterable<R | [K, V]>): boolean[] {
|
|
663
560
|
const results: boolean[] = [];
|
|
664
561
|
for (const rawEle of entryOrRawElements) {
|
|
665
562
|
let key: K | undefined, value: V | undefined;
|
|
666
|
-
if (this.isEntry(rawEle))
|
|
667
|
-
|
|
668
|
-
value = rawEle[1];
|
|
669
|
-
} else if (this._toEntryFn) {
|
|
670
|
-
const item = this._toEntryFn(rawEle);
|
|
671
|
-
key = item[0];
|
|
672
|
-
value = item[1];
|
|
673
|
-
}
|
|
674
|
-
|
|
563
|
+
if (this.isEntry(rawEle)) [key, value] = rawEle;
|
|
564
|
+
else if (this._toEntryFn) [key, value] = this._toEntryFn(rawEle);
|
|
675
565
|
if (key !== undefined && value !== undefined) results.push(this.set(key, value));
|
|
676
566
|
}
|
|
677
567
|
return results;
|
|
678
568
|
}
|
|
679
569
|
|
|
680
|
-
/**
|
|
681
|
-
* Time Complexity: O(1)
|
|
682
|
-
* Space Complexity: O(1)
|
|
683
|
-
*
|
|
684
|
-
* The function checks if a given key exists in a map, using different logic depending on whether the
|
|
685
|
-
* key is a weak key or not.
|
|
686
|
-
* @param {K} key - The `key` parameter is the key that is being checked for existence in the map.
|
|
687
|
-
* @returns The method `has` is returning a boolean value.
|
|
688
|
-
*/
|
|
689
570
|
override has(key: K): boolean {
|
|
690
571
|
if (isWeakKey(key)) {
|
|
691
572
|
const hash = this._objHashFn(key);
|
|
692
573
|
return this.objMap.has(hash);
|
|
693
|
-
} else {
|
|
694
|
-
const hash = this._hashFn(key);
|
|
695
|
-
return hash in this.noObjMap;
|
|
696
574
|
}
|
|
575
|
+
const hash = this._hashFn(key);
|
|
576
|
+
return hash in this.noObjMap;
|
|
697
577
|
}
|
|
698
578
|
|
|
699
|
-
/**
|
|
700
|
-
* Time Complexity: O(1)
|
|
701
|
-
* Space Complexity: O(1)
|
|
702
|
-
*
|
|
703
|
-
* The function `get` retrieves the value associated with a given key from a map, either by using the
|
|
704
|
-
* key directly or by using an index stored in the key object.
|
|
705
|
-
* @param {K} key - The `key` parameter is the key used to retrieve a value from the map. It can be
|
|
706
|
-
* of any type, but typically it is a string or symbol.
|
|
707
|
-
* @returns The value associated with the given key is being returned. If the key is an object key,
|
|
708
|
-
* the value is retrieved from the `_nodes` array using the index stored in the `OBJ_KEY_INDEX`
|
|
709
|
-
* property of the key. If the key is a string key, the value is retrieved from the `_noObjMap` object
|
|
710
|
-
* using the key itself. If the key is not found, `undefined` is
|
|
711
|
-
*/
|
|
712
579
|
override get(key: K): V | undefined {
|
|
713
580
|
if (isWeakKey(key)) {
|
|
714
581
|
const hash = this._objHashFn(key);
|
|
715
582
|
const node = this.objMap.get(hash);
|
|
716
583
|
return node ? node.value : undefined;
|
|
717
|
-
} else {
|
|
718
|
-
const hash = this._hashFn(key);
|
|
719
|
-
const node = this.noObjMap[hash];
|
|
720
|
-
return node ? node.value : undefined;
|
|
721
584
|
}
|
|
585
|
+
const hash = this._hashFn(key);
|
|
586
|
+
const node = this.noObjMap[hash];
|
|
587
|
+
return node ? node.value : undefined;
|
|
722
588
|
}
|
|
723
589
|
|
|
724
590
|
/**
|
|
725
|
-
*
|
|
726
|
-
*
|
|
727
|
-
*
|
|
728
|
-
*
|
|
729
|
-
* @param {number} index - The index parameter is a number that represents the position of the
|
|
730
|
-
* element we want to retrieve from the data structure.
|
|
731
|
-
* @returns The method `at(index: number)` is returning an array containing the key-value pair at
|
|
732
|
-
* the specified index in the data structure. The key-value pair is represented as a tuple `[K, V]`,
|
|
733
|
-
* where `K` is the key and `V` is the value.
|
|
591
|
+
* Get the value at a given index in insertion order.
|
|
592
|
+
* @remarks Time O(N), Space O(1)
|
|
593
|
+
* @param index - Zero-based index.
|
|
594
|
+
* @returns Value at the index.
|
|
734
595
|
*/
|
|
735
596
|
at(index: number): V | undefined {
|
|
736
597
|
rangeCheck(index, 0, this._size - 1);
|
|
737
598
|
let node = this.head;
|
|
738
|
-
while (index--)
|
|
739
|
-
node = node.next;
|
|
740
|
-
}
|
|
599
|
+
while (index--) node = node.next;
|
|
741
600
|
return node.value;
|
|
742
601
|
}
|
|
743
602
|
|
|
744
|
-
/**
|
|
745
|
-
* Time Complexity: O(1)
|
|
746
|
-
* Space Complexity: O(1)
|
|
747
|
-
*
|
|
748
|
-
* The `delete` function removes a key-value pair from a map-like data structure.
|
|
749
|
-
* @param {K} key - The `key` parameter is the key that you want to delete from the data structure.
|
|
750
|
-
* It can be of any type, but typically it is a string or an object.
|
|
751
|
-
* @returns a boolean value. It returns `true` if the deletion was successful, and `false` if the key
|
|
752
|
-
* was not found.
|
|
753
|
-
*/
|
|
754
603
|
delete(key: K): boolean {
|
|
755
|
-
let node;
|
|
756
|
-
|
|
604
|
+
let node: HashMapLinkedNode<K, V | undefined> | undefined;
|
|
757
605
|
if (isWeakKey(key)) {
|
|
758
606
|
const hash = this._objHashFn(key);
|
|
759
|
-
// Get nodes from WeakMap
|
|
760
607
|
node = this.objMap.get(hash);
|
|
761
|
-
|
|
762
|
-
if (!node) {
|
|
763
|
-
return false; // If the node does not exist, return false
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
// Remove nodes from WeakMap
|
|
608
|
+
if (!node) return false;
|
|
767
609
|
this.objMap.delete(hash);
|
|
768
610
|
} else {
|
|
769
611
|
const hash = this._hashFn(key);
|
|
770
|
-
// Get nodes from noObjMap
|
|
771
612
|
node = this.noObjMap[hash];
|
|
772
|
-
|
|
773
|
-
if (!node) {
|
|
774
|
-
return false; // If the node does not exist, return false
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
// Remove nodes from orgMap
|
|
613
|
+
if (!node) return false;
|
|
778
614
|
delete this.noObjMap[hash];
|
|
779
615
|
}
|
|
616
|
+
return this._deleteNode(node);
|
|
617
|
+
}
|
|
780
618
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
619
|
+
/**
|
|
620
|
+
* Delete the first entry that matches a predicate.
|
|
621
|
+
* @remarks Time O(N), Space O(1)
|
|
622
|
+
* @param predicate - Function (key, value, index, map) → boolean to decide deletion.
|
|
623
|
+
* @returns True if an entry was removed.
|
|
624
|
+
*/
|
|
625
|
+
deleteWhere(predicate: (key: K, value: V | undefined, index: number, map: this) => boolean): boolean {
|
|
626
|
+
let node = this._head;
|
|
627
|
+
let i = 0;
|
|
628
|
+
while (node !== this._sentinel) {
|
|
629
|
+
const cur = node;
|
|
630
|
+
node = node.next;
|
|
631
|
+
if (predicate(cur.key as K, cur.value as V | undefined, i++, this)) {
|
|
632
|
+
if (isWeakKey(cur.key as unknown as object)) {
|
|
633
|
+
this._objMap.delete(cur.key as unknown as object);
|
|
634
|
+
} else {
|
|
635
|
+
const hash = this._hashFn(cur.key as K);
|
|
636
|
+
delete this._noObjMap[hash];
|
|
637
|
+
}
|
|
638
|
+
return this._deleteNode(cur);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
return false;
|
|
784
642
|
}
|
|
785
643
|
|
|
786
644
|
/**
|
|
787
|
-
*
|
|
788
|
-
*
|
|
789
|
-
*
|
|
790
|
-
*
|
|
791
|
-
* @param {number} index - The index parameter represents the position at which the node should be
|
|
792
|
-
* deleted in the linked list.
|
|
793
|
-
* @returns The size of the list after deleting the element at the specified index.
|
|
645
|
+
* Delete the entry at a given index.
|
|
646
|
+
* @remarks Time O(N), Space O(1)
|
|
647
|
+
* @param index - Zero-based index.
|
|
648
|
+
* @returns True if removed.
|
|
794
649
|
*/
|
|
795
650
|
deleteAt(index: number): boolean {
|
|
796
651
|
rangeCheck(index, 0, this._size - 1);
|
|
797
652
|
let node = this.head;
|
|
798
|
-
while (index--)
|
|
799
|
-
node = node.next;
|
|
800
|
-
}
|
|
653
|
+
while (index--) node = node.next;
|
|
801
654
|
return this._deleteNode(node);
|
|
802
655
|
}
|
|
803
656
|
|
|
804
|
-
/**
|
|
805
|
-
* Time Complexity: O(1)
|
|
806
|
-
* Space Complexity: O(1)
|
|
807
|
-
*
|
|
808
|
-
* The function checks if a data structure is empty by comparing its size to zero.
|
|
809
|
-
* @returns The method is returning a boolean value indicating whether the size of the object is 0 or
|
|
810
|
-
* not.
|
|
811
|
-
*/
|
|
812
657
|
isEmpty(): boolean {
|
|
813
658
|
return this._size === 0;
|
|
814
659
|
}
|
|
815
660
|
|
|
816
|
-
/**
|
|
817
|
-
* The function checks if a given element is an array with exactly two elements.
|
|
818
|
-
* @param {any} rawElement - The `rawElement` parameter is of type `any`, which means it can be any
|
|
819
|
-
* data type.
|
|
820
|
-
* @returns a boolean value.
|
|
821
|
-
*/
|
|
822
661
|
isEntry(rawElement: any): rawElement is [K, V] {
|
|
823
662
|
return Array.isArray(rawElement) && rawElement.length === 2;
|
|
824
663
|
}
|
|
825
664
|
|
|
826
|
-
/**
|
|
827
|
-
* Time Complexity: O(1)
|
|
828
|
-
* Space Complexity: O(1)
|
|
829
|
-
*
|
|
830
|
-
* The `clear` function clears all the entries in a data structure and resets its properties.
|
|
831
|
-
*/
|
|
832
665
|
clear(): void {
|
|
833
666
|
this._noObjMap = {};
|
|
834
667
|
this._size = 0;
|
|
835
668
|
this._head = this._tail = this._sentinel.prev = this._sentinel.next = this._sentinel;
|
|
836
669
|
}
|
|
837
670
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
* of the original `LinkedHashMap` object.
|
|
846
|
-
*/
|
|
847
|
-
clone(): LinkedHashMap<K, V> {
|
|
848
|
-
const cloned = new LinkedHashMap<K, V>([], { hashFn: this._hashFn, objHashFn: this._objHashFn });
|
|
849
|
-
for (const entry of this) {
|
|
850
|
-
const [key, value] = entry;
|
|
851
|
-
cloned.set(key, value);
|
|
852
|
-
}
|
|
853
|
-
return cloned;
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
/**
|
|
857
|
-
* Time Complexity: O(n)
|
|
858
|
-
* Space Complexity: O(n)
|
|
859
|
-
*
|
|
860
|
-
* The `filter` function creates a new `LinkedHashMap` containing key-value pairs from the original
|
|
861
|
-
* map that satisfy a given predicate function.
|
|
862
|
-
* @param predicate - The `predicate` parameter is a callback function that takes four arguments:
|
|
863
|
-
* `value`, `key`, `index`, and `this`. It should return a boolean value indicating whether the
|
|
864
|
-
* current element should be included in the filtered map or not.
|
|
865
|
-
* @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to
|
|
866
|
-
* specify the value of `this` within the `predicate` function. It is used when you want to bind a
|
|
867
|
-
* specific object as the context for the `predicate` function. If `thisArg` is not provided, `this
|
|
868
|
-
* @returns a new `LinkedHashMap` object that contains the key-value pairs from the original
|
|
869
|
-
* `LinkedHashMap` object that satisfy the given predicate function.
|
|
870
|
-
*/
|
|
871
|
-
filter(predicate: EntryCallback<K, V, boolean>, thisArg?: any): LinkedHashMap<K, V> {
|
|
872
|
-
const filteredMap = new LinkedHashMap<K, V>();
|
|
671
|
+
clone(): any {
|
|
672
|
+
const opts = { hashFn: this._hashFn, objHashFn: this._objHashFn };
|
|
673
|
+
return this._createLike<[K, V], [K, V], [K, V]>(this, opts);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
filter(predicate: EntryCallback<K, V, boolean>, thisArg?: any): any {
|
|
677
|
+
const out = this._createLike<K, V, [K, V]>();
|
|
873
678
|
let index = 0;
|
|
874
679
|
for (const [key, value] of this) {
|
|
875
|
-
if (predicate.call(thisArg, key, value, index, this))
|
|
876
|
-
filteredMap.set(key, value);
|
|
877
|
-
}
|
|
680
|
+
if (predicate.call(thisArg, key, value, index, this)) out.set(key, value);
|
|
878
681
|
index++;
|
|
879
682
|
}
|
|
880
|
-
return
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
/**
|
|
884
|
-
*
|
|
885
|
-
*
|
|
886
|
-
*
|
|
887
|
-
*
|
|
888
|
-
*
|
|
889
|
-
* @param
|
|
890
|
-
*
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
* specify the value of `this` within the callback function. If provided, the callback function will
|
|
895
|
-
* be called with `thisArg` as its `this` value. If not provided, `this` will refer to the current
|
|
896
|
-
* map
|
|
897
|
-
* @returns a new `LinkedHashMap` object with the values mapped according to the provided callback
|
|
898
|
-
* function.
|
|
899
|
-
*/
|
|
900
|
-
map<MK, MV>(callback: EntryCallback<K, V, [MK, MV]>, thisArg?: any): LinkedHashMap<MK, MV> {
|
|
901
|
-
const mappedMap = new LinkedHashMap<MK, MV>();
|
|
683
|
+
return out;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Map each entry to a new [key, value] pair and preserve order.
|
|
688
|
+
* @remarks Time O(N), Space O(N)
|
|
689
|
+
* @template MK
|
|
690
|
+
* @template MV
|
|
691
|
+
* @param callback - Mapping function (key, value, index, map) → [newKey, newValue].
|
|
692
|
+
* @param [thisArg] - Value for `this` inside the callback.
|
|
693
|
+
* @returns A new map of the same class with transformed entries.
|
|
694
|
+
*/
|
|
695
|
+
map<MK, MV>(callback: EntryCallback<K, V, [MK, MV]>, thisArg?: any): any {
|
|
696
|
+
const out = this._createLike<MK, MV, [MK, MV]>();
|
|
902
697
|
let index = 0;
|
|
903
698
|
for (const [key, value] of this) {
|
|
904
699
|
const [newKey, newValue] = callback.call(thisArg, key, value, index, this);
|
|
905
|
-
|
|
700
|
+
out.set(newKey, newValue);
|
|
906
701
|
index++;
|
|
907
702
|
}
|
|
908
|
-
return
|
|
703
|
+
return out;
|
|
909
704
|
}
|
|
910
705
|
|
|
911
|
-
|
|
912
|
-
* Time Complexity: O(n)
|
|
913
|
-
* Space Complexity: O(1)
|
|
914
|
-
* where n is the number of entries in the LinkedHashMap.
|
|
915
|
-
*
|
|
916
|
-
* The above function is an iterator that yields key-value pairs from a linked list.
|
|
917
|
-
*/
|
|
918
|
-
protected *_getIterator() {
|
|
706
|
+
protected *_getIterator(): IterableIterator<[K, V]> {
|
|
919
707
|
let node = this.head;
|
|
920
708
|
while (node !== this._sentinel) {
|
|
921
709
|
yield [node.key, node.value] as [K, V];
|
|
@@ -923,30 +711,20 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
923
711
|
}
|
|
924
712
|
}
|
|
925
713
|
|
|
926
|
-
/**
|
|
927
|
-
* Time Complexity: O(1)
|
|
928
|
-
* Space Complexity: O(1)
|
|
929
|
-
*
|
|
930
|
-
* The `_deleteNode` function removes a node from a doubly linked list and updates the head and tail
|
|
931
|
-
* pointers if necessary.
|
|
932
|
-
* @param node - The `node` parameter is an instance of the `HashMapLinkedNode` class, which
|
|
933
|
-
* represents a node in a linked list. It contains a key-value pair and references to the previous
|
|
934
|
-
* and next nodes in the list.
|
|
935
|
-
*/
|
|
936
714
|
protected _deleteNode(node: HashMapLinkedNode<K, V | undefined>): boolean {
|
|
937
715
|
const { prev, next } = node;
|
|
938
716
|
prev.next = next;
|
|
939
717
|
next.prev = prev;
|
|
940
718
|
|
|
941
|
-
if (node === this.head)
|
|
942
|
-
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
if (node === this.tail) {
|
|
946
|
-
this._tail = prev;
|
|
947
|
-
}
|
|
719
|
+
if (node === this.head) this._head = next;
|
|
720
|
+
if (node === this.tail) this._tail = prev;
|
|
948
721
|
|
|
949
722
|
this._size -= 1;
|
|
950
723
|
return true;
|
|
951
724
|
}
|
|
725
|
+
|
|
726
|
+
protected _createLike<TK = K, TV = V, TR = [TK, TV]>(entries: Iterable<[TK, TV] | TR> = [], options?: any): any {
|
|
727
|
+
const Ctor = this.constructor as new (e?: Iterable<[TK, TV] | TR>, o?: any) => any;
|
|
728
|
+
return new Ctor(entries, options);
|
|
729
|
+
}
|
|
952
730
|
}
|