1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.INDEFINITE_MULTIWAY_TREES --
9 -- Copyright (C) 2004-2014, 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 Annotate
(CodePeer
, Skip_Analysis
);
42 type Root_Iterator
is abstract new Limited_Controlled
and
43 Tree_Iterator_Interfaces
.Forward_Iterator
with
45 Container
: Tree_Access
;
46 Subtree
: Tree_Node_Access
;
49 overriding
procedure Finalize
(Object
: in out Root_Iterator
);
51 -----------------------
52 -- Subtree_Iterator --
53 -----------------------
55 type Subtree_Iterator
is new Root_Iterator
with null record;
57 overriding
function First
(Object
: Subtree_Iterator
) return Cursor
;
59 overriding
function Next
60 (Object
: Subtree_Iterator
;
61 Position
: Cursor
) return Cursor
;
67 type Child_Iterator
is new Root_Iterator
and
68 Tree_Iterator_Interfaces
.Reversible_Iterator
with null record;
70 overriding
function First
(Object
: Child_Iterator
) return Cursor
;
72 overriding
function Next
73 (Object
: Child_Iterator
;
74 Position
: Cursor
) return Cursor
;
76 overriding
function Last
(Object
: Child_Iterator
) return Cursor
;
78 overriding
function Previous
79 (Object
: Child_Iterator
;
80 Position
: Cursor
) return Cursor
;
82 -----------------------
83 -- Local Subprograms --
84 -----------------------
86 function Root_Node
(Container
: Tree
) return Tree_Node_Access
;
88 procedure Free_Element
is
89 new Ada
.Unchecked_Deallocation
(Element_Type
, Element_Access
);
91 procedure Deallocate_Node
(X
: in out Tree_Node_Access
);
93 procedure Deallocate_Children
94 (Subtree
: Tree_Node_Access
;
95 Count
: in out Count_Type
);
97 procedure Deallocate_Subtree
98 (Subtree
: in out Tree_Node_Access
;
99 Count
: in out Count_Type
);
101 function Equal_Children
102 (Left_Subtree
, Right_Subtree
: Tree_Node_Access
) return Boolean;
104 function Equal_Subtree
105 (Left_Subtree
, Right_Subtree
: Tree_Node_Access
) return Boolean;
107 procedure Iterate_Children
108 (Container
: Tree_Access
;
109 Subtree
: Tree_Node_Access
;
110 Process
: not null access procedure (Position
: Cursor
));
112 procedure Iterate_Subtree
113 (Container
: Tree_Access
;
114 Subtree
: Tree_Node_Access
;
115 Process
: not null access procedure (Position
: Cursor
));
117 procedure Copy_Children
118 (Source
: Children_Type
;
119 Parent
: Tree_Node_Access
;
120 Count
: in out Count_Type
);
122 procedure Copy_Subtree
123 (Source
: Tree_Node_Access
;
124 Parent
: Tree_Node_Access
;
125 Target
: out Tree_Node_Access
;
126 Count
: in out Count_Type
);
128 function Find_In_Children
129 (Subtree
: Tree_Node_Access
;
130 Item
: Element_Type
) return Tree_Node_Access
;
132 function Find_In_Subtree
133 (Subtree
: Tree_Node_Access
;
134 Item
: Element_Type
) return Tree_Node_Access
;
136 function Child_Count
(Children
: Children_Type
) return Count_Type
;
138 function Subtree_Node_Count
139 (Subtree
: Tree_Node_Access
) return Count_Type
;
141 function Is_Reachable
(From
, To
: Tree_Node_Access
) return Boolean;
143 procedure Remove_Subtree
(Subtree
: Tree_Node_Access
);
145 procedure Insert_Subtree_Node
146 (Subtree
: Tree_Node_Access
;
147 Parent
: Tree_Node_Access
;
148 Before
: Tree_Node_Access
);
150 procedure Insert_Subtree_List
151 (First
: Tree_Node_Access
;
152 Last
: Tree_Node_Access
;
153 Parent
: Tree_Node_Access
;
154 Before
: Tree_Node_Access
);
156 procedure Splice_Children
157 (Target_Parent
: Tree_Node_Access
;
158 Before
: Tree_Node_Access
;
159 Source_Parent
: Tree_Node_Access
);
165 function "=" (Left
, Right
: Tree
) return Boolean is
167 if Left
'Address = Right
'Address then
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);
191 Container.Count := 0;
193 -- Copy_Children returns a count of the number of nodes that it
194 -- allocates, but it works by incrementing the value that is passed in.
195 -- We must therefore initialize the count value before calling
200 -- Now we attempt the allocation of subtrees. The invariants are
201 -- satisfied even if the allocation fails.
203 Copy_Children (Source, Root_Node (Container), Target_Count);
204 pragma Assert (Target_Count = Source_Count);
206 Container.Count := Source_Count;
209 procedure Adjust (Control : in out Reference_Control_Type) is
211 if Control.Container /= null then
213 C : Tree renames Control.Container.all;
214 B : Natural renames C.Busy;
215 L : Natural renames C.Lock;
227 function Ancestor_Find
229 Item : Element_Type) return Cursor
231 R, N : Tree_Node_Access;
234 if Position = No_Element then
235 raise Constraint_Error with "Position cursor has no element";
238 -- Commented-out pending ARG ruling. ???
240 -- if Position.Container /= Container'Unrestricted_Access then
241 -- raise Program_Error with "Position cursor not in container";
244 -- AI-0136 says to raise PE if Position equals the root node. This does
245 -- not seem correct, as this value is just the limiting condition of the
246 -- search. For now we omit this check pending a ruling from the ARG.???
248 -- if Is_Root (Position) then
249 -- raise Program_Error with "Position cursor designates root";
252 R := Root_Node (Position.Container.all);
255 if N.Element.all = Item then
256 return Cursor'(Position
.Container
, N
);
269 procedure Append_Child
270 (Container
: in out Tree
;
272 New_Item
: Element_Type
;
273 Count
: Count_Type
:= 1)
275 First
, Last
: Tree_Node_Access
;
276 Element
: Element_Access
;
279 if Parent
= No_Element
then
280 raise Constraint_Error
with "Parent cursor has no element";
283 if Parent
.Container
/= Container
'Unrestricted_Access then
284 raise Program_Error
with "Parent cursor not in container";
291 if Container
.Busy
> 0 then
293 with "attempt to tamper with cursors (tree is busy)";
297 -- The element allocator may need an accessibility check in the case
298 -- the actual type is class-wide or has access discriminants (see
299 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
300 -- allocator in the loop below, because the one in this block would
301 -- have failed already.
303 pragma Unsuppress
(Accessibility_Check
);
306 Element
:= new Element_Type
'(New_Item);
309 First := new Tree_Node_Type'(Parent
=> Parent
.Node
,
315 for J
in Count_Type
'(2) .. Count loop
317 -- Reclaim other nodes if Storage_Error. ???
319 Element := new Element_Type'(New_Item
);
320 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
331 Parent => Parent.Node,
332 Before => null); -- null means "insert at end of list"
334 -- In order for operation Node_Count to complete in O(1) time, we cache
335 -- the count value. Here we increment the total count by the number of
336 -- nodes we just inserted.
338 Container.Count := Container.Count + Count;
345 procedure Assign (Target : in out Tree; Source : Tree) is
346 Source_Count : constant Count_Type := Source.Count;
347 Target_Count : Count_Type;
350 if Target'Address = Source'Address then
354 Target.Clear; -- checks busy bit
356 -- Copy_Children returns the number of nodes that it allocates, but it
357 -- does this by incrementing the count value passed in, so we must
358 -- initialize the count before calling Copy_Children.
362 -- Note that Copy_Children inserts the newly-allocated children into
363 -- their parent list only after the allocation of all the children has
364 -- succeeded. This preserves invariants even if the allocation fails.
366 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
367 pragma Assert (Target_Count = Source_Count);
369 Target.Count := Source_Count;
376 function Child_Count (Parent : Cursor) return Count_Type is
378 if Parent = No_Element then
381 return Child_Count (Parent.Node.Children);
385 function Child_Count (Children : Children_Type) return Count_Type is
387 Node : Tree_Node_Access;
391 Node := Children.First;
392 while Node /= null loop
393 Result := Result + 1;
404 function Child_Depth (Parent, Child : Cursor) return Count_Type is
406 N : Tree_Node_Access;
409 if Parent = No_Element then
410 raise Constraint_Error with "Parent cursor has no element";
413 if Child = No_Element then
414 raise Constraint_Error with "Child cursor has no element";
417 if Parent.Container /= Child.Container then
418 raise Program_Error with "Parent and Child in different containers";
423 while N /= Parent.Node loop
424 Result := Result + 1;
428 raise Program_Error with "Parent is not ancestor of Child";
439 procedure Clear (Container : in out Tree) is
440 Container_Count : Count_Type;
441 Children_Count : Count_Type;
444 if Container.Busy > 0 then
446 with "attempt to tamper with cursors (tree is busy)";
449 -- We first set the container count to 0, in order to preserve
450 -- invariants in case the deallocation fails. (This works because
451 -- Deallocate_Children immediately removes the children from their
452 -- parent, and then does the actual deallocation.)
454 Container_Count := Container.Count;
455 Container.Count := 0;
457 -- Deallocate_Children returns the number of nodes that it deallocates,
458 -- but it does this by incrementing the count value that is passed in,
459 -- so we must first initialize the count return value before calling it.
463 -- See comment above. Deallocate_Children immediately removes the
464 -- children list from their parent node (here, the root of the tree),
465 -- and only after that does it attempt the actual deallocation. So even
466 -- if the deallocation fails, the representation invariants
468 Deallocate_Children (Root_Node (Container), Children_Count);
469 pragma Assert (Children_Count = Container_Count);
472 ------------------------
473 -- Constant_Reference --
474 ------------------------
476 function Constant_Reference
477 (Container : aliased Tree;
478 Position : Cursor) return Constant_Reference_Type
481 if Position.Container = null then
482 raise Constraint_Error with
483 "Position cursor has no element";
486 if Position.Container /= Container'Unrestricted_Access then
487 raise Program_Error with
488 "Position cursor designates wrong container";
491 if Position.Node = Root_Node (Container) then
492 raise Program_Error with "Position cursor designates root";
495 if Position.Node.Element = null then
496 raise Program_Error with "Node has no element";
499 -- Implement Vet for multiway tree???
500 -- pragma Assert (Vet (Position),
501 -- "Position cursor in Constant_Reference is bad");
504 C : Tree renames Position.Container.all;
505 B : Natural renames C.Busy;
506 L : Natural renames C.Lock;
508 return R : constant Constant_Reference_Type :=
509 (Element => Position.Node.Element.all'Access,
510 Control => (Controlled with Container'Unrestricted_Access))
516 end Constant_Reference;
524 Item : Element_Type) return Boolean
527 return Find (Container, Item) /= No_Element;
534 function Copy (Source : Tree) return Tree is
536 return Target : Tree do
538 (Source => Source.Root.Children,
539 Parent => Root_Node (Target),
540 Count => Target.Count);
542 pragma Assert (Target.Count = Source.Count);
550 procedure Copy_Children
551 (Source : Children_Type;
552 Parent : Tree_Node_Access;
553 Count : in out Count_Type)
555 pragma Assert (Parent /= null);
556 pragma Assert (Parent.Children.First = null);
557 pragma Assert (Parent.Children.Last = null);
560 C : Tree_Node_Access;
563 -- We special-case the first allocation, in order to establish the
564 -- representation invariants for type Children_Type.
580 -- The representation invariants for the Children_Type list have been
581 -- established, so we can now copy the remaining children of Source.
588 Target => CC.Last.Next,
591 CC.Last.Next.Prev := CC.Last;
592 CC.Last := CC.Last.Next;
597 -- We add the newly-allocated children to their parent list only after
598 -- the allocation has succeeded, in order to preserve invariants of the
601 Parent.Children := CC;
608 procedure Copy_Subtree
609 (Target : in out Tree;
614 Target_Subtree : Tree_Node_Access;
615 Target_Count : Count_Type;
618 if Parent = No_Element then
619 raise Constraint_Error with "Parent cursor has no element";
622 if Parent.Container /= Target'Unrestricted_Access then
623 raise Program_Error with "Parent cursor not in container";
626 if Before /= No_Element then
627 if Before.Container /= Target'Unrestricted_Access then
628 raise Program_Error with "Before cursor not in container";
631 if Before.Node.Parent /= Parent.Node then
632 raise Constraint_Error with "Before cursor not child of Parent";
636 if Source = No_Element then
640 if Is_Root (Source) then
641 raise Constraint_Error with "Source cursor designates root";
644 -- Copy_Subtree returns a count of the number of nodes that it
645 -- allocates, but it works by incrementing the value that is passed in.
646 -- We must therefore initialize the count value before calling
652 (Source => Source.Node,
653 Parent => Parent.Node,
654 Target => Target_Subtree,
655 Count => Target_Count);
657 pragma Assert (Target_Subtree /= null);
658 pragma Assert (Target_Subtree.Parent = Parent.Node);
659 pragma Assert (Target_Count >= 1);
662 (Subtree => Target_Subtree,
663 Parent => Parent.Node,
664 Before => Before.Node);
666 -- In order for operation Node_Count to complete in O(1) time, we cache
667 -- the count value. Here we increment the total count by the number of
668 -- nodes we just inserted.
670 Target.Count := Target.Count + Target_Count;
673 procedure Copy_Subtree
674 (Source : Tree_Node_Access;
675 Parent : Tree_Node_Access;
676 Target : out Tree_Node_Access;
677 Count : in out Count_Type)
679 E : constant Element_Access := new Element_Type'(Source
.Element
.all);
682 Target
:= new Tree_Node_Type
'(Element => E,
689 (Source => Source.Children,
694 -------------------------
695 -- Deallocate_Children --
696 -------------------------
698 procedure Deallocate_Children
699 (Subtree : Tree_Node_Access;
700 Count : in out Count_Type)
702 pragma Assert (Subtree /= null);
704 CC : Children_Type := Subtree.Children;
705 C : Tree_Node_Access;
708 -- We immediately remove the children from their parent, in order to
709 -- preserve invariants in case the deallocation fails.
711 Subtree.Children := Children_Type'(others => null);
713 while CC
.First
/= null loop
717 Deallocate_Subtree
(C
, Count
);
719 end Deallocate_Children
;
721 ---------------------
722 -- Deallocate_Node --
723 ---------------------
725 procedure Deallocate_Node
(X
: in out Tree_Node_Access
) is
726 procedure Free_Node
is
727 new Ada
.Unchecked_Deallocation
(Tree_Node_Type
, Tree_Node_Access
);
729 -- Start of processing for Deallocate_Node
733 Free_Element
(X
.Element
);
738 ------------------------
739 -- Deallocate_Subtree --
740 ------------------------
742 procedure Deallocate_Subtree
743 (Subtree
: in out Tree_Node_Access
;
744 Count
: in out Count_Type
)
747 Deallocate_Children
(Subtree
, Count
);
748 Deallocate_Node
(Subtree
);
750 end Deallocate_Subtree
;
752 ---------------------
753 -- Delete_Children --
754 ---------------------
756 procedure Delete_Children
757 (Container
: in out Tree
;
763 if Parent
= No_Element
then
764 raise Constraint_Error
with "Parent cursor has no element";
767 if Parent
.Container
/= Container
'Unrestricted_Access then
768 raise Program_Error
with "Parent cursor not in container";
771 if Container
.Busy
> 0 then
773 with "attempt to tamper with cursors (tree is busy)";
776 -- Deallocate_Children returns a count of the number of nodes
777 -- that it deallocates, but it works by incrementing the
778 -- value that is passed in. We must therefore initialize
779 -- the count value before calling Deallocate_Children.
783 Deallocate_Children
(Parent
.Node
, Count
);
784 pragma Assert
(Count
<= Container
.Count
);
786 Container
.Count
:= Container
.Count
- Count
;
793 procedure Delete_Leaf
794 (Container
: in out Tree
;
795 Position
: in out Cursor
)
797 X
: Tree_Node_Access
;
800 if Position
= No_Element
then
801 raise Constraint_Error
with "Position cursor has no element";
804 if Position
.Container
/= Container
'Unrestricted_Access then
805 raise Program_Error
with "Position cursor not in container";
808 if Is_Root
(Position
) then
809 raise Program_Error
with "Position cursor designates root";
812 if not Is_Leaf
(Position
) then
813 raise Constraint_Error
with "Position cursor does not designate leaf";
816 if Container
.Busy
> 0 then
818 with "attempt to tamper with cursors (tree is busy)";
822 Position
:= No_Element
;
824 -- Restore represention invariants before attempting the actual
828 Container
.Count
:= Container
.Count
- 1;
830 -- It is now safe to attempt the deallocation. This leaf node has been
831 -- disassociated from the tree, so even if the deallocation fails,
832 -- representation invariants will remain satisfied.
841 procedure Delete_Subtree
842 (Container
: in out Tree
;
843 Position
: in out Cursor
)
845 X
: Tree_Node_Access
;
849 if Position
= No_Element
then
850 raise Constraint_Error
with "Position cursor has no element";
853 if Position
.Container
/= Container
'Unrestricted_Access then
854 raise Program_Error
with "Position cursor not in container";
857 if Is_Root
(Position
) then
858 raise Program_Error
with "Position cursor designates root";
861 if Container
.Busy
> 0 then
863 with "attempt to tamper with cursors (tree is busy)";
867 Position
:= No_Element
;
869 -- Here is one case where a deallocation failure can result in the
870 -- violation of a representation invariant. We disassociate the subtree
871 -- from the tree now, but we only decrement the total node count after
872 -- we attempt the deallocation. However, if the deallocation fails, the
873 -- total node count will not get decremented.
875 -- One way around this dilemma is to count the nodes in the subtree
876 -- before attempt to delete the subtree, but that is an O(n) operation,
877 -- so it does not seem worth it.
879 -- Perhaps this is much ado about nothing, since the only way
880 -- deallocation can fail is if Controlled Finalization fails: this
881 -- propagates Program_Error so all bets are off anyway. ???
885 -- Deallocate_Subtree returns a count of the number of nodes that it
886 -- deallocates, but it works by incrementing the value that is passed
887 -- in. We must therefore initialize the count value before calling
888 -- Deallocate_Subtree.
892 Deallocate_Subtree
(X
, Count
);
893 pragma Assert
(Count
<= Container
.Count
);
895 -- See comments above. We would prefer to do this sooner, but there's no
896 -- way to satisfy that goal without an potentially severe execution
899 Container
.Count
:= Container
.Count
- Count
;
906 function Depth
(Position
: Cursor
) return Count_Type
is
908 N
: Tree_Node_Access
;
915 Result
:= Result
+ 1;
925 function Element
(Position
: Cursor
) return Element_Type
is
927 if Position
.Container
= null then
928 raise Constraint_Error
with "Position cursor has no element";
931 if Position
.Node
= Root_Node
(Position
.Container
.all) then
932 raise Program_Error
with "Position cursor designates root";
935 return Position
.Node
.Element
.all;
942 function Equal_Children
943 (Left_Subtree
: Tree_Node_Access
;
944 Right_Subtree
: Tree_Node_Access
) return Boolean
946 Left_Children
: Children_Type
renames Left_Subtree
.Children
;
947 Right_Children
: Children_Type
renames Right_Subtree
.Children
;
949 L
, R
: Tree_Node_Access
;
952 if Child_Count
(Left_Children
) /= Child_Count
(Right_Children
) then
956 L
:= Left_Children
.First
;
957 R
:= Right_Children
.First
;
959 if not Equal_Subtree
(L
, R
) then
974 function Equal_Subtree
975 (Left_Position
: Cursor
;
976 Right_Position
: Cursor
) return Boolean
979 if Left_Position
= No_Element
then
980 raise Constraint_Error
with "Left cursor has no element";
983 if Right_Position
= No_Element
then
984 raise Constraint_Error
with "Right cursor has no element";
987 if Left_Position
= Right_Position
then
991 if Is_Root
(Left_Position
) then
992 if not Is_Root
(Right_Position
) then
996 return Equal_Children
(Left_Position
.Node
, Right_Position
.Node
);
999 if Is_Root
(Right_Position
) then
1003 return Equal_Subtree
(Left_Position
.Node
, Right_Position
.Node
);
1006 function Equal_Subtree
1007 (Left_Subtree
: Tree_Node_Access
;
1008 Right_Subtree
: Tree_Node_Access
) return Boolean
1011 if Left_Subtree
.Element
.all /= Right_Subtree
.Element
.all then
1015 return Equal_Children
(Left_Subtree
, Right_Subtree
);
1022 procedure Finalize
(Object
: in out Root_Iterator
) is
1023 B
: Natural renames Object
.Container
.Busy
;
1028 procedure Finalize
(Control
: in out Reference_Control_Type
) is
1030 if Control
.Container
/= null then
1032 C
: Tree
renames Control
.Container
.all;
1033 B
: Natural renames C
.Busy
;
1034 L
: Natural renames C
.Lock
;
1040 Control
.Container
:= null;
1050 Item
: Element_Type
) return Cursor
1052 N
: constant Tree_Node_Access
:=
1053 Find_In_Children
(Root_Node
(Container
), Item
);
1060 return Cursor
'(Container'Unrestricted_Access, N);
1067 overriding function First (Object : Subtree_Iterator) return Cursor is
1069 if Object.Subtree = Root_Node (Object.Container.all) then
1070 return First_Child (Root (Object.Container.all));
1072 return Cursor'(Object
.Container
, Object
.Subtree
);
1076 overriding
function First
(Object
: Child_Iterator
) return Cursor
is
1078 return First_Child
(Cursor
'(Object.Container, Object.Subtree));
1085 function First_Child (Parent : Cursor) return Cursor is
1086 Node : Tree_Node_Access;
1089 if Parent = No_Element then
1090 raise Constraint_Error with "Parent cursor has no element";
1093 Node := Parent.Node.Children.First;
1099 return Cursor'(Parent
.Container
, Node
);
1102 -------------------------
1103 -- First_Child_Element --
1104 -------------------------
1106 function First_Child_Element
(Parent
: Cursor
) return Element_Type
is
1108 return Element
(First_Child
(Parent
));
1109 end First_Child_Element
;
1111 ----------------------
1112 -- Find_In_Children --
1113 ----------------------
1115 function Find_In_Children
1116 (Subtree
: Tree_Node_Access
;
1117 Item
: Element_Type
) return Tree_Node_Access
1119 N
, Result
: Tree_Node_Access
;
1122 N
:= Subtree
.Children
.First
;
1123 while N
/= null loop
1124 Result
:= Find_In_Subtree
(N
, Item
);
1126 if Result
/= null then
1134 end Find_In_Children
;
1136 ---------------------
1137 -- Find_In_Subtree --
1138 ---------------------
1140 function Find_In_Subtree
1142 Item
: Element_Type
) return Cursor
1144 Result
: Tree_Node_Access
;
1147 if Position
= No_Element
then
1148 raise Constraint_Error
with "Position cursor has no element";
1151 -- Commented-out pending ruling from ARG. ???
1153 -- if Position.Container /= Container'Unrestricted_Access then
1154 -- raise Program_Error with "Position cursor not in container";
1157 if Is_Root
(Position
) then
1158 Result
:= Find_In_Children
(Position
.Node
, Item
);
1161 Result
:= Find_In_Subtree
(Position
.Node
, Item
);
1164 if Result
= null then
1168 return Cursor
'(Position.Container, Result);
1169 end Find_In_Subtree;
1171 function Find_In_Subtree
1172 (Subtree : Tree_Node_Access;
1173 Item : Element_Type) return Tree_Node_Access
1176 if Subtree.Element.all = Item then
1180 return Find_In_Children (Subtree, Item);
1181 end Find_In_Subtree;
1187 function Has_Element (Position : Cursor) return Boolean is
1189 if Position = No_Element then
1193 return Position.Node.Parent /= null;
1200 procedure Insert_Child
1201 (Container : in out Tree;
1204 New_Item : Element_Type;
1205 Count : Count_Type := 1)
1208 pragma Unreferenced (Position);
1211 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1214 procedure Insert_Child
1215 (Container : in out Tree;
1218 New_Item : Element_Type;
1219 Position : out Cursor;
1220 Count : Count_Type := 1)
1222 First : Tree_Node_Access;
1223 Last : Tree_Node_Access;
1224 Element : Element_Access;
1227 if Parent = No_Element then
1228 raise Constraint_Error with "Parent cursor has no element";
1231 if Parent.Container /= Container'Unrestricted_Access then
1232 raise Program_Error with "Parent cursor not in container";
1235 if Before /= No_Element then
1236 if Before.Container /= Container'Unrestricted_Access then
1237 raise Program_Error with "Before cursor not in container";
1240 if Before.Node.Parent /= Parent.Node then
1241 raise Constraint_Error with "Parent cursor not parent of Before";
1246 Position := No_Element; -- Need ruling from ARG ???
1250 if Container.Busy > 0 then
1252 with "attempt to tamper with cursors (tree is busy)";
1256 -- The element allocator may need an accessibility check in the case
1257 -- the actual type is class-wide or has access discriminants (see
1258 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
1259 -- allocator in the loop below, because the one in this block would
1260 -- have failed already.
1262 pragma Unsuppress (Accessibility_Check);
1265 Element := new Element_Type'(New_Item
);
1268 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
1273 for J in Count_Type'(2) .. Count
loop
1275 -- Reclaim other nodes if Storage_Error. ???
1277 Element
:= new Element_Type
'(New_Item);
1278 Last.Next := new Tree_Node_Type'(Parent
=> Parent
.Node
,
1289 Parent
=> Parent
.Node
,
1290 Before
=> Before
.Node
);
1292 -- In order for operation Node_Count to complete in O(1) time, we cache
1293 -- the count value. Here we increment the total count by the number of
1294 -- nodes we just inserted.
1296 Container
.Count
:= Container
.Count
+ Count
;
1298 Position
:= Cursor
'(Parent.Container, First);
1301 -------------------------
1302 -- Insert_Subtree_List --
1303 -------------------------
1305 procedure Insert_Subtree_List
1306 (First : Tree_Node_Access;
1307 Last : Tree_Node_Access;
1308 Parent : Tree_Node_Access;
1309 Before : Tree_Node_Access)
1311 pragma Assert (Parent /= null);
1312 C : Children_Type renames Parent.Children;
1315 -- This is a simple utility operation to insert a list of nodes (from
1316 -- First..Last) as children of Parent. The Before node specifies where
1317 -- the new children should be inserted relative to the existing
1320 if First = null then
1321 pragma Assert (Last = null);
1325 pragma Assert (Last /= null);
1326 pragma Assert (Before = null or else Before.Parent = Parent);
1328 if C.First = null then
1330 C.First.Prev := null;
1332 C.Last.Next := null;
1334 elsif Before = null then -- means "insert after existing nodes"
1335 C.Last.Next := First;
1336 First.Prev := C.Last;
1338 C.Last.Next := null;
1340 elsif Before = C.First then
1341 Last.Next := C.First;
1342 C.First.Prev := Last;
1344 C.First.Prev := null;
1347 Before.Prev.Next := First;
1348 First.Prev := Before.Prev;
1349 Last.Next := Before;
1350 Before.Prev := Last;
1352 end Insert_Subtree_List;
1354 -------------------------
1355 -- Insert_Subtree_Node --
1356 -------------------------
1358 procedure Insert_Subtree_Node
1359 (Subtree : Tree_Node_Access;
1360 Parent : Tree_Node_Access;
1361 Before : Tree_Node_Access)
1364 -- This is a simple wrapper operation to insert a single child into the
1365 -- Parent's children list.
1372 end Insert_Subtree_Node;
1378 function Is_Empty (Container : Tree) return Boolean is
1380 return Container.Root.Children.First = null;
1387 function Is_Leaf (Position : Cursor) return Boolean is
1389 if Position = No_Element then
1393 return Position.Node.Children.First = null;
1400 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1401 pragma Assert (From /= null);
1402 pragma Assert (To /= null);
1404 N : Tree_Node_Access;
1408 while N /= null loop
1423 function Is_Root (Position : Cursor) return Boolean is
1425 if Position.Container = null then
1429 return Position = Root (Position.Container.all);
1438 Process : not null access procedure (Position : Cursor))
1440 B : Natural renames Container'Unrestricted_Access.all.Busy;
1446 (Container => Container'Unrestricted_Access,
1447 Subtree => Root_Node (Container),
1448 Process => Process);
1458 function Iterate (Container : Tree)
1459 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1462 return Iterate_Subtree (Root (Container));
1465 ----------------------
1466 -- Iterate_Children --
1467 ----------------------
1469 procedure Iterate_Children
1471 Process : not null access procedure (Position : Cursor))
1474 if Parent = No_Element then
1475 raise Constraint_Error with "Parent cursor has no element";
1479 B : Natural renames Parent.Container.Busy;
1480 C : Tree_Node_Access;
1485 C := Parent.Node.Children.First;
1486 while C /= null loop
1487 Process (Position => Cursor'(Parent
.Container
, Node
=> C
));
1498 end Iterate_Children
;
1500 procedure Iterate_Children
1501 (Container
: Tree_Access
;
1502 Subtree
: Tree_Node_Access
;
1503 Process
: not null access procedure (Position
: Cursor
))
1505 Node
: Tree_Node_Access
;
1508 -- This is a helper function to recursively iterate over all the nodes
1509 -- in a subtree, in depth-first fashion. This particular helper just
1510 -- visits the children of this subtree, not the root of the subtree node
1511 -- itself. This is useful when starting from the ultimate root of the
1512 -- entire tree (see Iterate), as that root does not have an element.
1514 Node
:= Subtree
.Children
.First
;
1515 while Node
/= null loop
1516 Iterate_Subtree
(Container
, Node
, Process
);
1519 end Iterate_Children
;
1521 function Iterate_Children
1524 return Tree_Iterator_Interfaces
.Reversible_Iterator
'Class
1526 C
: constant Tree_Access
:= Container
'Unrestricted_Access;
1527 B
: Natural renames C
.Busy
;
1530 if Parent
= No_Element
then
1531 raise Constraint_Error
with "Parent cursor has no element";
1534 if Parent
.Container
/= C
then
1535 raise Program_Error
with "Parent cursor not in container";
1538 return It
: constant Child_Iterator
:=
1539 Child_Iterator
'(Limited_Controlled with
1541 Subtree => Parent.Node)
1545 end Iterate_Children;
1547 ---------------------
1548 -- Iterate_Subtree --
1549 ---------------------
1551 function Iterate_Subtree
1553 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1556 if Position = No_Element then
1557 raise Constraint_Error with "Position cursor has no element";
1560 -- Implement Vet for multiway trees???
1561 -- pragma Assert (Vet (Position), "bad subtree cursor");
1564 B : Natural renames Position.Container.Busy;
1566 return It : constant Subtree_Iterator :=
1567 (Limited_Controlled with
1568 Container => Position.Container,
1569 Subtree => Position.Node)
1574 end Iterate_Subtree;
1576 procedure Iterate_Subtree
1578 Process : not null access procedure (Position : Cursor))
1581 if Position = No_Element then
1582 raise Constraint_Error with "Position cursor has no element";
1586 B : Natural renames Position.Container.Busy;
1591 if Is_Root (Position) then
1592 Iterate_Children (Position.Container, Position.Node, Process);
1594 Iterate_Subtree (Position.Container, Position.Node, Process);
1604 end Iterate_Subtree;
1606 procedure Iterate_Subtree
1607 (Container : Tree_Access;
1608 Subtree : Tree_Node_Access;
1609 Process : not null access procedure (Position : Cursor))
1612 -- This is a helper function to recursively iterate over all the nodes
1613 -- in a subtree, in depth-first fashion. It first visits the root of the
1614 -- subtree, then visits its children.
1616 Process (Cursor'(Container
, Subtree
));
1617 Iterate_Children
(Container
, Subtree
, Process
);
1618 end Iterate_Subtree
;
1624 overriding
function Last
(Object
: Child_Iterator
) return Cursor
is
1626 return Last_Child
(Cursor
'(Object.Container, Object.Subtree));
1633 function Last_Child (Parent : Cursor) return Cursor is
1634 Node : Tree_Node_Access;
1637 if Parent = No_Element then
1638 raise Constraint_Error with "Parent cursor has no element";
1641 Node := Parent.Node.Children.Last;
1647 return (Parent.Container, Node);
1650 ------------------------
1651 -- Last_Child_Element --
1652 ------------------------
1654 function Last_Child_Element (Parent : Cursor) return Element_Type is
1656 return Element (Last_Child (Parent));
1657 end Last_Child_Element;
1663 procedure Move (Target : in out Tree; Source : in out Tree) is
1664 Node : Tree_Node_Access;
1667 if Target'Address = Source'Address then
1671 if Source.Busy > 0 then
1673 with "attempt to tamper with cursors of Source (tree is busy)";
1676 Target.Clear; -- checks busy bit
1678 Target.Root.Children := Source.Root.Children;
1679 Source.Root.Children := Children_Type'(others => null);
1681 Node
:= Target
.Root
.Children
.First
;
1682 while Node
/= null loop
1683 Node
.Parent
:= Root_Node
(Target
);
1687 Target
.Count
:= Source
.Count
;
1696 (Object
: Subtree_Iterator
;
1697 Position
: Cursor
) return Cursor
1699 Node
: Tree_Node_Access
;
1702 if Position
.Container
= null then
1706 if Position
.Container
/= Object
.Container
then
1707 raise Program_Error
with
1708 "Position cursor of Next designates wrong tree";
1711 Node
:= Position
.Node
;
1713 if Node
.Children
.First
/= null then
1714 return Cursor
'(Object.Container, Node.Children.First);
1717 while Node /= Object.Subtree loop
1718 if Node.Next /= null then
1719 return Cursor'(Object
.Container
, Node
.Next
);
1722 Node
:= Node
.Parent
;
1729 (Object
: Child_Iterator
;
1730 Position
: Cursor
) return Cursor
1733 if Position
.Container
= null then
1737 if Position
.Container
/= Object
.Container
then
1738 raise Program_Error
with
1739 "Position cursor of Next designates wrong tree";
1742 return Next_Sibling
(Position
);
1749 function Next_Sibling
(Position
: Cursor
) return Cursor
is
1751 if Position
= No_Element
then
1755 if Position
.Node
.Next
= null then
1759 return Cursor
'(Position.Container, Position.Node.Next);
1762 procedure Next_Sibling (Position : in out Cursor) is
1764 Position := Next_Sibling (Position);
1771 function Node_Count (Container : Tree) return Count_Type is
1773 -- Container.Count is the number of nodes we have actually allocated. We
1774 -- cache the value specifically so this Node_Count operation can execute
1775 -- in O(1) time, which makes it behave similarly to how the Length
1776 -- selector function behaves for other containers.
1778 -- The cached node count value only describes the nodes we have
1779 -- allocated; the root node itself is not included in that count. The
1780 -- Node_Count operation returns a value that includes the root node
1781 -- (because the RM says so), so we must add 1 to our cached value.
1783 return 1 + Container.Count;
1790 function Parent (Position : Cursor) return Cursor is
1792 if Position = No_Element then
1796 if Position.Node.Parent = null then
1800 return Cursor'(Position
.Container
, Position
.Node
.Parent
);
1807 procedure Prepend_Child
1808 (Container
: in out Tree
;
1810 New_Item
: Element_Type
;
1811 Count
: Count_Type
:= 1)
1813 First
, Last
: Tree_Node_Access
;
1814 Element
: Element_Access
;
1817 if Parent
= No_Element
then
1818 raise Constraint_Error
with "Parent cursor has no element";
1821 if Parent
.Container
/= Container
'Unrestricted_Access then
1822 raise Program_Error
with "Parent cursor not in container";
1829 if Container
.Busy
> 0 then
1831 with "attempt to tamper with cursors (tree is busy)";
1835 -- The element allocator may need an accessibility check in the case
1836 -- the actual type is class-wide or has access discriminants (see
1837 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
1838 -- allocator in the loop below, because the one in this block would
1839 -- have failed already.
1841 pragma Unsuppress
(Accessibility_Check
);
1844 Element
:= new Element_Type
'(New_Item);
1847 First := new Tree_Node_Type'(Parent
=> Parent
.Node
,
1853 for J
in Count_Type
'(2) .. Count loop
1855 -- Reclaim other nodes if Storage_Error. ???
1857 Element := new Element_Type'(New_Item
);
1858 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
1869 Parent => Parent.Node,
1870 Before => Parent.Node.Children.First);
1872 -- In order for operation Node_Count to complete in O(1) time, we cache
1873 -- the count value. Here we increment the total count by the number of
1874 -- nodes we just inserted.
1876 Container.Count := Container.Count + Count;
1883 overriding function Previous
1884 (Object : Child_Iterator;
1885 Position : Cursor) return Cursor
1888 if Position.Container = null then
1892 if Position.Container /= Object.Container then
1893 raise Program_Error with
1894 "Position cursor of Previous designates wrong tree";
1897 return Previous_Sibling (Position);
1900 ----------------------
1901 -- Previous_Sibling --
1902 ----------------------
1904 function Previous_Sibling (Position : Cursor) return Cursor is
1906 if Position = No_Element then
1910 if Position.Node.Prev = null then
1914 return Cursor'(Position
.Container
, Position
.Node
.Prev
);
1915 end Previous_Sibling
;
1917 procedure Previous_Sibling
(Position
: in out Cursor
) is
1919 Position
:= Previous_Sibling
(Position
);
1920 end Previous_Sibling
;
1926 procedure Query_Element
1928 Process
: not null access procedure (Element
: Element_Type
))
1931 if Position
= No_Element
then
1932 raise Constraint_Error
with "Position cursor has no element";
1935 if Is_Root
(Position
) then
1936 raise Program_Error
with "Position cursor designates root";
1940 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
1941 B
: Natural renames T
.Busy
;
1942 L
: Natural renames T
.Lock
;
1948 Process
(Position
.Node
.Element
.all);
1966 (Stream
: not null access Root_Stream_Type
'Class;
1967 Container
: out Tree
)
1969 procedure Read_Children
(Subtree
: Tree_Node_Access
);
1971 function Read_Subtree
1972 (Parent
: Tree_Node_Access
) return Tree_Node_Access
;
1974 Total_Count
: Count_Type
'Base;
1975 -- Value read from the stream that says how many elements follow
1977 Read_Count
: Count_Type
'Base;
1978 -- Actual number of elements read from the stream
1984 procedure Read_Children
(Subtree
: Tree_Node_Access
) is
1985 pragma Assert
(Subtree
/= null);
1986 pragma Assert
(Subtree
.Children
.First
= null);
1987 pragma Assert
(Subtree
.Children
.Last
= null);
1989 Count
: Count_Type
'Base;
1990 -- Number of child subtrees
1995 Count_Type
'Read (Stream
, Count
);
1998 raise Program_Error
with "attempt to read from corrupt stream";
2005 C
.First
:= Read_Subtree
(Parent
=> Subtree
);
2008 for J
in Count_Type
'(2) .. Count loop
2009 C.Last.Next := Read_Subtree (Parent => Subtree);
2010 C.Last.Next.Prev := C.Last;
2011 C.Last := C.Last.Next;
2014 -- Now that the allocation and reads have completed successfully, it
2015 -- is safe to link the children to their parent.
2017 Subtree.Children := C;
2024 function Read_Subtree
2025 (Parent : Tree_Node_Access) return Tree_Node_Access
2027 Element : constant Element_Access :=
2028 new Element_Type'(Element_Type
'Input (Stream
));
2030 Subtree
: constant Tree_Node_Access
:=
2032 (Parent => Parent, Element => Element, others => <>);
2035 Read_Count := Read_Count + 1;
2037 Read_Children (Subtree);
2042 -- Start of processing for Read
2045 Container.Clear; -- checks busy bit
2047 Count_Type'Read (Stream, Total_Count);
2049 if Total_Count < 0 then
2050 raise Program_Error with "attempt to read from corrupt stream";
2053 if Total_Count = 0 then
2059 Read_Children (Root_Node (Container));
2061 if Read_Count /= Total_Count then
2062 raise Program_Error with "attempt to read from corrupt stream";
2065 Container.Count := Total_Count;
2069 (Stream : not null access Root_Stream_Type'Class;
2070 Position : out Cursor)
2073 raise Program_Error with "attempt to read tree cursor from stream";
2077 (Stream : not null access Root_Stream_Type'Class;
2078 Item : out Reference_Type)
2081 raise Program_Error with "attempt to stream reference";
2085 (Stream : not null access Root_Stream_Type'Class;
2086 Item : out Constant_Reference_Type)
2089 raise Program_Error with "attempt to stream reference";
2097 (Container : aliased in out Tree;
2098 Position : Cursor) return Reference_Type
2101 if Position.Container = null then
2102 raise Constraint_Error with
2103 "Position cursor has no element";
2106 if Position.Container /= Container'Unrestricted_Access then
2107 raise Program_Error with
2108 "Position cursor designates wrong container";
2111 if Position.Node = Root_Node (Container) then
2112 raise Program_Error with "Position cursor designates root";
2115 if Position.Node.Element = null then
2116 raise Program_Error with "Node has no element";
2119 -- Implement Vet for multiway tree???
2120 -- pragma Assert (Vet (Position),
2121 -- "Position cursor in Constant_Reference is bad");
2124 C : Tree renames Position.Container.all;
2125 B : Natural renames C.Busy;
2126 L : Natural renames C.Lock;
2128 return R : constant Reference_Type :=
2129 (Element => Position.Node.Element.all'Access,
2130 Control => (Controlled with Position.Container))
2138 --------------------
2139 -- Remove_Subtree --
2140 --------------------
2142 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2143 C : Children_Type renames Subtree.Parent.Children;
2146 -- This is a utility operation to remove a subtree node from its
2147 -- parent's list of children.
2149 if C.First = Subtree then
2150 pragma Assert (Subtree.Prev = null);
2152 if C.Last = Subtree then
2153 pragma Assert (Subtree.Next = null);
2158 C.First := Subtree.Next;
2159 C.First.Prev := null;
2162 elsif C.Last = Subtree then
2163 pragma Assert (Subtree.Next = null);
2164 C.Last := Subtree.Prev;
2165 C.Last.Next := null;
2168 Subtree.Prev.Next := Subtree.Next;
2169 Subtree.Next.Prev := Subtree.Prev;
2173 ----------------------
2174 -- Replace_Element --
2175 ----------------------
2177 procedure Replace_Element
2178 (Container : in out Tree;
2180 New_Item : Element_Type)
2182 E, X : Element_Access;
2185 if Position = No_Element then
2186 raise Constraint_Error with "Position cursor has no element";
2189 if Position.Container /= Container'Unrestricted_Access then
2190 raise Program_Error with "Position cursor not in container";
2193 if Is_Root (Position) then
2194 raise Program_Error with "Position cursor designates root";
2197 if Container.Lock > 0 then
2199 with "attempt to tamper with elements (tree is locked)";
2203 -- The element allocator may need an accessibility check in the case
2204 -- the actual type is class-wide or has access discriminants (see
2205 -- RM 4.8(10.1) and AI12-0035).
2207 pragma Unsuppress (Accessibility_Check);
2210 E := new Element_Type'(New_Item
);
2213 X
:= Position
.Node
.Element
;
2214 Position
.Node
.Element
:= E
;
2217 end Replace_Element
;
2219 ------------------------------
2220 -- Reverse_Iterate_Children --
2221 ------------------------------
2223 procedure Reverse_Iterate_Children
2225 Process
: not null access procedure (Position
: Cursor
))
2228 if Parent
= No_Element
then
2229 raise Constraint_Error
with "Parent cursor has no element";
2233 B
: Natural renames Parent
.Container
.Busy
;
2234 C
: Tree_Node_Access
;
2239 C
:= Parent
.Node
.Children
.Last
;
2240 while C
/= null loop
2241 Process
(Position
=> Cursor
'(Parent.Container, Node => C));
2252 end Reverse_Iterate_Children;
2258 function Root (Container : Tree) return Cursor is
2260 return (Container'Unrestricted_Access, Root_Node (Container));
2267 function Root_Node (Container : Tree) return Tree_Node_Access is
2269 return Container.Root'Unrestricted_Access;
2272 ---------------------
2273 -- Splice_Children --
2274 ---------------------
2276 procedure Splice_Children
2277 (Target : in out Tree;
2278 Target_Parent : Cursor;
2280 Source : in out Tree;
2281 Source_Parent : Cursor)
2286 if Target_Parent = No_Element then
2287 raise Constraint_Error with "Target_Parent cursor has no element";
2290 if Target_Parent.Container /= Target'Unrestricted_Access then
2292 with "Target_Parent cursor not in Target container";
2295 if Before /= No_Element then
2296 if Before.Container /= Target'Unrestricted_Access then
2298 with "Before cursor not in Target container";
2301 if Before.Node.Parent /= Target_Parent.Node then
2302 raise Constraint_Error
2303 with "Before cursor not child of Target_Parent";
2307 if Source_Parent = No_Element then
2308 raise Constraint_Error with "Source_Parent cursor has no element";
2311 if Source_Parent.Container /= Source'Unrestricted_Access then
2313 with "Source_Parent cursor not in Source container";
2316 if Target'Address = Source'Address then
2317 if Target_Parent = Source_Parent then
2321 if Target.Busy > 0 then
2323 with "attempt to tamper with cursors (Target tree is busy)";
2326 if Is_Reachable (From => Target_Parent.Node,
2327 To => Source_Parent.Node)
2329 raise Constraint_Error
2330 with "Source_Parent is ancestor of Target_Parent";
2334 (Target_Parent => Target_Parent.Node,
2335 Before => Before.Node,
2336 Source_Parent => Source_Parent.Node);
2341 if Target.Busy > 0 then
2343 with "attempt to tamper with cursors (Target tree is busy)";
2346 if Source.Busy > 0 then
2348 with "attempt to tamper with cursors (Source tree is busy)";
2351 -- We cache the count of the nodes we have allocated, so that operation
2352 -- Node_Count can execute in O(1) time. But that means we must count the
2353 -- nodes in the subtree we remove from Source and insert into Target, in
2354 -- order to keep the count accurate.
2356 Count := Subtree_Node_Count (Source_Parent.Node);
2357 pragma Assert (Count >= 1);
2359 Count := Count - 1; -- because Source_Parent node does not move
2362 (Target_Parent => Target_Parent.Node,
2363 Before => Before.Node,
2364 Source_Parent => Source_Parent.Node);
2366 Source.Count := Source.Count - Count;
2367 Target.Count := Target.Count + Count;
2368 end Splice_Children;
2370 procedure Splice_Children
2371 (Container : in out Tree;
2372 Target_Parent : Cursor;
2374 Source_Parent : Cursor)
2377 if Target_Parent = No_Element then
2378 raise Constraint_Error with "Target_Parent cursor has no element";
2381 if Target_Parent.Container /= Container'Unrestricted_Access then
2383 with "Target_Parent cursor not in container";
2386 if Before /= No_Element then
2387 if Before.Container /= Container'Unrestricted_Access then
2389 with "Before cursor not in container";
2392 if Before.Node.Parent /= Target_Parent.Node then
2393 raise Constraint_Error
2394 with "Before cursor not child of Target_Parent";
2398 if Source_Parent = No_Element then
2399 raise Constraint_Error with "Source_Parent cursor has no element";
2402 if Source_Parent.Container /= Container'Unrestricted_Access then
2404 with "Source_Parent cursor not in container";
2407 if Target_Parent = Source_Parent then
2411 if Container.Busy > 0 then
2413 with "attempt to tamper with cursors (tree is busy)";
2416 if Is_Reachable (From => Target_Parent.Node,
2417 To => Source_Parent.Node)
2419 raise Constraint_Error
2420 with "Source_Parent is ancestor of Target_Parent";
2424 (Target_Parent => Target_Parent.Node,
2425 Before => Before.Node,
2426 Source_Parent => Source_Parent.Node);
2427 end Splice_Children;
2429 procedure Splice_Children
2430 (Target_Parent : Tree_Node_Access;
2431 Before : Tree_Node_Access;
2432 Source_Parent : Tree_Node_Access)
2434 CC : constant Children_Type := Source_Parent.Children;
2435 C : Tree_Node_Access;
2438 -- This is a utility operation to remove the children from Source parent
2439 -- and insert them into Target parent.
2441 Source_Parent.Children := Children_Type'(others => null);
2443 -- Fix up the Parent pointers of each child to designate its new Target
2447 while C
/= null loop
2448 C
.Parent
:= Target_Parent
;
2455 Parent
=> Target_Parent
,
2457 end Splice_Children
;
2459 --------------------
2460 -- Splice_Subtree --
2461 --------------------
2463 procedure Splice_Subtree
2464 (Target
: in out Tree
;
2467 Source
: in out Tree
;
2468 Position
: in out Cursor
)
2470 Subtree_Count
: Count_Type
;
2473 if Parent
= No_Element
then
2474 raise Constraint_Error
with "Parent cursor has no element";
2477 if Parent
.Container
/= Target
'Unrestricted_Access then
2478 raise Program_Error
with "Parent cursor not in Target container";
2481 if Before
/= No_Element
then
2482 if Before
.Container
/= Target
'Unrestricted_Access then
2483 raise Program_Error
with "Before cursor not in Target container";
2486 if Before
.Node
.Parent
/= Parent
.Node
then
2487 raise Constraint_Error
with "Before cursor not child of Parent";
2491 if Position
= No_Element
then
2492 raise Constraint_Error
with "Position cursor has no element";
2495 if Position
.Container
/= Source
'Unrestricted_Access then
2496 raise Program_Error
with "Position cursor not in Source container";
2499 if Is_Root
(Position
) then
2500 raise Program_Error
with "Position cursor designates root";
2503 if Target
'Address = Source
'Address then
2504 if Position
.Node
.Parent
= Parent
.Node
then
2505 if Position
.Node
= Before
.Node
then
2509 if Position
.Node
.Next
= Before
.Node
then
2514 if Target
.Busy
> 0 then
2516 with "attempt to tamper with cursors (Target tree is busy)";
2519 if Is_Reachable
(From
=> Parent
.Node
, To
=> Position
.Node
) then
2520 raise Constraint_Error
with "Position is ancestor of Parent";
2523 Remove_Subtree
(Position
.Node
);
2525 Position
.Node
.Parent
:= Parent
.Node
;
2526 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2531 if Target
.Busy
> 0 then
2533 with "attempt to tamper with cursors (Target tree is busy)";
2536 if Source
.Busy
> 0 then
2538 with "attempt to tamper with cursors (Source tree is busy)";
2541 -- This is an unfortunate feature of this API: we must count the nodes
2542 -- in the subtree that we remove from the source tree, which is an O(n)
2543 -- operation. It would have been better if the Tree container did not
2544 -- have a Node_Count selector; a user that wants the number of nodes in
2545 -- the tree could simply call Subtree_Node_Count, with the understanding
2546 -- that such an operation is O(n).
2548 -- Of course, we could choose to implement the Node_Count selector as an
2549 -- O(n) operation, which would turn this splice operation into an O(1)
2552 Subtree_Count
:= Subtree_Node_Count
(Position
.Node
);
2553 pragma Assert
(Subtree_Count
<= Source
.Count
);
2555 Remove_Subtree
(Position
.Node
);
2556 Source
.Count
:= Source
.Count
- Subtree_Count
;
2558 Position
.Node
.Parent
:= Parent
.Node
;
2559 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2561 Target
.Count
:= Target
.Count
+ Subtree_Count
;
2563 Position
.Container
:= Target
'Unrestricted_Access;
2566 procedure Splice_Subtree
2567 (Container
: in out Tree
;
2573 if Parent
= No_Element
then
2574 raise Constraint_Error
with "Parent cursor has no element";
2577 if Parent
.Container
/= Container
'Unrestricted_Access then
2578 raise Program_Error
with "Parent cursor not in container";
2581 if Before
/= No_Element
then
2582 if Before
.Container
/= Container
'Unrestricted_Access then
2583 raise Program_Error
with "Before cursor not in container";
2586 if Before
.Node
.Parent
/= Parent
.Node
then
2587 raise Constraint_Error
with "Before cursor not child of Parent";
2591 if Position
= No_Element
then
2592 raise Constraint_Error
with "Position cursor has no element";
2595 if Position
.Container
/= Container
'Unrestricted_Access then
2596 raise Program_Error
with "Position cursor not in container";
2599 if Is_Root
(Position
) then
2601 -- Should this be PE instead? Need ARG confirmation. ???
2603 raise Constraint_Error
with "Position cursor designates root";
2606 if Position
.Node
.Parent
= Parent
.Node
then
2607 if Position
.Node
= Before
.Node
then
2611 if Position
.Node
.Next
= Before
.Node
then
2616 if Container
.Busy
> 0 then
2618 with "attempt to tamper with cursors (tree is busy)";
2621 if Is_Reachable
(From
=> Parent
.Node
, To
=> Position
.Node
) then
2622 raise Constraint_Error
with "Position is ancestor of Parent";
2625 Remove_Subtree
(Position
.Node
);
2627 Position
.Node
.Parent
:= Parent
.Node
;
2628 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2631 ------------------------
2632 -- Subtree_Node_Count --
2633 ------------------------
2635 function Subtree_Node_Count
(Position
: Cursor
) return Count_Type
is
2637 if Position
= No_Element
then
2641 return Subtree_Node_Count
(Position
.Node
);
2642 end Subtree_Node_Count
;
2644 function Subtree_Node_Count
2645 (Subtree
: Tree_Node_Access
) return Count_Type
2647 Result
: Count_Type
;
2648 Node
: Tree_Node_Access
;
2652 Node
:= Subtree
.Children
.First
;
2653 while Node
/= null loop
2654 Result
:= Result
+ Subtree_Node_Count
(Node
);
2659 end Subtree_Node_Count
;
2666 (Container
: in out Tree
;
2670 if I
= No_Element
then
2671 raise Constraint_Error
with "I cursor has no element";
2674 if I
.Container
/= Container
'Unrestricted_Access then
2675 raise Program_Error
with "I cursor not in container";
2679 raise Program_Error
with "I cursor designates root";
2682 if I
= J
then -- make this test sooner???
2686 if J
= No_Element
then
2687 raise Constraint_Error
with "J cursor has no element";
2690 if J
.Container
/= Container
'Unrestricted_Access then
2691 raise Program_Error
with "J cursor not in container";
2695 raise Program_Error
with "J cursor designates root";
2698 if Container
.Lock
> 0 then
2700 with "attempt to tamper with elements (tree is locked)";
2704 EI
: constant Element_Access
:= I
.Node
.Element
;
2707 I
.Node
.Element
:= J
.Node
.Element
;
2708 J
.Node
.Element
:= EI
;
2712 --------------------
2713 -- Update_Element --
2714 --------------------
2716 procedure Update_Element
2717 (Container
: in out Tree
;
2719 Process
: not null access procedure (Element
: in out Element_Type
))
2722 if Position
= No_Element
then
2723 raise Constraint_Error
with "Position cursor has no element";
2726 if Position
.Container
/= Container
'Unrestricted_Access then
2727 raise Program_Error
with "Position cursor not in container";
2730 if Is_Root
(Position
) then
2731 raise Program_Error
with "Position cursor designates root";
2735 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
2736 B
: Natural renames T
.Busy
;
2737 L
: Natural renames T
.Lock
;
2743 Process
(Position
.Node
.Element
.all);
2762 (Stream
: not null access Root_Stream_Type
'Class;
2765 procedure Write_Children
(Subtree
: Tree_Node_Access
);
2766 procedure Write_Subtree
(Subtree
: Tree_Node_Access
);
2768 --------------------
2769 -- Write_Children --
2770 --------------------
2772 procedure Write_Children
(Subtree
: Tree_Node_Access
) is
2773 CC
: Children_Type
renames Subtree
.Children
;
2774 C
: Tree_Node_Access
;
2777 Count_Type
'Write (Stream
, Child_Count
(CC
));
2780 while C
/= null loop
2790 procedure Write_Subtree
(Subtree
: Tree_Node_Access
) is
2792 Element_Type
'Output (Stream
, Subtree
.Element
.all);
2793 Write_Children
(Subtree
);
2796 -- Start of processing for Write
2799 Count_Type
'Write (Stream
, Container
.Count
);
2801 if Container
.Count
= 0 then
2805 Write_Children
(Root_Node
(Container
));
2809 (Stream
: not null access Root_Stream_Type
'Class;
2813 raise Program_Error
with "attempt to write tree cursor to stream";
2817 (Stream
: not null access Root_Stream_Type
'Class;
2818 Item
: Reference_Type
)
2821 raise Program_Error
with "attempt to stream reference";
2825 (Stream
: not null access Root_Stream_Type
'Class;
2826 Item
: Constant_Reference_Type
)
2829 raise Program_Error
with "attempt to stream reference";
2832 end Ada
.Containers
.Indefinite_Multiway_Trees
;