This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

269 lines
7.4 KiB
C++

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