Skip to content

Commit 418f795

Browse files
committed
fix: adding getSubSet and clone for NestedSet
1 parent 6384211 commit 418f795

File tree

2 files changed

+39
-13
lines changed

2 files changed

+39
-13
lines changed

libs/js-tuple/docs/advanced-getsubmap-example.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ console.log(subClone.get([3])); // 'z'
9999
- **Multi-tenant Data:**
100100
- Partition data by tenant/user/project, and operate on each partition via submaps for isolation and clarity.
101101

102-
102+
## About NestedSet
103+
NestedSet offers the equivalent methods, too, **getSubSet** and **clone**, and everything explained here is valid for them, too!
103104

104105
## Notes
105106
- Traversal from a submap yields keys relative to the base path.

libs/js-tuple/src/nested-set.ts

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,83 @@
11
import { NestedMap } from './nested-map';
2-
import { IterationOptions } from './types';
2+
import { IterationOptions, PartialKey } from './types';
33

44
export interface NestedSet<K> extends Set<K> {}
55
export class NestedSet<K> implements Set<K> {
6-
private readonly _map = new NestedMap<K, 1>();
6+
#map = new NestedMap<K, 1>();
77

88
add(value: K): this {
9-
this._map.set(value, 1);
9+
this.#map.set(value, 1);
1010
return this;
1111
}
1212
clear(): void {
13-
this._map.clear();
13+
this.#map.clear();
1414
}
1515
delete(value: K): boolean {
16-
return this._map.delete(value);
16+
return this.#map.delete(value);
1717
}
1818
forEach(
1919
callbackfn: (value: K, value2: K, set: Set<K>) => void,
2020
thisArg?: unknown,
2121
): void {
2222
thisArg ??= this;
23-
this._map.forEach.call(
23+
this.#map.forEach.call(
2424
thisArg,
2525
(_, k: K) => callbackfn(k, k, this),
2626
thisArg,
2727
);
2828
}
2929
has(value: K): boolean {
30-
return this._map.has(value);
30+
return this.#map.has(value);
3131
}
3232

3333
get size(): number {
34-
return this._map.size;
34+
return this.#map.size;
3535
}
3636

3737
*entries(options?: IterationOptions<K>): SetIterator<[K, K]> {
38-
for (const key of this._map.keys(options)) {
38+
for (const key of this.#map.keys(options)) {
3939
yield [key, key];
4040
}
4141
}
4242

4343
keys(options?: IterationOptions<K>): SetIterator<K> {
44-
return this._map.keys(options);
44+
return this.#map.keys(options);
4545
}
4646

4747
values(options?: IterationOptions<K>): SetIterator<K> {
48-
return this._map.keys(options);
48+
return this.#map.keys(options);
4949
}
5050

5151
[Symbol.iterator](): SetIterator<K> {
52-
return this._map.keys();
52+
return this.#map.keys();
5353
}
5454

5555
get [Symbol.toStringTag](): string {
5656
return 'NestedSet';
5757
}
58+
59+
/**
60+
* Creates a new NestedSet instance that represents a subtree starting from the specified basePath.
61+
* The new NestedSet is a view from the same structure and values as the original map for the specified subtree.
62+
* Changes to the subtree in the new map will be reflected in the original map and vice versa.
63+
* @param basePath - The path to the subtree root
64+
* @returns A new NestedSet instance exposing the subtree
65+
*/
66+
getSubSet(basePath: PartialKey<K>): NestedSet<K> {
67+
const map = this.#map.getSubMap(basePath);
68+
const result = new NestedSet<K>();
69+
result.#map = map;
70+
return result;
71+
}
72+
73+
/**
74+
* Efficiently deep clones the NestedSet or a subtree if basePath is provided (O(N)), using BFS pre-order for insertion order preservation.
75+
* @param basePath - Optional path to clone only a subtree
76+
* @returns A new NestedSet instance with the same structure and values
77+
*/
78+
clone(basePath?: PartialKey<K>): NestedSet<K> {
79+
const result = new NestedSet<K>();
80+
result.#map = this.#map.clone(basePath);
81+
return result;
82+
}
5883
}

0 commit comments

Comments
 (0)