Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

343 lines
15 KiB

  1. //#pragma title( "TNode.hpp - List/Tree base classes" )
  2. /*
  3. Copyright (c) 1995-1998, Mission Critical Software, Inc. All rights reserved.
  4. ===============================================================================
  5. Module - TNode.hpp
  6. System - Common
  7. Author - Tom Bernhardt
  8. Created - 1989-11-19
  9. Description - List/Tree base classes.
  10. Updates -
  11. ===============================================================================
  12. */
  13. #ifndef MCSINC_TNode_hpp
  14. #define MCSINC_TNode_hpp
  15. #include "common.hpp"
  16. #define MCS_ListError_InvalidHead 0x00000001
  17. #define MCS_ListError_InvalidTail 0x00000002
  18. #define MCS_ListError_InvalidCount 0x00000004
  19. #define MCS_ListError_InvalidPtr 0x00000008
  20. #define MCS_ListError_Exception 0x00000010
  21. #define TNodeCompare(name) \
  22. int /* ret-0(v1==v2) >0(v1>v2) <0(v1<v2)*/\
  23. name( \
  24. TNode const * v1 ,/* in -value1 to compare */\
  25. TNode const * v2 /* in -value2 to compare */\
  26. )
  27. #define TNodeCompareValue(name) \
  28. int /* ret-0(v1==v2) >0(v1>v2) <0(v1<v2)*/\
  29. name( \
  30. TNode const * tnode ,/* in -value1 to compare */\
  31. void const * value /* in -value2 to compare */\
  32. )
  33. #define DeleteAllListItems(datatype) \
  34. TNodeListEnum tenum; /* enumerate values */ \
  35. datatype * tnode; /* this node */ \
  36. datatype * tnext; /* next node */ \
  37. for ( tnode = (datatype *) tenum.OpenFirst( this ); \
  38. tnode; \
  39. tnode = tnext ) \
  40. { \
  41. tnext = (datatype *) tenum.Next(); \
  42. Remove( tnode ); \
  43. delete tnode; \
  44. } \
  45. tenum.Close()
  46. // TNode is a a base class for any derived object to be put into one of the
  47. // TNodeList classes.
  48. class TNode
  49. {
  50. friend class TNodeList;
  51. friend class TNodeListSortable;
  52. friend class TNodeListEnum;
  53. friend class TNodeListOrdEnum;
  54. friend class TNodeTreeEnum;
  55. TNode * left;
  56. TNode * right;
  57. public:
  58. TNode * Next() const { MCSASSERT(this); return right; }
  59. // virtual ~TNode() {}
  60. };
  61. class TNodeList
  62. {
  63. friend class TNodeListEnum;
  64. friend class TNodeListOrdEnum;
  65. friend class TNodeTreeEnum;
  66. protected:
  67. TNode * head,
  68. * tail;
  69. DWORD count;
  70. public:
  71. TNodeList() { head = tail = NULL; count = 0; };
  72. ~TNodeList();
  73. void InsertTop( TNode * eIns );
  74. void InsertBottom( TNode * eIns );
  75. void InsertAfter( TNode * eIns, TNode * eAft );
  76. void InsertBefore( TNode * eIns, TNode * eBef );
  77. void Remove(TNode const * t);
  78. // void Delete(TNode * t) { Remove(t); delete t; };
  79. void Reverse();
  80. TNode * Find(TNodeCompareValue((* Compare)), void const * findval) const;
  81. long Pos(TNode const * t) const
  82. {
  83. long n;
  84. TNode * c;
  85. MCSASSERT(this);
  86. for (c=head, n=0; c!=t; c=c->right,n++);
  87. return c ? n : -1;
  88. }
  89. TNode * Head() const { MCSASSERT(this); return head; }
  90. DWORD Count() const { MCSASSERT (this); return count; }
  91. protected:
  92. DWORD Validate( TNode ** pErrorNode );
  93. };
  94. /*
  95. A dynamically sortable collection of TNode entries. The TNodes are arranged
  96. in either of two forms: a sorted linked linear list or a binary tree. The
  97. current data data structure (form) is stored in the listType member.
  98. The form of the list may be easily changed from binary tree to sorted list or
  99. vice versa. The following member functions support these transformations:
  100. ToSorted Converts the tree form into a sorted linear list form without
  101. need for comparisons; the order is preserved.
  102. SortedToTree Converts the sorted linear list form into a perfectly
  103. balanced binary tree without comparisons; the order is preserved.
  104. UnsortedToTree Converts the sorted linear list form into a binary tree
  105. that is not necesarily balanced. It uses the PCompare function
  106. to form the order of the tree. Thus if the list order closely
  107. matches the PCompare directed order, the resulting tree will be
  108. grossly unbalanced. This has a bearing on the performance and
  109. memory requirements of the ToSorted function which is recursive.
  110. So be careful, especially with large lists.
  111. Sort This resorts either a tree or list form according to the argument
  112. pCompare function pointer provided. Note the above admonition.
  113. In either form, exposed are also Insert and Remove member functions. The functions
  114. are wrappers for TreeInsert and SortedInsert function depending upon the current
  115. list type.
  116. */
  117. enum TNodeListType { TNodeTypeError, TNodeTypeUnsorted, TNodeTypeLinear, TNodeTypeTree };
  118. class TNodeListSortable : public TNodeList
  119. {
  120. private:
  121. TNode * lastInsert;
  122. static TNode * // ret-head of sorted list
  123. TreeToSortedList(
  124. TNode * top ,// i/o-top of [sub]tree to squash
  125. TNode ** newhead ,// out-leftmost branch from tree
  126. TNode ** newtail // out-rightmost branch from tree
  127. );
  128. static TNode * // ret-middle of list (head of Btree)
  129. ListSortedToTree(
  130. TNode * top // i/o-top of [sub]list to tree-ify
  131. );
  132. BOOL CountTree( TNode * pCurrentTop, DWORD * pCount);
  133. protected:
  134. TNodeListType listType;
  135. TNodeCompare((* PCompare));
  136. public:
  137. TNodeListSortable(TNodeCompare((* pCompare)) = NULL, TNodeListType t = TNodeTypeLinear)
  138. { lastInsert = NULL; listType = t; PCompare = pCompare; };
  139. ~TNodeListSortable() { if ( IsTree() ) ToSorted(); }
  140. void CompareSet(TNodeCompare((* pCompare))) { PCompare = pCompare; }
  141. void TypeSetTree() { listType = TNodeTypeTree; }
  142. void TypeSetSorted() { listType = TNodeTypeLinear; }
  143. void TreeInsert(TNode * item, short * depth);
  144. TNode ** TreeFindInsert(TNode const * item, short * depth);
  145. BOOL TreeInsertIfNew(TNode * item, short * depth)
  146. {
  147. TNode ** r=TreeFindInsert(item,depth);
  148. if (*r) return FALSE;
  149. *r=item;
  150. item->left = item->right = NULL;
  151. count++;
  152. return TRUE;
  153. }
  154. void TreeInsert(TNode * item) { short discard; TreeInsert(item, &discard); };
  155. void TreeRemove(TNode * item);
  156. TNode * TreeFind(TNodeCompareValue((* pCompare)), void const * findval) const;
  157. void SortedInsert(TNode * t);
  158. BOOL SortedInsertIfNew(TNode * t);
  159. TNode * SortedFindInsertBefore(TNode * item, BOOL * exists);
  160. void Insert(TNode * t) { if (IsTree()) TreeInsert(t); else SortedInsert(t); }
  161. BOOL InsertIfNew(TNode * t) { short depth; if (IsTree()) return TreeInsertIfNew(t,&depth);
  162. else return SortedInsertIfNew(t); }
  163. virtual void Remove(TNode * t) { if (t==lastInsert) lastInsert = NULL;
  164. if (IsTree()) TreeRemove(t);
  165. else TNodeList::Remove(t); };
  166. // void Delete(TNode * t) { Remove(t); delete t; };
  167. TNode * Find(TNodeCompareValue((* pCompare)), void const * findval) const
  168. { if (IsTree()) return TreeFind(pCompare,findval); return TNodeList::Find(pCompare,findval); }
  169. void SortedToTree()
  170. {
  171. MCSASSERTSZ( !IsTree(), "TNodeListSortable::SortedToTree - list is already a tree" );
  172. if ( !IsTree() )
  173. {
  174. head = ListSortedToTree( head );
  175. tail = NULL;
  176. listType = TNodeTypeTree;
  177. }
  178. }
  179. TNode * UnsortedToTree();
  180. void ToSorted()
  181. {
  182. MCSASSERTSZ( IsTree(), "TNodeListSortable::ToSorted - list is not a tree" );
  183. if ( IsTree() )
  184. {
  185. MCSASSERT( ValidateTree() );
  186. if ( head )
  187. TreeToSortedList( head, &head, &tail );
  188. listType = TNodeTypeLinear;
  189. }
  190. }
  191. void Balance()
  192. {
  193. MCSASSERTSZ( IsTree(), "TNodeListSortable::Balance - list is not a tree" );
  194. if ( IsTree() )
  195. {
  196. ToSorted();
  197. SortedToTree();
  198. }
  199. }
  200. void Sort(TNodeCompare((* pCompare))) { TNodeListType lt = listType;
  201. if (lt == TNodeTypeTree) ToSorted();
  202. CompareSet(pCompare);
  203. UnsortedToTree();
  204. if (lt != TNodeTypeTree) ToSorted(); }
  205. void SortedToScrambledTree();
  206. BOOL IsTree() const { return listType == TNodeTypeTree; };
  207. BOOL ValidateTree( );
  208. DWORD ValidateList( TNode ** pErrorNode = NULL)
  209. {
  210. MCSASSERT(listType != TNodeTypeTree);
  211. return Validate(pErrorNode);
  212. }
  213. };
  214. /*
  215. TNodeListEnum is a 'friend' of TNode used to enumerate/iterate through
  216. TNodeList in linear list form. It is an error to give it a TNodeList in
  217. tree form.
  218. */
  219. class TNodeListEnum
  220. {
  221. protected:
  222. TNodeList const * list; // list for which enums are carried out
  223. TNode * curr; // last node processed by enum functions
  224. public:
  225. TNodeListEnum() { list = NULL; curr = NULL; };
  226. TNodeListEnum(TNodeList const * tlist) { Open(tlist); }
  227. ~TNodeListEnum() { };
  228. void Open(TNodeList const * tlist) { list = tlist; Top(); };
  229. TNode * OpenFirst(TNodeList const * tlist) { list = tlist; return First(); }
  230. TNode * First() { return curr = list->head; };
  231. TNode * Next() { return curr = (curr ? curr->right : list->head); }
  232. TNode * Prev() { return curr = (curr ? curr->left : list->tail); }
  233. TNode * Last() { return curr = list->tail; };
  234. TNode * Get() { return curr; }
  235. TNode * Get(long n) { TNode * c; Top(); while ( n-->=0 && (c=Next()) ); return c; }
  236. void Close() { curr = NULL; }
  237. void Top() { curr = NULL; };
  238. };
  239. // provides optimized direct accessibility by ordinal to TNodeList at some
  240. // expense to sequential traversal performance
  241. class TNodeListOrdEnum : public TNodeListEnum
  242. {
  243. private:
  244. long nCurr;
  245. public:
  246. TNodeListOrdEnum() : TNodeListEnum() { nCurr = -1; };
  247. TNodeListOrdEnum(TNodeList const * tlist) { Open(tlist); };
  248. void Open(TNodeList const * tlist) { TNodeListEnum::Open(tlist); nCurr = -1; };
  249. TNode * OpenFirst(TNodeList const * tlist) { Open(tlist); return First(); }
  250. TNode * First() { nCurr = list->head ? 0 : -1; return TNodeListEnum::First(); };
  251. TNode * Next() { TNode * t = TNodeListEnum::Next(); if (curr) nCurr++; else nCurr=-1; return t; }
  252. TNode * Prev() { TNode * t = TNodeListEnum::Prev(); if (curr) if (nCurr>0) nCurr--; else nCurr=list->Count()-1; else nCurr=-1; return t; }
  253. void Close() { nCurr=-1; TNodeListEnum::Close(); }
  254. void Top() { nCurr=-1; TNodeListEnum::Top(); };
  255. long Pos() const { return nCurr; };
  256. long Pos(TNode const * t) { long n; TNode * c;
  257. for (c=list->head, n=0; c!=t; c=c->right,n++);
  258. if (c) nCurr=n; else nCurr=-1; curr=c; return nCurr; }
  259. TNode * Get(long n);
  260. };
  261. /*
  262. TNodeTreeEnum enumerates a TNodeListSortable that is in tree form. It is an error
  263. to give it a TNodeListSortable that is in linear list form.
  264. */
  265. enum TNodeTreeStackEntryState {Snone, Sleft, Sused, Sright, SComplete};
  266. struct TNodeTreeStackEntry
  267. {
  268. TNode * save;
  269. TNodeTreeStackEntryState state;
  270. };
  271. const TREE_STACKSIZE = 200; // default maximum recursion depth
  272. class TNodeTreeEnum
  273. {
  274. private:
  275. TNodeTreeStackEntry * stackBase,
  276. * stackPos;
  277. int stackSize;
  278. void Push(TNode * item) { (++stackPos)->save = item; stackPos->state = Snone; };
  279. BOOL Pop() { return --stackPos >= stackBase; };
  280. void StackAlloc(int stacksize)
  281. { stackSize = stacksize;
  282. stackBase = new TNodeTreeStackEntry[stacksize]; };
  283. protected:
  284. TNode * top; // tree top for which enums are carried out
  285. TNode * curr; // next node processed by enum functions
  286. public:
  287. TNodeTreeEnum(int stacksize = TREE_STACKSIZE) { top = NULL; StackAlloc(stacksize); };
  288. TNodeTreeEnum(TNodeListSortable const * tlist, int stacksize = TREE_STACKSIZE) { StackAlloc(stacksize); Open(tlist); };
  289. ~TNodeTreeEnum() { Close(); delete [] stackBase; };
  290. void Open(TNodeListSortable const * tlist)
  291. {
  292. top = tlist->head;
  293. stackPos = stackBase;
  294. stackPos->save = NULL;
  295. stackPos->state = SComplete;
  296. if ( top )
  297. Push(top);
  298. }
  299. TNode * First();
  300. TNode * FirstAfter(TNodeCompareValue((* Compare) ), void const * findVal);
  301. TNode * OpenFirst(TNodeListSortable const * tlist) { Open(tlist); return Next(); }
  302. TNode * Next();
  303. TNode * StackTop() { return stackPos->save; }
  304. void Close() { stackPos = stackBase; }
  305. };
  306. #endif // MCSINC_TNode_hpp
  307. // TNode.hpp - end of file