Windows NT 4.0 source code leak
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.

1098 lines
26 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. Gentable.c
  5. Abstract:
  6. This module implements the generic table package.
  7. Author:
  8. Gary Kimura [GaryKi] 23-May-1989
  9. Environment:
  10. Pure Utility Routines
  11. Revision History:
  12. Anthony V. Ercolano [tonye] 23-May-1990
  13. Implement package.
  14. Anthony V. Ercolano [tonye] 1-Jun-1990
  15. Added ability to get elements out in the order
  16. inserted. *NOTE* *NOTE* This depends on the implicit
  17. ordering of record fields:
  18. SPLAY_LINKS,
  19. LIST_ENTRY,
  20. USER_DATA
  21. --*/
  22. #include <nt.h>
  23. #include <ntrtl.h>
  24. //
  25. // This enumerated type is used as the function return
  26. // value of the function that is used to search the tree
  27. // for a key. FoundNode indicates that the function found
  28. // the key. InsertAsLeft indicates that the key was not found
  29. // and the node should be inserted as the left child of the
  30. // parent. InsertAsRight indicates that the key was not found
  31. // and the node should be inserted as the right child of the
  32. // parent.
  33. //
  34. typedef enum _SEARCH_RESULT{
  35. EmptyTree,
  36. FoundNode,
  37. InsertAsLeft,
  38. InsertAsRight
  39. } SEARCH_RESULT;
  40. static
  41. SEARCH_RESULT
  42. FindNodeOrParent(
  43. IN PRTL_GENERIC_TABLE Table,
  44. IN PVOID Buffer,
  45. OUT PRTL_SPLAY_LINKS *NodeOrParent
  46. )
  47. /*++
  48. Routine Description:
  49. This routine is used by all of the routines of the generic
  50. table package to locate the a node in the tree. It will
  51. find and return (via the NodeOrParent parameter) the node
  52. with the given key, or if that node is not in the tree it
  53. will return (via the NodeOrParent parameter) a pointer to
  54. the parent.
  55. Arguments:
  56. Table - The generic table to search for the key.
  57. Buffer - Pointer to a buffer holding the key. The table
  58. package doesn't examine the key itself. It leaves
  59. this up to the user supplied compare routine.
  60. NodeOrParent - Will be set to point to the node containing the
  61. the key or what should be the parent of the node
  62. if it were in the tree. Note that this will *NOT*
  63. be set if the search result is EmptyTree.
  64. Return Value:
  65. SEARCH_RESULT - EmptyTree: The tree was empty. NodeOrParent
  66. is *not* altered.
  67. FoundNode: A node with the key is in the tree.
  68. NodeOrParent points to that node.
  69. InsertAsLeft: Node with key was not found.
  70. NodeOrParent points to what would be
  71. parent. The node would be the left
  72. child.
  73. InsertAsRight: Node with key was not found.
  74. NodeOrParent points to what would be
  75. parent. The node would be the right
  76. child.
  77. --*/
  78. {
  79. if (RtlIsGenericTableEmpty(Table)) {
  80. return EmptyTree;
  81. } else {
  82. //
  83. // Used as the iteration variable while stepping through
  84. // the generic table.
  85. //
  86. PRTL_SPLAY_LINKS NodeToExamine = Table->TableRoot;
  87. //
  88. // Just a temporary. Hopefully a good compiler will get
  89. // rid of it.
  90. //
  91. PRTL_SPLAY_LINKS Child;
  92. //
  93. // Holds the value of the comparasion.
  94. //
  95. RTL_GENERIC_COMPARE_RESULTS Result;
  96. while (TRUE) {
  97. //
  98. // Compare the buffer with the key in the tree element.
  99. //
  100. Result = Table->CompareRoutine(
  101. Table,
  102. Buffer,
  103. ((PLIST_ENTRY)((PVOID)(NodeToExamine+1)))+1
  104. );
  105. if (Result == GenericLessThan) {
  106. if (Child = RtlLeftChild(NodeToExamine)) {
  107. NodeToExamine = Child;
  108. } else {
  109. //
  110. // Node is not in the tree. Set the output
  111. // parameter to point to what would be its
  112. // parent and return which child it would be.
  113. //
  114. *NodeOrParent = NodeToExamine;
  115. return InsertAsLeft;
  116. }
  117. } else if (Result == GenericGreaterThan) {
  118. if (Child = RtlRightChild(NodeToExamine)) {
  119. NodeToExamine = Child;
  120. } else {
  121. //
  122. // Node is not in the tree. Set the output
  123. // parameter to point to what would be its
  124. // parent and return which child it would be.
  125. //
  126. *NodeOrParent = NodeToExamine;
  127. return InsertAsRight;
  128. }
  129. } else {
  130. //
  131. // Node is in the tree (or it better be because of the
  132. // assert). Set the output parameter to point to
  133. // the node and tell the caller that we found the node.
  134. //
  135. ASSERT(Result == GenericEqual);
  136. *NodeOrParent = NodeToExamine;
  137. return FoundNode;
  138. }
  139. }
  140. }
  141. }
  142. VOID
  143. RtlInitializeGenericTable (
  144. IN PRTL_GENERIC_TABLE Table,
  145. IN PRTL_GENERIC_COMPARE_ROUTINE CompareRoutine,
  146. IN PRTL_GENERIC_ALLOCATE_ROUTINE AllocateRoutine,
  147. IN PRTL_GENERIC_FREE_ROUTINE FreeRoutine,
  148. IN PVOID TableContext
  149. )
  150. /*++
  151. Routine Description:
  152. The procedure InitializeGenericTable takes as input an uninitialized
  153. generic table variable and pointers to the three user supplied routines.
  154. This must be called for every individual generic table variable before
  155. it can be used.
  156. Arguments:
  157. Table - Pointer to the generic table to be initialized.
  158. CompareRoutine - User routine to be used to compare to keys in the
  159. table.
  160. AllocateRoutine - User routine to call to allocate memory for a new
  161. node in the generic table.
  162. FreeRoutine - User routine to call to deallocate memory for
  163. a node in the generic table.
  164. TableContext - Supplies user supplied context for the table.
  165. Return Value:
  166. None.
  167. --*/
  168. {
  169. //
  170. // Initialize each field of the Table parameter.
  171. //
  172. Table->TableRoot = NULL;
  173. InitializeListHead(&Table->InsertOrderList);
  174. Table->NumberGenericTableElements = 0;
  175. Table->OrderedPointer = &Table->InsertOrderList;
  176. Table->WhichOrderedElement = 0;
  177. Table->CompareRoutine = CompareRoutine;
  178. Table->AllocateRoutine = AllocateRoutine;
  179. Table->FreeRoutine = FreeRoutine;
  180. Table->TableContext = TableContext;
  181. }
  182. PVOID
  183. RtlInsertElementGenericTable (
  184. IN PRTL_GENERIC_TABLE Table,
  185. IN PVOID Buffer,
  186. IN CLONG BufferSize,
  187. OUT PBOOLEAN NewElement OPTIONAL
  188. )
  189. /*++
  190. Routine Description:
  191. The function InsertElementGenericTable will insert a new element
  192. in a table. It does this by allocating space for the new element
  193. (this includes splay links), inserting the element in the table, and
  194. then returning to the user a pointer to the new element (which is
  195. the first available space after the splay links). If an element
  196. with the same key already exists in the table the return value is a pointer
  197. to the old element. The optional output parameter NewElement is used
  198. to indicate if the element previously existed in the table. Note: the user
  199. supplied Buffer is only used for searching the table, upon insertion its
  200. contents are copied to the newly created element. This means that
  201. pointer to the input buffer will not point to the new element.
  202. Arguments:
  203. Table - Pointer to the table in which to (possibly) insert the
  204. key buffer.
  205. Buffer - Passed to the user comparasion routine. Its contents are
  206. up to the user but one could imagine that it contains some
  207. sort of key value.
  208. BufferSize - The amount of space to allocate when the (possible)
  209. insertion is made. Note that if we actually do
  210. not find the node and we do allocate space then we
  211. will add the size of the SPLAY_LINKS to this buffer
  212. size. The user should really take care not to depend
  213. on anything in the first sizeof(SPLAY_LINKS) bytes
  214. of the memory allocated via the memory allocation
  215. routine.
  216. NewElement - Optional Flag. If present then it will be set to
  217. TRUE if the buffer was not "found" in the generic
  218. table.
  219. Return Value:
  220. PVOID - Pointer to the user defined data.
  221. --*/
  222. {
  223. //
  224. // Holds a pointer to the node in the table or what would be the
  225. // parent of the node.
  226. //
  227. PRTL_SPLAY_LINKS NodeOrParent;
  228. //
  229. // Holds the result of the table lookup.
  230. //
  231. SEARCH_RESULT Lookup;
  232. //
  233. // Node will point to the splay links of what
  234. // will be returned to the user.
  235. //
  236. PRTL_SPLAY_LINKS NodeToReturn;
  237. Lookup = FindNodeOrParent(
  238. Table,
  239. Buffer,
  240. &NodeOrParent
  241. );
  242. if (Lookup != FoundNode) {
  243. //
  244. // We just check that the table isn't getting
  245. // too big.
  246. //
  247. ASSERT(Table->NumberGenericTableElements != (MAXULONG-1));
  248. //
  249. // The node wasn't in the (possibly empty) tree.
  250. // Call the user allocation routine to get space
  251. // for the new node.
  252. //
  253. NodeToReturn = Table->AllocateRoutine(
  254. Table,
  255. BufferSize+sizeof(RTL_SPLAY_LINKS)+sizeof(LIST_ENTRY)
  256. );
  257. //
  258. // If the return is NULL, return NULL from here to indicate that
  259. // the entry could not be added.
  260. //
  261. if (NodeToReturn == NULL) {
  262. if (ARGUMENT_PRESENT(NewElement)) {
  263. *NewElement = FALSE;
  264. }
  265. return(NULL);
  266. }
  267. RtlInitializeSplayLinks(NodeToReturn);
  268. InitializeListHead((PLIST_ENTRY)((PVOID)(NodeToReturn+1)));
  269. //
  270. // Insert the new node at the end of the ordered linked list.
  271. //
  272. InsertTailList(
  273. &Table->InsertOrderList,
  274. (PLIST_ENTRY)((PVOID)(NodeToReturn+1))
  275. );
  276. Table->NumberGenericTableElements++;
  277. //
  278. // Insert the new node in the tree.
  279. //
  280. if (Lookup == EmptyTree) {
  281. Table->TableRoot = NodeToReturn;
  282. } else {
  283. if (Lookup == InsertAsLeft) {
  284. RtlInsertAsLeftChild(
  285. NodeOrParent,
  286. NodeToReturn
  287. );
  288. } else {
  289. RtlInsertAsRightChild(
  290. NodeOrParent,
  291. NodeToReturn
  292. );
  293. }
  294. }
  295. //
  296. // Copy the users buffer into the user data area of the table.
  297. //
  298. RtlCopyMemory(
  299. ((PLIST_ENTRY)((PVOID)(NodeToReturn+1)))+1,
  300. Buffer,
  301. BufferSize
  302. );
  303. } else {
  304. NodeToReturn = NodeOrParent;
  305. }
  306. //
  307. // Always splay the (possibly) new node.
  308. //
  309. Table->TableRoot = RtlSplay(NodeToReturn);
  310. if (ARGUMENT_PRESENT(NewElement)) {
  311. *NewElement = ((Lookup == FoundNode)?(FALSE):(TRUE));
  312. }
  313. //
  314. // Insert the element on the ordered list;
  315. //
  316. return ((PLIST_ENTRY)((PVOID)(NodeToReturn+1)))+1;
  317. }
  318. BOOLEAN
  319. RtlDeleteElementGenericTable (
  320. IN PRTL_GENERIC_TABLE Table,
  321. IN PVOID Buffer
  322. )
  323. /*++
  324. Routine Description:
  325. The function DeleteElementGenericTable will find and delete an element
  326. from a generic table. If the element is located and deleted the return
  327. value is TRUE, otherwise if the element is not located the return value
  328. is FALSE. The user supplied input buffer is only used as a key in
  329. locating the element in the table.
  330. Arguments:
  331. Table - Pointer to the table in which to (possibly) delete the
  332. memory accessed by the key buffer.
  333. Buffer - Passed to the user comparasion routine. Its contents are
  334. up to the user but one could imagine that it contains some
  335. sort of key value.
  336. Return Value:
  337. BOOLEAN - If the table contained the key then true, otherwise false.
  338. --*/
  339. {
  340. //
  341. // Holds a pointer to the node in the table or what would be the
  342. // parent of the node.
  343. //
  344. PRTL_SPLAY_LINKS NodeOrParent;
  345. //
  346. // Holds the result of the table lookup.
  347. //
  348. SEARCH_RESULT Lookup;
  349. Lookup = FindNodeOrParent(
  350. Table,
  351. Buffer,
  352. &NodeOrParent
  353. );
  354. if ((Lookup == EmptyTree) || (Lookup != FoundNode)) {
  355. return FALSE;
  356. } else {
  357. //
  358. // Delete the node from the splay tree.
  359. //
  360. Table->TableRoot = RtlDelete(NodeOrParent);
  361. //
  362. // Delete the element from the linked list.
  363. //
  364. RemoveEntryList((PLIST_ENTRY)((PVOID)(NodeOrParent+1)));
  365. Table->NumberGenericTableElements--;
  366. Table->WhichOrderedElement = 0;
  367. Table->OrderedPointer = &Table->InsertOrderList;
  368. //
  369. // The node has been deleted from the splay table.
  370. // Now give the node to the user deletion routine.
  371. // NOTE: We are giving the deletion routine a pointer
  372. // to the splay links rather then the user data. It
  373. // is assumed that the deallocation is rather stupid.
  374. //
  375. Table->FreeRoutine(Table,NodeOrParent);
  376. return TRUE;
  377. }
  378. }
  379. PVOID
  380. RtlLookupElementGenericTable (
  381. IN PRTL_GENERIC_TABLE Table,
  382. IN PVOID Buffer
  383. )
  384. /*++
  385. Routine Description:
  386. The function LookupElementGenericTable will find an element in a generic
  387. table. If the element is located the return value is a pointer to
  388. the user defined structure associated with the element, otherwise if
  389. the element is not located the return value is NULL. The user supplied
  390. input buffer is only used as a key in locating the element in the table.
  391. Arguments:
  392. Table - Pointer to the users Generic table to search for the key.
  393. Buffer - Used for the comparasion.
  394. Return Value:
  395. PVOID - returns a pointer to the user data.
  396. --*/
  397. {
  398. //
  399. // Holds a pointer to the node in the table or what would be the
  400. // parent of the node.
  401. //
  402. PRTL_SPLAY_LINKS NodeOrParent;
  403. //
  404. // Holds the result of the table lookup.
  405. //
  406. SEARCH_RESULT Lookup;
  407. Lookup = FindNodeOrParent(
  408. Table,
  409. Buffer,
  410. &NodeOrParent
  411. );
  412. if ((Lookup == EmptyTree) || (Lookup != FoundNode)) {
  413. return NULL;
  414. } else {
  415. //
  416. // Splay the tree with this node.
  417. //
  418. Table->TableRoot = RtlSplay(NodeOrParent);
  419. //
  420. // Return a pointer to the user data.
  421. //
  422. return ((PLIST_ENTRY)((PVOID)(NodeOrParent+1)))+1;
  423. }
  424. }
  425. PVOID
  426. RtlEnumerateGenericTable (
  427. IN PRTL_GENERIC_TABLE Table,
  428. IN BOOLEAN Restart
  429. )
  430. /*++
  431. Routine Description:
  432. The function EnumerateGenericTable will return to the caller one-by-one
  433. the elements of of a table. The return value is a pointer to the user
  434. defined structure associated with the element. The input parameter
  435. Restart indicates if the enumeration should start from the beginning
  436. or should return the next element. If the are no more new elements to
  437. return the return value is NULL. As an example of its use, to enumerate
  438. all of the elements in a table the user would write:
  439. for (ptr = EnumerateGenericTable(Table,TRUE);
  440. ptr != NULL;
  441. ptr = EnumerateGenericTable(Table, FALSE)) {
  442. :
  443. }
  444. Arguments:
  445. Table - Pointer to the generic table to enumerate.
  446. Restart - Flag that if true we should start with the least
  447. element in the tree otherwise, return we return
  448. a pointer to the user data for the root and make
  449. the real successor to the root the new root.
  450. Return Value:
  451. PVOID - Pointer to the user data.
  452. --*/
  453. {
  454. if (RtlIsGenericTableEmpty(Table)) {
  455. //
  456. // Nothing to do if the table is empty.
  457. //
  458. return NULL;
  459. } else {
  460. //
  461. // Will be used as the "iteration" through the tree.
  462. //
  463. PRTL_SPLAY_LINKS NodeToReturn;
  464. //
  465. // If the restart flag is true then go to the least element
  466. // in the tree.
  467. //
  468. if (Restart) {
  469. //
  470. // We just loop until we find the leftmost child of the root.
  471. //
  472. for (
  473. NodeToReturn = Table->TableRoot;
  474. RtlLeftChild(NodeToReturn);
  475. NodeToReturn = RtlLeftChild(NodeToReturn)
  476. ) {
  477. ;
  478. }
  479. Table->TableRoot = RtlSplay(NodeToReturn);
  480. } else {
  481. //
  482. // The assumption here is that the root of the
  483. // tree is the last node that we returned. We
  484. // find the real successor to the root and return
  485. // it as next element of the enumeration. The
  486. // node that is to be returned is splayed (thereby
  487. // making it the root of the tree). Note that we
  488. // need to take care when there are no more elements.
  489. //
  490. NodeToReturn = RtlRealSuccessor(Table->TableRoot);
  491. if (NodeToReturn) {
  492. Table->TableRoot = RtlSplay(NodeToReturn);
  493. }
  494. }
  495. //
  496. // If there actually is a next element in the enumeration
  497. // then the pointer to return is right after the list links.
  498. //
  499. return ((NodeToReturn)?
  500. ((PVOID)((PLIST_ENTRY)((PVOID)(NodeToReturn+1))+1))
  501. :((PVOID)(NULL)));
  502. }
  503. }
  504. BOOLEAN
  505. RtlIsGenericTableEmpty (
  506. IN PRTL_GENERIC_TABLE Table
  507. )
  508. /*++
  509. Routine Description:
  510. The function IsGenericTableEmpty will return to the caller TRUE if
  511. the input table is empty (i.e., does not contain any elements) and
  512. FALSE otherwise.
  513. Arguments:
  514. Table - Supplies a pointer to the Generic Table.
  515. Return Value:
  516. BOOLEAN - if enabled the tree is empty.
  517. --*/
  518. {
  519. //
  520. // Table is empty if the root pointer is null.
  521. //
  522. return ((Table->TableRoot)?(FALSE):(TRUE));
  523. }
  524. PVOID
  525. RtlGetElementGenericTable (
  526. IN PRTL_GENERIC_TABLE Table,
  527. IN ULONG I
  528. )
  529. /*++
  530. Routine Description:
  531. The function GetElementGenericTable will return the i'th element
  532. inserted in the generic table. I = 0 implies the first element,
  533. I = (RtlNumberGenericTableElements(Table)-1) will return the last element
  534. inserted into the generic table. The type of I is ULONG. Values
  535. of I > than (NumberGenericTableElements(Table)-1) will return NULL. If
  536. an arbitrary element is deleted from the generic table it will cause
  537. all elements inserted after the deleted element to "move up".
  538. Arguments:
  539. Table - Pointer to the generic table from which to get the ith element.
  540. I - Which element to get.
  541. Return Value:
  542. PVOID - Pointer to the user data.
  543. --*/
  544. {
  545. //
  546. // Current location in the table.
  547. //
  548. ULONG CurrentLocation = Table->WhichOrderedElement;
  549. //
  550. // Hold the number of elements in the table.
  551. //
  552. ULONG NumberInTable = Table->NumberGenericTableElements;
  553. //
  554. // Holds the value of I+1.
  555. //
  556. // Note that we don't care if this value overflows.
  557. // If we end up accessing it we know that it didn't.
  558. //
  559. ULONG NormalizedI = I + 1;
  560. //
  561. // Will hold distances to travel to the desired node;
  562. //
  563. ULONG ForwardDistance,BackwardDistance;
  564. //
  565. // Will point to the current element in the linked list.
  566. //
  567. PLIST_ENTRY CurrentNode = Table->OrderedPointer;
  568. //
  569. // If it's out of bounds get out quick.
  570. //
  571. if ((I == MAXULONG) || (NormalizedI > NumberInTable)) return NULL;
  572. //
  573. // If we're already at the node then return it.
  574. //
  575. if (NormalizedI == CurrentLocation) return CurrentNode+1;
  576. //
  577. // Calculate the forward and backward distance to the node.
  578. //
  579. if (CurrentLocation > NormalizedI) {
  580. //
  581. // When CurrentLocation is greater than where we want to go,
  582. // if moving forward gets us there quicker than moving backward
  583. // then it follows that moving forward from the listhead is
  584. // going to take fewer steps. (This is because, moving forward
  585. // in this case must move *through* the listhead.)
  586. //
  587. // The work here is to figure out if moving backward would be quicker.
  588. //
  589. // Moving backward would be quicker only if the location we wish to
  590. // go to is more than half way between the listhead and where we
  591. // currently are.
  592. //
  593. if (NormalizedI > (CurrentLocation/2)) {
  594. //
  595. // Where we want to go is more than half way from the listhead
  596. // We can traval backwards from our current location.
  597. //
  598. for (
  599. BackwardDistance = CurrentLocation - NormalizedI;
  600. BackwardDistance;
  601. BackwardDistance--
  602. ) {
  603. CurrentNode = CurrentNode->Blink;
  604. }
  605. } else {
  606. //
  607. // Where we want to go is less than halfway between the start
  608. // and where we currently are. Start from the listhead.
  609. //
  610. for (
  611. CurrentNode = &Table->InsertOrderList;
  612. NormalizedI;
  613. NormalizedI--
  614. ) {
  615. CurrentNode = CurrentNode->Flink;
  616. }
  617. }
  618. } else {
  619. //
  620. // When CurrentLocation is less than where we want to go,
  621. // if moving backwards gets us there quicker than moving forwards
  622. // then it follows that moving backwards from the listhead is
  623. // going to take fewer steps. (This is because, moving backwards
  624. // in this case must move *through* the listhead.)
  625. //
  626. ForwardDistance = NormalizedI - CurrentLocation;
  627. //
  628. // Do the backwards calculation as if we are starting from the
  629. // listhead.
  630. //
  631. BackwardDistance = (NumberInTable - NormalizedI) + 1;
  632. if (ForwardDistance <= BackwardDistance) {
  633. for (
  634. ;
  635. ForwardDistance;
  636. ForwardDistance--
  637. ) {
  638. CurrentNode = CurrentNode->Flink;
  639. }
  640. } else {
  641. for (
  642. CurrentNode = &Table->InsertOrderList;
  643. BackwardDistance;
  644. BackwardDistance--
  645. ) {
  646. CurrentNode = CurrentNode->Blink;
  647. }
  648. }
  649. }
  650. //
  651. // We're where we want to be. Save our current location and return
  652. // a pointer to the data to the user.
  653. //
  654. Table->OrderedPointer = CurrentNode;
  655. Table->WhichOrderedElement = I+1;
  656. return CurrentNode+1;
  657. }
  658. ULONG
  659. RtlNumberGenericTableElements(
  660. IN PRTL_GENERIC_TABLE Table
  661. )
  662. /*++
  663. Routine Description:
  664. The function NumberGenericTableElements returns a ULONG value
  665. which is the number of generic table elements currently inserted
  666. in the generic table.
  667. Arguments:
  668. Table - Pointer to the generic table from which to find out the number
  669. of elements.
  670. Return Value:
  671. ULONG - The number of elements in the generic table.
  672. --*/
  673. {
  674. return Table->NumberGenericTableElements;
  675. }
  676. PVOID
  677. RtlEnumerateGenericTableWithoutSplaying (
  678. IN PRTL_GENERIC_TABLE Table,
  679. IN PVOID *RestartKey
  680. )
  681. /*++
  682. Routine Description:
  683. The function EnumerateGenericTableWithoutSplaying will return to the
  684. caller one-by-one the elements of of a table. The return value is a
  685. pointer to the user defined structure associated with the element.
  686. The input parameter RestartKey indicates if the enumeration should
  687. start from the beginning or should return the next element. If the
  688. are no more new elements to return the return value is NULL. As an
  689. example of its use, to enumerate all of the elements in a table the
  690. user would write:
  691. *RestartKey = NULL;
  692. for (ptr = EnumerateGenericTableWithoutSplaying(Table, &RestartKey);
  693. ptr != NULL;
  694. ptr = EnumerateGenericTableWithoutSplaying(Table, &RestartKey)) {
  695. :
  696. }
  697. Arguments:
  698. Table - Pointer to the generic table to enumerate.
  699. RestartKey - Pointer that indicates if we should restart or return the next
  700. element. If the contents of RestartKey is NULL, the search
  701. will be started from the beginning.
  702. Return Value:
  703. PVOID - Pointer to the user data.
  704. --*/
  705. {
  706. if (RtlIsGenericTableEmpty(Table)) {
  707. //
  708. // Nothing to do if the table is empty.
  709. //
  710. return NULL;
  711. } else {
  712. //
  713. // Will be used as the "iteration" through the tree.
  714. //
  715. PRTL_SPLAY_LINKS NodeToReturn;
  716. //
  717. // If the restart flag is true then go to the least element
  718. // in the tree.
  719. //
  720. if (*RestartKey == NULL) {
  721. //
  722. // We just loop until we find the leftmost child of the root.
  723. //
  724. for (
  725. NodeToReturn = Table->TableRoot;
  726. RtlLeftChild(NodeToReturn);
  727. NodeToReturn = RtlLeftChild(NodeToReturn)
  728. ) {
  729. ;
  730. }
  731. *RestartKey = NodeToReturn;
  732. } else {
  733. //
  734. // The caller has passed in the previous entry found
  735. // in the table to enable us to continue the search. We call
  736. // RtlRealSuccessor to step to the next element in the tree.
  737. //
  738. NodeToReturn = RtlRealSuccessor(*RestartKey);
  739. if (NodeToReturn) {
  740. *RestartKey = NodeToReturn;
  741. }
  742. }
  743. //
  744. // If there actually is a next element in the enumeration
  745. // then the pointer to return is right after the list links.
  746. //
  747. return ((NodeToReturn)?
  748. ((PVOID)((PLIST_ENTRY)((PVOID)(NodeToReturn+1))+1))
  749. :((PVOID)(NULL)));
  750. }
  751. }