//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #ifndef __TREE_H__ #define __TREE_H__ #include "ArrayStack.h" #include "List.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__ */