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.

1631 lines
34 KiB

  1. /*++
  2. Copyright (c) 1997 - 98, Microsoft Corporation
  3. Module Name:
  4. avltrie.c
  5. Abstract:
  6. Contains routines for a best matching
  7. prefix lookup using an AVL trie.
  8. Author:
  9. Chaitanya Kodeboyina (chaitk) 24-Jun-1998
  10. Revision History:
  11. --*/
  12. #include "pchrtm.h"
  13. #pragma hdrstop
  14. #include "avltrie.h"
  15. DWORD
  16. WINAPI
  17. CreateTable(
  18. IN UINT MaxBytes,
  19. OUT HANDLE *Table
  20. )
  21. /*++
  22. Routine Description:
  23. Create a table that enables to you add and delete prefixes
  24. (and associated data) and do best matching prefix queries.
  25. Arguments:
  26. MaxBytes - Max length of any prefix in the table,
  27. Table - Pointer to the table that was created.
  28. Return Value:
  29. Status of the operation
  30. --*/
  31. {
  32. PAVL_TRIE NewTrie;
  33. ASSERT(sizeof(AVL_CONTEXT) <= sizeof(LOOKUP_CONTEXT));
  34. ASSERT(sizeof(AVL_LINKAGE) <= sizeof(LOOKUP_LINKAGE));
  35. if (MaxBytes == 0)
  36. {
  37. return ERROR_INVALID_PARAMETER;
  38. }
  39. //
  40. // Allocate and initialize a new prefix table
  41. //
  42. NewTrie = AllocNZeroMemory(sizeof(AVL_TRIE));
  43. if (NewTrie == NULL)
  44. {
  45. return ERROR_NOT_ENOUGH_MEMORY;
  46. }
  47. #if _PROF_
  48. NewTrie->MemoryInUse = sizeof(AVL_TRIE);
  49. #endif
  50. NewTrie->MaxKeyBytes = MaxBytes;
  51. *Table = NewTrie;
  52. return NO_ERROR;
  53. }
  54. DWORD
  55. WINAPI
  56. InsertIntoTable(
  57. IN HANDLE Table,
  58. IN USHORT NumBits,
  59. IN PUCHAR KeyBits,
  60. IN PLOOKUP_CONTEXT Context OPTIONAL,
  61. IN PLOOKUP_LINKAGE Data
  62. )
  63. /*++
  64. Routine Description:
  65. Inserts new prefix (and associated data) into a prefix table.
  66. Arguments:
  67. Table - Table into which prefix is being inserted,
  68. NumBits - Number of bits in the prefix being added,
  69. KeyBits - Value of the bits that form the prefix,
  70. Context - Search context for the prefix being added,
  71. Data - Data associated with this prefix being added.
  72. Return Value:
  73. Status of the operation
  74. --*/
  75. {
  76. PAVL_TRIE Trie;
  77. PAVL_NODE PrevNode;
  78. PAVL_NODE BestNode;
  79. PAVL_NODE NewNode;
  80. LOOKUP_CONTEXT Context1;
  81. AVL_BALANCE NextChild;
  82. PLOOKUP_LINKAGE Dummy;
  83. Trie = Table;
  84. #if PROF
  85. Trie->NumInsertions++;
  86. #endif
  87. //
  88. // If there is a search context, and we have an
  89. // update, we can avoid the lookup (common case)
  90. //
  91. if (!ARGUMENT_PRESENT(Context))
  92. {
  93. Context = &Context1;
  94. SearchInTable(Table, NumBits, KeyBits, Context, &Dummy);
  95. }
  96. BestNode = ((PAVL_CONTEXT) Context)->BestNode;
  97. if (BestNode && (BestNode->NumBits == NumBits))
  98. {
  99. SET_NODEPTR_INTO_DATA(BestNode->Data, NULL);
  100. BestNode->Data = Data;
  101. SET_NODEPTR_INTO_DATA(Data, BestNode);
  102. return NO_ERROR;
  103. }
  104. NewNode = CreateTrieNode(Trie, NumBits, KeyBits, BestNode, Data);
  105. if (NewNode)
  106. {
  107. PrevNode = ((PAVL_CONTEXT) Context)->InsPoint;
  108. if (PrevNode)
  109. {
  110. NextChild = ((PAVL_CONTEXT) Context)->InsChild;
  111. PrevNode->Child[NextChild] = NewNode;
  112. NewNode->Parent = PrevNode;
  113. ((PAVL_CONTEXT) Context)->BestNode = NewNode;
  114. // Enumerate in range of the new node & update prefixes
  115. AdjustPrefixes(Trie, BestNode, NewNode, NewNode, Context);
  116. // Balance trie if it was thrown off balance
  117. BalanceAfterInsert(Trie, PrevNode, NextChild);
  118. }
  119. else
  120. {
  121. Trie->TrieRoot = NewNode;
  122. }
  123. #if _DBG_
  124. if (CheckTable(Table) != TRUE)
  125. {
  126. DbgBreakPoint();
  127. }
  128. #endif
  129. return NO_ERROR;
  130. }
  131. else // if CreateTrieNode failed
  132. {
  133. return ERROR_NOT_ENOUGH_MEMORY;
  134. }
  135. }
  136. DWORD
  137. WINAPI
  138. DeleteFromTable(
  139. IN HANDLE Table,
  140. IN USHORT NumBits,
  141. IN PUCHAR KeyBits,
  142. IN PLOOKUP_CONTEXT Context OPTIONAL,
  143. OUT PLOOKUP_LINKAGE *Data
  144. )
  145. /*++
  146. Routine Description:
  147. Deletes a prefix from a prefix table and returns associated data.
  148. Arguments:
  149. Table - Table from which prefix is being deleted,
  150. NumBits - Number of bits in the prefix being deleted,
  151. KeyBits - Value of the bits that form the prefix,
  152. Context - Search context for the prefix being deleted,
  153. Data - Data associated with this prefix is retd here.
  154. Return Value:
  155. Status of the operation
  156. --*/
  157. {
  158. PAVL_TRIE Trie;
  159. PAVL_NODE PrevNode;
  160. PAVL_NODE CurrNode;
  161. PAVL_NODE NextNode;
  162. LOOKUP_CONTEXT Context1;
  163. AVL_BALANCE NextChild;
  164. DWORD Status;
  165. #if _DBG_
  166. USHORT Depth = 0;
  167. #endif
  168. Trie = Table;
  169. #if PROF
  170. Trie->NumDeletions++;
  171. #endif
  172. //
  173. // If there is a search context that is valid,
  174. // we will avoid doing a lookup (common case)
  175. //
  176. if (!ARGUMENT_PRESENT(Context))
  177. {
  178. Context = &Context1;
  179. Status = SearchInTable(Table, NumBits, KeyBits, Context, Data);
  180. if (Status != NO_ERROR)
  181. {
  182. return Status;
  183. }
  184. }
  185. #if WRN
  186. NextChild = INVALID;
  187. #endif
  188. //
  189. // We should not come here unless the context
  190. // points accurately to element to be deleted
  191. //
  192. CurrNode = ((PAVL_CONTEXT) Context)->BestNode;
  193. ASSERT(CurrNode && (CurrNode->NumBits == NumBits) &&
  194. (CompareFullKeys(CurrNode->KeyBits,
  195. KeyBits,
  196. Trie->MaxKeyBytes) == 0));
  197. PrevNode = ((PAVL_CONTEXT) Context)->InsPoint;
  198. ASSERT(PrevNode == CurrNode->Parent);
  199. if (PrevNode)
  200. {
  201. NextChild = ((PAVL_CONTEXT) Context)->InsChild;
  202. }
  203. ASSERT(((PrevNode == NULL) && (Trie->TrieRoot == CurrNode))
  204. || (PrevNode->Child[NextChild] == CurrNode));
  205. //
  206. // If the node being deleted has two children,
  207. // swap its position with its successor node
  208. //
  209. if (CurrNode->Child[LEFT] && CurrNode->Child[RIGHT])
  210. {
  211. #if _DBG_
  212. if (CheckSubTrie(PrevNode, &Depth) != NO_ERROR)
  213. {
  214. DbgBreakPoint();
  215. }
  216. #endif
  217. SwapWithSuccessor(Trie, (PAVL_CONTEXT) Context);
  218. #if _DBG_
  219. if (CheckSubTrie(PrevNode, &Depth) != NO_ERROR)
  220. {
  221. DbgBreakPoint();
  222. }
  223. #endif
  224. CurrNode = ((PAVL_CONTEXT) Context)->BestNode;
  225. PrevNode = ((PAVL_CONTEXT) Context)->InsPoint;
  226. NextChild = ((PAVL_CONTEXT) Context)->InsChild;
  227. }
  228. ASSERT(((PrevNode == NULL) && (Trie->TrieRoot == CurrNode))
  229. || (PrevNode->Child[NextChild] == CurrNode));
  230. #if _DBG_
  231. if (CheckTable(Table) != TRUE)
  232. {
  233. DbgBreakPoint();
  234. }
  235. #endif
  236. AdjustPrefixes(Trie, CurrNode, CurrNode->Prefix, CurrNode, Context);
  237. #if _DBG_
  238. if (CheckTable(Table) != TRUE)
  239. {
  240. DbgBreakPoint();
  241. }
  242. #endif
  243. if (!CurrNode->Child[LEFT])
  244. {
  245. // (LEFT Child = NULL) => Promote the right child
  246. NextNode = CurrNode->Child[RIGHT];
  247. if (NextNode)
  248. {
  249. NextNode->Parent = CurrNode->Parent;
  250. }
  251. }
  252. else
  253. {
  254. // (RIGHT Child = NULL) => Promote the left child
  255. ASSERT(!CurrNode->Child[RIGHT]);
  256. NextNode = CurrNode->Child[LEFT];
  257. NextNode->Parent = CurrNode->Parent;
  258. }
  259. if (PrevNode)
  260. {
  261. PrevNode->Child[NextChild] = NextNode;
  262. // Balance trie if it was thrown off balance
  263. BalanceAfterDelete(Trie, PrevNode, NextChild);
  264. }
  265. else
  266. {
  267. Trie->TrieRoot = NextNode;
  268. }
  269. *Data = CurrNode->Data;
  270. DestroyTrieNode(Trie, CurrNode);
  271. #if _DBG_
  272. if (CheckTable(Table) != TRUE)
  273. {
  274. DbgBreakPoint();
  275. }
  276. #endif
  277. return NO_ERROR;
  278. }
  279. DWORD
  280. WINAPI
  281. SearchInTable(
  282. IN HANDLE Table,
  283. IN USHORT NumBits,
  284. IN PUCHAR KeyBits,
  285. OUT PLOOKUP_CONTEXT Context OPTIONAL,
  286. OUT PLOOKUP_LINKAGE *Data
  287. )
  288. {
  289. PAVL_TRIE Trie;
  290. PAVL_NODE PrevNode;
  291. PAVL_NODE CurrNode;
  292. PAVL_NODE BestNode;
  293. AVL_BALANCE NextChild;
  294. INT Comp;
  295. #if _PROF_
  296. UINT NumTravsDn;
  297. UINT NumTravsUp;
  298. #endif
  299. Trie = Table;
  300. ASSERT(NumBits <= Trie->MaxKeyBytes * BITS_IN_BYTE);
  301. #if _PROF_
  302. NumTravsDn = 0;
  303. NumTravsUp = 0;
  304. #endif
  305. //
  306. // Go down the trie using key comparisions
  307. // in search of a prefix matching this key
  308. //
  309. CurrNode = Trie->TrieRoot;
  310. PrevNode = NULL;
  311. NextChild = LEFT;
  312. BestNode = NULL;
  313. while (CurrNode)
  314. {
  315. #if _PROF_
  316. NumTravsDn++;
  317. #endif
  318. Comp = CompareFullKeys(KeyBits,
  319. CurrNode->KeyBits,
  320. Trie->MaxKeyBytes);
  321. if ((Comp < 0) || ((Comp == 0) && (NumBits < CurrNode->NumBits)))
  322. {
  323. NextChild = LEFT;
  324. }
  325. else
  326. if ((Comp > 0) || (NumBits > CurrNode->NumBits))
  327. {
  328. NextChild = RIGHT;
  329. BestNode = CurrNode;
  330. }
  331. else
  332. {
  333. BestNode = CurrNode;
  334. break;
  335. }
  336. PrevNode = CurrNode;
  337. CurrNode = PrevNode->Child[NextChild];
  338. }
  339. if (!CurrNode)
  340. {
  341. //
  342. // We do not have an exact match - so now
  343. // we try to refine BestNode guess to get
  344. // the next best prefix to the new prefix
  345. //
  346. while(BestNode)
  347. {
  348. if (BestNode->NumBits <= NumBits)
  349. {
  350. if (!(ComparePartialKeys(BestNode->KeyBits,
  351. KeyBits,
  352. BestNode->NumBits)))
  353. {
  354. break;
  355. }
  356. }
  357. BestNode = BestNode->Prefix;
  358. #if _PROF_
  359. if (BestNode)
  360. {
  361. NumTravsUp++;
  362. }
  363. #endif
  364. }
  365. }
  366. if (ARGUMENT_PRESENT(Context))
  367. {
  368. ((PAVL_CONTEXT) Context)->BestNode = BestNode;
  369. ((PAVL_CONTEXT) Context)->InsPoint = PrevNode;
  370. ((PAVL_CONTEXT) Context)->InsChild = NextChild;
  371. }
  372. *Data = BestNode ? BestNode->Data : NULL;
  373. #if _PROF_
  374. Print("Num Travs Dn = %5d, Travs Up = %5d\n",
  375. NumTravsDn,
  376. NumTravsUp);
  377. #endif
  378. return CurrNode ? NO_ERROR : ERROR_NOT_FOUND;
  379. }
  380. DWORD
  381. WINAPI
  382. BestMatchInTable(
  383. IN HANDLE Table,
  384. IN PUCHAR KeyBits,
  385. OUT PLOOKUP_LINKAGE *BestData
  386. )
  387. {
  388. PAVL_TRIE Trie;
  389. PAVL_NODE CurrNode;
  390. PAVL_NODE BestNode;
  391. INT Comp;
  392. #if _PROF_
  393. UINT NumTravsDn;
  394. UINT NumTravsUp;
  395. #endif
  396. Trie = Table;
  397. #if _PROF_
  398. NumTravsDn = 0;
  399. NumTravsUp = 0;
  400. #endif
  401. //
  402. // Go down the trie using key comparisions
  403. // in search of a prefix matching this key
  404. //
  405. CurrNode = Trie->TrieRoot;
  406. BestNode = NULL;
  407. while (CurrNode)
  408. {
  409. #if _PROF_
  410. NumTravsDn++;
  411. #endif
  412. Comp = CompareFullKeys(KeyBits,
  413. CurrNode->KeyBits,
  414. Trie->MaxKeyBytes);
  415. if (Comp < 0)
  416. {
  417. CurrNode = CurrNode->Child[LEFT];
  418. }
  419. else
  420. {
  421. BestNode = CurrNode;
  422. CurrNode = CurrNode->Child[RIGHT];
  423. }
  424. }
  425. //
  426. // Now we refine the BestNode guess to get
  427. // the next best prefix to the new prefix
  428. //
  429. while(BestNode)
  430. {
  431. if (!(ComparePartialKeys(BestNode->KeyBits,
  432. KeyBits,
  433. BestNode->NumBits)))
  434. {
  435. break;
  436. }
  437. BestNode = BestNode->Prefix;
  438. #if _PROF_
  439. if (BestNode)
  440. {
  441. NumTravsUp++;
  442. }
  443. #endif
  444. }
  445. *BestData = BestNode ? BestNode->Data : NULL;
  446. #if _PROF_
  447. Print("Num Travs Dn = %5d, Travs Up = %5d\n",
  448. NumTravsDn,
  449. NumTravsUp);
  450. #endif
  451. return NO_ERROR;
  452. }
  453. DWORD
  454. WINAPI
  455. NextMatchInTable(
  456. IN HANDLE Table,
  457. IN PLOOKUP_LINKAGE BestData,
  458. OUT PLOOKUP_LINKAGE *NextBestData
  459. )
  460. {
  461. PAVL_NODE BestNode;
  462. UNREFERENCED_PARAMETER(Table);
  463. //
  464. // Assume the input data passed in is valid,
  465. // and the data is one of the items in trie
  466. //
  467. BestNode = GET_NODEPTR_FROM_DATA(BestData);
  468. *NextBestData = BestNode->Prefix ? BestNode->Prefix->Data : NULL;
  469. return NO_ERROR;
  470. }
  471. DWORD
  472. WINAPI
  473. EnumOverTable(
  474. IN HANDLE Table,
  475. IN OUT PUSHORT StartNumBits,
  476. IN OUT PUCHAR StartKeyBits,
  477. IN OUT PLOOKUP_CONTEXT Context OPTIONAL,
  478. IN USHORT StopNumBits OPTIONAL,
  479. IN PUCHAR StopKeyBits OPTIONAL,
  480. IN OUT PUINT NumItems,
  481. OUT PLOOKUP_LINKAGE *DataItems
  482. )
  483. {
  484. PAVL_TRIE Trie;
  485. PLOOKUP_LINKAGE Data;
  486. PAVL_NODE PrevNode;
  487. PAVL_NODE CurrNode;
  488. PAVL_NODE NextNode;
  489. LOOKUP_CONTEXT Context1;
  490. AVL_BALANCE NextChild;
  491. UINT ItemsCopied;
  492. INT Comp;
  493. Trie = Table;
  494. if (!ARGUMENT_PRESENT(Context))
  495. {
  496. // No context - initialize local context
  497. Context = &Context1;
  498. ((PAVL_CONTEXT) Context)->InsChild = EVEN;
  499. }
  500. //
  501. // If there is a search context that is valid,
  502. // we will avoid doing a lookup (common case)
  503. //
  504. if (((PAVL_CONTEXT) Context)->InsChild == EVEN)
  505. {
  506. //
  507. // If we did not find an exact match,
  508. // remember it by modifying context
  509. //
  510. if (SearchInTable(Table,
  511. *StartNumBits,
  512. StartKeyBits,
  513. Context,
  514. &Data) != NO_ERROR)
  515. {
  516. ((PAVL_CONTEXT) Context)->BestNode = NULL;
  517. }
  518. }
  519. CurrNode = ((PAVL_CONTEXT) Context)->BestNode;
  520. //
  521. // If we did not find an exact match, find the
  522. // successor ( node with smallest key > key )
  523. //
  524. if (!CurrNode)
  525. {
  526. PrevNode = ((PAVL_CONTEXT) Context)->InsPoint;
  527. if (!PrevNode)
  528. {
  529. // No items copied
  530. *NumItems = 0;
  531. return ERROR_NO_MORE_ITEMS;
  532. }
  533. NextChild = ((PAVL_CONTEXT) Context)->InsChild;
  534. if (NextChild == LEFT)
  535. {
  536. CurrNode = PrevNode;
  537. }
  538. else
  539. {
  540. CurrNode = PrevNode;
  541. while (CurrNode->Parent)
  542. {
  543. if (CurrNode->Parent->Child[LEFT] == CurrNode)
  544. {
  545. break;
  546. }
  547. CurrNode = CurrNode->Parent;
  548. }
  549. if (CurrNode->Parent)
  550. {
  551. CurrNode = CurrNode->Parent;
  552. }
  553. else
  554. {
  555. // No Items copied
  556. *NumItems = 0;
  557. return ERROR_NO_MORE_ITEMS;
  558. }
  559. }
  560. }
  561. if (*NumItems == 0)
  562. {
  563. return ERROR_INVALID_PARAMETER;
  564. }
  565. //
  566. // Enumeration Order: Node->LeftTree, Node, Node->RightTree
  567. //
  568. ItemsCopied = 0;
  569. do
  570. {
  571. // Check if this dest is before Stop Prefix (if it exists)
  572. if (StopKeyBits)
  573. {
  574. Comp = CompareFullKeys(CurrNode->KeyBits,
  575. StopKeyBits,
  576. Trie->MaxKeyBytes);
  577. if (Comp == 0)
  578. {
  579. if (CurrNode->NumBits <= StopNumBits)
  580. {
  581. Comp = -1;
  582. }
  583. else
  584. {
  585. Comp = +1;
  586. }
  587. }
  588. if (Comp > 0)
  589. {
  590. // Return Items Copied
  591. *NumItems = ItemsCopied;
  592. return ERROR_NO_MORE_ITEMS;
  593. }
  594. }
  595. // Copy current data to the output buffer
  596. DataItems[ItemsCopied++] = CurrNode->Data;
  597. // Find successor (smallest node > this node)
  598. if (CurrNode->Child[RIGHT])
  599. {
  600. NextNode = CurrNode->Child[RIGHT];
  601. while (NextNode->Child[LEFT])
  602. {
  603. NextNode = NextNode->Child[LEFT];
  604. }
  605. CurrNode = NextNode;
  606. }
  607. else
  608. {
  609. while (CurrNode->Parent)
  610. {
  611. if (CurrNode->Parent->Child[LEFT] == CurrNode)
  612. {
  613. break;
  614. }
  615. CurrNode = CurrNode->Parent;
  616. }
  617. if (CurrNode->Parent)
  618. {
  619. CurrNode = CurrNode->Parent;
  620. }
  621. else
  622. {
  623. // Return Items Copied
  624. *NumItems = ItemsCopied;
  625. return ERROR_NO_MORE_ITEMS;
  626. }
  627. }
  628. }
  629. while (ItemsCopied < *NumItems);
  630. // Update the temporary context
  631. ((PAVL_CONTEXT) Context)->BestNode = CurrNode;
  632. // Update enumeration context by adjusting starting prefix
  633. if (StartKeyBits)
  634. {
  635. *StartNumBits = CurrNode->NumBits;
  636. CopyFullKeys(StartKeyBits,
  637. CurrNode->KeyBits,
  638. Trie->MaxKeyBytes);
  639. }
  640. // Return Items Copied
  641. *NumItems = ItemsCopied;
  642. return NO_ERROR;
  643. }
  644. DWORD
  645. WINAPI
  646. DestroyTable(
  647. IN HANDLE Table
  648. )
  649. {
  650. PAVL_TRIE Trie;
  651. Trie = Table;
  652. if (Trie->TrieRoot != NULL)
  653. {
  654. return ERROR_NOT_EMPTY;
  655. }
  656. ASSERT(Trie->NumNodes == 0);
  657. #if _PROF_
  658. Trie->MemoryInUse -= sizeof(AVL_TRIE);
  659. #endif
  660. FreeMemory(Trie);
  661. return NO_ERROR;
  662. }
  663. BOOL
  664. WINAPI
  665. CheckTable(
  666. IN HANDLE Table
  667. )
  668. {
  669. BOOL Status;
  670. USHORT Depth;
  671. Status = CheckSubTrie(((PAVL_TRIE)Table)->TrieRoot, &Depth);
  672. #if _DBG_
  673. if (SUCCESS(Status))
  674. {
  675. Print("\nDepth of the AVL Trie = %lu\n\n", Depth);
  676. }
  677. #endif
  678. return SUCCESS(Status) ? TRUE : FALSE;
  679. }
  680. VOID
  681. WINAPI
  682. DumpTable(
  683. IN HANDLE Table,
  684. IN DWORD Flags
  685. )
  686. {
  687. PAVL_TRIE Trie;
  688. Trie = Table;
  689. Print("---------------- TABLE BEGIN ---------------------------\n\n");
  690. if (Flags & SUMMARY)
  691. {
  692. ;
  693. }
  694. #if PROF
  695. if (Flags & STATS)
  696. {
  697. Print(
  698. "Num of Ins = %6lu, Dels = %6lu, Sing Rots = %6lu, Dob Rots = %6lu\n"
  699. "Num Allocs = %6lu, Free = %6lu, Num Nodes = %6lu, Mem Used = %6lu\n",
  700. Trie->NumInsertions,
  701. Trie->NumDeletions,
  702. Trie->NumSingleRots,
  703. Trie->NumDoubleRots,
  704. Trie->NumAllocs,
  705. Trie->NumFrees,
  706. Trie->NumNodes,
  707. Trie->MemoryInUse);
  708. }
  709. #endif
  710. if (Flags & ITEMS)
  711. {
  712. Print("\n");
  713. DumpSubTrie(Trie->TrieRoot);
  714. Print("\n");
  715. }
  716. Print("---------------- TABLE END ---------------------------\n\n");
  717. }
  718. //
  719. // Helper Functions - used in insert and delete
  720. //
  721. VOID
  722. BalanceAfterInsert(
  723. IN PAVL_TRIE Trie,
  724. IN PAVL_NODE Node,
  725. IN AVL_BALANCE Longer
  726. )
  727. {
  728. #if _DBG_
  729. Print("Balance after Insert Called: %p %02x\n", Node, Longer);
  730. #endif
  731. ASSERT((Longer == LEFT) || (Longer == RIGHT));
  732. // Go up the tree adjusting the balances
  733. while (Node->Balance == EVEN)
  734. {
  735. Node->Balance = Longer;
  736. if (!Node->Parent)
  737. {
  738. return;
  739. }
  740. Longer = (Node->Parent->Child[LEFT] == Node) ? LEFT : RIGHT;
  741. Node = Node->Parent;
  742. }
  743. // We made the balance of an ancestor even
  744. if (Node->Balance != Longer)
  745. {
  746. Node->Balance = EVEN;
  747. return;
  748. }
  749. // Unbalanced a ancestor - rotate the tree
  750. if (Node->Child[Longer]->Balance == Longer)
  751. {
  752. SingleRotate(Trie, Node, (AVL_BALANCE) -Longer, &Node);
  753. }
  754. else
  755. {
  756. DoubleRotate(Trie, Node, (AVL_BALANCE) -Longer, &Node);
  757. }
  758. return;
  759. }
  760. VOID
  761. BalanceAfterDelete(
  762. IN PAVL_TRIE Trie,
  763. IN PAVL_NODE Node,
  764. IN AVL_BALANCE Shorter
  765. )
  766. {
  767. #if _DBG_
  768. Print("Balance after Delete Called: %p %02x\n", Node, Shorter);
  769. #endif
  770. ASSERT((Shorter == LEFT) || (Shorter == RIGHT));
  771. while (TRUE)
  772. {
  773. if (Node->Balance == EVEN)
  774. {
  775. Node->Balance = -Shorter;
  776. return;
  777. }
  778. if (Node->Balance == Shorter)
  779. {
  780. Node->Balance = EVEN;
  781. }
  782. else
  783. {
  784. ASSERT(Node->Child[-Shorter] != NULL);
  785. if (Node->Child[-Shorter]->Balance == -Shorter)
  786. {
  787. SingleRotate(Trie, Node, Shorter, &Node);
  788. }
  789. else
  790. if (Node->Child[-Shorter]->Balance == Shorter)
  791. {
  792. DoubleRotate(Trie, Node, Shorter, &Node);
  793. }
  794. else
  795. {
  796. SingleRotate(Trie, Node, Shorter, &Node);
  797. Node->Balance = Shorter;
  798. Node->Child[Shorter]->Balance = -Shorter;
  799. return;
  800. }
  801. }
  802. if (!Node->Parent)
  803. {
  804. return;
  805. }
  806. Shorter = (Node->Parent->Child[LEFT] == Node) ? LEFT : RIGHT;
  807. Node = Node->Parent;
  808. }
  809. }
  810. VOID
  811. SingleRotate(
  812. IN PAVL_TRIE Trie,
  813. IN PAVL_NODE UnbalNode,
  814. IN AVL_BALANCE Direction,
  815. OUT PAVL_NODE *BalancedNode
  816. )
  817. {
  818. PAVL_NODE PrevNode;
  819. PAVL_NODE CurrNode;
  820. PAVL_NODE NextNode;
  821. #if _DBG_
  822. Print("Single Rotate Called: %p %02x\n", UnbalNode, Direction);
  823. #endif
  824. #if PROF
  825. Trie->NumSingleRots++;
  826. #endif
  827. ASSERT((Direction == LEFT) || (Direction == RIGHT));
  828. CurrNode = UnbalNode;
  829. ASSERT(CurrNode != NULL);
  830. // To rotate right, we need left child and vice versa
  831. NextNode = CurrNode->Child[-Direction];
  832. ASSERT(NextNode != NULL);
  833. //
  834. // Promote the child to the unbalanced node's position
  835. //
  836. PrevNode = CurrNode->Parent;
  837. if (PrevNode)
  838. {
  839. if (PrevNode->Child[LEFT] == CurrNode)
  840. {
  841. PrevNode->Child[LEFT] = NextNode;
  842. }
  843. else
  844. {
  845. PrevNode->Child[RIGHT] = NextNode;
  846. }
  847. }
  848. else
  849. {
  850. Trie->TrieRoot = NextNode;
  851. }
  852. NextNode->Parent = PrevNode;
  853. //
  854. // Shift a subtree of child node to unbalanced node
  855. //
  856. CurrNode->Child[-Direction] = NextNode->Child[Direction];
  857. if (NextNode->Child[Direction])
  858. {
  859. NextNode->Child[Direction]->Parent = CurrNode;
  860. }
  861. //
  862. // Push unbalanced node as child of the next node
  863. // in place of this subtree that was moved before
  864. //
  865. NextNode->Child[Direction] = CurrNode;
  866. CurrNode->Parent = NextNode;
  867. //
  868. // Adjust balances that have changed due to rotation.
  869. // When this is not accurate, the caller adjusts the
  870. // balances appropriately upon return from this func.
  871. //
  872. CurrNode->Balance = NextNode->Balance = EVEN;
  873. // Return the next node as the new balanced node
  874. *BalancedNode = NextNode;
  875. return;
  876. }
  877. VOID
  878. DoubleRotate(
  879. IN PAVL_TRIE Trie,
  880. IN PAVL_NODE UnbalNode,
  881. IN AVL_BALANCE Direction,
  882. OUT PAVL_NODE *BalancedNode
  883. )
  884. {
  885. PAVL_NODE PrevNode;
  886. PAVL_NODE CurrNode;
  887. PAVL_NODE NextNode;
  888. PAVL_NODE LastNode;
  889. #if _DBG_
  890. Print("Double Rotate Called: %p %02x\n", UnbalNode, Direction);
  891. #endif
  892. #if PROF
  893. Trie->NumDoubleRots++;
  894. #endif
  895. ASSERT((Direction == LEFT) || (Direction == RIGHT));
  896. CurrNode = UnbalNode;
  897. ASSERT(CurrNode != NULL);
  898. //
  899. // To rotate right, we need left child and its right child
  900. //
  901. NextNode = CurrNode->Child[-Direction];
  902. ASSERT(NextNode != NULL);
  903. LastNode = NextNode->Child[Direction];
  904. ASSERT(LastNode != NULL);
  905. //
  906. // Move grandchild's children to other nodes higher up
  907. //
  908. CurrNode->Child[-Direction] = LastNode->Child[Direction];
  909. if (LastNode->Child[Direction])
  910. {
  911. LastNode->Child[Direction]->Parent = CurrNode;
  912. }
  913. NextNode->Child[Direction] = LastNode->Child[-Direction];
  914. if (LastNode->Child[-Direction])
  915. {
  916. LastNode->Child[-Direction]->Parent = NextNode;
  917. }
  918. //
  919. // Adjust the balances after the above node movements
  920. //
  921. CurrNode->Balance = EVEN;
  922. NextNode->Balance = EVEN;
  923. if (LastNode->Balance == LEFT)
  924. {
  925. if (Direction == LEFT)
  926. {
  927. NextNode->Balance = RIGHT;
  928. }
  929. else
  930. {
  931. CurrNode->Balance = RIGHT;
  932. }
  933. }
  934. else
  935. if (LastNode->Balance == RIGHT)
  936. {
  937. if (Direction == LEFT)
  938. {
  939. CurrNode->Balance = LEFT;
  940. }
  941. else
  942. {
  943. NextNode->Balance = LEFT;
  944. }
  945. }
  946. //
  947. // Promote grandchild to the unbalanced node's position
  948. //
  949. PrevNode = CurrNode->Parent;
  950. LastNode->Parent = PrevNode;
  951. if (PrevNode)
  952. {
  953. if (PrevNode->Child[LEFT] == CurrNode)
  954. {
  955. PrevNode->Child[LEFT] = LastNode;
  956. }
  957. else
  958. {
  959. PrevNode->Child[RIGHT] = LastNode;
  960. }
  961. }
  962. else
  963. {
  964. Trie->TrieRoot = LastNode;
  965. }
  966. LastNode->Child[-Direction] = NextNode;
  967. NextNode->Parent = LastNode;
  968. LastNode->Child[Direction] = CurrNode;
  969. CurrNode->Parent = LastNode;
  970. LastNode->Balance = EVEN;
  971. // The grandchild node is the new balanced node now
  972. *BalancedNode = LastNode;
  973. return;
  974. }
  975. VOID
  976. SwapWithSuccessor(
  977. IN PAVL_TRIE Trie,
  978. IN OUT PAVL_CONTEXT Context
  979. )
  980. {
  981. PAVL_NODE PrevNode;
  982. PAVL_NODE CurrNode;
  983. PAVL_NODE NextNode;
  984. PAVL_NODE TempNode1;
  985. PAVL_NODE TempNode2;
  986. AVL_BALANCE NextChild;
  987. // Get the context before the successor swap
  988. CurrNode = Context->BestNode;
  989. PrevNode = Context->InsPoint;
  990. NextChild = Context->InsChild;
  991. ASSERT(CurrNode->Child[LEFT] && CurrNode->Child[RIGHT]);
  992. // Find successor (smallest node > this node)
  993. NextNode = CurrNode->Child[RIGHT];
  994. while (NextNode->Child[LEFT])
  995. {
  996. NextNode = NextNode->Child[LEFT];
  997. }
  998. //
  999. // Save info for swapping node with its successor
  1000. //
  1001. TempNode1 = NextNode->Parent;
  1002. TempNode2 = NextNode->Child[RIGHT];
  1003. //
  1004. // Promote the successor to the node's position
  1005. //
  1006. NextNode->Balance = CurrNode->Balance;
  1007. NextNode->Parent = PrevNode;
  1008. if (PrevNode)
  1009. {
  1010. PrevNode->Child[NextChild] = NextNode;
  1011. }
  1012. else
  1013. {
  1014. Trie->TrieRoot = NextNode;
  1015. }
  1016. NextNode->Child[LEFT] = CurrNode->Child[LEFT];
  1017. NextNode->Child[LEFT]->Parent = NextNode;
  1018. // Is the successor the immediate right child ?
  1019. if (NextNode != CurrNode->Child[RIGHT])
  1020. {
  1021. NextNode->Child[RIGHT] = CurrNode->Child[RIGHT];
  1022. CurrNode->Parent = TempNode1;
  1023. TempNode1->Child[LEFT] = CurrNode;
  1024. NextChild = LEFT;
  1025. }
  1026. else
  1027. {
  1028. NextNode->Child[RIGHT] = CurrNode;
  1029. NextChild = RIGHT;
  1030. }
  1031. NextNode->Child[RIGHT]->Parent = NextNode;
  1032. //
  1033. // Put the node in the successor position
  1034. //
  1035. CurrNode->Child[LEFT] = NULL;
  1036. CurrNode->Child[RIGHT] = TempNode2;
  1037. if (CurrNode->Child[RIGHT])
  1038. {
  1039. CurrNode->Child[RIGHT]->Parent = CurrNode;
  1040. CurrNode->Balance = RIGHT;
  1041. }
  1042. else
  1043. {
  1044. CurrNode->Balance = EVEN;
  1045. }
  1046. PrevNode = CurrNode->Parent;
  1047. //
  1048. // Adjust prefix relationship between the
  1049. // node and its successor (if it existed)
  1050. //
  1051. if (NextNode->Prefix == CurrNode)
  1052. {
  1053. NextNode->Prefix = CurrNode->Prefix;
  1054. }
  1055. // Update context to reflect the successor swap
  1056. Context->BestNode = CurrNode;
  1057. Context->InsPoint = PrevNode;
  1058. Context->InsChild = NextChild;
  1059. return;
  1060. }
  1061. VOID
  1062. AdjustPrefixes(
  1063. IN PAVL_TRIE Trie,
  1064. IN PAVL_NODE OldNode,
  1065. IN PAVL_NODE NewNode,
  1066. IN PAVL_NODE TheNode,
  1067. IN PLOOKUP_CONTEXT Context
  1068. )
  1069. {
  1070. PAVL_NODE CurrNode;
  1071. UINT NumItems;
  1072. PLOOKUP_LINKAGE Dummy;
  1073. DWORD Status;
  1074. INT Comp;
  1075. #if _PROF_
  1076. UINT NumChecks;
  1077. UINT NumAdjust;
  1078. #endif
  1079. #if _DBG_
  1080. Print("Adjust Prefix Called: %p %p %p\n", OldNode, NewNode, TheNode);
  1081. #endif
  1082. //
  1083. // If this is part of an insert, we end our prefixes'
  1084. // adjustment when we pass out of the range of the
  1085. // node being inserted, while in the case of delete
  1086. // the range is determined by the node being deleted
  1087. //
  1088. // This node being deleted or inserted is "TheNode"
  1089. //
  1090. ASSERT((OldNode == TheNode) || (NewNode == TheNode));
  1091. #if _PROF_
  1092. NumChecks = 0;
  1093. NumAdjust = 0;
  1094. #endif
  1095. NumItems = 1;
  1096. do
  1097. {
  1098. #if _PROF_
  1099. NumChecks++;
  1100. #endif
  1101. Status =
  1102. EnumOverTable(Trie, NULL, NULL, Context, 0, NULL, &NumItems, &Dummy);
  1103. CurrNode = ((PAVL_CONTEXT) Context)->BestNode;
  1104. if (CurrNode->NumBits > TheNode->NumBits)
  1105. {
  1106. // Did we reach the end of our range ?
  1107. Comp = ComparePartialKeys(CurrNode->KeyBits,
  1108. TheNode->KeyBits,
  1109. TheNode->NumBits);
  1110. if (Comp > 0)
  1111. {
  1112. break;
  1113. }
  1114. if (CurrNode->Prefix == OldNode)
  1115. {
  1116. #if _PROF_
  1117. NumAdjust++;
  1118. #endif
  1119. CurrNode->Prefix = NewNode;
  1120. }
  1121. }
  1122. }
  1123. while (Status != ERROR_NO_MORE_ITEMS);
  1124. #if _PROF_
  1125. Print("Num Checks = %5d, Num Adjusts = %5d\n",
  1126. NumChecks,
  1127. NumAdjust);
  1128. #endif
  1129. }
  1130. //
  1131. // Helper Functions - used in CheckTable
  1132. //
  1133. DWORD
  1134. CheckSubTrie(
  1135. IN PAVL_NODE Node,
  1136. OUT PUSHORT Depth
  1137. )
  1138. {
  1139. DWORD Status;
  1140. USHORT LDepth;
  1141. USHORT RDepth;
  1142. Status = NO_ERROR;
  1143. *Depth = 0;
  1144. #if WRN
  1145. LDepth = 0;
  1146. RDepth = 0;
  1147. #endif
  1148. if (Node)
  1149. {
  1150. if (SUCCESS(Status))
  1151. {
  1152. Status = CheckSubTrie(Node->Child[LEFT], &LDepth);
  1153. }
  1154. if (SUCCESS(Status))
  1155. {
  1156. Status = CheckSubTrie(Node->Child[RIGHT], &RDepth);
  1157. }
  1158. if (SUCCESS(Status))
  1159. {
  1160. Status = CheckTrieNode(Node, LDepth, RDepth);
  1161. if (!SUCCESS(Status))
  1162. {
  1163. Print("Inconsistent information @ Node: %p\n",
  1164. Node);
  1165. }
  1166. }
  1167. if (SUCCESS(Status))
  1168. {
  1169. *Depth = (USHORT)((LDepth > RDepth) ? (LDepth + 1) : (RDepth + 1));
  1170. }
  1171. }
  1172. return Status;
  1173. }
  1174. DWORD
  1175. CheckTrieNode(
  1176. IN PAVL_NODE Node,
  1177. IN USHORT LDepth,
  1178. IN USHORT RDepth
  1179. )
  1180. {
  1181. AVL_BALANCE Balance;
  1182. // Check the balance first w.r.t LDepth and RDepth
  1183. Balance = RDepth - LDepth;
  1184. if ((Balance < -1) || (Balance > 1))
  1185. {
  1186. Print("Balance out of bounds: %d\n", Balance);
  1187. Print("LDepth = %lu, RDepth = %lu, NodeBal = %d\n",
  1188. LDepth, RDepth, Node->Balance);
  1189. DumpSubTrie(Node);
  1190. return ERROR_INVALID_DATA;
  1191. }
  1192. if (Balance != Node->Balance)
  1193. {
  1194. Print("Balance inconsistent\n");
  1195. return ERROR_INVALID_DATA;
  1196. }
  1197. // Check its child relationship with its parent
  1198. if (Node->Parent)
  1199. {
  1200. if ((Node->Parent->Child[LEFT] != Node) &&
  1201. (Node->Parent->Child[RIGHT] != Node))
  1202. {
  1203. Print("Parent relationship bad\n");
  1204. return ERROR_INVALID_DATA;
  1205. }
  1206. }
  1207. // Check its prefix relationship with its prefix
  1208. if (Node->Prefix)
  1209. {
  1210. if (Node->Prefix->NumBits >= Node->NumBits)
  1211. {
  1212. Print("Prefix relationship bad @1\n");
  1213. return ERROR_INVALID_DATA;
  1214. }
  1215. if (ComparePartialKeys(Node->Prefix->KeyBits,
  1216. Node->KeyBits,
  1217. Node->Prefix->NumBits) != 0)
  1218. {
  1219. Print("Prefix relationship bad @2\n");
  1220. return ERROR_INVALID_DATA;
  1221. }
  1222. }
  1223. return NO_ERROR;
  1224. }
  1225. //
  1226. // Helper Functions - used in DumpTable
  1227. //
  1228. VOID
  1229. DumpSubTrie(
  1230. IN PAVL_NODE Node
  1231. )
  1232. {
  1233. if (Node)
  1234. {
  1235. DumpSubTrie(Node->Child[LEFT]);
  1236. DumpTrieNode(Node);
  1237. DumpSubTrie(Node->Child[RIGHT]);
  1238. }
  1239. }
  1240. VOID
  1241. DumpTrieNode(
  1242. IN PAVL_NODE Node
  1243. )
  1244. {
  1245. USHORT i;
  1246. if (Node)
  1247. {
  1248. Print("TrieNode @ %p: NB = %8d, KB = ", Node, Node->NumBits);
  1249. for (i = 0; i < (Node->NumBits + BITS_IN_BYTE - 1) / BITS_IN_BYTE; i++)
  1250. {
  1251. Print("%3d.", Node->KeyBits[i]);
  1252. }
  1253. Print("\nLeft = %p, Parent = %p, Right = %p\n",
  1254. Node->Child[LEFT],
  1255. Node->Parent,
  1256. Node->Child[RIGHT]);
  1257. Print("Prefix = %p, Data = %p, Balance = %2d\n\n",
  1258. Node->Prefix,
  1259. Node->Data,
  1260. Node->Balance);
  1261. }
  1262. }