//========= 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 NTreeNode { public: // constructor NTreeNode( T data ); NTreeNode *PrependChild( NTreeNode *node ); NTreeNode *AppendChild( NTreeNode *node ); NTreeNode *InsertChildAfterIndex( NTreeNode *node, int index ); NTreeNode *InsertChildBeforeIndex( NTreeNode *node, int index ); NTreeNode *RemoveChild( Position position ); NTreeNode *RemoveChild( int index ); Position InsertAfter( NTreeNode *node, Position position ); Position InsertBefore( NTreeNode *node, Position position ); int GetNumChildren(); Position GetChildPosition( int childNum ); NTreeNode *GetChild( int childNum ); NTreeNode *GetChild( Position position ); int GetIndexRelativeToParent(); T GetItem(); NTreeNode *GetParent(); NTreeNode *GetRoot(); NTreeNode *GetNextSibling(); void Traverse( void (*VisitFunc)( T, int depth ), int maxTreeDepth ); NTreeNode *ReentrantTraversalGetFirst( int maxTreeDepth ); NTreeNode *ReentrantTraversalGetNext( void ); protected: GList * > *list; T data; NTreeNode *parent; ArrayStack *> *reentrantStack; }; template NTreeNode::NTreeNode( T data ) { list = new GList * >; this->data = data; this->parent = NULL; this->reentrantStack = NULL; } template NTreeNode *NTreeNode::PrependChild( NTreeNode *node ) { node->parent = this; return list->GetItemAtPosition( list->InsertAtHead( node ) ); } template NTreeNode *NTreeNode::AppendChild( NTreeNode *node ) { node->parent = this; return list->GetItemAtPosition( list->InsertAtTail( node ) ); } template NTreeNode *NTreeNode::InsertChildAfterIndex( NTreeNode *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 NTreeNode *NTreeNode::InsertChildBeforeIndex( NTreeNode *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 NTreeNode *NTreeNode::RemoveChild( Position position ) { NTreeNode **node = ( NTreeNode ** )( void * )position; ( *node )->parent = NULL; return list->Remove( position ); } template NTreeNode *NTreeNode::RemoveChild( int index ) { Position position = list->GetPositionAtIndex( index ); NTreeNode **node = ( NTreeNode ** )( void * )position; ( *node )->parent = NULL; return list->Remove( position ); } template Position NTreeNode::InsertAfter( NTreeNode *node, Position position ) { node->parent = this; return list->InsertAfter( node, position ); } template Position NTreeNode::InsertBefore( NTreeNode *node, Position position ) { node->parent = this; return list->InsertBefore( node, position ); } template int NTreeNode::GetNumChildren() { return list->GetNumItems(); } template Position NTreeNode::GetChildPosition( int childNum ) { return list->GetPositionAtIndex( childNum ); } template NTreeNode *NTreeNode::GetChild( int childNum ) { return list->GetItemAtIndex( childNum ); } template NTreeNode *NTreeNode::GetChild( Position position ) { return list->GetItemAtIndex( position ); } template int NTreeNode::GetIndexRelativeToParent() { if( !parent ) { assert( 0 ); // hack return -1; } GListIterator *> 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 T NTreeNode::GetItem() { return data; } template NTreeNode *NTreeNode::GetParent() { return parent; } template NTreeNode *NTreeNode::GetRoot() { NTreeNode *node; node = this; while( node->GetParent() ) { node = node->GetParent(); } return node; } template NTreeNode *NTreeNode::GetNextSibling() { int currentID, siblingID; NTreeNode *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 void NTreeNode::Traverse( void (*VisitFunc)( T, int depth ), int maxTreeDepth ) { ArrayStack *> stack( maxTreeDepth ); NTreeNode *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 NTreeNode *NTreeNode::ReentrantTraversalGetFirst( int maxTreeDepth ) { if( reentrantStack ) { delete reentrantStack; } reentrantStack = new ArrayStack *>( maxTreeDepth ); reentrantStack->Push( this ); return this; } template NTreeNode *NTreeNode::ReentrantTraversalGetNext( void ) { NTreeNode *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__ */