Skip to content

Commit 80acfa9

Browse files
committed
make TenarySearchTree have generic key and value, implement for URI, touches on microsoft#93368
1 parent f502660 commit 80acfa9

10 files changed

Lines changed: 195 additions & 54 deletions

File tree

src/vs/base/common/map.ts

Lines changed: 120 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import { URI } from 'vs/base/common/uri';
77
import { CharCode } from 'vs/base/common/charCode';
8+
import { compareIgnoreCase } from 'vs/base/common/strings';
89

910
/**
1011
* @deprecated ES6: use `[...SetOrMap.values()]`
@@ -55,16 +56,16 @@ export function setToString<K>(set: Set<K>): string {
5556
return `Set(${set.size}) {${entries.join(', ')}}`;
5657
}
5758

58-
export interface IKeyIterator {
59-
reset(key: string): this;
59+
export interface IKeyIterator<K> {
60+
reset(key: K): this;
6061
next(): this;
6162

6263
hasNext(): boolean;
6364
cmp(a: string): number;
6465
value(): string;
6566
}
6667

67-
export class StringIterator implements IKeyIterator {
68+
export class StringIterator implements IKeyIterator<string> {
6869

6970
private _value: string = '';
7071
private _pos: number = 0;
@@ -95,7 +96,7 @@ export class StringIterator implements IKeyIterator {
9596
}
9697
}
9798

98-
export class PathIterator implements IKeyIterator {
99+
export class PathIterator implements IKeyIterator<string> {
99100

100101
private _value!: string;
101102
private _from!: number;
@@ -162,46 +163,129 @@ export class PathIterator implements IKeyIterator {
162163
}
163164
}
164165

165-
class TernarySearchTreeNode<E> {
166+
const enum UriIteratorState {
167+
Scheme = 1, Authority = 2, Path = 3, Query = 4, Fragment = 5
168+
}
169+
170+
export class UriIterator implements IKeyIterator<URI> {
171+
172+
private _pathIterator = new PathIterator(false);
173+
private _value!: URI;
174+
private _states: UriIteratorState[] = [];
175+
private _stateIdx: number = 0;
176+
177+
reset(key: URI): this {
178+
this._value = key;
179+
this._states = [];
180+
if (this._value.scheme) {
181+
this._states.push(UriIteratorState.Scheme);
182+
}
183+
if (this._value.authority) {
184+
this._states.push(UriIteratorState.Authority);
185+
}
186+
if (this._value.path) {
187+
this._states.push(UriIteratorState.Path);
188+
this._pathIterator.reset(key.path);
189+
}
190+
if (this._value.query) {
191+
this._states.push(UriIteratorState.Query);
192+
}
193+
if (this._value.fragment) {
194+
this._states.push(UriIteratorState.Fragment);
195+
}
196+
this._stateIdx = 0;
197+
return this;
198+
}
199+
200+
next(): this {
201+
if (this._states[this._stateIdx] === UriIteratorState.Path && this._pathIterator.hasNext()) {
202+
this._pathIterator.next();
203+
} else {
204+
this._stateIdx += 1;
205+
}
206+
return this;
207+
}
208+
209+
hasNext(): boolean {
210+
return (this._states[this._stateIdx] === UriIteratorState.Path && this._pathIterator.hasNext())
211+
|| this._stateIdx < this._states.length - 1;
212+
}
213+
214+
cmp(a: string): number {
215+
if (this._states[this._stateIdx] === UriIteratorState.Scheme) {
216+
return compareIgnoreCase(a, this._value.scheme);
217+
} else if (this._states[this._stateIdx] === UriIteratorState.Authority) {
218+
return compareIgnoreCase(a, this._value.authority);
219+
} else if (this._states[this._stateIdx] === UriIteratorState.Path) {
220+
return this._pathIterator.cmp(a);
221+
} else if (this._states[this._stateIdx] === UriIteratorState.Query) {
222+
return compareIgnoreCase(a, this._value.scheme);
223+
} else if (this._states[this._stateIdx] === UriIteratorState.Fragment) {
224+
return compareIgnoreCase(a, this._value.fragment);
225+
}
226+
throw new Error();
227+
}
228+
229+
value(): string {
230+
if (this._states[this._stateIdx] === UriIteratorState.Scheme) {
231+
return this._value.scheme;
232+
} else if (this._states[this._stateIdx] === UriIteratorState.Authority) {
233+
return this._value.authority;
234+
} else if (this._states[this._stateIdx] === UriIteratorState.Path) {
235+
return this._pathIterator.value();
236+
} else if (this._states[this._stateIdx] === UriIteratorState.Query) {
237+
return this._value.query;
238+
} else if (this._states[this._stateIdx] === UriIteratorState.Fragment) {
239+
return this._value.fragment;
240+
}
241+
throw new Error();
242+
}
243+
}
244+
245+
class TernarySearchTreeNode<K, V> {
166246
segment!: string;
167-
value: E | undefined;
168-
key!: string;
169-
left: TernarySearchTreeNode<E> | undefined;
170-
mid: TernarySearchTreeNode<E> | undefined;
171-
right: TernarySearchTreeNode<E> | undefined;
247+
value: V | undefined;
248+
key!: K;
249+
left: TernarySearchTreeNode<K, V> | undefined;
250+
mid: TernarySearchTreeNode<K, V> | undefined;
251+
right: TernarySearchTreeNode<K, V> | undefined;
172252

173253
isEmpty(): boolean {
174254
return !this.left && !this.mid && !this.right && !this.value;
175255
}
176256
}
177257

178-
export class TernarySearchTree<E> {
258+
export class TernarySearchTree<K, V> {
259+
260+
static forUris<E>(): TernarySearchTree<URI, E> {
261+
return new TernarySearchTree<URI, E>(new UriIterator());
262+
}
179263

180-
static forPaths<E>(): TernarySearchTree<E> {
181-
return new TernarySearchTree<E>(new PathIterator());
264+
static forPaths<E>(): TernarySearchTree<string, E> {
265+
return new TernarySearchTree<string, E>(new PathIterator());
182266
}
183267

184-
static forStrings<E>(): TernarySearchTree<E> {
185-
return new TernarySearchTree<E>(new StringIterator());
268+
static forStrings<E>(): TernarySearchTree<string, E> {
269+
return new TernarySearchTree<string, E>(new StringIterator());
186270
}
187271

188-
private _iter: IKeyIterator;
189-
private _root: TernarySearchTreeNode<E> | undefined;
272+
private _iter: IKeyIterator<K>;
273+
private _root: TernarySearchTreeNode<K, V> | undefined;
190274

191-
constructor(segments: IKeyIterator) {
275+
constructor(segments: IKeyIterator<K>) {
192276
this._iter = segments;
193277
}
194278

195279
clear(): void {
196280
this._root = undefined;
197281
}
198282

199-
set(key: string, element: E): E | undefined {
283+
set(key: K, element: V): V | undefined {
200284
const iter = this._iter.reset(key);
201-
let node: TernarySearchTreeNode<E>;
285+
let node: TernarySearchTreeNode<K, V>;
202286

203287
if (!this._root) {
204-
this._root = new TernarySearchTreeNode<E>();
288+
this._root = new TernarySearchTreeNode<K, V>();
205289
this._root.segment = iter.value();
206290
}
207291

@@ -211,15 +295,15 @@ export class TernarySearchTree<E> {
211295
if (val > 0) {
212296
// left
213297
if (!node.left) {
214-
node.left = new TernarySearchTreeNode<E>();
298+
node.left = new TernarySearchTreeNode<K, V>();
215299
node.left.segment = iter.value();
216300
}
217301
node = node.left;
218302

219303
} else if (val < 0) {
220304
// right
221305
if (!node.right) {
222-
node.right = new TernarySearchTreeNode<E>();
306+
node.right = new TernarySearchTreeNode<K, V>();
223307
node.right.segment = iter.value();
224308
}
225309
node = node.right;
@@ -228,7 +312,7 @@ export class TernarySearchTree<E> {
228312
// mid
229313
iter.next();
230314
if (!node.mid) {
231-
node.mid = new TernarySearchTreeNode<E>();
315+
node.mid = new TernarySearchTreeNode<K, V>();
232316
node.mid.segment = iter.value();
233317
}
234318
node = node.mid;
@@ -242,7 +326,7 @@ export class TernarySearchTree<E> {
242326
return oldElement;
243327
}
244328

245-
get(key: string): E | undefined {
329+
get(key: K): V | undefined {
246330
const iter = this._iter.reset(key);
247331
let node = this._root;
248332
while (node) {
@@ -264,10 +348,10 @@ export class TernarySearchTree<E> {
264348
return node ? node.value : undefined;
265349
}
266350

267-
delete(key: string): void {
351+
delete(key: K): void {
268352

269353
const iter = this._iter.reset(key);
270-
const stack: [-1 | 0 | 1, TernarySearchTreeNode<E>][] = [];
354+
const stack: [-1 | 0 | 1, TernarySearchTreeNode<K, V>][] = [];
271355
let node = this._root;
272356

273357
// find and unset node
@@ -305,10 +389,10 @@ export class TernarySearchTree<E> {
305389
}
306390
}
307391

308-
findSubstr(key: string): E | undefined {
392+
findSubstr(key: K): V | undefined {
309393
const iter = this._iter.reset(key);
310394
let node = this._root;
311-
let candidate: E | undefined = undefined;
395+
let candidate: V | undefined = undefined;
312396
while (node) {
313397
const val = iter.cmp(node.segment);
314398
if (val > 0) {
@@ -329,7 +413,7 @@ export class TernarySearchTree<E> {
329413
return node && node.value || candidate;
330414
}
331415

332-
findSuperstr(key: string): Iterator<E> | undefined {
416+
findSuperstr(key: K): Iterator<V> | undefined {
333417
const iter = this._iter.reset(key);
334418
let node = this._root;
335419
while (node) {
@@ -356,11 +440,11 @@ export class TernarySearchTree<E> {
356440
return undefined;
357441
}
358442

359-
private _nodeIterator(node: TernarySearchTreeNode<E>): Iterator<E> {
360-
let res: { done: false; value: E; };
443+
private _nodeIterator(node: TernarySearchTreeNode<K, V>): Iterator<V> {
444+
let res: { done: false; value: V; };
361445
let idx: number;
362-
let data: E[];
363-
const next = (): IteratorResult<E> => {
446+
let data: V[];
447+
const next = (): IteratorResult<V> => {
364448
if (!data) {
365449
// lazy till first invocation
366450
data = [];
@@ -381,11 +465,11 @@ export class TernarySearchTree<E> {
381465
return { next };
382466
}
383467

384-
forEach(callback: (value: E, index: string) => any) {
468+
forEach(callback: (value: V, index: K) => any) {
385469
this._forEach(this._root, callback);
386470
}
387471

388-
private _forEach(node: TernarySearchTreeNode<E> | undefined, callback: (value: E, index: string) => any) {
472+
private _forEach(node: TernarySearchTreeNode<K, V> | undefined, callback: (value: V, index: K) => any) {
389473
if (node) {
390474
// left
391475
this._forEach(node.left, callback);

src/vs/base/common/resources.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ export namespace DataUri {
336336
export class ResourceGlobMatcher {
337337

338338
private readonly globalExpression: ParsedExpression;
339-
private readonly expressionsByRoot: TernarySearchTree<{ root: URI, expression: ParsedExpression }> = TernarySearchTree.forPaths<{ root: URI, expression: ParsedExpression }>();
339+
private readonly expressionsByRoot: TernarySearchTree<string, { root: URI, expression: ParsedExpression }> = TernarySearchTree.forPaths<{ root: URI, expression: ParsedExpression }>();
340340

341341
constructor(
342342
globalExpression: IExpression,

src/vs/base/node/id.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { getMac } from 'vs/base/node/macAddress';
2121
// Sun xVM VirtualBox 08-00-27
2222
export const virtualMachineHint: { value(): number } = new class {
2323

24-
private _virtualMachineOUIs?: TernarySearchTree<boolean>;
24+
private _virtualMachineOUIs?: TernarySearchTree<string, boolean>;
2525
private _value?: number;
2626

2727
private _isVirtualMachineMacAdress(mac: string): boolean {

0 commit comments

Comments
 (0)