1------------------------------------------------------------------------------ 2-- -- 3-- GNAT LIBRARY COMPONENTS -- 4-- -- 5-- A D A . C O N T A I N E R S . M U L T I W A Y _ T R E E S -- 6-- -- 7-- B o d y -- 8-- -- 9-- Copyright (C) 2004-2020, Free Software Foundation, Inc. -- 10-- -- 11-- GNAT is free software; you can redistribute it and/or modify it under -- 12-- terms of the GNU General Public License as published by the Free Soft- -- 13-- ware Foundation; either version 3, or (at your option) any later ver- -- 14-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- 15-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- 16-- or FITNESS FOR A PARTICULAR PURPOSE. -- 17-- -- 18-- As a special exception under Section 7 of GPL version 3, you are granted -- 19-- additional permissions described in the GCC Runtime Library Exception, -- 20-- version 3.1, as published by the Free Software Foundation. -- 21-- -- 22-- You should have received a copy of the GNU General Public License and -- 23-- a copy of the GCC Runtime Library Exception along with this program; -- 24-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- 25-- <http://www.gnu.org/licenses/>. -- 26-- -- 27-- This unit was originally developed by Matthew J Heaney. -- 28------------------------------------------------------------------------------ 29 30with Ada.Unchecked_Conversion; 31with Ada.Unchecked_Deallocation; 32 33with System; use type System.Address; 34with System.Put_Images; 35 36package body Ada.Containers.Multiway_Trees with 37 SPARK_Mode => Off 38is 39 40 pragma Warnings (Off, "variable ""Busy*"" is not referenced"); 41 pragma Warnings (Off, "variable ""Lock*"" is not referenced"); 42 -- See comment in Ada.Containers.Helpers 43 44 -------------------- 45 -- Root_Iterator -- 46 -------------------- 47 48 type Root_Iterator is abstract new Limited_Controlled and 49 Tree_Iterator_Interfaces.Forward_Iterator with 50 record 51 Container : Tree_Access; 52 Subtree : Tree_Node_Access; 53 end record 54 with Disable_Controlled => not T_Check; 55 56 overriding procedure Finalize (Object : in out Root_Iterator); 57 58 ----------------------- 59 -- Subtree_Iterator -- 60 ----------------------- 61 62 -- ??? these headers are a bit odd, but for sure they do not substitute 63 -- for documenting things, what *is* a Subtree_Iterator? 64 65 type Subtree_Iterator is new Root_Iterator with null record; 66 67 overriding function First (Object : Subtree_Iterator) return Cursor; 68 69 overriding function Next 70 (Object : Subtree_Iterator; 71 Position : Cursor) return Cursor; 72 73 --------------------- 74 -- Child_Iterator -- 75 --------------------- 76 77 type Child_Iterator is new Root_Iterator and 78 Tree_Iterator_Interfaces.Reversible_Iterator with null record 79 with Disable_Controlled => not T_Check; 80 81 overriding function First (Object : Child_Iterator) return Cursor; 82 83 overriding function Next 84 (Object : Child_Iterator; 85 Position : Cursor) return Cursor; 86 87 overriding function Last (Object : Child_Iterator) return Cursor; 88 89 overriding function Previous 90 (Object : Child_Iterator; 91 Position : Cursor) return Cursor; 92 93 ----------------------- 94 -- Local Subprograms -- 95 ----------------------- 96 97 function Root_Node (Container : Tree) return Tree_Node_Access; 98 99 procedure Deallocate_Node is 100 new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access); 101 102 procedure Deallocate_Children 103 (Subtree : Tree_Node_Access; 104 Count : in out Count_Type); 105 106 procedure Deallocate_Subtree 107 (Subtree : in out Tree_Node_Access; 108 Count : in out Count_Type); 109 110 function Equal_Children 111 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean; 112 113 function Equal_Subtree 114 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean; 115 116 procedure Iterate_Children 117 (Container : Tree_Access; 118 Subtree : Tree_Node_Access; 119 Process : not null access procedure (Position : Cursor)); 120 121 procedure Iterate_Subtree 122 (Container : Tree_Access; 123 Subtree : Tree_Node_Access; 124 Process : not null access procedure (Position : Cursor)); 125 126 procedure Copy_Children 127 (Source : Children_Type; 128 Parent : Tree_Node_Access; 129 Count : in out Count_Type); 130 131 procedure Copy_Subtree 132 (Source : Tree_Node_Access; 133 Parent : Tree_Node_Access; 134 Target : out Tree_Node_Access; 135 Count : in out Count_Type); 136 137 function Find_In_Children 138 (Subtree : Tree_Node_Access; 139 Item : Element_Type) return Tree_Node_Access; 140 141 function Find_In_Subtree 142 (Subtree : Tree_Node_Access; 143 Item : Element_Type) return Tree_Node_Access; 144 145 function Child_Count (Children : Children_Type) return Count_Type; 146 147 function Subtree_Node_Count 148 (Subtree : Tree_Node_Access) return Count_Type; 149 150 function Is_Reachable (From, To : Tree_Node_Access) return Boolean; 151 152 procedure Remove_Subtree (Subtree : Tree_Node_Access); 153 154 procedure Insert_Subtree_Node 155 (Subtree : Tree_Node_Access; 156 Parent : Tree_Node_Access; 157 Before : Tree_Node_Access); 158 159 procedure Insert_Subtree_List 160 (First : Tree_Node_Access; 161 Last : Tree_Node_Access; 162 Parent : Tree_Node_Access; 163 Before : Tree_Node_Access); 164 165 procedure Splice_Children 166 (Target_Parent : Tree_Node_Access; 167 Before : Tree_Node_Access; 168 Source_Parent : Tree_Node_Access); 169 170 --------- 171 -- "=" -- 172 --------- 173 174 function "=" (Left, Right : Tree) return Boolean is 175 begin 176 return Equal_Children (Root_Node (Left), Root_Node (Right)); 177 end "="; 178 179 ------------ 180 -- Adjust -- 181 ------------ 182 183 procedure Adjust (Container : in out Tree) is 184 Source : constant Children_Type := Container.Root.Children; 185 Source_Count : constant Count_Type := Container.Count; 186 Target_Count : Count_Type; 187 188 begin 189 -- We first restore the target container to its default-initialized 190 -- state, before we attempt any allocation, to ensure that invariants 191 -- are preserved in the event that the allocation fails. 192 193 Container.Root.Children := Children_Type'(others => null); 194 Zero_Counts (Container.TC); 195 Container.Count := 0; 196 197 -- Copy_Children returns a count of the number of nodes that it 198 -- allocates, but it works by incrementing the value that is passed 199 -- in. We must therefore initialize the count value before calling 200 -- Copy_Children. 201 202 Target_Count := 0; 203 204 -- Now we attempt the allocation of subtrees. The invariants are 205 -- satisfied even if the allocation fails. 206 207 Copy_Children (Source, Root_Node (Container), Target_Count); 208 pragma Assert (Target_Count = Source_Count); 209 210 Container.Count := Source_Count; 211 end Adjust; 212 213 ------------------- 214 -- Ancestor_Find -- 215 ------------------- 216 217 function Ancestor_Find 218 (Position : Cursor; 219 Item : Element_Type) return Cursor 220 is 221 R, N : Tree_Node_Access; 222 223 begin 224 if Checks and then Position = No_Element then 225 raise Constraint_Error with "Position cursor has no element"; 226 end if; 227 228 -- Commented-out pending official ruling from ARG. ??? 229 230 -- if Position.Container /= Container'Unrestricted_Access then 231 -- raise Program_Error with "Position cursor not in container"; 232 -- end if; 233 234 -- AI-0136 says to raise PE if Position equals the root node. This does 235 -- not seem correct, as this value is just the limiting condition of the 236 -- search. For now we omit this check, pending a ruling from the ARG.??? 237 238 -- if Checks and then Is_Root (Position) then 239 -- raise Program_Error with "Position cursor designates root"; 240 -- end if; 241 242 R := Root_Node (Position.Container.all); 243 N := Position.Node; 244 while N /= R loop 245 if N.Element = Item then 246 return Cursor'(Position.Container, N); 247 end if; 248 249 N := N.Parent; 250 end loop; 251 252 return No_Element; 253 end Ancestor_Find; 254 255 ------------------ 256 -- Append_Child -- 257 ------------------ 258 259 procedure Append_Child 260 (Container : in out Tree; 261 Parent : Cursor; 262 New_Item : Element_Type; 263 Count : Count_Type := 1) 264 is 265 First : Tree_Node_Access; 266 Last : Tree_Node_Access; 267 268 begin 269 TC_Check (Container.TC); 270 271 if Checks and then Parent = No_Element then 272 raise Constraint_Error with "Parent cursor has no element"; 273 end if; 274 275 if Checks and then Parent.Container /= Container'Unrestricted_Access then 276 raise Program_Error with "Parent cursor not in container"; 277 end if; 278 279 if Count = 0 then 280 return; 281 end if; 282 283 First := new Tree_Node_Type'(Parent => Parent.Node, 284 Element => New_Item, 285 others => <>); 286 287 Last := First; 288 for J in Count_Type'(2) .. Count loop 289 290 -- Reclaim other nodes if Storage_Error. ??? 291 292 Last.Next := new Tree_Node_Type'(Parent => Parent.Node, 293 Prev => Last, 294 Element => New_Item, 295 others => <>); 296 297 Last := Last.Next; 298 end loop; 299 300 Insert_Subtree_List 301 (First => First, 302 Last => Last, 303 Parent => Parent.Node, 304 Before => null); -- null means "insert at end of list" 305 306 -- In order for operation Node_Count to complete in O(1) time, we cache 307 -- the count value. Here we increment the total count by the number of 308 -- nodes we just inserted. 309 310 Container.Count := Container.Count + Count; 311 end Append_Child; 312 313 ------------ 314 -- Assign -- 315 ------------ 316 317 procedure Assign (Target : in out Tree; Source : Tree) is 318 Source_Count : constant Count_Type := Source.Count; 319 Target_Count : Count_Type; 320 321 begin 322 if Target'Address = Source'Address then 323 return; 324 end if; 325 326 Target.Clear; -- checks busy bit 327 328 -- Copy_Children returns the number of nodes that it allocates, but it 329 -- does this by incrementing the count value passed in, so we must 330 -- initialize the count before calling Copy_Children. 331 332 Target_Count := 0; 333 334 -- Note that Copy_Children inserts the newly-allocated children into 335 -- their parent list only after the allocation of all the children has 336 -- succeeded. This preserves invariants even if the allocation fails. 337 338 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count); 339 pragma Assert (Target_Count = Source_Count); 340 341 Target.Count := Source_Count; 342 end Assign; 343 344 ----------------- 345 -- Child_Count -- 346 ----------------- 347 348 function Child_Count (Parent : Cursor) return Count_Type is 349 begin 350 return (if Parent = No_Element 351 then 0 else Child_Count (Parent.Node.Children)); 352 end Child_Count; 353 354 function Child_Count (Children : Children_Type) return Count_Type is 355 Result : Count_Type; 356 Node : Tree_Node_Access; 357 358 begin 359 Result := 0; 360 Node := Children.First; 361 while Node /= null loop 362 Result := Result + 1; 363 Node := Node.Next; 364 end loop; 365 366 return Result; 367 end Child_Count; 368 369 ----------------- 370 -- Child_Depth -- 371 ----------------- 372 373 function Child_Depth (Parent, Child : Cursor) return Count_Type is 374 Result : Count_Type; 375 N : Tree_Node_Access; 376 377 begin 378 if Checks and then Parent = No_Element then 379 raise Constraint_Error with "Parent cursor has no element"; 380 end if; 381 382 if Checks and then Child = No_Element then 383 raise Constraint_Error with "Child cursor has no element"; 384 end if; 385 386 if Checks and then Parent.Container /= Child.Container then 387 raise Program_Error with "Parent and Child in different containers"; 388 end if; 389 390 Result := 0; 391 N := Child.Node; 392 while N /= Parent.Node loop 393 Result := Result + 1; 394 N := N.Parent; 395 396 if Checks and then N = null then 397 raise Program_Error with "Parent is not ancestor of Child"; 398 end if; 399 end loop; 400 401 return Result; 402 end Child_Depth; 403 404 ----------- 405 -- Clear -- 406 ----------- 407 408 procedure Clear (Container : in out Tree) is 409 Container_Count, Children_Count : Count_Type; 410 411 begin 412 TC_Check (Container.TC); 413 414 -- We first set the container count to 0, in order to preserve 415 -- invariants in case the deallocation fails. (This works because 416 -- Deallocate_Children immediately removes the children from their 417 -- parent, and then does the actual deallocation.) 418 419 Container_Count := Container.Count; 420 Container.Count := 0; 421 422 -- Deallocate_Children returns the number of nodes that it deallocates, 423 -- but it does this by incrementing the count value that is passed in, 424 -- so we must first initialize the count return value before calling it. 425 426 Children_Count := 0; 427 428 -- See comment above. Deallocate_Children immediately removes the 429 -- children list from their parent node (here, the root of the tree), 430 -- and only after that does it attempt the actual deallocation. So even 431 -- if the deallocation fails, the representation invariants for the tree 432 -- are preserved. 433 434 Deallocate_Children (Root_Node (Container), Children_Count); 435 pragma Assert (Children_Count = Container_Count); 436 end Clear; 437 438 ------------------------ 439 -- Constant_Reference -- 440 ------------------------ 441 442 function Constant_Reference 443 (Container : aliased Tree; 444 Position : Cursor) return Constant_Reference_Type 445 is 446 begin 447 if Checks and then Position.Container = null then 448 raise Constraint_Error with 449 "Position cursor has no element"; 450 end if; 451 452 if Checks and then Position.Container /= Container'Unrestricted_Access 453 then 454 raise Program_Error with 455 "Position cursor designates wrong container"; 456 end if; 457 458 if Checks and then Position.Node = Root_Node (Container) then 459 raise Program_Error with "Position cursor designates root"; 460 end if; 461 462 -- Implement Vet for multiway tree??? 463 -- pragma Assert (Vet (Position), 464 -- "Position cursor in Constant_Reference is bad"); 465 466 declare 467 C : Tree renames Position.Container.all; 468 TC : constant Tamper_Counts_Access := 469 C.TC'Unrestricted_Access; 470 begin 471 return R : constant Constant_Reference_Type := 472 (Element => Position.Node.Element'Access, 473 Control => (Controlled with TC)) 474 do 475 Busy (TC.all); 476 end return; 477 end; 478 end Constant_Reference; 479 480 -------------- 481 -- Contains -- 482 -------------- 483 484 function Contains 485 (Container : Tree; 486 Item : Element_Type) return Boolean 487 is 488 begin 489 return Find (Container, Item) /= No_Element; 490 end Contains; 491 492 ---------- 493 -- Copy -- 494 ---------- 495 496 function Copy (Source : Tree) return Tree is 497 begin 498 return Target : Tree do 499 Copy_Children 500 (Source => Source.Root.Children, 501 Parent => Root_Node (Target), 502 Count => Target.Count); 503 504 pragma Assert (Target.Count = Source.Count); 505 end return; 506 end Copy; 507 508 ------------------- 509 -- Copy_Children -- 510 ------------------- 511 512 procedure Copy_Children 513 (Source : Children_Type; 514 Parent : Tree_Node_Access; 515 Count : in out Count_Type) 516 is 517 pragma Assert (Parent /= null); 518 pragma Assert (Parent.Children.First = null); 519 pragma Assert (Parent.Children.Last = null); 520 521 CC : Children_Type; 522 C : Tree_Node_Access; 523 524 begin 525 -- We special-case the first allocation, in order to establish the 526 -- representation invariants for type Children_Type. 527 528 C := Source.First; 529 530 if C = null then 531 return; 532 end if; 533 534 Copy_Subtree 535 (Source => C, 536 Parent => Parent, 537 Target => CC.First, 538 Count => Count); 539 540 CC.Last := CC.First; 541 542 -- The representation invariants for the Children_Type list have been 543 -- established, so we can now copy the remaining children of Source. 544 545 C := C.Next; 546 while C /= null loop 547 Copy_Subtree 548 (Source => C, 549 Parent => Parent, 550 Target => CC.Last.Next, 551 Count => Count); 552 553 CC.Last.Next.Prev := CC.Last; 554 CC.Last := CC.Last.Next; 555 556 C := C.Next; 557 end loop; 558 559 -- Add the newly-allocated children to their parent list only after the 560 -- allocation has succeeded, so as to preserve invariants of the parent. 561 562 Parent.Children := CC; 563 end Copy_Children; 564 565 ------------------ 566 -- Copy_Subtree -- 567 ------------------ 568 569 procedure Copy_Subtree 570 (Target : in out Tree; 571 Parent : Cursor; 572 Before : Cursor; 573 Source : Cursor) 574 is 575 Target_Subtree : Tree_Node_Access; 576 Target_Count : Count_Type; 577 578 begin 579 if Checks and then Parent = No_Element then 580 raise Constraint_Error with "Parent cursor has no element"; 581 end if; 582 583 if Checks and then Parent.Container /= Target'Unrestricted_Access then 584 raise Program_Error with "Parent cursor not in container"; 585 end if; 586 587 if Before /= No_Element then 588 if Checks and then Before.Container /= Target'Unrestricted_Access then 589 raise Program_Error with "Before cursor not in container"; 590 end if; 591 592 if Checks and then Before.Node.Parent /= Parent.Node then 593 raise Constraint_Error with "Before cursor not child of Parent"; 594 end if; 595 end if; 596 597 if Source = No_Element then 598 return; 599 end if; 600 601 if Checks and then Is_Root (Source) then 602 raise Constraint_Error with "Source cursor designates root"; 603 end if; 604 605 -- Copy_Subtree returns a count of the number of nodes that it 606 -- allocates, but it works by incrementing the value that is passed 607 -- in. We must therefore initialize the count value before calling 608 -- Copy_Subtree. 609 610 Target_Count := 0; 611 612 Copy_Subtree 613 (Source => Source.Node, 614 Parent => Parent.Node, 615 Target => Target_Subtree, 616 Count => Target_Count); 617 618 pragma Assert (Target_Subtree /= null); 619 pragma Assert (Target_Subtree.Parent = Parent.Node); 620 pragma Assert (Target_Count >= 1); 621 622 Insert_Subtree_Node 623 (Subtree => Target_Subtree, 624 Parent => Parent.Node, 625 Before => Before.Node); 626 627 -- In order for operation Node_Count to complete in O(1) time, we cache 628 -- the count value. Here we increment the total count by the number of 629 -- nodes we just inserted. 630 631 Target.Count := Target.Count + Target_Count; 632 end Copy_Subtree; 633 634 procedure Copy_Subtree 635 (Source : Tree_Node_Access; 636 Parent : Tree_Node_Access; 637 Target : out Tree_Node_Access; 638 Count : in out Count_Type) 639 is 640 begin 641 Target := new Tree_Node_Type'(Element => Source.Element, 642 Parent => Parent, 643 others => <>); 644 645 Count := Count + 1; 646 647 Copy_Children 648 (Source => Source.Children, 649 Parent => Target, 650 Count => Count); 651 end Copy_Subtree; 652 653 ------------------------- 654 -- Deallocate_Children -- 655 ------------------------- 656 657 procedure Deallocate_Children 658 (Subtree : Tree_Node_Access; 659 Count : in out Count_Type) 660 is 661 pragma Assert (Subtree /= null); 662 663 CC : Children_Type := Subtree.Children; 664 C : Tree_Node_Access; 665 666 begin 667 -- We immediately remove the children from their parent, in order to 668 -- preserve invariants in case the deallocation fails. 669 670 Subtree.Children := Children_Type'(others => null); 671 672 while CC.First /= null loop 673 C := CC.First; 674 CC.First := C.Next; 675 676 Deallocate_Subtree (C, Count); 677 end loop; 678 end Deallocate_Children; 679 680 ------------------------ 681 -- Deallocate_Subtree -- 682 ------------------------ 683 684 procedure Deallocate_Subtree 685 (Subtree : in out Tree_Node_Access; 686 Count : in out Count_Type) 687 is 688 begin 689 Deallocate_Children (Subtree, Count); 690 Deallocate_Node (Subtree); 691 Count := Count + 1; 692 end Deallocate_Subtree; 693 694 --------------------- 695 -- Delete_Children -- 696 --------------------- 697 698 procedure Delete_Children 699 (Container : in out Tree; 700 Parent : Cursor) 701 is 702 Count : Count_Type; 703 704 begin 705 TC_Check (Container.TC); 706 707 if Checks and then Parent = No_Element then 708 raise Constraint_Error with "Parent cursor has no element"; 709 end if; 710 711 if Checks and then Parent.Container /= Container'Unrestricted_Access then 712 raise Program_Error with "Parent cursor not in container"; 713 end if; 714 715 -- Deallocate_Children returns a count of the number of nodes that it 716 -- deallocates, but it works by incrementing the value that is passed 717 -- in. We must therefore initialize the count value before calling 718 -- Deallocate_Children. 719 720 Count := 0; 721 722 Deallocate_Children (Parent.Node, Count); 723 pragma Assert (Count <= Container.Count); 724 725 Container.Count := Container.Count - Count; 726 end Delete_Children; 727 728 ----------------- 729 -- Delete_Leaf -- 730 ----------------- 731 732 procedure Delete_Leaf 733 (Container : in out Tree; 734 Position : in out Cursor) 735 is 736 X : Tree_Node_Access; 737 738 begin 739 TC_Check (Container.TC); 740 741 if Checks and then Position = No_Element then 742 raise Constraint_Error with "Position cursor has no element"; 743 end if; 744 745 if Checks and then Position.Container /= Container'Unrestricted_Access 746 then 747 raise Program_Error with "Position cursor not in container"; 748 end if; 749 750 if Checks and then Is_Root (Position) then 751 raise Program_Error with "Position cursor designates root"; 752 end if; 753 754 if Checks and then not Is_Leaf (Position) then 755 raise Constraint_Error with "Position cursor does not designate leaf"; 756 end if; 757 758 X := Position.Node; 759 Position := No_Element; 760 761 -- Restore represention invariants before attempting the actual 762 -- deallocation. 763 764 Remove_Subtree (X); 765 Container.Count := Container.Count - 1; 766 767 -- It is now safe to attempt the deallocation. This leaf node has been 768 -- disassociated from the tree, so even if the deallocation fails, 769 -- representation invariants will remain satisfied. 770 771 Deallocate_Node (X); 772 end Delete_Leaf; 773 774 -------------------- 775 -- Delete_Subtree -- 776 -------------------- 777 778 procedure Delete_Subtree 779 (Container : in out Tree; 780 Position : in out Cursor) 781 is 782 X : Tree_Node_Access; 783 Count : Count_Type; 784 785 begin 786 TC_Check (Container.TC); 787 788 if Checks and then Position = No_Element then 789 raise Constraint_Error with "Position cursor has no element"; 790 end if; 791 792 if Checks and then Position.Container /= Container'Unrestricted_Access 793 then 794 raise Program_Error with "Position cursor not in container"; 795 end if; 796 797 if Checks and then Is_Root (Position) then 798 raise Program_Error with "Position cursor designates root"; 799 end if; 800 801 X := Position.Node; 802 Position := No_Element; 803 804 -- Here is one case where a deallocation failure can result in the 805 -- violation of a representation invariant. We disassociate the subtree 806 -- from the tree now, but we only decrement the total node count after 807 -- we attempt the deallocation. However, if the deallocation fails, the 808 -- total node count will not get decremented. 809 810 -- One way around this dilemma is to count the nodes in the subtree 811 -- before attempt to delete the subtree, but that is an O(n) operation, 812 -- so it does not seem worth it. 813 814 -- Perhaps this is much ado about nothing, since the only way 815 -- deallocation can fail is if Controlled Finalization fails: this 816 -- propagates Program_Error so all bets are off anyway. ??? 817 818 Remove_Subtree (X); 819 820 -- Deallocate_Subtree returns a count of the number of nodes that it 821 -- deallocates, but it works by incrementing the value that is passed 822 -- in. We must therefore initialize the count value before calling 823 -- Deallocate_Subtree. 824 825 Count := 0; 826 827 Deallocate_Subtree (X, Count); 828 pragma Assert (Count <= Container.Count); 829 830 -- See comments above. We would prefer to do this sooner, but there's no 831 -- way to satisfy that goal without a potentially severe execution 832 -- penalty. 833 834 Container.Count := Container.Count - Count; 835 end Delete_Subtree; 836 837 ----------- 838 -- Depth -- 839 ----------- 840 841 function Depth (Position : Cursor) return Count_Type is 842 Result : Count_Type; 843 N : Tree_Node_Access; 844 845 begin 846 Result := 0; 847 N := Position.Node; 848 while N /= null loop 849 N := N.Parent; 850 Result := Result + 1; 851 end loop; 852 853 return Result; 854 end Depth; 855 856 ------------- 857 -- Element -- 858 ------------- 859 860 function Element (Position : Cursor) return Element_Type is 861 begin 862 if Checks and then Position.Container = null then 863 raise Constraint_Error with "Position cursor has no element"; 864 end if; 865 866 if Checks and then Position.Node = Root_Node (Position.Container.all) 867 then 868 raise Program_Error with "Position cursor designates root"; 869 end if; 870 871 return Position.Node.Element; 872 end Element; 873 874 -------------------- 875 -- Equal_Children -- 876 -------------------- 877 878 function Equal_Children 879 (Left_Subtree : Tree_Node_Access; 880 Right_Subtree : Tree_Node_Access) return Boolean 881 is 882 Left_Children : Children_Type renames Left_Subtree.Children; 883 Right_Children : Children_Type renames Right_Subtree.Children; 884 885 L, R : Tree_Node_Access; 886 887 begin 888 if Child_Count (Left_Children) /= Child_Count (Right_Children) then 889 return False; 890 end if; 891 892 L := Left_Children.First; 893 R := Right_Children.First; 894 while L /= null loop 895 if not Equal_Subtree (L, R) then 896 return False; 897 end if; 898 899 L := L.Next; 900 R := R.Next; 901 end loop; 902 903 return True; 904 end Equal_Children; 905 906 ------------------- 907 -- Equal_Subtree -- 908 ------------------- 909 910 function Equal_Subtree 911 (Left_Position : Cursor; 912 Right_Position : Cursor) return Boolean 913 is 914 begin 915 if Checks and then Left_Position = No_Element then 916 raise Constraint_Error with "Left cursor has no element"; 917 end if; 918 919 if Checks and then Right_Position = No_Element then 920 raise Constraint_Error with "Right cursor has no element"; 921 end if; 922 923 if Left_Position = Right_Position then 924 return True; 925 end if; 926 927 if Is_Root (Left_Position) then 928 if not Is_Root (Right_Position) then 929 return False; 930 end if; 931 932 return Equal_Children (Left_Position.Node, Right_Position.Node); 933 end if; 934 935 if Is_Root (Right_Position) then 936 return False; 937 end if; 938 939 return Equal_Subtree (Left_Position.Node, Right_Position.Node); 940 end Equal_Subtree; 941 942 function Equal_Subtree 943 (Left_Subtree : Tree_Node_Access; 944 Right_Subtree : Tree_Node_Access) return Boolean 945 is 946 begin 947 if Left_Subtree.Element /= Right_Subtree.Element then 948 return False; 949 end if; 950 951 return Equal_Children (Left_Subtree, Right_Subtree); 952 end Equal_Subtree; 953 954 -------------- 955 -- Finalize -- 956 -------------- 957 958 procedure Finalize (Object : in out Root_Iterator) is 959 begin 960 Unbusy (Object.Container.TC); 961 end Finalize; 962 963 ---------- 964 -- Find -- 965 ---------- 966 967 function Find 968 (Container : Tree; 969 Item : Element_Type) return Cursor 970 is 971 N : constant Tree_Node_Access := 972 Find_In_Children (Root_Node (Container), Item); 973 begin 974 if N = null then 975 return No_Element; 976 else 977 return Cursor'(Container'Unrestricted_Access, N); 978 end if; 979 end Find; 980 981 ----------- 982 -- First -- 983 ----------- 984 985 overriding function First (Object : Subtree_Iterator) return Cursor is 986 begin 987 if Object.Subtree = Root_Node (Object.Container.all) then 988 return First_Child (Root (Object.Container.all)); 989 else 990 return Cursor'(Object.Container, Object.Subtree); 991 end if; 992 end First; 993 994 overriding function First (Object : Child_Iterator) return Cursor is 995 begin 996 return First_Child (Cursor'(Object.Container, Object.Subtree)); 997 end First; 998 999 ----------------- 1000 -- First_Child -- 1001 ----------------- 1002 1003 function First_Child (Parent : Cursor) return Cursor is 1004 Node : Tree_Node_Access; 1005 1006 begin 1007 if Checks and then Parent = No_Element then 1008 raise Constraint_Error with "Parent cursor has no element"; 1009 end if; 1010 1011 Node := Parent.Node.Children.First; 1012 1013 if Node = null then 1014 return No_Element; 1015 end if; 1016 1017 return Cursor'(Parent.Container, Node); 1018 end First_Child; 1019 1020 ------------------------- 1021 -- First_Child_Element -- 1022 ------------------------- 1023 1024 function First_Child_Element (Parent : Cursor) return Element_Type is 1025 begin 1026 return Element (First_Child (Parent)); 1027 end First_Child_Element; 1028 1029 ---------------------- 1030 -- Find_In_Children -- 1031 ---------------------- 1032 1033 function Find_In_Children 1034 (Subtree : Tree_Node_Access; 1035 Item : Element_Type) return Tree_Node_Access 1036 is 1037 N, Result : Tree_Node_Access; 1038 1039 begin 1040 N := Subtree.Children.First; 1041 while N /= null loop 1042 Result := Find_In_Subtree (N, Item); 1043 1044 if Result /= null then 1045 return Result; 1046 end if; 1047 1048 N := N.Next; 1049 end loop; 1050 1051 return null; 1052 end Find_In_Children; 1053 1054 --------------------- 1055 -- Find_In_Subtree -- 1056 --------------------- 1057 1058 function Find_In_Subtree 1059 (Position : Cursor; 1060 Item : Element_Type) return Cursor 1061 is 1062 Result : Tree_Node_Access; 1063 1064 begin 1065 if Checks and then Position = No_Element then 1066 raise Constraint_Error with "Position cursor has no element"; 1067 end if; 1068 1069 -- Commented out pending official ruling by ARG. ??? 1070 1071 -- if Checks and then 1072 -- Position.Container /= Container'Unrestricted_Access 1073 -- then 1074 -- raise Program_Error with "Position cursor not in container"; 1075 -- end if; 1076 1077 Result := 1078 (if Is_Root (Position) 1079 then Find_In_Children (Position.Node, Item) 1080 else Find_In_Subtree (Position.Node, Item)); 1081 1082 if Result = null then 1083 return No_Element; 1084 end if; 1085 1086 return Cursor'(Position.Container, Result); 1087 end Find_In_Subtree; 1088 1089 function Find_In_Subtree 1090 (Subtree : Tree_Node_Access; 1091 Item : Element_Type) return Tree_Node_Access 1092 is 1093 begin 1094 if Subtree.Element = Item then 1095 return Subtree; 1096 end if; 1097 1098 return Find_In_Children (Subtree, Item); 1099 end Find_In_Subtree; 1100 1101 ------------------------ 1102 -- Get_Element_Access -- 1103 ------------------------ 1104 1105 function Get_Element_Access 1106 (Position : Cursor) return not null Element_Access is 1107 begin 1108 return Position.Node.Element'Access; 1109 end Get_Element_Access; 1110 1111 ----------------- 1112 -- Has_Element -- 1113 ----------------- 1114 1115 function Has_Element (Position : Cursor) return Boolean is 1116 begin 1117 return (if Position = No_Element then False 1118 else Position.Node.Parent /= null); 1119 end Has_Element; 1120 1121 ------------------ 1122 -- Insert_Child -- 1123 ------------------ 1124 1125 procedure Insert_Child 1126 (Container : in out Tree; 1127 Parent : Cursor; 1128 Before : Cursor; 1129 New_Item : Element_Type; 1130 Count : Count_Type := 1) 1131 is 1132 Position : Cursor; 1133 pragma Unreferenced (Position); 1134 1135 begin 1136 Insert_Child (Container, Parent, Before, New_Item, Position, Count); 1137 end Insert_Child; 1138 1139 procedure Insert_Child 1140 (Container : in out Tree; 1141 Parent : Cursor; 1142 Before : Cursor; 1143 New_Item : Element_Type; 1144 Position : out Cursor; 1145 Count : Count_Type := 1) 1146 is 1147 First : Tree_Node_Access; 1148 Last : Tree_Node_Access; 1149 1150 begin 1151 TC_Check (Container.TC); 1152 1153 if Checks and then Parent = No_Element then 1154 raise Constraint_Error with "Parent cursor has no element"; 1155 end if; 1156 1157 if Checks and then Parent.Container /= Container'Unrestricted_Access then 1158 raise Program_Error with "Parent cursor not in container"; 1159 end if; 1160 1161 if Before /= No_Element then 1162 if Checks and then Before.Container /= Container'Unrestricted_Access 1163 then 1164 raise Program_Error with "Before cursor not in container"; 1165 end if; 1166 1167 if Checks and then Before.Node.Parent /= Parent.Node then 1168 raise Constraint_Error with "Parent cursor not parent of Before"; 1169 end if; 1170 end if; 1171 1172 if Count = 0 then 1173 Position := No_Element; -- Need ruling from ARG ??? 1174 return; 1175 end if; 1176 1177 First := new Tree_Node_Type'(Parent => Parent.Node, 1178 Element => New_Item, 1179 others => <>); 1180 1181 Last := First; 1182 for J in Count_Type'(2) .. Count loop 1183 1184 -- Reclaim other nodes if Storage_Error. ??? 1185 1186 Last.Next := new Tree_Node_Type'(Parent => Parent.Node, 1187 Prev => Last, 1188 Element => New_Item, 1189 others => <>); 1190 1191 Last := Last.Next; 1192 end loop; 1193 1194 Insert_Subtree_List 1195 (First => First, 1196 Last => Last, 1197 Parent => Parent.Node, 1198 Before => Before.Node); 1199 1200 -- In order for operation Node_Count to complete in O(1) time, we cache 1201 -- the count value. Here we increment the total count by the number of 1202 -- nodes we just inserted. 1203 1204 Container.Count := Container.Count + Count; 1205 1206 Position := Cursor'(Parent.Container, First); 1207 end Insert_Child; 1208 1209 procedure Insert_Child 1210 (Container : in out Tree; 1211 Parent : Cursor; 1212 Before : Cursor; 1213 Position : out Cursor; 1214 Count : Count_Type := 1) 1215 is 1216 First : Tree_Node_Access; 1217 Last : Tree_Node_Access; 1218 1219 begin 1220 TC_Check (Container.TC); 1221 1222 if Checks and then Parent = No_Element then 1223 raise Constraint_Error with "Parent cursor has no element"; 1224 end if; 1225 1226 if Checks and then Parent.Container /= Container'Unrestricted_Access then 1227 raise Program_Error with "Parent cursor not in container"; 1228 end if; 1229 1230 if Before /= No_Element then 1231 if Checks and then Before.Container /= Container'Unrestricted_Access 1232 then 1233 raise Program_Error with "Before cursor not in container"; 1234 end if; 1235 1236 if Checks and then Before.Node.Parent /= Parent.Node then 1237 raise Constraint_Error with "Parent cursor not parent of Before"; 1238 end if; 1239 end if; 1240 1241 if Count = 0 then 1242 Position := No_Element; -- Need ruling from ARG ??? 1243 return; 1244 end if; 1245 1246 First := new Tree_Node_Type'(Parent => Parent.Node, 1247 Element => <>, 1248 others => <>); 1249 1250 Last := First; 1251 for J in Count_Type'(2) .. Count loop 1252 1253 -- Reclaim other nodes if Storage_Error. ??? 1254 1255 Last.Next := new Tree_Node_Type'(Parent => Parent.Node, 1256 Prev => Last, 1257 Element => <>, 1258 others => <>); 1259 1260 Last := Last.Next; 1261 end loop; 1262 1263 Insert_Subtree_List 1264 (First => First, 1265 Last => Last, 1266 Parent => Parent.Node, 1267 Before => Before.Node); 1268 1269 -- In order for operation Node_Count to complete in O(1) time, we cache 1270 -- the count value. Here we increment the total count by the number of 1271 -- nodes we just inserted. 1272 1273 Container.Count := Container.Count + Count; 1274 1275 Position := Cursor'(Parent.Container, First); 1276 end Insert_Child; 1277 1278 ------------------------- 1279 -- Insert_Subtree_List -- 1280 ------------------------- 1281 1282 procedure Insert_Subtree_List 1283 (First : Tree_Node_Access; 1284 Last : Tree_Node_Access; 1285 Parent : Tree_Node_Access; 1286 Before : Tree_Node_Access) 1287 is 1288 pragma Assert (Parent /= null); 1289 C : Children_Type renames Parent.Children; 1290 1291 begin 1292 -- This is a simple utility operation to insert a list of nodes (from 1293 -- First..Last) as children of Parent. The Before node specifies where 1294 -- the new children should be inserted relative to the existing 1295 -- children. 1296 1297 if First = null then 1298 pragma Assert (Last = null); 1299 return; 1300 end if; 1301 1302 pragma Assert (Last /= null); 1303 pragma Assert (Before = null or else Before.Parent = Parent); 1304 1305 if C.First = null then 1306 C.First := First; 1307 C.First.Prev := null; 1308 C.Last := Last; 1309 C.Last.Next := null; 1310 1311 elsif Before = null then -- means "insert after existing nodes" 1312 C.Last.Next := First; 1313 First.Prev := C.Last; 1314 C.Last := Last; 1315 C.Last.Next := null; 1316 1317 elsif Before = C.First then 1318 Last.Next := C.First; 1319 C.First.Prev := Last; 1320 C.First := First; 1321 C.First.Prev := null; 1322 1323 else 1324 Before.Prev.Next := First; 1325 First.Prev := Before.Prev; 1326 Last.Next := Before; 1327 Before.Prev := Last; 1328 end if; 1329 end Insert_Subtree_List; 1330 1331 ------------------------- 1332 -- Insert_Subtree_Node -- 1333 ------------------------- 1334 1335 procedure Insert_Subtree_Node 1336 (Subtree : Tree_Node_Access; 1337 Parent : Tree_Node_Access; 1338 Before : Tree_Node_Access) 1339 is 1340 begin 1341 -- This is a simple wrapper operation to insert a single child into the 1342 -- Parent's children list. 1343 1344 Insert_Subtree_List 1345 (First => Subtree, 1346 Last => Subtree, 1347 Parent => Parent, 1348 Before => Before); 1349 end Insert_Subtree_Node; 1350 1351 -------------- 1352 -- Is_Empty -- 1353 -------------- 1354 1355 function Is_Empty (Container : Tree) return Boolean is 1356 begin 1357 return Container.Root.Children.First = null; 1358 end Is_Empty; 1359 1360 ------------- 1361 -- Is_Leaf -- 1362 ------------- 1363 1364 function Is_Leaf (Position : Cursor) return Boolean is 1365 begin 1366 return (if Position = No_Element then False 1367 else Position.Node.Children.First = null); 1368 end Is_Leaf; 1369 1370 ------------------ 1371 -- Is_Reachable -- 1372 ------------------ 1373 1374 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is 1375 pragma Assert (From /= null); 1376 pragma Assert (To /= null); 1377 1378 N : Tree_Node_Access; 1379 1380 begin 1381 N := From; 1382 while N /= null loop 1383 if N = To then 1384 return True; 1385 end if; 1386 1387 N := N.Parent; 1388 end loop; 1389 1390 return False; 1391 end Is_Reachable; 1392 1393 ------------- 1394 -- Is_Root -- 1395 ------------- 1396 1397 function Is_Root (Position : Cursor) return Boolean is 1398 begin 1399 return (if Position.Container = null then False 1400 else Position = Root (Position.Container.all)); 1401 end Is_Root; 1402 1403 ------------- 1404 -- Iterate -- 1405 ------------- 1406 1407 procedure Iterate 1408 (Container : Tree; 1409 Process : not null access procedure (Position : Cursor)) 1410 is 1411 Busy : With_Busy (Container.TC'Unrestricted_Access); 1412 begin 1413 Iterate_Children 1414 (Container => Container'Unrestricted_Access, 1415 Subtree => Root_Node (Container), 1416 Process => Process); 1417 end Iterate; 1418 1419 function Iterate (Container : Tree) 1420 return Tree_Iterator_Interfaces.Forward_Iterator'Class 1421 is 1422 begin 1423 return Iterate_Subtree (Root (Container)); 1424 end Iterate; 1425 1426 ---------------------- 1427 -- Iterate_Children -- 1428 ---------------------- 1429 1430 procedure Iterate_Children 1431 (Parent : Cursor; 1432 Process : not null access procedure (Position : Cursor)) 1433 is 1434 C : Tree_Node_Access; 1435 Busy : With_Busy (Parent.Container.TC'Unrestricted_Access); 1436 begin 1437 if Checks and then Parent = No_Element then 1438 raise Constraint_Error with "Parent cursor has no element"; 1439 end if; 1440 1441 C := Parent.Node.Children.First; 1442 while C /= null loop 1443 Process (Position => Cursor'(Parent.Container, Node => C)); 1444 C := C.Next; 1445 end loop; 1446 end Iterate_Children; 1447 1448 procedure Iterate_Children 1449 (Container : Tree_Access; 1450 Subtree : Tree_Node_Access; 1451 Process : not null access procedure (Position : Cursor)) 1452 is 1453 Node : Tree_Node_Access; 1454 1455 begin 1456 -- This is a helper function to recursively iterate over all the nodes 1457 -- in a subtree, in depth-first fashion. This particular helper just 1458 -- visits the children of this subtree, not the root of the subtree node 1459 -- itself. This is useful when starting from the ultimate root of the 1460 -- entire tree (see Iterate), as that root does not have an element. 1461 1462 Node := Subtree.Children.First; 1463 while Node /= null loop 1464 Iterate_Subtree (Container, Node, Process); 1465 Node := Node.Next; 1466 end loop; 1467 end Iterate_Children; 1468 1469 function Iterate_Children 1470 (Container : Tree; 1471 Parent : Cursor) 1472 return Tree_Iterator_Interfaces.Reversible_Iterator'Class 1473 is 1474 C : constant Tree_Access := Container'Unrestricted_Access; 1475 begin 1476 if Checks and then Parent = No_Element then 1477 raise Constraint_Error with "Parent cursor has no element"; 1478 end if; 1479 1480 if Checks and then Parent.Container /= C then 1481 raise Program_Error with "Parent cursor not in container"; 1482 end if; 1483 1484 return It : constant Child_Iterator := 1485 (Limited_Controlled with 1486 Container => C, 1487 Subtree => Parent.Node) 1488 do 1489 Busy (C.TC); 1490 end return; 1491 end Iterate_Children; 1492 1493 --------------------- 1494 -- Iterate_Subtree -- 1495 --------------------- 1496 1497 function Iterate_Subtree 1498 (Position : Cursor) 1499 return Tree_Iterator_Interfaces.Forward_Iterator'Class 1500 is 1501 C : constant Tree_Access := Position.Container; 1502 begin 1503 if Checks and then Position = No_Element then 1504 raise Constraint_Error with "Position cursor has no element"; 1505 end if; 1506 1507 -- Implement Vet for multiway trees??? 1508 -- pragma Assert (Vet (Position), "bad subtree cursor"); 1509 1510 return It : constant Subtree_Iterator := 1511 (Limited_Controlled with 1512 Container => C, 1513 Subtree => Position.Node) 1514 do 1515 Busy (C.TC); 1516 end return; 1517 end Iterate_Subtree; 1518 1519 procedure Iterate_Subtree 1520 (Position : Cursor; 1521 Process : not null access procedure (Position : Cursor)) 1522 is 1523 Busy : With_Busy (Position.Container.TC'Unrestricted_Access); 1524 begin 1525 if Checks and then Position = No_Element then 1526 raise Constraint_Error with "Position cursor has no element"; 1527 end if; 1528 1529 if Is_Root (Position) then 1530 Iterate_Children (Position.Container, Position.Node, Process); 1531 else 1532 Iterate_Subtree (Position.Container, Position.Node, Process); 1533 end if; 1534 end Iterate_Subtree; 1535 1536 procedure Iterate_Subtree 1537 (Container : Tree_Access; 1538 Subtree : Tree_Node_Access; 1539 Process : not null access procedure (Position : Cursor)) 1540 is 1541 begin 1542 -- This is a helper function to recursively iterate over all the nodes 1543 -- in a subtree, in depth-first fashion. It first visits the root of the 1544 -- subtree, then visits its children. 1545 1546 Process (Cursor'(Container, Subtree)); 1547 Iterate_Children (Container, Subtree, Process); 1548 end Iterate_Subtree; 1549 1550 ---------- 1551 -- Last -- 1552 ---------- 1553 1554 overriding function Last (Object : Child_Iterator) return Cursor is 1555 begin 1556 return Last_Child (Cursor'(Object.Container, Object.Subtree)); 1557 end Last; 1558 1559 ---------------- 1560 -- Last_Child -- 1561 ---------------- 1562 1563 function Last_Child (Parent : Cursor) return Cursor is 1564 Node : Tree_Node_Access; 1565 1566 begin 1567 if Checks and then Parent = No_Element then 1568 raise Constraint_Error with "Parent cursor has no element"; 1569 end if; 1570 1571 Node := Parent.Node.Children.Last; 1572 1573 if Node = null then 1574 return No_Element; 1575 end if; 1576 1577 return (Parent.Container, Node); 1578 end Last_Child; 1579 1580 ------------------------ 1581 -- Last_Child_Element -- 1582 ------------------------ 1583 1584 function Last_Child_Element (Parent : Cursor) return Element_Type is 1585 begin 1586 return Element (Last_Child (Parent)); 1587 end Last_Child_Element; 1588 1589 ---------- 1590 -- Move -- 1591 ---------- 1592 1593 procedure Move (Target : in out Tree; Source : in out Tree) is 1594 Node : Tree_Node_Access; 1595 1596 begin 1597 if Target'Address = Source'Address then 1598 return; 1599 end if; 1600 1601 TC_Check (Source.TC); 1602 1603 Target.Clear; -- checks busy bit 1604 1605 Target.Root.Children := Source.Root.Children; 1606 Source.Root.Children := Children_Type'(others => null); 1607 1608 Node := Target.Root.Children.First; 1609 while Node /= null loop 1610 Node.Parent := Root_Node (Target); 1611 Node := Node.Next; 1612 end loop; 1613 1614 Target.Count := Source.Count; 1615 Source.Count := 0; 1616 end Move; 1617 1618 ---------- 1619 -- Next -- 1620 ---------- 1621 1622 function Next 1623 (Object : Subtree_Iterator; 1624 Position : Cursor) return Cursor 1625 is 1626 Node : Tree_Node_Access; 1627 1628 begin 1629 if Position.Container = null then 1630 return No_Element; 1631 end if; 1632 1633 if Checks and then Position.Container /= Object.Container then 1634 raise Program_Error with 1635 "Position cursor of Next designates wrong tree"; 1636 end if; 1637 1638 Node := Position.Node; 1639 1640 if Node.Children.First /= null then 1641 return Cursor'(Object.Container, Node.Children.First); 1642 end if; 1643 1644 while Node /= Object.Subtree loop 1645 if Node.Next /= null then 1646 return Cursor'(Object.Container, Node.Next); 1647 end if; 1648 1649 Node := Node.Parent; 1650 end loop; 1651 1652 return No_Element; 1653 end Next; 1654 1655 function Next 1656 (Object : Child_Iterator; 1657 Position : Cursor) return Cursor 1658 is 1659 begin 1660 if Position.Container = null then 1661 return No_Element; 1662 end if; 1663 1664 if Checks and then Position.Container /= Object.Container then 1665 raise Program_Error with 1666 "Position cursor of Next designates wrong tree"; 1667 end if; 1668 1669 return Next_Sibling (Position); 1670 end Next; 1671 1672 ------------------ 1673 -- Next_Sibling -- 1674 ------------------ 1675 1676 function Next_Sibling (Position : Cursor) return Cursor is 1677 begin 1678 if Position = No_Element then 1679 return No_Element; 1680 end if; 1681 1682 if Position.Node.Next = null then 1683 return No_Element; 1684 end if; 1685 1686 return Cursor'(Position.Container, Position.Node.Next); 1687 end Next_Sibling; 1688 1689 procedure Next_Sibling (Position : in out Cursor) is 1690 begin 1691 Position := Next_Sibling (Position); 1692 end Next_Sibling; 1693 1694 ---------------- 1695 -- Node_Count -- 1696 ---------------- 1697 1698 function Node_Count (Container : Tree) return Count_Type is 1699 begin 1700 -- Container.Count is the number of nodes we have actually allocated. We 1701 -- cache the value specifically so this Node_Count operation can execute 1702 -- in O(1) time, which makes it behave similarly to how the Length 1703 -- selector function behaves for other containers. 1704 1705 -- The cached node count value only describes the nodes we have 1706 -- allocated; the root node itself is not included in that count. The 1707 -- Node_Count operation returns a value that includes the root node 1708 -- (because the RM says so), so we must add 1 to our cached value. 1709 1710 return 1 + Container.Count; 1711 end Node_Count; 1712 1713 ------------ 1714 -- Parent -- 1715 ------------ 1716 1717 function Parent (Position : Cursor) return Cursor is 1718 begin 1719 if Position = No_Element then 1720 return No_Element; 1721 end if; 1722 1723 if Position.Node.Parent = null then 1724 return No_Element; 1725 end if; 1726 1727 return Cursor'(Position.Container, Position.Node.Parent); 1728 end Parent; 1729 1730 ------------------- 1731 -- Prepend_Child -- 1732 ------------------- 1733 1734 procedure Prepend_Child 1735 (Container : in out Tree; 1736 Parent : Cursor; 1737 New_Item : Element_Type; 1738 Count : Count_Type := 1) 1739 is 1740 First, Last : Tree_Node_Access; 1741 1742 begin 1743 TC_Check (Container.TC); 1744 1745 if Checks and then Parent = No_Element then 1746 raise Constraint_Error with "Parent cursor has no element"; 1747 end if; 1748 1749 if Checks and then Parent.Container /= Container'Unrestricted_Access then 1750 raise Program_Error with "Parent cursor not in container"; 1751 end if; 1752 1753 if Count = 0 then 1754 return; 1755 end if; 1756 1757 First := new Tree_Node_Type'(Parent => Parent.Node, 1758 Element => New_Item, 1759 others => <>); 1760 1761 Last := First; 1762 1763 for J in Count_Type'(2) .. Count loop 1764 1765 -- Reclaim other nodes if Storage_Error??? 1766 1767 Last.Next := new Tree_Node_Type'(Parent => Parent.Node, 1768 Prev => Last, 1769 Element => New_Item, 1770 others => <>); 1771 1772 Last := Last.Next; 1773 end loop; 1774 1775 Insert_Subtree_List 1776 (First => First, 1777 Last => Last, 1778 Parent => Parent.Node, 1779 Before => Parent.Node.Children.First); 1780 1781 -- In order for operation Node_Count to complete in O(1) time, we cache 1782 -- the count value. Here we increment the total count by the number of 1783 -- nodes we just inserted. 1784 1785 Container.Count := Container.Count + Count; 1786 end Prepend_Child; 1787 1788 -------------- 1789 -- Previous -- 1790 -------------- 1791 1792 overriding function Previous 1793 (Object : Child_Iterator; 1794 Position : Cursor) return Cursor 1795 is 1796 begin 1797 if Position.Container = null then 1798 return No_Element; 1799 end if; 1800 1801 if Checks and then Position.Container /= Object.Container then 1802 raise Program_Error with 1803 "Position cursor of Previous designates wrong tree"; 1804 end if; 1805 1806 return Previous_Sibling (Position); 1807 end Previous; 1808 1809 ---------------------- 1810 -- Previous_Sibling -- 1811 ---------------------- 1812 1813 function Previous_Sibling (Position : Cursor) return Cursor is 1814 begin 1815 return 1816 (if Position = No_Element then No_Element 1817 elsif Position.Node.Prev = null then No_Element 1818 else Cursor'(Position.Container, Position.Node.Prev)); 1819 end Previous_Sibling; 1820 1821 procedure Previous_Sibling (Position : in out Cursor) is 1822 begin 1823 Position := Previous_Sibling (Position); 1824 end Previous_Sibling; 1825 1826 ---------------------- 1827 -- Pseudo_Reference -- 1828 ---------------------- 1829 1830 function Pseudo_Reference 1831 (Container : aliased Tree'Class) return Reference_Control_Type 1832 is 1833 TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access; 1834 begin 1835 return R : constant Reference_Control_Type := (Controlled with TC) do 1836 Busy (TC.all); 1837 end return; 1838 end Pseudo_Reference; 1839 1840 ------------------- 1841 -- Query_Element -- 1842 ------------------- 1843 1844 procedure Query_Element 1845 (Position : Cursor; 1846 Process : not null access procedure (Element : Element_Type)) 1847 is 1848 T : Tree renames Position.Container.all'Unrestricted_Access.all; 1849 Lock : With_Lock (T.TC'Unrestricted_Access); 1850 begin 1851 if Checks and then Position = No_Element then 1852 raise Constraint_Error with "Position cursor has no element"; 1853 end if; 1854 1855 if Checks and then Is_Root (Position) then 1856 raise Program_Error with "Position cursor designates root"; 1857 end if; 1858 1859 Process (Position.Node.Element); 1860 end Query_Element; 1861 1862 --------------- 1863 -- Put_Image -- 1864 --------------- 1865 1866 procedure Put_Image 1867 (S : in out Ada.Strings.Text_Output.Sink'Class; V : Tree) 1868 is 1869 use System.Put_Images; 1870 1871 procedure Rec (Position : Cursor); 1872 -- Recursive routine operating on cursors 1873 1874 procedure Rec (Position : Cursor) is 1875 First_Time : Boolean := True; 1876 begin 1877 Array_Before (S); 1878 1879 for X in Iterate_Children (V, Position) loop 1880 if First_Time then 1881 First_Time := False; 1882 else 1883 Array_Between (S); 1884 end if; 1885 1886 Element_Type'Put_Image (S, Element (X)); 1887 if Child_Count (X) > 0 then 1888 Simple_Array_Between (S); 1889 Rec (X); 1890 end if; 1891 end loop; 1892 1893 Array_After (S); 1894 end Rec; 1895 1896 begin 1897 if First_Child (Root (V)) = No_Element then 1898 Array_Before (S); 1899 Array_After (S); 1900 else 1901 Rec (First_Child (Root (V))); 1902 end if; 1903 end Put_Image; 1904 1905 ---------- 1906 -- Read -- 1907 ---------- 1908 1909 procedure Read 1910 (Stream : not null access Root_Stream_Type'Class; 1911 Container : out Tree) 1912 is 1913 procedure Read_Children (Subtree : Tree_Node_Access); 1914 1915 function Read_Subtree 1916 (Parent : Tree_Node_Access) return Tree_Node_Access; 1917 1918 Total_Count : Count_Type'Base; 1919 -- Value read from the stream that says how many elements follow 1920 1921 Read_Count : Count_Type'Base; 1922 -- Actual number of elements read from the stream 1923 1924 ------------------- 1925 -- Read_Children -- 1926 ------------------- 1927 1928 procedure Read_Children (Subtree : Tree_Node_Access) is 1929 pragma Assert (Subtree /= null); 1930 pragma Assert (Subtree.Children.First = null); 1931 pragma Assert (Subtree.Children.Last = null); 1932 1933 Count : Count_Type'Base; 1934 -- Number of child subtrees 1935 1936 C : Children_Type; 1937 1938 begin 1939 Count_Type'Read (Stream, Count); 1940 1941 if Checks and then Count < 0 then 1942 raise Program_Error with "attempt to read from corrupt stream"; 1943 end if; 1944 1945 if Count = 0 then 1946 return; 1947 end if; 1948 1949 C.First := Read_Subtree (Parent => Subtree); 1950 C.Last := C.First; 1951 1952 for J in Count_Type'(2) .. Count loop 1953 C.Last.Next := Read_Subtree (Parent => Subtree); 1954 C.Last.Next.Prev := C.Last; 1955 C.Last := C.Last.Next; 1956 end loop; 1957 1958 -- Now that the allocation and reads have completed successfully, it 1959 -- is safe to link the children to their parent. 1960 1961 Subtree.Children := C; 1962 end Read_Children; 1963 1964 ------------------ 1965 -- Read_Subtree -- 1966 ------------------ 1967 1968 function Read_Subtree 1969 (Parent : Tree_Node_Access) return Tree_Node_Access 1970 is 1971 Subtree : constant Tree_Node_Access := 1972 new Tree_Node_Type' 1973 (Parent => Parent, 1974 Element => Element_Type'Input (Stream), 1975 others => <>); 1976 1977 begin 1978 Read_Count := Read_Count + 1; 1979 1980 Read_Children (Subtree); 1981 1982 return Subtree; 1983 end Read_Subtree; 1984 1985 -- Start of processing for Read 1986 1987 begin 1988 Container.Clear; -- checks busy bit 1989 1990 Count_Type'Read (Stream, Total_Count); 1991 1992 if Checks and then Total_Count < 0 then 1993 raise Program_Error with "attempt to read from corrupt stream"; 1994 end if; 1995 1996 if Total_Count = 0 then 1997 return; 1998 end if; 1999 2000 Read_Count := 0; 2001 2002 Read_Children (Root_Node (Container)); 2003 2004 if Checks and then Read_Count /= Total_Count then 2005 raise Program_Error with "attempt to read from corrupt stream"; 2006 end if; 2007 2008 Container.Count := Total_Count; 2009 end Read; 2010 2011 procedure Read 2012 (Stream : not null access Root_Stream_Type'Class; 2013 Position : out Cursor) 2014 is 2015 begin 2016 raise Program_Error with "attempt to read tree cursor from stream"; 2017 end Read; 2018 2019 procedure Read 2020 (Stream : not null access Root_Stream_Type'Class; 2021 Item : out Reference_Type) 2022 is 2023 begin 2024 raise Program_Error with "attempt to stream reference"; 2025 end Read; 2026 2027 procedure Read 2028 (Stream : not null access Root_Stream_Type'Class; 2029 Item : out Constant_Reference_Type) 2030 is 2031 begin 2032 raise Program_Error with "attempt to stream reference"; 2033 end Read; 2034 2035 --------------- 2036 -- Reference -- 2037 --------------- 2038 2039 function Reference 2040 (Container : aliased in out Tree; 2041 Position : Cursor) return Reference_Type 2042 is 2043 begin 2044 if Checks and then Position.Container = null then 2045 raise Constraint_Error with 2046 "Position cursor has no element"; 2047 end if; 2048 2049 if Checks and then Position.Container /= Container'Unrestricted_Access 2050 then 2051 raise Program_Error with 2052 "Position cursor designates wrong container"; 2053 end if; 2054 2055 if Checks and then Position.Node = Root_Node (Container) then 2056 raise Program_Error with "Position cursor designates root"; 2057 end if; 2058 2059 -- Implement Vet for multiway tree??? 2060 -- pragma Assert (Vet (Position), 2061 -- "Position cursor in Constant_Reference is bad"); 2062 2063 declare 2064 C : Tree renames Position.Container.all; 2065 TC : constant Tamper_Counts_Access := 2066 C.TC'Unrestricted_Access; 2067 begin 2068 return R : constant Reference_Type := 2069 (Element => Position.Node.Element'Access, 2070 Control => (Controlled with TC)) 2071 do 2072 Busy (TC.all); 2073 end return; 2074 end; 2075 end Reference; 2076 2077 -------------------- 2078 -- Remove_Subtree -- 2079 -------------------- 2080 2081 procedure Remove_Subtree (Subtree : Tree_Node_Access) is 2082 C : Children_Type renames Subtree.Parent.Children; 2083 2084 begin 2085 -- This is a utility operation to remove a subtree node from its 2086 -- parent's list of children. 2087 2088 if C.First = Subtree then 2089 pragma Assert (Subtree.Prev = null); 2090 2091 if C.Last = Subtree then 2092 pragma Assert (Subtree.Next = null); 2093 C.First := null; 2094 C.Last := null; 2095 2096 else 2097 C.First := Subtree.Next; 2098 C.First.Prev := null; 2099 end if; 2100 2101 elsif C.Last = Subtree then 2102 pragma Assert (Subtree.Next = null); 2103 C.Last := Subtree.Prev; 2104 C.Last.Next := null; 2105 2106 else 2107 Subtree.Prev.Next := Subtree.Next; 2108 Subtree.Next.Prev := Subtree.Prev; 2109 end if; 2110 end Remove_Subtree; 2111 2112 ---------------------- 2113 -- Replace_Element -- 2114 ---------------------- 2115 2116 procedure Replace_Element 2117 (Container : in out Tree; 2118 Position : Cursor; 2119 New_Item : Element_Type) 2120 is 2121 begin 2122 TE_Check (Container.TC); 2123 2124 if Checks and then Position = No_Element then 2125 raise Constraint_Error with "Position cursor has no element"; 2126 end if; 2127 2128 if Checks and then Position.Container /= Container'Unrestricted_Access 2129 then 2130 raise Program_Error with "Position cursor not in container"; 2131 end if; 2132 2133 if Checks and then Is_Root (Position) then 2134 raise Program_Error with "Position cursor designates root"; 2135 end if; 2136 2137 Position.Node.Element := New_Item; 2138 end Replace_Element; 2139 2140 ------------------------------ 2141 -- Reverse_Iterate_Children -- 2142 ------------------------------ 2143 2144 procedure Reverse_Iterate_Children 2145 (Parent : Cursor; 2146 Process : not null access procedure (Position : Cursor)) 2147 is 2148 C : Tree_Node_Access; 2149 Busy : With_Busy (Parent.Container.TC'Unrestricted_Access); 2150 begin 2151 if Checks and then Parent = No_Element then 2152 raise Constraint_Error with "Parent cursor has no element"; 2153 end if; 2154 2155 C := Parent.Node.Children.Last; 2156 while C /= null loop 2157 Process (Position => Cursor'(Parent.Container, Node => C)); 2158 C := C.Prev; 2159 end loop; 2160 end Reverse_Iterate_Children; 2161 2162 ---------- 2163 -- Root -- 2164 ---------- 2165 2166 function Root (Container : Tree) return Cursor is 2167 begin 2168 return (Container'Unrestricted_Access, Root_Node (Container)); 2169 end Root; 2170 2171 --------------- 2172 -- Root_Node -- 2173 --------------- 2174 2175 function Root_Node (Container : Tree) return Tree_Node_Access is 2176 type Root_Node_Access is access all Root_Node_Type; 2177 for Root_Node_Access'Storage_Size use 0; 2178 pragma Convention (C, Root_Node_Access); 2179 2180 function To_Tree_Node_Access is 2181 new Ada.Unchecked_Conversion (Root_Node_Access, Tree_Node_Access); 2182 2183 -- Start of processing for Root_Node 2184 2185 begin 2186 -- This is a utility function for converting from an access type that 2187 -- designates the distinguished root node to an access type designating 2188 -- a non-root node. The representation of a root node does not have an 2189 -- element, but is otherwise identical to a non-root node, so the 2190 -- conversion itself is safe. 2191 2192 return To_Tree_Node_Access (Container.Root'Unrestricted_Access); 2193 end Root_Node; 2194 2195 --------------------- 2196 -- Splice_Children -- 2197 --------------------- 2198 2199 procedure Splice_Children 2200 (Target : in out Tree; 2201 Target_Parent : Cursor; 2202 Before : Cursor; 2203 Source : in out Tree; 2204 Source_Parent : Cursor) 2205 is 2206 Count : Count_Type; 2207 2208 begin 2209 TC_Check (Target.TC); 2210 TC_Check (Source.TC); 2211 2212 if Checks and then Target_Parent = No_Element then 2213 raise Constraint_Error with "Target_Parent cursor has no element"; 2214 end if; 2215 2216 if Checks and then Target_Parent.Container /= Target'Unrestricted_Access 2217 then 2218 raise Program_Error 2219 with "Target_Parent cursor not in Target container"; 2220 end if; 2221 2222 if Before /= No_Element then 2223 if Checks and then Before.Container /= Target'Unrestricted_Access then 2224 raise Program_Error 2225 with "Before cursor not in Target container"; 2226 end if; 2227 2228 if Checks and then Before.Node.Parent /= Target_Parent.Node then 2229 raise Constraint_Error 2230 with "Before cursor not child of Target_Parent"; 2231 end if; 2232 end if; 2233 2234 if Checks and then Source_Parent = No_Element then 2235 raise Constraint_Error with "Source_Parent cursor has no element"; 2236 end if; 2237 2238 if Checks and then Source_Parent.Container /= Source'Unrestricted_Access 2239 then 2240 raise Program_Error 2241 with "Source_Parent cursor not in Source container"; 2242 end if; 2243 2244 if Target'Address = Source'Address then 2245 if Target_Parent = Source_Parent then 2246 return; 2247 end if; 2248 2249 if Checks and then Is_Reachable (From => Target_Parent.Node, 2250 To => Source_Parent.Node) 2251 then 2252 raise Constraint_Error 2253 with "Source_Parent is ancestor of Target_Parent"; 2254 end if; 2255 2256 Splice_Children 2257 (Target_Parent => Target_Parent.Node, 2258 Before => Before.Node, 2259 Source_Parent => Source_Parent.Node); 2260 2261 return; 2262 end if; 2263 2264 -- We cache the count of the nodes we have allocated, so that operation 2265 -- Node_Count can execute in O(1) time. But that means we must count the 2266 -- nodes in the subtree we remove from Source and insert into Target, in 2267 -- order to keep the count accurate. 2268 2269 Count := Subtree_Node_Count (Source_Parent.Node); 2270 pragma Assert (Count >= 1); 2271 2272 Count := Count - 1; -- because Source_Parent node does not move 2273 2274 Splice_Children 2275 (Target_Parent => Target_Parent.Node, 2276 Before => Before.Node, 2277 Source_Parent => Source_Parent.Node); 2278 2279 Source.Count := Source.Count - Count; 2280 Target.Count := Target.Count + Count; 2281 end Splice_Children; 2282 2283 procedure Splice_Children 2284 (Container : in out Tree; 2285 Target_Parent : Cursor; 2286 Before : Cursor; 2287 Source_Parent : Cursor) 2288 is 2289 begin 2290 TC_Check (Container.TC); 2291 2292 if Checks and then Target_Parent = No_Element then 2293 raise Constraint_Error with "Target_Parent cursor has no element"; 2294 end if; 2295 2296 if Checks and then 2297 Target_Parent.Container /= Container'Unrestricted_Access 2298 then 2299 raise Program_Error 2300 with "Target_Parent cursor not in container"; 2301 end if; 2302 2303 if Before /= No_Element then 2304 if Checks and then Before.Container /= Container'Unrestricted_Access 2305 then 2306 raise Program_Error 2307 with "Before cursor not in container"; 2308 end if; 2309 2310 if Checks and then Before.Node.Parent /= Target_Parent.Node then 2311 raise Constraint_Error 2312 with "Before cursor not child of Target_Parent"; 2313 end if; 2314 end if; 2315 2316 if Checks and then Source_Parent = No_Element then 2317 raise Constraint_Error with "Source_Parent cursor has no element"; 2318 end if; 2319 2320 if Checks and then 2321 Source_Parent.Container /= Container'Unrestricted_Access 2322 then 2323 raise Program_Error 2324 with "Source_Parent cursor not in container"; 2325 end if; 2326 2327 if Target_Parent = Source_Parent then 2328 return; 2329 end if; 2330 2331 if Checks and then Is_Reachable (From => Target_Parent.Node, 2332 To => Source_Parent.Node) 2333 then 2334 raise Constraint_Error 2335 with "Source_Parent is ancestor of Target_Parent"; 2336 end if; 2337 2338 Splice_Children 2339 (Target_Parent => Target_Parent.Node, 2340 Before => Before.Node, 2341 Source_Parent => Source_Parent.Node); 2342 end Splice_Children; 2343 2344 procedure Splice_Children 2345 (Target_Parent : Tree_Node_Access; 2346 Before : Tree_Node_Access; 2347 Source_Parent : Tree_Node_Access) 2348 is 2349 CC : constant Children_Type := Source_Parent.Children; 2350 C : Tree_Node_Access; 2351 2352 begin 2353 -- This is a utility operation to remove the children from 2354 -- Source parent and insert them into Target parent. 2355 2356 Source_Parent.Children := Children_Type'(others => null); 2357 2358 -- Fix up the Parent pointers of each child to designate 2359 -- its new Target parent. 2360 2361 C := CC.First; 2362 while C /= null loop 2363 C.Parent := Target_Parent; 2364 C := C.Next; 2365 end loop; 2366 2367 Insert_Subtree_List 2368 (First => CC.First, 2369 Last => CC.Last, 2370 Parent => Target_Parent, 2371 Before => Before); 2372 end Splice_Children; 2373 2374 -------------------- 2375 -- Splice_Subtree -- 2376 -------------------- 2377 2378 procedure Splice_Subtree 2379 (Target : in out Tree; 2380 Parent : Cursor; 2381 Before : Cursor; 2382 Source : in out Tree; 2383 Position : in out Cursor) 2384 is 2385 Subtree_Count : Count_Type; 2386 2387 begin 2388 TC_Check (Target.TC); 2389 TC_Check (Source.TC); 2390 2391 if Checks and then Parent = No_Element then 2392 raise Constraint_Error with "Parent cursor has no element"; 2393 end if; 2394 2395 if Checks and then Parent.Container /= Target'Unrestricted_Access then 2396 raise Program_Error with "Parent cursor not in Target container"; 2397 end if; 2398 2399 if Before /= No_Element then 2400 if Checks and then Before.Container /= Target'Unrestricted_Access then 2401 raise Program_Error with "Before cursor not in Target container"; 2402 end if; 2403 2404 if Checks and then Before.Node.Parent /= Parent.Node then 2405 raise Constraint_Error with "Before cursor not child of Parent"; 2406 end if; 2407 end if; 2408 2409 if Checks and then Position = No_Element then 2410 raise Constraint_Error with "Position cursor has no element"; 2411 end if; 2412 2413 if Checks and then Position.Container /= Source'Unrestricted_Access then 2414 raise Program_Error with "Position cursor not in Source container"; 2415 end if; 2416 2417 if Checks and then Is_Root (Position) then 2418 raise Program_Error with "Position cursor designates root"; 2419 end if; 2420 2421 if Target'Address = Source'Address then 2422 if Position.Node.Parent = Parent.Node then 2423 if Position.Node = Before.Node then 2424 return; 2425 end if; 2426 2427 if Position.Node.Next = Before.Node then 2428 return; 2429 end if; 2430 end if; 2431 2432 if Checks and then 2433 Is_Reachable (From => Parent.Node, To => Position.Node) 2434 then 2435 raise Constraint_Error with "Position is ancestor of Parent"; 2436 end if; 2437 2438 Remove_Subtree (Position.Node); 2439 2440 Position.Node.Parent := Parent.Node; 2441 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node); 2442 2443 return; 2444 end if; 2445 2446 -- This is an unfortunate feature of this API: we must count the nodes 2447 -- in the subtree that we remove from the source tree, which is an O(n) 2448 -- operation. It would have been better if the Tree container did not 2449 -- have a Node_Count selector; a user that wants the number of nodes in 2450 -- the tree could simply call Subtree_Node_Count, with the understanding 2451 -- that such an operation is O(n). 2452 2453 -- Of course, we could choose to implement the Node_Count selector as an 2454 -- O(n) operation, which would turn this splice operation into an O(1) 2455 -- operation. ??? 2456 2457 Subtree_Count := Subtree_Node_Count (Position.Node); 2458 pragma Assert (Subtree_Count <= Source.Count); 2459 2460 Remove_Subtree (Position.Node); 2461 Source.Count := Source.Count - Subtree_Count; 2462 2463 Position.Node.Parent := Parent.Node; 2464 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node); 2465 2466 Target.Count := Target.Count + Subtree_Count; 2467 2468 Position.Container := Target'Unrestricted_Access; 2469 end Splice_Subtree; 2470 2471 procedure Splice_Subtree 2472 (Container : in out Tree; 2473 Parent : Cursor; 2474 Before : Cursor; 2475 Position : Cursor) 2476 is 2477 begin 2478 TC_Check (Container.TC); 2479 2480 if Checks and then Parent = No_Element then 2481 raise Constraint_Error with "Parent cursor has no element"; 2482 end if; 2483 2484 if Checks and then Parent.Container /= Container'Unrestricted_Access then 2485 raise Program_Error with "Parent cursor not in container"; 2486 end if; 2487 2488 if Before /= No_Element then 2489 if Checks and then Before.Container /= Container'Unrestricted_Access 2490 then 2491 raise Program_Error with "Before cursor not in container"; 2492 end if; 2493 2494 if Checks and then Before.Node.Parent /= Parent.Node then 2495 raise Constraint_Error with "Before cursor not child of Parent"; 2496 end if; 2497 end if; 2498 2499 if Checks and then Position = No_Element then 2500 raise Constraint_Error with "Position cursor has no element"; 2501 end if; 2502 2503 if Checks and then Position.Container /= Container'Unrestricted_Access 2504 then 2505 raise Program_Error with "Position cursor not in container"; 2506 end if; 2507 2508 if Checks and then Is_Root (Position) then 2509 2510 -- Should this be PE instead? Need ARG confirmation. ??? 2511 2512 raise Constraint_Error with "Position cursor designates root"; 2513 end if; 2514 2515 if Position.Node.Parent = Parent.Node then 2516 if Position.Node = Before.Node then 2517 return; 2518 end if; 2519 2520 if Position.Node.Next = Before.Node then 2521 return; 2522 end if; 2523 end if; 2524 2525 if Checks and then 2526 Is_Reachable (From => Parent.Node, To => Position.Node) 2527 then 2528 raise Constraint_Error with "Position is ancestor of Parent"; 2529 end if; 2530 2531 Remove_Subtree (Position.Node); 2532 2533 Position.Node.Parent := Parent.Node; 2534 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node); 2535 end Splice_Subtree; 2536 2537 ------------------------ 2538 -- Subtree_Node_Count -- 2539 ------------------------ 2540 2541 function Subtree_Node_Count (Position : Cursor) return Count_Type is 2542 begin 2543 if Position = No_Element then 2544 return 0; 2545 end if; 2546 2547 return Subtree_Node_Count (Position.Node); 2548 end Subtree_Node_Count; 2549 2550 function Subtree_Node_Count 2551 (Subtree : Tree_Node_Access) return Count_Type 2552 is 2553 Result : Count_Type; 2554 Node : Tree_Node_Access; 2555 2556 begin 2557 Result := 1; 2558 Node := Subtree.Children.First; 2559 while Node /= null loop 2560 Result := Result + Subtree_Node_Count (Node); 2561 Node := Node.Next; 2562 end loop; 2563 2564 return Result; 2565 end Subtree_Node_Count; 2566 2567 ---------- 2568 -- Swap -- 2569 ---------- 2570 2571 procedure Swap 2572 (Container : in out Tree; 2573 I, J : Cursor) 2574 is 2575 begin 2576 TE_Check (Container.TC); 2577 2578 if Checks and then I = No_Element then 2579 raise Constraint_Error with "I cursor has no element"; 2580 end if; 2581 2582 if Checks and then I.Container /= Container'Unrestricted_Access then 2583 raise Program_Error with "I cursor not in container"; 2584 end if; 2585 2586 if Checks and then Is_Root (I) then 2587 raise Program_Error with "I cursor designates root"; 2588 end if; 2589 2590 if I = J then -- make this test sooner??? 2591 return; 2592 end if; 2593 2594 if Checks and then J = No_Element then 2595 raise Constraint_Error with "J cursor has no element"; 2596 end if; 2597 2598 if Checks and then J.Container /= Container'Unrestricted_Access then 2599 raise Program_Error with "J cursor not in container"; 2600 end if; 2601 2602 if Checks and then Is_Root (J) then 2603 raise Program_Error with "J cursor designates root"; 2604 end if; 2605 2606 declare 2607 EI : constant Element_Type := I.Node.Element; 2608 2609 begin 2610 I.Node.Element := J.Node.Element; 2611 J.Node.Element := EI; 2612 end; 2613 end Swap; 2614 2615 -------------------- 2616 -- Update_Element -- 2617 -------------------- 2618 2619 procedure Update_Element 2620 (Container : in out Tree; 2621 Position : Cursor; 2622 Process : not null access procedure (Element : in out Element_Type)) 2623 is 2624 T : Tree renames Position.Container.all'Unrestricted_Access.all; 2625 Lock : With_Lock (T.TC'Unrestricted_Access); 2626 begin 2627 if Checks and then Position = No_Element then 2628 raise Constraint_Error with "Position cursor has no element"; 2629 end if; 2630 2631 if Checks and then Position.Container /= Container'Unrestricted_Access 2632 then 2633 raise Program_Error with "Position cursor not in container"; 2634 end if; 2635 2636 if Checks and then Is_Root (Position) then 2637 raise Program_Error with "Position cursor designates root"; 2638 end if; 2639 2640 Process (Position.Node.Element); 2641 end Update_Element; 2642 2643 ----------- 2644 -- Write -- 2645 ----------- 2646 2647 procedure Write 2648 (Stream : not null access Root_Stream_Type'Class; 2649 Container : Tree) 2650 is 2651 procedure Write_Children (Subtree : Tree_Node_Access); 2652 procedure Write_Subtree (Subtree : Tree_Node_Access); 2653 2654 -------------------- 2655 -- Write_Children -- 2656 -------------------- 2657 2658 procedure Write_Children (Subtree : Tree_Node_Access) is 2659 CC : Children_Type renames Subtree.Children; 2660 C : Tree_Node_Access; 2661 2662 begin 2663 Count_Type'Write (Stream, Child_Count (CC)); 2664 2665 C := CC.First; 2666 while C /= null loop 2667 Write_Subtree (C); 2668 C := C.Next; 2669 end loop; 2670 end Write_Children; 2671 2672 ------------------- 2673 -- Write_Subtree -- 2674 ------------------- 2675 2676 procedure Write_Subtree (Subtree : Tree_Node_Access) is 2677 begin 2678 Element_Type'Output (Stream, Subtree.Element); 2679 Write_Children (Subtree); 2680 end Write_Subtree; 2681 2682 -- Start of processing for Write 2683 2684 begin 2685 Count_Type'Write (Stream, Container.Count); 2686 2687 if Container.Count = 0 then 2688 return; 2689 end if; 2690 2691 Write_Children (Root_Node (Container)); 2692 end Write; 2693 2694 procedure Write 2695 (Stream : not null access Root_Stream_Type'Class; 2696 Position : Cursor) 2697 is 2698 begin 2699 raise Program_Error with "attempt to write tree cursor to stream"; 2700 end Write; 2701 2702 procedure Write 2703 (Stream : not null access Root_Stream_Type'Class; 2704 Item : Reference_Type) 2705 is 2706 begin 2707 raise Program_Error with "attempt to stream reference"; 2708 end Write; 2709 2710 procedure Write 2711 (Stream : not null access Root_Stream_Type'Class; 2712 Item : Constant_Reference_Type) 2713 is 2714 begin 2715 raise Program_Error with "attempt to stream reference"; 2716 end Write; 2717 2718end Ada.Containers.Multiway_Trees; 2719