@ -6,7 +6,6 @@ import { Iterables } from '../system/iterable';
export interface IKeyIterator {
export interface IKeyIterator {
reset ( key : string ) : this ;
reset ( key : string ) : this ;
next ( ) : this ;
next ( ) : this ;
join ( parts : string [ ] ) : string ;
hasNext ( ) : boolean ;
hasNext ( ) : boolean ;
cmp ( a : string ) : number ;
cmp ( a : string ) : number ;
@ -29,10 +28,6 @@ export class StringIterator implements IKeyIterator {
return this ;
return this ;
}
}
join ( parts : string [ ] ) : string {
return parts . join ( '' ) ;
}
hasNext ( ) : boolean {
hasNext ( ) : boolean {
return this . _pos < this . _value . length - 1 ;
return this . _pos < this . _value . length - 1 ;
}
}
@ -48,10 +43,18 @@ export class StringIterator implements IKeyIterator {
}
}
}
}
export class PathIterator implements IKeyIterator {
const enum CharCode {
/ * *
* The ` / ` character .
* /
Slash = 47 ,
/ * *
* The ` \` character.
* /
Backslash = 92
}
private static readonly _fwd = '/' . charCodeAt ( 0 ) ;
private static readonly _bwd = '\\' . charCodeAt ( 0 ) ;
export class PathIterator implements IKeyIterator {
private _value ! : string ;
private _value ! : string ;
private _from ! : number ;
private _from ! : number ;
@ -68,17 +71,13 @@ export class PathIterator implements IKeyIterator {
return this . _to < this . _value . length ;
return this . _to < this . _value . length ;
}
}
join ( parts : string [ ] ) : string {
return parts . join ( '/' ) ;
}
next ( ) : this {
next ( ) : this {
// this._data = key.split(/[\\/]/).filter(s => !!s);
// this._data = key.split(/[\\/]/).filter(s => !!s);
this . _from = this . _to ;
this . _from = this . _to ;
let justSeps = true ;
let justSeps = true ;
for ( ; this . _to < this . _value . length ; this . _to ++ ) {
for ( ; this . _to < this . _value . length ; this . _to ++ ) {
const ch = this . _value . charCodeAt ( this . _to ) ;
const ch = this . _value . charCodeAt ( this . _to ) ;
if ( ch === PathIterator . _fwd || ch === PathIterator . _bwd ) {
if ( ch === CharCode . Slash || ch === CharCode . Backslash ) {
if ( justSeps ) {
if ( justSeps ) {
this . _from ++ ;
this . _from ++ ;
} else {
} else {
@ -121,14 +120,15 @@ export class PathIterator implements IKeyIterator {
}
}
class TernarySearchTreeNode < E > {
class TernarySearchTreeNode < E > {
str ! : string ;
element : E | undefined ;
segment ! : string ;
value : E | undefined ;
key ! : string ;
left : TernarySearchTreeNode < E > | undefined ;
left : TernarySearchTreeNode < E > | undefined ;
mid : TernarySearchTreeNode < E > | undefined ;
mid : TernarySearchTreeNode < E > | undefined ;
right : TernarySearchTreeNode < E > | undefined ;
right : TernarySearchTreeNode < E > | undefined ;
isEmpty ( ) : boolean {
isEmpty ( ) : boolean {
return this . left === undefined && this . mid === undefined && this . right === undefined && this . element === undefined ;
return ! this . left && ! this . mid && ! this . right && ! this . value ;
}
}
}
}
@ -159,17 +159,17 @@ export class TernarySearchTree {
if ( ! this . _root ) {
if ( ! this . _root ) {
this . _root = new TernarySearchTreeNode < E > ( ) ;
this . _root = new TernarySearchTreeNode < E > ( ) ;
this . _root . str = iter . value ( ) ;
this . _root . segmen t = iter . value ( ) ;
}
}
node = this . _root ;
node = this . _root ;
while ( true ) {
while ( true ) {
const val = iter . cmp ( node . str ) ;
const val = iter . cmp ( node . segmen t ) ;
if ( val > 0 ) {
if ( val > 0 ) {
// left
// left
if ( ! node . left ) {
if ( ! node . left ) {
node . left = new TernarySearchTreeNode < E > ( ) ;
node . left = new TernarySearchTreeNode < E > ( ) ;
node . left . str = iter . value ( ) ;
node . left . segmen t = iter . value ( ) ;
}
}
node = node . left ;
node = node . left ;
@ -177,7 +177,7 @@ export class TernarySearchTree {
// right
// right
if ( ! node . right ) {
if ( ! node . right ) {
node . right = new TernarySearchTreeNode < E > ( ) ;
node . right = new TernarySearchTreeNode < E > ( ) ;
node . right . str = iter . value ( ) ;
node . right . segmen t = iter . value ( ) ;
}
}
node = node . right ;
node = node . right ;
@ -186,15 +186,16 @@ export class TernarySearchTree {
iter . next ( ) ;
iter . next ( ) ;
if ( ! node . mid ) {
if ( ! node . mid ) {
node . mid = new TernarySearchTreeNode < E > ( ) ;
node . mid = new TernarySearchTreeNode < E > ( ) ;
node . mid . str = iter . value ( ) ;
node . mid . segmen t = iter . value ( ) ;
}
}
node = node . mid ;
node = node . mid ;
} else {
} else {
break ;
break ;
}
}
}
}
const oldElement = node . element ;
node . element = element ;
const oldElement = node . value ;
node . value = element ;
node . key = key ;
return oldElement ;
return oldElement ;
}
}
@ -202,7 +203,7 @@ export class TernarySearchTree {
const iter = this . _iter . reset ( key ) ;
const iter = this . _iter . reset ( key ) ;
let node = this . _root ;
let node = this . _root ;
while ( node ) {
while ( node ) {
const val = iter . cmp ( node . str ) ;
const val = iter . cmp ( node . segmen t ) ;
if ( val > 0 ) {
if ( val > 0 ) {
// left
// left
node = node . left ;
node = node . left ;
@ -217,7 +218,7 @@ export class TernarySearchTree {
break ;
break ;
}
}
}
}
return node ? node.element : undefined ;
return node ? node.value : undefined ;
}
}
delete ( key : string ) : void {
delete ( key : string ) : void {
@ -227,7 +228,7 @@ export class TernarySearchTree {
// find and unset node
// find and unset node
while ( node ) {
while ( node ) {
const val = iter . cmp ( node . str ) ;
const val = iter . cmp ( node . segmen t ) ;
if ( val > 0 ) {
if ( val > 0 ) {
// left
// left
stack . push ( [ 1 , node ] ) ;
stack . push ( [ 1 , node ] ) ;
@ -243,7 +244,7 @@ export class TernarySearchTree {
node = node . mid ;
node = node . mid ;
} else {
} else {
// remove element
// remove element
node . element = undefined ;
node . value = undefined ;
// clean up empty nodes
// clean up empty nodes
while ( stack . length > 0 && node . isEmpty ( ) ) {
while ( stack . length > 0 && node . isEmpty ( ) ) {
@ -265,7 +266,7 @@ export class TernarySearchTree {
let node = this . _root ;
let node = this . _root ;
let candidate : E | undefined ;
let candidate : E | undefined ;
while ( node ) {
while ( node ) {
const val = iter . cmp ( node . str ) ;
const val = iter . cmp ( node . segmen t ) ;
if ( val > 0 ) {
if ( val > 0 ) {
// left
// left
node = node . left ;
node = node . left ;
@ -275,20 +276,20 @@ export class TernarySearchTree {
} else if ( iter . hasNext ( ) ) {
} else if ( iter . hasNext ( ) ) {
// mid
// mid
iter . next ( ) ;
iter . next ( ) ;
candidate = node . element || candidate ;
candidate = node . value || candidate ;
node = node . mid ;
node = node . mid ;
} else {
} else {
break ;
break ;
}
}
}
}
return node && node . element || candidate ;
return node && node . value || candidate ;
}
}
findSuperstr ( key : string ) : TernarySearchTree < E > | undefined {
findSuperstr ( key : string ) : TernarySearchTree < E > | undefined {
const iter = this . _iter . reset ( key ) ;
const iter = this . _iter . reset ( key ) ;
let node = this . _root ;
let node = this . _root ;
while ( node ) {
while ( node ) {
const val = iter . cmp ( node . str ) ;
const val = iter . cmp ( node . segmen t ) ;
if ( val > 0 ) {
if ( val > 0 ) {
// left
// left
node = node . left ;
node = node . left ;
@ -313,44 +314,43 @@ export class TernarySearchTree {
}
}
forEach ( callback : ( value : E , index : string ) = > any ) {
forEach ( callback : ( value : E , index : string ) = > any ) {
this . _forEach ( this . _root ! , [ ] , callback ) ;
this . _forEach ( this . _root ! , callback ) ;
}
}
private _forEach ( node : TernarySearchTreeNode < E > , parts : string [ ] , callback: ( value : E , index : string ) = > any ) {
private _forEach ( node : TernarySearchTreeNode < E > , callback : ( value : E , index : string ) = > any ) {
if ( node === undefined ) return ;
if ( node === undefined ) return ;
// left
// left
this . _forEach ( node . left ! , parts , callback) ;
this . _forEach ( node . left ! , callback ) ;
// node
// node
parts . push ( node . str ) ;
if ( node . element ) {
callback ( node . element , this . _iter . join ( parts ) ) ;
if ( node . value ) {
callback ( node . value , node . key ) ;
}
}
// mid
// mid
this . _forEach ( node . mid ! , parts , callback ) ;
parts . pop ( ) ;
this . _forEach ( node . mid ! , callback ) ;
// right
// right
this . _forEach ( node . right ! , parts , callback) ;
this . _forEach ( node . right ! , callback ) ;
}
}
any ( ) : boolean {
any ( ) : boolean {
return this . _root !== undefined && ! this . _root . isEmpty ( ) ;
return this . _root !== undefined && ! this . _root . isEmpty ( ) ;
}
}
count ( ) : number {
count ( predicate ? : ( entry : E ) = > boolean ) : number {
if ( this . _root === undefined || this . _root . isEmpty ( ) ) return 0 ;
if ( this . _root === undefined || this . _root . isEmpty ( ) ) return 0 ;
return Iterables . count ( this . entries ( ) ) ;
return Iterables . count ( this . entries ( ) , predicate === undefined ? undefined : ( [ e ] ) = > predicate ( e ) );
}
}
entries ( ) : Iterable < [ E , string ] > {
entries ( ) : Iterable < [ E , string ] > {
return this . _iterator ( this . _root ! , [ ] );
return this . _iterator ( this . _root ! ) ;
}
}
values ( ) : Iterable < E > {
values ( ) : Iterable < E > {
return Iterables . map ( this . entries ( ) , e = > e [ 0 ] ) ;
return Iterables . map ( this . entries ( ) , ( [ e ] ) = > e ) ;
}
}
highlander ( ) : [ E , string ] | undefined {
highlander ( ) : [ E , string ] | undefined {
@ -375,22 +375,27 @@ export class TernarySearchTree {
return value ;
return value ;
}
}
private * _iterator ( node : TernarySearchTreeNode < E > | undefined , parts : string [ ] ) : IterableIterator < [ E , string ] > {
some ( predicate : ( entry : E ) = > boolean ) : boolean {
if ( this . _root === undefined || this . _root . isEmpty ( ) ) return false ;
return Iterables . some ( this . entries ( ) , ( [ e ] ) = > predicate ( e ) ) ;
}
private * _iterator ( node : TernarySearchTreeNode < E > | undefined ) : IterableIterator < [ E , string ] > {
if ( node !== undefined ) {
if ( node !== undefined ) {
// left
// left
yield * this . _iterator ( node . left ! , parts ) ;
yield * this . _iterator ( node . left ! ) ;
// node
// node
parts . push ( node . str ) ;
if ( node . element ) {
yield [ node . element , this . _iter . join ( parts ) ] ;
if ( node . value ) {
yield [ node . value , node . key ] ;
}
}
// mid
// mid
yield * this . _iterator ( node . mid ! , parts ) ;
parts . pop ( ) ;
yield * this . _iterator ( node . mid ! ) ;
// right
// right
yield * this . _iterator ( node . right ! , parts );
yield * this . _iterator ( node . right ! ) ;
}
}
}
}
}
}