sqwarmed/sdk_src/public/ntree.h

317 lines
7.1 KiB
C++

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef __TREE_H__
#define __TREE_H__
#include "List.h"
#include "ArrayStack.h"
// NTreeNode: Class decleration and definition
template <class T> class NTreeNode
{
public:
// constructor
NTreeNode<T>( T data );
NTreeNode<T> *PrependChild( NTreeNode<T> *node );
NTreeNode<T> *AppendChild( NTreeNode<T> *node );
NTreeNode<T> *InsertChildAfterIndex( NTreeNode<T> *node, int index );
NTreeNode<T> *InsertChildBeforeIndex( NTreeNode<T> *node, int index );
NTreeNode<T> *RemoveChild( Position position );
NTreeNode<T> *RemoveChild( int index );
Position InsertAfter( NTreeNode<T> *node, Position position );
Position InsertBefore( NTreeNode<T> *node, Position position );
int GetNumChildren();
Position GetChildPosition( int childNum );
NTreeNode<T> *GetChild( int childNum );
NTreeNode<T> *GetChild( Position position );
int GetIndexRelativeToParent();
T GetItem();
NTreeNode<T> *GetParent();
NTreeNode<T> *GetRoot();
NTreeNode<T> *GetNextSibling();
void Traverse( void (*VisitFunc)( T, int depth ), int maxTreeDepth );
NTreeNode<T> *ReentrantTraversalGetFirst( int maxTreeDepth );
NTreeNode<T> *ReentrantTraversalGetNext( void );
protected:
GList<NTreeNode<T> * > *list;
T data;
NTreeNode<T> *parent;
ArrayStack<NTreeNode<T> *> *reentrantStack;
};
template <class T>
NTreeNode<T>::NTreeNode( T data )
{
list = new GList<NTreeNode<T> * >;
this->data = data;
this->parent = NULL;
this->reentrantStack = NULL;
}
template <class T>
NTreeNode<T> *NTreeNode<T>::PrependChild( NTreeNode<T> *node )
{
node->parent = this;
return list->GetItemAtPosition( list->InsertAtHead( node ) );
}
template <class T>
NTreeNode<T> *NTreeNode<T>::AppendChild( NTreeNode<T> *node )
{
node->parent = this;
return list->GetItemAtPosition( list->InsertAtTail( node ) );
}
template <class T>
NTreeNode<T> *NTreeNode<T>::InsertChildAfterIndex( NTreeNode<T> *node, int index )
{
node->parent = this;
if( index < 0 )
{
// if out of range in the negative direction, prepend
this->PrependChild( node );
}
else if( index > list->GetNumItems() - 1 )
{
// if out of range, just append.
this->AppendChild( node );
}
else
{
Position pos;
pos = list->GetPositionAtIndex( index );
list->InsertAfter( node, pos );
}
return node;
}
template <class T>
NTreeNode<T> *NTreeNode<T>::InsertChildBeforeIndex( NTreeNode<T> *node, int index )
{
node->parent = this;
if( index < 0 )
{
// if out of range in the negative direction, prepend
this->PrependChild( node );
}
else if( index > list->GetNumItems() - 1 )
{
// if out of range, just append.
this->AppendChild( node );
}
else
{
Position pos;
pos = list->GetPositionAtIndex( index );
list->InsertBefore( node, pos );
}
return node;
}
template <class T>
NTreeNode<T> *NTreeNode<T>::RemoveChild( Position position )
{
NTreeNode<T> **node = ( NTreeNode<T> ** )( void * )position;
( *node )->parent = NULL;
return list->Remove( position );
}
template <class T>
NTreeNode<T> *NTreeNode<T>::RemoveChild( int index )
{
Position position = list->GetPositionAtIndex( index );
NTreeNode<T> **node = ( NTreeNode<T> ** )( void * )position;
( *node )->parent = NULL;
return list->Remove( position );
}
template <class T>
Position NTreeNode<T>::InsertAfter( NTreeNode<T> *node, Position position )
{
node->parent = this;
return list->InsertAfter( node, position );
}
template <class T>
Position NTreeNode<T>::InsertBefore( NTreeNode<T> *node, Position position )
{
node->parent = this;
return list->InsertBefore( node, position );
}
template <class T>
int NTreeNode<T>::GetNumChildren()
{
return list->GetNumItems();
}
template <class T>
Position NTreeNode<T>::GetChildPosition( int childNum )
{
return list->GetPositionAtIndex( childNum );
}
template <class T>
NTreeNode<T> *NTreeNode<T>::GetChild( int childNum )
{
return list->GetItemAtIndex( childNum );
}
template <class T>
NTreeNode<T> *NTreeNode<T>::GetChild( Position position )
{
return list->GetItemAtIndex( position );
}
template <class T>
int NTreeNode<T>::GetIndexRelativeToParent()
{
if( !parent )
{
assert( 0 ); // hack
return -1;
}
GListIterator<NTreeNode<T> *> iterator( parent->list );
int i;
for( i = 0, iterator.GotoHead(); !iterator.AtEnd(); iterator++, i++ )
{
if( iterator.GetCurrent() == this )
{
return i;
}
}
assert( 0 ); // hack
return -1;
}
template <class T>
T NTreeNode<T>::GetItem()
{
return data;
}
template <class T>
NTreeNode<T> *NTreeNode<T>::GetParent()
{
return parent;
}
template <class T>
NTreeNode<T> *NTreeNode<T>::GetRoot()
{
NTreeNode<T> *node;
node = this;
while( node->GetParent() )
{
node = node->GetParent();
}
return node;
}
template <class T>
NTreeNode<T> *NTreeNode<T>::GetNextSibling()
{
int currentID, siblingID;
NTreeNode<T> *parent;
parent = this->GetParent();
if( !parent )
{
return NULL;
}
currentID = this->GetIndexRelativeToParent();
siblingID = currentID + 1;
if( siblingID < parent->GetNumChildren() )
{
return parent->GetChild( siblingID );
}
else
{
return NULL;
}
}
template <class T>
void NTreeNode<T>::Traverse( void (*VisitFunc)( T, int depth ), int maxTreeDepth )
{
ArrayStack<NTreeNode<T> *> stack( maxTreeDepth );
NTreeNode<T> *current, *nextSibling;
stack.Push( this );
Visit( this->GetItem(), 0 );
while( !stack.IsEmpty() )
{
current = stack.Pop();
if( current->GetNumChildren() > 0 )
{
stack.Push( current );
stack.Push( current->GetChild( 0 ) );
Visit( current->GetChild( 0 )->GetItem(), stack.GetDepth() - 1 );
}
else
{
while( !stack.IsEmpty() && !( nextSibling = current->GetNextSibling() ) )
{
current = stack.Pop();
}
if( !stack.IsEmpty() )
{
stack.Push( nextSibling );
Visit( nextSibling->GetItem(), stack.GetDepth() - 1 );
}
}
}
}
template <class T>
NTreeNode<T> *NTreeNode<T>::ReentrantTraversalGetFirst( int maxTreeDepth )
{
if( reentrantStack )
{
delete reentrantStack;
}
reentrantStack = new ArrayStack<NTreeNode<T> *>( maxTreeDepth );
reentrantStack->Push( this );
return this;
}
template <class T>
NTreeNode<T> *NTreeNode<T>::ReentrantTraversalGetNext( void )
{
NTreeNode<T> *current, *nextSibling;
while( !reentrantStack->IsEmpty() )
{
current = reentrantStack->Pop();
if( current->GetNumChildren() > 0 )
{
reentrantStack->Push( current );
reentrantStack->Push( current->GetChild( 0 ) );
return current->GetChild( 0 );
}
else
{
while( !reentrantStack->IsEmpty() && !( nextSibling = current->GetNextSibling() ) )
{
current = reentrantStack->Pop();
}
if( !reentrantStack->IsEmpty() )
{
reentrantStack->Push( nextSibling );
return nextSibling;
}
}
}
delete reentrantStack;
reentrantStack = NULL;
return NULL;
}
#endif /* __TREE_H__ */