1------------------------------------------------------------------------------ 2-- -- 3-- GNAT LIBRARY COMPONENTS -- 4-- -- 5-- ADA.CONTAINERS.BOUNDED_MULTIWAY_TREES -- 6-- -- 7-- B o d y -- 8-- -- 9-- Copyright (C) 2011-2019, 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.Finalization; 31with System; use type System.Address; 32 33package body Ada.Containers.Bounded_Multiway_Trees is 34 35 pragma Warnings (Off, "variable ""Busy*"" is not referenced"); 36 pragma Warnings (Off, "variable ""Lock*"" is not referenced"); 37 -- See comment in Ada.Containers.Helpers 38 39 use Finalization; 40 41 -------------------- 42 -- Root_Iterator -- 43 -------------------- 44 45 type Root_Iterator is abstract new Limited_Controlled and 46 Tree_Iterator_Interfaces.Forward_Iterator with 47 record 48 Container : Tree_Access; 49 Subtree : Count_Type; 50 end record; 51 52 overriding procedure Finalize (Object : in out Root_Iterator); 53 54 ----------------------- 55 -- Subtree_Iterator -- 56 ----------------------- 57 58 type Subtree_Iterator is new Root_Iterator with null record; 59 60 overriding function First (Object : Subtree_Iterator) return Cursor; 61 62 overriding function Next 63 (Object : Subtree_Iterator; 64 Position : Cursor) return Cursor; 65 66 --------------------- 67 -- Child_Iterator -- 68 --------------------- 69 70 type Child_Iterator is new Root_Iterator and 71 Tree_Iterator_Interfaces.Reversible_Iterator with null record; 72 73 overriding function First (Object : Child_Iterator) return Cursor; 74 75 overriding function Next 76 (Object : Child_Iterator; 77 Position : Cursor) return Cursor; 78 79 overriding function Last (Object : Child_Iterator) return Cursor; 80 81 overriding function Previous 82 (Object : Child_Iterator; 83 Position : Cursor) return Cursor; 84 85 ----------------------- 86 -- Local Subprograms -- 87 ----------------------- 88 89 procedure Initialize_Node (Container : in out Tree; Index : Count_Type); 90 procedure Initialize_Root (Container : in out Tree); 91 92 procedure Allocate_Node 93 (Container : in out Tree; 94 Initialize_Element : not null access procedure (Index : Count_Type); 95 New_Node : out Count_Type); 96 97 procedure Allocate_Node 98 (Container : in out Tree; 99 New_Item : Element_Type; 100 New_Node : out Count_Type); 101 102 procedure Allocate_Node 103 (Container : in out Tree; 104 Stream : not null access Root_Stream_Type'Class; 105 New_Node : out Count_Type); 106 107 procedure Deallocate_Node 108 (Container : in out Tree; 109 X : Count_Type); 110 111 procedure Deallocate_Children 112 (Container : in out Tree; 113 Subtree : Count_Type; 114 Count : in out Count_Type); 115 116 procedure Deallocate_Subtree 117 (Container : in out Tree; 118 Subtree : Count_Type; 119 Count : in out Count_Type); 120 121 function Equal_Children 122 (Left_Tree : Tree; 123 Left_Subtree : Count_Type; 124 Right_Tree : Tree; 125 Right_Subtree : Count_Type) return Boolean; 126 127 function Equal_Subtree 128 (Left_Tree : Tree; 129 Left_Subtree : Count_Type; 130 Right_Tree : Tree; 131 Right_Subtree : Count_Type) return Boolean; 132 133 procedure Iterate_Children 134 (Container : Tree; 135 Subtree : Count_Type; 136 Process : not null access procedure (Position : Cursor)); 137 138 procedure Iterate_Subtree 139 (Container : Tree; 140 Subtree : Count_Type; 141 Process : not null access procedure (Position : Cursor)); 142 143 procedure Copy_Children 144 (Source : Tree; 145 Source_Parent : Count_Type; 146 Target : in out Tree; 147 Target_Parent : Count_Type; 148 Count : in out Count_Type); 149 150 procedure Copy_Subtree 151 (Source : Tree; 152 Source_Subtree : Count_Type; 153 Target : in out Tree; 154 Target_Parent : Count_Type; 155 Target_Subtree : out Count_Type; 156 Count : in out Count_Type); 157 158 function Find_In_Children 159 (Container : Tree; 160 Subtree : Count_Type; 161 Item : Element_Type) return Count_Type; 162 163 function Find_In_Subtree 164 (Container : Tree; 165 Subtree : Count_Type; 166 Item : Element_Type) return Count_Type; 167 168 function Child_Count 169 (Container : Tree; 170 Parent : Count_Type) return Count_Type; 171 172 function Subtree_Node_Count 173 (Container : Tree; 174 Subtree : Count_Type) return Count_Type; 175 176 function Is_Reachable 177 (Container : Tree; 178 From, To : Count_Type) return Boolean; 179 180 function Root_Node (Container : Tree) return Count_Type; 181 182 procedure Remove_Subtree 183 (Container : in out Tree; 184 Subtree : Count_Type); 185 186 procedure Insert_Subtree_Node 187 (Container : in out Tree; 188 Subtree : Count_Type'Base; 189 Parent : Count_Type; 190 Before : Count_Type'Base); 191 192 procedure Insert_Subtree_List 193 (Container : in out Tree; 194 First : Count_Type'Base; 195 Last : Count_Type'Base; 196 Parent : Count_Type; 197 Before : Count_Type'Base); 198 199 procedure Splice_Children 200 (Container : in out Tree; 201 Target_Parent : Count_Type; 202 Before : Count_Type'Base; 203 Source_Parent : Count_Type); 204 205 procedure Splice_Children 206 (Target : in out Tree; 207 Target_Parent : Count_Type; 208 Before : Count_Type'Base; 209 Source : in out Tree; 210 Source_Parent : Count_Type); 211 212 procedure Splice_Subtree 213 (Target : in out Tree; 214 Parent : Count_Type; 215 Before : Count_Type'Base; 216 Source : in out Tree; 217 Position : in out Count_Type); -- source on input, target on output 218 219 --------- 220 -- "=" -- 221 --------- 222 223 function "=" (Left, Right : Tree) return Boolean is 224 begin 225 if Left.Count /= Right.Count then 226 return False; 227 end if; 228 229 if Left.Count = 0 then 230 return True; 231 end if; 232 233 return Equal_Children 234 (Left_Tree => Left, 235 Left_Subtree => Root_Node (Left), 236 Right_Tree => Right, 237 Right_Subtree => Root_Node (Right)); 238 end "="; 239 240 ------------------- 241 -- Allocate_Node -- 242 ------------------- 243 244 procedure Allocate_Node 245 (Container : in out Tree; 246 Initialize_Element : not null access procedure (Index : Count_Type); 247 New_Node : out Count_Type) 248 is 249 begin 250 if Container.Free >= 0 then 251 New_Node := Container.Free; 252 pragma Assert (New_Node in Container.Elements'Range); 253 254 -- We always perform the assignment first, before we change container 255 -- state, in order to defend against exceptions duration assignment. 256 257 Initialize_Element (New_Node); 258 259 Container.Free := Container.Nodes (New_Node).Next; 260 261 else 262 -- A negative free store value means that the links of the nodes in 263 -- the free store have not been initialized. In this case, the nodes 264 -- are physically contiguous in the array, starting at the index that 265 -- is the absolute value of the Container.Free, and continuing until 266 -- the end of the array (Nodes'Last). 267 268 New_Node := abs Container.Free; 269 pragma Assert (New_Node in Container.Elements'Range); 270 271 -- As above, we perform this assignment first, before modifying any 272 -- container state. 273 274 Initialize_Element (New_Node); 275 276 Container.Free := Container.Free - 1; 277 278 if abs Container.Free > Container.Capacity then 279 Container.Free := 0; 280 end if; 281 end if; 282 283 Initialize_Node (Container, New_Node); 284 end Allocate_Node; 285 286 procedure Allocate_Node 287 (Container : in out Tree; 288 New_Item : Element_Type; 289 New_Node : out Count_Type) 290 is 291 procedure Initialize_Element (Index : Count_Type); 292 293 procedure Initialize_Element (Index : Count_Type) is 294 begin 295 Container.Elements (Index) := New_Item; 296 end Initialize_Element; 297 298 begin 299 Allocate_Node (Container, Initialize_Element'Access, New_Node); 300 end Allocate_Node; 301 302 procedure Allocate_Node 303 (Container : in out Tree; 304 Stream : not null access Root_Stream_Type'Class; 305 New_Node : out Count_Type) 306 is 307 procedure Initialize_Element (Index : Count_Type); 308 309 procedure Initialize_Element (Index : Count_Type) is 310 begin 311 Element_Type'Read (Stream, Container.Elements (Index)); 312 end Initialize_Element; 313 314 begin 315 Allocate_Node (Container, Initialize_Element'Access, New_Node); 316 end Allocate_Node; 317 318 ------------------- 319 -- Ancestor_Find -- 320 ------------------- 321 322 function Ancestor_Find 323 (Position : Cursor; 324 Item : Element_Type) return Cursor 325 is 326 R, N : Count_Type; 327 328 begin 329 if Checks and then Position = No_Element then 330 raise Constraint_Error with "Position cursor has no element"; 331 end if; 332 333 -- AI-0136 says to raise PE if Position equals the root node. This does 334 -- not seem correct, as this value is just the limiting condition of the 335 -- search. For now we omit this check, pending a ruling from the ARG. 336 -- ??? 337 -- 338 -- if Checks and then Is_Root (Position) then 339 -- raise Program_Error with "Position cursor designates root"; 340 -- end if; 341 342 R := Root_Node (Position.Container.all); 343 N := Position.Node; 344 while N /= R loop 345 if Position.Container.Elements (N) = Item then 346 return Cursor'(Position.Container, N); 347 end if; 348 349 N := Position.Container.Nodes (N).Parent; 350 end loop; 351 352 return No_Element; 353 end Ancestor_Find; 354 355 ------------------ 356 -- Append_Child -- 357 ------------------ 358 359 procedure Append_Child 360 (Container : in out Tree; 361 Parent : Cursor; 362 New_Item : Element_Type; 363 Count : Count_Type := 1) 364 is 365 Nodes : Tree_Node_Array renames Container.Nodes; 366 First, Last : Count_Type; 367 368 begin 369 if Checks and then Parent = No_Element then 370 raise Constraint_Error with "Parent cursor has no element"; 371 end if; 372 373 if Checks and then Parent.Container /= Container'Unrestricted_Access then 374 raise Program_Error with "Parent cursor not in container"; 375 end if; 376 377 if Count = 0 then 378 return; 379 end if; 380 381 if Checks and then Container.Count > Container.Capacity - Count then 382 raise Capacity_Error 383 with "requested count exceeds available storage"; 384 end if; 385 386 TC_Check (Container.TC); 387 388 if Container.Count = 0 then 389 Initialize_Root (Container); 390 end if; 391 392 Allocate_Node (Container, New_Item, First); 393 Nodes (First).Parent := Parent.Node; 394 395 Last := First; 396 for J in Count_Type'(2) .. Count loop 397 Allocate_Node (Container, New_Item, Nodes (Last).Next); 398 Nodes (Nodes (Last).Next).Parent := Parent.Node; 399 Nodes (Nodes (Last).Next).Prev := Last; 400 401 Last := Nodes (Last).Next; 402 end loop; 403 404 Insert_Subtree_List 405 (Container => Container, 406 First => First, 407 Last => Last, 408 Parent => Parent.Node, 409 Before => No_Node); -- means "insert at end of list" 410 411 Container.Count := Container.Count + Count; 412 end Append_Child; 413 414 ------------ 415 -- Assign -- 416 ------------ 417 418 procedure Assign (Target : in out Tree; Source : Tree) is 419 Target_Count : Count_Type; 420 421 begin 422 if Target'Address = Source'Address then 423 return; 424 end if; 425 426 if Checks and then Target.Capacity < Source.Count then 427 raise Capacity_Error -- ??? 428 with "Target capacity is less than Source count"; 429 end if; 430 431 Target.Clear; -- Checks busy bit 432 433 if Source.Count = 0 then 434 return; 435 end if; 436 437 Initialize_Root (Target); 438 439 -- Copy_Children returns the number of nodes that it allocates, but it 440 -- does this by incrementing the count value passed in, so we must 441 -- initialize the count before calling Copy_Children. 442 443 Target_Count := 0; 444 445 Copy_Children 446 (Source => Source, 447 Source_Parent => Root_Node (Source), 448 Target => Target, 449 Target_Parent => Root_Node (Target), 450 Count => Target_Count); 451 452 pragma Assert (Target_Count = Source.Count); 453 Target.Count := Source.Count; 454 end Assign; 455 456 ----------------- 457 -- Child_Count -- 458 ----------------- 459 460 function Child_Count (Parent : Cursor) return Count_Type is 461 begin 462 if Parent = No_Element then 463 return 0; 464 465 elsif Parent.Container.Count = 0 then 466 pragma Assert (Is_Root (Parent)); 467 return 0; 468 469 else 470 return Child_Count (Parent.Container.all, Parent.Node); 471 end if; 472 end Child_Count; 473 474 function Child_Count 475 (Container : Tree; 476 Parent : Count_Type) return Count_Type 477 is 478 NN : Tree_Node_Array renames Container.Nodes; 479 CC : Children_Type renames NN (Parent).Children; 480 481 Result : Count_Type; 482 Node : Count_Type'Base; 483 484 begin 485 Result := 0; 486 Node := CC.First; 487 while Node > 0 loop 488 Result := Result + 1; 489 Node := NN (Node).Next; 490 end loop; 491 492 return Result; 493 end Child_Count; 494 495 ----------------- 496 -- Child_Depth -- 497 ----------------- 498 499 function Child_Depth (Parent, Child : Cursor) return Count_Type is 500 Result : Count_Type; 501 N : Count_Type'Base; 502 503 begin 504 if Checks and then Parent = No_Element then 505 raise Constraint_Error with "Parent cursor has no element"; 506 end if; 507 508 if Checks and then Child = No_Element then 509 raise Constraint_Error with "Child cursor has no element"; 510 end if; 511 512 if Checks and then Parent.Container /= Child.Container then 513 raise Program_Error with "Parent and Child in different containers"; 514 end if; 515 516 if Parent.Container.Count = 0 then 517 pragma Assert (Is_Root (Parent)); 518 pragma Assert (Child = Parent); 519 return 0; 520 end if; 521 522 Result := 0; 523 N := Child.Node; 524 while N /= Parent.Node loop 525 Result := Result + 1; 526 N := Parent.Container.Nodes (N).Parent; 527 528 if Checks and then N < 0 then 529 raise Program_Error with "Parent is not ancestor of Child"; 530 end if; 531 end loop; 532 533 return Result; 534 end Child_Depth; 535 536 ----------- 537 -- Clear -- 538 ----------- 539 540 procedure Clear (Container : in out Tree) is 541 Container_Count : constant Count_Type := Container.Count; 542 Count : Count_Type; 543 544 begin 545 TC_Check (Container.TC); 546 547 if Container_Count = 0 then 548 return; 549 end if; 550 551 Container.Count := 0; 552 553 -- Deallocate_Children returns the number of nodes that it deallocates, 554 -- but it does this by incrementing the count value that is passed in, 555 -- so we must first initialize the count return value before calling it. 556 557 Count := 0; 558 559 Deallocate_Children 560 (Container => Container, 561 Subtree => Root_Node (Container), 562 Count => Count); 563 564 pragma Assert (Count = Container_Count); 565 end Clear; 566 567 ------------------------ 568 -- Constant_Reference -- 569 ------------------------ 570 571 function Constant_Reference 572 (Container : aliased Tree; 573 Position : Cursor) return Constant_Reference_Type 574 is 575 begin 576 if Checks and then Position.Container = null then 577 raise Constraint_Error with 578 "Position cursor has no element"; 579 end if; 580 581 if Checks and then Position.Container /= Container'Unrestricted_Access 582 then 583 raise Program_Error with 584 "Position cursor designates wrong container"; 585 end if; 586 587 if Checks and then Position.Node = Root_Node (Container) then 588 raise Program_Error with "Position cursor designates root"; 589 end if; 590 591 -- Implement Vet for multiway tree??? 592 -- pragma Assert (Vet (Position), 593 -- "Position cursor in Constant_Reference is bad"); 594 595 declare 596 TC : constant Tamper_Counts_Access := 597 Container.TC'Unrestricted_Access; 598 begin 599 return R : constant Constant_Reference_Type := 600 (Element => Container.Elements (Position.Node)'Access, 601 Control => (Controlled with TC)) 602 do 603 Lock (TC.all); 604 end return; 605 end; 606 end Constant_Reference; 607 608 -------------- 609 -- Contains -- 610 -------------- 611 612 function Contains 613 (Container : Tree; 614 Item : Element_Type) return Boolean 615 is 616 begin 617 return Find (Container, Item) /= No_Element; 618 end Contains; 619 620 ---------- 621 -- Copy -- 622 ---------- 623 624 function Copy 625 (Source : Tree; 626 Capacity : Count_Type := 0) return Tree 627 is 628 C : Count_Type; 629 630 begin 631 if Capacity = 0 then 632 C := Source.Count; 633 elsif Capacity >= Source.Count then 634 C := Capacity; 635 elsif Checks then 636 raise Capacity_Error with "Capacity value too small"; 637 end if; 638 639 return Target : Tree (Capacity => C) do 640 Initialize_Root (Target); 641 642 if Source.Count = 0 then 643 return; 644 end if; 645 646 Copy_Children 647 (Source => Source, 648 Source_Parent => Root_Node (Source), 649 Target => Target, 650 Target_Parent => Root_Node (Target), 651 Count => Target.Count); 652 653 pragma Assert (Target.Count = Source.Count); 654 end return; 655 end Copy; 656 657 ------------------- 658 -- Copy_Children -- 659 ------------------- 660 661 procedure Copy_Children 662 (Source : Tree; 663 Source_Parent : Count_Type; 664 Target : in out Tree; 665 Target_Parent : Count_Type; 666 Count : in out Count_Type) 667 is 668 S_Nodes : Tree_Node_Array renames Source.Nodes; 669 S_Node : Tree_Node_Type renames S_Nodes (Source_Parent); 670 671 T_Nodes : Tree_Node_Array renames Target.Nodes; 672 T_Node : Tree_Node_Type renames T_Nodes (Target_Parent); 673 674 pragma Assert (T_Node.Children.First <= 0); 675 pragma Assert (T_Node.Children.Last <= 0); 676 677 T_CC : Children_Type; 678 C : Count_Type'Base; 679 680 begin 681 -- We special-case the first allocation, in order to establish the 682 -- representation invariants for type Children_Type. 683 684 C := S_Node.Children.First; 685 686 if C <= 0 then -- source parent has no children 687 return; 688 end if; 689 690 Copy_Subtree 691 (Source => Source, 692 Source_Subtree => C, 693 Target => Target, 694 Target_Parent => Target_Parent, 695 Target_Subtree => T_CC.First, 696 Count => Count); 697 698 T_CC.Last := T_CC.First; 699 700 -- The representation invariants for the Children_Type list have been 701 -- established, so we can now copy the remaining children of Source. 702 703 C := S_Nodes (C).Next; 704 while C > 0 loop 705 Copy_Subtree 706 (Source => Source, 707 Source_Subtree => C, 708 Target => Target, 709 Target_Parent => Target_Parent, 710 Target_Subtree => T_Nodes (T_CC.Last).Next, 711 Count => Count); 712 713 T_Nodes (T_Nodes (T_CC.Last).Next).Prev := T_CC.Last; 714 T_CC.Last := T_Nodes (T_CC.Last).Next; 715 716 C := S_Nodes (C).Next; 717 end loop; 718 719 -- We add the newly-allocated children to their parent list only after 720 -- the allocation has succeeded, in order to preserve invariants of the 721 -- parent. 722 723 T_Node.Children := T_CC; 724 end Copy_Children; 725 726 ------------------ 727 -- Copy_Subtree -- 728 ------------------ 729 730 procedure Copy_Subtree 731 (Target : in out Tree; 732 Parent : Cursor; 733 Before : Cursor; 734 Source : Cursor) 735 is 736 Target_Subtree : Count_Type; 737 Target_Count : Count_Type; 738 739 begin 740 if Checks and then Parent = No_Element then 741 raise Constraint_Error with "Parent cursor has no element"; 742 end if; 743 744 if Checks and then Parent.Container /= Target'Unrestricted_Access then 745 raise Program_Error with "Parent cursor not in container"; 746 end if; 747 748 if Before /= No_Element then 749 if Checks and then Before.Container /= Target'Unrestricted_Access then 750 raise Program_Error with "Before cursor not in container"; 751 end if; 752 753 if Checks and then 754 Before.Container.Nodes (Before.Node).Parent /= Parent.Node 755 then 756 raise Constraint_Error with "Before cursor not child of Parent"; 757 end if; 758 end if; 759 760 if Source = No_Element then 761 return; 762 end if; 763 764 if Checks and then Is_Root (Source) then 765 raise Constraint_Error with "Source cursor designates root"; 766 end if; 767 768 if Target.Count = 0 then 769 Initialize_Root (Target); 770 end if; 771 772 -- Copy_Subtree returns a count of the number of nodes that it 773 -- allocates, but it works by incrementing the value that is passed 774 -- in. We must therefore initialize the count value before calling 775 -- Copy_Subtree. 776 777 Target_Count := 0; 778 779 Copy_Subtree 780 (Source => Source.Container.all, 781 Source_Subtree => Source.Node, 782 Target => Target, 783 Target_Parent => Parent.Node, 784 Target_Subtree => Target_Subtree, 785 Count => Target_Count); 786 787 Insert_Subtree_Node 788 (Container => Target, 789 Subtree => Target_Subtree, 790 Parent => Parent.Node, 791 Before => Before.Node); 792 793 Target.Count := Target.Count + Target_Count; 794 end Copy_Subtree; 795 796 procedure Copy_Subtree 797 (Source : Tree; 798 Source_Subtree : Count_Type; 799 Target : in out Tree; 800 Target_Parent : Count_Type; 801 Target_Subtree : out Count_Type; 802 Count : in out Count_Type) 803 is 804 T_Nodes : Tree_Node_Array renames Target.Nodes; 805 806 begin 807 -- First we allocate the root of the target subtree. 808 809 Allocate_Node 810 (Container => Target, 811 New_Item => Source.Elements (Source_Subtree), 812 New_Node => Target_Subtree); 813 814 T_Nodes (Target_Subtree).Parent := Target_Parent; 815 Count := Count + 1; 816 817 -- We now have a new subtree (for the Target tree), containing only a 818 -- copy of the corresponding element in the Source subtree. Next we copy 819 -- the children of the Source subtree as children of the new Target 820 -- subtree. 821 822 Copy_Children 823 (Source => Source, 824 Source_Parent => Source_Subtree, 825 Target => Target, 826 Target_Parent => Target_Subtree, 827 Count => Count); 828 end Copy_Subtree; 829 830 ------------------------- 831 -- Deallocate_Children -- 832 ------------------------- 833 834 procedure Deallocate_Children 835 (Container : in out Tree; 836 Subtree : Count_Type; 837 Count : in out Count_Type) 838 is 839 Nodes : Tree_Node_Array renames Container.Nodes; 840 Node : Tree_Node_Type renames Nodes (Subtree); -- parent 841 CC : Children_Type renames Node.Children; 842 C : Count_Type'Base; 843 844 begin 845 while CC.First > 0 loop 846 C := CC.First; 847 CC.First := Nodes (C).Next; 848 849 Deallocate_Subtree (Container, C, Count); 850 end loop; 851 852 CC.Last := 0; 853 end Deallocate_Children; 854 855 --------------------- 856 -- Deallocate_Node -- 857 --------------------- 858 859 procedure Deallocate_Node 860 (Container : in out Tree; 861 X : Count_Type) 862 is 863 NN : Tree_Node_Array renames Container.Nodes; 864 pragma Assert (X > 0); 865 pragma Assert (X <= NN'Last); 866 867 N : Tree_Node_Type renames NN (X); 868 pragma Assert (N.Parent /= X); -- node is active 869 870 begin 871 -- The tree container actually contains two lists: one for the "active" 872 -- nodes that contain elements that have been inserted onto the tree, 873 -- and another for the "inactive" nodes of the free store, from which 874 -- nodes are allocated when a new child is inserted in the tree. 875 876 -- We desire that merely declaring a tree object should have only 877 -- minimal cost; specially, we want to avoid having to initialize the 878 -- free store (to fill in the links), especially if the capacity of the 879 -- tree object is large. 880 881 -- The head of the free list is indicated by Container.Free. If its 882 -- value is non-negative, then the free store has been initialized in 883 -- the "normal" way: Container.Free points to the head of the list of 884 -- free (inactive) nodes, and the value 0 means the free list is 885 -- empty. Each node on the free list has been initialized to point to 886 -- the next free node (via its Next component), and the value 0 means 887 -- that this is the last node of the free list. 888 889 -- If Container.Free is negative, then the links on the free store have 890 -- not been initialized. In this case the link values are implied: the 891 -- free store comprises the components of the node array started with 892 -- the absolute value of Container.Free, and continuing until the end of 893 -- the array (Nodes'Last). 894 895 -- We prefer to lazy-init the free store (in fact, we would prefer to 896 -- not initialize it at all, because such initialization is an O(n) 897 -- operation). The time when we need to actually initialize the nodes in 898 -- the free store is when the node that becomes inactive is not at the 899 -- end of the active list. The free store would then be discontigous and 900 -- so its nodes would need to be linked in the traditional way. 901 902 -- It might be possible to perform an optimization here. Suppose that 903 -- the free store can be represented as having two parts: one comprising 904 -- the non-contiguous inactive nodes linked together in the normal way, 905 -- and the other comprising the contiguous inactive nodes (that are not 906 -- linked together, at the end of the nodes array). This would allow us 907 -- to never have to initialize the free store, except in a lazy way as 908 -- nodes become inactive. ??? 909 910 -- When an element is deleted from the list container, its node becomes 911 -- inactive, and so we set its Parent and Prev components to an 912 -- impossible value (the index of the node itself), to indicate that it 913 -- is now inactive. This provides a useful way to detect a dangling 914 -- cursor reference. 915 916 N.Parent := X; -- Node is deallocated (not on active list) 917 N.Prev := X; 918 919 if Container.Free >= 0 then 920 -- The free store has previously been initialized. All we need to do 921 -- here is link the newly-free'd node onto the free list. 922 923 N.Next := Container.Free; 924 Container.Free := X; 925 926 elsif X + 1 = abs Container.Free then 927 -- The free store has not been initialized, and the node becoming 928 -- inactive immediately precedes the start of the free store. All 929 -- we need to do is move the start of the free store back by one. 930 931 N.Next := X; -- Not strictly necessary, but marginally safer 932 Container.Free := Container.Free + 1; 933 934 else 935 -- The free store has not been initialized, and the node becoming 936 -- inactive does not immediately precede the free store. Here we 937 -- first initialize the free store (meaning the links are given 938 -- values in the traditional way), and then link the newly-free'd 939 -- node onto the head of the free store. 940 941 -- See the comments above for an optimization opportunity. If the 942 -- next link for a node on the free store is negative, then this 943 -- means the remaining nodes on the free store are physically 944 -- contiguous, starting at the absolute value of that index value. 945 -- ??? 946 947 Container.Free := abs Container.Free; 948 949 if Container.Free > Container.Capacity then 950 Container.Free := 0; 951 952 else 953 for J in Container.Free .. Container.Capacity - 1 loop 954 NN (J).Next := J + 1; 955 end loop; 956 957 NN (Container.Capacity).Next := 0; 958 end if; 959 960 NN (X).Next := Container.Free; 961 Container.Free := X; 962 end if; 963 end Deallocate_Node; 964 965 ------------------------ 966 -- Deallocate_Subtree -- 967 ------------------------ 968 969 procedure Deallocate_Subtree 970 (Container : in out Tree; 971 Subtree : Count_Type; 972 Count : in out Count_Type) 973 is 974 begin 975 Deallocate_Children (Container, Subtree, Count); 976 Deallocate_Node (Container, Subtree); 977 Count := Count + 1; 978 end Deallocate_Subtree; 979 980 --------------------- 981 -- Delete_Children -- 982 --------------------- 983 984 procedure Delete_Children 985 (Container : in out Tree; 986 Parent : Cursor) 987 is 988 Count : Count_Type; 989 990 begin 991 if Checks and then Parent = No_Element then 992 raise Constraint_Error with "Parent cursor has no element"; 993 end if; 994 995 if Checks and then Parent.Container /= Container'Unrestricted_Access then 996 raise Program_Error with "Parent cursor not in container"; 997 end if; 998 999 TC_Check (Container.TC); 1000 1001 if Container.Count = 0 then 1002 pragma Assert (Is_Root (Parent)); 1003 return; 1004 end if; 1005 1006 -- Deallocate_Children returns a count of the number of nodes that it 1007 -- deallocates, but it works by incrementing the value that is passed 1008 -- in. We must therefore initialize the count value before calling 1009 -- Deallocate_Children. 1010 1011 Count := 0; 1012 1013 Deallocate_Children (Container, Parent.Node, Count); 1014 pragma Assert (Count <= Container.Count); 1015 1016 Container.Count := Container.Count - Count; 1017 end Delete_Children; 1018 1019 ----------------- 1020 -- Delete_Leaf -- 1021 ----------------- 1022 1023 procedure Delete_Leaf 1024 (Container : in out Tree; 1025 Position : in out Cursor) 1026 is 1027 X : Count_Type; 1028 1029 begin 1030 if Checks and then Position = No_Element then 1031 raise Constraint_Error with "Position cursor has no element"; 1032 end if; 1033 1034 if Checks and then Position.Container /= Container'Unrestricted_Access 1035 then 1036 raise Program_Error with "Position cursor not in container"; 1037 end if; 1038 1039 if Checks and then Is_Root (Position) then 1040 raise Program_Error with "Position cursor designates root"; 1041 end if; 1042 1043 if Checks and then not Is_Leaf (Position) then 1044 raise Constraint_Error with "Position cursor does not designate leaf"; 1045 end if; 1046 1047 TC_Check (Container.TC); 1048 1049 X := Position.Node; 1050 Position := No_Element; 1051 1052 Remove_Subtree (Container, X); 1053 Container.Count := Container.Count - 1; 1054 1055 Deallocate_Node (Container, X); 1056 end Delete_Leaf; 1057 1058 -------------------- 1059 -- Delete_Subtree -- 1060 -------------------- 1061 1062 procedure Delete_Subtree 1063 (Container : in out Tree; 1064 Position : in out Cursor) 1065 is 1066 X : Count_Type; 1067 Count : Count_Type; 1068 1069 begin 1070 if Checks and then Position = No_Element then 1071 raise Constraint_Error with "Position cursor has no element"; 1072 end if; 1073 1074 if Checks and then Position.Container /= Container'Unrestricted_Access 1075 then 1076 raise Program_Error with "Position cursor not in container"; 1077 end if; 1078 1079 if Checks and then Is_Root (Position) then 1080 raise Program_Error with "Position cursor designates root"; 1081 end if; 1082 1083 TC_Check (Container.TC); 1084 1085 X := Position.Node; 1086 Position := No_Element; 1087 1088 Remove_Subtree (Container, X); 1089 1090 -- Deallocate_Subtree returns a count of the number of nodes that it 1091 -- deallocates, but it works by incrementing the value that is passed 1092 -- in. We must therefore initialize the count value before calling 1093 -- Deallocate_Subtree. 1094 1095 Count := 0; 1096 1097 Deallocate_Subtree (Container, X, Count); 1098 pragma Assert (Count <= Container.Count); 1099 1100 Container.Count := Container.Count - Count; 1101 end Delete_Subtree; 1102 1103 ----------- 1104 -- Depth -- 1105 ----------- 1106 1107 function Depth (Position : Cursor) return Count_Type is 1108 Result : Count_Type; 1109 N : Count_Type'Base; 1110 1111 begin 1112 if Position = No_Element then 1113 return 0; 1114 end if; 1115 1116 if Is_Root (Position) then 1117 return 1; 1118 end if; 1119 1120 Result := 0; 1121 N := Position.Node; 1122 while N >= 0 loop 1123 N := Position.Container.Nodes (N).Parent; 1124 Result := Result + 1; 1125 end loop; 1126 1127 return Result; 1128 end Depth; 1129 1130 ------------- 1131 -- Element -- 1132 ------------- 1133 1134 function Element (Position : Cursor) return Element_Type is 1135 begin 1136 if Checks and then Position.Container = null then 1137 raise Constraint_Error with "Position cursor has no element"; 1138 end if; 1139 1140 if Checks and then Position.Node = Root_Node (Position.Container.all) 1141 then 1142 raise Program_Error with "Position cursor designates root"; 1143 end if; 1144 1145 return Position.Container.Elements (Position.Node); 1146 end Element; 1147 1148 -------------------- 1149 -- Equal_Children -- 1150 -------------------- 1151 1152 function Equal_Children 1153 (Left_Tree : Tree; 1154 Left_Subtree : Count_Type; 1155 Right_Tree : Tree; 1156 Right_Subtree : Count_Type) return Boolean 1157 is 1158 L_NN : Tree_Node_Array renames Left_Tree.Nodes; 1159 R_NN : Tree_Node_Array renames Right_Tree.Nodes; 1160 1161 Left_Children : Children_Type renames L_NN (Left_Subtree).Children; 1162 Right_Children : Children_Type renames R_NN (Right_Subtree).Children; 1163 1164 L, R : Count_Type'Base; 1165 1166 begin 1167 if Child_Count (Left_Tree, Left_Subtree) 1168 /= Child_Count (Right_Tree, Right_Subtree) 1169 then 1170 return False; 1171 end if; 1172 1173 L := Left_Children.First; 1174 R := Right_Children.First; 1175 while L > 0 loop 1176 if not Equal_Subtree (Left_Tree, L, Right_Tree, R) then 1177 return False; 1178 end if; 1179 1180 L := L_NN (L).Next; 1181 R := R_NN (R).Next; 1182 end loop; 1183 1184 return True; 1185 end Equal_Children; 1186 1187 ------------------- 1188 -- Equal_Subtree -- 1189 ------------------- 1190 1191 function Equal_Subtree 1192 (Left_Position : Cursor; 1193 Right_Position : Cursor) return Boolean 1194 is 1195 begin 1196 if Checks and then Left_Position = No_Element then 1197 raise Constraint_Error with "Left cursor has no element"; 1198 end if; 1199 1200 if Checks and then Right_Position = No_Element then 1201 raise Constraint_Error with "Right cursor has no element"; 1202 end if; 1203 1204 if Left_Position = Right_Position then 1205 return True; 1206 end if; 1207 1208 if Is_Root (Left_Position) then 1209 if not Is_Root (Right_Position) then 1210 return False; 1211 end if; 1212 1213 if Left_Position.Container.Count = 0 then 1214 return Right_Position.Container.Count = 0; 1215 end if; 1216 1217 if Right_Position.Container.Count = 0 then 1218 return False; 1219 end if; 1220 1221 return Equal_Children 1222 (Left_Tree => Left_Position.Container.all, 1223 Left_Subtree => Left_Position.Node, 1224 Right_Tree => Right_Position.Container.all, 1225 Right_Subtree => Right_Position.Node); 1226 end if; 1227 1228 if Is_Root (Right_Position) then 1229 return False; 1230 end if; 1231 1232 return Equal_Subtree 1233 (Left_Tree => Left_Position.Container.all, 1234 Left_Subtree => Left_Position.Node, 1235 Right_Tree => Right_Position.Container.all, 1236 Right_Subtree => Right_Position.Node); 1237 end Equal_Subtree; 1238 1239 function Equal_Subtree 1240 (Left_Tree : Tree; 1241 Left_Subtree : Count_Type; 1242 Right_Tree : Tree; 1243 Right_Subtree : Count_Type) return Boolean 1244 is 1245 begin 1246 if Left_Tree.Elements (Left_Subtree) /= 1247 Right_Tree.Elements (Right_Subtree) 1248 then 1249 return False; 1250 end if; 1251 1252 return Equal_Children 1253 (Left_Tree => Left_Tree, 1254 Left_Subtree => Left_Subtree, 1255 Right_Tree => Right_Tree, 1256 Right_Subtree => Right_Subtree); 1257 end Equal_Subtree; 1258 1259 -------------- 1260 -- Finalize -- 1261 -------------- 1262 1263 procedure Finalize (Object : in out Root_Iterator) is 1264 begin 1265 Unbusy (Object.Container.TC); 1266 end Finalize; 1267 1268 ---------- 1269 -- Find -- 1270 ---------- 1271 1272 function Find 1273 (Container : Tree; 1274 Item : Element_Type) return Cursor 1275 is 1276 Node : Count_Type; 1277 1278 begin 1279 if Container.Count = 0 then 1280 return No_Element; 1281 end if; 1282 1283 Node := Find_In_Children (Container, Root_Node (Container), Item); 1284 1285 if Node = 0 then 1286 return No_Element; 1287 end if; 1288 1289 return Cursor'(Container'Unrestricted_Access, Node); 1290 end Find; 1291 1292 ----------- 1293 -- First -- 1294 ----------- 1295 1296 overriding function First (Object : Subtree_Iterator) return Cursor is 1297 begin 1298 if Object.Subtree = Root_Node (Object.Container.all) then 1299 return First_Child (Root (Object.Container.all)); 1300 else 1301 return Cursor'(Object.Container, Object.Subtree); 1302 end if; 1303 end First; 1304 1305 overriding function First (Object : Child_Iterator) return Cursor is 1306 begin 1307 return First_Child (Cursor'(Object.Container, Object.Subtree)); 1308 end First; 1309 1310 ----------------- 1311 -- First_Child -- 1312 ----------------- 1313 1314 function First_Child (Parent : Cursor) return Cursor is 1315 Node : Count_Type'Base; 1316 1317 begin 1318 if Checks and then Parent = No_Element then 1319 raise Constraint_Error with "Parent cursor has no element"; 1320 end if; 1321 1322 if Parent.Container.Count = 0 then 1323 pragma Assert (Is_Root (Parent)); 1324 return No_Element; 1325 end if; 1326 1327 Node := Parent.Container.Nodes (Parent.Node).Children.First; 1328 1329 if Node <= 0 then 1330 return No_Element; 1331 end if; 1332 1333 return Cursor'(Parent.Container, Node); 1334 end First_Child; 1335 1336 ------------------------- 1337 -- First_Child_Element -- 1338 ------------------------- 1339 1340 function First_Child_Element (Parent : Cursor) return Element_Type is 1341 begin 1342 return Element (First_Child (Parent)); 1343 end First_Child_Element; 1344 1345 ---------------------- 1346 -- Find_In_Children -- 1347 ---------------------- 1348 1349 function Find_In_Children 1350 (Container : Tree; 1351 Subtree : Count_Type; 1352 Item : Element_Type) return Count_Type 1353 is 1354 N : Count_Type'Base; 1355 Result : Count_Type; 1356 1357 begin 1358 N := Container.Nodes (Subtree).Children.First; 1359 while N > 0 loop 1360 Result := Find_In_Subtree (Container, N, Item); 1361 1362 if Result > 0 then 1363 return Result; 1364 end if; 1365 1366 N := Container.Nodes (N).Next; 1367 end loop; 1368 1369 return 0; 1370 end Find_In_Children; 1371 1372 --------------------- 1373 -- Find_In_Subtree -- 1374 --------------------- 1375 1376 function Find_In_Subtree 1377 (Position : Cursor; 1378 Item : Element_Type) return Cursor 1379 is 1380 Result : Count_Type; 1381 1382 begin 1383 if Checks and then Position = No_Element then 1384 raise Constraint_Error with "Position cursor has no element"; 1385 end if; 1386 1387 -- Commented-out pending ruling by ARG. ??? 1388 1389 -- if Checks and then 1390 -- Position.Container /= Container'Unrestricted_Access 1391 -- then 1392 -- raise Program_Error with "Position cursor not in container"; 1393 -- end if; 1394 1395 if Position.Container.Count = 0 then 1396 pragma Assert (Is_Root (Position)); 1397 return No_Element; 1398 end if; 1399 1400 if Is_Root (Position) then 1401 Result := Find_In_Children 1402 (Container => Position.Container.all, 1403 Subtree => Position.Node, 1404 Item => Item); 1405 1406 else 1407 Result := Find_In_Subtree 1408 (Container => Position.Container.all, 1409 Subtree => Position.Node, 1410 Item => Item); 1411 end if; 1412 1413 if Result = 0 then 1414 return No_Element; 1415 end if; 1416 1417 return Cursor'(Position.Container, Result); 1418 end Find_In_Subtree; 1419 1420 function Find_In_Subtree 1421 (Container : Tree; 1422 Subtree : Count_Type; 1423 Item : Element_Type) return Count_Type 1424 is 1425 begin 1426 if Container.Elements (Subtree) = Item then 1427 return Subtree; 1428 end if; 1429 1430 return Find_In_Children (Container, Subtree, Item); 1431 end Find_In_Subtree; 1432 1433 ------------------------ 1434 -- Get_Element_Access -- 1435 ------------------------ 1436 1437 function Get_Element_Access 1438 (Position : Cursor) return not null Element_Access is 1439 begin 1440 return Position.Container.Elements (Position.Node)'Access; 1441 end Get_Element_Access; 1442 1443 ----------------- 1444 -- Has_Element -- 1445 ----------------- 1446 1447 function Has_Element (Position : Cursor) return Boolean is 1448 begin 1449 if Position = No_Element then 1450 return False; 1451 end if; 1452 1453 return Position.Node /= Root_Node (Position.Container.all); 1454 end Has_Element; 1455 1456 --------------------- 1457 -- Initialize_Node -- 1458 --------------------- 1459 1460 procedure Initialize_Node 1461 (Container : in out Tree; 1462 Index : Count_Type) 1463 is 1464 begin 1465 Container.Nodes (Index) := 1466 (Parent => No_Node, 1467 Prev => 0, 1468 Next => 0, 1469 Children => (others => 0)); 1470 end Initialize_Node; 1471 1472 --------------------- 1473 -- Initialize_Root -- 1474 --------------------- 1475 1476 procedure Initialize_Root (Container : in out Tree) is 1477 begin 1478 Initialize_Node (Container, Root_Node (Container)); 1479 end Initialize_Root; 1480 1481 ------------------ 1482 -- Insert_Child -- 1483 ------------------ 1484 1485 procedure Insert_Child 1486 (Container : in out Tree; 1487 Parent : Cursor; 1488 Before : Cursor; 1489 New_Item : Element_Type; 1490 Count : Count_Type := 1) 1491 is 1492 Position : Cursor; 1493 pragma Unreferenced (Position); 1494 1495 begin 1496 Insert_Child (Container, Parent, Before, New_Item, Position, Count); 1497 end Insert_Child; 1498 1499 procedure Insert_Child 1500 (Container : in out Tree; 1501 Parent : Cursor; 1502 Before : Cursor; 1503 New_Item : Element_Type; 1504 Position : out Cursor; 1505 Count : Count_Type := 1) 1506 is 1507 Nodes : Tree_Node_Array renames Container.Nodes; 1508 First : Count_Type; 1509 Last : Count_Type; 1510 1511 begin 1512 if Checks and then Parent = No_Element then 1513 raise Constraint_Error with "Parent cursor has no element"; 1514 end if; 1515 1516 if Checks and then Parent.Container /= Container'Unrestricted_Access then 1517 raise Program_Error with "Parent cursor not in container"; 1518 end if; 1519 1520 if Before /= No_Element then 1521 if Checks and then Before.Container /= Container'Unrestricted_Access 1522 then 1523 raise Program_Error with "Before cursor not in container"; 1524 end if; 1525 1526 if Checks and then 1527 Before.Container.Nodes (Before.Node).Parent /= Parent.Node 1528 then 1529 raise Constraint_Error with "Parent cursor not parent of Before"; 1530 end if; 1531 end if; 1532 1533 if Count = 0 then 1534 Position := No_Element; -- Need ruling from ARG ??? 1535 return; 1536 end if; 1537 1538 if Checks and then Container.Count > Container.Capacity - Count then 1539 raise Capacity_Error 1540 with "requested count exceeds available storage"; 1541 end if; 1542 1543 TC_Check (Container.TC); 1544 1545 if Container.Count = 0 then 1546 Initialize_Root (Container); 1547 end if; 1548 1549 Allocate_Node (Container, New_Item, First); 1550 Nodes (First).Parent := Parent.Node; 1551 1552 Last := First; 1553 for J in Count_Type'(2) .. Count loop 1554 Allocate_Node (Container, New_Item, Nodes (Last).Next); 1555 Nodes (Nodes (Last).Next).Parent := Parent.Node; 1556 Nodes (Nodes (Last).Next).Prev := Last; 1557 1558 Last := Nodes (Last).Next; 1559 end loop; 1560 1561 Insert_Subtree_List 1562 (Container => Container, 1563 First => First, 1564 Last => Last, 1565 Parent => Parent.Node, 1566 Before => Before.Node); 1567 1568 Container.Count := Container.Count + Count; 1569 1570 Position := Cursor'(Parent.Container, First); 1571 end Insert_Child; 1572 1573 procedure Insert_Child 1574 (Container : in out Tree; 1575 Parent : Cursor; 1576 Before : Cursor; 1577 Position : out Cursor; 1578 Count : Count_Type := 1) 1579 is 1580 Nodes : Tree_Node_Array renames Container.Nodes; 1581 First : Count_Type; 1582 Last : Count_Type; 1583 1584 pragma Warnings (Off); 1585 Default_Initialized_Item : Element_Type; 1586 pragma Unmodified (Default_Initialized_Item); 1587 -- OK to reference, see below 1588 1589 begin 1590 if Checks and then Parent = No_Element then 1591 raise Constraint_Error with "Parent cursor has no element"; 1592 end if; 1593 1594 if Checks and then Parent.Container /= Container'Unrestricted_Access then 1595 raise Program_Error with "Parent cursor not in container"; 1596 end if; 1597 1598 if Before /= No_Element then 1599 if Checks and then Before.Container /= Container'Unrestricted_Access 1600 then 1601 raise Program_Error with "Before cursor not in container"; 1602 end if; 1603 1604 if Checks and then 1605 Before.Container.Nodes (Before.Node).Parent /= Parent.Node 1606 then 1607 raise Constraint_Error with "Parent cursor not parent of Before"; 1608 end if; 1609 end if; 1610 1611 if Count = 0 then 1612 Position := No_Element; -- Need ruling from ARG ??? 1613 return; 1614 end if; 1615 1616 if Checks and then Container.Count > Container.Capacity - Count then 1617 raise Capacity_Error 1618 with "requested count exceeds available storage"; 1619 end if; 1620 1621 TC_Check (Container.TC); 1622 1623 if Container.Count = 0 then 1624 Initialize_Root (Container); 1625 end if; 1626 1627 -- There is no explicit element provided, but in an instance the element 1628 -- type may be a scalar with a Default_Value aspect, or a composite 1629 -- type with such a scalar component, or components with default 1630 -- initialization, so insert the specified number of possibly 1631 -- initialized elements at the given position. 1632 1633 Allocate_Node (Container, Default_Initialized_Item, First); 1634 Nodes (First).Parent := Parent.Node; 1635 1636 Last := First; 1637 for J in Count_Type'(2) .. Count loop 1638 Allocate_Node 1639 (Container, Default_Initialized_Item, Nodes (Last).Next); 1640 Nodes (Nodes (Last).Next).Parent := Parent.Node; 1641 Nodes (Nodes (Last).Next).Prev := Last; 1642 1643 Last := Nodes (Last).Next; 1644 end loop; 1645 1646 Insert_Subtree_List 1647 (Container => Container, 1648 First => First, 1649 Last => Last, 1650 Parent => Parent.Node, 1651 Before => Before.Node); 1652 1653 Container.Count := Container.Count + Count; 1654 1655 Position := Cursor'(Parent.Container, First); 1656 pragma Warnings (On); 1657 end Insert_Child; 1658 1659 ------------------------- 1660 -- Insert_Subtree_List -- 1661 ------------------------- 1662 1663 procedure Insert_Subtree_List 1664 (Container : in out Tree; 1665 First : Count_Type'Base; 1666 Last : Count_Type'Base; 1667 Parent : Count_Type; 1668 Before : Count_Type'Base) 1669 is 1670 NN : Tree_Node_Array renames Container.Nodes; 1671 N : Tree_Node_Type renames NN (Parent); 1672 CC : Children_Type renames N.Children; 1673 1674 begin 1675 -- This is a simple utility operation to insert a list of nodes 1676 -- (First..Last) as children of Parent. The Before node specifies where 1677 -- the new children should be inserted relative to existing children. 1678 1679 if First <= 0 then 1680 pragma Assert (Last <= 0); 1681 return; 1682 end if; 1683 1684 pragma Assert (Last > 0); 1685 pragma Assert (Before <= 0 or else NN (Before).Parent = Parent); 1686 1687 if CC.First <= 0 then -- no existing children 1688 CC.First := First; 1689 NN (CC.First).Prev := 0; 1690 CC.Last := Last; 1691 NN (CC.Last).Next := 0; 1692 1693 elsif Before <= 0 then -- means "insert after existing nodes" 1694 NN (CC.Last).Next := First; 1695 NN (First).Prev := CC.Last; 1696 CC.Last := Last; 1697 NN (CC.Last).Next := 0; 1698 1699 elsif Before = CC.First then 1700 NN (Last).Next := CC.First; 1701 NN (CC.First).Prev := Last; 1702 CC.First := First; 1703 NN (CC.First).Prev := 0; 1704 1705 else 1706 NN (NN (Before).Prev).Next := First; 1707 NN (First).Prev := NN (Before).Prev; 1708 NN (Last).Next := Before; 1709 NN (Before).Prev := Last; 1710 end if; 1711 end Insert_Subtree_List; 1712 1713 ------------------------- 1714 -- Insert_Subtree_Node -- 1715 ------------------------- 1716 1717 procedure Insert_Subtree_Node 1718 (Container : in out Tree; 1719 Subtree : Count_Type'Base; 1720 Parent : Count_Type; 1721 Before : Count_Type'Base) 1722 is 1723 begin 1724 -- This is a simple wrapper operation to insert a single child into the 1725 -- Parent's children list. 1726 1727 Insert_Subtree_List 1728 (Container => Container, 1729 First => Subtree, 1730 Last => Subtree, 1731 Parent => Parent, 1732 Before => Before); 1733 end Insert_Subtree_Node; 1734 1735 -------------- 1736 -- Is_Empty -- 1737 -------------- 1738 1739 function Is_Empty (Container : Tree) return Boolean is 1740 begin 1741 return Container.Count = 0; 1742 end Is_Empty; 1743 1744 ------------- 1745 -- Is_Leaf -- 1746 ------------- 1747 1748 function Is_Leaf (Position : Cursor) return Boolean is 1749 begin 1750 if Position = No_Element then 1751 return False; 1752 end if; 1753 1754 if Position.Container.Count = 0 then 1755 pragma Assert (Is_Root (Position)); 1756 return True; 1757 end if; 1758 1759 return Position.Container.Nodes (Position.Node).Children.First <= 0; 1760 end Is_Leaf; 1761 1762 ------------------ 1763 -- Is_Reachable -- 1764 ------------------ 1765 1766 function Is_Reachable 1767 (Container : Tree; 1768 From, To : Count_Type) return Boolean 1769 is 1770 Idx : Count_Type; 1771 1772 begin 1773 Idx := From; 1774 while Idx >= 0 loop 1775 if Idx = To then 1776 return True; 1777 end if; 1778 1779 Idx := Container.Nodes (Idx).Parent; 1780 end loop; 1781 1782 return False; 1783 end Is_Reachable; 1784 1785 ------------- 1786 -- Is_Root -- 1787 ------------- 1788 1789 function Is_Root (Position : Cursor) return Boolean is 1790 begin 1791 return 1792 (if Position.Container = null then False 1793 else Position.Node = Root_Node (Position.Container.all)); 1794 end Is_Root; 1795 1796 ------------- 1797 -- Iterate -- 1798 ------------- 1799 1800 procedure Iterate 1801 (Container : Tree; 1802 Process : not null access procedure (Position : Cursor)) 1803 is 1804 Busy : With_Busy (Container.TC'Unrestricted_Access); 1805 begin 1806 if Container.Count = 0 then 1807 return; 1808 end if; 1809 1810 Iterate_Children 1811 (Container => Container, 1812 Subtree => Root_Node (Container), 1813 Process => Process); 1814 end Iterate; 1815 1816 function Iterate (Container : Tree) 1817 return Tree_Iterator_Interfaces.Forward_Iterator'Class 1818 is 1819 begin 1820 return Iterate_Subtree (Root (Container)); 1821 end Iterate; 1822 1823 ---------------------- 1824 -- Iterate_Children -- 1825 ---------------------- 1826 1827 procedure Iterate_Children 1828 (Parent : Cursor; 1829 Process : not null access procedure (Position : Cursor)) 1830 is 1831 begin 1832 if Checks and then Parent = No_Element then 1833 raise Constraint_Error with "Parent cursor has no element"; 1834 end if; 1835 1836 if Parent.Container.Count = 0 then 1837 pragma Assert (Is_Root (Parent)); 1838 return; 1839 end if; 1840 1841 declare 1842 C : Count_Type; 1843 NN : Tree_Node_Array renames Parent.Container.Nodes; 1844 Busy : With_Busy (Parent.Container.TC'Unrestricted_Access); 1845 1846 begin 1847 C := NN (Parent.Node).Children.First; 1848 while C > 0 loop 1849 Process (Cursor'(Parent.Container, Node => C)); 1850 C := NN (C).Next; 1851 end loop; 1852 end; 1853 end Iterate_Children; 1854 1855 procedure Iterate_Children 1856 (Container : Tree; 1857 Subtree : Count_Type; 1858 Process : not null access procedure (Position : Cursor)) 1859 is 1860 NN : Tree_Node_Array renames Container.Nodes; 1861 N : Tree_Node_Type renames NN (Subtree); 1862 C : Count_Type; 1863 1864 begin 1865 -- This is a helper function to recursively iterate over all the nodes 1866 -- in a subtree, in depth-first fashion. This particular helper just 1867 -- visits the children of this subtree, not the root of the subtree 1868 -- itself. This is useful when starting from the ultimate root of the 1869 -- entire tree (see Iterate), as that root does not have an element. 1870 1871 C := N.Children.First; 1872 while C > 0 loop 1873 Iterate_Subtree (Container, C, Process); 1874 C := NN (C).Next; 1875 end loop; 1876 end Iterate_Children; 1877 1878 function Iterate_Children 1879 (Container : Tree; 1880 Parent : Cursor) 1881 return Tree_Iterator_Interfaces.Reversible_Iterator'Class 1882 is 1883 C : constant Tree_Access := Container'Unrestricted_Access; 1884 begin 1885 if Checks and then Parent = No_Element then 1886 raise Constraint_Error with "Parent cursor has no element"; 1887 end if; 1888 1889 if Checks and then Parent.Container /= C then 1890 raise Program_Error with "Parent cursor not in container"; 1891 end if; 1892 1893 return It : constant Child_Iterator := 1894 Child_Iterator'(Limited_Controlled with 1895 Container => C, 1896 Subtree => Parent.Node) 1897 do 1898 Busy (C.TC); 1899 end return; 1900 end Iterate_Children; 1901 1902 --------------------- 1903 -- Iterate_Subtree -- 1904 --------------------- 1905 1906 function Iterate_Subtree 1907 (Position : Cursor) 1908 return Tree_Iterator_Interfaces.Forward_Iterator'Class 1909 is 1910 C : constant Tree_Access := Position.Container; 1911 begin 1912 if Checks and then Position = No_Element then 1913 raise Constraint_Error with "Position cursor has no element"; 1914 end if; 1915 1916 -- Implement Vet for multiway trees??? 1917 -- pragma Assert (Vet (Position), "bad subtree cursor"); 1918 1919 return It : constant Subtree_Iterator := 1920 (Limited_Controlled with 1921 Container => C, 1922 Subtree => Position.Node) 1923 do 1924 Busy (C.TC); 1925 end return; 1926 end Iterate_Subtree; 1927 1928 procedure Iterate_Subtree 1929 (Position : Cursor; 1930 Process : not null access procedure (Position : Cursor)) 1931 is 1932 begin 1933 if Checks and then Position = No_Element then 1934 raise Constraint_Error with "Position cursor has no element"; 1935 end if; 1936 1937 if Position.Container.Count = 0 then 1938 pragma Assert (Is_Root (Position)); 1939 return; 1940 end if; 1941 1942 declare 1943 T : Tree renames Position.Container.all; 1944 Busy : With_Busy (T.TC'Unrestricted_Access); 1945 begin 1946 if Is_Root (Position) then 1947 Iterate_Children (T, Position.Node, Process); 1948 else 1949 Iterate_Subtree (T, Position.Node, Process); 1950 end if; 1951 end; 1952 end Iterate_Subtree; 1953 1954 procedure Iterate_Subtree 1955 (Container : Tree; 1956 Subtree : Count_Type; 1957 Process : not null access procedure (Position : Cursor)) 1958 is 1959 begin 1960 -- This is a helper function to recursively iterate over all the nodes 1961 -- in a subtree, in depth-first fashion. It first visits the root of the 1962 -- subtree, then visits its children. 1963 1964 Process (Cursor'(Container'Unrestricted_Access, Subtree)); 1965 Iterate_Children (Container, Subtree, Process); 1966 end Iterate_Subtree; 1967 1968 ---------- 1969 -- Last -- 1970 ---------- 1971 1972 overriding function Last (Object : Child_Iterator) return Cursor is 1973 begin 1974 return Last_Child (Cursor'(Object.Container, Object.Subtree)); 1975 end Last; 1976 1977 ---------------- 1978 -- Last_Child -- 1979 ---------------- 1980 1981 function Last_Child (Parent : Cursor) return Cursor is 1982 Node : Count_Type'Base; 1983 1984 begin 1985 if Checks and then Parent = No_Element then 1986 raise Constraint_Error with "Parent cursor has no element"; 1987 end if; 1988 1989 if Parent.Container.Count = 0 then 1990 pragma Assert (Is_Root (Parent)); 1991 return No_Element; 1992 end if; 1993 1994 Node := Parent.Container.Nodes (Parent.Node).Children.Last; 1995 1996 if Node <= 0 then 1997 return No_Element; 1998 end if; 1999 2000 return Cursor'(Parent.Container, Node); 2001 end Last_Child; 2002 2003 ------------------------ 2004 -- Last_Child_Element -- 2005 ------------------------ 2006 2007 function Last_Child_Element (Parent : Cursor) return Element_Type is 2008 begin 2009 return Element (Last_Child (Parent)); 2010 end Last_Child_Element; 2011 2012 ---------- 2013 -- Move -- 2014 ---------- 2015 2016 procedure Move (Target : in out Tree; Source : in out Tree) is 2017 begin 2018 if Target'Address = Source'Address then 2019 return; 2020 end if; 2021 2022 TC_Check (Source.TC); 2023 2024 Target.Assign (Source); 2025 Source.Clear; 2026 end Move; 2027 2028 ---------- 2029 -- Next -- 2030 ---------- 2031 2032 overriding function Next 2033 (Object : Subtree_Iterator; 2034 Position : Cursor) return Cursor 2035 is 2036 begin 2037 if Position.Container = null then 2038 return No_Element; 2039 end if; 2040 2041 if Checks and then Position.Container /= Object.Container then 2042 raise Program_Error with 2043 "Position cursor of Next designates wrong tree"; 2044 end if; 2045 2046 pragma Assert (Object.Container.Count > 0); 2047 pragma Assert (Position.Node /= Root_Node (Object.Container.all)); 2048 2049 declare 2050 Nodes : Tree_Node_Array renames Object.Container.Nodes; 2051 Node : Count_Type; 2052 2053 begin 2054 Node := Position.Node; 2055 2056 if Nodes (Node).Children.First > 0 then 2057 return Cursor'(Object.Container, Nodes (Node).Children.First); 2058 end if; 2059 2060 while Node /= Object.Subtree loop 2061 if Nodes (Node).Next > 0 then 2062 return Cursor'(Object.Container, Nodes (Node).Next); 2063 end if; 2064 2065 Node := Nodes (Node).Parent; 2066 end loop; 2067 2068 return No_Element; 2069 end; 2070 end Next; 2071 2072 overriding function Next 2073 (Object : Child_Iterator; 2074 Position : Cursor) return Cursor 2075 is 2076 begin 2077 if Position.Container = null then 2078 return No_Element; 2079 end if; 2080 2081 if Checks and then Position.Container /= Object.Container then 2082 raise Program_Error with 2083 "Position cursor of Next designates wrong tree"; 2084 end if; 2085 2086 pragma Assert (Object.Container.Count > 0); 2087 pragma Assert (Position.Node /= Root_Node (Object.Container.all)); 2088 2089 return Next_Sibling (Position); 2090 end Next; 2091 2092 ------------------ 2093 -- Next_Sibling -- 2094 ------------------ 2095 2096 function Next_Sibling (Position : Cursor) return Cursor is 2097 begin 2098 if Position = No_Element then 2099 return No_Element; 2100 end if; 2101 2102 if Position.Container.Count = 0 then 2103 pragma Assert (Is_Root (Position)); 2104 return No_Element; 2105 end if; 2106 2107 declare 2108 T : Tree renames Position.Container.all; 2109 NN : Tree_Node_Array renames T.Nodes; 2110 N : Tree_Node_Type renames NN (Position.Node); 2111 2112 begin 2113 if N.Next <= 0 then 2114 return No_Element; 2115 end if; 2116 2117 return Cursor'(Position.Container, N.Next); 2118 end; 2119 end Next_Sibling; 2120 2121 procedure Next_Sibling (Position : in out Cursor) is 2122 begin 2123 Position := Next_Sibling (Position); 2124 end Next_Sibling; 2125 2126 ---------------- 2127 -- Node_Count -- 2128 ---------------- 2129 2130 function Node_Count (Container : Tree) return Count_Type is 2131 begin 2132 -- Container.Count is the number of nodes we have actually allocated. We 2133 -- cache the value specifically so this Node_Count operation can execute 2134 -- in O(1) time, which makes it behave similarly to how the Length 2135 -- selector function behaves for other containers. 2136 -- 2137 -- The cached node count value only describes the nodes we have 2138 -- allocated; the root node itself is not included in that count. The 2139 -- Node_Count operation returns a value that includes the root node 2140 -- (because the RM says so), so we must add 1 to our cached value. 2141 2142 return 1 + Container.Count; 2143 end Node_Count; 2144 2145 ------------ 2146 -- Parent -- 2147 ------------ 2148 2149 function Parent (Position : Cursor) return Cursor is 2150 begin 2151 if Position = No_Element then 2152 return No_Element; 2153 end if; 2154 2155 if Position.Container.Count = 0 then 2156 pragma Assert (Is_Root (Position)); 2157 return No_Element; 2158 end if; 2159 2160 declare 2161 T : Tree renames Position.Container.all; 2162 NN : Tree_Node_Array renames T.Nodes; 2163 N : Tree_Node_Type renames NN (Position.Node); 2164 2165 begin 2166 if N.Parent < 0 then 2167 pragma Assert (Position.Node = Root_Node (T)); 2168 return No_Element; 2169 end if; 2170 2171 return Cursor'(Position.Container, N.Parent); 2172 end; 2173 end Parent; 2174 2175 ------------------- 2176 -- Prepend_Child -- 2177 ------------------- 2178 2179 procedure Prepend_Child 2180 (Container : in out Tree; 2181 Parent : Cursor; 2182 New_Item : Element_Type; 2183 Count : Count_Type := 1) 2184 is 2185 Nodes : Tree_Node_Array renames Container.Nodes; 2186 First, Last : Count_Type; 2187 2188 begin 2189 if Checks and then Parent = No_Element then 2190 raise Constraint_Error with "Parent cursor has no element"; 2191 end if; 2192 2193 if Checks and then Parent.Container /= Container'Unrestricted_Access then 2194 raise Program_Error with "Parent cursor not in container"; 2195 end if; 2196 2197 if Count = 0 then 2198 return; 2199 end if; 2200 2201 if Checks and then Container.Count > Container.Capacity - Count then 2202 raise Capacity_Error 2203 with "requested count exceeds available storage"; 2204 end if; 2205 2206 TC_Check (Container.TC); 2207 2208 if Container.Count = 0 then 2209 Initialize_Root (Container); 2210 end if; 2211 2212 Allocate_Node (Container, New_Item, First); 2213 Nodes (First).Parent := Parent.Node; 2214 2215 Last := First; 2216 for J in Count_Type'(2) .. Count loop 2217 Allocate_Node (Container, New_Item, Nodes (Last).Next); 2218 Nodes (Nodes (Last).Next).Parent := Parent.Node; 2219 Nodes (Nodes (Last).Next).Prev := Last; 2220 2221 Last := Nodes (Last).Next; 2222 end loop; 2223 2224 Insert_Subtree_List 2225 (Container => Container, 2226 First => First, 2227 Last => Last, 2228 Parent => Parent.Node, 2229 Before => Nodes (Parent.Node).Children.First); 2230 2231 Container.Count := Container.Count + Count; 2232 end Prepend_Child; 2233 2234 -------------- 2235 -- Previous -- 2236 -------------- 2237 2238 overriding function Previous 2239 (Object : Child_Iterator; 2240 Position : Cursor) return Cursor 2241 is 2242 begin 2243 if Position.Container = null then 2244 return No_Element; 2245 end if; 2246 2247 if Checks and then Position.Container /= Object.Container then 2248 raise Program_Error with 2249 "Position cursor of Previous designates wrong tree"; 2250 end if; 2251 2252 return Previous_Sibling (Position); 2253 end Previous; 2254 2255 ---------------------- 2256 -- Previous_Sibling -- 2257 ---------------------- 2258 2259 function Previous_Sibling (Position : Cursor) return Cursor is 2260 begin 2261 if Position = No_Element then 2262 return No_Element; 2263 end if; 2264 2265 if Position.Container.Count = 0 then 2266 pragma Assert (Is_Root (Position)); 2267 return No_Element; 2268 end if; 2269 2270 declare 2271 T : Tree renames Position.Container.all; 2272 NN : Tree_Node_Array renames T.Nodes; 2273 N : Tree_Node_Type renames NN (Position.Node); 2274 2275 begin 2276 if N.Prev <= 0 then 2277 return No_Element; 2278 end if; 2279 2280 return Cursor'(Position.Container, N.Prev); 2281 end; 2282 end Previous_Sibling; 2283 2284 procedure Previous_Sibling (Position : in out Cursor) is 2285 begin 2286 Position := Previous_Sibling (Position); 2287 end Previous_Sibling; 2288 2289 ---------------------- 2290 -- Pseudo_Reference -- 2291 ---------------------- 2292 2293 function Pseudo_Reference 2294 (Container : aliased Tree'Class) return Reference_Control_Type 2295 is 2296 TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access; 2297 begin 2298 return R : constant Reference_Control_Type := (Controlled with TC) do 2299 Lock (TC.all); 2300 end return; 2301 end Pseudo_Reference; 2302 2303 ------------------- 2304 -- Query_Element -- 2305 ------------------- 2306 2307 procedure Query_Element 2308 (Position : Cursor; 2309 Process : not null access procedure (Element : Element_Type)) 2310 is 2311 begin 2312 if Checks and then Position = No_Element then 2313 raise Constraint_Error with "Position cursor has no element"; 2314 end if; 2315 2316 if Checks and then Is_Root (Position) then 2317 raise Program_Error with "Position cursor designates root"; 2318 end if; 2319 2320 declare 2321 T : Tree renames Position.Container.all'Unrestricted_Access.all; 2322 Lock : With_Lock (T.TC'Unrestricted_Access); 2323 begin 2324 Process (Element => T.Elements (Position.Node)); 2325 end; 2326 end Query_Element; 2327 2328 ---------- 2329 -- Read -- 2330 ---------- 2331 2332 procedure Read 2333 (Stream : not null access Root_Stream_Type'Class; 2334 Container : out Tree) 2335 is 2336 procedure Read_Children (Subtree : Count_Type); 2337 2338 function Read_Subtree 2339 (Parent : Count_Type) return Count_Type; 2340 2341 NN : Tree_Node_Array renames Container.Nodes; 2342 2343 Total_Count : Count_Type'Base; 2344 -- Value read from the stream that says how many elements follow 2345 2346 Read_Count : Count_Type'Base; 2347 -- Actual number of elements read from the stream 2348 2349 ------------------- 2350 -- Read_Children -- 2351 ------------------- 2352 2353 procedure Read_Children (Subtree : Count_Type) is 2354 Count : Count_Type'Base; 2355 -- number of child subtrees 2356 2357 CC : Children_Type; 2358 2359 begin 2360 Count_Type'Read (Stream, Count); 2361 2362 if Checks and then Count < 0 then 2363 raise Program_Error with "attempt to read from corrupt stream"; 2364 end if; 2365 2366 if Count = 0 then 2367 return; 2368 end if; 2369 2370 CC.First := Read_Subtree (Parent => Subtree); 2371 CC.Last := CC.First; 2372 2373 for J in Count_Type'(2) .. Count loop 2374 NN (CC.Last).Next := Read_Subtree (Parent => Subtree); 2375 NN (NN (CC.Last).Next).Prev := CC.Last; 2376 CC.Last := NN (CC.Last).Next; 2377 end loop; 2378 2379 -- Now that the allocation and reads have completed successfully, it 2380 -- is safe to link the children to their parent. 2381 2382 NN (Subtree).Children := CC; 2383 end Read_Children; 2384 2385 ------------------ 2386 -- Read_Subtree -- 2387 ------------------ 2388 2389 function Read_Subtree 2390 (Parent : Count_Type) return Count_Type 2391 is 2392 Subtree : Count_Type; 2393 2394 begin 2395 Allocate_Node (Container, Stream, Subtree); 2396 Container.Nodes (Subtree).Parent := Parent; 2397 2398 Read_Count := Read_Count + 1; 2399 2400 Read_Children (Subtree); 2401 2402 return Subtree; 2403 end Read_Subtree; 2404 2405 -- Start of processing for Read 2406 2407 begin 2408 Container.Clear; -- checks busy bit 2409 2410 Count_Type'Read (Stream, Total_Count); 2411 2412 if Checks and then Total_Count < 0 then 2413 raise Program_Error with "attempt to read from corrupt stream"; 2414 end if; 2415 2416 if Total_Count = 0 then 2417 return; 2418 end if; 2419 2420 if Checks and then Total_Count > Container.Capacity then 2421 raise Capacity_Error -- ??? 2422 with "node count in stream exceeds container capacity"; 2423 end if; 2424 2425 Initialize_Root (Container); 2426 2427 Read_Count := 0; 2428 2429 Read_Children (Root_Node (Container)); 2430 2431 if Checks and then Read_Count /= Total_Count then 2432 raise Program_Error with "attempt to read from corrupt stream"; 2433 end if; 2434 2435 Container.Count := Total_Count; 2436 end Read; 2437 2438 procedure Read 2439 (Stream : not null access Root_Stream_Type'Class; 2440 Position : out Cursor) 2441 is 2442 begin 2443 raise Program_Error with "attempt to read tree cursor from stream"; 2444 end Read; 2445 2446 procedure Read 2447 (Stream : not null access Root_Stream_Type'Class; 2448 Item : out Reference_Type) 2449 is 2450 begin 2451 raise Program_Error with "attempt to stream reference"; 2452 end Read; 2453 2454 procedure Read 2455 (Stream : not null access Root_Stream_Type'Class; 2456 Item : out Constant_Reference_Type) 2457 is 2458 begin 2459 raise Program_Error with "attempt to stream reference"; 2460 end Read; 2461 2462 --------------- 2463 -- Reference -- 2464 --------------- 2465 2466 function Reference 2467 (Container : aliased in out Tree; 2468 Position : Cursor) return Reference_Type 2469 is 2470 begin 2471 if Checks and then Position.Container = null then 2472 raise Constraint_Error with 2473 "Position cursor has no element"; 2474 end if; 2475 2476 if Checks and then Position.Container /= Container'Unrestricted_Access 2477 then 2478 raise Program_Error with 2479 "Position cursor designates wrong container"; 2480 end if; 2481 2482 if Checks and then Position.Node = Root_Node (Container) then 2483 raise Program_Error with "Position cursor designates root"; 2484 end if; 2485 2486 -- Implement Vet for multiway tree??? 2487 -- pragma Assert (Vet (Position), 2488 -- "Position cursor in Constant_Reference is bad"); 2489 2490 declare 2491 TC : constant Tamper_Counts_Access := 2492 Container.TC'Unrestricted_Access; 2493 begin 2494 return R : constant Reference_Type := 2495 (Element => Container.Elements (Position.Node)'Access, 2496 Control => (Controlled with TC)) 2497 do 2498 Lock (TC.all); 2499 end return; 2500 end; 2501 end Reference; 2502 2503 -------------------- 2504 -- Remove_Subtree -- 2505 -------------------- 2506 2507 procedure Remove_Subtree 2508 (Container : in out Tree; 2509 Subtree : Count_Type) 2510 is 2511 NN : Tree_Node_Array renames Container.Nodes; 2512 N : Tree_Node_Type renames NN (Subtree); 2513 CC : Children_Type renames NN (N.Parent).Children; 2514 2515 begin 2516 -- This is a utility operation to remove a subtree node from its 2517 -- parent's list of children. 2518 2519 if CC.First = Subtree then 2520 pragma Assert (N.Prev <= 0); 2521 2522 if CC.Last = Subtree then 2523 pragma Assert (N.Next <= 0); 2524 CC.First := 0; 2525 CC.Last := 0; 2526 2527 else 2528 CC.First := N.Next; 2529 NN (CC.First).Prev := 0; 2530 end if; 2531 2532 elsif CC.Last = Subtree then 2533 pragma Assert (N.Next <= 0); 2534 CC.Last := N.Prev; 2535 NN (CC.Last).Next := 0; 2536 2537 else 2538 NN (N.Prev).Next := N.Next; 2539 NN (N.Next).Prev := N.Prev; 2540 end if; 2541 end Remove_Subtree; 2542 2543 ---------------------- 2544 -- Replace_Element -- 2545 ---------------------- 2546 2547 procedure Replace_Element 2548 (Container : in out Tree; 2549 Position : Cursor; 2550 New_Item : Element_Type) 2551 is 2552 begin 2553 if Checks and then Position = No_Element then 2554 raise Constraint_Error with "Position cursor has no element"; 2555 end if; 2556 2557 if Checks and then Position.Container /= Container'Unrestricted_Access 2558 then 2559 raise Program_Error with "Position cursor not in container"; 2560 end if; 2561 2562 if Checks and then Is_Root (Position) then 2563 raise Program_Error with "Position cursor designates root"; 2564 end if; 2565 2566 TE_Check (Container.TC); 2567 2568 Container.Elements (Position.Node) := New_Item; 2569 end Replace_Element; 2570 2571 ------------------------------ 2572 -- Reverse_Iterate_Children -- 2573 ------------------------------ 2574 2575 procedure Reverse_Iterate_Children 2576 (Parent : Cursor; 2577 Process : not null access procedure (Position : Cursor)) 2578 is 2579 begin 2580 if Checks and then Parent = No_Element then 2581 raise Constraint_Error with "Parent cursor has no element"; 2582 end if; 2583 2584 if Parent.Container.Count = 0 then 2585 pragma Assert (Is_Root (Parent)); 2586 return; 2587 end if; 2588 2589 declare 2590 NN : Tree_Node_Array renames Parent.Container.Nodes; 2591 Busy : With_Busy (Parent.Container.TC'Unrestricted_Access); 2592 C : Count_Type; 2593 2594 begin 2595 C := NN (Parent.Node).Children.Last; 2596 while C > 0 loop 2597 Process (Cursor'(Parent.Container, Node => C)); 2598 C := NN (C).Prev; 2599 end loop; 2600 end; 2601 end Reverse_Iterate_Children; 2602 2603 ---------- 2604 -- Root -- 2605 ---------- 2606 2607 function Root (Container : Tree) return Cursor is 2608 begin 2609 return (Container'Unrestricted_Access, Root_Node (Container)); 2610 end Root; 2611 2612 --------------- 2613 -- Root_Node -- 2614 --------------- 2615 2616 function Root_Node (Container : Tree) return Count_Type is 2617 pragma Unreferenced (Container); 2618 2619 begin 2620 return 0; 2621 end Root_Node; 2622 2623 --------------------- 2624 -- Splice_Children -- 2625 --------------------- 2626 2627 procedure Splice_Children 2628 (Target : in out Tree; 2629 Target_Parent : Cursor; 2630 Before : Cursor; 2631 Source : in out Tree; 2632 Source_Parent : Cursor) 2633 is 2634 begin 2635 if Checks and then Target_Parent = No_Element then 2636 raise Constraint_Error with "Target_Parent cursor has no element"; 2637 end if; 2638 2639 if Checks and then Target_Parent.Container /= Target'Unrestricted_Access 2640 then 2641 raise Program_Error 2642 with "Target_Parent cursor not in Target container"; 2643 end if; 2644 2645 if Before /= No_Element then 2646 if Checks and then Before.Container /= Target'Unrestricted_Access then 2647 raise Program_Error 2648 with "Before cursor not in Target container"; 2649 end if; 2650 2651 if Checks and then 2652 Target.Nodes (Before.Node).Parent /= Target_Parent.Node 2653 then 2654 raise Constraint_Error 2655 with "Before cursor not child of Target_Parent"; 2656 end if; 2657 end if; 2658 2659 if Checks and then Source_Parent = No_Element then 2660 raise Constraint_Error with "Source_Parent cursor has no element"; 2661 end if; 2662 2663 if Checks and then Source_Parent.Container /= Source'Unrestricted_Access 2664 then 2665 raise Program_Error 2666 with "Source_Parent cursor not in Source container"; 2667 end if; 2668 2669 if Source.Count = 0 then 2670 pragma Assert (Is_Root (Source_Parent)); 2671 return; 2672 end if; 2673 2674 if Target'Address = Source'Address then 2675 if Target_Parent = Source_Parent then 2676 return; 2677 end if; 2678 2679 TC_Check (Target.TC); 2680 2681 if Checks and then Is_Reachable (Container => Target, 2682 From => Target_Parent.Node, 2683 To => Source_Parent.Node) 2684 then 2685 raise Constraint_Error 2686 with "Source_Parent is ancestor of Target_Parent"; 2687 end if; 2688 2689 Splice_Children 2690 (Container => Target, 2691 Target_Parent => Target_Parent.Node, 2692 Before => Before.Node, 2693 Source_Parent => Source_Parent.Node); 2694 2695 return; 2696 end if; 2697 2698 TC_Check (Target.TC); 2699 TC_Check (Source.TC); 2700 2701 if Target.Count = 0 then 2702 Initialize_Root (Target); 2703 end if; 2704 2705 Splice_Children 2706 (Target => Target, 2707 Target_Parent => Target_Parent.Node, 2708 Before => Before.Node, 2709 Source => Source, 2710 Source_Parent => Source_Parent.Node); 2711 end Splice_Children; 2712 2713 procedure Splice_Children 2714 (Container : in out Tree; 2715 Target_Parent : Cursor; 2716 Before : Cursor; 2717 Source_Parent : Cursor) 2718 is 2719 begin 2720 if Checks and then Target_Parent = No_Element then 2721 raise Constraint_Error with "Target_Parent cursor has no element"; 2722 end if; 2723 2724 if Checks and then 2725 Target_Parent.Container /= Container'Unrestricted_Access 2726 then 2727 raise Program_Error 2728 with "Target_Parent cursor not in container"; 2729 end if; 2730 2731 if Before /= No_Element then 2732 if Checks and then Before.Container /= Container'Unrestricted_Access 2733 then 2734 raise Program_Error 2735 with "Before cursor not in container"; 2736 end if; 2737 2738 if Checks and then 2739 Container.Nodes (Before.Node).Parent /= Target_Parent.Node 2740 then 2741 raise Constraint_Error 2742 with "Before cursor not child of Target_Parent"; 2743 end if; 2744 end if; 2745 2746 if Checks and then Source_Parent = No_Element then 2747 raise Constraint_Error with "Source_Parent cursor has no element"; 2748 end if; 2749 2750 if Checks and then 2751 Source_Parent.Container /= Container'Unrestricted_Access 2752 then 2753 raise Program_Error 2754 with "Source_Parent cursor not in container"; 2755 end if; 2756 2757 if Target_Parent = Source_Parent then 2758 return; 2759 end if; 2760 2761 pragma Assert (Container.Count > 0); 2762 2763 TC_Check (Container.TC); 2764 2765 if Checks and then Is_Reachable (Container => Container, 2766 From => Target_Parent.Node, 2767 To => Source_Parent.Node) 2768 then 2769 raise Constraint_Error 2770 with "Source_Parent is ancestor of Target_Parent"; 2771 end if; 2772 2773 Splice_Children 2774 (Container => Container, 2775 Target_Parent => Target_Parent.Node, 2776 Before => Before.Node, 2777 Source_Parent => Source_Parent.Node); 2778 end Splice_Children; 2779 2780 procedure Splice_Children 2781 (Container : in out Tree; 2782 Target_Parent : Count_Type; 2783 Before : Count_Type'Base; 2784 Source_Parent : Count_Type) 2785 is 2786 NN : Tree_Node_Array renames Container.Nodes; 2787 CC : constant Children_Type := NN (Source_Parent).Children; 2788 C : Count_Type'Base; 2789 2790 begin 2791 -- This is a utility operation to remove the children from Source parent 2792 -- and insert them into Target parent. 2793 2794 NN (Source_Parent).Children := Children_Type'(others => 0); 2795 2796 -- Fix up the Parent pointers of each child to designate its new Target 2797 -- parent. 2798 2799 C := CC.First; 2800 while C > 0 loop 2801 NN (C).Parent := Target_Parent; 2802 C := NN (C).Next; 2803 end loop; 2804 2805 Insert_Subtree_List 2806 (Container => Container, 2807 First => CC.First, 2808 Last => CC.Last, 2809 Parent => Target_Parent, 2810 Before => Before); 2811 end Splice_Children; 2812 2813 procedure Splice_Children 2814 (Target : in out Tree; 2815 Target_Parent : Count_Type; 2816 Before : Count_Type'Base; 2817 Source : in out Tree; 2818 Source_Parent : Count_Type) 2819 is 2820 S_NN : Tree_Node_Array renames Source.Nodes; 2821 S_CC : Children_Type renames S_NN (Source_Parent).Children; 2822 2823 Target_Count, Source_Count : Count_Type; 2824 T, S : Count_Type'Base; 2825 2826 begin 2827 -- This is a utility operation to copy the children from the Source 2828 -- parent and insert them as children of the Target parent, and then 2829 -- delete them from the Source. (This is not a true splice operation, 2830 -- but it is the best we can do in a bounded form.) The Before position 2831 -- specifies where among the Target parent's exising children the new 2832 -- children are inserted. 2833 2834 -- Before we attempt the insertion, we must count the sources nodes in 2835 -- order to determine whether the target have enough storage 2836 -- available. Note that calculating this value is an O(n) operation. 2837 2838 -- Here is an optimization opportunity: iterate of each children the 2839 -- source explicitly, and keep a running count of the total number of 2840 -- nodes. Compare the running total to the capacity of the target each 2841 -- pass through the loop. This is more efficient than summing the counts 2842 -- of child subtree (which is what Subtree_Node_Count does) and then 2843 -- comparing that total sum to the target's capacity. ??? 2844 2845 -- Here is another possibility. We currently treat the splice as an 2846 -- all-or-nothing proposition: either we can insert all of children of 2847 -- the source, or we raise exception with modifying the target. The 2848 -- price for not causing side-effect is an O(n) determination of the 2849 -- source count. If we are willing to tolerate side-effect, then we 2850 -- could loop over the children of the source, counting that subtree and 2851 -- then immediately inserting it in the target. The issue here is that 2852 -- the test for available storage could fail during some later pass, 2853 -- after children have already been inserted into target. ??? 2854 2855 Source_Count := Subtree_Node_Count (Source, Source_Parent) - 1; 2856 2857 if Source_Count = 0 then 2858 return; 2859 end if; 2860 2861 if Checks and then Target.Count > Target.Capacity - Source_Count then 2862 raise Capacity_Error -- ??? 2863 with "Source count exceeds available storage on Target"; 2864 end if; 2865 2866 -- Copy_Subtree returns a count of the number of nodes it inserts, but 2867 -- it does this by incrementing the value passed in. Therefore we must 2868 -- initialize the count before calling Copy_Subtree. 2869 2870 Target_Count := 0; 2871 2872 S := S_CC.First; 2873 while S > 0 loop 2874 Copy_Subtree 2875 (Source => Source, 2876 Source_Subtree => S, 2877 Target => Target, 2878 Target_Parent => Target_Parent, 2879 Target_Subtree => T, 2880 Count => Target_Count); 2881 2882 Insert_Subtree_Node 2883 (Container => Target, 2884 Subtree => T, 2885 Parent => Target_Parent, 2886 Before => Before); 2887 2888 S := S_NN (S).Next; 2889 end loop; 2890 2891 pragma Assert (Target_Count = Source_Count); 2892 Target.Count := Target.Count + Target_Count; 2893 2894 -- As with Copy_Subtree, operation Deallocate_Children returns a count 2895 -- of the number of nodes it deallocates, but it works by incrementing 2896 -- the value passed in. We must therefore initialize the count before 2897 -- calling it. 2898 2899 Source_Count := 0; 2900 2901 Deallocate_Children (Source, Source_Parent, Source_Count); 2902 pragma Assert (Source_Count = Target_Count); 2903 2904 Source.Count := Source.Count - Source_Count; 2905 end Splice_Children; 2906 2907 -------------------- 2908 -- Splice_Subtree -- 2909 -------------------- 2910 2911 procedure Splice_Subtree 2912 (Target : in out Tree; 2913 Parent : Cursor; 2914 Before : Cursor; 2915 Source : in out Tree; 2916 Position : in out Cursor) 2917 is 2918 begin 2919 if Checks and then Parent = No_Element then 2920 raise Constraint_Error with "Parent cursor has no element"; 2921 end if; 2922 2923 if Checks and then Parent.Container /= Target'Unrestricted_Access then 2924 raise Program_Error with "Parent cursor not in Target container"; 2925 end if; 2926 2927 if Before /= No_Element then 2928 if Checks and then Before.Container /= Target'Unrestricted_Access then 2929 raise Program_Error with "Before cursor not in Target container"; 2930 end if; 2931 2932 if Checks and then Target.Nodes (Before.Node).Parent /= Parent.Node 2933 then 2934 raise Constraint_Error with "Before cursor not child of Parent"; 2935 end if; 2936 end if; 2937 2938 if Checks and then Position = No_Element then 2939 raise Constraint_Error with "Position cursor has no element"; 2940 end if; 2941 2942 if Checks and then Position.Container /= Source'Unrestricted_Access then 2943 raise Program_Error with "Position cursor not in Source container"; 2944 end if; 2945 2946 if Checks and then Is_Root (Position) then 2947 raise Program_Error with "Position cursor designates root"; 2948 end if; 2949 2950 if Target'Address = Source'Address then 2951 if Target.Nodes (Position.Node).Parent = Parent.Node then 2952 if Before = No_Element then 2953 if Target.Nodes (Position.Node).Next <= 0 then -- last child 2954 return; 2955 end if; 2956 2957 elsif Position.Node = Before.Node then 2958 return; 2959 2960 elsif Target.Nodes (Position.Node).Next = Before.Node then 2961 return; 2962 end if; 2963 end if; 2964 2965 TC_Check (Target.TC); 2966 2967 if Checks and then Is_Reachable (Container => Target, 2968 From => Parent.Node, 2969 To => Position.Node) 2970 then 2971 raise Constraint_Error with "Position is ancestor of Parent"; 2972 end if; 2973 2974 Remove_Subtree (Target, Position.Node); 2975 2976 Target.Nodes (Position.Node).Parent := Parent.Node; 2977 Insert_Subtree_Node (Target, Position.Node, Parent.Node, Before.Node); 2978 2979 return; 2980 end if; 2981 2982 TC_Check (Target.TC); 2983 TC_Check (Source.TC); 2984 2985 if Target.Count = 0 then 2986 Initialize_Root (Target); 2987 end if; 2988 2989 Splice_Subtree 2990 (Target => Target, 2991 Parent => Parent.Node, 2992 Before => Before.Node, 2993 Source => Source, 2994 Position => Position.Node); -- modified during call 2995 2996 Position.Container := Target'Unrestricted_Access; 2997 end Splice_Subtree; 2998 2999 procedure Splice_Subtree 3000 (Container : in out Tree; 3001 Parent : Cursor; 3002 Before : Cursor; 3003 Position : Cursor) 3004 is 3005 begin 3006 if Checks and then Parent = No_Element then 3007 raise Constraint_Error with "Parent cursor has no element"; 3008 end if; 3009 3010 if Checks and then Parent.Container /= Container'Unrestricted_Access then 3011 raise Program_Error with "Parent cursor not in container"; 3012 end if; 3013 3014 if Before /= No_Element then 3015 if Checks and then Before.Container /= Container'Unrestricted_Access 3016 then 3017 raise Program_Error with "Before cursor not in container"; 3018 end if; 3019 3020 if Checks and then Container.Nodes (Before.Node).Parent /= Parent.Node 3021 then 3022 raise Constraint_Error with "Before cursor not child of Parent"; 3023 end if; 3024 end if; 3025 3026 if Checks and then Position = No_Element then 3027 raise Constraint_Error with "Position cursor has no element"; 3028 end if; 3029 3030 if Checks and then Position.Container /= Container'Unrestricted_Access 3031 then 3032 raise Program_Error with "Position cursor not in container"; 3033 end if; 3034 3035 if Checks and then Is_Root (Position) then 3036 3037 -- Should this be PE instead? Need ARG confirmation. ??? 3038 3039 raise Constraint_Error with "Position cursor designates root"; 3040 end if; 3041 3042 if Container.Nodes (Position.Node).Parent = Parent.Node then 3043 if Before = No_Element then 3044 if Container.Nodes (Position.Node).Next <= 0 then -- last child 3045 return; 3046 end if; 3047 3048 elsif Position.Node = Before.Node then 3049 return; 3050 3051 elsif Container.Nodes (Position.Node).Next = Before.Node then 3052 return; 3053 end if; 3054 end if; 3055 3056 TC_Check (Container.TC); 3057 3058 if Checks and then Is_Reachable (Container => Container, 3059 From => Parent.Node, 3060 To => Position.Node) 3061 then 3062 raise Constraint_Error with "Position is ancestor of Parent"; 3063 end if; 3064 3065 Remove_Subtree (Container, Position.Node); 3066 Container.Nodes (Position.Node).Parent := Parent.Node; 3067 Insert_Subtree_Node (Container, Position.Node, Parent.Node, Before.Node); 3068 end Splice_Subtree; 3069 3070 procedure Splice_Subtree 3071 (Target : in out Tree; 3072 Parent : Count_Type; 3073 Before : Count_Type'Base; 3074 Source : in out Tree; 3075 Position : in out Count_Type) -- Source on input, Target on output 3076 is 3077 Source_Count : Count_Type := Subtree_Node_Count (Source, Position); 3078 pragma Assert (Source_Count >= 1); 3079 3080 Target_Subtree : Count_Type; 3081 Target_Count : Count_Type; 3082 3083 begin 3084 -- This is a utility operation to do the heavy lifting associated with 3085 -- splicing a subtree from one tree to another. Note that "splicing" 3086 -- is a bit of a misnomer here in the case of a bounded tree, because 3087 -- the elements must be copied from the source to the target. 3088 3089 if Checks and then Target.Count > Target.Capacity - Source_Count then 3090 raise Capacity_Error -- ??? 3091 with "Source count exceeds available storage on Target"; 3092 end if; 3093 3094 -- Copy_Subtree returns a count of the number of nodes it inserts, but 3095 -- it does this by incrementing the value passed in. Therefore we must 3096 -- initialize the count before calling Copy_Subtree. 3097 3098 Target_Count := 0; 3099 3100 Copy_Subtree 3101 (Source => Source, 3102 Source_Subtree => Position, 3103 Target => Target, 3104 Target_Parent => Parent, 3105 Target_Subtree => Target_Subtree, 3106 Count => Target_Count); 3107 3108 pragma Assert (Target_Count = Source_Count); 3109 3110 -- Now link the newly-allocated subtree into the target. 3111 3112 Insert_Subtree_Node 3113 (Container => Target, 3114 Subtree => Target_Subtree, 3115 Parent => Parent, 3116 Before => Before); 3117 3118 Target.Count := Target.Count + Target_Count; 3119 3120 -- The manipulation of the Target container is complete. Now we remove 3121 -- the subtree from the Source container. 3122 3123 Remove_Subtree (Source, Position); -- unlink the subtree 3124 3125 -- As with Copy_Subtree, operation Deallocate_Subtree returns a count of 3126 -- the number of nodes it deallocates, but it works by incrementing the 3127 -- value passed in. We must therefore initialize the count before 3128 -- calling it. 3129 3130 Source_Count := 0; 3131 3132 Deallocate_Subtree (Source, Position, Source_Count); 3133 pragma Assert (Source_Count = Target_Count); 3134 3135 Source.Count := Source.Count - Source_Count; 3136 3137 Position := Target_Subtree; 3138 end Splice_Subtree; 3139 3140 ------------------------ 3141 -- Subtree_Node_Count -- 3142 ------------------------ 3143 3144 function Subtree_Node_Count (Position : Cursor) return Count_Type is 3145 begin 3146 if Position = No_Element then 3147 return 0; 3148 end if; 3149 3150 if Position.Container.Count = 0 then 3151 pragma Assert (Is_Root (Position)); 3152 return 1; 3153 end if; 3154 3155 return Subtree_Node_Count (Position.Container.all, Position.Node); 3156 end Subtree_Node_Count; 3157 3158 function Subtree_Node_Count 3159 (Container : Tree; 3160 Subtree : Count_Type) return Count_Type 3161 is 3162 Result : Count_Type; 3163 Node : Count_Type'Base; 3164 3165 begin 3166 Result := 1; 3167 Node := Container.Nodes (Subtree).Children.First; 3168 while Node > 0 loop 3169 Result := Result + Subtree_Node_Count (Container, Node); 3170 Node := Container.Nodes (Node).Next; 3171 end loop; 3172 return Result; 3173 end Subtree_Node_Count; 3174 3175 ---------- 3176 -- Swap -- 3177 ---------- 3178 3179 procedure Swap 3180 (Container : in out Tree; 3181 I, J : Cursor) 3182 is 3183 begin 3184 if Checks and then I = No_Element then 3185 raise Constraint_Error with "I cursor has no element"; 3186 end if; 3187 3188 if Checks and then I.Container /= Container'Unrestricted_Access then 3189 raise Program_Error with "I cursor not in container"; 3190 end if; 3191 3192 if Checks and then Is_Root (I) then 3193 raise Program_Error with "I cursor designates root"; 3194 end if; 3195 3196 if I = J then -- make this test sooner??? 3197 return; 3198 end if; 3199 3200 if Checks and then J = No_Element then 3201 raise Constraint_Error with "J cursor has no element"; 3202 end if; 3203 3204 if Checks and then J.Container /= Container'Unrestricted_Access then 3205 raise Program_Error with "J cursor not in container"; 3206 end if; 3207 3208 if Checks and then Is_Root (J) then 3209 raise Program_Error with "J cursor designates root"; 3210 end if; 3211 3212 TE_Check (Container.TC); 3213 3214 declare 3215 EE : Element_Array renames Container.Elements; 3216 EI : constant Element_Type := EE (I.Node); 3217 3218 begin 3219 EE (I.Node) := EE (J.Node); 3220 EE (J.Node) := EI; 3221 end; 3222 end Swap; 3223 3224 -------------------- 3225 -- Update_Element -- 3226 -------------------- 3227 3228 procedure Update_Element 3229 (Container : in out Tree; 3230 Position : Cursor; 3231 Process : not null access procedure (Element : in out Element_Type)) 3232 is 3233 begin 3234 if Checks and then Position = No_Element then 3235 raise Constraint_Error with "Position cursor has no element"; 3236 end if; 3237 3238 if Checks and then Position.Container /= Container'Unrestricted_Access 3239 then 3240 raise Program_Error with "Position cursor not in container"; 3241 end if; 3242 3243 if Checks and then Is_Root (Position) then 3244 raise Program_Error with "Position cursor designates root"; 3245 end if; 3246 3247 declare 3248 T : Tree renames Position.Container.all'Unrestricted_Access.all; 3249 Lock : With_Lock (T.TC'Unrestricted_Access); 3250 begin 3251 Process (Element => T.Elements (Position.Node)); 3252 end; 3253 end Update_Element; 3254 3255 ----------- 3256 -- Write -- 3257 ----------- 3258 3259 procedure Write 3260 (Stream : not null access Root_Stream_Type'Class; 3261 Container : Tree) 3262 is 3263 procedure Write_Children (Subtree : Count_Type); 3264 procedure Write_Subtree (Subtree : Count_Type); 3265 3266 -------------------- 3267 -- Write_Children -- 3268 -------------------- 3269 3270 procedure Write_Children (Subtree : Count_Type) is 3271 CC : Children_Type renames Container.Nodes (Subtree).Children; 3272 C : Count_Type'Base; 3273 3274 begin 3275 Count_Type'Write (Stream, Child_Count (Container, Subtree)); 3276 3277 C := CC.First; 3278 while C > 0 loop 3279 Write_Subtree (C); 3280 C := Container.Nodes (C).Next; 3281 end loop; 3282 end Write_Children; 3283 3284 ------------------- 3285 -- Write_Subtree -- 3286 ------------------- 3287 3288 procedure Write_Subtree (Subtree : Count_Type) is 3289 begin 3290 Element_Type'Write (Stream, Container.Elements (Subtree)); 3291 Write_Children (Subtree); 3292 end Write_Subtree; 3293 3294 -- Start of processing for Write 3295 3296 begin 3297 Count_Type'Write (Stream, Container.Count); 3298 3299 if Container.Count = 0 then 3300 return; 3301 end if; 3302 3303 Write_Children (Root_Node (Container)); 3304 end Write; 3305 3306 procedure Write 3307 (Stream : not null access Root_Stream_Type'Class; 3308 Position : Cursor) 3309 is 3310 begin 3311 raise Program_Error with "attempt to write tree cursor to stream"; 3312 end Write; 3313 3314 procedure Write 3315 (Stream : not null access Root_Stream_Type'Class; 3316 Item : Reference_Type) 3317 is 3318 begin 3319 raise Program_Error with "attempt to stream reference"; 3320 end Write; 3321 3322 procedure Write 3323 (Stream : not null access Root_Stream_Type'Class; 3324 Item : Constant_Reference_Type) 3325 is 3326 begin 3327 raise Program_Error with "attempt to stream reference"; 3328 end Write; 3329 3330end Ada.Containers.Bounded_Multiway_Trees; 3331