322 lines
5.4 KiB
C#
322 lines
5.4 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
|
|
namespace Rokojori
|
|
{
|
|
public abstract class TreeWalker<N> where N:class
|
|
{
|
|
public abstract N Parent( N node );
|
|
|
|
public abstract N ChildAt( N node, int index );
|
|
|
|
public abstract int NumChildren( N node );
|
|
|
|
public bool HasChildren( N node )
|
|
{
|
|
return NumChildren( node ) > 0;
|
|
}
|
|
|
|
public bool HasParent( N node )
|
|
{
|
|
return Parent( node ) != null;
|
|
}
|
|
|
|
|
|
public int ChildIndexOf( N node )
|
|
{
|
|
var p = Parent( node );
|
|
|
|
if ( p == null )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
var numKids = NumChildren( p );
|
|
|
|
for ( var i = 0; i<numKids; i++ )
|
|
{
|
|
if ( ChildAt( p, i ) == node )
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
public N SiblingAt( N node, int index )
|
|
{
|
|
var p = Parent( node );
|
|
|
|
if ( p == null || index<0 || index >= NumChildren( p ) )
|
|
{ return null; }
|
|
|
|
return ChildAt( p, index );
|
|
}
|
|
|
|
|
|
public N NextSibling( N node )
|
|
{
|
|
var index = ChildIndexOf( node );
|
|
return SiblingAt( node, index+1 );
|
|
}
|
|
|
|
|
|
public N PreviousSibling( N node )
|
|
{
|
|
var index = ChildIndexOf( node );
|
|
return SiblingAt( node, index-1 );
|
|
}
|
|
|
|
|
|
public bool HasSiblingAt( N node, int index )
|
|
{
|
|
var p = Parent( node );
|
|
if ( p == null || index<0 || index >= NumChildren( p ) )
|
|
{ return false; }
|
|
return true;
|
|
}
|
|
|
|
|
|
public N FirstChild( N node )
|
|
{
|
|
return NumChildren( node )<=0?null:ChildAt( node, 0 );
|
|
}
|
|
|
|
|
|
public N LastChild( N node )
|
|
{
|
|
var num = NumChildren( node );
|
|
return num <= 0 ? null : ChildAt( node, num - 1 );
|
|
}
|
|
|
|
|
|
public N NextNode( N node )
|
|
{
|
|
if ( HasChildren( node ) )
|
|
{
|
|
return FirstChild( node );
|
|
}
|
|
|
|
var next = NextSibling( node );
|
|
|
|
if ( next != null )
|
|
{
|
|
return next;
|
|
}
|
|
|
|
var parent = Parent( node );
|
|
|
|
while ( parent != null )
|
|
{
|
|
var n = NextSibling( parent );
|
|
|
|
if ( n != null )
|
|
{
|
|
return n;
|
|
}
|
|
|
|
parent = Parent( parent );
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
public N PreviousNode( N node )
|
|
{
|
|
var prev = PreviousSibling( node );
|
|
|
|
if ( prev != null )
|
|
{
|
|
while ( HasChildren( prev ) )
|
|
{
|
|
prev = LastChild( prev );
|
|
}
|
|
return prev;
|
|
}
|
|
|
|
return Parent( node );
|
|
}
|
|
|
|
|
|
public N RootParent( N node )
|
|
{
|
|
node = Parent( node );
|
|
|
|
if ( node == null )
|
|
{
|
|
return null;
|
|
}
|
|
|
|
while ( HasParent( node ) )
|
|
{
|
|
node = Parent( node );
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
|
|
public N LastGrandChild( N node )
|
|
{
|
|
if ( HasChildren( node ) )
|
|
{
|
|
node = LastChild( node );
|
|
|
|
while ( HasChildren( node ) )
|
|
{
|
|
node = LastChild( node );
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
public bool IsChildOf( N child, N parent )
|
|
{
|
|
var p = Parent( child );
|
|
|
|
while ( p != null )
|
|
{
|
|
if ( p == parent )
|
|
{
|
|
return true;
|
|
}
|
|
p = Parent( p );
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
public int NumParents( N node )
|
|
{
|
|
var num = 0;
|
|
var p = Parent( node );
|
|
|
|
while ( p != null )
|
|
{
|
|
num++;
|
|
p = Parent( p );
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
|
|
public N LastOuterNode( N node )
|
|
{
|
|
var its = 0;
|
|
var max = 10000;
|
|
|
|
while ( HasChildren( node ) )
|
|
{
|
|
its++;
|
|
|
|
if ( its > max )
|
|
{
|
|
throw new System.Exception();
|
|
}
|
|
|
|
node = LastChild( node );
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
|
|
public N NextNonChild( N node )
|
|
{
|
|
return NextNode( LastOuterNode( node ) );
|
|
}
|
|
|
|
public N IterationEndOf( N node )
|
|
{
|
|
return NextNonChild( node );
|
|
}
|
|
|
|
public void Iterate( N node, System.Action<N> callback, bool childrenOnly = false )
|
|
{
|
|
var end = IterationEndOf( node );
|
|
var it = node;
|
|
|
|
if ( childrenOnly )
|
|
{
|
|
it = NextNode( it );
|
|
}
|
|
|
|
while ( it != end )
|
|
{
|
|
callback( it );
|
|
it = NextNode( it );
|
|
}
|
|
}
|
|
|
|
public N Find( N node, System.Predicate<N> predicate, bool childrenOnly )
|
|
{
|
|
var end = IterationEndOf( node );
|
|
var it = node;
|
|
|
|
if ( childrenOnly )
|
|
{
|
|
it = NextNode( it );
|
|
}
|
|
|
|
while ( it != end )
|
|
{
|
|
if ( predicate( it ) )
|
|
{
|
|
return it;
|
|
}
|
|
|
|
it = NextNode( it );
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public void Filter( List<N> list, N node, System.Predicate<N> predicate, bool childrenOnly )
|
|
{
|
|
System.Action<N> addToList = ( N n ) =>
|
|
{
|
|
if ( predicate( n ) )
|
|
{
|
|
list.Add( n );
|
|
}
|
|
};
|
|
|
|
Iterate( node, addToList, childrenOnly );
|
|
}
|
|
|
|
public void FilterAndMap<U>( List<U> list, N node, System.Predicate<N> predicate, System.Func<N,U> mapper, bool childrenOnly )
|
|
{
|
|
System.Action<N> addToList = ( N n ) =>
|
|
{
|
|
if ( predicate( n ) )
|
|
{
|
|
list.Add( mapper( n ) );
|
|
}
|
|
};
|
|
|
|
Iterate( node, addToList, childrenOnly );
|
|
}
|
|
|
|
public void Map<U>( List<U> list, N node, System.Predicate<N> predicate, System.Func<N,U> mapper, bool childrenOnly )
|
|
{
|
|
System.Action<N> addToList = ( N n ) =>
|
|
{
|
|
list.Add( mapper( n ) );
|
|
};
|
|
|
|
Iterate( node, addToList, childrenOnly );
|
|
}
|
|
|
|
|
|
}
|
|
|
|
} |