提交 80acfa92 编写于 作者: J Johannes Rieken

make TenarySearchTree have generic key and value, implement for URI, touches...

make TenarySearchTree have generic key and value, implement for URI, touches on https://github.com/microsoft/vscode/issues/93368
上级 f5026604
......@@ -5,6 +5,7 @@
import { URI } from 'vs/base/common/uri';
import { CharCode } from 'vs/base/common/charCode';
import { compareIgnoreCase } from 'vs/base/common/strings';
/**
* @deprecated ES6: use `[...SetOrMap.values()]`
......@@ -55,8 +56,8 @@ export function setToString<K>(set: Set<K>): string {
return `Set(${set.size}) {${entries.join(', ')}}`;
}
export interface IKeyIterator {
reset(key: string): this;
export interface IKeyIterator<K> {
reset(key: K): this;
next(): this;
hasNext(): boolean;
......@@ -64,7 +65,7 @@ export interface IKeyIterator {
value(): string;
}
export class StringIterator implements IKeyIterator {
export class StringIterator implements IKeyIterator<string> {
private _value: string = '';
private _pos: number = 0;
......@@ -95,7 +96,7 @@ export class StringIterator implements IKeyIterator {
}
}
export class PathIterator implements IKeyIterator {
export class PathIterator implements IKeyIterator<string> {
private _value!: string;
private _from!: number;
......@@ -162,33 +163,116 @@ export class PathIterator implements IKeyIterator {
}
}
class TernarySearchTreeNode<E> {
const enum UriIteratorState {
Scheme = 1, Authority = 2, Path = 3, Query = 4, Fragment = 5
}
export class UriIterator implements IKeyIterator<URI> {
private _pathIterator = new PathIterator(false);
private _value!: URI;
private _states: UriIteratorState[] = [];
private _stateIdx: number = 0;
reset(key: URI): this {
this._value = key;
this._states = [];
if (this._value.scheme) {
this._states.push(UriIteratorState.Scheme);
}
if (this._value.authority) {
this._states.push(UriIteratorState.Authority);
}
if (this._value.path) {
this._states.push(UriIteratorState.Path);
this._pathIterator.reset(key.path);
}
if (this._value.query) {
this._states.push(UriIteratorState.Query);
}
if (this._value.fragment) {
this._states.push(UriIteratorState.Fragment);
}
this._stateIdx = 0;
return this;
}
next(): this {
if (this._states[this._stateIdx] === UriIteratorState.Path && this._pathIterator.hasNext()) {
this._pathIterator.next();
} else {
this._stateIdx += 1;
}
return this;
}
hasNext(): boolean {
return (this._states[this._stateIdx] === UriIteratorState.Path && this._pathIterator.hasNext())
|| this._stateIdx < this._states.length - 1;
}
cmp(a: string): number {
if (this._states[this._stateIdx] === UriIteratorState.Scheme) {
return compareIgnoreCase(a, this._value.scheme);
} else if (this._states[this._stateIdx] === UriIteratorState.Authority) {
return compareIgnoreCase(a, this._value.authority);
} else if (this._states[this._stateIdx] === UriIteratorState.Path) {
return this._pathIterator.cmp(a);
} else if (this._states[this._stateIdx] === UriIteratorState.Query) {
return compareIgnoreCase(a, this._value.scheme);
} else if (this._states[this._stateIdx] === UriIteratorState.Fragment) {
return compareIgnoreCase(a, this._value.fragment);
}
throw new Error();
}
value(): string {
if (this._states[this._stateIdx] === UriIteratorState.Scheme) {
return this._value.scheme;
} else if (this._states[this._stateIdx] === UriIteratorState.Authority) {
return this._value.authority;
} else if (this._states[this._stateIdx] === UriIteratorState.Path) {
return this._pathIterator.value();
} else if (this._states[this._stateIdx] === UriIteratorState.Query) {
return this._value.query;
} else if (this._states[this._stateIdx] === UriIteratorState.Fragment) {
return this._value.fragment;
}
throw new Error();
}
}
class TernarySearchTreeNode<K, V> {
segment!: string;
value: E | undefined;
key!: string;
left: TernarySearchTreeNode<E> | undefined;
mid: TernarySearchTreeNode<E> | undefined;
right: TernarySearchTreeNode<E> | undefined;
value: V | undefined;
key!: K;
left: TernarySearchTreeNode<K, V> | undefined;
mid: TernarySearchTreeNode<K, V> | undefined;
right: TernarySearchTreeNode<K, V> | undefined;
isEmpty(): boolean {
return !this.left && !this.mid && !this.right && !this.value;
}
}
export class TernarySearchTree<E> {
export class TernarySearchTree<K, V> {
static forUris<E>(): TernarySearchTree<URI, E> {
return new TernarySearchTree<URI, E>(new UriIterator());
}
static forPaths<E>(): TernarySearchTree<E> {
return new TernarySearchTree<E>(new PathIterator());
static forPaths<E>(): TernarySearchTree<string, E> {
return new TernarySearchTree<string, E>(new PathIterator());
}
static forStrings<E>(): TernarySearchTree<E> {
return new TernarySearchTree<E>(new StringIterator());
static forStrings<E>(): TernarySearchTree<string, E> {
return new TernarySearchTree<string, E>(new StringIterator());
}
private _iter: IKeyIterator;
private _root: TernarySearchTreeNode<E> | undefined;
private _iter: IKeyIterator<K>;
private _root: TernarySearchTreeNode<K, V> | undefined;
constructor(segments: IKeyIterator) {
constructor(segments: IKeyIterator<K>) {
this._iter = segments;
}
......@@ -196,12 +280,12 @@ export class TernarySearchTree<E> {
this._root = undefined;
}
set(key: string, element: E): E | undefined {
set(key: K, element: V): V | undefined {
const iter = this._iter.reset(key);
let node: TernarySearchTreeNode<E>;
let node: TernarySearchTreeNode<K, V>;
if (!this._root) {
this._root = new TernarySearchTreeNode<E>();
this._root = new TernarySearchTreeNode<K, V>();
this._root.segment = iter.value();
}
......@@ -211,7 +295,7 @@ export class TernarySearchTree<E> {
if (val > 0) {
// left
if (!node.left) {
node.left = new TernarySearchTreeNode<E>();
node.left = new TernarySearchTreeNode<K, V>();
node.left.segment = iter.value();
}
node = node.left;
......@@ -219,7 +303,7 @@ export class TernarySearchTree<E> {
} else if (val < 0) {
// right
if (!node.right) {
node.right = new TernarySearchTreeNode<E>();
node.right = new TernarySearchTreeNode<K, V>();
node.right.segment = iter.value();
}
node = node.right;
......@@ -228,7 +312,7 @@ export class TernarySearchTree<E> {
// mid
iter.next();
if (!node.mid) {
node.mid = new TernarySearchTreeNode<E>();
node.mid = new TernarySearchTreeNode<K, V>();
node.mid.segment = iter.value();
}
node = node.mid;
......@@ -242,7 +326,7 @@ export class TernarySearchTree<E> {
return oldElement;
}
get(key: string): E | undefined {
get(key: K): V | undefined {
const iter = this._iter.reset(key);
let node = this._root;
while (node) {
......@@ -264,10 +348,10 @@ export class TernarySearchTree<E> {
return node ? node.value : undefined;
}
delete(key: string): void {
delete(key: K): void {
const iter = this._iter.reset(key);
const stack: [-1 | 0 | 1, TernarySearchTreeNode<E>][] = [];
const stack: [-1 | 0 | 1, TernarySearchTreeNode<K, V>][] = [];
let node = this._root;
// find and unset node
......@@ -305,10 +389,10 @@ export class TernarySearchTree<E> {
}
}
findSubstr(key: string): E | undefined {
findSubstr(key: K): V | undefined {
const iter = this._iter.reset(key);
let node = this._root;
let candidate: E | undefined = undefined;
let candidate: V | undefined = undefined;
while (node) {
const val = iter.cmp(node.segment);
if (val > 0) {
......@@ -329,7 +413,7 @@ export class TernarySearchTree<E> {
return node && node.value || candidate;
}
findSuperstr(key: string): Iterator<E> | undefined {
findSuperstr(key: K): Iterator<V> | undefined {
const iter = this._iter.reset(key);
let node = this._root;
while (node) {
......@@ -356,11 +440,11 @@ export class TernarySearchTree<E> {
return undefined;
}
private _nodeIterator(node: TernarySearchTreeNode<E>): Iterator<E> {
let res: { done: false; value: E; };
private _nodeIterator(node: TernarySearchTreeNode<K, V>): Iterator<V> {
let res: { done: false; value: V; };
let idx: number;
let data: E[];
const next = (): IteratorResult<E> => {
let data: V[];
const next = (): IteratorResult<V> => {
if (!data) {
// lazy till first invocation
data = [];
......@@ -381,11 +465,11 @@ export class TernarySearchTree<E> {
return { next };
}
forEach(callback: (value: E, index: string) => any) {
forEach(callback: (value: V, index: K) => any) {
this._forEach(this._root, callback);
}
private _forEach(node: TernarySearchTreeNode<E> | undefined, callback: (value: E, index: string) => any) {
private _forEach(node: TernarySearchTreeNode<K, V> | undefined, callback: (value: V, index: K) => any) {
if (node) {
// left
this._forEach(node.left, callback);
......
......@@ -336,7 +336,7 @@ export namespace DataUri {
export class ResourceGlobMatcher {
private readonly globalExpression: ParsedExpression;
private readonly expressionsByRoot: TernarySearchTree<{ root: URI, expression: ParsedExpression }> = TernarySearchTree.forPaths<{ root: URI, expression: ParsedExpression }>();
private readonly expressionsByRoot: TernarySearchTree<string, { root: URI, expression: ParsedExpression }> = TernarySearchTree.forPaths<{ root: URI, expression: ParsedExpression }>();
constructor(
globalExpression: IExpression,
......
......@@ -21,7 +21,7 @@ import { getMac } from 'vs/base/node/macAddress';
// Sun xVM VirtualBox 08-00-27
export const virtualMachineHint: { value(): number } = new class {
private _virtualMachineOUIs?: TernarySearchTree<boolean>;
private _virtualMachineOUIs?: TernarySearchTree<string, boolean>;
private _value?: number;
private _isVirtualMachineMacAdress(mac: string): boolean {
......
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ResourceMap, TernarySearchTree, PathIterator, StringIterator, LinkedMap, Touch, LRUCache } from 'vs/base/common/map';
import { ResourceMap, TernarySearchTree, PathIterator, StringIterator, LinkedMap, Touch, LRUCache, UriIterator } from 'vs/base/common/map';
import * as assert from 'assert';
import { URI } from 'vs/base/common/uri';
......@@ -312,7 +312,64 @@ suite('Map', () => {
assert.equal(iter.hasNext(), false);
});
function assertTernarySearchTree<E>(trie: TernarySearchTree<E>, ...elements: [string, E][]) {
test('URIIterator', function () {
const iter = new UriIterator();
iter.reset(URI.parse('file:///usr/bin/file.txt'));
assert.equal(iter.value(), 'file');
assert.equal(iter.cmp('FILE'), 0);
assert.equal(iter.hasNext(), true);
iter.next();
assert.equal(iter.value(), 'usr');
assert.equal(iter.hasNext(), true);
iter.next();
assert.equal(iter.value(), 'bin');
assert.equal(iter.hasNext(), true);
iter.next();
assert.equal(iter.value(), 'file.txt');
assert.equal(iter.hasNext(), false);
iter.reset(URI.parse('file://share/usr/bin/file.txt?foo'));
// scheme
assert.equal(iter.value(), 'file');
assert.equal(iter.cmp('FILE'), 0);
assert.equal(iter.hasNext(), true);
iter.next();
// authority
assert.equal(iter.value(), 'share');
assert.equal(iter.cmp('SHARe'), 0);
assert.equal(iter.hasNext(), true);
iter.next();
// path
assert.equal(iter.value(), 'usr');
assert.equal(iter.hasNext(), true);
iter.next();
// path
assert.equal(iter.value(), 'bin');
assert.equal(iter.hasNext(), true);
iter.next();
// path
assert.equal(iter.value(), 'file.txt');
assert.equal(iter.hasNext(), true);
iter.next();
// query
assert.equal(iter.value(), 'foo');
assert.equal(iter.cmp('z') > 0, true);
assert.equal(iter.cmp('a') < 0, true);
assert.equal(iter.hasNext(), false);
});
function assertTernarySearchTree<E>(trie: TernarySearchTree<string, E>, ...elements: [string, E][]) {
const map = new Map<string, E>();
for (const [key, value] of elements) {
map.set(key, value);
......@@ -378,7 +435,7 @@ suite('Map', () => {
});
test('TernarySearchTree - basics', function () {
let trie = new TernarySearchTree<number>(new StringIterator());
let trie = new TernarySearchTree<string, number>(new StringIterator());
trie.set('foo', 1);
trie.set('bar', 2);
......@@ -408,7 +465,7 @@ suite('Map', () => {
});
test('TernarySearchTree - delete & cleanup', function () {
let trie = new TernarySearchTree<number>(new StringIterator());
let trie = new TernarySearchTree<string, number>(new StringIterator());
trie.set('foo', 1);
trie.set('foobar', 2);
trie.set('bar', 3);
......@@ -418,7 +475,7 @@ suite('Map', () => {
});
test('TernarySearchTree (PathSegments) - basics', function () {
let trie = new TernarySearchTree<number>(new PathIterator());
let trie = new TernarySearchTree<string, number>(new PathIterator());
trie.set('/user/foo/bar', 1);
trie.set('/user/foo', 2);
......@@ -442,7 +499,7 @@ suite('Map', () => {
test('TernarySearchTree (PathSegments) - lookup', function () {
const map = new TernarySearchTree<number>(new PathIterator());
const map = new TernarySearchTree<string, number>(new PathIterator());
map.set('/user/foo/bar', 1);
map.set('/user/foo', 2);
map.set('/user/foo/flip/flop', 3);
......@@ -456,7 +513,7 @@ suite('Map', () => {
test('TernarySearchTree (PathSegments) - superstr', function () {
const map = new TernarySearchTree<number>(new PathIterator());
const map = new TernarySearchTree<string, number>(new PathIterator());
map.set('/user/foo/bar', 1);
map.set('/user/foo', 2);
map.set('/user/foo/flip/flop', 3);
......
......@@ -18,7 +18,7 @@ export class TestConfigurationService implements IConfigurationService {
this.configuration = configuration || Object.create(null);
}
private configurationByRoot: TernarySearchTree<any> = TernarySearchTree.forPaths<any>();
private configurationByRoot: TernarySearchTree<string, any> = TernarySearchTree.forPaths<any>();
public reloadConfiguration<T>(): Promise<T> {
return Promise.resolve(this.getValue());
......
......@@ -182,7 +182,7 @@ export class FileService extends Disposable implements IFileService {
const stat = await provider.stat(resource);
let trie: TernarySearchTree<boolean> | undefined;
let trie: TernarySearchTree<string, boolean> | undefined;
return this.toFileStat(provider, resource, stat, undefined, !!resolveMetadata, (stat, siblings) => {
......
......@@ -144,7 +144,7 @@ export interface IWorkspaceFolder extends IWorkspaceFolderData {
export class Workspace implements IWorkspace {
private _foldersMap: TernarySearchTree<WorkspaceFolder> = TernarySearchTree.forPaths<WorkspaceFolder>();
private _foldersMap: TernarySearchTree<string, WorkspaceFolder> = TernarySearchTree.forPaths<WorkspaceFolder>();
private _folders!: WorkspaceFolder[];
constructor(
......
......@@ -90,7 +90,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
private readonly _storage: ExtHostStorage;
private readonly _storagePath: IExtensionStoragePaths;
private readonly _activator: ExtensionsActivator;
private _extensionPathIndex: Promise<TernarySearchTree<IExtensionDescription>> | null;
private _extensionPathIndex: Promise<TernarySearchTree<string, IExtensionDescription>> | null;
private readonly _resolvers: { [authorityPrefix: string]: vscode.RemoteAuthorityResolver; };
......@@ -236,7 +236,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
}
// create trie to enable fast 'filename -> extension id' look up
public getExtensionPathIndex(): Promise<TernarySearchTree<IExtensionDescription>> {
public getExtensionPathIndex(): Promise<TernarySearchTree<string, IExtensionDescription>> {
if (!this._extensionPathIndex) {
const tree = TernarySearchTree.forPaths<IExtensionDescription>();
const extensions = this._registry.getAllExtensionDescriptions().map(ext => {
......@@ -792,6 +792,6 @@ export interface IExtHostExtensionService extends AbstractExtHostExtensionServic
deactivateAll(): Promise<void>;
getExtensionExports(extensionId: ExtensionIdentifier): IExtensionAPI | null | undefined;
getExtensionRegistry(): Promise<ExtensionDescriptionRegistry>;
getExtensionPathIndex(): Promise<TernarySearchTree<IExtensionDescription>>;
getExtensionPathIndex(): Promise<TernarySearchTree<string, IExtensionDescription>>;
registerRemoteAuthorityResolver(authorityPrefix: string, resolver: vscode.RemoteAuthorityResolver): vscode.Disposable;
}
......@@ -91,7 +91,7 @@ class VSCodeNodeModuleFactory implements INodeModuleFactory {
constructor(
private readonly _apiFactory: IExtensionApiFactory,
private readonly _extensionPaths: TernarySearchTree<IExtensionDescription>,
private readonly _extensionPaths: TernarySearchTree<string, IExtensionDescription>,
private readonly _extensionRegistry: ExtensionDescriptionRegistry,
private readonly _configProvider: ExtHostConfigProvider,
private readonly _logService: ILogService,
......@@ -230,7 +230,7 @@ class OpenNodeModuleFactory implements INodeModuleFactory {
private _mainThreadTelemetry: MainThreadTelemetryShape;
constructor(
private readonly _extensionPaths: TernarySearchTree<IExtensionDescription>,
private readonly _extensionPaths: TernarySearchTree<string, IExtensionDescription>,
private readonly _appUriScheme: string,
@IExtHostRpcService rpcService: IExtHostRpcService,
) {
......
......@@ -696,7 +696,7 @@ export class SearchResult extends Disposable {
private _folderMatches: FolderMatchWithResource[] = [];
private _otherFilesMatch: FolderMatch | null = null;
private _folderMatchesMap: TernarySearchTree<FolderMatchWithResource> = TernarySearchTree.forPaths<FolderMatchWithResource>();
private _folderMatchesMap: TernarySearchTree<string, FolderMatchWithResource> = TernarySearchTree.forPaths<FolderMatchWithResource>();
private _showHighlights: boolean = false;
private _query: ITextQuery | null = null;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册