1
>
/*---------------------------------------------------------------------------------------------
prefixTree.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import { Iterable } from './iterator.js';
7
>
8
>
const unset = Symbol('unset');
9
>
10
>
export interface IPrefixTreeNode<T> {
11
>
/** Possible children of the node. */
12
>
children?: ReadonlyMap<string, Node<T>>;
13
>
14
>
/** The value if data exists for this node in the tree. Mutable. */
15
>
value: T | undefined;
16
>
}
17
>
18
>
/**
19
>
* A simple prefix tree implementation where a value is stored based on
20
>
* well-defined prefix segments.
21
>
*/
22
>
export class WellDefinedPrefixTree<V> {
23
public readonly root = new Node<V>();
24
private _size = 0;
26
>
/** Tree size, not including the root. */
27
>
public get size() {
28
return this._size;
29
}
31
>
/** Gets the top-level nodes of the tree */
32
>
public get nodes(): Iterable<IPrefixTreeNode<V>> {
33
return this.root.children?.values() || Iterable.empty();
34
}
36
>
/** Gets the top-level nodes of the tree */
37
>
public get entries(): Iterable<[string, IPrefixTreeNode<V>]> {
38
return this.root.children?.entries() || Iterable.empty();
39
}
41
>
/**
42
>
* Inserts a new value in the prefix tree.
43
>
* @param onNode - called for each node as we descend to the insertion point,
44
>
* including the insertion point itself.
45
>
*/
46
>
insert(key: Iterable<string>, value: V, onNode?: (n: IPrefixTreeNode<V>) => void): void {
47
this.opNode(key, n => n._value = value, onNode);
48
}
50
>
/** Mutates a value in the prefix tree. */
51
>
mutate(key: Iterable<string>, mutate: (value?: V) => V): void {
52
this.opNode(key, n => n._value = mutate(n._value === unset ? undefined : n._value));
53
}
55
>
/** Mutates nodes along the path in the prefix tree. */
56
>
mutatePath(key: Iterable<string>, mutate: (node: IPrefixTreeNode<V>) => void): void {
57
this.opNode(key, () => { }, n => mutate(n));
58
}
60
>
/** Deletes a node from the prefix tree, returning the value it contained. */
61
>
delete(key: Iterable<string>): V | undefined {
62
const path = this.getPathToKey(key);
63
if (!path) {