avl-tree-typed 1.47.9 → 1.48.1

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.
@@ -7,9 +7,310 @@
7
7
  * @license MIT License
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.HashMap = void 0;
10
+ exports.LinkedHashMap = exports.HashMap = void 0;
11
11
  const utils_1 = require("../../utils");
12
12
  class HashMap {
13
+ /**
14
+ * The constructor function initializes a new instance of a class with optional elements and options.
15
+ * @param elements - The `elements` parameter is an iterable containing key-value pairs `[K, V]`. It
16
+ * is optional and defaults to an empty array `[]`. This parameter is used to initialize the map with
17
+ * key-value pairs.
18
+ * @param [options] - The `options` parameter is an optional object that can contain additional
19
+ * configuration options for the constructor. In this case, it has one property:
20
+ */
21
+ constructor(elements = [], options) {
22
+ this._store = {};
23
+ this._objMap = new Map();
24
+ this._size = 0;
25
+ this._hashFn = (key) => String(key);
26
+ if (options) {
27
+ const { hashFn } = options;
28
+ if (hashFn) {
29
+ this._hashFn = hashFn;
30
+ }
31
+ }
32
+ if (elements) {
33
+ this.setMany(elements);
34
+ }
35
+ }
36
+ get size() {
37
+ return this._size;
38
+ }
39
+ isEmpty() {
40
+ return this.size === 0;
41
+ }
42
+ clear() {
43
+ this._store = {};
44
+ this._objMap.clear();
45
+ this._size = 0;
46
+ }
47
+ /**
48
+ * The `set` function adds a key-value pair to a map-like data structure, incrementing the size if
49
+ * the key is not already present.
50
+ * @param {K} key - The key parameter is the key used to identify the value in the data structure. It
51
+ * can be of any type, but if it is an object, it will be stored in a Map, otherwise it will be
52
+ * stored in a regular JavaScript object.
53
+ * @param {V} value - The value parameter represents the value that you want to associate with the
54
+ * key in the data structure.
55
+ */
56
+ set(key, value) {
57
+ if (this._isObjKey(key)) {
58
+ if (!this._objMap.has(key)) {
59
+ this._size++;
60
+ }
61
+ this._objMap.set(key, value);
62
+ }
63
+ else {
64
+ const strKey = this._getNoObjKey(key);
65
+ if (this._store[strKey] === undefined) {
66
+ this._size++;
67
+ }
68
+ this._store[strKey] = { key, value };
69
+ }
70
+ }
71
+ /**
72
+ * The function "setMany" sets multiple key-value pairs in a map.
73
+ * @param elements - The `elements` parameter is an iterable containing key-value pairs. Each
74
+ * key-value pair is represented as an array with two elements: the key and the value.
75
+ */
76
+ setMany(elements) {
77
+ for (const [key, value] of elements)
78
+ this.set(key, value);
79
+ }
80
+ /**
81
+ * The `get` function retrieves a value from a map based on a given key, either from an object map or
82
+ * a string map.
83
+ * @param {K} key - The `key` parameter is the key used to retrieve a value from the map. It can be
84
+ * of any type, but it should be compatible with the key type used when the map was created.
85
+ * @returns The method `get(key: K)` returns a value of type `V` if the key exists in the `_objMap`
86
+ * or `_store`, otherwise it returns `undefined`.
87
+ */
88
+ get(key) {
89
+ var _a;
90
+ if (this._isObjKey(key)) {
91
+ return this._objMap.get(key);
92
+ }
93
+ else {
94
+ const strKey = this._getNoObjKey(key);
95
+ return (_a = this._store[strKey]) === null || _a === void 0 ? void 0 : _a.value;
96
+ }
97
+ }
98
+ /**
99
+ * The `has` function checks if a given key exists in the `_objMap` or `_store` based on whether it
100
+ * is an object key or not.
101
+ * @param {K} key - The parameter "key" is of type K, which means it can be any type.
102
+ * @returns The `has` method is returning a boolean value.
103
+ */
104
+ has(key) {
105
+ if (this._isObjKey(key)) {
106
+ return this._objMap.has(key);
107
+ }
108
+ else {
109
+ const strKey = this._getNoObjKey(key);
110
+ return strKey in this._store;
111
+ }
112
+ }
113
+ /**
114
+ * The `delete` function removes an element from a map-like data structure based on the provided key.
115
+ * @param {K} key - The `key` parameter is the key of the element that you want to delete from the
116
+ * data structure.
117
+ * @returns The `delete` method returns a boolean value. It returns `true` if the key was
118
+ * successfully deleted from the map, and `false` if the key was not found in the map.
119
+ */
120
+ delete(key) {
121
+ if (this._isObjKey(key)) {
122
+ if (this._objMap.has(key)) {
123
+ this._size--;
124
+ }
125
+ return this._objMap.delete(key);
126
+ }
127
+ else {
128
+ const strKey = this._getNoObjKey(key);
129
+ if (strKey in this._store) {
130
+ delete this._store[strKey];
131
+ this._size--;
132
+ return true;
133
+ }
134
+ return false;
135
+ }
136
+ }
137
+ /**
138
+ * The function returns an iterator that yields key-value pairs from both an object store and an
139
+ * object map.
140
+ */
141
+ *[Symbol.iterator]() {
142
+ for (const node of Object.values(this._store)) {
143
+ yield [node.key, node.value];
144
+ }
145
+ for (const node of this._objMap) {
146
+ yield node;
147
+ }
148
+ }
149
+ /**
150
+ * The function returns an iterator that yields key-value pairs from the object.
151
+ */
152
+ *entries() {
153
+ for (const item of this) {
154
+ yield item;
155
+ }
156
+ }
157
+ /**
158
+ * The function `keys()` returns an iterator that yields all the keys of the object.
159
+ */
160
+ *keys() {
161
+ for (const [key] of this) {
162
+ yield key;
163
+ }
164
+ }
165
+ *values() {
166
+ for (const [, value] of this) {
167
+ yield value;
168
+ }
169
+ }
170
+ /**
171
+ * The `every` function checks if every element in a HashMap satisfies a given predicate function.
172
+ * @param predicate - The predicate parameter is a function that takes four arguments: value, key,
173
+ * index, and map. It is used to test each element in the map against a condition. If the predicate
174
+ * function returns false for any element, the every() method will return false. If the predicate
175
+ * function returns true for all
176
+ * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
177
+ * to be used as `this` when executing the `predicate` function. If `thisArg` is provided, it will be
178
+ * passed as the `this` value to the `predicate` function. If `thisArg` is
179
+ * @returns The method is returning a boolean value. It returns true if the predicate function
180
+ * returns true for every element in the map, and false otherwise.
181
+ */
182
+ every(predicate, thisArg) {
183
+ let index = 0;
184
+ for (const [key, value] of this) {
185
+ if (!predicate.call(thisArg, value, key, index++, this)) {
186
+ return false;
187
+ }
188
+ }
189
+ return true;
190
+ }
191
+ /**
192
+ * The "some" function checks if at least one element in a HashMap satisfies a given predicate.
193
+ * @param predicate - The `predicate` parameter is a function that takes four arguments: `value`,
194
+ * `key`, `index`, and `map`. It is used to determine whether a specific condition is met for a given
195
+ * key-value pair in the `HashMap`.
196
+ * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
197
+ * to be used as `this` when executing the `predicate` function. If `thisArg` is provided, it will be
198
+ * passed as the `this` value to the `predicate` function. If `thisArg` is
199
+ * @returns a boolean value. It returns true if the predicate function returns true for any element
200
+ * in the map, and false otherwise.
201
+ */
202
+ some(predicate, thisArg) {
203
+ let index = 0;
204
+ for (const [key, value] of this) {
205
+ if (predicate.call(thisArg, value, key, index++, this)) {
206
+ return true;
207
+ }
208
+ }
209
+ return false;
210
+ }
211
+ /**
212
+ * The `forEach` function iterates over the elements of a HashMap and applies a callback function to
213
+ * each element.
214
+ * @param callbackfn - A function that will be called for each key-value pair in the HashMap. It
215
+ * takes four parameters:
216
+ * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
217
+ * to be used as `this` when executing the `callbackfn` function. If `thisArg` is provided, it will
218
+ * be passed as the `this` value inside the `callbackfn` function. If `thisArg
219
+ */
220
+ forEach(callbackfn, thisArg) {
221
+ let index = 0;
222
+ for (const [key, value] of this) {
223
+ callbackfn.call(thisArg, value, key, index++, this);
224
+ }
225
+ }
226
+ /**
227
+ * The `map` function in TypeScript creates a new HashMap by applying a callback function to each
228
+ * key-value pair in the original HashMap.
229
+ * @param callbackfn - The callback function that will be called for each key-value pair in the
230
+ * HashMap. It takes four parameters:
231
+ * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
232
+ * to be used as `this` when executing the `callbackfn` function. If `thisArg` is provided, it will
233
+ * be passed as the `this` value to the `callbackfn` function. If `thisArg
234
+ * @returns The `map` method is returning a new `HashMap` object with the transformed values based on
235
+ * the provided callback function.
236
+ */
237
+ map(callbackfn, thisArg) {
238
+ const resultMap = new HashMap();
239
+ let index = 0;
240
+ for (const [key, value] of this) {
241
+ resultMap.set(key, callbackfn.call(thisArg, value, key, index++, this));
242
+ }
243
+ return resultMap;
244
+ }
245
+ /**
246
+ * The `filter` function creates a new HashMap containing key-value pairs from the original HashMap
247
+ * that satisfy a given predicate function.
248
+ * @param predicate - The predicate parameter is a function that takes four arguments: value, key,
249
+ * index, and map. It is used to determine whether an element should be included in the filtered map
250
+ * or not. The function should return a boolean value - true if the element should be included, and
251
+ * false otherwise.
252
+ * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
253
+ * to be used as `this` when executing the `predicate` function. If `thisArg` is provided, it will be
254
+ * passed as the `this` value to the `predicate` function. If `thisArg` is
255
+ * @returns The `filter` method is returning a new `HashMap` object that contains the key-value pairs
256
+ * from the original `HashMap` that pass the provided `predicate` function.
257
+ */
258
+ filter(predicate, thisArg) {
259
+ const filteredMap = new HashMap();
260
+ let index = 0;
261
+ for (const [key, value] of this) {
262
+ if (predicate.call(thisArg, value, key, index++, this)) {
263
+ filteredMap.set(key, value);
264
+ }
265
+ }
266
+ return filteredMap;
267
+ }
268
+ /**
269
+ * The `reduce` function iterates over the elements of a HashMap and applies a callback function to
270
+ * each element, accumulating a single value.
271
+ * @param callbackfn - The callback function that will be called for each element in the HashMap. It
272
+ * takes five parameters:
273
+ * @param {U} initialValue - The initialValue parameter is the initial value of the accumulator. It
274
+ * is the value that will be used as the first argument of the callback function when reducing the
275
+ * elements of the map.
276
+ * @returns The `reduce` method is returning the final value of the accumulator after iterating over
277
+ * all the elements in the `HashMap`.
278
+ */
279
+ reduce(callbackfn, initialValue) {
280
+ let accumulator = initialValue;
281
+ let index = 0;
282
+ for (const [key, value] of this) {
283
+ accumulator = callbackfn(accumulator, value, key, index++, this);
284
+ }
285
+ return accumulator;
286
+ }
287
+ print() {
288
+ console.log([...this.entries()]);
289
+ }
290
+ _isObjKey(key) {
291
+ const keyType = typeof key;
292
+ return (keyType === 'object' || keyType === 'function') && key !== null;
293
+ }
294
+ _getNoObjKey(key) {
295
+ const keyType = typeof key;
296
+ let strKey;
297
+ if (keyType !== "string" && keyType !== "number" && keyType !== "symbol") {
298
+ strKey = this._hashFn(key);
299
+ }
300
+ else {
301
+ if (keyType === "number") {
302
+ // TODO numeric key should has its own hash
303
+ strKey = key;
304
+ }
305
+ else {
306
+ strKey = key;
307
+ }
308
+ }
309
+ return strKey;
310
+ }
311
+ }
312
+ exports.HashMap = HashMap;
313
+ class LinkedHashMap {
13
314
  constructor(elements, options = {
14
315
  hashFn: (key) => String(key),
15
316
  objHashFn: (key) => key
@@ -92,47 +393,74 @@ class HashMap {
92
393
  */
93
394
  set(key, value) {
94
395
  let node;
396
+ const isNewKey = !this.has(key); // Check if the key is new
95
397
  if ((0, utils_1.isWeakKey)(key)) {
96
398
  const hash = this._objHashFn(key);
97
399
  node = this._objMap.get(hash);
98
- if (node) {
99
- // If the node already exists, update its value
100
- node.value = value;
101
- }
102
- else {
400
+ if (!node && isNewKey) {
103
401
  // Create new node
104
402
  node = { key: hash, value, prev: this._tail, next: this._sentinel };
105
- // Add new nodes to _objMap and linked list
106
403
  this._objMap.set(hash, node);
107
404
  }
405
+ else if (node) {
406
+ // Update the value of an existing node
407
+ node.value = value;
408
+ }
108
409
  }
109
410
  else {
110
411
  const hash = this._hashFn(key);
111
- // Non-object keys are handled in the same way as the original implementation
112
412
  node = this._noObjMap[hash];
113
- if (node) {
413
+ if (!node && isNewKey) {
414
+ this._noObjMap[hash] = node = { key, value, prev: this._tail, next: this._sentinel };
415
+ }
416
+ else if (node) {
417
+ // Update the value of an existing node
114
418
  node.value = value;
115
419
  }
420
+ }
421
+ if (node && isNewKey) {
422
+ // Update the head and tail of the linked list
423
+ if (this._size === 0) {
424
+ this._head = node;
425
+ this._sentinel.next = node;
426
+ }
116
427
  else {
117
- this._noObjMap[hash] = node = {
118
- key,
119
- value,
120
- prev: this._tail,
121
- next: this._sentinel
122
- };
428
+ this._tail.next = node;
429
+ node.prev = this._tail; // Make sure that the prev of the new node points to the current tail node
123
430
  }
431
+ this._tail = node;
432
+ this._sentinel.prev = node;
433
+ this._size++;
124
434
  }
125
- if (this._size === 0) {
126
- this._head = node;
127
- this._sentinel.next = node;
435
+ return this._size;
436
+ }
437
+ has(key) {
438
+ if ((0, utils_1.isWeakKey)(key)) {
439
+ const hash = this._objHashFn(key);
440
+ return this._objMap.has(hash);
128
441
  }
129
442
  else {
130
- this._tail.next = node;
443
+ const hash = this._hashFn(key);
444
+ return hash in this._noObjMap;
131
445
  }
132
- this._tail = node;
133
- this._sentinel.prev = node;
134
- this._size++;
135
- return this._size;
446
+ }
447
+ setMany(entries) {
448
+ for (const entry of entries) {
449
+ const [key, value] = entry;
450
+ this.set(key, value);
451
+ }
452
+ }
453
+ keys() {
454
+ const keys = [];
455
+ for (const [key] of this)
456
+ keys.push(key);
457
+ return keys;
458
+ }
459
+ values() {
460
+ const values = [];
461
+ for (const [, value] of this)
462
+ values.push(value);
463
+ return values;
136
464
  }
137
465
  /**
138
466
  * Time Complexity: O(1)
@@ -254,14 +582,22 @@ class HashMap {
254
582
  this._size = 0;
255
583
  this._head = this._tail = this._sentinel.prev = this._sentinel.next = this._sentinel;
256
584
  }
585
+ clone() {
586
+ const cloned = new LinkedHashMap([], { hashFn: this._hashFn, objHashFn: this._objHashFn });
587
+ for (const entry of this) {
588
+ const [key, value] = entry;
589
+ cloned.set(key, value);
590
+ }
591
+ return cloned;
592
+ }
257
593
  /**
258
- * Time Complexity: O(n), where n is the number of elements in the HashMap.
594
+ * Time Complexity: O(n), where n is the number of elements in the LinkedHashMap.
259
595
  * Space Complexity: O(1)
260
596
  *
261
- * The `forEach` function iterates over each element in a HashMap and executes a callback function on
597
+ * The `forEach` function iterates over each element in a LinkedHashMap and executes a callback function on
262
598
  * each element.
263
599
  * @param callback - The callback parameter is a function that will be called for each element in the
264
- * HashMap. It takes three arguments:
600
+ * LinkedHashMap. It takes three arguments:
265
601
  */
266
602
  forEach(callback) {
267
603
  let index = 0;
@@ -272,15 +608,15 @@ class HashMap {
272
608
  }
273
609
  }
274
610
  /**
275
- * The `filter` function takes a predicate function and returns a new HashMap containing only the
611
+ * The `filter` function takes a predicate function and returns a new LinkedHashMap containing only the
276
612
  * key-value pairs that satisfy the predicate.
277
613
  * @param predicate - The `predicate` parameter is a function that takes two arguments: `element` and
278
614
  * `map`.
279
- * @returns a new HashMap object that contains the key-value pairs from the original HashMap that
615
+ * @returns a new LinkedHashMap object that contains the key-value pairs from the original LinkedHashMap that
280
616
  * satisfy the given predicate function.
281
617
  */
282
618
  filter(predicate) {
283
- const filteredMap = new HashMap();
619
+ const filteredMap = new LinkedHashMap();
284
620
  let index = 0;
285
621
  for (const [key, value] of this) {
286
622
  if (predicate([key, value], index, this)) {
@@ -291,14 +627,14 @@ class HashMap {
291
627
  return filteredMap;
292
628
  }
293
629
  /**
294
- * The `map` function takes a callback function and returns a new HashMap with the values transformed
630
+ * The `map` function takes a callback function and returns a new LinkedHashMap with the values transformed
295
631
  * by the callback.
296
632
  * @param callback - The `callback` parameter is a function that takes two arguments: `element` and
297
633
  * `map`.
298
- * @returns a new HashMap object with the values mapped according to the provided callback function.
634
+ * @returns a new LinkedHashMap object with the values mapped according to the provided callback function.
299
635
  */
300
636
  map(callback) {
301
- const mappedMap = new HashMap();
637
+ const mappedMap = new LinkedHashMap();
302
638
  let index = 0;
303
639
  for (const [key, value] of this) {
304
640
  const newValue = callback([key, value], index, this);
@@ -308,16 +644,16 @@ class HashMap {
308
644
  return mappedMap;
309
645
  }
310
646
  /**
311
- * The `reduce` function iterates over the elements of a HashMap and applies a callback function to
647
+ * The `reduce` function iterates over the elements of a LinkedHashMap and applies a callback function to
312
648
  * each element, accumulating a single value.
313
649
  * @param callback - The callback parameter is a function that takes three arguments: accumulator,
314
- * element, and map. It is called for each element in the HashMap and is used to accumulate a single
650
+ * element, and map. It is called for each element in the LinkedHashMap and is used to accumulate a single
315
651
  * result.
316
652
  * @param {A} initialValue - The `initialValue` parameter is the initial value of the accumulator. It
317
653
  * is the value that will be passed as the first argument to the `callback` function when reducing
318
654
  * the elements of the map.
319
655
  * @returns The `reduce` function is returning the final value of the accumulator after iterating
320
- * over all the elements in the HashMap and applying the callback function to each element.
656
+ * over all the elements in the LinkedHashMap and applying the callback function to each element.
321
657
  */
322
658
  reduce(callback, initialValue) {
323
659
  let accumulator = initialValue;
@@ -329,7 +665,7 @@ class HashMap {
329
665
  return accumulator;
330
666
  }
331
667
  /**
332
- * Time Complexity: O(n), where n is the number of elements in the HashMap.
668
+ * Time Complexity: O(n), where n is the number of elements in the LinkedHashMap.
333
669
  * Space Complexity: O(1)
334
670
  *
335
671
  * The above function is an iterator that yields key-value pairs from a linked list.
@@ -367,4 +703,4 @@ class HashMap {
367
703
  this._size -= 1;
368
704
  }
369
705
  }
370
- exports.HashMap = HashMap;
706
+ exports.LinkedHashMap = LinkedHashMap;
@@ -8,3 +8,7 @@ export type HashMapOptions<K> = {
8
8
  hashFn: (key: K) => string;
9
9
  objHashFn: (key: K) => object;
10
10
  };
11
+ export type HashMapStoreItem<K, V> = {
12
+ key: K;
13
+ value: V;
14
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "avl-tree-typed",
3
- "version": "1.47.9",
3
+ "version": "1.48.1",
4
4
  "description": "AVLTree(Adelson-Velsky and Landis Tree). Javascript & Typescript Data Structure.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -163,6 +163,6 @@
163
163
  "typescript": "^4.9.5"
164
164
  },
165
165
  "dependencies": {
166
- "data-structure-typed": "^1.47.9"
166
+ "data-structure-typed": "^1.48.1"
167
167
  }
168
168
  }
@@ -82,6 +82,15 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
82
82
  }) as TREE;
83
83
  }
84
84
 
85
+ /**
86
+ * The function checks if an exemplar is an instance of AVLTreeNode.
87
+ * @param exemplar - The `exemplar` parameter is of type `BTNodeExemplar<V, N>`.
88
+ * @returns a boolean value indicating whether the exemplar is an instance of the AVLTreeNode class.
89
+ */
90
+ override isNode(exemplar: BTNodeExemplar<V, N>): exemplar is N {
91
+ return exemplar instanceof AVLTreeNode;
92
+ }
93
+
85
94
  /**
86
95
  * Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (BST) has logarithmic time complexity.
87
96
  * Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size.