|
|
//========= 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__ */
|