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.

597 lines
14 KiB

  1. /*
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. splay.cpp
  5. Abstract:
  6. Splay trees are simpler, more space-efficient, more flexible, and faster than any other balanced tree
  7. scheme for storing an ordered set. This data structure satisfies all the invariants of a binary tree.
  8. Searching, insertion, deletion, and many other operations can all be done with amortized logarithmic
  9. performance. Since the trees adapt to the sequence of requests, their performance on real access
  10. patterns is typically even better.
  11. Author:
  12. Vishnu Patankar (vishnup) 15-Aug-2000 created
  13. Jin Huang (jinhuang) 06-Apr-2001 modified for supporting string value and to handle multiple clients
  14. --*/
  15. #include "splay.h"
  16. //#include "dumpnt.h"
  17. #define SCEP_MIN(a, b) (a < b ? a : b)
  18. static
  19. PSCEP_SPLAY_NODE
  20. ScepSplaySplay(
  21. IN SCEP_NODE_VALUE_TYPE Value,
  22. IN PSCEP_SPLAY_NODE pNodeToSplayAbout,
  23. IN PSCEP_SPLAY_NODE pSentinel,
  24. IN SCEP_NODE_VALUE_TYPE Type
  25. );
  26. int
  27. ScepValueCompare(
  28. PVOID pValue1,
  29. PVOID pValue2,
  30. SCEP_NODE_VALUE_TYPE Type
  31. );
  32. static VOID
  33. ScepSplayFreeNodes(
  34. IN PSCEP_SPLAY_NODE pNode,
  35. IN PSCEP_SPLAY_NODE pSentinel
  36. );
  37. PSCEP_SPLAY_TREE
  38. ScepSplayInitialize(
  39. SCEP_NODE_VALUE_TYPE Type
  40. )
  41. /*
  42. Routine Description:
  43. This function initializes the splay tree with a sentinel (equivalent to a NULL ptr).
  44. Arguments:
  45. Type - the type for the splay value
  46. Return Value:
  47. Pointer to the splay tree root.
  48. */
  49. {
  50. if ( Type != SplayNodeSidType && Type != SplayNodeStringType ) {
  51. return NULL;
  52. }
  53. PSCEP_SPLAY_TREE pRoot = (PSCEP_SPLAY_TREE)LocalAlloc(LPTR, sizeof( SCEP_SPLAY_TREE ) );
  54. if ( pRoot ) {
  55. pRoot->Sentinel = (PSCEP_SPLAY_NODE) LocalAlloc(LPTR, sizeof( SCEP_SPLAY_NODE ) );
  56. if ( pRoot->Sentinel ) {
  57. pRoot->Sentinel->Left = pRoot->Sentinel->Right = pRoot->Sentinel;
  58. pRoot->Root = pRoot->Sentinel;
  59. pRoot->Type = Type;
  60. return pRoot;
  61. } else {
  62. LocalFree(pRoot);
  63. }
  64. }
  65. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  66. return NULL;
  67. }
  68. VOID
  69. ScepSplayFreeTree(
  70. IN PSCEP_SPLAY_TREE *ppTreeRoot,
  71. IN BOOL bDestroyTree
  72. )
  73. /*
  74. Routine Description:
  75. This function frees the splay tree including the satellite data "Value".
  76. Arguments:
  77. ppTreeRoot - address of the root of the tree
  78. bDestroyTree - if the tree root should be destroyed (freed)
  79. Return Value:
  80. VOID
  81. */
  82. {
  83. if ( ppTreeRoot == NULL || *ppTreeRoot == NULL )
  84. return;
  85. ScepSplayFreeNodes( (*ppTreeRoot)->Root, (*ppTreeRoot)->Sentinel );
  86. if ( bDestroyTree ) {
  87. //
  88. // free Sentinel
  89. //
  90. LocalFree( (*ppTreeRoot)->Sentinel);
  91. LocalFree( *ppTreeRoot );
  92. *ppTreeRoot = NULL;
  93. } else {
  94. ( *ppTreeRoot)->Root = (*ppTreeRoot)->Sentinel;
  95. }
  96. return;
  97. }
  98. static VOID
  99. ScepSplayFreeNodes(
  100. IN PSCEP_SPLAY_NODE pNode,
  101. IN PSCEP_SPLAY_NODE pSentinel
  102. )
  103. {
  104. if ( pNode != pSentinel ) {
  105. ScepSplayFreeNodes( pNode->Left, pSentinel );
  106. ScepSplayFreeNodes( pNode->Right, pSentinel );
  107. if (pNode->Value)
  108. LocalFree( pNode->Value );
  109. LocalFree (pNode);
  110. }
  111. }
  112. static PSCEP_SPLAY_NODE
  113. ScepSplaySingleRotateWithLeft(
  114. IN PSCEP_SPLAY_NODE pNodeLeftRotate
  115. )
  116. /*
  117. Routine Description:
  118. This function can be called only if pNodeLeftRotate has a left child
  119. Perform a rotate between a node (pNodeLeftRotate) and its left child
  120. Update heights, then return new local root
  121. Arguments:
  122. pNodeLeftRotate - the node to rotate left about (local to this module)
  123. Return Value:
  124. New local root after rotation
  125. */
  126. {
  127. if ( pNodeLeftRotate == NULL ) return pNodeLeftRotate;
  128. PSCEP_SPLAY_NODE pNodeRightRotate;
  129. pNodeRightRotate = pNodeLeftRotate->Left;
  130. pNodeLeftRotate->Left = pNodeRightRotate->Right;
  131. pNodeRightRotate->Right = pNodeLeftRotate;
  132. return pNodeRightRotate;
  133. }
  134. static PSCEP_SPLAY_NODE
  135. ScepSplaySingleRotateWithRight(
  136. IN PSCEP_SPLAY_NODE pNodeRightRotate
  137. )
  138. /*
  139. Routine Description:
  140. This function can be called only if pNodeRightRotate has a right child
  141. Perform a rotate between a node (pNodeRightRotate) and its right child
  142. Update heights, then return new root
  143. Arguments:
  144. pNodeRightRotate - the node to rotate right about (local to this module)
  145. Return Value:
  146. New local root after rotation
  147. */
  148. {
  149. if ( pNodeRightRotate == NULL ) return pNodeRightRotate;
  150. PSCEP_SPLAY_NODE pNodeLeftRotate;
  151. pNodeLeftRotate = pNodeRightRotate->Right;
  152. pNodeRightRotate->Right = pNodeLeftRotate->Left;
  153. pNodeLeftRotate->Left = pNodeRightRotate;
  154. return pNodeLeftRotate;
  155. }
  156. static
  157. PSCEP_SPLAY_NODE
  158. ScepSplaySplay(
  159. IN PVOID Value,
  160. IN PSCEP_SPLAY_NODE pNodeToSplayAbout,
  161. IN PSCEP_SPLAY_NODE pSentinel,
  162. IN SCEP_NODE_VALUE_TYPE Type
  163. )
  164. /*
  165. Routine Description:
  166. This is really the key routine doing all the balancing (splaying)
  167. Top-down splay procedure that does not requiring Value to be in tree.
  168. Arguments:
  169. Value - the value to splay the tree about
  170. pNodeToSplayAbout - the node to splay about (external routines such as ScepSplayInsert()
  171. usually pass in the tree root). This routine is local to this module.
  172. pSentinel - the Sentinel (terminating node)
  173. Type - type of the splay values
  174. Return Value:
  175. New local root after rotation
  176. */
  177. {
  178. if ( pNodeToSplayAbout == NULL || pSentinel == NULL || Value == NULL) return pNodeToSplayAbout;
  179. SCEP_SPLAY_NODE Header;
  180. PSCEP_SPLAY_NODE LeftTreeMax, RightTreeMin;
  181. Header.Left = Header.Right = pSentinel;
  182. LeftTreeMax = RightTreeMin = &Header;
  183. pSentinel->Value = Value;
  184. int iRes=0;
  185. while ( 0 != (iRes=ScepValueCompare(Value, pNodeToSplayAbout->Value, Type)) ) {
  186. if ( 0 > iRes ) {
  187. if ( 0 > ScepValueCompare(Value, pNodeToSplayAbout->Left->Value, Type) )
  188. pNodeToSplayAbout = ScepSplaySingleRotateWithLeft( pNodeToSplayAbout );
  189. if ( pNodeToSplayAbout->Left == pSentinel )
  190. break;
  191. //
  192. // Link right
  193. //
  194. RightTreeMin->Left = pNodeToSplayAbout;
  195. RightTreeMin = pNodeToSplayAbout;
  196. pNodeToSplayAbout = pNodeToSplayAbout->Left;
  197. } else {
  198. if ( 0 < ScepValueCompare(Value, pNodeToSplayAbout->Right->Value, Type) )
  199. pNodeToSplayAbout = ScepSplaySingleRotateWithRight( pNodeToSplayAbout );
  200. if ( pNodeToSplayAbout->Right == pSentinel )
  201. break;
  202. //
  203. // Link left
  204. //
  205. LeftTreeMax->Right = pNodeToSplayAbout;
  206. LeftTreeMax = pNodeToSplayAbout;
  207. pNodeToSplayAbout = pNodeToSplayAbout->Right;
  208. }
  209. }
  210. //
  211. // reassemble
  212. //
  213. LeftTreeMax->Right = pNodeToSplayAbout->Left;
  214. RightTreeMin->Left = pNodeToSplayAbout->Right;
  215. pNodeToSplayAbout->Left = Header.Right;
  216. pNodeToSplayAbout->Right = Header.Left;
  217. //
  218. // reset Sentinel so that it does not point to some invalid buffer after
  219. // this function returns.
  220. //
  221. pSentinel->Value = NULL;
  222. return pNodeToSplayAbout;
  223. }
  224. DWORD
  225. ScepSplayInsert(
  226. IN PVOID Value,
  227. IN OUT PSCEP_SPLAY_TREE pTreeRoot,
  228. OUT BOOL *pbExists
  229. )
  230. /*
  231. Routine Description:
  232. This function is called to insert a particular Value
  233. Arguments:
  234. Value - the value to insert into the tree
  235. pTreeRoot - the node to splay about (usually pass in the tree root)
  236. pbExists - pointer to boolean that says if actual insertion was done or not
  237. Return Value:
  238. error code
  239. */
  240. {
  241. PSCEP_SPLAY_NODE pNewNode = NULL;
  242. NTSTATUS Status;
  243. DWORD dwValueLen;
  244. DWORD rc=ERROR_SUCCESS;
  245. if (pbExists)
  246. *pbExists = FALSE;
  247. if (Value == NULL || pTreeRoot == NULL ) {
  248. return ERROR_INVALID_PARAMETER;
  249. }
  250. //
  251. // check parameter type
  252. //
  253. switch (pTreeRoot->Type) {
  254. case SplayNodeSidType:
  255. if ( !RtlValidSid((PSID)Value) ) {
  256. return ERROR_INVALID_PARAMETER;
  257. }
  258. dwValueLen = RtlLengthSid((PSID)Value);
  259. break;
  260. case SplayNodeStringType:
  261. if ( *((PWSTR)Value) == L'\0') {
  262. return ERROR_INVALID_PARAMETER;
  263. }
  264. dwValueLen = (wcslen((PWSTR)Value)+1)*sizeof(TCHAR);
  265. break;
  266. default:
  267. return ERROR_INVALID_PARAMETER;
  268. }
  269. pNewNode = (PSCEP_SPLAY_NODE) LocalAlloc(LMEM_ZEROINIT, sizeof( SCEP_SPLAY_NODE ) );
  270. if ( pNewNode == NULL ) {
  271. return ERROR_NOT_ENOUGH_MEMORY;
  272. }
  273. pNewNode->dwByteLength = dwValueLen;
  274. pNewNode->Value = (PSID) LocalAlloc(LMEM_ZEROINIT, pNewNode->dwByteLength);
  275. if (pNewNode->Value == NULL) {
  276. LocalFree(pNewNode);
  277. return ERROR_NOT_ENOUGH_MEMORY;
  278. }
  279. switch (pTreeRoot->Type) {
  280. case SplayNodeSidType:
  281. Status = RtlCopySid(pNewNode->dwByteLength, (PSID)(pNewNode->Value), (PSID)Value);
  282. if (!NT_SUCCESS(Status)) {
  283. LocalFree(pNewNode->Value);
  284. LocalFree(pNewNode);
  285. return RtlNtStatusToDosError(Status);
  286. }
  287. break;
  288. case SplayNodeStringType:
  289. memcpy( pNewNode->Value, Value, dwValueLen );
  290. break;
  291. }
  292. if ( pTreeRoot->Root == pTreeRoot->Sentinel ) {
  293. pNewNode->Left = pNewNode->Right = pTreeRoot->Sentinel;
  294. pTreeRoot->Root = pNewNode;
  295. } else {
  296. pTreeRoot->Root = ScepSplaySplay( Value, pTreeRoot->Root, pTreeRoot->Sentinel, pTreeRoot->Type );
  297. int iRes;
  298. if ( 0 > (iRes=ScepValueCompare(Value, pTreeRoot->Root->Value, pTreeRoot->Type)) ) {
  299. pNewNode->Left = pTreeRoot->Root->Left;
  300. pNewNode->Right = pTreeRoot->Root;
  301. pTreeRoot->Root->Left = pTreeRoot->Sentinel;
  302. pTreeRoot->Root = pNewNode;
  303. } else if ( 0 < iRes ) {
  304. pNewNode->Right = pTreeRoot->Root->Right;
  305. pNewNode->Left = pTreeRoot->Root;
  306. pTreeRoot->Root->Right = pTreeRoot->Sentinel;
  307. pTreeRoot->Root = pNewNode;
  308. } else {
  309. //
  310. // Already in the tree
  311. //
  312. if (pbExists)
  313. *pbExists = TRUE;
  314. LocalFree(pNewNode->Value);
  315. LocalFree(pNewNode);
  316. return rc;
  317. }
  318. }
  319. return rc;
  320. }
  321. DWORD
  322. ScepSplayDelete(
  323. IN PVOID Value,
  324. IN PSCEP_SPLAY_TREE pTreeRoot
  325. )
  326. /*
  327. Routine Description:
  328. This function is called to delete a particular Value
  329. Arguments:
  330. Value - the value to insert into the tree
  331. pTreeRoot - the node to splay about (usually pass in the tree root)
  332. Return Value:
  333. New root after deletion and splaying
  334. */
  335. {
  336. if ( pTreeRoot == NULL ) return ERROR_INVALID_PARAMETER;
  337. PSCEP_SPLAY_NODE NewTree;
  338. if ( pTreeRoot->Root != pTreeRoot->Sentinel ) {
  339. //
  340. // strong type check
  341. //
  342. if ( ( pTreeRoot->Type != SplayNodeSidType &&
  343. pTreeRoot->Type != SplayNodeStringType ) ||
  344. ( pTreeRoot->Type == SplayNodeSidType &&
  345. !RtlValidSid((PSID)Value) ) ||
  346. ( pTreeRoot->Type == SplayNodeStringType &&
  347. *((PWSTR)Value) == L'\0' ) ) {
  348. //
  349. // invalid value/type
  350. //
  351. return ERROR_INVALID_PARAMETER;
  352. }
  353. pTreeRoot->Root = ScepSplaySplay( Value, pTreeRoot->Root, pTreeRoot->Sentinel, pTreeRoot->Type );
  354. if ( 0 == ScepValueCompare(Value, pTreeRoot->Root->Value, pTreeRoot->Type) ) {
  355. //
  356. // found it
  357. //
  358. if ( pTreeRoot->Root->Left == pTreeRoot->Sentinel )
  359. NewTree = pTreeRoot->Root->Right;
  360. else {
  361. NewTree = pTreeRoot->Root->Left;
  362. NewTree = ScepSplaySplay( Value, NewTree, pTreeRoot->Sentinel, pTreeRoot->Type );
  363. NewTree->Right = pTreeRoot->Root->Right;
  364. }
  365. if (pTreeRoot->Root->Value)
  366. LocalFree( pTreeRoot->Root->Value);
  367. LocalFree( pTreeRoot->Root );
  368. pTreeRoot->Root = NewTree;
  369. }
  370. }
  371. return ERROR_SUCCESS;
  372. }
  373. BOOL
  374. ScepSplayValueExist(
  375. IN PVOID Value,
  376. IN OUT PSCEP_SPLAY_TREE pTreeRoot
  377. )
  378. {
  379. PSCEP_SPLAY_NODE pMatchedNode = NULL;
  380. if ( pTreeRoot == NULL || Value == NULL) {
  381. return FALSE;
  382. }
  383. //
  384. // strong type check
  385. //
  386. if ( ( pTreeRoot->Type != SplayNodeSidType &&
  387. pTreeRoot->Type != SplayNodeStringType ) ||
  388. ( pTreeRoot->Type == SplayNodeSidType &&
  389. !RtlValidSid((PSID)Value) ) ||
  390. ( pTreeRoot->Type == SplayNodeStringType &&
  391. *((PWSTR)Value) == L'\0' ) ) {
  392. //
  393. // invalid value/type
  394. //
  395. return FALSE;
  396. }
  397. pTreeRoot->Root = ScepSplaySplay( Value, pTreeRoot->Root, pTreeRoot->Sentinel, pTreeRoot->Type );
  398. pMatchedNode = pTreeRoot->Root;
  399. if (pMatchedNode && pMatchedNode->Value) {
  400. if (ScepValueCompare(pMatchedNode->Value, Value, pTreeRoot->Type) == 0) {
  401. return TRUE;
  402. }
  403. }
  404. return FALSE;
  405. }
  406. int
  407. ScepValueCompare(
  408. PVOID pValue1,
  409. PVOID pValue2,
  410. SCEP_NODE_VALUE_TYPE Type
  411. )
  412. /*
  413. Routine Description:
  414. Lexical sid byte compare
  415. Arguments:
  416. pValue1 - ptr to first value
  417. pValue2 - ptr to second value
  418. Type - the type of the value
  419. Return Value:
  420. 0 if Value1 == Value2
  421. +ve if Value1 > Value2
  422. -ve if Value1 < Value2
  423. */
  424. {
  425. DWORD dwValue1 = 0;
  426. DWORD dwValue2 = 0;
  427. int iByteCmpResult = 0;
  428. switch ( Type ) {
  429. case SplayNodeSidType:
  430. dwValue1 = RtlLengthSid((PSID)pValue1);
  431. dwValue2 = RtlLengthSid((PSID)pValue2);
  432. iByteCmpResult = memcmp(pValue1, pValue2, SCEP_MIN(dwValue1, dwValue2));
  433. if (dwValue1 == dwValue2)
  434. return iByteCmpResult;
  435. else if (iByteCmpResult == 0)
  436. return dwValue1-dwValue2;
  437. return iByteCmpResult;
  438. case SplayNodeStringType:
  439. iByteCmpResult = _wcsicmp((PWSTR)pValue1, (PWSTR)pValue2);
  440. return iByteCmpResult;
  441. }
  442. return 0;
  443. }
  444. BOOL
  445. ScepSplayTreeEmpty(
  446. IN PSCEP_SPLAY_TREE pTreeRoot
  447. )
  448. {
  449. if ( pTreeRoot == NULL ||
  450. pTreeRoot->Root == NULL ||
  451. pTreeRoot->Root == pTreeRoot->Sentinel ) {
  452. return TRUE;
  453. }
  454. return FALSE;
  455. }