cspell-trie-lib 8.4.0 → 8.5.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/lib/Builder/TrieBuilder.d.ts +0 -10
- package/dist/lib/Builder/cursor-util.d.ts +0 -1
- package/dist/lib/Builder/cursor-util.js +3 -18
- package/dist/lib/ITrieNode/find.js +2 -2
- package/dist/lib/TrieBlob/FastTrieBlob.d.ts +4 -26
- package/dist/lib/TrieBlob/FastTrieBlob.js +17 -98
- package/dist/lib/TrieBlob/FastTrieBlobBuilder.d.ts +1 -4
- package/dist/lib/TrieBlob/FastTrieBlobBuilder.js +12 -82
- package/dist/lib/TrieBlob/FastTrieBlobIRoot.d.ts +7 -17
- package/dist/lib/TrieBlob/FastTrieBlobIRoot.js +39 -129
- package/dist/lib/TrieBlob/FastTrieBlobInternals.d.ts +2 -3
- package/dist/lib/TrieBlob/FastTrieBlobInternals.js +0 -3
- package/dist/lib/TrieBlob/TrieBlob.d.ts +4 -57
- package/dist/lib/TrieBlob/TrieBlob.js +20 -119
- package/dist/lib/TrieBlob/TrieBlobIRoot.d.ts +7 -19
- package/dist/lib/TrieBlob/TrieBlobIRoot.js +33 -129
- package/dist/lib/TrieBlob/createTrieBlob.d.ts +1 -1
- package/dist/lib/TrieData.d.ts +0 -2
- package/dist/lib/TrieNode/TrieNodeBuilder.d.ts +0 -1
- package/dist/lib/TrieNode/TrieNodeBuilder.js +0 -1
- package/dist/lib/TrieNode/TrieNodeTrie.d.ts +0 -1
- package/dist/lib/TrieNode/TrieNodeTrie.js +0 -1
- package/dist/lib/utils/text.d.ts +0 -2
- package/dist/lib/utils/text.js +0 -27
- package/package.json +7 -7
- package/dist/lib/TrieBlob/NumberSequenceByteDecoderAccumulator.d.ts +0 -34
- package/dist/lib/TrieBlob/NumberSequenceByteDecoderAccumulator.js +0 -120
|
@@ -2,16 +2,6 @@ import type { PartialTrieOptions, TrieOptions } from '../trie.js';
|
|
|
2
2
|
import type { TrieData } from '../TrieData.js';
|
|
3
3
|
import type { BuilderCursor } from './BuilderCursor.js';
|
|
4
4
|
export interface TrieBuilder<T extends TrieData> {
|
|
5
|
-
/**
|
|
6
|
-
* Use this method to convert a word into an array of characters.
|
|
7
|
-
* Since `[...word]` is not equal to `word.split('')` or `word[i]` in some cases,
|
|
8
|
-
* this method is used to ensure that the characters are split correctly.
|
|
9
|
-
* @see [String.codePointAt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt)
|
|
10
|
-
* @see [String.charCodeAt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt)
|
|
11
|
-
* @param word - The word to convert into an array of characters.
|
|
12
|
-
* @returns An array of characters, one for each character in the word.
|
|
13
|
-
*/
|
|
14
|
-
wordToCharacters(word: string): string[];
|
|
15
5
|
getCursor(): BuilderCursor;
|
|
16
6
|
build(): T;
|
|
17
7
|
setOptions(options: Readonly<PartialTrieOptions>): Readonly<TrieOptions>;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import type { BuilderCursor } from './BuilderCursor.js';
|
|
2
2
|
export declare function insertWordsAtCursor(cursor: BuilderCursor, words: Iterable<string>): void;
|
|
3
|
-
export declare function commonStringPrefixLen(a: string, b: string): number;
|
|
4
3
|
//# sourceMappingURL=cursor-util.d.ts.map
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
export function insertWordsAtCursor(cursor, words) {
|
|
2
2
|
let prevWord = '';
|
|
3
3
|
for (const word of words) {
|
|
4
|
-
const pLen =
|
|
4
|
+
const pLen = commonPrefixLen(prevWord, word);
|
|
5
5
|
const stepBack = prevWord.length - pLen;
|
|
6
6
|
cursor.backStep(stepBack);
|
|
7
|
-
|
|
8
|
-
for (let i = pLen; i < wLen; ++i) {
|
|
7
|
+
for (let i = pLen; i < word.length; ++i) {
|
|
9
8
|
cursor.insertChar(word[i]);
|
|
10
9
|
}
|
|
11
10
|
cursor.markEOW();
|
|
@@ -13,21 +12,7 @@ export function insertWordsAtCursor(cursor, words) {
|
|
|
13
12
|
}
|
|
14
13
|
cursor.backStep(prevWord.length);
|
|
15
14
|
}
|
|
16
|
-
|
|
17
|
-
let i = 0;
|
|
18
|
-
for (i = 0; i < a.length && a[i] === b[i]; ++i) {
|
|
19
|
-
/* empty */
|
|
20
|
-
}
|
|
21
|
-
if (i) {
|
|
22
|
-
// detect second half of a surrogate pair and backup.
|
|
23
|
-
const c = a.charCodeAt(i) & 0xffff;
|
|
24
|
-
if (c >= 0xdc00 && c <= 0xdfff) {
|
|
25
|
-
--i;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return i;
|
|
29
|
-
}
|
|
30
|
-
function commonStrPrefix(a, b) {
|
|
15
|
+
function commonPrefixLen(a, b) {
|
|
31
16
|
let i = 0;
|
|
32
17
|
for (i = 0; i < a.length && a[i] === b[i]; ++i) {
|
|
33
18
|
/* empty */
|
|
@@ -186,10 +186,10 @@ export function isEndOfWordNode(n) {
|
|
|
186
186
|
return !!n?.eow;
|
|
187
187
|
}
|
|
188
188
|
function walk(root, word) {
|
|
189
|
-
const w =
|
|
189
|
+
const w = word;
|
|
190
190
|
let n = root;
|
|
191
191
|
let i = 0;
|
|
192
|
-
while (n && i <
|
|
192
|
+
while (n && i < word.length) {
|
|
193
193
|
const h = w[i++];
|
|
194
194
|
n = n.get(h);
|
|
195
195
|
}
|
|
@@ -6,29 +6,21 @@ import { FastTrieBlobInternals } from './FastTrieBlobInternals.js';
|
|
|
6
6
|
import { TrieBlob } from './TrieBlob.js';
|
|
7
7
|
export declare class FastTrieBlob implements TrieData {
|
|
8
8
|
private nodes;
|
|
9
|
-
private
|
|
9
|
+
private charIndex;
|
|
10
10
|
readonly bitMasksInfo: FastTrieBlobBitMaskInfo;
|
|
11
|
-
private
|
|
11
|
+
private charToIndexMap;
|
|
12
12
|
private _readonly;
|
|
13
13
|
private _forbidIdx;
|
|
14
14
|
private _iTrieRoot;
|
|
15
|
-
wordToCharacters: (word: string) => readonly string[];
|
|
16
15
|
readonly info: Readonly<TrieInfo>;
|
|
17
16
|
private constructor();
|
|
18
|
-
private
|
|
19
|
-
private wordToNodeCharIndexSequence;
|
|
20
|
-
private letterToNodeCharIndexSequence;
|
|
17
|
+
private lookUpCharIndex;
|
|
21
18
|
has(word: string): boolean;
|
|
22
19
|
private _has;
|
|
23
20
|
words(): Iterable<string>;
|
|
24
21
|
toTrieBlob(): TrieBlob;
|
|
25
22
|
isReadonly(): boolean;
|
|
26
23
|
freeze(): this;
|
|
27
|
-
toJSON(): {
|
|
28
|
-
info: Readonly<TrieInfo>;
|
|
29
|
-
nodes: NodeElement[];
|
|
30
|
-
charIndex: readonly string[];
|
|
31
|
-
};
|
|
32
24
|
static create(data: FastTrieBlobInternals, options?: PartialTrieInfo): FastTrieBlob;
|
|
33
25
|
static toITrieNodeRoot(trie: FastTrieBlob): ITrieNodeRoot;
|
|
34
26
|
static NodeMaskEOW: number;
|
|
@@ -42,20 +34,6 @@ export declare class FastTrieBlob implements TrieData {
|
|
|
42
34
|
hasForbiddenWords(): boolean;
|
|
43
35
|
/** number of nodes */
|
|
44
36
|
get size(): number;
|
|
45
|
-
private
|
|
46
|
-
/** Search from nodeIdx for the node index representing the character. */
|
|
47
|
-
private _searchNodeForChar;
|
|
48
|
-
get charIndex(): readonly string[];
|
|
49
|
-
static fromTrieBlob(trie: TrieBlob): FastTrieBlob;
|
|
37
|
+
private _lookupChar;
|
|
50
38
|
}
|
|
51
|
-
interface NodeElement {
|
|
52
|
-
id: number;
|
|
53
|
-
eow: boolean;
|
|
54
|
-
n: number;
|
|
55
|
-
c: {
|
|
56
|
-
c: number | string;
|
|
57
|
-
i: number;
|
|
58
|
-
}[];
|
|
59
|
-
}
|
|
60
|
-
export {};
|
|
61
39
|
//# sourceMappingURL=FastTrieBlob.d.ts.map
|
|
@@ -3,35 +3,26 @@ import { mergeOptionalWithDefaults } from '../utils/mergeOptionalWithDefaults.js
|
|
|
3
3
|
import { extractInfo } from './FastTrieBlobBitMaskInfo.js';
|
|
4
4
|
import { FastTrieBlobInternals } from './FastTrieBlobInternals.js';
|
|
5
5
|
import { FastTrieBlobIRoot } from './FastTrieBlobIRoot.js';
|
|
6
|
-
import { NumberSequenceByteDecoderAccumulator } from './NumberSequenceByteDecoderAccumulator.js';
|
|
7
6
|
import { TrieBlob } from './TrieBlob.js';
|
|
8
7
|
export class FastTrieBlob {
|
|
9
8
|
nodes;
|
|
10
|
-
|
|
9
|
+
charIndex;
|
|
11
10
|
bitMasksInfo;
|
|
12
|
-
|
|
11
|
+
charToIndexMap;
|
|
13
12
|
_readonly = false;
|
|
14
13
|
_forbidIdx;
|
|
15
14
|
_iTrieRoot;
|
|
16
|
-
wordToCharacters;
|
|
17
15
|
info;
|
|
18
|
-
constructor(nodes,
|
|
16
|
+
constructor(nodes, charIndex, bitMasksInfo, options) {
|
|
19
17
|
this.nodes = nodes;
|
|
20
|
-
this.
|
|
18
|
+
this.charIndex = charIndex;
|
|
21
19
|
this.bitMasksInfo = bitMasksInfo;
|
|
22
20
|
this.info = mergeOptionalWithDefaults(options);
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
25
|
-
this._forbidIdx = this._searchNodeForChar(0, this.info.forbiddenWordPrefix);
|
|
21
|
+
this.charToIndexMap = createCharToIndexMap(charIndex);
|
|
22
|
+
this._forbidIdx = this._lookupChar(0, this.info.forbiddenWordPrefix);
|
|
26
23
|
}
|
|
27
|
-
|
|
28
|
-
return this.
|
|
29
|
-
}
|
|
30
|
-
wordToNodeCharIndexSequence(word) {
|
|
31
|
-
return TrieBlob.charactersToCharIndexSequence(this.wordToCharacters(word), (c) => this._lookUpCharIndex(c));
|
|
32
|
-
}
|
|
33
|
-
letterToNodeCharIndexSequence(letter) {
|
|
34
|
-
return TrieBlob.toCharIndexSequence(this._lookUpCharIndex(letter));
|
|
24
|
+
lookUpCharIndex(char) {
|
|
25
|
+
return this.charToIndexMap[char] ?? -1;
|
|
35
26
|
}
|
|
36
27
|
has(word) {
|
|
37
28
|
return this._has(0, word);
|
|
@@ -41,11 +32,10 @@ export class FastTrieBlob {
|
|
|
41
32
|
const NodeChildRefShift = this.bitMasksInfo.NodeChildRefShift;
|
|
42
33
|
const NodeMaskEOW = this.bitMasksInfo.NodeMaskEOW;
|
|
43
34
|
const nodes = this.nodes;
|
|
44
|
-
const
|
|
45
|
-
const len = charIndexes.length;
|
|
35
|
+
const len = word.length;
|
|
46
36
|
let node = nodes[nodeIdx];
|
|
47
37
|
for (let p = 0; p < len; ++p, node = nodes[nodeIdx]) {
|
|
48
|
-
const letterIdx =
|
|
38
|
+
const letterIdx = this.lookUpCharIndex(word[p]);
|
|
49
39
|
const count = node.length;
|
|
50
40
|
let i = count - 1;
|
|
51
41
|
for (; i > 0; --i) {
|
|
@@ -66,11 +56,10 @@ export class FastTrieBlob {
|
|
|
66
56
|
const NodeChildRefShift = this.bitMasksInfo.NodeChildRefShift;
|
|
67
57
|
const NodeMaskEOW = this.bitMasksInfo.NodeMaskEOW;
|
|
68
58
|
const nodes = this.nodes;
|
|
69
|
-
const
|
|
70
|
-
const stack = [{ nodeIdx: 0, pos: 0, word: '', accumulator }];
|
|
59
|
+
const stack = [{ nodeIdx: 0, pos: 0, word: '' }];
|
|
71
60
|
let depth = 0;
|
|
72
61
|
while (depth >= 0) {
|
|
73
|
-
const { nodeIdx, pos, word
|
|
62
|
+
const { nodeIdx, pos, word } = stack[depth];
|
|
74
63
|
const node = nodes[nodeIdx];
|
|
75
64
|
if (!pos && node[0] & NodeMaskEOW) {
|
|
76
65
|
yield word;
|
|
@@ -82,15 +71,12 @@ export class FastTrieBlob {
|
|
|
82
71
|
const nextPos = ++stack[depth].pos;
|
|
83
72
|
const entry = node[nextPos];
|
|
84
73
|
const charIdx = entry & NodeMaskChildCharIndex;
|
|
85
|
-
const
|
|
86
|
-
const letterIdx = acc.decode(charIdx);
|
|
87
|
-
const letter = (letterIdx && this._charIndex[letterIdx]) || '';
|
|
74
|
+
const letter = this.charIndex[charIdx];
|
|
88
75
|
++depth;
|
|
89
76
|
stack[depth] = {
|
|
90
77
|
nodeIdx: entry >>> NodeChildRefShift,
|
|
91
78
|
pos: 0,
|
|
92
79
|
word: word + letter,
|
|
93
|
-
accumulator: acc,
|
|
94
80
|
};
|
|
95
81
|
}
|
|
96
82
|
}
|
|
@@ -125,7 +111,7 @@ export class FastTrieBlob {
|
|
|
125
111
|
binNodes[offset++] = (nodeToIndex[nodeRef] << refShift) | charIndex;
|
|
126
112
|
}
|
|
127
113
|
}
|
|
128
|
-
return new TrieBlob(binNodes, this.
|
|
114
|
+
return new TrieBlob(binNodes, this.charIndex, this.info);
|
|
129
115
|
}
|
|
130
116
|
isReadonly() {
|
|
131
117
|
return this._readonly;
|
|
@@ -134,18 +120,11 @@ export class FastTrieBlob {
|
|
|
134
120
|
this._readonly = true;
|
|
135
121
|
return this;
|
|
136
122
|
}
|
|
137
|
-
toJSON() {
|
|
138
|
-
return {
|
|
139
|
-
info: this.info,
|
|
140
|
-
nodes: nodesToJson(this.nodes),
|
|
141
|
-
charIndex: this._charIndex,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
123
|
static create(data, options) {
|
|
145
124
|
return new FastTrieBlob(data.nodes, data.charIndex, extractInfo(data), options);
|
|
146
125
|
}
|
|
147
126
|
static toITrieNodeRoot(trie) {
|
|
148
|
-
return new FastTrieBlobIRoot(new FastTrieBlobInternals(trie.nodes, trie.
|
|
127
|
+
return new FastTrieBlobIRoot(new FastTrieBlobInternals(trie.nodes, trie.charIndex, trie.charToIndexMap, trie.bitMasksInfo), 0, trie.info);
|
|
149
128
|
}
|
|
150
129
|
static NodeMaskEOW = TrieBlob.NodeMaskEOW;
|
|
151
130
|
static NodeChildRefShift = TrieBlob.NodeChildRefShift;
|
|
@@ -174,12 +153,12 @@ export class FastTrieBlob {
|
|
|
174
153
|
get size() {
|
|
175
154
|
return this.nodes.length;
|
|
176
155
|
}
|
|
177
|
-
|
|
156
|
+
_lookupChar(nodeIdx, char) {
|
|
178
157
|
const NodeMaskChildCharIndex = this.bitMasksInfo.NodeMaskChildCharIndex;
|
|
179
158
|
const NodeChildRefShift = this.bitMasksInfo.NodeChildRefShift;
|
|
180
159
|
const nodes = this.nodes;
|
|
181
160
|
const node = nodes[nodeIdx];
|
|
182
|
-
const letterIdx =
|
|
161
|
+
const letterIdx = this.lookUpCharIndex(char);
|
|
183
162
|
const count = node.length;
|
|
184
163
|
let i = count - 1;
|
|
185
164
|
for (; i > 0; --i) {
|
|
@@ -189,54 +168,6 @@ export class FastTrieBlob {
|
|
|
189
168
|
}
|
|
190
169
|
return 0;
|
|
191
170
|
}
|
|
192
|
-
/** Search from nodeIdx for the node index representing the character. */
|
|
193
|
-
_searchNodeForChar(nodeIdx, char) {
|
|
194
|
-
const charIndexes = this.letterToNodeCharIndexSequence(char);
|
|
195
|
-
let idx = nodeIdx;
|
|
196
|
-
for (let i = 0; i < charIndexes.length; ++i) {
|
|
197
|
-
idx = this._lookupCharIndexNode(idx, charIndexes[i]);
|
|
198
|
-
if (!idx)
|
|
199
|
-
return 0;
|
|
200
|
-
}
|
|
201
|
-
return idx;
|
|
202
|
-
}
|
|
203
|
-
get charIndex() {
|
|
204
|
-
return [...this._charIndex];
|
|
205
|
-
}
|
|
206
|
-
static fromTrieBlob(trie) {
|
|
207
|
-
const bitMasksInfo = {
|
|
208
|
-
NodeMaskEOW: TrieBlob.NodeMaskEOW,
|
|
209
|
-
NodeMaskChildCharIndex: TrieBlob.NodeMaskChildCharIndex,
|
|
210
|
-
NodeChildRefShift: TrieBlob.NodeChildRefShift,
|
|
211
|
-
};
|
|
212
|
-
const trieNodesBin = TrieBlob.nodesView(trie);
|
|
213
|
-
const nodeOffsets = [];
|
|
214
|
-
for (let offset = 0; offset < trieNodesBin.length; offset += (trieNodesBin[offset] & TrieBlob.NodeMaskNumChildren) + 1) {
|
|
215
|
-
nodeOffsets.push(offset);
|
|
216
|
-
}
|
|
217
|
-
const offsetToNodeIndex = new Map(nodeOffsets.map((offset, i) => [offset, i]));
|
|
218
|
-
const nodes = new Array(nodeOffsets.length);
|
|
219
|
-
for (let i = 0; i < nodes.length; ++i) {
|
|
220
|
-
const offset = nodeOffsets[i];
|
|
221
|
-
const n = trieNodesBin[offset];
|
|
222
|
-
const eow = n & TrieBlob.NodeMaskEOW;
|
|
223
|
-
const count = n & TrieBlob.NodeMaskNumChildren;
|
|
224
|
-
const node = new Array(count + 1);
|
|
225
|
-
node[0] = eow;
|
|
226
|
-
nodes[i] = node;
|
|
227
|
-
for (let j = 1; j <= count; ++j) {
|
|
228
|
-
const n = trieNodesBin[offset + j];
|
|
229
|
-
const charIndex = n & TrieBlob.NodeMaskChildCharIndex;
|
|
230
|
-
const nodeIndex = n >>> TrieBlob.NodeChildRefShift;
|
|
231
|
-
const idx = offsetToNodeIndex.get(nodeIndex);
|
|
232
|
-
if (idx === undefined) {
|
|
233
|
-
throw new Error(`Invalid node index ${nodeIndex}`);
|
|
234
|
-
}
|
|
235
|
-
node[j] = (idx << TrieBlob.NodeChildRefShift) | charIndex;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
return new FastTrieBlob(nodes, trie.charIndex, bitMasksInfo, trie.info);
|
|
239
|
-
}
|
|
240
171
|
}
|
|
241
172
|
function createCharToIndexMap(charIndex) {
|
|
242
173
|
const map = Object.create(null);
|
|
@@ -247,16 +178,4 @@ function createCharToIndexMap(charIndex) {
|
|
|
247
178
|
}
|
|
248
179
|
return map;
|
|
249
180
|
}
|
|
250
|
-
function nodesToJson(nodes) {
|
|
251
|
-
function nodeElement(node, index) {
|
|
252
|
-
const eow = !!(node[0] & TrieBlob.NodeMaskEOW);
|
|
253
|
-
const children = node.slice(1).map((n) => ({
|
|
254
|
-
c: ('00' + (n & TrieBlob.NodeMaskChildCharIndex).toString(16)).slice(-2),
|
|
255
|
-
i: n >>> TrieBlob.NodeChildRefShift,
|
|
256
|
-
}));
|
|
257
|
-
return { id: index, eow, n: node.length, c: children };
|
|
258
|
-
}
|
|
259
|
-
const elements = nodes.map((n, i) => nodeElement(n, i));
|
|
260
|
-
return elements;
|
|
261
|
-
}
|
|
262
181
|
//# sourceMappingURL=FastTrieBlob.js.map
|
|
@@ -11,14 +11,11 @@ export declare class FastTrieBlobBuilder implements TrieBuilder<FastTrieBlob> {
|
|
|
11
11
|
private IdxEOW;
|
|
12
12
|
private _cursor;
|
|
13
13
|
private _options;
|
|
14
|
-
wordToCharacters: (word: string) => string[];
|
|
15
14
|
readonly bitMasksInfo: FastTrieBlobBitMaskInfo;
|
|
16
15
|
constructor(options?: PartialTrieInfo, bitMasksInfo?: FastTrieBlobBitMaskInfo);
|
|
17
16
|
setOptions(options: PartialTrieInfo): Readonly<TrieInfo>;
|
|
18
17
|
get options(): Readonly<TrieInfo>;
|
|
19
18
|
private getCharIndex;
|
|
20
|
-
private wordToNodeCharIndexSequence;
|
|
21
|
-
private letterToNodeCharIndexSequence;
|
|
22
19
|
insert(word: string | Iterable<string> | string[]): this;
|
|
23
20
|
getCursor(): BuilderCursor;
|
|
24
21
|
private createCursor;
|
|
@@ -27,7 +24,7 @@ export declare class FastTrieBlobBuilder implements TrieBuilder<FastTrieBlob> {
|
|
|
27
24
|
isReadonly(): boolean;
|
|
28
25
|
freeze(): this;
|
|
29
26
|
build(): FastTrieBlob;
|
|
30
|
-
static fromWordList(words:
|
|
27
|
+
static fromWordList(words: string[] | Iterable<string>, options?: PartialTrieInfo): FastTrieBlob;
|
|
31
28
|
static fromTrieRoot(root: TrieRoot): FastTrieBlob;
|
|
32
29
|
static NodeMaskEOW: number;
|
|
33
30
|
static NodeChildRefShift: number;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { assert } from '../utils/assert.js';
|
|
2
2
|
import { mergeOptionalWithDefaults } from '../utils/mergeOptionalWithDefaults.js';
|
|
3
|
-
import { assertValidUtf16Character } from '../utils/text.js';
|
|
4
3
|
import { FastTrieBlob } from './FastTrieBlob.js';
|
|
5
4
|
import { FastTrieBlobInternals } from './FastTrieBlobInternals.js';
|
|
6
5
|
import { resolveMap } from './resolveMap.js';
|
|
@@ -13,7 +12,6 @@ export class FastTrieBlobBuilder {
|
|
|
13
12
|
IdxEOW;
|
|
14
13
|
_cursor;
|
|
15
14
|
_options;
|
|
16
|
-
wordToCharacters = (word) => [...word];
|
|
17
15
|
bitMasksInfo;
|
|
18
16
|
constructor(options, bitMasksInfo = FastTrieBlobBuilder.DefaultBitMaskInfo) {
|
|
19
17
|
this._options = mergeOptionalWithDefaults(options);
|
|
@@ -39,12 +37,6 @@ export class FastTrieBlobBuilder {
|
|
|
39
37
|
this.charToIndexMap[charNFD] = idx;
|
|
40
38
|
return idx;
|
|
41
39
|
}
|
|
42
|
-
wordToNodeCharIndexSequence(word) {
|
|
43
|
-
return TrieBlob.charactersToCharIndexSequence(this.wordToCharacters(word), (c) => this.getCharIndex(c));
|
|
44
|
-
}
|
|
45
|
-
letterToNodeCharIndexSequence(letter) {
|
|
46
|
-
return TrieBlob.toCharIndexSequence(this.getCharIndex(letter));
|
|
47
|
-
}
|
|
48
40
|
insert(word) {
|
|
49
41
|
if (this.isReadonly()) {
|
|
50
42
|
throw new Error('FastTrieBlob is readonly');
|
|
@@ -84,43 +76,10 @@ export class FastTrieBlobBuilder {
|
|
|
84
76
|
const eow = 1;
|
|
85
77
|
const eowShifted = eow << NodeChildRefShift;
|
|
86
78
|
const nodes = this.nodes;
|
|
87
|
-
const stack = [{ nodeIdx: 0, pos: 0
|
|
79
|
+
const stack = [{ nodeIdx: 0, pos: 0 }];
|
|
88
80
|
let nodeIdx = 0;
|
|
89
81
|
let depth = 0;
|
|
90
82
|
const insertChar = (char) => {
|
|
91
|
-
const cc = char.charCodeAt(0) & 0xdc00;
|
|
92
|
-
// Work with partial surrogate pairs.
|
|
93
|
-
if (cc === 0xd800 && char.length == 1) {
|
|
94
|
-
// We have a high surrogate
|
|
95
|
-
const s = stack[depth];
|
|
96
|
-
const ns = stack[++depth];
|
|
97
|
-
if (ns) {
|
|
98
|
-
ns.nodeIdx = s.nodeIdx;
|
|
99
|
-
ns.pos = s.pos;
|
|
100
|
-
ns.dCount = 1;
|
|
101
|
-
ns.ps = char;
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
stack[depth] = { nodeIdx: s.nodeIdx, pos: s.pos, dCount: 1, ps: char };
|
|
105
|
-
}
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
if (stack[depth].ps) {
|
|
109
|
-
char = stack[depth].ps + char;
|
|
110
|
-
assertValidUtf16Character(char);
|
|
111
|
-
}
|
|
112
|
-
const indexSeq = this.letterToNodeCharIndexSequence(char);
|
|
113
|
-
for (let i = 0; i < indexSeq.length; ++i) {
|
|
114
|
-
insertCharIndexes(indexSeq[i], i + 1);
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
/**
|
|
118
|
-
* A single character can result in multiple nodes being created
|
|
119
|
-
* because it takes multiple bytes to represent a character.
|
|
120
|
-
* @param charIndex - partial character index.
|
|
121
|
-
* @param char - the source character
|
|
122
|
-
*/
|
|
123
|
-
const insertCharIndexes = (charIndex, dCount) => {
|
|
124
83
|
// console.warn('i %o at %o', char, nodeIdx);
|
|
125
84
|
if (nodes[nodeIdx] && Object.isFrozen(nodes[nodeIdx])) {
|
|
126
85
|
nodeIdx = nodes.push([...nodes[nodeIdx]]) - 1;
|
|
@@ -132,7 +91,7 @@ export class FastTrieBlobBuilder {
|
|
|
132
91
|
}
|
|
133
92
|
const node = nodes[nodeIdx] ?? [0];
|
|
134
93
|
nodes[nodeIdx] = node;
|
|
135
|
-
const letterIdx =
|
|
94
|
+
const letterIdx = this.getCharIndex(char);
|
|
136
95
|
const hasIdx = childPos(node, letterIdx);
|
|
137
96
|
const childIdx = hasIdx ? node[hasIdx] >>> NodeChildRefShift : nodes.length;
|
|
138
97
|
const pos = hasIdx || node.push((childIdx << NodeChildRefShift) | letterIdx) - 1;
|
|
@@ -141,11 +100,9 @@ export class FastTrieBlobBuilder {
|
|
|
141
100
|
if (s) {
|
|
142
101
|
s.nodeIdx = nodeIdx;
|
|
143
102
|
s.pos = pos;
|
|
144
|
-
s.dCount = dCount;
|
|
145
|
-
s.ps = '';
|
|
146
103
|
}
|
|
147
104
|
else {
|
|
148
|
-
stack[depth] = { nodeIdx, pos
|
|
105
|
+
stack[depth] = { nodeIdx, pos };
|
|
149
106
|
}
|
|
150
107
|
nodeIdx = childIdx;
|
|
151
108
|
};
|
|
@@ -184,9 +141,7 @@ export class FastTrieBlobBuilder {
|
|
|
184
141
|
return;
|
|
185
142
|
// console.warn('<< %o', num);
|
|
186
143
|
assert(num <= depth && num > 0);
|
|
187
|
-
|
|
188
|
-
depth -= stack[depth].dCount;
|
|
189
|
-
}
|
|
144
|
+
depth -= num;
|
|
190
145
|
nodeIdx = stack[depth + 1].nodeIdx;
|
|
191
146
|
};
|
|
192
147
|
const c = {
|
|
@@ -206,11 +161,10 @@ export class FastTrieBlobBuilder {
|
|
|
206
161
|
const NodeMaskEOW = this.bitMasksInfo.NodeMaskEOW;
|
|
207
162
|
const IdxEOW = this.IdxEOW;
|
|
208
163
|
const nodes = this.nodes;
|
|
209
|
-
const
|
|
210
|
-
const len = charIndexes.length;
|
|
164
|
+
const len = word.length;
|
|
211
165
|
let nodeIdx = 0;
|
|
212
166
|
for (let p = 0; p < len; ++p) {
|
|
213
|
-
const letterIdx =
|
|
167
|
+
const letterIdx = this.getCharIndex(word[p]);
|
|
214
168
|
const node = nodes[nodeIdx];
|
|
215
169
|
const count = node.length;
|
|
216
170
|
let i = count - 1;
|
|
@@ -243,12 +197,11 @@ export class FastTrieBlobBuilder {
|
|
|
243
197
|
const NodeChildRefShift = this.bitMasksInfo.NodeChildRefShift;
|
|
244
198
|
const NodeMaskEOW = this.bitMasksInfo.NodeMaskEOW;
|
|
245
199
|
const nodes = this.nodes;
|
|
246
|
-
const
|
|
247
|
-
const len = charIndexes.length;
|
|
200
|
+
const len = word.length;
|
|
248
201
|
let nodeIdx = 0;
|
|
249
202
|
let node = nodes[nodeIdx];
|
|
250
203
|
for (let p = 0; p < len; ++p, node = nodes[nodeIdx]) {
|
|
251
|
-
const letterIdx =
|
|
204
|
+
const letterIdx = this.charToIndexMap[word[p]];
|
|
252
205
|
const count = node.length;
|
|
253
206
|
let i = count - 1;
|
|
254
207
|
for (; i > 0; --i) {
|
|
@@ -281,7 +234,6 @@ export class FastTrieBlobBuilder {
|
|
|
281
234
|
static fromTrieRoot(root) {
|
|
282
235
|
const bitMasksInfo = FastTrieBlobBuilder.DefaultBitMaskInfo;
|
|
283
236
|
const NodeChildRefShift = bitMasksInfo.NodeChildRefShift;
|
|
284
|
-
const NodeCharIndexMask = bitMasksInfo.NodeMaskChildCharIndex;
|
|
285
237
|
const NodeMaskEOW = bitMasksInfo.NodeMaskEOW;
|
|
286
238
|
const tf = new FastTrieBlobBuilder(undefined, bitMasksInfo);
|
|
287
239
|
const IdxEOW = tf.IdxEOW;
|
|
@@ -301,37 +253,15 @@ export class FastTrieBlobBuilder {
|
|
|
301
253
|
if (!n.c)
|
|
302
254
|
return nodeIdx;
|
|
303
255
|
const children = Object.entries(n.c);
|
|
256
|
+
node.length = children.length + 1;
|
|
304
257
|
for (let p = 0; p < children.length; ++p) {
|
|
305
258
|
const [char, childNode] = children[p];
|
|
306
|
-
|
|
259
|
+
const letterIdx = tf.getCharIndex(char);
|
|
260
|
+
const childIdx = walk(childNode);
|
|
261
|
+
node[p + 1] = (childIdx << NodeChildRefShift) | letterIdx;
|
|
307
262
|
}
|
|
308
263
|
return nodeIdx;
|
|
309
264
|
}
|
|
310
|
-
function resolveChild(node, charIndex) {
|
|
311
|
-
let i = 1;
|
|
312
|
-
for (i = 1; i < node.length && (node[i] & NodeCharIndexMask) !== charIndex; ++i) {
|
|
313
|
-
// empty
|
|
314
|
-
}
|
|
315
|
-
return i;
|
|
316
|
-
}
|
|
317
|
-
function addCharToNode(node, char, n) {
|
|
318
|
-
const indexSeq = tf.letterToNodeCharIndexSequence(char);
|
|
319
|
-
for (const idx of indexSeq.slice(0, -1)) {
|
|
320
|
-
const pos = resolveChild(node, idx);
|
|
321
|
-
if (pos < node.length) {
|
|
322
|
-
node = tf.nodes[node[pos] >>> NodeChildRefShift];
|
|
323
|
-
}
|
|
324
|
-
else {
|
|
325
|
-
const next = [0];
|
|
326
|
-
const nodeIdx = tf.nodes.push(next) - 1;
|
|
327
|
-
node[pos] = (nodeIdx << NodeChildRefShift) | idx;
|
|
328
|
-
node = next;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
const letterIdx = indexSeq[indexSeq.length - 1];
|
|
332
|
-
const i = node.push(letterIdx) - 1;
|
|
333
|
-
node[i] = (walk(n) << NodeChildRefShift) | letterIdx;
|
|
334
|
-
}
|
|
335
265
|
walk(root);
|
|
336
266
|
return tf.build();
|
|
337
267
|
}
|
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
import type { ITrieNode, ITrieNodeId, ITrieNodeRoot } from '../ITrieNode/ITrieNode.js';
|
|
2
2
|
import type { TrieInfo } from '../ITrieNode/TrieInfo.js';
|
|
3
3
|
import type { FastTrieBlobInternals } from './FastTrieBlobInternals.js';
|
|
4
|
-
type Node = readonly number[];
|
|
5
|
-
type NodeIndex = number;
|
|
6
4
|
declare class FastTrieBlobINode implements ITrieNode {
|
|
7
5
|
readonly trie: FastTrieBlobInternals;
|
|
8
|
-
readonly nodeIdx:
|
|
6
|
+
readonly nodeIdx: number;
|
|
9
7
|
readonly id: number;
|
|
10
|
-
readonly
|
|
8
|
+
readonly size: number;
|
|
9
|
+
readonly node: number[];
|
|
11
10
|
readonly eow: boolean;
|
|
11
|
+
charToIdx: Record<string, number> | undefined;
|
|
12
12
|
private _keys;
|
|
13
|
-
|
|
14
|
-
private _size;
|
|
15
|
-
private _chained;
|
|
16
|
-
private _nodesEntries;
|
|
17
|
-
private _entries;
|
|
18
|
-
private _values;
|
|
19
|
-
protected charToIdx: Readonly<Record<string, NodeIndex>> | undefined;
|
|
20
|
-
constructor(trie: FastTrieBlobInternals, nodeIdx: NodeIndex);
|
|
21
|
-
/** get keys to children */
|
|
13
|
+
constructor(trie: FastTrieBlobInternals, nodeIdx: number);
|
|
22
14
|
keys(): readonly string[];
|
|
15
|
+
/** get keys to children */
|
|
16
|
+
private calcKeys;
|
|
23
17
|
values(): readonly ITrieNode[];
|
|
24
18
|
entries(): readonly (readonly [string, ITrieNode])[];
|
|
25
19
|
/** get child ITrieNode */
|
|
@@ -28,10 +22,6 @@ declare class FastTrieBlobINode implements ITrieNode {
|
|
|
28
22
|
hasChildren(): boolean;
|
|
29
23
|
child(keyIdx: number): ITrieNode;
|
|
30
24
|
getCharToIdxMap(): Record<string, number>;
|
|
31
|
-
private containsChainedIndexes;
|
|
32
|
-
private getNodesEntries;
|
|
33
|
-
private walkChainedIndexes;
|
|
34
|
-
get size(): number;
|
|
35
25
|
}
|
|
36
26
|
export declare class FastTrieBlobIRoot extends FastTrieBlobINode implements ITrieNodeRoot {
|
|
37
27
|
readonly info: Readonly<TrieInfo>;
|