1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.INDEFINITE_MULTIWAY_TREES --
9 -- Copyright (C) 2004-2017, 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_Deallocation
;
32 with System
; use type System
.Address
;
34 package body Ada
.Containers
.Indefinite_Multiway_Trees
is
36 pragma Warnings
(Off
, "variable ""Busy*"" is not referenced");
37 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
38 -- See comment in Ada.Containers.Helpers
44 type Root_Iterator
is abstract new Limited_Controlled
and
45 Tree_Iterator_Interfaces
.Forward_Iterator
with
47 Container
: Tree_Access
;
48 Subtree
: Tree_Node_Access
;
51 overriding
procedure Finalize
(Object
: in out Root_Iterator
);
53 -----------------------
54 -- Subtree_Iterator --
55 -----------------------
57 type Subtree_Iterator
is new Root_Iterator
with null record;
59 overriding
function First
(Object
: Subtree_Iterator
) return Cursor
;
61 overriding
function Next
62 (Object
: Subtree_Iterator
;
63 Position
: Cursor
) return Cursor
;
69 type Child_Iterator
is new Root_Iterator
and
70 Tree_Iterator_Interfaces
.Reversible_Iterator
with null record;
72 overriding
function First
(Object
: Child_Iterator
) return Cursor
;
74 overriding
function Next
75 (Object
: Child_Iterator
;
76 Position
: Cursor
) return Cursor
;
78 overriding
function Last
(Object
: Child_Iterator
) return Cursor
;
80 overriding
function Previous
81 (Object
: Child_Iterator
;
82 Position
: Cursor
) return Cursor
;
84 -----------------------
85 -- Local Subprograms --
86 -----------------------
88 function Root_Node
(Container
: Tree
) return Tree_Node_Access
;
90 procedure Free_Element
is
91 new Ada
.Unchecked_Deallocation
(Element_Type
, Element_Access
);
93 procedure Deallocate_Node
(X
: in out Tree_Node_Access
);
95 procedure Deallocate_Children
96 (Subtree
: Tree_Node_Access
;
97 Count
: in out Count_Type
);
99 procedure Deallocate_Subtree
100 (Subtree
: in out Tree_Node_Access
;
101 Count
: in out Count_Type
);
103 function Equal_Children
104 (Left_Subtree
, Right_Subtree
: Tree_Node_Access
) return Boolean;
106 function Equal_Subtree
107 (Left_Subtree
, Right_Subtree
: Tree_Node_Access
) return Boolean;
109 procedure Iterate_Children
110 (Container
: Tree_Access
;
111 Subtree
: Tree_Node_Access
;
112 Process
: not null access procedure (Position
: Cursor
));
114 procedure Iterate_Subtree
115 (Container
: Tree_Access
;
116 Subtree
: Tree_Node_Access
;
117 Process
: not null access procedure (Position
: Cursor
));
119 procedure Copy_Children
120 (Source
: Children_Type
;
121 Parent
: Tree_Node_Access
;
122 Count
: in out Count_Type
);
124 procedure Copy_Subtree
125 (Source
: Tree_Node_Access
;
126 Parent
: Tree_Node_Access
;
127 Target
: out Tree_Node_Access
;
128 Count
: in out Count_Type
);
130 function Find_In_Children
131 (Subtree
: Tree_Node_Access
;
132 Item
: Element_Type
) return Tree_Node_Access
;
134 function Find_In_Subtree
135 (Subtree
: Tree_Node_Access
;
136 Item
: Element_Type
) return Tree_Node_Access
;
138 function Child_Count
(Children
: Children_Type
) return Count_Type
;
140 function Subtree_Node_Count
141 (Subtree
: Tree_Node_Access
) return Count_Type
;
143 function Is_Reachable
(From
, To
: Tree_Node_Access
) return Boolean;
145 procedure Remove_Subtree
(Subtree
: Tree_Node_Access
);
147 procedure Insert_Subtree_Node
148 (Subtree
: Tree_Node_Access
;
149 Parent
: Tree_Node_Access
;
150 Before
: Tree_Node_Access
);
152 procedure Insert_Subtree_List
153 (First
: Tree_Node_Access
;
154 Last
: Tree_Node_Access
;
155 Parent
: Tree_Node_Access
;
156 Before
: Tree_Node_Access
);
158 procedure Splice_Children
159 (Target_Parent
: Tree_Node_Access
;
160 Before
: Tree_Node_Access
;
161 Source_Parent
: Tree_Node_Access
);
167 function "=" (Left
, Right
: Tree
) return Boolean is
169 return Equal_Children
(Root_Node
(Left
), Root_Node
(Right
));
176 procedure Adjust
(Container
: in out Tree
) is
177 Source
: constant Children_Type
:= Container
.Root
.Children
;
178 Source_Count
: constant Count_Type
:= Container
.Count
;
179 Target_Count
: Count_Type
;
182 -- We first restore the target container to its default-initialized
183 -- state, before we attempt any allocation, to ensure that invariants
184 -- are preserved in the event that the allocation fails.
186 Container
.Root
.Children
:= Children_Type
'(others => null);
187 Zero_Counts (Container.TC);
188 Container.Count := 0;
190 -- Copy_Children returns a count of the number of nodes that it
191 -- allocates, but it works by incrementing the value that is passed in.
192 -- We must therefore initialize the count value before calling
197 -- Now we attempt the allocation of subtrees. The invariants are
198 -- satisfied even if the allocation fails.
200 Copy_Children (Source, Root_Node (Container), Target_Count);
201 pragma Assert (Target_Count = Source_Count);
203 Container.Count := Source_Count;
210 function Ancestor_Find
212 Item : Element_Type) return Cursor
214 R, N : Tree_Node_Access;
217 if Checks and then Position = No_Element then
218 raise Constraint_Error with "Position cursor has no element";
221 -- Commented-out pending ARG ruling. ???
223 -- if Checks and then
224 -- Position.Container /= Container'Unrestricted_Access
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.all = 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
, Last
: Tree_Node_Access
;
261 Element
: Element_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
);
279 -- The element allocator may need an accessibility check in the case
280 -- the actual type is class-wide or has access discriminants (see
281 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
282 -- allocator in the loop below, because the one in this block would
283 -- have failed already.
285 pragma Unsuppress
(Accessibility_Check
);
288 Element
:= new Element_Type
'(New_Item);
291 First := new Tree_Node_Type'(Parent
=> Parent
.Node
,
297 for J
in Count_Type
'(2) .. Count loop
299 -- Reclaim other nodes if Storage_Error. ???
301 Element := new Element_Type'(New_Item
);
302 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
313 Parent => Parent.Node,
314 Before => null); -- null means "insert at end of list"
316 -- In order for operation Node_Count to complete in O(1) time, we cache
317 -- the count value. Here we increment the total count by the number of
318 -- nodes we just inserted.
320 Container.Count := Container.Count + Count;
327 procedure Assign (Target : in out Tree; Source : Tree) is
328 Source_Count : constant Count_Type := Source.Count;
329 Target_Count : Count_Type;
332 if Target'Address = Source'Address then
336 Target.Clear; -- checks busy bit
338 -- Copy_Children returns the number of nodes that it allocates, but it
339 -- does this by incrementing the count value passed in, so we must
340 -- initialize the count before calling Copy_Children.
344 -- Note that Copy_Children inserts the newly-allocated children into
345 -- their parent list only after the allocation of all the children has
346 -- succeeded. This preserves invariants even if the allocation fails.
348 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
349 pragma Assert (Target_Count = Source_Count);
351 Target.Count := Source_Count;
358 function Child_Count (Parent : Cursor) return Count_Type is
360 if Parent = No_Element then
363 return Child_Count (Parent.Node.Children);
367 function Child_Count (Children : Children_Type) return Count_Type is
369 Node : Tree_Node_Access;
373 Node := Children.First;
374 while Node /= null loop
375 Result := Result + 1;
386 function Child_Depth (Parent, Child : Cursor) return Count_Type is
388 N : Tree_Node_Access;
391 if Checks and then Parent = No_Element then
392 raise Constraint_Error with "Parent cursor has no element";
395 if Checks and then Child = No_Element then
396 raise Constraint_Error with "Child cursor has no element";
399 if Checks and then Parent.Container /= Child.Container then
400 raise Program_Error with "Parent and Child in different containers";
405 while N /= Parent.Node loop
406 Result := Result + 1;
409 if Checks and then N = null then
410 raise Program_Error with "Parent is not ancestor of Child";
421 procedure Clear (Container : in out Tree) is
422 Container_Count : Count_Type;
423 Children_Count : Count_Type;
426 TC_Check (Container.TC);
428 -- We first set the container count to 0, in order to preserve
429 -- invariants in case the deallocation fails. (This works because
430 -- Deallocate_Children immediately removes the children from their
431 -- parent, and then does the actual deallocation.)
433 Container_Count := Container.Count;
434 Container.Count := 0;
436 -- Deallocate_Children returns the number of nodes that it deallocates,
437 -- but it does this by incrementing the count value that is passed in,
438 -- so we must first initialize the count return value before calling it.
442 -- See comment above. Deallocate_Children immediately removes the
443 -- children list from their parent node (here, the root of the tree),
444 -- and only after that does it attempt the actual deallocation. So even
445 -- if the deallocation fails, the representation invariants
447 Deallocate_Children (Root_Node (Container), Children_Count);
448 pragma Assert (Children_Count = Container_Count);
451 ------------------------
452 -- Constant_Reference --
453 ------------------------
455 function Constant_Reference
456 (Container : aliased Tree;
457 Position : Cursor) return Constant_Reference_Type
460 if Checks and then Position.Container = null then
461 raise Constraint_Error with
462 "Position cursor has no element";
465 if Checks and then Position.Container /= Container'Unrestricted_Access
467 raise Program_Error with
468 "Position cursor designates wrong container";
471 if Checks and then Position.Node = Root_Node (Container) then
472 raise Program_Error with "Position cursor designates root";
475 if Checks and then Position.Node.Element = null then
476 raise Program_Error with "Node has no element";
479 -- Implement Vet for multiway tree???
480 -- pragma Assert (Vet (Position),
481 -- "Position cursor in Constant_Reference is bad");
484 TC : constant Tamper_Counts_Access :=
485 Container.TC'Unrestricted_Access;
487 return R : constant Constant_Reference_Type :=
488 (Element => Position.Node.Element.all'Access,
489 Control => (Controlled with TC))
494 end Constant_Reference;
502 Item : Element_Type) return Boolean
505 return Find (Container, Item) /= No_Element;
512 function Copy (Source : Tree) return Tree is
514 return Target : Tree do
516 (Source => Source.Root.Children,
517 Parent => Root_Node (Target),
518 Count => Target.Count);
520 pragma Assert (Target.Count = Source.Count);
528 procedure Copy_Children
529 (Source : Children_Type;
530 Parent : Tree_Node_Access;
531 Count : in out Count_Type)
533 pragma Assert (Parent /= null);
534 pragma Assert (Parent.Children.First = null);
535 pragma Assert (Parent.Children.Last = null);
538 C : Tree_Node_Access;
541 -- We special-case the first allocation, in order to establish the
542 -- representation invariants for type Children_Type.
558 -- The representation invariants for the Children_Type list have been
559 -- established, so we can now copy the remaining children of Source.
566 Target => CC.Last.Next,
569 CC.Last.Next.Prev := CC.Last;
570 CC.Last := CC.Last.Next;
575 -- We add the newly-allocated children to their parent list only after
576 -- the allocation has succeeded, in order to preserve invariants of the
579 Parent.Children := CC;
586 procedure Copy_Subtree
587 (Target : in out Tree;
592 Target_Subtree : Tree_Node_Access;
593 Target_Count : Count_Type;
596 if Checks and then Parent = No_Element then
597 raise Constraint_Error with "Parent cursor has no element";
600 if Checks and then Parent.Container /= Target'Unrestricted_Access then
601 raise Program_Error with "Parent cursor not in container";
604 if Before /= No_Element then
605 if Checks and then Before.Container /= Target'Unrestricted_Access then
606 raise Program_Error with "Before cursor not in container";
609 if Checks and then Before.Node.Parent /= Parent.Node then
610 raise Constraint_Error with "Before cursor not child of Parent";
614 if Source = No_Element then
618 if Checks and then Is_Root (Source) then
619 raise Constraint_Error with "Source cursor designates root";
622 -- Copy_Subtree returns a count of the number of nodes that it
623 -- allocates, but it works by incrementing the value that is passed in.
624 -- We must therefore initialize the count value before calling
630 (Source => Source.Node,
631 Parent => Parent.Node,
632 Target => Target_Subtree,
633 Count => Target_Count);
635 pragma Assert (Target_Subtree /= null);
636 pragma Assert (Target_Subtree.Parent = Parent.Node);
637 pragma Assert (Target_Count >= 1);
640 (Subtree => Target_Subtree,
641 Parent => Parent.Node,
642 Before => Before.Node);
644 -- In order for operation Node_Count to complete in O(1) time, we cache
645 -- the count value. Here we increment the total count by the number of
646 -- nodes we just inserted.
648 Target.Count := Target.Count + Target_Count;
651 procedure Copy_Subtree
652 (Source : Tree_Node_Access;
653 Parent : Tree_Node_Access;
654 Target : out Tree_Node_Access;
655 Count : in out Count_Type)
657 E : constant Element_Access := new Element_Type'(Source
.Element
.all);
660 Target
:= new Tree_Node_Type
'(Element => E,
667 (Source => Source.Children,
672 -------------------------
673 -- Deallocate_Children --
674 -------------------------
676 procedure Deallocate_Children
677 (Subtree : Tree_Node_Access;
678 Count : in out Count_Type)
680 pragma Assert (Subtree /= null);
682 CC : Children_Type := Subtree.Children;
683 C : Tree_Node_Access;
686 -- We immediately remove the children from their parent, in order to
687 -- preserve invariants in case the deallocation fails.
689 Subtree.Children := Children_Type'(others => null);
691 while CC
.First
/= null loop
695 Deallocate_Subtree
(C
, Count
);
697 end Deallocate_Children
;
699 ---------------------
700 -- Deallocate_Node --
701 ---------------------
703 procedure Deallocate_Node
(X
: in out Tree_Node_Access
) is
704 procedure Free_Node
is
705 new Ada
.Unchecked_Deallocation
(Tree_Node_Type
, Tree_Node_Access
);
707 -- Start of processing for Deallocate_Node
711 Free_Element
(X
.Element
);
716 ------------------------
717 -- Deallocate_Subtree --
718 ------------------------
720 procedure Deallocate_Subtree
721 (Subtree
: in out Tree_Node_Access
;
722 Count
: in out Count_Type
)
725 Deallocate_Children
(Subtree
, Count
);
726 Deallocate_Node
(Subtree
);
728 end Deallocate_Subtree
;
730 ---------------------
731 -- Delete_Children --
732 ---------------------
734 procedure Delete_Children
735 (Container
: in out Tree
;
741 if Checks
and then Parent
= No_Element
then
742 raise Constraint_Error
with "Parent cursor has no element";
745 if Checks
and then Parent
.Container
/= Container
'Unrestricted_Access then
746 raise Program_Error
with "Parent cursor not in container";
749 TC_Check
(Container
.TC
);
751 -- Deallocate_Children returns a count of the number of nodes
752 -- that it deallocates, but it works by incrementing the
753 -- value that is passed in. We must therefore initialize
754 -- the count value before calling Deallocate_Children.
758 Deallocate_Children
(Parent
.Node
, Count
);
759 pragma Assert
(Count
<= Container
.Count
);
761 Container
.Count
:= Container
.Count
- Count
;
768 procedure Delete_Leaf
769 (Container
: in out Tree
;
770 Position
: in out Cursor
)
772 X
: Tree_Node_Access
;
775 if Checks
and then Position
= No_Element
then
776 raise Constraint_Error
with "Position cursor has no element";
779 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
781 raise Program_Error
with "Position cursor not in container";
784 if Checks
and then Is_Root
(Position
) then
785 raise Program_Error
with "Position cursor designates root";
788 if Checks
and then not Is_Leaf
(Position
) then
789 raise Constraint_Error
with "Position cursor does not designate leaf";
792 TC_Check
(Container
.TC
);
795 Position
:= No_Element
;
797 -- Restore represention invariants before attempting the actual
801 Container
.Count
:= Container
.Count
- 1;
803 -- It is now safe to attempt the deallocation. This leaf node has been
804 -- disassociated from the tree, so even if the deallocation fails,
805 -- representation invariants will remain satisfied.
814 procedure Delete_Subtree
815 (Container
: in out Tree
;
816 Position
: in out Cursor
)
818 X
: Tree_Node_Access
;
822 if Checks
and then Position
= No_Element
then
823 raise Constraint_Error
with "Position cursor has no element";
826 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
828 raise Program_Error
with "Position cursor not in container";
831 if Checks
and then Is_Root
(Position
) then
832 raise Program_Error
with "Position cursor designates root";
835 TC_Check
(Container
.TC
);
838 Position
:= No_Element
;
840 -- Here is one case where a deallocation failure can result in the
841 -- violation of a representation invariant. We disassociate the subtree
842 -- from the tree now, but we only decrement the total node count after
843 -- we attempt the deallocation. However, if the deallocation fails, the
844 -- total node count will not get decremented.
846 -- One way around this dilemma is to count the nodes in the subtree
847 -- before attempt to delete the subtree, but that is an O(n) operation,
848 -- so it does not seem worth it.
850 -- Perhaps this is much ado about nothing, since the only way
851 -- deallocation can fail is if Controlled Finalization fails: this
852 -- propagates Program_Error so all bets are off anyway. ???
856 -- Deallocate_Subtree returns a count of the number of nodes that it
857 -- deallocates, but it works by incrementing the value that is passed
858 -- in. We must therefore initialize the count value before calling
859 -- Deallocate_Subtree.
863 Deallocate_Subtree
(X
, Count
);
864 pragma Assert
(Count
<= Container
.Count
);
866 -- See comments above. We would prefer to do this sooner, but there's no
867 -- way to satisfy that goal without an potentially severe execution
870 Container
.Count
:= Container
.Count
- Count
;
877 function Depth
(Position
: Cursor
) return Count_Type
is
879 N
: Tree_Node_Access
;
886 Result
:= Result
+ 1;
896 function Element
(Position
: Cursor
) return Element_Type
is
898 if Checks
and then Position
.Container
= null then
899 raise Constraint_Error
with "Position cursor has no element";
902 if Checks
and then Position
.Node
= Root_Node
(Position
.Container
.all)
904 raise Program_Error
with "Position cursor designates root";
907 return Position
.Node
.Element
.all;
914 function Equal_Children
915 (Left_Subtree
: Tree_Node_Access
;
916 Right_Subtree
: Tree_Node_Access
) return Boolean
918 Left_Children
: Children_Type
renames Left_Subtree
.Children
;
919 Right_Children
: Children_Type
renames Right_Subtree
.Children
;
921 L
, R
: Tree_Node_Access
;
924 if Child_Count
(Left_Children
) /= Child_Count
(Right_Children
) then
928 L
:= Left_Children
.First
;
929 R
:= Right_Children
.First
;
931 if not Equal_Subtree
(L
, R
) then
946 function Equal_Subtree
947 (Left_Position
: Cursor
;
948 Right_Position
: Cursor
) return Boolean
951 if Checks
and then Left_Position
= No_Element
then
952 raise Constraint_Error
with "Left cursor has no element";
955 if Checks
and then Right_Position
= No_Element
then
956 raise Constraint_Error
with "Right cursor has no element";
959 if Left_Position
= Right_Position
then
963 if Is_Root
(Left_Position
) then
964 if not Is_Root
(Right_Position
) then
968 return Equal_Children
(Left_Position
.Node
, Right_Position
.Node
);
971 if Is_Root
(Right_Position
) then
975 return Equal_Subtree
(Left_Position
.Node
, Right_Position
.Node
);
978 function Equal_Subtree
979 (Left_Subtree
: Tree_Node_Access
;
980 Right_Subtree
: Tree_Node_Access
) return Boolean
983 if Left_Subtree
.Element
.all /= Right_Subtree
.Element
.all then
987 return Equal_Children
(Left_Subtree
, Right_Subtree
);
994 procedure Finalize
(Object
: in out Root_Iterator
) is
996 Unbusy
(Object
.Container
.TC
);
1005 Item
: Element_Type
) return Cursor
1007 N
: constant Tree_Node_Access
:=
1008 Find_In_Children
(Root_Node
(Container
), Item
);
1015 return Cursor
'(Container'Unrestricted_Access, N);
1022 overriding function First (Object : Subtree_Iterator) return Cursor is
1024 if Object.Subtree = Root_Node (Object.Container.all) then
1025 return First_Child (Root (Object.Container.all));
1027 return Cursor'(Object
.Container
, Object
.Subtree
);
1031 overriding
function First
(Object
: Child_Iterator
) return Cursor
is
1033 return First_Child
(Cursor
'(Object.Container, Object.Subtree));
1040 function First_Child (Parent : Cursor) return Cursor is
1041 Node : Tree_Node_Access;
1044 if Checks and then Parent = No_Element then
1045 raise Constraint_Error with "Parent cursor has no element";
1048 Node := Parent.Node.Children.First;
1054 return Cursor'(Parent
.Container
, Node
);
1057 -------------------------
1058 -- First_Child_Element --
1059 -------------------------
1061 function First_Child_Element
(Parent
: Cursor
) return Element_Type
is
1063 return Element
(First_Child
(Parent
));
1064 end First_Child_Element
;
1066 ----------------------
1067 -- Find_In_Children --
1068 ----------------------
1070 function Find_In_Children
1071 (Subtree
: Tree_Node_Access
;
1072 Item
: Element_Type
) return Tree_Node_Access
1074 N
, Result
: Tree_Node_Access
;
1077 N
:= Subtree
.Children
.First
;
1078 while N
/= null loop
1079 Result
:= Find_In_Subtree
(N
, Item
);
1081 if Result
/= null then
1089 end Find_In_Children
;
1091 ---------------------
1092 -- Find_In_Subtree --
1093 ---------------------
1095 function Find_In_Subtree
1097 Item
: Element_Type
) return Cursor
1099 Result
: Tree_Node_Access
;
1102 if Checks
and then Position
= No_Element
then
1103 raise Constraint_Error
with "Position cursor has no element";
1106 -- Commented-out pending ruling from ARG. ???
1108 -- if Checks and then
1109 -- Position.Container /= Container'Unrestricted_Access
1111 -- raise Program_Error with "Position cursor not in container";
1114 if Is_Root
(Position
) then
1115 Result
:= Find_In_Children
(Position
.Node
, Item
);
1118 Result
:= Find_In_Subtree
(Position
.Node
, Item
);
1121 if Result
= null then
1125 return Cursor
'(Position.Container, Result);
1126 end Find_In_Subtree;
1128 function Find_In_Subtree
1129 (Subtree : Tree_Node_Access;
1130 Item : Element_Type) return Tree_Node_Access
1133 if Subtree.Element.all = Item then
1137 return Find_In_Children (Subtree, Item);
1138 end Find_In_Subtree;
1140 ------------------------
1141 -- Get_Element_Access --
1142 ------------------------
1144 function Get_Element_Access
1145 (Position : Cursor) return not null Element_Access is
1147 return Position.Node.Element;
1148 end Get_Element_Access;
1154 function Has_Element (Position : Cursor) return Boolean is
1156 if Position = No_Element then
1160 return Position.Node.Parent /= null;
1167 procedure Insert_Child
1168 (Container : in out Tree;
1171 New_Item : Element_Type;
1172 Count : Count_Type := 1)
1175 pragma Unreferenced (Position);
1178 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1181 procedure Insert_Child
1182 (Container : in out Tree;
1185 New_Item : Element_Type;
1186 Position : out Cursor;
1187 Count : Count_Type := 1)
1189 First : Tree_Node_Access;
1190 Last : Tree_Node_Access;
1191 Element : Element_Access;
1194 if Checks and then Parent = No_Element then
1195 raise Constraint_Error with "Parent cursor has no element";
1198 if Checks and then Parent.Container /= Container'Unrestricted_Access then
1199 raise Program_Error with "Parent cursor not in container";
1202 if Before /= No_Element then
1203 if Checks and then Before.Container /= Container'Unrestricted_Access
1205 raise Program_Error with "Before cursor not in container";
1208 if Checks and then Before.Node.Parent /= Parent.Node then
1209 raise Constraint_Error with "Parent cursor not parent of Before";
1214 Position := No_Element; -- Need ruling from ARG ???
1218 TC_Check (Container.TC);
1221 -- The element allocator may need an accessibility check in the case
1222 -- the actual type is class-wide or has access discriminants (see
1223 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
1224 -- allocator in the loop below, because the one in this block would
1225 -- have failed already.
1227 pragma Unsuppress (Accessibility_Check);
1230 Element := new Element_Type'(New_Item
);
1233 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
1238 for J in Count_Type'(2) .. Count
loop
1240 -- Reclaim other nodes if Storage_Error. ???
1242 Element
:= new Element_Type
'(New_Item);
1243 Last.Next := new Tree_Node_Type'(Parent
=> Parent
.Node
,
1254 Parent
=> Parent
.Node
,
1255 Before
=> Before
.Node
);
1257 -- In order for operation Node_Count to complete in O(1) time, we cache
1258 -- the count value. Here we increment the total count by the number of
1259 -- nodes we just inserted.
1261 Container
.Count
:= Container
.Count
+ Count
;
1263 Position
:= Cursor
'(Parent.Container, First);
1266 -------------------------
1267 -- Insert_Subtree_List --
1268 -------------------------
1270 procedure Insert_Subtree_List
1271 (First : Tree_Node_Access;
1272 Last : Tree_Node_Access;
1273 Parent : Tree_Node_Access;
1274 Before : Tree_Node_Access)
1276 pragma Assert (Parent /= null);
1277 C : Children_Type renames Parent.Children;
1280 -- This is a simple utility operation to insert a list of nodes (from
1281 -- First..Last) as children of Parent. The Before node specifies where
1282 -- the new children should be inserted relative to the existing
1285 if First = null then
1286 pragma Assert (Last = null);
1290 pragma Assert (Last /= null);
1291 pragma Assert (Before = null or else Before.Parent = Parent);
1293 if C.First = null then
1295 C.First.Prev := null;
1297 C.Last.Next := null;
1299 elsif Before = null then -- means "insert after existing nodes"
1300 C.Last.Next := First;
1301 First.Prev := C.Last;
1303 C.Last.Next := null;
1305 elsif Before = C.First then
1306 Last.Next := C.First;
1307 C.First.Prev := Last;
1309 C.First.Prev := null;
1312 Before.Prev.Next := First;
1313 First.Prev := Before.Prev;
1314 Last.Next := Before;
1315 Before.Prev := Last;
1317 end Insert_Subtree_List;
1319 -------------------------
1320 -- Insert_Subtree_Node --
1321 -------------------------
1323 procedure Insert_Subtree_Node
1324 (Subtree : Tree_Node_Access;
1325 Parent : Tree_Node_Access;
1326 Before : Tree_Node_Access)
1329 -- This is a simple wrapper operation to insert a single child into the
1330 -- Parent's children list.
1337 end Insert_Subtree_Node;
1343 function Is_Empty (Container : Tree) return Boolean is
1345 return Container.Root.Children.First = null;
1352 function Is_Leaf (Position : Cursor) return Boolean is
1354 if Position = No_Element then
1358 return Position.Node.Children.First = null;
1365 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1366 pragma Assert (From /= null);
1367 pragma Assert (To /= null);
1369 N : Tree_Node_Access;
1373 while N /= null loop
1388 function Is_Root (Position : Cursor) return Boolean is
1390 if Position.Container = null then
1394 return Position = Root (Position.Container.all);
1403 Process : not null access procedure (Position : Cursor))
1405 Busy : With_Busy (Container.TC'Unrestricted_Access);
1408 (Container => Container'Unrestricted_Access,
1409 Subtree => Root_Node (Container),
1410 Process => Process);
1413 function Iterate (Container : Tree)
1414 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1417 return Iterate_Subtree (Root (Container));
1420 ----------------------
1421 -- Iterate_Children --
1422 ----------------------
1424 procedure Iterate_Children
1426 Process : not null access procedure (Position : Cursor))
1428 C : Tree_Node_Access;
1429 Busy : With_Busy (Parent.Container.TC'Unrestricted_Access);
1431 if Checks and then Parent = No_Element then
1432 raise Constraint_Error with "Parent cursor has no element";
1435 C := Parent.Node.Children.First;
1436 while C /= null loop
1437 Process (Position => Cursor'(Parent
.Container
, Node
=> C
));
1440 end Iterate_Children
;
1442 procedure Iterate_Children
1443 (Container
: Tree_Access
;
1444 Subtree
: Tree_Node_Access
;
1445 Process
: not null access procedure (Position
: Cursor
))
1447 Node
: Tree_Node_Access
;
1450 -- This is a helper function to recursively iterate over all the nodes
1451 -- in a subtree, in depth-first fashion. This particular helper just
1452 -- visits the children of this subtree, not the root of the subtree node
1453 -- itself. This is useful when starting from the ultimate root of the
1454 -- entire tree (see Iterate), as that root does not have an element.
1456 Node
:= Subtree
.Children
.First
;
1457 while Node
/= null loop
1458 Iterate_Subtree
(Container
, Node
, Process
);
1461 end Iterate_Children
;
1463 function Iterate_Children
1466 return Tree_Iterator_Interfaces
.Reversible_Iterator
'Class
1468 C
: constant Tree_Access
:= Container
'Unrestricted_Access;
1470 if Checks
and then Parent
= No_Element
then
1471 raise Constraint_Error
with "Parent cursor has no element";
1474 if Checks
and then Parent
.Container
/= C
then
1475 raise Program_Error
with "Parent cursor not in container";
1478 return It
: constant Child_Iterator
:=
1479 Child_Iterator
'(Limited_Controlled with
1481 Subtree => Parent.Node)
1485 end Iterate_Children;
1487 ---------------------
1488 -- Iterate_Subtree --
1489 ---------------------
1491 function Iterate_Subtree
1493 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1495 C : constant Tree_Access := Position.Container;
1497 if Checks and then Position = No_Element then
1498 raise Constraint_Error with "Position cursor has no element";
1501 -- Implement Vet for multiway trees???
1502 -- pragma Assert (Vet (Position), "bad subtree cursor");
1504 return It : constant Subtree_Iterator :=
1505 (Limited_Controlled with
1506 Container => Position.Container,
1507 Subtree => Position.Node)
1511 end Iterate_Subtree;
1513 procedure Iterate_Subtree
1515 Process : not null access procedure (Position : Cursor))
1517 Busy : With_Busy (Position.Container.TC'Unrestricted_Access);
1519 if Checks and then Position = No_Element then
1520 raise Constraint_Error with "Position cursor has no element";
1523 if Is_Root (Position) then
1524 Iterate_Children (Position.Container, Position.Node, Process);
1526 Iterate_Subtree (Position.Container, Position.Node, Process);
1528 end Iterate_Subtree;
1530 procedure Iterate_Subtree
1531 (Container : Tree_Access;
1532 Subtree : Tree_Node_Access;
1533 Process : not null access procedure (Position : Cursor))
1536 -- This is a helper function to recursively iterate over all the nodes
1537 -- in a subtree, in depth-first fashion. It first visits the root of the
1538 -- subtree, then visits its children.
1540 Process (Cursor'(Container
, Subtree
));
1541 Iterate_Children
(Container
, Subtree
, Process
);
1542 end Iterate_Subtree
;
1548 overriding
function Last
(Object
: Child_Iterator
) return Cursor
is
1550 return Last_Child
(Cursor
'(Object.Container, Object.Subtree));
1557 function Last_Child (Parent : Cursor) return Cursor is
1558 Node : Tree_Node_Access;
1561 if Checks and then Parent = No_Element then
1562 raise Constraint_Error with "Parent cursor has no element";
1565 Node := Parent.Node.Children.Last;
1571 return (Parent.Container, Node);
1574 ------------------------
1575 -- Last_Child_Element --
1576 ------------------------
1578 function Last_Child_Element (Parent : Cursor) return Element_Type is
1580 return Element (Last_Child (Parent));
1581 end Last_Child_Element;
1587 procedure Move (Target : in out Tree; Source : in out Tree) is
1588 Node : Tree_Node_Access;
1591 if Target'Address = Source'Address then
1595 TC_Check (Source.TC);
1597 Target.Clear; -- checks busy bit
1599 Target.Root.Children := Source.Root.Children;
1600 Source.Root.Children := Children_Type'(others => null);
1602 Node
:= Target
.Root
.Children
.First
;
1603 while Node
/= null loop
1604 Node
.Parent
:= Root_Node
(Target
);
1608 Target
.Count
:= Source
.Count
;
1617 (Object
: Subtree_Iterator
;
1618 Position
: Cursor
) return Cursor
1620 Node
: Tree_Node_Access
;
1623 if Position
.Container
= null then
1627 if Checks
and then Position
.Container
/= Object
.Container
then
1628 raise Program_Error
with
1629 "Position cursor of Next designates wrong tree";
1632 Node
:= Position
.Node
;
1634 if Node
.Children
.First
/= null then
1635 return Cursor
'(Object.Container, Node.Children.First);
1638 while Node /= Object.Subtree loop
1639 if Node.Next /= null then
1640 return Cursor'(Object
.Container
, Node
.Next
);
1643 Node
:= Node
.Parent
;
1650 (Object
: Child_Iterator
;
1651 Position
: Cursor
) return Cursor
1654 if Position
.Container
= null then
1658 if Checks
and then Position
.Container
/= Object
.Container
then
1659 raise Program_Error
with
1660 "Position cursor of Next designates wrong tree";
1663 return Next_Sibling
(Position
);
1670 function Next_Sibling
(Position
: Cursor
) return Cursor
is
1672 if Position
= No_Element
then
1676 if Position
.Node
.Next
= null then
1680 return Cursor
'(Position.Container, Position.Node.Next);
1683 procedure Next_Sibling (Position : in out Cursor) is
1685 Position := Next_Sibling (Position);
1692 function Node_Count (Container : Tree) return Count_Type is
1694 -- Container.Count is the number of nodes we have actually allocated. We
1695 -- cache the value specifically so this Node_Count operation can execute
1696 -- in O(1) time, which makes it behave similarly to how the Length
1697 -- selector function behaves for other containers.
1699 -- The cached node count value only describes the nodes we have
1700 -- allocated; the root node itself is not included in that count. The
1701 -- Node_Count operation returns a value that includes the root node
1702 -- (because the RM says so), so we must add 1 to our cached value.
1704 return 1 + Container.Count;
1711 function Parent (Position : Cursor) return Cursor is
1713 if Position = No_Element then
1717 if Position.Node.Parent = null then
1721 return Cursor'(Position
.Container
, Position
.Node
.Parent
);
1728 procedure Prepend_Child
1729 (Container
: in out Tree
;
1731 New_Item
: Element_Type
;
1732 Count
: Count_Type
:= 1)
1734 First
, Last
: Tree_Node_Access
;
1735 Element
: Element_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
);
1753 -- The element allocator may need an accessibility check in the case
1754 -- the actual type is class-wide or has access discriminants (see
1755 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
1756 -- allocator in the loop below, because the one in this block would
1757 -- have failed already.
1759 pragma Unsuppress
(Accessibility_Check
);
1762 Element
:= new Element_Type
'(New_Item);
1765 First := new Tree_Node_Type'(Parent
=> Parent
.Node
,
1771 for J
in Count_Type
'(2) .. Count loop
1773 -- Reclaim other nodes if Storage_Error. ???
1775 Element := new Element_Type'(New_Item
);
1776 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
1787 Parent => Parent.Node,
1788 Before => Parent.Node.Children.First);
1790 -- In order for operation Node_Count to complete in O(1) time, we cache
1791 -- the count value. Here we increment the total count by the number of
1792 -- nodes we just inserted.
1794 Container.Count := Container.Count + Count;
1801 overriding function Previous
1802 (Object : Child_Iterator;
1803 Position : Cursor) return Cursor
1806 if Position.Container = null then
1810 if Checks and then Position.Container /= Object.Container then
1811 raise Program_Error with
1812 "Position cursor of Previous designates wrong tree";
1815 return Previous_Sibling (Position);
1818 ----------------------
1819 -- Previous_Sibling --
1820 ----------------------
1822 function Previous_Sibling (Position : Cursor) return Cursor is
1824 if Position = No_Element then
1828 if Position.Node.Prev = null then
1832 return Cursor'(Position
.Container
, Position
.Node
.Prev
);
1833 end Previous_Sibling
;
1835 procedure Previous_Sibling
(Position
: in out Cursor
) is
1837 Position
:= Previous_Sibling
(Position
);
1838 end Previous_Sibling
;
1840 ----------------------
1841 -- Pseudo_Reference --
1842 ----------------------
1844 function Pseudo_Reference
1845 (Container
: aliased Tree
'Class) return Reference_Control_Type
1847 TC
: constant Tamper_Counts_Access
:= Container
.TC
'Unrestricted_Access;
1849 return R
: constant Reference_Control_Type
:= (Controlled
with TC
) do
1852 end Pseudo_Reference
;
1858 procedure Query_Element
1860 Process
: not null access procedure (Element
: Element_Type
))
1862 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
1863 Lock
: With_Lock
(T
.TC
'Unrestricted_Access);
1865 if Checks
and then Position
= No_Element
then
1866 raise Constraint_Error
with "Position cursor has no element";
1869 if Checks
and then Is_Root
(Position
) then
1870 raise Program_Error
with "Position cursor designates root";
1873 Process
(Position
.Node
.Element
.all);
1881 (Stream
: not null access Root_Stream_Type
'Class;
1882 Container
: out Tree
)
1884 procedure Read_Children
(Subtree
: Tree_Node_Access
);
1886 function Read_Subtree
1887 (Parent
: Tree_Node_Access
) return Tree_Node_Access
;
1889 Total_Count
: Count_Type
'Base;
1890 -- Value read from the stream that says how many elements follow
1892 Read_Count
: Count_Type
'Base;
1893 -- Actual number of elements read from the stream
1899 procedure Read_Children
(Subtree
: Tree_Node_Access
) is
1900 pragma Assert
(Subtree
/= null);
1901 pragma Assert
(Subtree
.Children
.First
= null);
1902 pragma Assert
(Subtree
.Children
.Last
= null);
1904 Count
: Count_Type
'Base;
1905 -- Number of child subtrees
1910 Count_Type
'Read (Stream
, Count
);
1912 if Checks
and then Count
< 0 then
1913 raise Program_Error
with "attempt to read from corrupt stream";
1920 C
.First
:= Read_Subtree
(Parent
=> Subtree
);
1923 for J
in Count_Type
'(2) .. Count loop
1924 C.Last.Next := Read_Subtree (Parent => Subtree);
1925 C.Last.Next.Prev := C.Last;
1926 C.Last := C.Last.Next;
1929 -- Now that the allocation and reads have completed successfully, it
1930 -- is safe to link the children to their parent.
1932 Subtree.Children := C;
1939 function Read_Subtree
1940 (Parent : Tree_Node_Access) return Tree_Node_Access
1942 Element : constant Element_Access :=
1943 new Element_Type'(Element_Type
'Input (Stream
));
1945 Subtree
: constant Tree_Node_Access
:=
1947 (Parent => Parent, Element => Element, others => <>);
1950 Read_Count := Read_Count + 1;
1952 Read_Children (Subtree);
1957 -- Start of processing for Read
1960 Container.Clear; -- checks busy bit
1962 Count_Type'Read (Stream, Total_Count);
1964 if Checks and then Total_Count < 0 then
1965 raise Program_Error with "attempt to read from corrupt stream";
1968 if Total_Count = 0 then
1974 Read_Children (Root_Node (Container));
1976 if Checks and then Read_Count /= Total_Count then
1977 raise Program_Error with "attempt to read from corrupt stream";
1980 Container.Count := Total_Count;
1984 (Stream : not null access Root_Stream_Type'Class;
1985 Position : out Cursor)
1988 raise Program_Error with "attempt to read tree cursor from stream";
1992 (Stream : not null access Root_Stream_Type'Class;
1993 Item : out Reference_Type)
1996 raise Program_Error with "attempt to stream reference";
2000 (Stream : not null access Root_Stream_Type'Class;
2001 Item : out Constant_Reference_Type)
2004 raise Program_Error with "attempt to stream reference";
2012 (Container : aliased in out Tree;
2013 Position : Cursor) return Reference_Type
2016 if Checks and then Position.Container = null then
2017 raise Constraint_Error with
2018 "Position cursor has no element";
2021 if Checks and then Position.Container /= Container'Unrestricted_Access
2023 raise Program_Error with
2024 "Position cursor designates wrong container";
2027 if Checks and then Position.Node = Root_Node (Container) then
2028 raise Program_Error with "Position cursor designates root";
2031 if Checks and then Position.Node.Element = null then
2032 raise Program_Error with "Node has no element";
2035 -- Implement Vet for multiway tree???
2036 -- pragma Assert (Vet (Position),
2037 -- "Position cursor in Constant_Reference is bad");
2040 TC : constant Tamper_Counts_Access :=
2041 Container.TC'Unrestricted_Access;
2043 return R : constant Reference_Type :=
2044 (Element => Position.Node.Element.all'Access,
2045 Control => (Controlled with TC))
2052 --------------------
2053 -- Remove_Subtree --
2054 --------------------
2056 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2057 C : Children_Type renames Subtree.Parent.Children;
2060 -- This is a utility operation to remove a subtree node from its
2061 -- parent's list of children.
2063 if C.First = Subtree then
2064 pragma Assert (Subtree.Prev = null);
2066 if C.Last = Subtree then
2067 pragma Assert (Subtree.Next = null);
2072 C.First := Subtree.Next;
2073 C.First.Prev := null;
2076 elsif C.Last = Subtree then
2077 pragma Assert (Subtree.Next = null);
2078 C.Last := Subtree.Prev;
2079 C.Last.Next := null;
2082 Subtree.Prev.Next := Subtree.Next;
2083 Subtree.Next.Prev := Subtree.Prev;
2087 ----------------------
2088 -- Replace_Element --
2089 ----------------------
2091 procedure Replace_Element
2092 (Container : in out Tree;
2094 New_Item : Element_Type)
2096 E, X : Element_Access;
2099 if Checks and then Position = No_Element then
2100 raise Constraint_Error with "Position cursor has no element";
2103 if Checks and then Position.Container /= Container'Unrestricted_Access
2105 raise Program_Error with "Position cursor not in container";
2108 if Checks and then Is_Root (Position) then
2109 raise Program_Error with "Position cursor designates root";
2112 TE_Check (Container.TC);
2115 -- The element allocator may need an accessibility check in the case
2116 -- the actual type is class-wide or has access discriminants (see
2117 -- RM 4.8(10.1) and AI12-0035).
2119 pragma Unsuppress (Accessibility_Check);
2122 E := new Element_Type'(New_Item
);
2125 X
:= Position
.Node
.Element
;
2126 Position
.Node
.Element
:= E
;
2129 end Replace_Element
;
2131 ------------------------------
2132 -- Reverse_Iterate_Children --
2133 ------------------------------
2135 procedure Reverse_Iterate_Children
2137 Process
: not null access procedure (Position
: Cursor
))
2139 C
: Tree_Node_Access
;
2140 Busy
: With_Busy
(Parent
.Container
.TC
'Unrestricted_Access);
2142 if Checks
and then Parent
= No_Element
then
2143 raise Constraint_Error
with "Parent cursor has no element";
2146 C
:= Parent
.Node
.Children
.Last
;
2147 while C
/= null loop
2148 Process
(Position
=> Cursor
'(Parent.Container, Node => C));
2151 end Reverse_Iterate_Children;
2157 function Root (Container : Tree) return Cursor is
2159 return (Container'Unrestricted_Access, Root_Node (Container));
2166 function Root_Node (Container : Tree) return Tree_Node_Access is
2168 return Container.Root'Unrestricted_Access;
2171 ---------------------
2172 -- Splice_Children --
2173 ---------------------
2175 procedure Splice_Children
2176 (Target : in out Tree;
2177 Target_Parent : Cursor;
2179 Source : in out Tree;
2180 Source_Parent : Cursor)
2185 if Checks and then Target_Parent = No_Element then
2186 raise Constraint_Error with "Target_Parent cursor has no element";
2189 if Checks and then Target_Parent.Container /= Target'Unrestricted_Access
2192 with "Target_Parent cursor not in Target container";
2195 if Before /= No_Element then
2196 if Checks and then Before.Container /= Target'Unrestricted_Access then
2198 with "Before cursor not in Target container";
2201 if Checks and then Before.Node.Parent /= Target_Parent.Node then
2202 raise Constraint_Error
2203 with "Before cursor not child of Target_Parent";
2207 if Checks and then Source_Parent = No_Element then
2208 raise Constraint_Error with "Source_Parent cursor has no element";
2211 if Checks and then Source_Parent.Container /= Source'Unrestricted_Access
2214 with "Source_Parent cursor not in Source container";
2217 if Target'Address = Source'Address then
2218 if Target_Parent = Source_Parent then
2222 TC_Check (Target.TC);
2224 if Checks and then Is_Reachable (From => Target_Parent.Node,
2225 To => Source_Parent.Node)
2227 raise Constraint_Error
2228 with "Source_Parent is ancestor of Target_Parent";
2232 (Target_Parent => Target_Parent.Node,
2233 Before => Before.Node,
2234 Source_Parent => Source_Parent.Node);
2239 TC_Check (Target.TC);
2240 TC_Check (Source.TC);
2242 -- We cache the count of the nodes we have allocated, so that operation
2243 -- Node_Count can execute in O(1) time. But that means we must count the
2244 -- nodes in the subtree we remove from Source and insert into Target, in
2245 -- order to keep the count accurate.
2247 Count := Subtree_Node_Count (Source_Parent.Node);
2248 pragma Assert (Count >= 1);
2250 Count := Count - 1; -- because Source_Parent node does not move
2253 (Target_Parent => Target_Parent.Node,
2254 Before => Before.Node,
2255 Source_Parent => Source_Parent.Node);
2257 Source.Count := Source.Count - Count;
2258 Target.Count := Target.Count + Count;
2259 end Splice_Children;
2261 procedure Splice_Children
2262 (Container : in out Tree;
2263 Target_Parent : Cursor;
2265 Source_Parent : Cursor)
2268 if Checks and then Target_Parent = No_Element then
2269 raise Constraint_Error with "Target_Parent cursor has no element";
2273 Target_Parent.Container /= Container'Unrestricted_Access
2276 with "Target_Parent cursor not in container";
2279 if Before /= No_Element then
2280 if Checks and then Before.Container /= Container'Unrestricted_Access
2283 with "Before cursor not in container";
2286 if Checks and then Before.Node.Parent /= Target_Parent.Node then
2287 raise Constraint_Error
2288 with "Before cursor not child of Target_Parent";
2292 if Checks and then Source_Parent = No_Element then
2293 raise Constraint_Error with "Source_Parent cursor has no element";
2297 Source_Parent.Container /= Container'Unrestricted_Access
2300 with "Source_Parent cursor not in container";
2303 if Target_Parent = Source_Parent then
2307 TC_Check (Container.TC);
2309 if Checks and then Is_Reachable (From => Target_Parent.Node,
2310 To => Source_Parent.Node)
2312 raise Constraint_Error
2313 with "Source_Parent is ancestor of Target_Parent";
2317 (Target_Parent => Target_Parent.Node,
2318 Before => Before.Node,
2319 Source_Parent => Source_Parent.Node);
2320 end Splice_Children;
2322 procedure Splice_Children
2323 (Target_Parent : Tree_Node_Access;
2324 Before : Tree_Node_Access;
2325 Source_Parent : Tree_Node_Access)
2327 CC : constant Children_Type := Source_Parent.Children;
2328 C : Tree_Node_Access;
2331 -- This is a utility operation to remove the children from Source parent
2332 -- and insert them into Target parent.
2334 Source_Parent.Children := Children_Type'(others => null);
2336 -- Fix up the Parent pointers of each child to designate its new Target
2340 while C
/= null loop
2341 C
.Parent
:= Target_Parent
;
2348 Parent
=> Target_Parent
,
2350 end Splice_Children
;
2352 --------------------
2353 -- Splice_Subtree --
2354 --------------------
2356 procedure Splice_Subtree
2357 (Target
: in out Tree
;
2360 Source
: in out Tree
;
2361 Position
: in out Cursor
)
2363 Subtree_Count
: Count_Type
;
2366 if Checks
and then Parent
= No_Element
then
2367 raise Constraint_Error
with "Parent cursor has no element";
2370 if Checks
and then Parent
.Container
/= Target
'Unrestricted_Access then
2371 raise Program_Error
with "Parent cursor not in Target container";
2374 if Before
/= No_Element
then
2375 if Checks
and then Before
.Container
/= Target
'Unrestricted_Access then
2376 raise Program_Error
with "Before cursor not in Target container";
2379 if Checks
and then Before
.Node
.Parent
/= Parent
.Node
then
2380 raise Constraint_Error
with "Before cursor not child of Parent";
2384 if Checks
and then Position
= No_Element
then
2385 raise Constraint_Error
with "Position cursor has no element";
2388 if Checks
and then Position
.Container
/= Source
'Unrestricted_Access then
2389 raise Program_Error
with "Position cursor not in Source container";
2392 if Checks
and then Is_Root
(Position
) then
2393 raise Program_Error
with "Position cursor designates root";
2396 if Target
'Address = Source
'Address then
2397 if Position
.Node
.Parent
= Parent
.Node
then
2398 if Position
.Node
= Before
.Node
then
2402 if Position
.Node
.Next
= Before
.Node
then
2407 TC_Check
(Target
.TC
);
2410 Is_Reachable
(From
=> Parent
.Node
, To
=> Position
.Node
)
2412 raise Constraint_Error
with "Position is ancestor of Parent";
2415 Remove_Subtree
(Position
.Node
);
2417 Position
.Node
.Parent
:= Parent
.Node
;
2418 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2423 TC_Check
(Target
.TC
);
2424 TC_Check
(Source
.TC
);
2426 -- This is an unfortunate feature of this API: we must count the nodes
2427 -- in the subtree that we remove from the source tree, which is an O(n)
2428 -- operation. It would have been better if the Tree container did not
2429 -- have a Node_Count selector; a user that wants the number of nodes in
2430 -- the tree could simply call Subtree_Node_Count, with the understanding
2431 -- that such an operation is O(n).
2433 -- Of course, we could choose to implement the Node_Count selector as an
2434 -- O(n) operation, which would turn this splice operation into an O(1)
2437 Subtree_Count
:= Subtree_Node_Count
(Position
.Node
);
2438 pragma Assert
(Subtree_Count
<= Source
.Count
);
2440 Remove_Subtree
(Position
.Node
);
2441 Source
.Count
:= Source
.Count
- Subtree_Count
;
2443 Position
.Node
.Parent
:= Parent
.Node
;
2444 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2446 Target
.Count
:= Target
.Count
+ Subtree_Count
;
2448 Position
.Container
:= Target
'Unrestricted_Access;
2451 procedure Splice_Subtree
2452 (Container
: in out Tree
;
2458 if Checks
and then Parent
= No_Element
then
2459 raise Constraint_Error
with "Parent cursor has no element";
2462 if Checks
and then Parent
.Container
/= Container
'Unrestricted_Access then
2463 raise Program_Error
with "Parent cursor not in container";
2466 if Before
/= No_Element
then
2467 if Checks
and then Before
.Container
/= Container
'Unrestricted_Access
2469 raise Program_Error
with "Before cursor not in container";
2472 if Checks
and then Before
.Node
.Parent
/= Parent
.Node
then
2473 raise Constraint_Error
with "Before cursor not child of Parent";
2477 if Checks
and then Position
= No_Element
then
2478 raise Constraint_Error
with "Position cursor has no element";
2481 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2483 raise Program_Error
with "Position cursor not in container";
2486 if Checks
and then Is_Root
(Position
) then
2488 -- Should this be PE instead? Need ARG confirmation. ???
2490 raise Constraint_Error
with "Position cursor designates root";
2493 if Position
.Node
.Parent
= Parent
.Node
then
2494 if Position
.Node
= Before
.Node
then
2498 if Position
.Node
.Next
= Before
.Node
then
2503 TC_Check
(Container
.TC
);
2506 Is_Reachable
(From
=> Parent
.Node
, To
=> Position
.Node
)
2508 raise Constraint_Error
with "Position is ancestor of Parent";
2511 Remove_Subtree
(Position
.Node
);
2513 Position
.Node
.Parent
:= Parent
.Node
;
2514 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2517 ------------------------
2518 -- Subtree_Node_Count --
2519 ------------------------
2521 function Subtree_Node_Count
(Position
: Cursor
) return Count_Type
is
2523 if Position
= No_Element
then
2527 return Subtree_Node_Count
(Position
.Node
);
2528 end Subtree_Node_Count
;
2530 function Subtree_Node_Count
2531 (Subtree
: Tree_Node_Access
) return Count_Type
2533 Result
: Count_Type
;
2534 Node
: Tree_Node_Access
;
2538 Node
:= Subtree
.Children
.First
;
2539 while Node
/= null loop
2540 Result
:= Result
+ Subtree_Node_Count
(Node
);
2545 end Subtree_Node_Count
;
2552 (Container
: in out Tree
;
2556 if Checks
and then I
= No_Element
then
2557 raise Constraint_Error
with "I cursor has no element";
2560 if Checks
and then I
.Container
/= Container
'Unrestricted_Access then
2561 raise Program_Error
with "I cursor not in container";
2564 if Checks
and then Is_Root
(I
) then
2565 raise Program_Error
with "I cursor designates root";
2568 if I
= J
then -- make this test sooner???
2572 if Checks
and then J
= No_Element
then
2573 raise Constraint_Error
with "J cursor has no element";
2576 if Checks
and then J
.Container
/= Container
'Unrestricted_Access then
2577 raise Program_Error
with "J cursor not in container";
2580 if Checks
and then Is_Root
(J
) then
2581 raise Program_Error
with "J cursor designates root";
2584 TE_Check
(Container
.TC
);
2587 EI
: constant Element_Access
:= I
.Node
.Element
;
2590 I
.Node
.Element
:= J
.Node
.Element
;
2591 J
.Node
.Element
:= EI
;
2595 --------------------
2596 -- Update_Element --
2597 --------------------
2599 procedure Update_Element
2600 (Container
: in out Tree
;
2602 Process
: not null access procedure (Element
: in out Element_Type
))
2604 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
2605 Lock
: With_Lock
(T
.TC
'Unrestricted_Access);
2607 if Checks
and then Position
= No_Element
then
2608 raise Constraint_Error
with "Position cursor has no element";
2611 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2613 raise Program_Error
with "Position cursor not in container";
2616 if Checks
and then Is_Root
(Position
) then
2617 raise Program_Error
with "Position cursor designates root";
2620 Process
(Position
.Node
.Element
.all);
2628 (Stream
: not null access Root_Stream_Type
'Class;
2631 procedure Write_Children
(Subtree
: Tree_Node_Access
);
2632 procedure Write_Subtree
(Subtree
: Tree_Node_Access
);
2634 --------------------
2635 -- Write_Children --
2636 --------------------
2638 procedure Write_Children
(Subtree
: Tree_Node_Access
) is
2639 CC
: Children_Type
renames Subtree
.Children
;
2640 C
: Tree_Node_Access
;
2643 Count_Type
'Write (Stream
, Child_Count
(CC
));
2646 while C
/= null loop
2656 procedure Write_Subtree
(Subtree
: Tree_Node_Access
) is
2658 Element_Type
'Output (Stream
, Subtree
.Element
.all);
2659 Write_Children
(Subtree
);
2662 -- Start of processing for Write
2665 Count_Type
'Write (Stream
, Container
.Count
);
2667 if Container
.Count
= 0 then
2671 Write_Children
(Root_Node
(Container
));
2675 (Stream
: not null access Root_Stream_Type
'Class;
2679 raise Program_Error
with "attempt to write tree cursor to stream";
2683 (Stream
: not null access Root_Stream_Type
'Class;
2684 Item
: Reference_Type
)
2687 raise Program_Error
with "attempt to stream reference";
2691 (Stream
: not null access Root_Stream_Type
'Class;
2692 Item
: Constant_Reference_Type
)
2695 raise Program_Error
with "attempt to stream reference";
2698 end Ada
.Containers
.Indefinite_Multiway_Trees
;