//#pragma title( "TNode.hpp - List/Tree base classes" ) /* Copyright (c) 1995-1998, Mission Critical Software, Inc. All rights reserved. =============================================================================== Module - TNode.hpp System - Common Author - Tom Bernhardt Created - 1989-11-19 Description - List/Tree base classes. Updates - =============================================================================== */ #ifndef MCSINC_TNode_hpp #define MCSINC_TNode_hpp #include "common.hpp" #define MCS_ListError_InvalidHead 0x00000001 #define MCS_ListError_InvalidTail 0x00000002 #define MCS_ListError_InvalidCount 0x00000004 #define MCS_ListError_InvalidPtr 0x00000008 #define MCS_ListError_Exception 0x00000010 #define TNodeCompare(name) \ int /* ret-0(v1==v2) >0(v1>v2) <0(v10(v1>v2) <0(v1right,n++); return c ? n : -1; } TNode * Head() const { MCSASSERT(this); return head; } DWORD Count() const { MCSASSERT (this); return count; } protected: DWORD Validate( TNode ** pErrorNode ); }; /* A dynamically sortable collection of TNode entries. The TNodes are arranged in either of two forms: a sorted linked linear list or a binary tree. The current data data structure (form) is stored in the listType member. The form of the list may be easily changed from binary tree to sorted list or vice versa. The following member functions support these transformations: ToSorted Converts the tree form into a sorted linear list form without need for comparisons; the order is preserved. SortedToTree Converts the sorted linear list form into a perfectly balanced binary tree without comparisons; the order is preserved. UnsortedToTree Converts the sorted linear list form into a binary tree that is not necesarily balanced. It uses the PCompare function to form the order of the tree. Thus if the list order closely matches the PCompare directed order, the resulting tree will be grossly unbalanced. This has a bearing on the performance and memory requirements of the ToSorted function which is recursive. So be careful, especially with large lists. Sort This resorts either a tree or list form according to the argument pCompare function pointer provided. Note the above admonition. In either form, exposed are also Insert and Remove member functions. The functions are wrappers for TreeInsert and SortedInsert function depending upon the current list type. */ enum TNodeListType { TNodeTypeError, TNodeTypeUnsorted, TNodeTypeLinear, TNodeTypeTree }; class TNodeListSortable : public TNodeList { private: TNode * lastInsert; static TNode * // ret-head of sorted list TreeToSortedList( TNode * top ,// i/o-top of [sub]tree to squash TNode ** newhead ,// out-leftmost branch from tree TNode ** newtail // out-rightmost branch from tree ); static TNode * // ret-middle of list (head of Btree) ListSortedToTree( TNode * top // i/o-top of [sub]list to tree-ify ); BOOL CountTree( TNode * pCurrentTop, DWORD * pCount); protected: TNodeListType listType; TNodeCompare((* PCompare)); public: TNodeListSortable(TNodeCompare((* pCompare)) = NULL, TNodeListType t = TNodeTypeLinear) { lastInsert = NULL; listType = t; PCompare = pCompare; }; ~TNodeListSortable() { if ( IsTree() ) ToSorted(); } void CompareSet(TNodeCompare((* pCompare))) { PCompare = pCompare; } void TypeSetTree() { listType = TNodeTypeTree; } void TypeSetSorted() { listType = TNodeTypeLinear; } void TreeInsert(TNode * item, short * depth); TNode ** TreeFindInsert(TNode const * item, short * depth); BOOL TreeInsertIfNew(TNode * item, short * depth) { TNode ** r=TreeFindInsert(item,depth); if (*r) return FALSE; *r=item; item->left = item->right = NULL; count++; return TRUE; } void TreeInsert(TNode * item) { short discard; TreeInsert(item, &discard); }; void TreeRemove(TNode * item); TNode * TreeFind(TNodeCompareValue((* pCompare)), void const * findval) const; void SortedInsert(TNode * t); BOOL SortedInsertIfNew(TNode * t); TNode * SortedFindInsertBefore(TNode * item, BOOL * exists); void Insert(TNode * t) { if (IsTree()) TreeInsert(t); else SortedInsert(t); } BOOL InsertIfNew(TNode * t) { short depth; if (IsTree()) return TreeInsertIfNew(t,&depth); else return SortedInsertIfNew(t); } virtual void Remove(TNode * t) { if (t==lastInsert) lastInsert = NULL; if (IsTree()) TreeRemove(t); else TNodeList::Remove(t); }; // void Delete(TNode * t) { Remove(t); delete t; }; TNode * Find(TNodeCompareValue((* pCompare)), void const * findval) const { if (IsTree()) return TreeFind(pCompare,findval); return TNodeList::Find(pCompare,findval); } void SortedToTree() { MCSASSERTSZ( !IsTree(), "TNodeListSortable::SortedToTree - list is already a tree" ); if ( !IsTree() ) { head = ListSortedToTree( head ); tail = NULL; listType = TNodeTypeTree; } } TNode * UnsortedToTree(); void ToSorted() { MCSASSERTSZ( IsTree(), "TNodeListSortable::ToSorted - list is not a tree" ); if ( IsTree() ) { MCSASSERT( ValidateTree() ); if ( head ) TreeToSortedList( head, &head, &tail ); listType = TNodeTypeLinear; } } void Balance() { MCSASSERTSZ( IsTree(), "TNodeListSortable::Balance - list is not a tree" ); if ( IsTree() ) { ToSorted(); SortedToTree(); } } void Sort(TNodeCompare((* pCompare))) { TNodeListType lt = listType; if (lt == TNodeTypeTree) ToSorted(); CompareSet(pCompare); UnsortedToTree(); if (lt != TNodeTypeTree) ToSorted(); } void SortedToScrambledTree(); BOOL IsTree() const { return listType == TNodeTypeTree; }; BOOL ValidateTree( ); DWORD ValidateList( TNode ** pErrorNode = NULL) { MCSASSERT(listType != TNodeTypeTree); return Validate(pErrorNode); } }; /* TNodeListEnum is a 'friend' of TNode used to enumerate/iterate through TNodeList in linear list form. It is an error to give it a TNodeList in tree form. */ class TNodeListEnum { protected: TNodeList const * list; // list for which enums are carried out TNode * curr; // last node processed by enum functions public: TNodeListEnum() { list = NULL; curr = NULL; }; TNodeListEnum(TNodeList const * tlist) { Open(tlist); } ~TNodeListEnum() { }; void Open(TNodeList const * tlist) { list = tlist; Top(); }; TNode * OpenFirst(TNodeList const * tlist) { list = tlist; return First(); } TNode * First() { return curr = list->head; }; TNode * Next() { return curr = (curr ? curr->right : list->head); } TNode * Prev() { return curr = (curr ? curr->left : list->tail); } TNode * Last() { return curr = list->tail; }; TNode * Get() { return curr; } TNode * Get(long n) { TNode * c; Top(); while ( n-->=0 && (c=Next()) ); return c; } void Close() { curr = NULL; } void Top() { curr = NULL; }; }; // provides optimized direct accessibility by ordinal to TNodeList at some // expense to sequential traversal performance class TNodeListOrdEnum : public TNodeListEnum { private: long nCurr; public: TNodeListOrdEnum() : TNodeListEnum() { nCurr = -1; }; TNodeListOrdEnum(TNodeList const * tlist) { Open(tlist); }; void Open(TNodeList const * tlist) { TNodeListEnum::Open(tlist); nCurr = -1; }; TNode * OpenFirst(TNodeList const * tlist) { Open(tlist); return First(); } TNode * First() { nCurr = list->head ? 0 : -1; return TNodeListEnum::First(); }; TNode * Next() { TNode * t = TNodeListEnum::Next(); if (curr) nCurr++; else nCurr=-1; return t; } TNode * Prev() { TNode * t = TNodeListEnum::Prev(); if (curr) if (nCurr>0) nCurr--; else nCurr=list->Count()-1; else nCurr=-1; return t; } void Close() { nCurr=-1; TNodeListEnum::Close(); } void Top() { nCurr=-1; TNodeListEnum::Top(); }; long Pos() const { return nCurr; }; long Pos(TNode const * t) { long n; TNode * c; for (c=list->head, n=0; c!=t; c=c->right,n++); if (c) nCurr=n; else nCurr=-1; curr=c; return nCurr; } TNode * Get(long n); }; /* TNodeTreeEnum enumerates a TNodeListSortable that is in tree form. It is an error to give it a TNodeListSortable that is in linear list form. */ enum TNodeTreeStackEntryState {Snone, Sleft, Sused, Sright, SComplete}; struct TNodeTreeStackEntry { TNode * save; TNodeTreeStackEntryState state; }; const TREE_STACKSIZE = 200; // default maximum recursion depth class TNodeTreeEnum { private: TNodeTreeStackEntry * stackBase, * stackPos; int stackSize; void Push(TNode * item) { (++stackPos)->save = item; stackPos->state = Snone; }; BOOL Pop() { return --stackPos >= stackBase; }; void StackAlloc(int stacksize) { stackSize = stacksize; stackBase = new TNodeTreeStackEntry[stacksize]; }; protected: TNode * top; // tree top for which enums are carried out TNode * curr; // next node processed by enum functions public: TNodeTreeEnum(int stacksize = TREE_STACKSIZE) { top = NULL; StackAlloc(stacksize); }; TNodeTreeEnum(TNodeListSortable const * tlist, int stacksize = TREE_STACKSIZE) { StackAlloc(stacksize); Open(tlist); }; ~TNodeTreeEnum() { Close(); delete [] stackBase; }; void Open(TNodeListSortable const * tlist) { top = tlist->head; stackPos = stackBase; stackPos->save = NULL; stackPos->state = SComplete; if ( top ) Push(top); } TNode * First(); TNode * FirstAfter(TNodeCompareValue((* Compare) ), void const * findVal); TNode * OpenFirst(TNodeListSortable const * tlist) { Open(tlist); return Next(); } TNode * Next(); TNode * StackTop() { return stackPos->save; } void Close() { stackPos = stackBase; } }; #endif // MCSINC_TNode_hpp // TNode.hpp - end of file