You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
316 lines
6.8 KiB
316 lines
6.8 KiB
//========= Copyright 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__ */
|
|
|