提交 51d37696 编写于 作者: J Joao Moreno

tree: cleanup

上级 0b6cfd53
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
interface TrieNode<K, T> {
value: T;
children: Map<K, TrieNode<K, T>>;
}
/**
* Do not use with undefined values!
*/
export class Trie<K, V> {
private root: TrieNode<K, V>;
constructor() {
this.clear();
}
set(path: K[], element: V): void {
if (path.length === 0) {
throw new Error('Invalid path length');
}
let node = this.root;
for (const key of path) {
let child = node.children.get(key);
if (!child) {
child = { value: undefined, children: new Map<K, TrieNode<K, V>>() };
node.children.set(key, child);
}
node = child;
}
node.value = element;
}
get(path: K[]): V | undefined {
if (path.length === 0) {
throw new Error('Invalid path length');
}
let node = this.root;
for (const key of path) {
let child = node.children.get(key);
if (!child) {
return undefined;
}
node = child;
}
return node.value;
}
delete(path: K[], recursive: boolean = false): V {
if (path.length === 0) {
throw new Error('Invalid path length');
}
let nodePath: { key: K, node: TrieNode<K, V> }[] = [];
let node = this.root;
for (const key of path) {
let child = node.children.get(key);
if (!child) {
return undefined;
}
nodePath.push({ key, node });
node = child;
}
const value = node.value;
node.value = undefined;
if (node.children && !recursive) {
return value;
}
for (let i = nodePath.length - 1; i >= 0; i--) {
const { key, node } = nodePath[i];
node.children.delete(key);
if (Object.keys(node.children).length > 0) {
break;
}
}
return value;
}
clear(): void {
this.root = { value: undefined, children: new Map<K, TrieNode<K, V>>() };
}
}
\ No newline at end of file
......@@ -9,12 +9,6 @@ import { ISpliceable } from 'vs/base/common/sequence';
import { IIterator, map, collect, iter, empty } from 'vs/base/common/iterator';
import { last } from 'vs/base/common/arrays';
/**
* TODO:
* remove trie
* remove tree
*/
export interface ITreeElement<T> {
readonly element: T;
readonly children: IIterator<ITreeElement<T>>;
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { tail2, last } from 'vs/base/common/arrays';
import { IIterator, map, iter, collect } from 'vs/base/common/iterator';
export interface ITreeElement<T> {
readonly element: T;
readonly children: IIterator<ITreeElement<T>>;
}
export interface ITreeNode<T> {
readonly element: T;
readonly children: ITreeNode<T>[];
}
function asNode<T>(element: ITreeElement<T>): ITreeNode<T> {
return {
element: element.element,
children: collect(map(element.children, asNode))
};
}
function asElement<T>(element: ITreeNode<T>): ITreeElement<T> {
return {
element: element.element,
children: map(iter(element.children), asElement)
};
}
export class Tree<T> {
private root: ITreeNode<T> = { element: undefined, children: [] };
splice(start: number[], deleteCount: number, elements: IIterator<ITreeElement<T>>): IIterator<ITreeElement<T>> {
if (start.length === 0) {
throw new Error('Invalid tree location');
}
const [rest, index] = tail2(start);
const parentPath = this.getNodePath(rest);
const parent = last(parentPath);
const nodes = collect(map(elements, asNode));
const deletedNodes = parent.children.splice(index, deleteCount, ...nodes);
return map(iter(deletedNodes), asElement);
}
getElement(location: number[]): T {
if (location.length === 0) {
throw new Error('Invalid tree location');
}
const nodePath = this.getNodePath(location);
const node = last(nodePath);
return node.element;
}
getElementPath(location: number[]): T[] {
if (location.length === 0) {
throw new Error('Invalid tree location');
}
const [, ...nodePath] = this.getNodePath(location);
return nodePath.map(node => node.element);
}
getElementRange(location: number[], length: number): [T[], IIterator<ITreeElement<T>>] {
if (location.length === 0) {
throw new Error('Invalid tree location');
}
const [parentLocation, index] = tail2(location);
const parentPath = this.getNodePath(parentLocation);
const parent = last(parentPath);
return [
parentPath.slice(1).map(node => node.element),
map(iter(parent.children, index, length), asElement)
];
}
getNodes(): ITreeNode<T>[] {
return this.root.children;
}
private getNodePath(location: number[], node: ITreeNode<T> = this.root): ITreeNode<T>[] {
if (location.length === 0) {
return [node];
}
let [index, ...rest] = location;
if (index < 0 || index >= node.children.length) {
throw new Error('Invalid location');
}
const child = node.children[index];
return [node, ...this.getNodePath(rest, child)];
}
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { Trie } from 'vs/base/browser/ui/list/trie';
suite('Trie', function () {
test('simple test', () => {
const trie = new Trie<number, string>();
trie.set([0, 0, 0], 'hello');
assert.equal(trie.get([0]), undefined);
assert.equal(trie.get([0, 0]), undefined);
assert.equal(trie.get([0, 0, 0]), 'hello');
assert.equal(trie.get([1, 0, 0]), undefined);
assert.equal(trie.get([0, 1, 0]), undefined);
assert.equal(trie.get([0, 0, 1]), undefined);
assert.equal(trie.get([0, 0, 0, 0]), undefined);
});
test('clear', () => {
const trie = new Trie<number, string>();
trie.set([0, 0, 0], 'hello');
assert.equal(trie.get([0, 0, 0]), 'hello');
trie.clear();
assert.equal(trie.get([0, 0, 0]), undefined);
});
test('delete', () => {
const trie = new Trie<number, string>();
trie.set([1, 2, 3], 'hello');
assert.equal(trie.get([1, 2, 3]), 'hello');
trie.delete([1, 2, 3]);
assert.equal(trie.get([1, 2, 3]), undefined);
});
test('recursive delete', () => {
const trie = new Trie<number, string>();
trie.set([1], 'hello');
trie.set([1, 2, 3], 'world');
assert.equal(trie.get([1]), 'hello');
assert.equal(trie.get([1, 2, 3]), 'world');
trie.delete([1], true);
assert.equal(trie.get([1]), undefined);
assert.equal(trie.get([1, 2, 3]), undefined);
});
test('non-recursive delete', () => {
const trie = new Trie<number, string>();
trie.set([1], 'hello');
trie.set([1, 2, 3], 'world');
assert.equal(trie.get([1]), 'hello');
assert.equal(trie.get([1, 2, 3]), 'world');
trie.delete([1], false);
assert.equal(trie.get([1]), undefined);
assert.equal(trie.get([1, 2, 3]), 'world');
});
test('map tests', () => {
const trie = new Trie<number, string>();
trie.set([0, 0, 0], 'hello');
assert.equal(trie.get([0, 0, 0]), 'hello');
trie.set([0, 0], 'world');
assert.equal(trie.get([0, 0]), 'world');
trie.set([0, 0, 1], 'cool');
assert.equal(trie.get([0, 0, 1]), 'cool');
});
});
\ No newline at end of file
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { ITreeListElement, TreeModel } from 'vs/base/browser/ui/list/treeModel';
import { ITreeListElement, TreeModel } from 'vs/base/browser/ui/tree/treeModel';
import { ISpliceable } from 'vs/base/browser/ui/list/splice';
import { iter } from 'vs/base/common/iterator';
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { Tree } from 'vs/base/common/tree';
import { iter } from 'vs/base/common/iterator';
suite('Base Tree', () => {
test('ctor', () => {
const tree = new Tree<number>();
assert(tree);
const nodes = tree.getNodes();
assert.equal(nodes.length, 0);
});
test('insert', () => {
const tree = new Tree<number>();
tree.splice([0], 0, iter([
{ element: 0, children: iter([]) },
{ element: 1, children: iter([]) },
{ element: 2, children: iter([]) }
]));
const nodes = tree.getNodes();
assert.deepEqual(nodes.length, 3);
assert.deepEqual(nodes[0].element, 0);
assert.deepEqual(nodes[1].element, 1);
assert.deepEqual(nodes[2].element, 2);
});
test('deep insert', () => {
const tree = new Tree<number>();
tree.splice([0], 0, iter([
{
element: 0, children: iter([
{ element: 10, children: iter([]) },
{ element: 11, children: iter([]) },
{ element: 12, children: iter([]) },
])
},
{ element: 1, children: iter([]) },
{ element: 2, children: iter([]) }
]));
const nodes = tree.getNodes();
assert.deepEqual(nodes.length, 3);
assert.deepEqual(nodes[0].element, 0);
assert.deepEqual(nodes[0].children.length, 3);
assert.deepEqual(nodes[0].children[0].element, 10);
assert.deepEqual(nodes[0].children[1].element, 11);
assert.deepEqual(nodes[0].children[2].element, 12);
assert.deepEqual(nodes[1].element, 1);
assert.deepEqual(nodes[2].element, 2);
});
test('delete', () => {
const tree = new Tree<number>();
tree.splice([0], 0, iter([
{ element: 0, children: iter([]) },
{ element: 1, children: iter([]) },
{ element: 2, children: iter([]) }
]));
tree.splice([0], 3, iter([]));
const nodes = tree.getNodes();
assert.equal(nodes.length, 0);
});
test('nested delete', () => {
const tree = new Tree<number>();
tree.splice([0], 0, iter([
{
element: 0, children: iter([
{ element: 10, children: iter([]) },
{ element: 11, children: iter([]) },
{ element: 12, children: iter([]) },
])
},
{ element: 1, children: iter([]) },
{ element: 2, children: iter([]) }
]));
tree.splice([0, 1], 1, iter([]));
const nodes = tree.getNodes();
assert.deepEqual(nodes.length, 3);
assert.deepEqual(nodes[0].element, 0);
assert.deepEqual(nodes[0].children.length, 2);
assert.deepEqual(nodes[0].children[0].element, 10);
assert.deepEqual(nodes[0].children[1].element, 12);
assert.deepEqual(nodes[1].element, 1);
assert.deepEqual(nodes[2].element, 2);
});
test('deep delete', () => {
const tree = new Tree<number>();
tree.splice([0], 0, iter([
{
element: 0, children: iter([
{ element: 10, children: iter([]) },
{ element: 11, children: iter([]) },
{ element: 12, children: iter([]) },
])
},
{ element: 1, children: iter([]) },
{ element: 2, children: iter([]) }
]));
tree.splice([0], 1, iter([]));
const nodes = tree.getNodes();
assert.deepEqual(nodes.length, 2);
assert.deepEqual(nodes[0].element, 1);
assert.deepEqual(nodes[1].element, 2);
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册