409 lines
7.0 KiB
C#
409 lines
7.0 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System;
|
|
|
|
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 Exception();
|
|
}
|
|
|
|
node = LastChild( node );
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
|
|
public N NextNonChild( N node )
|
|
{
|
|
return NextNode( LastOuterNode( node ) );
|
|
}
|
|
|
|
public N IterationEndOf( N node )
|
|
{
|
|
return NextNonChild( node );
|
|
}
|
|
|
|
public N GetInParents( N node, Func<N,bool> predicate )
|
|
{
|
|
var p = Parent( node );
|
|
|
|
while ( p != null )
|
|
{
|
|
if ( predicate( p ) )
|
|
{
|
|
return p;
|
|
}
|
|
|
|
p = Parent( p );
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
public int GetDepth( N node, Dictionary<N, int> depthMap = null )
|
|
{
|
|
if ( depthMap == null )
|
|
{
|
|
var depth = 0;
|
|
var it = Parent( node );
|
|
var maxDepth = 1000;
|
|
|
|
while ( it != null )
|
|
{
|
|
depth ++;
|
|
|
|
if ( depth == maxDepth )
|
|
{
|
|
RJLog.Log( "reached max depth", it );
|
|
return depth;
|
|
}
|
|
|
|
it = Parent( it );
|
|
}
|
|
|
|
return depth;
|
|
}
|
|
|
|
if ( depthMap.ContainsKey( node ) )
|
|
{
|
|
return depthMap[ node ];
|
|
}
|
|
|
|
var parent = Parent( node );
|
|
|
|
if ( parent == null )
|
|
{
|
|
depthMap[ node ] = 0;
|
|
return 0;
|
|
}
|
|
|
|
if ( depthMap.ContainsKey( parent ) )
|
|
{
|
|
var parentDepth = depthMap[ parent ];
|
|
var nodeDepth = parentDepth + 1;
|
|
|
|
depthMap[ node ] = nodeDepth;
|
|
|
|
return nodeDepth;
|
|
}
|
|
|
|
|
|
depthMap[ node ] = GetDepth( node );
|
|
|
|
return depthMap[ node ];
|
|
}
|
|
|
|
public void DepthIterate( N node, Action<N, int> callback, bool childrenOnly = false, Dictionary<N, int> depthMap = null )
|
|
{
|
|
if ( depthMap == null )
|
|
{
|
|
depthMap = new Dictionary<N, int>();
|
|
}
|
|
|
|
var iterationCallback = ( N node )=>
|
|
{
|
|
var depth = GetDepth( node, depthMap );
|
|
callback( node, depth );
|
|
};
|
|
|
|
Iterate( node, iterationCallback, childrenOnly );
|
|
}
|
|
|
|
public void Iterate( N node, 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, 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, Predicate<N> predicate, bool childrenOnly )
|
|
{
|
|
Action<N> addToList = ( N n ) =>
|
|
{
|
|
if ( predicate( n ) )
|
|
{
|
|
list.Add( n );
|
|
}
|
|
};
|
|
|
|
Iterate( node, addToList, childrenOnly );
|
|
}
|
|
|
|
public void FilterAndMap<U>( List<U> list, N node, Predicate<N> predicate, Func<N,U> mapper, bool childrenOnly )
|
|
{
|
|
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, Predicate<N> predicate, Func<N,U> mapper, bool childrenOnly )
|
|
{
|
|
Action<N> addToList = ( N n ) =>
|
|
{
|
|
list.Add( mapper( n ) );
|
|
};
|
|
|
|
Iterate( node, addToList, childrenOnly );
|
|
}
|
|
|
|
|
|
}
|
|
|
|
} |