rj-action-library/Runtime/Graphs/Trees/TreeWalker.cs

391 lines
6.8 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 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 );
}
}
}