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.

393 lines
11 KiB

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