Leaked source code of windows server 2003
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.

335 lines
11 KiB

  1. /**********************************************************************/
  2. /** Microsoft LAN Manager **/
  3. /** Copyright(c) Microsoft Corp., 1991 **/
  4. /**********************************************************************/
  5. /*
  6. aheap.hxx
  7. HEAP_BASE declaration and heap subclass macro definitions
  8. FILE HISTORY:
  9. rustanl 05-Jul-1991 Created
  10. rustanl 15-Jul-1991 Code review changes (no functional
  11. changes). CR attended by BenG,
  12. ChuckC, JimH, Hui-LiCh, TerryK,
  13. RustanL.
  14. */
  15. #ifndef _AHEAP_HXX_
  16. #define _AHEAP_HXX_
  17. #include "uibuffer.hxx"
  18. /*************************************************************************
  19. NAME: HEAP_BASE
  20. SYNOPSIS: Heap data structure base class
  21. INTERFACE: HEAP_BASE() - Constructor
  22. ~HEAP_BASE() - Destructor
  23. QueryCount() - Returns the number of items in the heap
  24. SetAllocCount() - Resizes the heap to be able to hold some
  25. given number of items
  26. Trim() - Trims the heap to only keep enough space
  27. for the current heap items.
  28. Interface of the derived subclasses:
  29. AddItem() - Adds an item to the heap. If heap is
  30. in auto-readjust mode, the heap will
  31. automatically be readjusted; otherwise,
  32. it will not.
  33. RemoveTopItem() - Removes the top item, returns it, and
  34. readjusts the heap.
  35. Method is only valid when the heap is
  36. non-empty and is in the auto-readjusting
  37. mode.
  38. PeekTopItem() - Returns the top item of the heap without
  39. removing it. Does not alter the heap.
  40. Method is only valid when the heap is
  41. non-empty and is in the auto-readjusting
  42. mode.
  43. Adjust() - Puts the heap in auto-readjust mode, and
  44. adjusts the heap.
  45. PARENT: BASE
  46. USES: BUFFER
  47. NOTES: The top item in the heap is the smallest one according to
  48. the subclass-defined Compare method. Compare takes a
  49. pointer to another item of the same class, and returns
  50. < 0 if *this < *pThat
  51. 0 if *this = *pThat
  52. > 1 if *this > *pThat
  53. AddItem requires O(1) time when not in auto-readjust mode,
  54. and O(log n) time in auto-readjust mode (where n is
  55. the number of items in the heap)
  56. RemoveTopItem requires O(log n) time.
  57. Adjust runs in O(n) time.
  58. Hence, if all items are known at the time the heap is
  59. constructed, the fastest way to initialize the heap is
  60. to start not in the auto-readjusting mode, then call
  61. AddItem for each item, and finally call Adjust.
  62. HISTORY:
  63. rustanl 05-Jul-1991 Created
  64. **************************************************************************/
  65. DLL_CLASS HEAP_BASE : public BASE
  66. {
  67. private:
  68. int _cItems;
  69. BOOL _fAutoReadjust;
  70. BUFFER _buf;
  71. protected:
  72. HEAP_BASE( int cInitialAllocCount = 0, BOOL fAutoReadjust = TRUE );
  73. ~HEAP_BASE();
  74. APIERR I_AddItem( VOID * pv );
  75. void * I_RemoveTopItem( void );
  76. void * PeekItem( int i ) const;
  77. void SetItem( int i, void * pv );
  78. /* The following inline methods are used by subclasses
  79. * to enhance readability. Note, it is up to the caller to make
  80. * sure the item queried for exists before using the return
  81. * value; these methods just do the calculations.
  82. */
  83. int QueryParent( int iChild ) const
  84. { return (iChild + 1) / 2 - 1; }
  85. int QueryLeftChild( int iParent ) const
  86. { return 2 * (iParent + 1) - 1; }
  87. int QueryRightSibling( int iLeftSibling ) const
  88. { return iLeftSibling + 1; }
  89. int QueryLastParent( void ) const
  90. /* Return the parent of the last item. */
  91. { return QueryParent( QueryCount() - 1 ); }
  92. int QueryFirstLeaf( void ) const
  93. /* Return the node following the parent of the last child node.
  94. * Note, intermediate values may not correspond to existing
  95. * items.
  96. */
  97. { return QueryParent( QueryCount() - 1 ) + 1; }
  98. BOOL IsRoot( int i ) const
  99. { return ( i == 0 ); }
  100. BOOL IsAutoReadjusting( void ) const
  101. { return _fAutoReadjust; }
  102. void SetAutoReadjust( BOOL f )
  103. { _fAutoReadjust = f; }
  104. public:
  105. int QueryCount( void ) const
  106. { return _cItems; }
  107. APIERR SetAllocCount( int cNewAllocCount );
  108. void Trim( void );
  109. }; // class HEAP_BASE
  110. #define DECLARE_HEAP_OF( type ) \
  111. \
  112. class type##_HEAP : public HEAP_BASE \
  113. { \
  114. private: \
  115. void AdjustUpwards( int i ); \
  116. void AdjustDownwards( int i ); \
  117. \
  118. public: \
  119. type##_HEAP( int cInitialAllocCount = 0, BOOL fAutoReadjust = TRUE ) \
  120. : HEAP_BASE( cInitialAllocCount, fAutoReadjust ) {} \
  121. \
  122. APIERR AddItem( type * pt ); \
  123. type * RemoveTopItem( void ); \
  124. type * PeekTopItem( void ) const \
  125. { UIASSERT( IsAutoReadjusting()); return (type *)PeekItem( 0 ); } \
  126. \
  127. void Adjust( void ); \
  128. \
  129. }; /* type##_HEAP */
  130. #define DEFINE_HEAP_OF( type ) \
  131. \
  132. void type##_HEAP::AdjustUpwards( int i ) \
  133. { \
  134. UIASSERT( 0 <= i && i < QueryCount()); \
  135. \
  136. /* Loop invariant: */ \
  137. /* 0 <= i < QueryCount() && */ \
  138. /* Item i's left and right subtrees have the heap property */ \
  139. \
  140. type * const pt = (type *)PeekItem( i ); \
  141. while ( ! IsRoot( i )) \
  142. { \
  143. int iParent = QueryParent( i ); \
  144. type * ptParent = (type *)PeekItem( iParent ); \
  145. \
  146. if ( ptParent->Compare( pt ) <= 0 ) \
  147. { \
  148. /* *ptParent is at most *pt. Now the heap is */ \
  149. /* completely adjusted. */ \
  150. break; \
  151. } \
  152. \
  153. /* Move parent down (in effect, swap item with its parent) */ \
  154. SetItem( i, ptParent ); \
  155. \
  156. i = iParent; \
  157. } \
  158. \
  159. SetItem( i, pt ); \
  160. \
  161. } /* type##_HEAP::AdjustUpwards */ \
  162. \
  163. \
  164. void type##_HEAP::AdjustDownwards( int i ) \
  165. { \
  166. UIASSERT( 0 <= i && i < QueryCount()); \
  167. \
  168. type * const pt = (type *)PeekItem( i ); \
  169. \
  170. /* We get and cache the index of the first leaf node (i.e., the */ \
  171. /* leaf node with the smallest index). We know such an item */ \
  172. /* exists, because we know the heap contains items, since we */ \
  173. /* assume that i is the index of an existing item. */ \
  174. int iFirstLeaf = QueryFirstLeaf(); \
  175. \
  176. while ( i < iFirstLeaf ) \
  177. { \
  178. /* Since i is less than the index of the first leaf, it */ \
  179. /* must be the index of a parent node. */ \
  180. \
  181. /* Since i is a parent, there must be a left child. */ \
  182. int iMinChild = QueryLeftChild( i ); \
  183. UIASSERT( 0 <= iMinChild && iMinChild < QueryCount()); \
  184. type * ptMinChild = (type *)PeekItem( iMinChild ); \
  185. if ( QueryRightSibling( iMinChild ) < QueryCount()) \
  186. { \
  187. /* There is also a right child, since computing the */ \
  188. /* index of the right sibling yields a valid index. */ \
  189. \
  190. /* Pick the smaller of the two to be the minimum */ \
  191. /* child. */ \
  192. UIASSERT( 0 <= QueryRightSibling( iMinChild ) && \
  193. QueryRightSibling( iMinChild ) < QueryCount()); \
  194. type * ptRightChild = (type *)PeekItem( \
  195. QueryRightSibling( iMinChild )); \
  196. if ( ptRightChild->Compare( ptMinChild ) < 0 ) \
  197. { \
  198. /* The right child is smaller. Use it. */ \
  199. iMinChild = QueryRightSibling( iMinChild ); \
  200. ptMinChild = ptRightChild; \
  201. } \
  202. } \
  203. \
  204. if ( pt->Compare( ptMinChild ) <= 0 ) \
  205. { \
  206. /* *pt is at most *ptMinChild. Hence, heap now has */ \
  207. /* proper heap property. */ \
  208. break; \
  209. } \
  210. \
  211. /* Move child up (in effect, swap item with its min child) */ \
  212. SetItem( i, ptMinChild ); \
  213. \
  214. i = iMinChild; \
  215. } \
  216. \
  217. SetItem( i, pt ); \
  218. \
  219. } /* type##_HEAP::AdjustDownwards */ \
  220. \
  221. \
  222. APIERR type##_HEAP::AddItem( type * pt ) \
  223. { \
  224. /* Add the item to the bottom of the heap */ \
  225. \
  226. int iNew = QueryCount(); \
  227. \
  228. APIERR err = I_AddItem( pt ); \
  229. if ( err != NERR_Success ) \
  230. return err; \
  231. \
  232. /* If heap is in the auto-readjusting state, restore */ \
  233. /* the heap property by adjusting the heap from the */ \
  234. /* new item upwards */ \
  235. \
  236. if ( IsAutoReadjusting()) \
  237. AdjustUpwards( iNew ); \
  238. \
  239. return NERR_Success; \
  240. \
  241. } /* type##_HEAP::AddItem */ \
  242. \
  243. \
  244. void type##_HEAP::Adjust( void ) \
  245. { \
  246. /* If the heap already is in the auto-readjusting state, */ \
  247. /* it is already fully adjusted. */ \
  248. if ( IsAutoReadjusting()) \
  249. return; \
  250. \
  251. /* From now on, the heap will be auto-readjust. */ \
  252. SetAutoReadjust( TRUE ); \
  253. \
  254. /* If the heap contains any items at all, adjust them in a */ \
  255. /* bottom-up fashion. In different terms, this creates */ \
  256. /* small heaps and then merges them. Note, this */ \
  257. /* operation, which is commonly used after inserting all */ \
  258. /* items into a non-auto-readjusting heap, runs in O(n) */ \
  259. /* time! Compare this to the O(n log n) needed if each */ \
  260. /* item was added to an auto-readjusting heap. (A proof */ \
  261. /* of the O(n) running time and the correctness of this */ \
  262. /* approach is left to the reader.) */ \
  263. if ( QueryCount() > 0 ) \
  264. { \
  265. int i = QueryFirstLeaf(); \
  266. while ( ! IsRoot( i )) \
  267. { \
  268. i--; \
  269. AdjustDownwards( i ); \
  270. } \
  271. } \
  272. \
  273. } /* type##_HEAP::Adjust */ \
  274. \
  275. \
  276. type * type##_HEAP::RemoveTopItem( void ) \
  277. { \
  278. /* Only allowed to be called on heaps in the auto-readjusting */ \
  279. /* state. This is asserted in I_RemoveTopItem, so that line */ \
  280. /* numbers in assertion failures make better sense at run- */ \
  281. /* time. */ \
  282. \
  283. /* Get the top item, and move the bottom-most item to the top */ \
  284. \
  285. type * ptReturnItem = (type *)I_RemoveTopItem(); \
  286. \
  287. /* Restore the heap property, provided there are items left in */ \
  288. /* the heap. */ \
  289. \
  290. if ( QueryCount() > 0 ) \
  291. AdjustDownwards( 0 ); \
  292. \
  293. return ptReturnItem; \
  294. \
  295. } /* type##_HEAP::RemoveTopItem */
  296. #endif // _AHEAP_HXX_