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.

328 lines
9.4 KiB

  1. #include <precomp.h>
  2. /*
  3. redblack.c
  4. Implementation of red-black binary tree insertion, deletion, and search.
  5. This algorithm efficiently guarantees that the tree depth will never exceed
  6. 2*Lg(N), so a one million node tree would have a worst case depth of 40.
  7. This insertion implementation is non-recursive and very efficient (the
  8. average insertion speed is less than twice the average search speed).
  9. Author: Tom McGuire (tommcg) 1/98
  10. Copyright (C) Microsoft, 1998.
  11. 2/98, modified this version of redblack.c for debug symbol lookups.
  12. */
  13. #ifndef PATCH_APPLY_CODE_ONLY
  14. //
  15. // Rather than storing NULL links as NULL, we point NULL links to a special
  16. // "Empty" node which is always black and its children links point to itself.
  17. // We do this to simplify the color testing for children and grandchildren
  18. // such that any link can be dereferenced and even double-dereferenced without
  19. // explicitly checking for NULL. The empty node must be colored black.
  20. //
  21. const SYMBOL_NODE SymRBEmptyNode = { RBNIL, RBNIL };
  22. VOID
  23. SymRBInitTree(
  24. IN OUT PSYMBOL_TREE Tree,
  25. IN HANDLE SubAllocator
  26. )
  27. {
  28. #if defined( DEBUG ) || defined( DBG ) || defined( TESTCODE )
  29. Tree->CountNodes = 0;
  30. Tree->DeletedAny = FALSE;
  31. #endif
  32. Tree->Root = RBNIL;
  33. Tree->SubAllocator = SubAllocator;
  34. }
  35. PSYMBOL_NODE
  36. SymRBFind(
  37. IN PSYMBOL_TREE Tree,
  38. IN LPSTR SymbolName
  39. )
  40. {
  41. PSYMBOL_NODE Node = Tree->Root;
  42. ULONG Hash;
  43. int Compare;
  44. Hash = HashName( SymbolName );
  45. while ( Node != RBNIL ) {
  46. if ( Hash < Node->Hash ) {
  47. Node = Node->Left;
  48. }
  49. else if ( Hash > Node->Hash ) {
  50. Node = Node->Right;
  51. }
  52. else {
  53. Compare = strcmp( SymbolName, Node->SymbolName );
  54. if ( Compare == 0 ) {
  55. return Node;
  56. }
  57. else if ( Compare < 0 ) {
  58. Node = Node->Left;
  59. }
  60. else {
  61. Node = Node->Right;
  62. }
  63. }
  64. }
  65. return NULL;
  66. }
  67. PSYMBOL_NODE
  68. SymRBInsert(
  69. IN OUT PSYMBOL_TREE Tree,
  70. IN LPSTR SymbolName,
  71. IN ULONG Rva
  72. )
  73. {
  74. PSYMBOL_NODE * Stack[ MAX_DEPTH ];
  75. PSYMBOL_NODE **StackPointer = Stack;
  76. PSYMBOL_NODE * Link;
  77. PSYMBOL_NODE Node;
  78. PSYMBOL_NODE Sibling;
  79. PSYMBOL_NODE Parent;
  80. PSYMBOL_NODE Child;
  81. PSYMBOL_NODE NewNode;
  82. ULONG NameLength;
  83. ULONG Hash;
  84. int Compare;
  85. ASSERT( ! Tree->DeletedAny );
  86. Hash = HashName( SymbolName );
  87. //
  88. // Walk down the tree to find either an existing node with the same key
  89. // (in which case we simply return) or the insertion point for the new
  90. // node. At each traversal we need to store the address of the link to
  91. // the next node so we can retrace the traversal path for balancing.
  92. // The speed of insertion is highly dependent on traversing the tree
  93. // quickly, so all balancing operations are deferred until after the
  94. // traversal is complete.
  95. //
  96. *StackPointer++ = &Tree->Root;
  97. Node = Tree->Root;
  98. while ( Node != RBNIL ) {
  99. if ( Hash < Node->Hash ) {
  100. *StackPointer++ = &Node->Left;
  101. Node = Node->Left;
  102. }
  103. else if ( Hash > Node->Hash ) {
  104. *StackPointer++ = &Node->Right;
  105. Node = Node->Right;
  106. }
  107. else {
  108. Compare = strcmp( SymbolName, Node->SymbolName );
  109. if ( Compare == 0 ) {
  110. //
  111. // Found a matching symbol.
  112. //
  113. return Node;
  114. }
  115. else if ( Compare < 0 ) {
  116. *StackPointer++ = &Node->Left;
  117. Node = Node->Left;
  118. }
  119. else {
  120. *StackPointer++ = &Node->Right;
  121. Node = Node->Right;
  122. }
  123. }
  124. }
  125. //
  126. // Didn't find a matching entry, so allocate a new node and add it
  127. // to the tree.
  128. //
  129. NameLength = (ULONG) strlen( SymbolName ) + 1;
  130. NewNode = SubAllocate( Tree->SubAllocator, ( sizeof( SYMBOL_NODE ) + NameLength ));
  131. if ( NewNode == NULL ) {
  132. return NULL;
  133. }
  134. #if defined( DEBUG ) || defined( DBG ) || defined( TESTCODE )
  135. Tree->CountNodes++;
  136. #endif
  137. NewNode->Left = RBNIL;
  138. NewNode->Right = RBNIL;
  139. NewNode->Hash = Hash;
  140. NewNode->RvaWithStatusBits = Rva | 0x80000000; // make new node RED, not hit
  141. memcpy( NewNode->SymbolName, SymbolName, NameLength );
  142. //
  143. // Insert new node under last link we traversed. The top of the stack
  144. // contains the address of the last link we traversed.
  145. //
  146. Link = *( --StackPointer );
  147. *Link = NewNode;
  148. //
  149. // Now walk back up the traversal chain to see if any balancing is
  150. // needed. This terminates in one of three ways: we walk all the way
  151. // up to the root (StackPointer == Stack), or find a black node that
  152. // we don't need to change (no balancing needs to be done above a
  153. // black node), or we perform a balancing rotation (only one necessary).
  154. //
  155. Node = NewNode;
  156. Child = RBNIL;
  157. while ( StackPointer > Stack ) {
  158. Link = *( --StackPointer );
  159. Parent = *Link;
  160. //
  161. // Node is always red here.
  162. //
  163. if ( IS_BLACK( Parent )) {
  164. Sibling = ( Parent->Left == Node ) ? Parent->Right : Parent->Left;
  165. if ( IS_RED( Sibling )) {
  166. //
  167. // Both Node and its Sibling are red, so change them both to
  168. // black and make the Parent red. This essentially moves the
  169. // red link up the tree so balancing can be performed at a
  170. // higher level.
  171. //
  172. // Pb Pr
  173. // / \ ----> / \
  174. // Cr Sr Cb Sb
  175. //
  176. MARK_BLACK( Sibling );
  177. MARK_BLACK( Node );
  178. MARK_RED( Parent );
  179. }
  180. else {
  181. //
  182. // This is a terminal case. The Parent is black, and it's
  183. // not going to be changed to red. If the Node's child is
  184. // red, we perform an appropriate rotation to balance the
  185. // tree. If the Node's child is black, we're done.
  186. //
  187. if ( IS_RED( Child )) {
  188. if ( Node->Left == Child ) {
  189. if ( Parent->Left == Node ) {
  190. //
  191. // Pb Nb
  192. // / \ / \
  193. // Nr Z to Cr Pr
  194. // / \ / \
  195. // Cr Y Y Z
  196. //
  197. MARK_RED( Parent );
  198. Parent->Left = Node->Right;
  199. Node->Right = Parent;
  200. MARK_BLACK( Node );
  201. *Link = Node;
  202. }
  203. else {
  204. //
  205. // Pb Cb
  206. // / \ / \
  207. // W Nr to Pr Nr
  208. // / \ / \ / \
  209. // Cr Z W X Y Z
  210. // / \
  211. // X Y
  212. //
  213. MARK_RED( Parent );
  214. Parent->Right = Child->Left;
  215. Child->Left = Parent;
  216. Node->Left = Child->Right;
  217. Child->Right = Node;
  218. MARK_BLACK( Child );
  219. *Link = Child;
  220. }
  221. }
  222. else {
  223. if ( Parent->Right == Node ) {
  224. MARK_RED( Parent );
  225. Parent->Right = Node->Left;
  226. Node->Left = Parent;
  227. MARK_BLACK( Node );
  228. *Link = Node;
  229. }
  230. else {
  231. MARK_RED( Parent );
  232. Parent->Left = Child->Right;
  233. Child->Right = Parent;
  234. Node->Right = Child->Left;
  235. Child->Left = Node;
  236. MARK_BLACK( Child );
  237. *Link = Child;
  238. }
  239. }
  240. }
  241. return NewNode;
  242. }
  243. }
  244. Child = Node;
  245. Node = Parent;
  246. }
  247. //
  248. // We bubbled red up to the root -- restore it to black.
  249. //
  250. MARK_BLACK( Tree->Root );
  251. return NewNode;
  252. }
  253. #endif // ! PATCH_APPLY_CODE_ONLY