1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | Object.defineProperty(exports, "__esModule", { value: true });
|
22 | exports.TernarySearchTree = exports.UriIterator = exports.PathIterator = void 0;
|
23 | const strings_1 = require("./strings");
|
24 | class PathIterator {
|
25 | constructor(_splitOnBackslash = true, _caseSensitive = true) {
|
26 | this._splitOnBackslash = _splitOnBackslash;
|
27 | this._caseSensitive = _caseSensitive;
|
28 | }
|
29 | reset(key) {
|
30 | this._value = key.replace(/\\$|\/$/, '');
|
31 | this._from = 0;
|
32 | this._to = 0;
|
33 | return this.next();
|
34 | }
|
35 | hasNext() {
|
36 | return this._to < this._value.length;
|
37 | }
|
38 | next() {
|
39 |
|
40 | this._from = this._to;
|
41 | let justSeps = true;
|
42 | for (; this._to < this._value.length; this._to++) {
|
43 | const ch = this._value.charCodeAt(this._to);
|
44 | if (ch === 47 || this._splitOnBackslash && ch === 92 ) {
|
45 | if (justSeps) {
|
46 | this._from++;
|
47 | }
|
48 | else {
|
49 | break;
|
50 | }
|
51 | }
|
52 | else {
|
53 | justSeps = false;
|
54 | }
|
55 | }
|
56 | return this;
|
57 | }
|
58 | cmp(a) {
|
59 | return this._caseSensitive
|
60 | ? (0, strings_1.compareSubstring)(a, this._value, 0, a.length, this._from, this._to)
|
61 | : (0, strings_1.compareSubstringIgnoreCase)(a, this._value, 0, a.length, this._from, this._to);
|
62 | }
|
63 | value() {
|
64 | return this._value.substring(this._from, this._to);
|
65 | }
|
66 | }
|
67 | exports.PathIterator = PathIterator;
|
68 | class UriIterator {
|
69 | constructor(caseSensitive) {
|
70 | this.caseSensitive = caseSensitive;
|
71 | this._states = [];
|
72 | this._stateIdx = 0;
|
73 | }
|
74 | reset(key) {
|
75 | this._value = key;
|
76 | this._states = [];
|
77 | if (this._value.scheme) {
|
78 | this._states.push(1 );
|
79 | }
|
80 | if (this._value.authority) {
|
81 | this._states.push(2 );
|
82 | }
|
83 | if (this._value.path) {
|
84 | this._pathIterator = new PathIterator(false, this.caseSensitive);
|
85 | this._pathIterator.reset(key.path.toString());
|
86 | if (this._pathIterator.value()) {
|
87 | this._states.push(3 );
|
88 | }
|
89 | }
|
90 | if (this._value.query) {
|
91 | this._states.push(4 );
|
92 | }
|
93 | if (this._value.fragment) {
|
94 | this._states.push(5 );
|
95 | }
|
96 | this._stateIdx = 0;
|
97 | return this;
|
98 | }
|
99 | next() {
|
100 | if (this._states[this._stateIdx] === 3 && this._pathIterator.hasNext()) {
|
101 | this._pathIterator.next();
|
102 | }
|
103 | else {
|
104 | this._stateIdx += 1;
|
105 | }
|
106 | return this;
|
107 | }
|
108 | hasNext() {
|
109 | return (this._states[this._stateIdx] === 3 && this._pathIterator.hasNext())
|
110 | || this._stateIdx < this._states.length - 1;
|
111 | }
|
112 | cmp(a) {
|
113 | if (this._states[this._stateIdx] === 1 ) {
|
114 | return (0, strings_1.compareSubstringIgnoreCase)(a, this._value.scheme);
|
115 | }
|
116 | else if (this._states[this._stateIdx] === 2 ) {
|
117 | return (0, strings_1.compareSubstringIgnoreCase)(a, this._value.authority);
|
118 | }
|
119 | else if (this._states[this._stateIdx] === 3 ) {
|
120 | return this._pathIterator.cmp(a);
|
121 | }
|
122 | else if (this._states[this._stateIdx] === 4 ) {
|
123 | return (0, strings_1.compare)(a, this._value.query);
|
124 | }
|
125 | else if (this._states[this._stateIdx] === 5 ) {
|
126 | return (0, strings_1.compare)(a, this._value.fragment);
|
127 | }
|
128 | throw new Error();
|
129 | }
|
130 | value() {
|
131 | if (this._states[this._stateIdx] === 1 ) {
|
132 | return this._value.scheme;
|
133 | }
|
134 | else if (this._states[this._stateIdx] === 2 ) {
|
135 | return this._value.authority;
|
136 | }
|
137 | else if (this._states[this._stateIdx] === 3 ) {
|
138 | return this._pathIterator.value();
|
139 | }
|
140 | else if (this._states[this._stateIdx] === 4 ) {
|
141 | return this._value.query;
|
142 | }
|
143 | else if (this._states[this._stateIdx] === 5 ) {
|
144 | return this._value.fragment;
|
145 | }
|
146 | throw new Error();
|
147 | }
|
148 | }
|
149 | exports.UriIterator = UriIterator;
|
150 | class TernarySearchTreeNode {
|
151 | isEmpty() {
|
152 | return !this.left && !this.mid && !this.right && !this.value;
|
153 | }
|
154 | }
|
155 | class TernarySearchTree {
|
156 | constructor(segments) {
|
157 | this._iter = segments;
|
158 | }
|
159 | static forUris(caseSensitive) {
|
160 | return new TernarySearchTree(new UriIterator(caseSensitive));
|
161 | }
|
162 | static forPaths() {
|
163 | return new TernarySearchTree(new PathIterator());
|
164 | }
|
165 | clear() {
|
166 | this._root = undefined;
|
167 | }
|
168 | set(key, element) {
|
169 | const iter = this._iter.reset(key);
|
170 | let node;
|
171 | if (!this._root) {
|
172 | this._root = new TernarySearchTreeNode();
|
173 | this._root.segment = iter.value();
|
174 | }
|
175 | node = this._root;
|
176 | while (true) {
|
177 | const val = iter.cmp(node.segment);
|
178 | if (val > 0) {
|
179 |
|
180 | if (!node.left) {
|
181 | node.left = new TernarySearchTreeNode();
|
182 | node.left.segment = iter.value();
|
183 | }
|
184 | node = node.left;
|
185 | }
|
186 | else if (val < 0) {
|
187 |
|
188 | if (!node.right) {
|
189 | node.right = new TernarySearchTreeNode();
|
190 | node.right.segment = iter.value();
|
191 | }
|
192 | node = node.right;
|
193 | }
|
194 | else if (iter.hasNext()) {
|
195 |
|
196 | iter.next();
|
197 | if (!node.mid) {
|
198 | node.mid = new TernarySearchTreeNode();
|
199 | node.mid.segment = iter.value();
|
200 | }
|
201 | node = node.mid;
|
202 | }
|
203 | else {
|
204 | break;
|
205 | }
|
206 | }
|
207 | const oldElement = node.value;
|
208 | node.value = element;
|
209 | node.key = key;
|
210 | return oldElement;
|
211 | }
|
212 | get(key) {
|
213 | const iter = this._iter.reset(key);
|
214 | let node = this._root;
|
215 | while (node) {
|
216 | const val = iter.cmp(node.segment);
|
217 | if (val > 0) {
|
218 |
|
219 | node = node.left;
|
220 | }
|
221 | else if (val < 0) {
|
222 |
|
223 | node = node.right;
|
224 | }
|
225 | else if (iter.hasNext()) {
|
226 |
|
227 | iter.next();
|
228 | node = node.mid;
|
229 | }
|
230 | else {
|
231 | break;
|
232 | }
|
233 | }
|
234 | return node ? node.value : undefined;
|
235 | }
|
236 | delete(key) {
|
237 | const iter = this._iter.reset(key);
|
238 | const stack = [];
|
239 | let node = this._root;
|
240 |
|
241 | while (node) {
|
242 | const val = iter.cmp(node.segment);
|
243 | if (val > 0) {
|
244 |
|
245 | stack.push([1, node]);
|
246 | node = node.left;
|
247 | }
|
248 | else if (val < 0) {
|
249 |
|
250 | stack.push([-1, node]);
|
251 | node = node.right;
|
252 | }
|
253 | else if (iter.hasNext()) {
|
254 |
|
255 | iter.next();
|
256 | stack.push([0, node]);
|
257 | node = node.mid;
|
258 | }
|
259 | else {
|
260 |
|
261 | node.value = undefined;
|
262 |
|
263 | while (stack.length > 0 && node.isEmpty()) {
|
264 | const [dir, parent] = stack.pop();
|
265 | switch (dir) {
|
266 | case 1:
|
267 | parent.left = undefined;
|
268 | break;
|
269 | case 0:
|
270 | parent.mid = undefined;
|
271 | break;
|
272 | case -1:
|
273 | parent.right = undefined;
|
274 | break;
|
275 | }
|
276 | node = parent;
|
277 | }
|
278 | break;
|
279 | }
|
280 | }
|
281 | }
|
282 | findSubstr(key) {
|
283 | const iter = this._iter.reset(key);
|
284 | let node = this._root;
|
285 | let candidate = undefined;
|
286 | while (node) {
|
287 | const val = iter.cmp(node.segment);
|
288 | if (val > 0) {
|
289 |
|
290 | node = node.left;
|
291 | }
|
292 | else if (val < 0) {
|
293 |
|
294 | node = node.right;
|
295 | }
|
296 | else if (iter.hasNext()) {
|
297 |
|
298 | iter.next();
|
299 | candidate = node.value || candidate;
|
300 | node = node.mid;
|
301 | }
|
302 | else {
|
303 | break;
|
304 | }
|
305 | }
|
306 | return node && node.value || candidate;
|
307 | }
|
308 | findSuperstr(key) {
|
309 | const iter = this._iter.reset(key);
|
310 | let node = this._root;
|
311 | while (node) {
|
312 | const val = iter.cmp(node.segment);
|
313 | if (val > 0) {
|
314 |
|
315 | node = node.left;
|
316 | }
|
317 | else if (val < 0) {
|
318 |
|
319 | node = node.right;
|
320 | }
|
321 | else if (iter.hasNext()) {
|
322 |
|
323 | iter.next();
|
324 | node = node.mid;
|
325 | }
|
326 | else {
|
327 |
|
328 | if (!node.mid) {
|
329 | return undefined;
|
330 | }
|
331 | else {
|
332 | return this._nodeIterator(node.mid);
|
333 | }
|
334 | }
|
335 | }
|
336 | return undefined;
|
337 | }
|
338 | _nodeIterator(node) {
|
339 | let res;
|
340 | let idx;
|
341 | let data;
|
342 | const next = () => {
|
343 | if (!data) {
|
344 |
|
345 | data = [];
|
346 | idx = 0;
|
347 | this._forEach(node, value => data.push(value));
|
348 | }
|
349 | if (idx >= data.length) {
|
350 | return { done: true, value: undefined };
|
351 | }
|
352 | if (!res) {
|
353 | res = { done: false, value: data[idx++] };
|
354 | }
|
355 | else {
|
356 | res.value = data[idx++];
|
357 | }
|
358 | return res;
|
359 | };
|
360 | return { next };
|
361 | }
|
362 | forEach(callback) {
|
363 | this._forEach(this._root, callback);
|
364 | }
|
365 | _forEach(node, callback) {
|
366 | if (node) {
|
367 |
|
368 | this._forEach(node.left, callback);
|
369 |
|
370 | if (node.value) {
|
371 |
|
372 | callback(node.value, node.key);
|
373 | }
|
374 |
|
375 | this._forEach(node.mid, callback);
|
376 |
|
377 | this._forEach(node.right, callback);
|
378 | }
|
379 | }
|
380 | }
|
381 | exports.TernarySearchTree = TernarySearchTree;
|
382 |
|
\ | No newline at end of file |