55
66'use strict' ;
77
8- import { clamp } from './numbers ' ;
8+ import { tail2 , last } from 'vs/base/common/arrays ' ;
99
1010export interface ITreeNode < T > {
1111 readonly element : T ;
1212 readonly children : ITreeNode < T > [ ] ;
1313}
1414
15- function clone < T > ( nodes : ITreeNode < T > [ ] ) : ITreeNode < T > [ ] {
16- return nodes . map ( ( { element, children } ) => ( { element, children : clone ( children ) } ) ) ;
17- }
18-
1915export class Tree < T > {
2016
21- private root : ITreeNode < T > [ ] = [ ] ;
17+ private root : ITreeNode < T > = { element : undefined , children : [ ] } ;
2218
2319 splice ( start : number [ ] , deleteCount : number , nodes : ITreeNode < T > [ ] = [ ] ) : ITreeNode < T > [ ] {
2420 if ( start . length === 0 ) {
25- throw new Error ( 'invalid tree location' ) ;
21+ throw new Error ( 'Invalid tree location' ) ;
2622 }
2723
28- const children = this . findChildren ( start ) ;
29- const index = start [ start . length - 1 ] ;
30- return children . splice ( index , deleteCount , ...clone ( nodes ) ) ;
24+ const [ rest , index ] = tail2 ( start ) ;
25+ const parentPath = this . getNodePath ( rest ) ;
26+ const parent = last ( parentPath ) ;
27+
28+ return parent . children . splice ( index , deleteCount , ...nodes ) ;
3129 }
3230
33- getElement ( location : number [ ] ) : T | undefined {
34- const node = this . findElement ( location ) ;
35- return node && node . element ;
31+ getElement ( location : number [ ] ) : T {
32+ if ( location . length === 0 ) {
33+ throw new Error ( 'Invalid tree location' ) ;
34+ }
35+
36+ const nodePath = this . getNodePath ( location ) ;
37+ const node = last ( nodePath ) ;
38+
39+ return node . element ;
3640 }
3741
38- getNodes ( ) : ITreeNode < T > [ ] {
39- return clone ( this . root ) ;
42+ getElementPath ( location : number [ ] ) : T [ ] {
43+ if ( location . length === 0 ) {
44+ throw new Error ( 'Invalid tree location' ) ;
45+ }
46+
47+ const nodePath = this . getNodePath ( location ) ;
48+ return nodePath . map ( node => node . element ) ;
4049 }
4150
42- private findElement ( location : number [ ] ) : ITreeNode < T > {
43- const children = this . findChildren ( location ) ;
44- const lastIndex = clamp ( location [ location . length - 1 ] , 0 , children . length ) ;
45- return children [ lastIndex ] ;
51+ getNodes ( ) : ITreeNode < T > [ ] {
52+ return this . root . children ;
4653 }
4754
48- private findChildren ( location : number [ ] , children : ITreeNode < T > [ ] = this . root ) : ITreeNode < T > [ ] {
49- if ( location . length === 1 ) {
50- return children ;
55+ private getNodePath ( location : number [ ] , node : ITreeNode < T > = this . root ) : ITreeNode < T > [ ] {
56+ if ( location . length === 0 ) {
57+ return [ node ] ;
58+ }
59+
60+ let [ index , ...rest ] = location ;
61+
62+ if ( index < 0 || index >= node . children . length ) {
63+ throw new Error ( 'Invalid location' ) ;
5164 }
5265
53- let [ i , ...rest ] = location ;
54- i = clamp ( i , 0 , children . length ) ;
55- return this . findChildren ( rest , children [ i ] . children ) ;
66+ const child = node . children [ index ] ;
67+ return [ node , ...this . getNodePath ( rest , child ) ] ;
5668 }
5769}
0 commit comments