compressed tree: setChildren

This commit is contained in:
Joao Moreno 2019-07-21 15:59:17 +02:00
parent f2adc2100c
commit 29ed9b3aba
2 changed files with 132 additions and 22 deletions

View file

@ -69,7 +69,18 @@ export function decompress<T>(element: ITreeElement<ICompressedTreeNode<T>>): IC
return _decompress(element, 0);
}
export interface ICompressedObjectTreeModelOptions<T, TFilterData> extends IObjectTreeModelOptions<T[], TFilterData> { }
export function splice<T>(treeElement: ICompressedTreeElement<T>, element: T, children: Iterator<ICompressedTreeElement<T>>): ICompressedTreeElement<T> {
if (treeElement.element === element) {
return { element, children };
}
return {
...treeElement,
children: Iterator.map(Iterator.from(treeElement.children), e => splice(e, element, children))
};
}
export interface ICompressedObjectTreeModelOptions<T, TFilterData> extends IObjectTreeModelOptions<ICompressedTreeNode<T>, TFilterData> { }
export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData extends NonNullable<any> = void> implements ITreeModel<T | null, TFilterData, T | null> {
@ -84,33 +95,80 @@ export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData e
private _onDidChangeRenderNodeCount = new Emitter<ITreeNode<T, TFilterData>>();
readonly onDidChangeRenderNodeCount: Event<ITreeNode<T, TFilterData>> = this._onDidChangeRenderNodeCount.event;
private model: ObjectTreeModel<T[], TFilterData>;
private map = new Map<T, T[]>();
private model: ObjectTreeModel<ICompressedTreeNode<T>, TFilterData>;
private nodes = new Map<T | null, ICompressedTreeNode<T>>();
constructor(list: ISpliceable<ITreeNode<T[], TFilterData>>, options: ICompressedObjectTreeModelOptions<T, TFilterData> = {}) {
get size(): number { return this.nodes.size; }
constructor(list: ISpliceable<ITreeNode<ICompressedTreeNode<T>, TFilterData>>, options: ICompressedObjectTreeModelOptions<T, TFilterData> = {}) {
this.model = new ObjectTreeModel(list, options);
}
setChildren(
element: T | null,
children: ISequence<ITreeElement<T>> | undefined
children: ISequence<ICompressedTreeElement<T>> | undefined,
onDidCreateNode?: (node: ITreeNode<ICompressedTreeNode<T>, TFilterData>) => void,
onDidDeleteNode?: (node: ITreeNode<ICompressedTreeNode<T>, TFilterData>) => void
): Iterator<ITreeElement<T | null>> {
if (element !== null && !this.map.has(element)) {
throw new Error('missing element');
const insertedElements = new Set<T | null>();
const _onDidCreateNode = (node: ITreeNode<ICompressedTreeNode<T>, TFilterData>) => {
for (const element of node.element.elements) {
insertedElements.add(element);
this.nodes.set(element, node.element);
}
// if (this.identityProvider) {
// const id = this.identityProvider.getId(node.element).toString();
// insertedElementIds.add(id);
// this.nodesByIdentity.set(id, node);
// }
if (onDidCreateNode) {
onDidCreateNode(node);
}
};
const _onDidDeleteNode = (node: ITreeNode<ICompressedTreeNode<T>, TFilterData>) => {
for (const element of node.element.elements) {
if (!insertedElements.has(element)) {
this.nodes.delete(element);
}
}
// if (this.identityProvider) {
// const id = this.identityProvider.getId(node.element).toString();
// if (!insertedElementIds.has(id)) {
// this.nodesByIdentity.delete(id);
// }
// }
if (onDidDeleteNode) {
onDidDeleteNode(node);
}
};
if (element === null) {
const compressedChildren = Iterator.map(Iterator.from(children), compress);
const result = this.model.setChildren(null, compressedChildren, _onDidCreateNode, _onDidDeleteNode);
return Iterator.map(result, decompress);
}
const compressedElement = element === null ? null : this.map.get(element)!;
const compressedChildren = this.compress(Iterator.from(children));
const deleted = this.model.setChildren(compressedElement, compressedChildren);
return this.decompress(deleted);
}
const compressedNode = this.nodes.get(element);
const node = this.model.getNode(compressedNode) as ITreeNode<ICompressedTreeNode<T>, TFilterData>;
const parent = node.parent!;
private compress(iterator: Iterator<ITreeElement<T>>): Iterator<ITreeElement<T[]>> {
throw new Error('todo');
}
const decompressedElement = decompress(node);
const splicedElement = splice(decompressedElement, element, Iterator.from(children));
const recompressedElement = compress(splicedElement);
private decompress(sequence: Iterator<ITreeElement<T[]>>): Iterator<ITreeElement<T>> {
throw new Error('todo');
const parentChildren = parent.children
.map(child => child === node ? recompressedElement : child);
this.model.setChildren(parent.element, parentChildren, _onDidCreateNode, _onDidDeleteNode);
// TODO
return Iterator.empty();
}
getListIndex(location: T | null): number {
@ -121,11 +179,11 @@ export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData e
throw new Error('Method not implemented.');
}
getNode(location?: T | null | undefined): ITreeNode<T | null, any> {
getNode(location?: T | null | undefined): ITreeNode<T | null, TFilterData> {
throw new Error('Method not implemented.');
}
getNodeLocation(node: ITreeNode<T | null, any>): T | null {
getNodeLocation(node: ITreeNode<T | null, TFilterData>): T | null {
throw new Error('Method not implemented.');
}

View file

@ -4,8 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { compress, ICompressedTreeElement, ICompressedTreeNode, decompress } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
import { compress, ICompressedTreeElement, ICompressedTreeNode, decompress, CompressedObjectTreeModel } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
import { Iterator } from 'vs/base/common/iterator';
import { ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { ISpliceable } from 'vs/base/common/sequence';
interface IResolvedCompressedTreeElement<T> extends ICompressedTreeElement<T> {
readonly element: T;
@ -27,9 +29,9 @@ function resolve<T>(treeElement: ICompressedTreeElement<T>): IResolvedCompressed
return result;
}
suite('CompressedObjectTreeModel', function () {
suite('CompressedObjectTree', function () {
suite('compress', function () {
suite('compress & decompress', function () {
test('small', function () {
const decompressed: ICompressedTreeElement<number> = { element: 1 };
@ -286,4 +288,54 @@ suite('CompressedObjectTreeModel', function () {
assert.deepEqual(resolve(decompress(compressed)), decompressed);
});
});
function toSpliceable<T>(arr: T[]): ISpliceable<T> {
return {
splice(start: number, deleteCount: number, elements: T[]): void {
arr.splice(start, deleteCount, ...elements);
}
};
}
function toArray<T>(list: ITreeNode<ICompressedTreeNode<T>>[]): T[][] {
return list.map(i => i.element.elements);
}
suite('CompressedObjectTreeModel', function () {
test('ctor', () => {
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
const model = new CompressedObjectTreeModel<number>(toSpliceable(list));
assert(model);
assert.equal(list.length, 0);
assert.equal(model.size, 0);
});
test('flat', () => {
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
const model = new CompressedObjectTreeModel<number>(toSpliceable(list));
model.setChildren(null, Iterator.fromArray([
{ element: 0 },
{ element: 1 },
{ element: 2 }
]));
assert.deepEqual(toArray(list), [[0], [1], [2]]);
assert.equal(model.size, 3);
model.setChildren(null, Iterator.fromArray([
{ element: 3 },
{ element: 4 },
{ element: 5 },
]));
assert.deepEqual(toArray(list), [[3], [4], [5]]);
assert.equal(model.size, 3);
model.setChildren(null, Iterator.empty());
assert.deepEqual(toArray(list), []);
assert.equal(model.size, 0);
});
});
});