1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . M U L T I W A Y _ T R E E S --
9 -- Copyright (C) 2004-2016, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada
.Unchecked_Conversion
;
31 with Ada
.Unchecked_Deallocation
;
33 with System
; use type System
.Address
;
35 package body Ada
.Containers
.Multiway_Trees
is
37 pragma Warnings
(Off
, "variable ""Busy*"" is not referenced");
38 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
39 -- See comment in Ada.Containers.Helpers
45 type Root_Iterator
is abstract new Limited_Controlled
and
46 Tree_Iterator_Interfaces
.Forward_Iterator
with
48 Container
: Tree_Access
;
49 Subtree
: Tree_Node_Access
;
51 with Disable_Controlled
=> not T_Check
;
53 overriding
procedure Finalize
(Object
: in out Root_Iterator
);
55 -----------------------
56 -- Subtree_Iterator --
57 -----------------------
59 -- ??? these headers are a bit odd, but for sure they do not substitute
60 -- for documenting things, what *is* a Subtree_Iterator?
62 type Subtree_Iterator
is new Root_Iterator
with null record;
64 overriding
function First
(Object
: Subtree_Iterator
) return Cursor
;
66 overriding
function Next
67 (Object
: Subtree_Iterator
;
68 Position
: Cursor
) return Cursor
;
74 type Child_Iterator
is new Root_Iterator
and
75 Tree_Iterator_Interfaces
.Reversible_Iterator
with null record
76 with Disable_Controlled
=> not T_Check
;
78 overriding
function First
(Object
: Child_Iterator
) return Cursor
;
80 overriding
function Next
81 (Object
: Child_Iterator
;
82 Position
: Cursor
) return Cursor
;
84 overriding
function Last
(Object
: Child_Iterator
) return Cursor
;
86 overriding
function Previous
87 (Object
: Child_Iterator
;
88 Position
: Cursor
) return Cursor
;
90 -----------------------
91 -- Local Subprograms --
92 -----------------------
94 function Root_Node
(Container
: Tree
) return Tree_Node_Access
;
96 procedure Deallocate_Node
is
97 new Ada
.Unchecked_Deallocation
(Tree_Node_Type
, Tree_Node_Access
);
99 procedure Deallocate_Children
100 (Subtree
: Tree_Node_Access
;
101 Count
: in out Count_Type
);
103 procedure Deallocate_Subtree
104 (Subtree
: in out Tree_Node_Access
;
105 Count
: in out Count_Type
);
107 function Equal_Children
108 (Left_Subtree
, Right_Subtree
: Tree_Node_Access
) return Boolean;
110 function Equal_Subtree
111 (Left_Subtree
, Right_Subtree
: Tree_Node_Access
) return Boolean;
113 procedure Iterate_Children
114 (Container
: Tree_Access
;
115 Subtree
: Tree_Node_Access
;
116 Process
: not null access procedure (Position
: Cursor
));
118 procedure Iterate_Subtree
119 (Container
: Tree_Access
;
120 Subtree
: Tree_Node_Access
;
121 Process
: not null access procedure (Position
: Cursor
));
123 procedure Copy_Children
124 (Source
: Children_Type
;
125 Parent
: Tree_Node_Access
;
126 Count
: in out Count_Type
);
128 procedure Copy_Subtree
129 (Source
: Tree_Node_Access
;
130 Parent
: Tree_Node_Access
;
131 Target
: out Tree_Node_Access
;
132 Count
: in out Count_Type
);
134 function Find_In_Children
135 (Subtree
: Tree_Node_Access
;
136 Item
: Element_Type
) return Tree_Node_Access
;
138 function Find_In_Subtree
139 (Subtree
: Tree_Node_Access
;
140 Item
: Element_Type
) return Tree_Node_Access
;
142 function Child_Count
(Children
: Children_Type
) return Count_Type
;
144 function Subtree_Node_Count
145 (Subtree
: Tree_Node_Access
) return Count_Type
;
147 function Is_Reachable
(From
, To
: Tree_Node_Access
) return Boolean;
149 procedure Remove_Subtree
(Subtree
: Tree_Node_Access
);
151 procedure Insert_Subtree_Node
152 (Subtree
: Tree_Node_Access
;
153 Parent
: Tree_Node_Access
;
154 Before
: Tree_Node_Access
);
156 procedure Insert_Subtree_List
157 (First
: Tree_Node_Access
;
158 Last
: Tree_Node_Access
;
159 Parent
: Tree_Node_Access
;
160 Before
: Tree_Node_Access
);
162 procedure Splice_Children
163 (Target_Parent
: Tree_Node_Access
;
164 Before
: Tree_Node_Access
;
165 Source_Parent
: Tree_Node_Access
);
171 function "=" (Left
, Right
: Tree
) return Boolean is
173 return Equal_Children
(Root_Node
(Left
), Root_Node
(Right
));
180 procedure Adjust
(Container
: in out Tree
) is
181 Source
: constant Children_Type
:= Container
.Root
.Children
;
182 Source_Count
: constant Count_Type
:= Container
.Count
;
183 Target_Count
: Count_Type
;
186 -- We first restore the target container to its default-initialized
187 -- state, before we attempt any allocation, to ensure that invariants
188 -- are preserved in the event that the allocation fails.
190 Container
.Root
.Children
:= Children_Type
'(others => null);
191 Zero_Counts (Container.TC);
192 Container.Count := 0;
194 -- Copy_Children returns a count of the number of nodes that it
195 -- allocates, but it works by incrementing the value that is passed
196 -- in. We must therefore initialize the count value before calling
201 -- Now we attempt the allocation of subtrees. The invariants are
202 -- satisfied even if the allocation fails.
204 Copy_Children (Source, Root_Node (Container), Target_Count);
205 pragma Assert (Target_Count = Source_Count);
207 Container.Count := Source_Count;
214 function Ancestor_Find
216 Item : Element_Type) return Cursor
218 R, N : Tree_Node_Access;
221 if Checks and then Position = No_Element then
222 raise Constraint_Error with "Position cursor has no element";
225 -- Commented-out pending official ruling from ARG. ???
227 -- if Position.Container /= Container'Unrestricted_Access then
228 -- raise Program_Error with "Position cursor not in container";
231 -- AI-0136 says to raise PE if Position equals the root node. This does
232 -- not seem correct, as this value is just the limiting condition of the
233 -- search. For now we omit this check, pending a ruling from the ARG.???
235 -- if Checks and then Is_Root (Position) then
236 -- raise Program_Error with "Position cursor designates root";
239 R := Root_Node (Position.Container.all);
242 if N.Element = Item then
243 return Cursor'(Position
.Container
, N
);
256 procedure Append_Child
257 (Container
: in out Tree
;
259 New_Item
: Element_Type
;
260 Count
: Count_Type
:= 1)
262 First
: Tree_Node_Access
;
263 Last
: Tree_Node_Access
;
266 if Checks
and then Parent
= No_Element
then
267 raise Constraint_Error
with "Parent cursor has no element";
270 if Checks
and then Parent
.Container
/= Container
'Unrestricted_Access then
271 raise Program_Error
with "Parent cursor not in container";
278 TC_Check
(Container
.TC
);
280 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
285 for J in Count_Type'(2) .. Count
loop
287 -- Reclaim other nodes if Storage_Error. ???
289 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
300 Parent => Parent.Node,
301 Before => null); -- null means "insert at end of list"
303 -- In order for operation Node_Count to complete in O(1) time, we cache
304 -- the count value. Here we increment the total count by the number of
305 -- nodes we just inserted.
307 Container.Count := Container.Count + Count;
314 procedure Assign (Target : in out Tree; Source : Tree) is
315 Source_Count : constant Count_Type := Source.Count;
316 Target_Count : Count_Type;
319 if Target'Address = Source'Address then
323 Target.Clear; -- checks busy bit
325 -- Copy_Children returns the number of nodes that it allocates, but it
326 -- does this by incrementing the count value passed in, so we must
327 -- initialize the count before calling Copy_Children.
331 -- Note that Copy_Children inserts the newly-allocated children into
332 -- their parent list only after the allocation of all the children has
333 -- succeeded. This preserves invariants even if the allocation fails.
335 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
336 pragma Assert (Target_Count = Source_Count);
338 Target.Count := Source_Count;
345 function Child_Count (Parent : Cursor) return Count_Type is
347 return (if Parent = No_Element
348 then 0 else Child_Count (Parent.Node.Children));
351 function Child_Count (Children : Children_Type) return Count_Type is
353 Node : Tree_Node_Access;
357 Node := Children.First;
358 while Node /= null loop
359 Result := Result + 1;
370 function Child_Depth (Parent, Child : Cursor) return Count_Type is
372 N : Tree_Node_Access;
375 if Checks and then Parent = No_Element then
376 raise Constraint_Error with "Parent cursor has no element";
379 if Checks and then Child = No_Element then
380 raise Constraint_Error with "Child cursor has no element";
383 if Checks and then Parent.Container /= Child.Container then
384 raise Program_Error with "Parent and Child in different containers";
389 while N /= Parent.Node loop
390 Result := Result + 1;
393 if Checks and then N = null then
394 raise Program_Error with "Parent is not ancestor of Child";
405 procedure Clear (Container : in out Tree) is
406 Container_Count, Children_Count : Count_Type;
409 TC_Check (Container.TC);
411 -- We first set the container count to 0, in order to preserve
412 -- invariants in case the deallocation fails. (This works because
413 -- Deallocate_Children immediately removes the children from their
414 -- parent, and then does the actual deallocation.)
416 Container_Count := Container.Count;
417 Container.Count := 0;
419 -- Deallocate_Children returns the number of nodes that it deallocates,
420 -- but it does this by incrementing the count value that is passed in,
421 -- so we must first initialize the count return value before calling it.
425 -- See comment above. Deallocate_Children immediately removes the
426 -- children list from their parent node (here, the root of the tree),
427 -- and only after that does it attempt the actual deallocation. So even
428 -- if the deallocation fails, the representation invariants for the tree
431 Deallocate_Children (Root_Node (Container), Children_Count);
432 pragma Assert (Children_Count = Container_Count);
435 ------------------------
436 -- Constant_Reference --
437 ------------------------
439 function Constant_Reference
440 (Container : aliased Tree;
441 Position : Cursor) return Constant_Reference_Type
444 if Checks and then Position.Container = null then
445 raise Constraint_Error with
446 "Position cursor has no element";
449 if Checks and then Position.Container /= Container'Unrestricted_Access
451 raise Program_Error with
452 "Position cursor designates wrong container";
455 if Checks and then Position.Node = Root_Node (Container) then
456 raise Program_Error with "Position cursor designates root";
459 -- Implement Vet for multiway tree???
460 -- pragma Assert (Vet (Position),
461 -- "Position cursor in Constant_Reference is bad");
464 C : Tree renames Position.Container.all;
465 TC : constant Tamper_Counts_Access :=
466 C.TC'Unrestricted_Access;
468 return R : constant Constant_Reference_Type :=
469 (Element => Position.Node.Element'Access,
470 Control => (Controlled with TC))
475 end Constant_Reference;
483 Item : Element_Type) return Boolean
486 return Find (Container, Item) /= No_Element;
493 function Copy (Source : Tree) return Tree is
495 return Target : Tree do
497 (Source => Source.Root.Children,
498 Parent => Root_Node (Target),
499 Count => Target.Count);
501 pragma Assert (Target.Count = Source.Count);
509 procedure Copy_Children
510 (Source : Children_Type;
511 Parent : Tree_Node_Access;
512 Count : in out Count_Type)
514 pragma Assert (Parent /= null);
515 pragma Assert (Parent.Children.First = null);
516 pragma Assert (Parent.Children.Last = null);
519 C : Tree_Node_Access;
522 -- We special-case the first allocation, in order to establish the
523 -- representation invariants for type Children_Type.
539 -- The representation invariants for the Children_Type list have been
540 -- established, so we can now copy the remaining children of Source.
547 Target => CC.Last.Next,
550 CC.Last.Next.Prev := CC.Last;
551 CC.Last := CC.Last.Next;
556 -- Add the newly-allocated children to their parent list only after the
557 -- allocation has succeeded, so as to preserve invariants of the parent.
559 Parent.Children := CC;
566 procedure Copy_Subtree
567 (Target : in out Tree;
572 Target_Subtree : Tree_Node_Access;
573 Target_Count : Count_Type;
576 if Checks and then Parent = No_Element then
577 raise Constraint_Error with "Parent cursor has no element";
580 if Checks and then Parent.Container /= Target'Unrestricted_Access then
581 raise Program_Error with "Parent cursor not in container";
584 if Before /= No_Element then
585 if Checks and then Before.Container /= Target'Unrestricted_Access then
586 raise Program_Error with "Before cursor not in container";
589 if Checks and then Before.Node.Parent /= Parent.Node then
590 raise Constraint_Error with "Before cursor not child of Parent";
594 if Source = No_Element then
598 if Checks and then Is_Root (Source) then
599 raise Constraint_Error with "Source cursor designates root";
602 -- Copy_Subtree returns a count of the number of nodes that it
603 -- allocates, but it works by incrementing the value that is passed
604 -- in. We must therefore initialize the count value before calling
610 (Source => Source.Node,
611 Parent => Parent.Node,
612 Target => Target_Subtree,
613 Count => Target_Count);
615 pragma Assert (Target_Subtree /= null);
616 pragma Assert (Target_Subtree.Parent = Parent.Node);
617 pragma Assert (Target_Count >= 1);
620 (Subtree => Target_Subtree,
621 Parent => Parent.Node,
622 Before => Before.Node);
624 -- In order for operation Node_Count to complete in O(1) time, we cache
625 -- the count value. Here we increment the total count by the number of
626 -- nodes we just inserted.
628 Target.Count := Target.Count + Target_Count;
631 procedure Copy_Subtree
632 (Source : Tree_Node_Access;
633 Parent : Tree_Node_Access;
634 Target : out Tree_Node_Access;
635 Count : in out Count_Type)
638 Target := new Tree_Node_Type'(Element
=> Source
.Element
,
645 (Source
=> Source
.Children
,
650 -------------------------
651 -- Deallocate_Children --
652 -------------------------
654 procedure Deallocate_Children
655 (Subtree
: Tree_Node_Access
;
656 Count
: in out Count_Type
)
658 pragma Assert
(Subtree
/= null);
660 CC
: Children_Type
:= Subtree
.Children
;
661 C
: Tree_Node_Access
;
664 -- We immediately remove the children from their parent, in order to
665 -- preserve invariants in case the deallocation fails.
667 Subtree
.Children
:= Children_Type
'(others => null);
669 while CC.First /= null loop
673 Deallocate_Subtree (C, Count);
675 end Deallocate_Children;
677 ------------------------
678 -- Deallocate_Subtree --
679 ------------------------
681 procedure Deallocate_Subtree
682 (Subtree : in out Tree_Node_Access;
683 Count : in out Count_Type)
686 Deallocate_Children (Subtree, Count);
687 Deallocate_Node (Subtree);
689 end Deallocate_Subtree;
691 ---------------------
692 -- Delete_Children --
693 ---------------------
695 procedure Delete_Children
696 (Container : in out Tree;
702 if Checks and then Parent = No_Element then
703 raise Constraint_Error with "Parent cursor has no element";
706 if Checks and then Parent.Container /= Container'Unrestricted_Access then
707 raise Program_Error with "Parent cursor not in container";
710 TC_Check (Container.TC);
712 -- Deallocate_Children returns a count of the number of nodes that it
713 -- deallocates, but it works by incrementing the value that is passed
714 -- in. We must therefore initialize the count value before calling
715 -- Deallocate_Children.
719 Deallocate_Children (Parent.Node, Count);
720 pragma Assert (Count <= Container.Count);
722 Container.Count := Container.Count - Count;
729 procedure Delete_Leaf
730 (Container : in out Tree;
731 Position : in out Cursor)
733 X : Tree_Node_Access;
736 if Checks and then Position = No_Element then
737 raise Constraint_Error with "Position cursor has no element";
740 if Checks and then Position.Container /= Container'Unrestricted_Access
742 raise Program_Error with "Position cursor not in container";
745 if Checks and then Is_Root (Position) then
746 raise Program_Error with "Position cursor designates root";
749 if Checks and then not Is_Leaf (Position) then
750 raise Constraint_Error with "Position cursor does not designate leaf";
753 TC_Check (Container.TC);
756 Position := No_Element;
758 -- Restore represention invariants before attempting the actual
762 Container.Count := Container.Count - 1;
764 -- It is now safe to attempt the deallocation. This leaf node has been
765 -- disassociated from the tree, so even if the deallocation fails,
766 -- representation invariants will remain satisfied.
775 procedure Delete_Subtree
776 (Container : in out Tree;
777 Position : in out Cursor)
779 X : Tree_Node_Access;
783 if Checks and then Position = No_Element then
784 raise Constraint_Error with "Position cursor has no element";
787 if Checks and then Position.Container /= Container'Unrestricted_Access
789 raise Program_Error with "Position cursor not in container";
792 if Checks and then Is_Root (Position) then
793 raise Program_Error with "Position cursor designates root";
796 TC_Check (Container.TC);
799 Position := No_Element;
801 -- Here is one case where a deallocation failure can result in the
802 -- violation of a representation invariant. We disassociate the subtree
803 -- from the tree now, but we only decrement the total node count after
804 -- we attempt the deallocation. However, if the deallocation fails, the
805 -- total node count will not get decremented.
807 -- One way around this dilemma is to count the nodes in the subtree
808 -- before attempt to delete the subtree, but that is an O(n) operation,
809 -- so it does not seem worth it.
811 -- Perhaps this is much ado about nothing, since the only way
812 -- deallocation can fail is if Controlled Finalization fails: this
813 -- propagates Program_Error so all bets are off anyway. ???
817 -- Deallocate_Subtree returns a count of the number of nodes that it
818 -- deallocates, but it works by incrementing the value that is passed
819 -- in. We must therefore initialize the count value before calling
820 -- Deallocate_Subtree.
824 Deallocate_Subtree (X, Count);
825 pragma Assert (Count <= Container.Count);
827 -- See comments above. We would prefer to do this sooner, but there's no
828 -- way to satisfy that goal without a potentially severe execution
831 Container.Count := Container.Count - Count;
838 function Depth (Position : Cursor) return Count_Type is
840 N : Tree_Node_Access;
847 Result := Result + 1;
857 function Element (Position : Cursor) return Element_Type is
859 if Checks and then Position.Container = null then
860 raise Constraint_Error with "Position cursor has no element";
863 if Checks and then Position.Node = Root_Node (Position.Container.all)
865 raise Program_Error with "Position cursor designates root";
868 return Position.Node.Element;
875 function Equal_Children
876 (Left_Subtree : Tree_Node_Access;
877 Right_Subtree : Tree_Node_Access) return Boolean
879 Left_Children : Children_Type renames Left_Subtree.Children;
880 Right_Children : Children_Type renames Right_Subtree.Children;
882 L, R : Tree_Node_Access;
885 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
889 L := Left_Children.First;
890 R := Right_Children.First;
892 if not Equal_Subtree (L, R) then
907 function Equal_Subtree
908 (Left_Position : Cursor;
909 Right_Position : Cursor) return Boolean
912 if Checks and then Left_Position = No_Element then
913 raise Constraint_Error with "Left cursor has no element";
916 if Checks and then Right_Position = No_Element then
917 raise Constraint_Error with "Right cursor has no element";
920 if Left_Position = Right_Position then
924 if Is_Root (Left_Position) then
925 if not Is_Root (Right_Position) then
929 return Equal_Children (Left_Position.Node, Right_Position.Node);
932 if Is_Root (Right_Position) then
936 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
939 function Equal_Subtree
940 (Left_Subtree : Tree_Node_Access;
941 Right_Subtree : Tree_Node_Access) return Boolean
944 if Left_Subtree.Element /= Right_Subtree.Element then
948 return Equal_Children (Left_Subtree, Right_Subtree);
955 procedure Finalize (Object : in out Root_Iterator) is
957 Unbusy (Object.Container.TC);
966 Item : Element_Type) return Cursor
968 N : constant Tree_Node_Access :=
969 Find_In_Children (Root_Node (Container), Item);
974 return Cursor'(Container
'Unrestricted_Access, N
);
982 overriding
function First
(Object
: Subtree_Iterator
) return Cursor
is
984 if Object
.Subtree
= Root_Node
(Object
.Container
.all) then
985 return First_Child
(Root
(Object
.Container
.all));
987 return Cursor
'(Object.Container, Object.Subtree);
991 overriding function First (Object : Child_Iterator) return Cursor is
993 return First_Child (Cursor'(Object
.Container
, Object
.Subtree
));
1000 function First_Child
(Parent
: Cursor
) return Cursor
is
1001 Node
: Tree_Node_Access
;
1004 if Checks
and then Parent
= No_Element
then
1005 raise Constraint_Error
with "Parent cursor has no element";
1008 Node
:= Parent
.Node
.Children
.First
;
1014 return Cursor
'(Parent.Container, Node);
1017 -------------------------
1018 -- First_Child_Element --
1019 -------------------------
1021 function First_Child_Element (Parent : Cursor) return Element_Type is
1023 return Element (First_Child (Parent));
1024 end First_Child_Element;
1026 ----------------------
1027 -- Find_In_Children --
1028 ----------------------
1030 function Find_In_Children
1031 (Subtree : Tree_Node_Access;
1032 Item : Element_Type) return Tree_Node_Access
1034 N, Result : Tree_Node_Access;
1037 N := Subtree.Children.First;
1038 while N /= null loop
1039 Result := Find_In_Subtree (N, Item);
1041 if Result /= null then
1049 end Find_In_Children;
1051 ---------------------
1052 -- Find_In_Subtree --
1053 ---------------------
1055 function Find_In_Subtree
1057 Item : Element_Type) return Cursor
1059 Result : Tree_Node_Access;
1062 if Checks and then Position = No_Element then
1063 raise Constraint_Error with "Position cursor has no element";
1066 -- Commented out pending official ruling by ARG. ???
1068 -- if Checks and then
1069 -- Position.Container /= Container'Unrestricted_Access
1071 -- raise Program_Error with "Position cursor not in container";
1075 (if Is_Root (Position)
1076 then Find_In_Children (Position.Node, Item)
1077 else Find_In_Subtree (Position.Node, Item));
1079 if Result = null then
1083 return Cursor'(Position
.Container
, Result
);
1084 end Find_In_Subtree
;
1086 function Find_In_Subtree
1087 (Subtree
: Tree_Node_Access
;
1088 Item
: Element_Type
) return Tree_Node_Access
1091 if Subtree
.Element
= Item
then
1095 return Find_In_Children
(Subtree
, Item
);
1096 end Find_In_Subtree
;
1098 ------------------------
1099 -- Get_Element_Access --
1100 ------------------------
1102 function Get_Element_Access
1103 (Position
: Cursor
) return not null Element_Access
is
1105 return Position
.Node
.Element
'Access;
1106 end Get_Element_Access
;
1112 function Has_Element
(Position
: Cursor
) return Boolean is
1114 return (if Position
= No_Element
then False
1115 else Position
.Node
.Parent
/= null);
1122 procedure Insert_Child
1123 (Container
: in out Tree
;
1126 New_Item
: Element_Type
;
1127 Count
: Count_Type
:= 1)
1130 pragma Unreferenced
(Position
);
1133 Insert_Child
(Container
, Parent
, Before
, New_Item
, Position
, Count
);
1136 procedure Insert_Child
1137 (Container
: in out Tree
;
1140 New_Item
: Element_Type
;
1141 Position
: out Cursor
;
1142 Count
: Count_Type
:= 1)
1144 First
: Tree_Node_Access
;
1145 Last
: Tree_Node_Access
;
1148 if Checks
and then Parent
= No_Element
then
1149 raise Constraint_Error
with "Parent cursor has no element";
1152 if Checks
and then Parent
.Container
/= Container
'Unrestricted_Access then
1153 raise Program_Error
with "Parent cursor not in container";
1156 if Before
/= No_Element
then
1157 if Checks
and then Before
.Container
/= Container
'Unrestricted_Access
1159 raise Program_Error
with "Before cursor not in container";
1162 if Checks
and then Before
.Node
.Parent
/= Parent
.Node
then
1163 raise Constraint_Error
with "Parent cursor not parent of Before";
1168 Position
:= No_Element
; -- Need ruling from ARG ???
1172 TC_Check
(Container
.TC
);
1174 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
1175 Element => New_Item,
1179 for J in Count_Type'(2) .. Count
loop
1181 -- Reclaim other nodes if Storage_Error. ???
1183 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
1185 Element => New_Item,
1194 Parent => Parent.Node,
1195 Before => Before.Node);
1197 -- In order for operation Node_Count to complete in O(1) time, we cache
1198 -- the count value. Here we increment the total count by the number of
1199 -- nodes we just inserted.
1201 Container.Count := Container.Count + Count;
1203 Position := Cursor'(Parent
.Container
, First
);
1206 procedure Insert_Child
1207 (Container
: in out Tree
;
1210 Position
: out Cursor
;
1211 Count
: Count_Type
:= 1)
1213 First
: Tree_Node_Access
;
1214 Last
: Tree_Node_Access
;
1217 if Checks
and then Parent
= No_Element
then
1218 raise Constraint_Error
with "Parent cursor has no element";
1221 if Checks
and then Parent
.Container
/= Container
'Unrestricted_Access then
1222 raise Program_Error
with "Parent cursor not in container";
1225 if Before
/= No_Element
then
1226 if Checks
and then Before
.Container
/= Container
'Unrestricted_Access
1228 raise Program_Error
with "Before cursor not in container";
1231 if Checks
and then Before
.Node
.Parent
/= Parent
.Node
then
1232 raise Constraint_Error
with "Parent cursor not parent of Before";
1237 Position
:= No_Element
; -- Need ruling from ARG ???
1241 TC_Check
(Container
.TC
);
1243 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
1248 for J in Count_Type'(2) .. Count
loop
1250 -- Reclaim other nodes if Storage_Error. ???
1252 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
1263 Parent => Parent.Node,
1264 Before => Before.Node);
1266 -- In order for operation Node_Count to complete in O(1) time, we cache
1267 -- the count value. Here we increment the total count by the number of
1268 -- nodes we just inserted.
1270 Container.Count := Container.Count + Count;
1272 Position := Cursor'(Parent
.Container
, First
);
1275 -------------------------
1276 -- Insert_Subtree_List --
1277 -------------------------
1279 procedure Insert_Subtree_List
1280 (First
: Tree_Node_Access
;
1281 Last
: Tree_Node_Access
;
1282 Parent
: Tree_Node_Access
;
1283 Before
: Tree_Node_Access
)
1285 pragma Assert
(Parent
/= null);
1286 C
: Children_Type
renames Parent
.Children
;
1289 -- This is a simple utility operation to insert a list of nodes (from
1290 -- First..Last) as children of Parent. The Before node specifies where
1291 -- the new children should be inserted relative to the existing
1294 if First
= null then
1295 pragma Assert
(Last
= null);
1299 pragma Assert
(Last
/= null);
1300 pragma Assert
(Before
= null or else Before
.Parent
= Parent
);
1302 if C
.First
= null then
1304 C
.First
.Prev
:= null;
1306 C
.Last
.Next
:= null;
1308 elsif Before
= null then -- means "insert after existing nodes"
1309 C
.Last
.Next
:= First
;
1310 First
.Prev
:= C
.Last
;
1312 C
.Last
.Next
:= null;
1314 elsif Before
= C
.First
then
1315 Last
.Next
:= C
.First
;
1316 C
.First
.Prev
:= Last
;
1318 C
.First
.Prev
:= null;
1321 Before
.Prev
.Next
:= First
;
1322 First
.Prev
:= Before
.Prev
;
1323 Last
.Next
:= Before
;
1324 Before
.Prev
:= Last
;
1326 end Insert_Subtree_List
;
1328 -------------------------
1329 -- Insert_Subtree_Node --
1330 -------------------------
1332 procedure Insert_Subtree_Node
1333 (Subtree
: Tree_Node_Access
;
1334 Parent
: Tree_Node_Access
;
1335 Before
: Tree_Node_Access
)
1338 -- This is a simple wrapper operation to insert a single child into the
1339 -- Parent's children list.
1346 end Insert_Subtree_Node
;
1352 function Is_Empty
(Container
: Tree
) return Boolean is
1354 return Container
.Root
.Children
.First
= null;
1361 function Is_Leaf
(Position
: Cursor
) return Boolean is
1363 return (if Position
= No_Element
then False
1364 else Position
.Node
.Children
.First
= null);
1371 function Is_Reachable
(From
, To
: Tree_Node_Access
) return Boolean is
1372 pragma Assert
(From
/= null);
1373 pragma Assert
(To
/= null);
1375 N
: Tree_Node_Access
;
1379 while N
/= null loop
1394 function Is_Root
(Position
: Cursor
) return Boolean is
1396 return (if Position
.Container
= null then False
1397 else Position
= Root
(Position
.Container
.all));
1406 Process
: not null access procedure (Position
: Cursor
))
1408 Busy
: With_Busy
(Container
.TC
'Unrestricted_Access);
1411 (Container
=> Container
'Unrestricted_Access,
1412 Subtree
=> Root_Node
(Container
),
1413 Process
=> Process
);
1416 function Iterate
(Container
: Tree
)
1417 return Tree_Iterator_Interfaces
.Forward_Iterator
'Class
1420 return Iterate_Subtree
(Root
(Container
));
1423 ----------------------
1424 -- Iterate_Children --
1425 ----------------------
1427 procedure Iterate_Children
1429 Process
: not null access procedure (Position
: Cursor
))
1431 C
: Tree_Node_Access
;
1432 Busy
: With_Busy
(Parent
.Container
.TC
'Unrestricted_Access);
1434 if Checks
and then Parent
= No_Element
then
1435 raise Constraint_Error
with "Parent cursor has no element";
1438 C
:= Parent
.Node
.Children
.First
;
1439 while C
/= null loop
1440 Process
(Position
=> Cursor
'(Parent.Container, Node => C));
1443 end Iterate_Children;
1445 procedure Iterate_Children
1446 (Container : Tree_Access;
1447 Subtree : Tree_Node_Access;
1448 Process : not null access procedure (Position : Cursor))
1450 Node : Tree_Node_Access;
1453 -- This is a helper function to recursively iterate over all the nodes
1454 -- in a subtree, in depth-first fashion. This particular helper just
1455 -- visits the children of this subtree, not the root of the subtree node
1456 -- itself. This is useful when starting from the ultimate root of the
1457 -- entire tree (see Iterate), as that root does not have an element.
1459 Node := Subtree.Children.First;
1460 while Node /= null loop
1461 Iterate_Subtree (Container, Node, Process);
1464 end Iterate_Children;
1466 function Iterate_Children
1469 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1471 C : constant Tree_Access := Container'Unrestricted_Access;
1473 if Checks and then Parent = No_Element then
1474 raise Constraint_Error with "Parent cursor has no element";
1477 if Checks and then Parent.Container /= C then
1478 raise Program_Error with "Parent cursor not in container";
1481 return It : constant Child_Iterator :=
1482 (Limited_Controlled with
1484 Subtree => Parent.Node)
1488 end Iterate_Children;
1490 ---------------------
1491 -- Iterate_Subtree --
1492 ---------------------
1494 function Iterate_Subtree
1496 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1498 C : constant Tree_Access := Position.Container;
1500 if Checks and then Position = No_Element then
1501 raise Constraint_Error with "Position cursor has no element";
1504 -- Implement Vet for multiway trees???
1505 -- pragma Assert (Vet (Position), "bad subtree cursor");
1507 return It : constant Subtree_Iterator :=
1508 (Limited_Controlled with
1510 Subtree => Position.Node)
1514 end Iterate_Subtree;
1516 procedure Iterate_Subtree
1518 Process : not null access procedure (Position : Cursor))
1520 Busy : With_Busy (Position.Container.TC'Unrestricted_Access);
1522 if Checks and then Position = No_Element then
1523 raise Constraint_Error with "Position cursor has no element";
1526 if Is_Root (Position) then
1527 Iterate_Children (Position.Container, Position.Node, Process);
1529 Iterate_Subtree (Position.Container, Position.Node, Process);
1531 end Iterate_Subtree;
1533 procedure Iterate_Subtree
1534 (Container : Tree_Access;
1535 Subtree : Tree_Node_Access;
1536 Process : not null access procedure (Position : Cursor))
1539 -- This is a helper function to recursively iterate over all the nodes
1540 -- in a subtree, in depth-first fashion. It first visits the root of the
1541 -- subtree, then visits its children.
1543 Process (Cursor'(Container
, Subtree
));
1544 Iterate_Children
(Container
, Subtree
, Process
);
1545 end Iterate_Subtree
;
1551 overriding
function Last
(Object
: Child_Iterator
) return Cursor
is
1553 return Last_Child
(Cursor
'(Object.Container, Object.Subtree));
1560 function Last_Child (Parent : Cursor) return Cursor is
1561 Node : Tree_Node_Access;
1564 if Checks and then Parent = No_Element then
1565 raise Constraint_Error with "Parent cursor has no element";
1568 Node := Parent.Node.Children.Last;
1574 return (Parent.Container, Node);
1577 ------------------------
1578 -- Last_Child_Element --
1579 ------------------------
1581 function Last_Child_Element (Parent : Cursor) return Element_Type is
1583 return Element (Last_Child (Parent));
1584 end Last_Child_Element;
1590 procedure Move (Target : in out Tree; Source : in out Tree) is
1591 Node : Tree_Node_Access;
1594 if Target'Address = Source'Address then
1598 TC_Check (Source.TC);
1600 Target.Clear; -- checks busy bit
1602 Target.Root.Children := Source.Root.Children;
1603 Source.Root.Children := Children_Type'(others => null);
1605 Node
:= Target
.Root
.Children
.First
;
1606 while Node
/= null loop
1607 Node
.Parent
:= Root_Node
(Target
);
1611 Target
.Count
:= Source
.Count
;
1620 (Object
: Subtree_Iterator
;
1621 Position
: Cursor
) return Cursor
1623 Node
: Tree_Node_Access
;
1626 if Position
.Container
= null then
1630 if Checks
and then Position
.Container
/= Object
.Container
then
1631 raise Program_Error
with
1632 "Position cursor of Next designates wrong tree";
1635 Node
:= Position
.Node
;
1637 if Node
.Children
.First
/= null then
1638 return Cursor
'(Object.Container, Node.Children.First);
1641 while Node /= Object.Subtree loop
1642 if Node.Next /= null then
1643 return Cursor'(Object
.Container
, Node
.Next
);
1646 Node
:= Node
.Parent
;
1653 (Object
: Child_Iterator
;
1654 Position
: Cursor
) return Cursor
1657 if Position
.Container
= null then
1661 if Checks
and then Position
.Container
/= Object
.Container
then
1662 raise Program_Error
with
1663 "Position cursor of Next designates wrong tree";
1666 return Next_Sibling
(Position
);
1673 function Next_Sibling
(Position
: Cursor
) return Cursor
is
1675 if Position
= No_Element
then
1679 if Position
.Node
.Next
= null then
1683 return Cursor
'(Position.Container, Position.Node.Next);
1686 procedure Next_Sibling (Position : in out Cursor) is
1688 Position := Next_Sibling (Position);
1695 function Node_Count (Container : Tree) return Count_Type is
1697 -- Container.Count is the number of nodes we have actually allocated. We
1698 -- cache the value specifically so this Node_Count operation can execute
1699 -- in O(1) time, which makes it behave similarly to how the Length
1700 -- selector function behaves for other containers.
1702 -- The cached node count value only describes the nodes we have
1703 -- allocated; the root node itself is not included in that count. The
1704 -- Node_Count operation returns a value that includes the root node
1705 -- (because the RM says so), so we must add 1 to our cached value.
1707 return 1 + Container.Count;
1714 function Parent (Position : Cursor) return Cursor is
1716 if Position = No_Element then
1720 if Position.Node.Parent = null then
1724 return Cursor'(Position
.Container
, Position
.Node
.Parent
);
1731 procedure Prepend_Child
1732 (Container
: in out Tree
;
1734 New_Item
: Element_Type
;
1735 Count
: Count_Type
:= 1)
1737 First
, Last
: Tree_Node_Access
;
1740 if Checks
and then Parent
= No_Element
then
1741 raise Constraint_Error
with "Parent cursor has no element";
1744 if Checks
and then Parent
.Container
/= Container
'Unrestricted_Access then
1745 raise Program_Error
with "Parent cursor not in container";
1752 TC_Check
(Container
.TC
);
1754 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
1755 Element => New_Item,
1760 for J in Count_Type'(2) .. Count
loop
1762 -- Reclaim other nodes if Storage_Error???
1764 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
1766 Element => New_Item,
1775 Parent => Parent.Node,
1776 Before => Parent.Node.Children.First);
1778 -- In order for operation Node_Count to complete in O(1) time, we cache
1779 -- the count value. Here we increment the total count by the number of
1780 -- nodes we just inserted.
1782 Container.Count := Container.Count + Count;
1789 overriding function Previous
1790 (Object : Child_Iterator;
1791 Position : Cursor) return Cursor
1794 if Position.Container = null then
1798 if Checks and then Position.Container /= Object.Container then
1799 raise Program_Error with
1800 "Position cursor of Previous designates wrong tree";
1803 return Previous_Sibling (Position);
1806 ----------------------
1807 -- Previous_Sibling --
1808 ----------------------
1810 function Previous_Sibling (Position : Cursor) return Cursor is
1813 (if Position = No_Element then No_Element
1814 elsif Position.Node.Prev = null then No_Element
1815 else Cursor'(Position
.Container
, Position
.Node
.Prev
));
1816 end Previous_Sibling
;
1818 procedure Previous_Sibling
(Position
: in out Cursor
) is
1820 Position
:= Previous_Sibling
(Position
);
1821 end Previous_Sibling
;
1823 ----------------------
1824 -- Pseudo_Reference --
1825 ----------------------
1827 function Pseudo_Reference
1828 (Container
: aliased Tree
'Class) return Reference_Control_Type
1830 TC
: constant Tamper_Counts_Access
:= Container
.TC
'Unrestricted_Access;
1832 return R
: constant Reference_Control_Type
:= (Controlled
with TC
) do
1835 end Pseudo_Reference
;
1841 procedure Query_Element
1843 Process
: not null access procedure (Element
: Element_Type
))
1845 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
1846 Lock
: With_Lock
(T
.TC
'Unrestricted_Access);
1848 if Checks
and then Position
= No_Element
then
1849 raise Constraint_Error
with "Position cursor has no element";
1852 if Checks
and then Is_Root
(Position
) then
1853 raise Program_Error
with "Position cursor designates root";
1856 Process
(Position
.Node
.Element
);
1864 (Stream
: not null access Root_Stream_Type
'Class;
1865 Container
: out Tree
)
1867 procedure Read_Children
(Subtree
: Tree_Node_Access
);
1869 function Read_Subtree
1870 (Parent
: Tree_Node_Access
) return Tree_Node_Access
;
1872 Total_Count
: Count_Type
'Base;
1873 -- Value read from the stream that says how many elements follow
1875 Read_Count
: Count_Type
'Base;
1876 -- Actual number of elements read from the stream
1882 procedure Read_Children
(Subtree
: Tree_Node_Access
) is
1883 pragma Assert
(Subtree
/= null);
1884 pragma Assert
(Subtree
.Children
.First
= null);
1885 pragma Assert
(Subtree
.Children
.Last
= null);
1887 Count
: Count_Type
'Base;
1888 -- Number of child subtrees
1893 Count_Type
'Read (Stream
, Count
);
1895 if Checks
and then Count
< 0 then
1896 raise Program_Error
with "attempt to read from corrupt stream";
1903 C
.First
:= Read_Subtree
(Parent
=> Subtree
);
1906 for J
in Count_Type
'(2) .. Count loop
1907 C.Last.Next := Read_Subtree (Parent => Subtree);
1908 C.Last.Next.Prev := C.Last;
1909 C.Last := C.Last.Next;
1912 -- Now that the allocation and reads have completed successfully, it
1913 -- is safe to link the children to their parent.
1915 Subtree.Children := C;
1922 function Read_Subtree
1923 (Parent : Tree_Node_Access) return Tree_Node_Access
1925 Subtree : constant Tree_Node_Access :=
1928 Element
=> Element_Type
'Input (Stream
),
1932 Read_Count
:= Read_Count
+ 1;
1934 Read_Children
(Subtree
);
1939 -- Start of processing for Read
1942 Container
.Clear
; -- checks busy bit
1944 Count_Type
'Read (Stream
, Total_Count
);
1946 if Checks
and then Total_Count
< 0 then
1947 raise Program_Error
with "attempt to read from corrupt stream";
1950 if Total_Count
= 0 then
1956 Read_Children
(Root_Node
(Container
));
1958 if Checks
and then Read_Count
/= Total_Count
then
1959 raise Program_Error
with "attempt to read from corrupt stream";
1962 Container
.Count
:= Total_Count
;
1966 (Stream
: not null access Root_Stream_Type
'Class;
1967 Position
: out Cursor
)
1970 raise Program_Error
with "attempt to read tree cursor from stream";
1974 (Stream
: not null access Root_Stream_Type
'Class;
1975 Item
: out Reference_Type
)
1978 raise Program_Error
with "attempt to stream reference";
1982 (Stream
: not null access Root_Stream_Type
'Class;
1983 Item
: out Constant_Reference_Type
)
1986 raise Program_Error
with "attempt to stream reference";
1994 (Container
: aliased in out Tree
;
1995 Position
: Cursor
) return Reference_Type
1998 if Checks
and then Position
.Container
= null then
1999 raise Constraint_Error
with
2000 "Position cursor has no element";
2003 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2005 raise Program_Error
with
2006 "Position cursor designates wrong container";
2009 if Checks
and then Position
.Node
= Root_Node
(Container
) then
2010 raise Program_Error
with "Position cursor designates root";
2013 -- Implement Vet for multiway tree???
2014 -- pragma Assert (Vet (Position),
2015 -- "Position cursor in Constant_Reference is bad");
2018 C
: Tree
renames Position
.Container
.all;
2019 TC
: constant Tamper_Counts_Access
:=
2020 C
.TC
'Unrestricted_Access;
2022 return R
: constant Reference_Type
:=
2023 (Element
=> Position
.Node
.Element
'Access,
2024 Control
=> (Controlled
with TC
))
2031 --------------------
2032 -- Remove_Subtree --
2033 --------------------
2035 procedure Remove_Subtree
(Subtree
: Tree_Node_Access
) is
2036 C
: Children_Type
renames Subtree
.Parent
.Children
;
2039 -- This is a utility operation to remove a subtree node from its
2040 -- parent's list of children.
2042 if C
.First
= Subtree
then
2043 pragma Assert
(Subtree
.Prev
= null);
2045 if C
.Last
= Subtree
then
2046 pragma Assert
(Subtree
.Next
= null);
2051 C
.First
:= Subtree
.Next
;
2052 C
.First
.Prev
:= null;
2055 elsif C
.Last
= Subtree
then
2056 pragma Assert
(Subtree
.Next
= null);
2057 C
.Last
:= Subtree
.Prev
;
2058 C
.Last
.Next
:= null;
2061 Subtree
.Prev
.Next
:= Subtree
.Next
;
2062 Subtree
.Next
.Prev
:= Subtree
.Prev
;
2066 ----------------------
2067 -- Replace_Element --
2068 ----------------------
2070 procedure Replace_Element
2071 (Container
: in out Tree
;
2073 New_Item
: Element_Type
)
2076 if Checks
and then Position
= No_Element
then
2077 raise Constraint_Error
with "Position cursor has no element";
2080 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2082 raise Program_Error
with "Position cursor not in container";
2085 if Checks
and then Is_Root
(Position
) then
2086 raise Program_Error
with "Position cursor designates root";
2089 TE_Check
(Container
.TC
);
2091 Position
.Node
.Element
:= New_Item
;
2092 end Replace_Element
;
2094 ------------------------------
2095 -- Reverse_Iterate_Children --
2096 ------------------------------
2098 procedure Reverse_Iterate_Children
2100 Process
: not null access procedure (Position
: Cursor
))
2102 C
: Tree_Node_Access
;
2103 Busy
: With_Busy
(Parent
.Container
.TC
'Unrestricted_Access);
2105 if Checks
and then Parent
= No_Element
then
2106 raise Constraint_Error
with "Parent cursor has no element";
2109 C
:= Parent
.Node
.Children
.Last
;
2110 while C
/= null loop
2111 Process
(Position
=> Cursor
'(Parent.Container, Node => C));
2114 end Reverse_Iterate_Children;
2120 function Root (Container : Tree) return Cursor is
2122 return (Container'Unrestricted_Access, Root_Node (Container));
2129 function Root_Node (Container : Tree) return Tree_Node_Access is
2130 type Root_Node_Access is access all Root_Node_Type;
2131 for Root_Node_Access'Storage_Size use 0;
2132 pragma Convention (C, Root_Node_Access);
2134 function To_Tree_Node_Access is
2135 new Ada.Unchecked_Conversion (Root_Node_Access, Tree_Node_Access);
2137 -- Start of processing for Root_Node
2140 -- This is a utility function for converting from an access type that
2141 -- designates the distinguished root node to an access type designating
2142 -- a non-root node. The representation of a root node does not have an
2143 -- element, but is otherwise identical to a non-root node, so the
2144 -- conversion itself is safe.
2146 return To_Tree_Node_Access (Container.Root'Unrestricted_Access);
2149 ---------------------
2150 -- Splice_Children --
2151 ---------------------
2153 procedure Splice_Children
2154 (Target : in out Tree;
2155 Target_Parent : Cursor;
2157 Source : in out Tree;
2158 Source_Parent : Cursor)
2163 if Checks and then Target_Parent = No_Element then
2164 raise Constraint_Error with "Target_Parent cursor has no element";
2167 if Checks and then Target_Parent.Container /= Target'Unrestricted_Access
2170 with "Target_Parent cursor not in Target container";
2173 if Before /= No_Element then
2174 if Checks and then Before.Container /= Target'Unrestricted_Access then
2176 with "Before cursor not in Target container";
2179 if Checks and then Before.Node.Parent /= Target_Parent.Node then
2180 raise Constraint_Error
2181 with "Before cursor not child of Target_Parent";
2185 if Checks and then Source_Parent = No_Element then
2186 raise Constraint_Error with "Source_Parent cursor has no element";
2189 if Checks and then Source_Parent.Container /= Source'Unrestricted_Access
2192 with "Source_Parent cursor not in Source container";
2195 if Target'Address = Source'Address then
2196 if Target_Parent = Source_Parent then
2200 TC_Check (Target.TC);
2202 if Checks and then Is_Reachable (From => Target_Parent.Node,
2203 To => Source_Parent.Node)
2205 raise Constraint_Error
2206 with "Source_Parent is ancestor of Target_Parent";
2210 (Target_Parent => Target_Parent.Node,
2211 Before => Before.Node,
2212 Source_Parent => Source_Parent.Node);
2217 TC_Check (Target.TC);
2218 TC_Check (Source.TC);
2220 -- We cache the count of the nodes we have allocated, so that operation
2221 -- Node_Count can execute in O(1) time. But that means we must count the
2222 -- nodes in the subtree we remove from Source and insert into Target, in
2223 -- order to keep the count accurate.
2225 Count := Subtree_Node_Count (Source_Parent.Node);
2226 pragma Assert (Count >= 1);
2228 Count := Count - 1; -- because Source_Parent node does not move
2231 (Target_Parent => Target_Parent.Node,
2232 Before => Before.Node,
2233 Source_Parent => Source_Parent.Node);
2235 Source.Count := Source.Count - Count;
2236 Target.Count := Target.Count + Count;
2237 end Splice_Children;
2239 procedure Splice_Children
2240 (Container : in out Tree;
2241 Target_Parent : Cursor;
2243 Source_Parent : Cursor)
2246 if Checks and then Target_Parent = No_Element then
2247 raise Constraint_Error with "Target_Parent cursor has no element";
2251 Target_Parent.Container /= Container'Unrestricted_Access
2254 with "Target_Parent cursor not in container";
2257 if Before /= No_Element then
2258 if Checks and then Before.Container /= Container'Unrestricted_Access
2261 with "Before cursor not in container";
2264 if Checks and then Before.Node.Parent /= Target_Parent.Node then
2265 raise Constraint_Error
2266 with "Before cursor not child of Target_Parent";
2270 if Checks and then Source_Parent = No_Element then
2271 raise Constraint_Error with "Source_Parent cursor has no element";
2275 Source_Parent.Container /= Container'Unrestricted_Access
2278 with "Source_Parent cursor not in container";
2281 if Target_Parent = Source_Parent then
2285 TC_Check (Container.TC);
2287 if Checks and then Is_Reachable (From => Target_Parent.Node,
2288 To => Source_Parent.Node)
2290 raise Constraint_Error
2291 with "Source_Parent is ancestor of Target_Parent";
2295 (Target_Parent => Target_Parent.Node,
2296 Before => Before.Node,
2297 Source_Parent => Source_Parent.Node);
2298 end Splice_Children;
2300 procedure Splice_Children
2301 (Target_Parent : Tree_Node_Access;
2302 Before : Tree_Node_Access;
2303 Source_Parent : Tree_Node_Access)
2305 CC : constant Children_Type := Source_Parent.Children;
2306 C : Tree_Node_Access;
2309 -- This is a utility operation to remove the children from
2310 -- Source parent and insert them into Target parent.
2312 Source_Parent.Children := Children_Type'(others => null);
2314 -- Fix up the Parent pointers of each child to designate
2315 -- its new Target parent.
2318 while C
/= null loop
2319 C
.Parent
:= Target_Parent
;
2326 Parent
=> Target_Parent
,
2328 end Splice_Children
;
2330 --------------------
2331 -- Splice_Subtree --
2332 --------------------
2334 procedure Splice_Subtree
2335 (Target
: in out Tree
;
2338 Source
: in out Tree
;
2339 Position
: in out Cursor
)
2341 Subtree_Count
: Count_Type
;
2344 if Checks
and then Parent
= No_Element
then
2345 raise Constraint_Error
with "Parent cursor has no element";
2348 if Checks
and then Parent
.Container
/= Target
'Unrestricted_Access then
2349 raise Program_Error
with "Parent cursor not in Target container";
2352 if Before
/= No_Element
then
2353 if Checks
and then Before
.Container
/= Target
'Unrestricted_Access then
2354 raise Program_Error
with "Before cursor not in Target container";
2357 if Checks
and then Before
.Node
.Parent
/= Parent
.Node
then
2358 raise Constraint_Error
with "Before cursor not child of Parent";
2362 if Checks
and then Position
= No_Element
then
2363 raise Constraint_Error
with "Position cursor has no element";
2366 if Checks
and then Position
.Container
/= Source
'Unrestricted_Access then
2367 raise Program_Error
with "Position cursor not in Source container";
2370 if Checks
and then Is_Root
(Position
) then
2371 raise Program_Error
with "Position cursor designates root";
2374 if Target
'Address = Source
'Address then
2375 if Position
.Node
.Parent
= Parent
.Node
then
2376 if Position
.Node
= Before
.Node
then
2380 if Position
.Node
.Next
= Before
.Node
then
2385 TC_Check
(Target
.TC
);
2388 Is_Reachable
(From
=> Parent
.Node
, To
=> Position
.Node
)
2390 raise Constraint_Error
with "Position is ancestor of Parent";
2393 Remove_Subtree
(Position
.Node
);
2395 Position
.Node
.Parent
:= Parent
.Node
;
2396 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2401 TC_Check
(Target
.TC
);
2402 TC_Check
(Source
.TC
);
2404 -- This is an unfortunate feature of this API: we must count the nodes
2405 -- in the subtree that we remove from the source tree, which is an O(n)
2406 -- operation. It would have been better if the Tree container did not
2407 -- have a Node_Count selector; a user that wants the number of nodes in
2408 -- the tree could simply call Subtree_Node_Count, with the understanding
2409 -- that such an operation is O(n).
2411 -- Of course, we could choose to implement the Node_Count selector as an
2412 -- O(n) operation, which would turn this splice operation into an O(1)
2415 Subtree_Count
:= Subtree_Node_Count
(Position
.Node
);
2416 pragma Assert
(Subtree_Count
<= Source
.Count
);
2418 Remove_Subtree
(Position
.Node
);
2419 Source
.Count
:= Source
.Count
- Subtree_Count
;
2421 Position
.Node
.Parent
:= Parent
.Node
;
2422 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2424 Target
.Count
:= Target
.Count
+ Subtree_Count
;
2426 Position
.Container
:= Target
'Unrestricted_Access;
2429 procedure Splice_Subtree
2430 (Container
: in out Tree
;
2436 if Checks
and then Parent
= No_Element
then
2437 raise Constraint_Error
with "Parent cursor has no element";
2440 if Checks
and then Parent
.Container
/= Container
'Unrestricted_Access then
2441 raise Program_Error
with "Parent cursor not in container";
2444 if Before
/= No_Element
then
2445 if Checks
and then Before
.Container
/= Container
'Unrestricted_Access
2447 raise Program_Error
with "Before cursor not in container";
2450 if Checks
and then Before
.Node
.Parent
/= Parent
.Node
then
2451 raise Constraint_Error
with "Before cursor not child of Parent";
2455 if Checks
and then Position
= No_Element
then
2456 raise Constraint_Error
with "Position cursor has no element";
2459 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2461 raise Program_Error
with "Position cursor not in container";
2464 if Checks
and then Is_Root
(Position
) then
2466 -- Should this be PE instead? Need ARG confirmation. ???
2468 raise Constraint_Error
with "Position cursor designates root";
2471 if Position
.Node
.Parent
= Parent
.Node
then
2472 if Position
.Node
= Before
.Node
then
2476 if Position
.Node
.Next
= Before
.Node
then
2481 TC_Check
(Container
.TC
);
2484 Is_Reachable
(From
=> Parent
.Node
, To
=> Position
.Node
)
2486 raise Constraint_Error
with "Position is ancestor of Parent";
2489 Remove_Subtree
(Position
.Node
);
2491 Position
.Node
.Parent
:= Parent
.Node
;
2492 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2495 ------------------------
2496 -- Subtree_Node_Count --
2497 ------------------------
2499 function Subtree_Node_Count
(Position
: Cursor
) return Count_Type
is
2501 if Position
= No_Element
then
2505 return Subtree_Node_Count
(Position
.Node
);
2506 end Subtree_Node_Count
;
2508 function Subtree_Node_Count
2509 (Subtree
: Tree_Node_Access
) return Count_Type
2511 Result
: Count_Type
;
2512 Node
: Tree_Node_Access
;
2516 Node
:= Subtree
.Children
.First
;
2517 while Node
/= null loop
2518 Result
:= Result
+ Subtree_Node_Count
(Node
);
2523 end Subtree_Node_Count
;
2530 (Container
: in out Tree
;
2534 if Checks
and then I
= No_Element
then
2535 raise Constraint_Error
with "I cursor has no element";
2538 if Checks
and then I
.Container
/= Container
'Unrestricted_Access then
2539 raise Program_Error
with "I cursor not in container";
2542 if Checks
and then Is_Root
(I
) then
2543 raise Program_Error
with "I cursor designates root";
2546 if I
= J
then -- make this test sooner???
2550 if Checks
and then J
= No_Element
then
2551 raise Constraint_Error
with "J cursor has no element";
2554 if Checks
and then J
.Container
/= Container
'Unrestricted_Access then
2555 raise Program_Error
with "J cursor not in container";
2558 if Checks
and then Is_Root
(J
) then
2559 raise Program_Error
with "J cursor designates root";
2562 TE_Check
(Container
.TC
);
2565 EI
: constant Element_Type
:= I
.Node
.Element
;
2568 I
.Node
.Element
:= J
.Node
.Element
;
2569 J
.Node
.Element
:= EI
;
2573 --------------------
2574 -- Update_Element --
2575 --------------------
2577 procedure Update_Element
2578 (Container
: in out Tree
;
2580 Process
: not null access procedure (Element
: in out Element_Type
))
2582 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
2583 Lock
: With_Lock
(T
.TC
'Unrestricted_Access);
2585 if Checks
and then Position
= No_Element
then
2586 raise Constraint_Error
with "Position cursor has no element";
2589 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2591 raise Program_Error
with "Position cursor not in container";
2594 if Checks
and then Is_Root
(Position
) then
2595 raise Program_Error
with "Position cursor designates root";
2598 Process
(Position
.Node
.Element
);
2606 (Stream
: not null access Root_Stream_Type
'Class;
2609 procedure Write_Children
(Subtree
: Tree_Node_Access
);
2610 procedure Write_Subtree
(Subtree
: Tree_Node_Access
);
2612 --------------------
2613 -- Write_Children --
2614 --------------------
2616 procedure Write_Children
(Subtree
: Tree_Node_Access
) is
2617 CC
: Children_Type
renames Subtree
.Children
;
2618 C
: Tree_Node_Access
;
2621 Count_Type
'Write (Stream
, Child_Count
(CC
));
2624 while C
/= null loop
2634 procedure Write_Subtree
(Subtree
: Tree_Node_Access
) is
2636 Element_Type
'Output (Stream
, Subtree
.Element
);
2637 Write_Children
(Subtree
);
2640 -- Start of processing for Write
2643 Count_Type
'Write (Stream
, Container
.Count
);
2645 if Container
.Count
= 0 then
2649 Write_Children
(Root_Node
(Container
));
2653 (Stream
: not null access Root_Stream_Type
'Class;
2657 raise Program_Error
with "attempt to write tree cursor to stream";
2661 (Stream
: not null access Root_Stream_Type
'Class;
2662 Item
: Reference_Type
)
2665 raise Program_Error
with "attempt to stream reference";
2669 (Stream
: not null access Root_Stream_Type
'Class;
2670 Item
: Constant_Reference_Type
)
2673 raise Program_Error
with "attempt to stream reference";
2676 end Ada
.Containers
.Multiway_Trees
;