1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . M U L T I W A Y _ T R E E S --
9 -- Copyright (C) 2004-2015, Free Software Foundation, Inc. --
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. --
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. --
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/>. --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada
.Unchecked_Conversion
;
31 with Ada
.Unchecked_Deallocation
;
33 with System
; use type System
.Address
;
35 package body Ada
.Containers
.Multiway_Trees
is
37 pragma Warnings
(Off
, "variable ""Busy*"" is not referenced");
38 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
39 -- See comment in Ada.Containers.Helpers
45 type Root_Iterator
is abstract new Limited_Controlled
and
46 Tree_Iterator_Interfaces
.Forward_Iterator
with
48 Container
: Tree_Access
;
49 Subtree
: Tree_Node_Access
;
52 overriding
procedure Finalize
(Object
: in out Root_Iterator
);
54 -----------------------
55 -- Subtree_Iterator --
56 -----------------------
58 -- ??? these headers are a bit odd, but for sure they do not substitute
59 -- for documenting things, what *is* a Subtree_Iterator?
61 type Subtree_Iterator
is new Root_Iterator
with null record;
63 overriding
function First
(Object
: Subtree_Iterator
) return Cursor
;
65 overriding
function Next
66 (Object
: Subtree_Iterator
;
67 Position
: Cursor
) return Cursor
;
73 type Child_Iterator
is new Root_Iterator
and
74 Tree_Iterator_Interfaces
.Reversible_Iterator
with null record;
76 overriding
function First
(Object
: Child_Iterator
) return Cursor
;
78 overriding
function Next
79 (Object
: Child_Iterator
;
80 Position
: Cursor
) return Cursor
;
82 overriding
function Last
(Object
: Child_Iterator
) return Cursor
;
84 overriding
function Previous
85 (Object
: Child_Iterator
;
86 Position
: Cursor
) return Cursor
;
88 -----------------------
89 -- Local Subprograms --
90 -----------------------
92 function Root_Node
(Container
: Tree
) return Tree_Node_Access
;
94 procedure Deallocate_Node
is
95 new Ada
.Unchecked_Deallocation
(Tree_Node_Type
, Tree_Node_Access
);
97 procedure Deallocate_Children
98 (Subtree
: Tree_Node_Access
;
99 Count
: in out Count_Type
);
101 procedure Deallocate_Subtree
102 (Subtree
: in out Tree_Node_Access
;
103 Count
: in out Count_Type
);
105 function Equal_Children
106 (Left_Subtree
, Right_Subtree
: Tree_Node_Access
) return Boolean;
108 function Equal_Subtree
109 (Left_Subtree
, Right_Subtree
: Tree_Node_Access
) return Boolean;
111 procedure Iterate_Children
112 (Container
: Tree_Access
;
113 Subtree
: Tree_Node_Access
;
114 Process
: not null access procedure (Position
: Cursor
));
116 procedure Iterate_Subtree
117 (Container
: Tree_Access
;
118 Subtree
: Tree_Node_Access
;
119 Process
: not null access procedure (Position
: Cursor
));
121 procedure Copy_Children
122 (Source
: Children_Type
;
123 Parent
: Tree_Node_Access
;
124 Count
: in out Count_Type
);
126 procedure Copy_Subtree
127 (Source
: Tree_Node_Access
;
128 Parent
: Tree_Node_Access
;
129 Target
: out Tree_Node_Access
;
130 Count
: in out Count_Type
);
132 function Find_In_Children
133 (Subtree
: Tree_Node_Access
;
134 Item
: Element_Type
) return Tree_Node_Access
;
136 function Find_In_Subtree
137 (Subtree
: Tree_Node_Access
;
138 Item
: Element_Type
) return Tree_Node_Access
;
140 function Child_Count
(Children
: Children_Type
) return Count_Type
;
142 function Subtree_Node_Count
143 (Subtree
: Tree_Node_Access
) return Count_Type
;
145 function Is_Reachable
(From
, To
: Tree_Node_Access
) return Boolean;
147 procedure Remove_Subtree
(Subtree
: Tree_Node_Access
);
149 procedure Insert_Subtree_Node
150 (Subtree
: Tree_Node_Access
;
151 Parent
: Tree_Node_Access
;
152 Before
: Tree_Node_Access
);
154 procedure Insert_Subtree_List
155 (First
: Tree_Node_Access
;
156 Last
: Tree_Node_Access
;
157 Parent
: Tree_Node_Access
;
158 Before
: Tree_Node_Access
);
160 procedure Splice_Children
161 (Target_Parent
: Tree_Node_Access
;
162 Before
: Tree_Node_Access
;
163 Source_Parent
: Tree_Node_Access
);
169 function "=" (Left
, Right
: Tree
) return Boolean is
171 return Equal_Children
(Root_Node
(Left
), Root_Node
(Right
));
178 procedure Adjust
(Container
: in out Tree
) is
179 Source
: constant Children_Type
:= Container
.Root
.Children
;
180 Source_Count
: constant Count_Type
:= Container
.Count
;
181 Target_Count
: Count_Type
;
184 -- We first restore the target container to its default-initialized
185 -- state, before we attempt any allocation, to ensure that invariants
186 -- are preserved in the event that the allocation fails.
188 Container
.Root
.Children
:= Children_Type
'(others => null);
189 Zero_Counts (Container.TC);
190 Container.Count := 0;
192 -- Copy_Children returns a count of the number of nodes that it
193 -- allocates, but it works by incrementing the value that is passed
194 -- in. We must therefore initialize the count value before calling
199 -- Now we attempt the allocation of subtrees. The invariants are
200 -- satisfied even if the allocation fails.
202 Copy_Children (Source, Root_Node (Container), Target_Count);
203 pragma Assert (Target_Count = Source_Count);
205 Container.Count := Source_Count;
212 function Ancestor_Find
214 Item : Element_Type) return Cursor
216 R, N : Tree_Node_Access;
219 if Checks and then Position = No_Element then
220 raise Constraint_Error with "Position cursor has no element";
223 -- Commented-out pending official ruling from ARG. ???
225 -- if Position.Container /= Container'Unrestricted_Access then
226 -- raise Program_Error with "Position cursor not in container";
229 -- AI-0136 says to raise PE if Position equals the root node. This does
230 -- not seem correct, as this value is just the limiting condition of the
231 -- search. For now we omit this check, pending a ruling from the ARG.???
233 -- if Checks and then Is_Root (Position) then
234 -- raise Program_Error with "Position cursor designates root";
237 R := Root_Node (Position.Container.all);
240 if N.Element = Item then
241 return Cursor'(Position
.Container
, N
);
254 procedure Append_Child
255 (Container
: in out Tree
;
257 New_Item
: Element_Type
;
258 Count
: Count_Type
:= 1)
260 First
: Tree_Node_Access
;
261 Last
: Tree_Node_Access
;
264 if Checks
and then Parent
= No_Element
then
265 raise Constraint_Error
with "Parent cursor has no element";
268 if Checks
and then Parent
.Container
/= Container
'Unrestricted_Access then
269 raise Program_Error
with "Parent cursor not in container";
276 TC_Check
(Container
.TC
);
278 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
283 for J in Count_Type'(2) .. Count
loop
285 -- Reclaim other nodes if Storage_Error. ???
287 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
298 Parent => Parent.Node,
299 Before => null); -- null means "insert at end of list"
301 -- In order for operation Node_Count to complete in O(1) time, we cache
302 -- the count value. Here we increment the total count by the number of
303 -- nodes we just inserted.
305 Container.Count := Container.Count + Count;
312 procedure Assign (Target : in out Tree; Source : Tree) is
313 Source_Count : constant Count_Type := Source.Count;
314 Target_Count : Count_Type;
317 if Target'Address = Source'Address then
321 Target.Clear; -- checks busy bit
323 -- Copy_Children returns the number of nodes that it allocates, but it
324 -- does this by incrementing the count value passed in, so we must
325 -- initialize the count before calling Copy_Children.
329 -- Note that Copy_Children inserts the newly-allocated children into
330 -- their parent list only after the allocation of all the children has
331 -- succeeded. This preserves invariants even if the allocation fails.
333 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
334 pragma Assert (Target_Count = Source_Count);
336 Target.Count := Source_Count;
343 function Child_Count (Parent : Cursor) return Count_Type is
345 return (if Parent = No_Element
346 then 0 else Child_Count (Parent.Node.Children));
349 function Child_Count (Children : Children_Type) return Count_Type is
351 Node : Tree_Node_Access;
355 Node := Children.First;
356 while Node /= null loop
357 Result := Result + 1;
368 function Child_Depth (Parent, Child : Cursor) return Count_Type is
370 N : Tree_Node_Access;
373 if Checks and then Parent = No_Element then
374 raise Constraint_Error with "Parent cursor has no element";
377 if Checks and then Child = No_Element then
378 raise Constraint_Error with "Child cursor has no element";
381 if Checks and then Parent.Container /= Child.Container then
382 raise Program_Error with "Parent and Child in different containers";
387 while N /= Parent.Node loop
388 Result := Result + 1;
391 if Checks and then N = null then
392 raise Program_Error with "Parent is not ancestor of Child";
403 procedure Clear (Container : in out Tree) is
404 Container_Count, Children_Count : Count_Type;
407 TC_Check (Container.TC);
409 -- We first set the container count to 0, in order to preserve
410 -- invariants in case the deallocation fails. (This works because
411 -- Deallocate_Children immediately removes the children from their
412 -- parent, and then does the actual deallocation.)
414 Container_Count := Container.Count;
415 Container.Count := 0;
417 -- Deallocate_Children returns the number of nodes that it deallocates,
418 -- but it does this by incrementing the count value that is passed in,
419 -- so we must first initialize the count return value before calling it.
423 -- See comment above. Deallocate_Children immediately removes the
424 -- children list from their parent node (here, the root of the tree),
425 -- and only after that does it attempt the actual deallocation. So even
426 -- if the deallocation fails, the representation invariants for the tree
429 Deallocate_Children (Root_Node (Container), Children_Count);
430 pragma Assert (Children_Count = Container_Count);
433 ------------------------
434 -- Constant_Reference --
435 ------------------------
437 function Constant_Reference
438 (Container : aliased Tree;
439 Position : Cursor) return Constant_Reference_Type
442 if Checks and then Position.Container = null then
443 raise Constraint_Error with
444 "Position cursor has no element";
447 if Checks and then Position.Container /= Container'Unrestricted_Access
449 raise Program_Error with
450 "Position cursor designates wrong container";
453 if Checks and then Position.Node = Root_Node (Container) then
454 raise Program_Error with "Position cursor designates root";
457 -- Implement Vet for multiway tree???
458 -- pragma Assert (Vet (Position),
459 -- "Position cursor in Constant_Reference is bad");
462 C : Tree renames Position.Container.all;
463 TC : constant Tamper_Counts_Access :=
464 C.TC'Unrestricted_Access;
466 return R : constant Constant_Reference_Type :=
467 (Element => Position.Node.Element'Access,
468 Control => (Controlled with TC))
473 end Constant_Reference;
481 Item : Element_Type) return Boolean
484 return Find (Container, Item) /= No_Element;
491 function Copy (Source : Tree) return Tree is
493 return Target : Tree do
495 (Source => Source.Root.Children,
496 Parent => Root_Node (Target),
497 Count => Target.Count);
499 pragma Assert (Target.Count = Source.Count);
507 procedure Copy_Children
508 (Source : Children_Type;
509 Parent : Tree_Node_Access;
510 Count : in out Count_Type)
512 pragma Assert (Parent /= null);
513 pragma Assert (Parent.Children.First = null);
514 pragma Assert (Parent.Children.Last = null);
517 C : Tree_Node_Access;
520 -- We special-case the first allocation, in order to establish the
521 -- representation invariants for type Children_Type.
537 -- The representation invariants for the Children_Type list have been
538 -- established, so we can now copy the remaining children of Source.
545 Target => CC.Last.Next,
548 CC.Last.Next.Prev := CC.Last;
549 CC.Last := CC.Last.Next;
554 -- Add the newly-allocated children to their parent list only after the
555 -- allocation has succeeded, so as to preserve invariants of the parent.
557 Parent.Children := CC;
564 procedure Copy_Subtree
565 (Target : in out Tree;
570 Target_Subtree : Tree_Node_Access;
571 Target_Count : Count_Type;
574 if Checks and then Parent = No_Element then
575 raise Constraint_Error with "Parent cursor has no element";
578 if Checks and then Parent.Container /= Target'Unrestricted_Access then
579 raise Program_Error with "Parent cursor not in container";
582 if Before /= No_Element then
583 if Checks and then Before.Container /= Target'Unrestricted_Access then
584 raise Program_Error with "Before cursor not in container";
587 if Checks and then Before.Node.Parent /= Parent.Node then
588 raise Constraint_Error with "Before cursor not child of Parent";
592 if Source = No_Element then
596 if Checks and then Is_Root (Source) then
597 raise Constraint_Error with "Source cursor designates root";
600 -- Copy_Subtree returns a count of the number of nodes that it
601 -- allocates, but it works by incrementing the value that is passed
602 -- in. We must therefore initialize the count value before calling
608 (Source => Source.Node,
609 Parent => Parent.Node,
610 Target => Target_Subtree,
611 Count => Target_Count);
613 pragma Assert (Target_Subtree /= null);
614 pragma Assert (Target_Subtree.Parent = Parent.Node);
615 pragma Assert (Target_Count >= 1);
618 (Subtree => Target_Subtree,
619 Parent => Parent.Node,
620 Before => Before.Node);
622 -- In order for operation Node_Count to complete in O(1) time, we cache
623 -- the count value. Here we increment the total count by the number of
624 -- nodes we just inserted.
626 Target.Count := Target.Count + Target_Count;
629 procedure Copy_Subtree
630 (Source : Tree_Node_Access;
631 Parent : Tree_Node_Access;
632 Target : out Tree_Node_Access;
633 Count : in out Count_Type)
636 Target := new Tree_Node_Type'(Element
=> Source
.Element
,
643 (Source
=> Source
.Children
,
648 -------------------------
649 -- Deallocate_Children --
650 -------------------------
652 procedure Deallocate_Children
653 (Subtree
: Tree_Node_Access
;
654 Count
: in out Count_Type
)
656 pragma Assert
(Subtree
/= null);
658 CC
: Children_Type
:= Subtree
.Children
;
659 C
: Tree_Node_Access
;
662 -- We immediately remove the children from their parent, in order to
663 -- preserve invariants in case the deallocation fails.
665 Subtree
.Children
:= Children_Type
'(others => null);
667 while CC.First /= null loop
671 Deallocate_Subtree (C, Count);
673 end Deallocate_Children;
675 ------------------------
676 -- Deallocate_Subtree --
677 ------------------------
679 procedure Deallocate_Subtree
680 (Subtree : in out Tree_Node_Access;
681 Count : in out Count_Type)
684 Deallocate_Children (Subtree, Count);
685 Deallocate_Node (Subtree);
687 end Deallocate_Subtree;
689 ---------------------
690 -- Delete_Children --
691 ---------------------
693 procedure Delete_Children
694 (Container : in out Tree;
700 if Checks and then Parent = No_Element then
701 raise Constraint_Error with "Parent cursor has no element";
704 if Checks and then Parent.Container /= Container'Unrestricted_Access then
705 raise Program_Error with "Parent cursor not in container";
708 TC_Check (Container.TC);
710 -- Deallocate_Children returns a count of the number of nodes that it
711 -- deallocates, but it works by incrementing the value that is passed
712 -- in. We must therefore initialize the count value before calling
713 -- Deallocate_Children.
717 Deallocate_Children (Parent.Node, Count);
718 pragma Assert (Count <= Container.Count);
720 Container.Count := Container.Count - Count;
727 procedure Delete_Leaf
728 (Container : in out Tree;
729 Position : in out Cursor)
731 X : Tree_Node_Access;
734 if Checks and then Position = No_Element then
735 raise Constraint_Error with "Position cursor has no element";
738 if Checks and then Position.Container /= Container'Unrestricted_Access
740 raise Program_Error with "Position cursor not in container";
743 if Checks and then Is_Root (Position) then
744 raise Program_Error with "Position cursor designates root";
747 if Checks and then not Is_Leaf (Position) then
748 raise Constraint_Error with "Position cursor does not designate leaf";
751 TC_Check (Container.TC);
754 Position := No_Element;
756 -- Restore represention invariants before attempting the actual
760 Container.Count := Container.Count - 1;
762 -- It is now safe to attempt the deallocation. This leaf node has been
763 -- disassociated from the tree, so even if the deallocation fails,
764 -- representation invariants will remain satisfied.
773 procedure Delete_Subtree
774 (Container : in out Tree;
775 Position : in out Cursor)
777 X : Tree_Node_Access;
781 if Checks and then Position = No_Element then
782 raise Constraint_Error with "Position cursor has no element";
785 if Checks and then Position.Container /= Container'Unrestricted_Access
787 raise Program_Error with "Position cursor not in container";
790 if Checks and then Is_Root (Position) then
791 raise Program_Error with "Position cursor designates root";
794 TC_Check (Container.TC);
797 Position := No_Element;
799 -- Here is one case where a deallocation failure can result in the
800 -- violation of a representation invariant. We disassociate the subtree
801 -- from the tree now, but we only decrement the total node count after
802 -- we attempt the deallocation. However, if the deallocation fails, the
803 -- total node count will not get decremented.
805 -- One way around this dilemma is to count the nodes in the subtree
806 -- before attempt to delete the subtree, but that is an O(n) operation,
807 -- so it does not seem worth it.
809 -- Perhaps this is much ado about nothing, since the only way
810 -- deallocation can fail is if Controlled Finalization fails: this
811 -- propagates Program_Error so all bets are off anyway. ???
815 -- Deallocate_Subtree returns a count of the number of nodes that it
816 -- deallocates, but it works by incrementing the value that is passed
817 -- in. We must therefore initialize the count value before calling
818 -- Deallocate_Subtree.
822 Deallocate_Subtree (X, Count);
823 pragma Assert (Count <= Container.Count);
825 -- See comments above. We would prefer to do this sooner, but there's no
826 -- way to satisfy that goal without a potentially severe execution
829 Container.Count := Container.Count - Count;
836 function Depth (Position : Cursor) return Count_Type is
838 N : Tree_Node_Access;
845 Result := Result + 1;
855 function Element (Position : Cursor) return Element_Type is
857 if Checks and then Position.Container = null then
858 raise Constraint_Error with "Position cursor has no element";
861 if Checks and then Position.Node = Root_Node (Position.Container.all)
863 raise Program_Error with "Position cursor designates root";
866 return Position.Node.Element;
873 function Equal_Children
874 (Left_Subtree : Tree_Node_Access;
875 Right_Subtree : Tree_Node_Access) return Boolean
877 Left_Children : Children_Type renames Left_Subtree.Children;
878 Right_Children : Children_Type renames Right_Subtree.Children;
880 L, R : Tree_Node_Access;
883 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
887 L := Left_Children.First;
888 R := Right_Children.First;
890 if not Equal_Subtree (L, R) then
905 function Equal_Subtree
906 (Left_Position : Cursor;
907 Right_Position : Cursor) return Boolean
910 if Checks and then Left_Position = No_Element then
911 raise Constraint_Error with "Left cursor has no element";
914 if Checks and then Right_Position = No_Element then
915 raise Constraint_Error with "Right cursor has no element";
918 if Left_Position = Right_Position then
922 if Is_Root (Left_Position) then
923 if not Is_Root (Right_Position) then
927 return Equal_Children (Left_Position.Node, Right_Position.Node);
930 if Is_Root (Right_Position) then
934 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
937 function Equal_Subtree
938 (Left_Subtree : Tree_Node_Access;
939 Right_Subtree : Tree_Node_Access) return Boolean
942 if Left_Subtree.Element /= Right_Subtree.Element then
946 return Equal_Children (Left_Subtree, Right_Subtree);
953 procedure Finalize (Object : in out Root_Iterator) is
955 Unbusy (Object.Container.TC);
964 Item : Element_Type) return Cursor
966 N : constant Tree_Node_Access :=
967 Find_In_Children (Root_Node (Container), Item);
972 return Cursor'(Container
'Unrestricted_Access, N
);
980 overriding
function First
(Object
: Subtree_Iterator
) return Cursor
is
982 if Object
.Subtree
= Root_Node
(Object
.Container
.all) then
983 return First_Child
(Root
(Object
.Container
.all));
985 return Cursor
'(Object.Container, Object.Subtree);
989 overriding function First (Object : Child_Iterator) return Cursor is
991 return First_Child (Cursor'(Object
.Container
, Object
.Subtree
));
998 function First_Child
(Parent
: Cursor
) return Cursor
is
999 Node
: Tree_Node_Access
;
1002 if Checks
and then Parent
= No_Element
then
1003 raise Constraint_Error
with "Parent cursor has no element";
1006 Node
:= Parent
.Node
.Children
.First
;
1012 return Cursor
'(Parent.Container, Node);
1015 -------------------------
1016 -- First_Child_Element --
1017 -------------------------
1019 function First_Child_Element (Parent : Cursor) return Element_Type is
1021 return Element (First_Child (Parent));
1022 end First_Child_Element;
1024 ----------------------
1025 -- Find_In_Children --
1026 ----------------------
1028 function Find_In_Children
1029 (Subtree : Tree_Node_Access;
1030 Item : Element_Type) return Tree_Node_Access
1032 N, Result : Tree_Node_Access;
1035 N := Subtree.Children.First;
1036 while N /= null loop
1037 Result := Find_In_Subtree (N, Item);
1039 if Result /= null then
1047 end Find_In_Children;
1049 ---------------------
1050 -- Find_In_Subtree --
1051 ---------------------
1053 function Find_In_Subtree
1055 Item : Element_Type) return Cursor
1057 Result : Tree_Node_Access;
1060 if Checks and then Position = No_Element then
1061 raise Constraint_Error with "Position cursor has no element";
1064 -- Commented out pending official ruling by ARG. ???
1066 -- if Checks and then
1067 -- Position.Container /= Container'Unrestricted_Access
1069 -- raise Program_Error with "Position cursor not in container";
1073 (if Is_Root (Position)
1074 then Find_In_Children (Position.Node, Item)
1075 else Find_In_Subtree (Position.Node, Item));
1077 if Result = null then
1081 return Cursor'(Position
.Container
, Result
);
1082 end Find_In_Subtree
;
1084 function Find_In_Subtree
1085 (Subtree
: Tree_Node_Access
;
1086 Item
: Element_Type
) return Tree_Node_Access
1089 if Subtree
.Element
= Item
then
1093 return Find_In_Children
(Subtree
, Item
);
1094 end Find_In_Subtree
;
1096 ------------------------
1097 -- Get_Element_Access --
1098 ------------------------
1100 function Get_Element_Access
1101 (Position
: Cursor
) return not null Element_Access
is
1103 return Position
.Node
.Element
'Access;
1104 end Get_Element_Access
;
1110 function Has_Element
(Position
: Cursor
) return Boolean is
1112 return (if Position
= No_Element
then False
1113 else Position
.Node
.Parent
/= null);
1120 procedure Insert_Child
1121 (Container
: in out Tree
;
1124 New_Item
: Element_Type
;
1125 Count
: Count_Type
:= 1)
1128 pragma Unreferenced
(Position
);
1131 Insert_Child
(Container
, Parent
, Before
, New_Item
, Position
, Count
);
1134 procedure Insert_Child
1135 (Container
: in out Tree
;
1138 New_Item
: Element_Type
;
1139 Position
: out Cursor
;
1140 Count
: Count_Type
:= 1)
1142 First
: Tree_Node_Access
;
1143 Last
: Tree_Node_Access
;
1146 if Checks
and then Parent
= No_Element
then
1147 raise Constraint_Error
with "Parent cursor has no element";
1150 if Checks
and then Parent
.Container
/= Container
'Unrestricted_Access then
1151 raise Program_Error
with "Parent cursor not in container";
1154 if Before
/= No_Element
then
1155 if Checks
and then Before
.Container
/= Container
'Unrestricted_Access
1157 raise Program_Error
with "Before cursor not in container";
1160 if Checks
and then Before
.Node
.Parent
/= Parent
.Node
then
1161 raise Constraint_Error
with "Parent cursor not parent of Before";
1166 Position
:= No_Element
; -- Need ruling from ARG ???
1170 TC_Check
(Container
.TC
);
1172 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
1173 Element => New_Item,
1177 for J in Count_Type'(2) .. Count
loop
1179 -- Reclaim other nodes if Storage_Error. ???
1181 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
1183 Element => New_Item,
1192 Parent => Parent.Node,
1193 Before => Before.Node);
1195 -- In order for operation Node_Count to complete in O(1) time, we cache
1196 -- the count value. Here we increment the total count by the number of
1197 -- nodes we just inserted.
1199 Container.Count := Container.Count + Count;
1201 Position := Cursor'(Parent
.Container
, First
);
1204 procedure Insert_Child
1205 (Container
: in out Tree
;
1208 Position
: out Cursor
;
1209 Count
: Count_Type
:= 1)
1211 First
: Tree_Node_Access
;
1212 Last
: Tree_Node_Access
;
1215 if Checks
and then Parent
= No_Element
then
1216 raise Constraint_Error
with "Parent cursor has no element";
1219 if Checks
and then Parent
.Container
/= Container
'Unrestricted_Access then
1220 raise Program_Error
with "Parent cursor not in container";
1223 if Before
/= No_Element
then
1224 if Checks
and then Before
.Container
/= Container
'Unrestricted_Access
1226 raise Program_Error
with "Before cursor not in container";
1229 if Checks
and then Before
.Node
.Parent
/= Parent
.Node
then
1230 raise Constraint_Error
with "Parent cursor not parent of Before";
1235 Position
:= No_Element
; -- Need ruling from ARG ???
1239 TC_Check
(Container
.TC
);
1241 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
1246 for J in Count_Type'(2) .. Count
loop
1248 -- Reclaim other nodes if Storage_Error. ???
1250 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
1261 Parent => Parent.Node,
1262 Before => Before.Node);
1264 -- In order for operation Node_Count to complete in O(1) time, we cache
1265 -- the count value. Here we increment the total count by the number of
1266 -- nodes we just inserted.
1268 Container.Count := Container.Count + Count;
1270 Position := Cursor'(Parent
.Container
, First
);
1273 -------------------------
1274 -- Insert_Subtree_List --
1275 -------------------------
1277 procedure Insert_Subtree_List
1278 (First
: Tree_Node_Access
;
1279 Last
: Tree_Node_Access
;
1280 Parent
: Tree_Node_Access
;
1281 Before
: Tree_Node_Access
)
1283 pragma Assert
(Parent
/= null);
1284 C
: Children_Type
renames Parent
.Children
;
1287 -- This is a simple utility operation to insert a list of nodes (from
1288 -- First..Last) as children of Parent. The Before node specifies where
1289 -- the new children should be inserted relative to the existing
1292 if First
= null then
1293 pragma Assert
(Last
= null);
1297 pragma Assert
(Last
/= null);
1298 pragma Assert
(Before
= null or else Before
.Parent
= Parent
);
1300 if C
.First
= null then
1302 C
.First
.Prev
:= null;
1304 C
.Last
.Next
:= null;
1306 elsif Before
= null then -- means "insert after existing nodes"
1307 C
.Last
.Next
:= First
;
1308 First
.Prev
:= C
.Last
;
1310 C
.Last
.Next
:= null;
1312 elsif Before
= C
.First
then
1313 Last
.Next
:= C
.First
;
1314 C
.First
.Prev
:= Last
;
1316 C
.First
.Prev
:= null;
1319 Before
.Prev
.Next
:= First
;
1320 First
.Prev
:= Before
.Prev
;
1321 Last
.Next
:= Before
;
1322 Before
.Prev
:= Last
;
1324 end Insert_Subtree_List
;
1326 -------------------------
1327 -- Insert_Subtree_Node --
1328 -------------------------
1330 procedure Insert_Subtree_Node
1331 (Subtree
: Tree_Node_Access
;
1332 Parent
: Tree_Node_Access
;
1333 Before
: Tree_Node_Access
)
1336 -- This is a simple wrapper operation to insert a single child into the
1337 -- Parent's children list.
1344 end Insert_Subtree_Node
;
1350 function Is_Empty
(Container
: Tree
) return Boolean is
1352 return Container
.Root
.Children
.First
= null;
1359 function Is_Leaf
(Position
: Cursor
) return Boolean is
1361 return (if Position
= No_Element
then False
1362 else Position
.Node
.Children
.First
= null);
1369 function Is_Reachable
(From
, To
: Tree_Node_Access
) return Boolean is
1370 pragma Assert
(From
/= null);
1371 pragma Assert
(To
/= null);
1373 N
: Tree_Node_Access
;
1377 while N
/= null loop
1392 function Is_Root
(Position
: Cursor
) return Boolean is
1394 return (if Position
.Container
= null then False
1395 else Position
= Root
(Position
.Container
.all));
1404 Process
: not null access procedure (Position
: Cursor
))
1406 Busy
: With_Busy
(Container
.TC
'Unrestricted_Access);
1409 (Container
=> Container
'Unrestricted_Access,
1410 Subtree
=> Root_Node
(Container
),
1411 Process
=> Process
);
1414 function Iterate
(Container
: Tree
)
1415 return Tree_Iterator_Interfaces
.Forward_Iterator
'Class
1418 return Iterate_Subtree
(Root
(Container
));
1421 ----------------------
1422 -- Iterate_Children --
1423 ----------------------
1425 procedure Iterate_Children
1427 Process
: not null access procedure (Position
: Cursor
))
1429 C
: Tree_Node_Access
;
1430 Busy
: With_Busy
(Parent
.Container
.TC
'Unrestricted_Access);
1432 if Checks
and then Parent
= No_Element
then
1433 raise Constraint_Error
with "Parent cursor has no element";
1436 C
:= Parent
.Node
.Children
.First
;
1437 while C
/= null loop
1438 Process
(Position
=> Cursor
'(Parent.Container, Node => C));
1441 end Iterate_Children;
1443 procedure Iterate_Children
1444 (Container : Tree_Access;
1445 Subtree : Tree_Node_Access;
1446 Process : not null access procedure (Position : Cursor))
1448 Node : Tree_Node_Access;
1451 -- This is a helper function to recursively iterate over all the nodes
1452 -- in a subtree, in depth-first fashion. This particular helper just
1453 -- visits the children of this subtree, not the root of the subtree node
1454 -- itself. This is useful when starting from the ultimate root of the
1455 -- entire tree (see Iterate), as that root does not have an element.
1457 Node := Subtree.Children.First;
1458 while Node /= null loop
1459 Iterate_Subtree (Container, Node, Process);
1462 end Iterate_Children;
1464 function Iterate_Children
1467 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1469 C : constant Tree_Access := Container'Unrestricted_Access;
1471 if Checks and then Parent = No_Element then
1472 raise Constraint_Error with "Parent cursor has no element";
1475 if Checks and then Parent.Container /= C then
1476 raise Program_Error with "Parent cursor not in container";
1479 return It : constant Child_Iterator :=
1480 (Limited_Controlled with
1482 Subtree => Parent.Node)
1486 end Iterate_Children;
1488 ---------------------
1489 -- Iterate_Subtree --
1490 ---------------------
1492 function Iterate_Subtree
1494 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1496 C : constant Tree_Access := Position.Container;
1498 if Checks and then Position = No_Element then
1499 raise Constraint_Error with "Position cursor has no element";
1502 -- Implement Vet for multiway trees???
1503 -- pragma Assert (Vet (Position), "bad subtree cursor");
1505 return It : constant Subtree_Iterator :=
1506 (Limited_Controlled with
1508 Subtree => Position.Node)
1512 end Iterate_Subtree;
1514 procedure Iterate_Subtree
1516 Process : not null access procedure (Position : Cursor))
1518 Busy : With_Busy (Position.Container.TC'Unrestricted_Access);
1520 if Checks and then Position = No_Element then
1521 raise Constraint_Error with "Position cursor has no element";
1524 if Is_Root (Position) then
1525 Iterate_Children (Position.Container, Position.Node, Process);
1527 Iterate_Subtree (Position.Container, Position.Node, Process);
1529 end Iterate_Subtree;
1531 procedure Iterate_Subtree
1532 (Container : Tree_Access;
1533 Subtree : Tree_Node_Access;
1534 Process : not null access procedure (Position : Cursor))
1537 -- This is a helper function to recursively iterate over all the nodes
1538 -- in a subtree, in depth-first fashion. It first visits the root of the
1539 -- subtree, then visits its children.
1541 Process (Cursor'(Container
, Subtree
));
1542 Iterate_Children
(Container
, Subtree
, Process
);
1543 end Iterate_Subtree
;
1549 overriding
function Last
(Object
: Child_Iterator
) return Cursor
is
1551 return Last_Child
(Cursor
'(Object.Container, Object.Subtree));
1558 function Last_Child (Parent : Cursor) return Cursor is
1559 Node : Tree_Node_Access;
1562 if Checks and then Parent = No_Element then
1563 raise Constraint_Error with "Parent cursor has no element";
1566 Node := Parent.Node.Children.Last;
1572 return (Parent.Container, Node);
1575 ------------------------
1576 -- Last_Child_Element --
1577 ------------------------
1579 function Last_Child_Element (Parent : Cursor) return Element_Type is
1581 return Element (Last_Child (Parent));
1582 end Last_Child_Element;
1588 procedure Move (Target : in out Tree; Source : in out Tree) is
1589 Node : Tree_Node_Access;
1592 if Target'Address = Source'Address then
1596 TC_Check (Source.TC);
1598 Target.Clear; -- checks busy bit
1600 Target.Root.Children := Source.Root.Children;
1601 Source.Root.Children := Children_Type'(others => null);
1603 Node
:= Target
.Root
.Children
.First
;
1604 while Node
/= null loop
1605 Node
.Parent
:= Root_Node
(Target
);
1609 Target
.Count
:= Source
.Count
;
1618 (Object
: Subtree_Iterator
;
1619 Position
: Cursor
) return Cursor
1621 Node
: Tree_Node_Access
;
1624 if Position
.Container
= null then
1628 if Checks
and then Position
.Container
/= Object
.Container
then
1629 raise Program_Error
with
1630 "Position cursor of Next designates wrong tree";
1633 Node
:= Position
.Node
;
1635 if Node
.Children
.First
/= null then
1636 return Cursor
'(Object.Container, Node.Children.First);
1639 while Node /= Object.Subtree loop
1640 if Node.Next /= null then
1641 return Cursor'(Object
.Container
, Node
.Next
);
1644 Node
:= Node
.Parent
;
1651 (Object
: Child_Iterator
;
1652 Position
: Cursor
) return Cursor
1655 if Position
.Container
= null then
1659 if Checks
and then Position
.Container
/= Object
.Container
then
1660 raise Program_Error
with
1661 "Position cursor of Next designates wrong tree";
1664 return Next_Sibling
(Position
);
1671 function Next_Sibling
(Position
: Cursor
) return Cursor
is
1673 if Position
= No_Element
then
1677 if Position
.Node
.Next
= null then
1681 return Cursor
'(Position.Container, Position.Node.Next);
1684 procedure Next_Sibling (Position : in out Cursor) is
1686 Position := Next_Sibling (Position);
1693 function Node_Count (Container : Tree) return Count_Type is
1695 -- Container.Count is the number of nodes we have actually allocated. We
1696 -- cache the value specifically so this Node_Count operation can execute
1697 -- in O(1) time, which makes it behave similarly to how the Length
1698 -- selector function behaves for other containers.
1700 -- The cached node count value only describes the nodes we have
1701 -- allocated; the root node itself is not included in that count. The
1702 -- Node_Count operation returns a value that includes the root node
1703 -- (because the RM says so), so we must add 1 to our cached value.
1705 return 1 + Container.Count;
1712 function Parent (Position : Cursor) return Cursor is
1714 if Position = No_Element then
1718 if Position.Node.Parent = null then
1722 return Cursor'(Position
.Container
, Position
.Node
.Parent
);
1729 procedure Prepend_Child
1730 (Container
: in out Tree
;
1732 New_Item
: Element_Type
;
1733 Count
: Count_Type
:= 1)
1735 First
, Last
: Tree_Node_Access
;
1738 if Checks
and then Parent
= No_Element
then
1739 raise Constraint_Error
with "Parent cursor has no element";
1742 if Checks
and then Parent
.Container
/= Container
'Unrestricted_Access then
1743 raise Program_Error
with "Parent cursor not in container";
1750 TC_Check
(Container
.TC
);
1752 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
1753 Element => New_Item,
1758 for J in Count_Type'(2) .. Count
loop
1760 -- Reclaim other nodes if Storage_Error???
1762 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
1764 Element => New_Item,
1773 Parent => Parent.Node,
1774 Before => Parent.Node.Children.First);
1776 -- In order for operation Node_Count to complete in O(1) time, we cache
1777 -- the count value. Here we increment the total count by the number of
1778 -- nodes we just inserted.
1780 Container.Count := Container.Count + Count;
1787 overriding function Previous
1788 (Object : Child_Iterator;
1789 Position : Cursor) return Cursor
1792 if Position.Container = null then
1796 if Checks and then Position.Container /= Object.Container then
1797 raise Program_Error with
1798 "Position cursor of Previous designates wrong tree";
1801 return Previous_Sibling (Position);
1804 ----------------------
1805 -- Previous_Sibling --
1806 ----------------------
1808 function Previous_Sibling (Position : Cursor) return Cursor is
1811 (if Position = No_Element then No_Element
1812 elsif Position.Node.Prev = null then No_Element
1813 else Cursor'(Position
.Container
, Position
.Node
.Prev
));
1814 end Previous_Sibling
;
1816 procedure Previous_Sibling
(Position
: in out Cursor
) is
1818 Position
:= Previous_Sibling
(Position
);
1819 end Previous_Sibling
;
1821 ----------------------
1822 -- Pseudo_Reference --
1823 ----------------------
1825 function Pseudo_Reference
1826 (Container
: aliased Tree
'Class) return Reference_Control_Type
1828 TC
: constant Tamper_Counts_Access
:= Container
.TC
'Unrestricted_Access;
1830 return R
: constant Reference_Control_Type
:= (Controlled
with TC
) do
1833 end Pseudo_Reference
;
1839 procedure Query_Element
1841 Process
: not null access procedure (Element
: Element_Type
))
1843 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
1844 Lock
: With_Lock
(T
.TC
'Unrestricted_Access);
1846 if Checks
and then Position
= No_Element
then
1847 raise Constraint_Error
with "Position cursor has no element";
1850 if Checks
and then Is_Root
(Position
) then
1851 raise Program_Error
with "Position cursor designates root";
1854 Process
(Position
.Node
.Element
);
1862 (Stream
: not null access Root_Stream_Type
'Class;
1863 Container
: out Tree
)
1865 procedure Read_Children
(Subtree
: Tree_Node_Access
);
1867 function Read_Subtree
1868 (Parent
: Tree_Node_Access
) return Tree_Node_Access
;
1870 Total_Count
: Count_Type
'Base;
1871 -- Value read from the stream that says how many elements follow
1873 Read_Count
: Count_Type
'Base;
1874 -- Actual number of elements read from the stream
1880 procedure Read_Children
(Subtree
: Tree_Node_Access
) is
1881 pragma Assert
(Subtree
/= null);
1882 pragma Assert
(Subtree
.Children
.First
= null);
1883 pragma Assert
(Subtree
.Children
.Last
= null);
1885 Count
: Count_Type
'Base;
1886 -- Number of child subtrees
1891 Count_Type
'Read (Stream
, Count
);
1893 if Checks
and then Count
< 0 then
1894 raise Program_Error
with "attempt to read from corrupt stream";
1901 C
.First
:= Read_Subtree
(Parent
=> Subtree
);
1904 for J
in Count_Type
'(2) .. Count loop
1905 C.Last.Next := Read_Subtree (Parent => Subtree);
1906 C.Last.Next.Prev := C.Last;
1907 C.Last := C.Last.Next;
1910 -- Now that the allocation and reads have completed successfully, it
1911 -- is safe to link the children to their parent.
1913 Subtree.Children := C;
1920 function Read_Subtree
1921 (Parent : Tree_Node_Access) return Tree_Node_Access
1923 Subtree : constant Tree_Node_Access :=
1926 Element
=> Element_Type
'Input (Stream
),
1930 Read_Count
:= Read_Count
+ 1;
1932 Read_Children
(Subtree
);
1937 -- Start of processing for Read
1940 Container
.Clear
; -- checks busy bit
1942 Count_Type
'Read (Stream
, Total_Count
);
1944 if Checks
and then Total_Count
< 0 then
1945 raise Program_Error
with "attempt to read from corrupt stream";
1948 if Total_Count
= 0 then
1954 Read_Children
(Root_Node
(Container
));
1956 if Checks
and then Read_Count
/= Total_Count
then
1957 raise Program_Error
with "attempt to read from corrupt stream";
1960 Container
.Count
:= Total_Count
;
1964 (Stream
: not null access Root_Stream_Type
'Class;
1965 Position
: out Cursor
)
1968 raise Program_Error
with "attempt to read tree cursor from stream";
1972 (Stream
: not null access Root_Stream_Type
'Class;
1973 Item
: out Reference_Type
)
1976 raise Program_Error
with "attempt to stream reference";
1980 (Stream
: not null access Root_Stream_Type
'Class;
1981 Item
: out Constant_Reference_Type
)
1984 raise Program_Error
with "attempt to stream reference";
1992 (Container
: aliased in out Tree
;
1993 Position
: Cursor
) return Reference_Type
1996 if Checks
and then Position
.Container
= null then
1997 raise Constraint_Error
with
1998 "Position cursor has no element";
2001 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2003 raise Program_Error
with
2004 "Position cursor designates wrong container";
2007 if Checks
and then Position
.Node
= Root_Node
(Container
) then
2008 raise Program_Error
with "Position cursor designates root";
2011 -- Implement Vet for multiway tree???
2012 -- pragma Assert (Vet (Position),
2013 -- "Position cursor in Constant_Reference is bad");
2016 C
: Tree
renames Position
.Container
.all;
2017 TC
: constant Tamper_Counts_Access
:=
2018 C
.TC
'Unrestricted_Access;
2020 return R
: constant Reference_Type
:=
2021 (Element
=> Position
.Node
.Element
'Access,
2022 Control
=> (Controlled
with TC
))
2029 --------------------
2030 -- Remove_Subtree --
2031 --------------------
2033 procedure Remove_Subtree
(Subtree
: Tree_Node_Access
) is
2034 C
: Children_Type
renames Subtree
.Parent
.Children
;
2037 -- This is a utility operation to remove a subtree node from its
2038 -- parent's list of children.
2040 if C
.First
= Subtree
then
2041 pragma Assert
(Subtree
.Prev
= null);
2043 if C
.Last
= Subtree
then
2044 pragma Assert
(Subtree
.Next
= null);
2049 C
.First
:= Subtree
.Next
;
2050 C
.First
.Prev
:= null;
2053 elsif C
.Last
= Subtree
then
2054 pragma Assert
(Subtree
.Next
= null);
2055 C
.Last
:= Subtree
.Prev
;
2056 C
.Last
.Next
:= null;
2059 Subtree
.Prev
.Next
:= Subtree
.Next
;
2060 Subtree
.Next
.Prev
:= Subtree
.Prev
;
2064 ----------------------
2065 -- Replace_Element --
2066 ----------------------
2068 procedure Replace_Element
2069 (Container
: in out Tree
;
2071 New_Item
: Element_Type
)
2074 if Checks
and then Position
= No_Element
then
2075 raise Constraint_Error
with "Position cursor has no element";
2078 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2080 raise Program_Error
with "Position cursor not in container";
2083 if Checks
and then Is_Root
(Position
) then
2084 raise Program_Error
with "Position cursor designates root";
2087 TE_Check
(Container
.TC
);
2089 Position
.Node
.Element
:= New_Item
;
2090 end Replace_Element
;
2092 ------------------------------
2093 -- Reverse_Iterate_Children --
2094 ------------------------------
2096 procedure Reverse_Iterate_Children
2098 Process
: not null access procedure (Position
: Cursor
))
2100 C
: Tree_Node_Access
;
2101 Busy
: With_Busy
(Parent
.Container
.TC
'Unrestricted_Access);
2103 if Checks
and then Parent
= No_Element
then
2104 raise Constraint_Error
with "Parent cursor has no element";
2107 C
:= Parent
.Node
.Children
.Last
;
2108 while C
/= null loop
2109 Process
(Position
=> Cursor
'(Parent.Container, Node => C));
2112 end Reverse_Iterate_Children;
2118 function Root (Container : Tree) return Cursor is
2120 return (Container'Unrestricted_Access, Root_Node (Container));
2127 function Root_Node (Container : Tree) return Tree_Node_Access is
2128 type Root_Node_Access is access all Root_Node_Type;
2129 for Root_Node_Access'Storage_Size use 0;
2130 pragma Convention (C, Root_Node_Access);
2132 function To_Tree_Node_Access is
2133 new Ada.Unchecked_Conversion (Root_Node_Access, Tree_Node_Access);
2135 -- Start of processing for Root_Node
2138 -- This is a utility function for converting from an access type that
2139 -- designates the distinguished root node to an access type designating
2140 -- a non-root node. The representation of a root node does not have an
2141 -- element, but is otherwise identical to a non-root node, so the
2142 -- conversion itself is safe.
2144 return To_Tree_Node_Access (Container.Root'Unrestricted_Access);
2147 ---------------------
2148 -- Splice_Children --
2149 ---------------------
2151 procedure Splice_Children
2152 (Target : in out Tree;
2153 Target_Parent : Cursor;
2155 Source : in out Tree;
2156 Source_Parent : Cursor)
2161 if Checks and then Target_Parent = No_Element then
2162 raise Constraint_Error with "Target_Parent cursor has no element";
2165 if Checks and then Target_Parent.Container /= Target'Unrestricted_Access
2168 with "Target_Parent cursor not in Target container";
2171 if Before /= No_Element then
2172 if Checks and then Before.Container /= Target'Unrestricted_Access then
2174 with "Before cursor not in Target container";
2177 if Checks and then Before.Node.Parent /= Target_Parent.Node then
2178 raise Constraint_Error
2179 with "Before cursor not child of Target_Parent";
2183 if Checks and then Source_Parent = No_Element then
2184 raise Constraint_Error with "Source_Parent cursor has no element";
2187 if Checks and then Source_Parent.Container /= Source'Unrestricted_Access
2190 with "Source_Parent cursor not in Source container";
2193 if Target'Address = Source'Address then
2194 if Target_Parent = Source_Parent then
2198 TC_Check (Target.TC);
2200 if Checks and then Is_Reachable (From => Target_Parent.Node,
2201 To => Source_Parent.Node)
2203 raise Constraint_Error
2204 with "Source_Parent is ancestor of Target_Parent";
2208 (Target_Parent => Target_Parent.Node,
2209 Before => Before.Node,
2210 Source_Parent => Source_Parent.Node);
2215 TC_Check (Target.TC);
2216 TC_Check (Source.TC);
2218 -- We cache the count of the nodes we have allocated, so that operation
2219 -- Node_Count can execute in O(1) time. But that means we must count the
2220 -- nodes in the subtree we remove from Source and insert into Target, in
2221 -- order to keep the count accurate.
2223 Count := Subtree_Node_Count (Source_Parent.Node);
2224 pragma Assert (Count >= 1);
2226 Count := Count - 1; -- because Source_Parent node does not move
2229 (Target_Parent => Target_Parent.Node,
2230 Before => Before.Node,
2231 Source_Parent => Source_Parent.Node);
2233 Source.Count := Source.Count - Count;
2234 Target.Count := Target.Count + Count;
2235 end Splice_Children;
2237 procedure Splice_Children
2238 (Container : in out Tree;
2239 Target_Parent : Cursor;
2241 Source_Parent : Cursor)
2244 if Checks and then Target_Parent = No_Element then
2245 raise Constraint_Error with "Target_Parent cursor has no element";
2249 Target_Parent.Container /= Container'Unrestricted_Access
2252 with "Target_Parent cursor not in container";
2255 if Before /= No_Element then
2256 if Checks and then Before.Container /= Container'Unrestricted_Access
2259 with "Before cursor not in container";
2262 if Checks and then Before.Node.Parent /= Target_Parent.Node then
2263 raise Constraint_Error
2264 with "Before cursor not child of Target_Parent";
2268 if Checks and then Source_Parent = No_Element then
2269 raise Constraint_Error with "Source_Parent cursor has no element";
2273 Source_Parent.Container /= Container'Unrestricted_Access
2276 with "Source_Parent cursor not in container";
2279 if Target_Parent = Source_Parent then
2283 TC_Check (Container.TC);
2285 if Checks and then Is_Reachable (From => Target_Parent.Node,
2286 To => Source_Parent.Node)
2288 raise Constraint_Error
2289 with "Source_Parent is ancestor of Target_Parent";
2293 (Target_Parent => Target_Parent.Node,
2294 Before => Before.Node,
2295 Source_Parent => Source_Parent.Node);
2296 end Splice_Children;
2298 procedure Splice_Children
2299 (Target_Parent : Tree_Node_Access;
2300 Before : Tree_Node_Access;
2301 Source_Parent : Tree_Node_Access)
2303 CC : constant Children_Type := Source_Parent.Children;
2304 C : Tree_Node_Access;
2307 -- This is a utility operation to remove the children from
2308 -- Source parent and insert them into Target parent.
2310 Source_Parent.Children := Children_Type'(others => null);
2312 -- Fix up the Parent pointers of each child to designate
2313 -- its new Target parent.
2316 while C
/= null loop
2317 C
.Parent
:= Target_Parent
;
2324 Parent
=> Target_Parent
,
2326 end Splice_Children
;
2328 --------------------
2329 -- Splice_Subtree --
2330 --------------------
2332 procedure Splice_Subtree
2333 (Target
: in out Tree
;
2336 Source
: in out Tree
;
2337 Position
: in out Cursor
)
2339 Subtree_Count
: Count_Type
;
2342 if Checks
and then Parent
= No_Element
then
2343 raise Constraint_Error
with "Parent cursor has no element";
2346 if Checks
and then Parent
.Container
/= Target
'Unrestricted_Access then
2347 raise Program_Error
with "Parent cursor not in Target container";
2350 if Before
/= No_Element
then
2351 if Checks
and then Before
.Container
/= Target
'Unrestricted_Access then
2352 raise Program_Error
with "Before cursor not in Target container";
2355 if Checks
and then Before
.Node
.Parent
/= Parent
.Node
then
2356 raise Constraint_Error
with "Before cursor not child of Parent";
2360 if Checks
and then Position
= No_Element
then
2361 raise Constraint_Error
with "Position cursor has no element";
2364 if Checks
and then Position
.Container
/= Source
'Unrestricted_Access then
2365 raise Program_Error
with "Position cursor not in Source container";
2368 if Checks
and then Is_Root
(Position
) then
2369 raise Program_Error
with "Position cursor designates root";
2372 if Target
'Address = Source
'Address then
2373 if Position
.Node
.Parent
= Parent
.Node
then
2374 if Position
.Node
= Before
.Node
then
2378 if Position
.Node
.Next
= Before
.Node
then
2383 TC_Check
(Target
.TC
);
2386 Is_Reachable
(From
=> Parent
.Node
, To
=> Position
.Node
)
2388 raise Constraint_Error
with "Position is ancestor of Parent";
2391 Remove_Subtree
(Position
.Node
);
2393 Position
.Node
.Parent
:= Parent
.Node
;
2394 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2399 TC_Check
(Target
.TC
);
2400 TC_Check
(Source
.TC
);
2402 -- This is an unfortunate feature of this API: we must count the nodes
2403 -- in the subtree that we remove from the source tree, which is an O(n)
2404 -- operation. It would have been better if the Tree container did not
2405 -- have a Node_Count selector; a user that wants the number of nodes in
2406 -- the tree could simply call Subtree_Node_Count, with the understanding
2407 -- that such an operation is O(n).
2409 -- Of course, we could choose to implement the Node_Count selector as an
2410 -- O(n) operation, which would turn this splice operation into an O(1)
2413 Subtree_Count
:= Subtree_Node_Count
(Position
.Node
);
2414 pragma Assert
(Subtree_Count
<= Source
.Count
);
2416 Remove_Subtree
(Position
.Node
);
2417 Source
.Count
:= Source
.Count
- Subtree_Count
;
2419 Position
.Node
.Parent
:= Parent
.Node
;
2420 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2422 Target
.Count
:= Target
.Count
+ Subtree_Count
;
2424 Position
.Container
:= Target
'Unrestricted_Access;
2427 procedure Splice_Subtree
2428 (Container
: in out Tree
;
2434 if Checks
and then Parent
= No_Element
then
2435 raise Constraint_Error
with "Parent cursor has no element";
2438 if Checks
and then Parent
.Container
/= Container
'Unrestricted_Access then
2439 raise Program_Error
with "Parent cursor not in container";
2442 if Before
/= No_Element
then
2443 if Checks
and then Before
.Container
/= Container
'Unrestricted_Access
2445 raise Program_Error
with "Before cursor not in container";
2448 if Checks
and then Before
.Node
.Parent
/= Parent
.Node
then
2449 raise Constraint_Error
with "Before cursor not child of Parent";
2453 if Checks
and then Position
= No_Element
then
2454 raise Constraint_Error
with "Position cursor has no element";
2457 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2459 raise Program_Error
with "Position cursor not in container";
2462 if Checks
and then Is_Root
(Position
) then
2464 -- Should this be PE instead? Need ARG confirmation. ???
2466 raise Constraint_Error
with "Position cursor designates root";
2469 if Position
.Node
.Parent
= Parent
.Node
then
2470 if Position
.Node
= Before
.Node
then
2474 if Position
.Node
.Next
= Before
.Node
then
2479 TC_Check
(Container
.TC
);
2482 Is_Reachable
(From
=> Parent
.Node
, To
=> Position
.Node
)
2484 raise Constraint_Error
with "Position is ancestor of Parent";
2487 Remove_Subtree
(Position
.Node
);
2489 Position
.Node
.Parent
:= Parent
.Node
;
2490 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2493 ------------------------
2494 -- Subtree_Node_Count --
2495 ------------------------
2497 function Subtree_Node_Count
(Position
: Cursor
) return Count_Type
is
2499 if Position
= No_Element
then
2503 return Subtree_Node_Count
(Position
.Node
);
2504 end Subtree_Node_Count
;
2506 function Subtree_Node_Count
2507 (Subtree
: Tree_Node_Access
) return Count_Type
2509 Result
: Count_Type
;
2510 Node
: Tree_Node_Access
;
2514 Node
:= Subtree
.Children
.First
;
2515 while Node
/= null loop
2516 Result
:= Result
+ Subtree_Node_Count
(Node
);
2521 end Subtree_Node_Count
;
2528 (Container
: in out Tree
;
2532 if Checks
and then I
= No_Element
then
2533 raise Constraint_Error
with "I cursor has no element";
2536 if Checks
and then I
.Container
/= Container
'Unrestricted_Access then
2537 raise Program_Error
with "I cursor not in container";
2540 if Checks
and then Is_Root
(I
) then
2541 raise Program_Error
with "I cursor designates root";
2544 if I
= J
then -- make this test sooner???
2548 if Checks
and then J
= No_Element
then
2549 raise Constraint_Error
with "J cursor has no element";
2552 if Checks
and then J
.Container
/= Container
'Unrestricted_Access then
2553 raise Program_Error
with "J cursor not in container";
2556 if Checks
and then Is_Root
(J
) then
2557 raise Program_Error
with "J cursor designates root";
2560 TE_Check
(Container
.TC
);
2563 EI
: constant Element_Type
:= I
.Node
.Element
;
2566 I
.Node
.Element
:= J
.Node
.Element
;
2567 J
.Node
.Element
:= EI
;
2571 --------------------
2572 -- Update_Element --
2573 --------------------
2575 procedure Update_Element
2576 (Container
: in out Tree
;
2578 Process
: not null access procedure (Element
: in out Element_Type
))
2580 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
2581 Lock
: With_Lock
(T
.TC
'Unrestricted_Access);
2583 if Checks
and then Position
= No_Element
then
2584 raise Constraint_Error
with "Position cursor has no element";
2587 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2589 raise Program_Error
with "Position cursor not in container";
2592 if Checks
and then Is_Root
(Position
) then
2593 raise Program_Error
with "Position cursor designates root";
2596 Process
(Position
.Node
.Element
);
2604 (Stream
: not null access Root_Stream_Type
'Class;
2607 procedure Write_Children
(Subtree
: Tree_Node_Access
);
2608 procedure Write_Subtree
(Subtree
: Tree_Node_Access
);
2610 --------------------
2611 -- Write_Children --
2612 --------------------
2614 procedure Write_Children
(Subtree
: Tree_Node_Access
) is
2615 CC
: Children_Type
renames Subtree
.Children
;
2616 C
: Tree_Node_Access
;
2619 Count_Type
'Write (Stream
, Child_Count
(CC
));
2622 while C
/= null loop
2632 procedure Write_Subtree
(Subtree
: Tree_Node_Access
) is
2634 Element_Type
'Output (Stream
, Subtree
.Element
);
2635 Write_Children
(Subtree
);
2638 -- Start of processing for Write
2641 Count_Type
'Write (Stream
, Container
.Count
);
2643 if Container
.Count
= 0 then
2647 Write_Children
(Root_Node
(Container
));
2651 (Stream
: not null access Root_Stream_Type
'Class;
2655 raise Program_Error
with "attempt to write tree cursor to stream";
2659 (Stream
: not null access Root_Stream_Type
'Class;
2660 Item
: Reference_Type
)
2663 raise Program_Error
with "attempt to stream reference";
2667 (Stream
: not null access Root_Stream_Type
'Class;
2668 Item
: Constant_Reference_Type
)
2671 raise Program_Error
with "attempt to stream reference";
2674 end Ada
.Containers
.Multiway_Trees
;