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-2011, 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
41 type Root_Iterator
is abstract new Limited_Controlled
and
42 Tree_Iterator_Interfaces
.Forward_Iterator
with
44 Container
: Tree_Access
;
45 Subtree
: Tree_Node_Access
;
48 overriding
procedure Finalize
(Object
: in out Root_Iterator
);
50 -----------------------
51 -- Subtree_Iterator --
52 -----------------------
54 -- ??? these headers are a bit odd, but for sure they do not substitute
55 -- for documenting things, what *is* a Subtree_Iterator?
57 type Subtree_Iterator
is new Root_Iterator
with null record;
59 overriding
function First
(Object
: Subtree_Iterator
) return Cursor
;
61 overriding
function Next
62 (Object
: Subtree_Iterator
;
63 Position
: Cursor
) return Cursor
;
69 type Child_Iterator
is new Root_Iterator
and
70 Tree_Iterator_Interfaces
.Reversible_Iterator
with null record;
72 overriding
function First
(Object
: Child_Iterator
) return Cursor
;
74 overriding
function Next
75 (Object
: Child_Iterator
;
76 Position
: Cursor
) return Cursor
;
78 overriding
function Last
(Object
: Child_Iterator
) return Cursor
;
80 overriding
function Previous
81 (Object
: Child_Iterator
;
82 Position
: Cursor
) return Cursor
;
84 -----------------------
85 -- Local Subprograms --
86 -----------------------
88 function Root_Node
(Container
: Tree
) return Tree_Node_Access
;
90 procedure Deallocate_Node
is
91 new Ada
.Unchecked_Deallocation
(Tree_Node_Type
, 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
195 -- in. 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;
213 function Ancestor_Find
215 Item : Element_Type) return Cursor
217 R, N : Tree_Node_Access;
220 if Position = No_Element then
221 raise Constraint_Error with "Position cursor has no element";
224 -- Commented-out pending official ruling from ARG. ???
226 -- if Position.Container /= Container'Unrestricted_Access then
227 -- raise Program_Error with "Position cursor not in container";
230 -- AI-0136 says to raise PE if Position equals the root node. This does
231 -- not seem correct, as this value is just the limiting condition of the
232 -- search. For now we omit this check, pending a ruling from the ARG.???
234 -- if Is_Root (Position) then
235 -- raise Program_Error with "Position cursor designates root";
238 R := Root_Node (Position.Container.all);
241 if N.Element = Item then
242 return Cursor'(Position
.Container
, N
);
255 procedure Append_Child
256 (Container
: in out Tree
;
258 New_Item
: Element_Type
;
259 Count
: Count_Type
:= 1)
261 First
, Last
: Tree_Node_Access
;
264 if Parent
= No_Element
then
265 raise Constraint_Error
with "Parent cursor has no element";
268 if Parent
.Container
/= Container
'Unrestricted_Access then
269 raise Program_Error
with "Parent cursor not in container";
276 if Container
.Busy
> 0 then
278 with "attempt to tamper with cursors (tree is busy)";
281 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
287 for J in Count_Type'(2) .. Count
loop
289 -- Reclaim other nodes if Storage_Error. ???
291 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
302 Parent => Parent.Node,
303 Before => null); -- null means "insert at end of list"
305 -- In order for operation Node_Count to complete in O(1) time, we cache
306 -- the count value. Here we increment the total count by the number of
307 -- nodes we just inserted.
309 Container.Count := Container.Count + Count;
316 procedure Assign (Target : in out Tree; Source : Tree) is
317 Source_Count : constant Count_Type := Source.Count;
318 Target_Count : Count_Type;
321 if Target'Address = Source'Address then
325 Target.Clear; -- checks busy bit
327 -- Copy_Children returns the number of nodes that it allocates, but it
328 -- does this by incrementing the count value passed in, so we must
329 -- initialize the count before calling Copy_Children.
333 -- Note that Copy_Children inserts the newly-allocated children into
334 -- their parent list only after the allocation of all the children has
335 -- succeeded. This preserves invariants even if the allocation fails.
337 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
338 pragma Assert (Target_Count = Source_Count);
340 Target.Count := Source_Count;
347 function Child_Count (Parent : Cursor) return Count_Type is
349 return (if Parent = No_Element
350 then 0 else Child_Count (Parent.Node.Children));
353 function Child_Count (Children : Children_Type) return Count_Type is
355 Node : Tree_Node_Access;
359 Node := Children.First;
360 while Node /= null loop
361 Result := Result + 1;
372 function Child_Depth (Parent, Child : Cursor) return Count_Type is
374 N : Tree_Node_Access;
377 if Parent = No_Element then
378 raise Constraint_Error with "Parent cursor has no element";
381 if Child = No_Element then
382 raise Constraint_Error with "Child cursor has no element";
385 if Parent.Container /= Child.Container then
386 raise Program_Error with "Parent and Child in different containers";
391 while N /= Parent.Node loop
392 Result := Result + 1;
396 raise Program_Error with "Parent is not ancestor of Child";
407 procedure Clear (Container : in out Tree) is
408 Container_Count, Children_Count : Count_Type;
411 if Container.Busy > 0 then
413 with "attempt to tamper with cursors (tree is busy)";
416 -- We first set the container count to 0, in order to preserve
417 -- invariants in case the deallocation fails. (This works because
418 -- Deallocate_Children immediately removes the children from their
419 -- parent, and then does the actual deallocation.)
421 Container_Count := Container.Count;
422 Container.Count := 0;
424 -- Deallocate_Children returns the number of nodes that it deallocates,
425 -- but it does this by incrementing the count value that is passed in,
426 -- so we must first initialize the count return value before calling it.
430 -- See comment above. Deallocate_Children immediately removes the
431 -- children list from their parent node (here, the root of the tree),
432 -- and only after that does it attempt the actual deallocation. So even
433 -- if the deallocation fails, the representation invariants for the tree
436 Deallocate_Children (Root_Node (Container), Children_Count);
437 pragma Assert (Children_Count = Container_Count);
446 Item : Element_Type) return Boolean
449 return Find (Container, Item) /= No_Element;
456 function Copy (Source : Tree) return Tree is
458 return Target : Tree do
460 (Source => Source.Root.Children,
461 Parent => Root_Node (Target),
462 Count => Target.Count);
464 pragma Assert (Target.Count = Source.Count);
472 procedure Copy_Children
473 (Source : Children_Type;
474 Parent : Tree_Node_Access;
475 Count : in out Count_Type)
477 pragma Assert (Parent /= null);
478 pragma Assert (Parent.Children.First = null);
479 pragma Assert (Parent.Children.Last = null);
482 C : Tree_Node_Access;
485 -- We special-case the first allocation, in order to establish the
486 -- representation invariants for type Children_Type.
502 -- The representation invariants for the Children_Type list have been
503 -- established, so we can now copy the remaining children of Source.
510 Target => CC.Last.Next,
513 CC.Last.Next.Prev := CC.Last;
514 CC.Last := CC.Last.Next;
519 -- Add the newly-allocated children to their parent list only after the
520 -- allocation has succeeded, so as to preserve invariants of the parent.
522 Parent.Children := CC;
529 procedure Copy_Subtree
530 (Target : in out Tree;
535 Target_Subtree : Tree_Node_Access;
536 Target_Count : Count_Type;
539 if Parent = No_Element then
540 raise Constraint_Error with "Parent cursor has no element";
543 if Parent.Container /= Target'Unrestricted_Access then
544 raise Program_Error with "Parent cursor not in container";
547 if Before /= No_Element then
548 if Before.Container /= Target'Unrestricted_Access then
549 raise Program_Error with "Before cursor not in container";
552 if Before.Node.Parent /= Parent.Node then
553 raise Constraint_Error with "Before cursor not child of Parent";
557 if Source = No_Element then
561 if Is_Root (Source) then
562 raise Constraint_Error with "Source cursor designates root";
565 -- Copy_Subtree returns a count of the number of nodes that it
566 -- allocates, but it works by incrementing the value that is passed
567 -- in. We must therefore initialize the count value before calling
573 (Source => Source.Node,
574 Parent => Parent.Node,
575 Target => Target_Subtree,
576 Count => Target_Count);
578 pragma Assert (Target_Subtree /= null);
579 pragma Assert (Target_Subtree.Parent = Parent.Node);
580 pragma Assert (Target_Count >= 1);
583 (Subtree => Target_Subtree,
584 Parent => Parent.Node,
585 Before => Before.Node);
587 -- In order for operation Node_Count to complete in O(1) time, we cache
588 -- the count value. Here we increment the total count by the number of
589 -- nodes we just inserted.
591 Target.Count := Target.Count + Target_Count;
594 procedure Copy_Subtree
595 (Source : Tree_Node_Access;
596 Parent : Tree_Node_Access;
597 Target : out Tree_Node_Access;
598 Count : in out Count_Type)
601 Target := new Tree_Node_Type'(Element
=> Source
.Element
,
608 (Source
=> Source
.Children
,
613 -------------------------
614 -- Deallocate_Children --
615 -------------------------
617 procedure Deallocate_Children
618 (Subtree
: Tree_Node_Access
;
619 Count
: in out Count_Type
)
621 pragma Assert
(Subtree
/= null);
623 CC
: Children_Type
:= Subtree
.Children
;
624 C
: Tree_Node_Access
;
627 -- We immediately remove the children from their parent, in order to
628 -- preserve invariants in case the deallocation fails.
630 Subtree
.Children
:= Children_Type
'(others => null);
632 while CC.First /= null loop
636 Deallocate_Subtree (C, Count);
638 end Deallocate_Children;
640 ------------------------
641 -- Deallocate_Subtree --
642 ------------------------
644 procedure Deallocate_Subtree
645 (Subtree : in out Tree_Node_Access;
646 Count : in out Count_Type)
649 Deallocate_Children (Subtree, Count);
650 Deallocate_Node (Subtree);
652 end Deallocate_Subtree;
654 ---------------------
655 -- Delete_Children --
656 ---------------------
658 procedure Delete_Children
659 (Container : in out Tree;
665 if Parent = No_Element then
666 raise Constraint_Error with "Parent cursor has no element";
669 if Parent.Container /= Container'Unrestricted_Access then
670 raise Program_Error with "Parent cursor not in container";
673 if Container.Busy > 0 then
675 with "attempt to tamper with cursors (tree is busy)";
678 -- Deallocate_Children returns a count of the number of nodes that it
679 -- deallocates, but it works by incrementing the value that is passed
680 -- in. We must therefore initialize the count value before calling
681 -- Deallocate_Children.
685 Deallocate_Children (Parent.Node, Count);
686 pragma Assert (Count <= Container.Count);
688 Container.Count := Container.Count - Count;
695 procedure Delete_Leaf
696 (Container : in out Tree;
697 Position : in out Cursor)
699 X : Tree_Node_Access;
702 if Position = No_Element then
703 raise Constraint_Error with "Position cursor has no element";
706 if Position.Container /= Container'Unrestricted_Access then
707 raise Program_Error with "Position cursor not in container";
710 if Is_Root (Position) then
711 raise Program_Error with "Position cursor designates root";
714 if not Is_Leaf (Position) then
715 raise Constraint_Error with "Position cursor does not designate leaf";
718 if Container.Busy > 0 then
720 with "attempt to tamper with cursors (tree is busy)";
724 Position := No_Element;
726 -- Restore represention invariants before attempting the actual
730 Container.Count := Container.Count - 1;
732 -- It is now safe to attempt the deallocation. This leaf node has been
733 -- disassociated from the tree, so even if the deallocation fails,
734 -- representation invariants will remain satisfied.
743 procedure Delete_Subtree
744 (Container : in out Tree;
745 Position : in out Cursor)
747 X : Tree_Node_Access;
751 if Position = No_Element then
752 raise Constraint_Error with "Position cursor has no element";
755 if Position.Container /= Container'Unrestricted_Access then
756 raise Program_Error with "Position cursor not in container";
759 if Is_Root (Position) then
760 raise Program_Error with "Position cursor designates root";
763 if Container.Busy > 0 then
765 with "attempt to tamper with cursors (tree is busy)";
769 Position := No_Element;
771 -- Here is one case where a deallocation failure can result in the
772 -- violation of a representation invariant. We disassociate the subtree
773 -- from the tree now, but we only decrement the total node count after
774 -- we attempt the deallocation. However, if the deallocation fails, the
775 -- total node count will not get decremented.
777 -- One way around this dilemma is to count the nodes in the subtree
778 -- before attempt to delete the subtree, but that is an O(n) operation,
779 -- so it does not seem worth it.
781 -- Perhaps this is much ado about nothing, since the only way
782 -- deallocation can fail is if Controlled Finalization fails: this
783 -- propagates Program_Error so all bets are off anyway. ???
787 -- Deallocate_Subtree returns a count of the number of nodes that it
788 -- deallocates, but it works by incrementing the value that is passed
789 -- in. We must therefore initialize the count value before calling
790 -- Deallocate_Subtree.
794 Deallocate_Subtree (X, Count);
795 pragma Assert (Count <= Container.Count);
797 -- See comments above. We would prefer to do this sooner, but there's no
798 -- way to satisfy that goal without a potentially severe execution
801 Container.Count := Container.Count - Count;
808 function Depth (Position : Cursor) return Count_Type is
810 N : Tree_Node_Access;
817 Result := Result + 1;
827 function Element (Position : Cursor) return Element_Type is
829 if Position.Container = null then
830 raise Constraint_Error with "Position cursor has no element";
833 if Position.Node = Root_Node (Position.Container.all) then
834 raise Program_Error with "Position cursor designates root";
837 return Position.Node.Element;
844 function Equal_Children
845 (Left_Subtree : Tree_Node_Access;
846 Right_Subtree : Tree_Node_Access) return Boolean
848 Left_Children : Children_Type renames Left_Subtree.Children;
849 Right_Children : Children_Type renames Right_Subtree.Children;
851 L, R : Tree_Node_Access;
854 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
858 L := Left_Children.First;
859 R := Right_Children.First;
861 if not Equal_Subtree (L, R) then
876 function Equal_Subtree
877 (Left_Position : Cursor;
878 Right_Position : Cursor) return Boolean
881 if Left_Position = No_Element then
882 raise Constraint_Error with "Left cursor has no element";
885 if Right_Position = No_Element then
886 raise Constraint_Error with "Right cursor has no element";
889 if Left_Position = Right_Position then
893 if Is_Root (Left_Position) then
894 if not Is_Root (Right_Position) then
898 return Equal_Children (Left_Position.Node, Right_Position.Node);
901 if Is_Root (Right_Position) then
905 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
908 function Equal_Subtree
909 (Left_Subtree : Tree_Node_Access;
910 Right_Subtree : Tree_Node_Access) return Boolean
913 if Left_Subtree.Element /= Right_Subtree.Element then
917 return Equal_Children (Left_Subtree, Right_Subtree);
924 procedure Finalize (Object : in out Root_Iterator) is
925 B : Natural renames Object.Container.Busy;
936 Item : Element_Type) return Cursor
938 N : constant Tree_Node_Access :=
939 Find_In_Children (Root_Node (Container), Item);
944 return Cursor'(Container
'Unrestricted_Access, N
);
952 overriding
function First
(Object
: Subtree_Iterator
) return Cursor
is
954 if Object
.Subtree
= Root_Node
(Object
.Container
.all) then
955 return First_Child
(Root
(Object
.Container
.all));
957 return Cursor
'(Object.Container, Object.Subtree);
961 overriding function First (Object : Child_Iterator) return Cursor is
963 return First_Child (Cursor'(Object
.Container
, Object
.Subtree
));
970 function First_Child
(Parent
: Cursor
) return Cursor
is
971 Node
: Tree_Node_Access
;
974 if Parent
= No_Element
then
975 raise Constraint_Error
with "Parent cursor has no element";
978 Node
:= Parent
.Node
.Children
.First
;
984 return Cursor
'(Parent.Container, Node);
987 -------------------------
988 -- First_Child_Element --
989 -------------------------
991 function First_Child_Element (Parent : Cursor) return Element_Type is
993 return Element (First_Child (Parent));
994 end First_Child_Element;
996 ----------------------
997 -- Find_In_Children --
998 ----------------------
1000 function Find_In_Children
1001 (Subtree : Tree_Node_Access;
1002 Item : Element_Type) return Tree_Node_Access
1004 N, Result : Tree_Node_Access;
1007 N := Subtree.Children.First;
1008 while N /= null loop
1009 Result := Find_In_Subtree (N, Item);
1011 if Result /= null then
1019 end Find_In_Children;
1021 ---------------------
1022 -- Find_In_Subtree --
1023 ---------------------
1025 function Find_In_Subtree
1027 Item : Element_Type) return Cursor
1029 Result : Tree_Node_Access;
1032 if Position = No_Element then
1033 raise Constraint_Error with "Position cursor has no element";
1036 -- Commented out pending official ruling by ARG. ???
1038 -- if Position.Container /= Container'Unrestricted_Access then
1039 -- raise Program_Error with "Position cursor not in container";
1043 (if Is_Root (Position)
1044 then Find_In_Children (Position.Node, Item)
1045 else Find_In_Subtree (Position.Node, Item));
1047 if Result = null then
1051 return Cursor'(Position
.Container
, Result
);
1052 end Find_In_Subtree
;
1054 function Find_In_Subtree
1055 (Subtree
: Tree_Node_Access
;
1056 Item
: Element_Type
) return Tree_Node_Access
1059 if Subtree
.Element
= Item
then
1063 return Find_In_Children
(Subtree
, Item
);
1064 end Find_In_Subtree
;
1070 function Has_Element
(Position
: Cursor
) return Boolean is
1072 return (if Position
= No_Element
then False
1073 else Position
.Node
.Parent
/= null);
1080 procedure Insert_Child
1081 (Container
: in out Tree
;
1084 New_Item
: Element_Type
;
1085 Count
: Count_Type
:= 1)
1088 pragma Unreferenced
(Position
);
1091 Insert_Child
(Container
, Parent
, Before
, New_Item
, Position
, Count
);
1094 procedure Insert_Child
1095 (Container
: in out Tree
;
1098 New_Item
: Element_Type
;
1099 Position
: out Cursor
;
1100 Count
: Count_Type
:= 1)
1102 Last
: Tree_Node_Access
;
1105 if Parent
= No_Element
then
1106 raise Constraint_Error
with "Parent cursor has no element";
1109 if Parent
.Container
/= Container
'Unrestricted_Access then
1110 raise Program_Error
with "Parent cursor not in container";
1113 if Before
/= No_Element
then
1114 if Before
.Container
/= Container
'Unrestricted_Access then
1115 raise Program_Error
with "Before cursor not in container";
1118 if Before
.Node
.Parent
/= Parent
.Node
then
1119 raise Constraint_Error
with "Parent cursor not parent of Before";
1124 Position
:= No_Element
; -- Need ruling from ARG ???
1128 if Container
.Busy
> 0 then
1130 with "attempt to tamper with cursors (tree is busy)";
1133 Position
.Container
:= Parent
.Container
;
1134 Position
.Node
:= new Tree_Node_Type
'(Parent => Parent.Node,
1135 Element => New_Item,
1138 Last := Position.Node;
1140 for J in Count_Type'(2) .. Count
loop
1142 -- Reclaim other nodes if Storage_Error. ???
1144 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
1146 Element => New_Item,
1153 (First => Position.Node,
1155 Parent => Parent.Node,
1156 Before => Before.Node);
1158 -- In order for operation Node_Count to complete in O(1) time, we cache
1159 -- the count value. Here we increment the total count by the number of
1160 -- nodes we just inserted.
1162 Container.Count := Container.Count + Count;
1165 procedure Insert_Child
1166 (Container : in out Tree;
1169 Position : out Cursor;
1170 Count : Count_Type := 1)
1172 Last : Tree_Node_Access;
1175 if Parent = No_Element then
1176 raise Constraint_Error with "Parent cursor has no element";
1179 if Parent.Container /= Container'Unrestricted_Access then
1180 raise Program_Error with "Parent cursor not in container";
1183 if Before /= No_Element then
1184 if Before.Container /= Container'Unrestricted_Access then
1185 raise Program_Error with "Before cursor not in container";
1188 if Before.Node.Parent /= Parent.Node then
1189 raise Constraint_Error with "Parent cursor not parent of Before";
1194 Position := No_Element; -- Need ruling from ARG ???
1198 if Container.Busy > 0 then
1200 with "attempt to tamper with cursors (tree is busy)";
1203 Position.Container := Parent.Container;
1204 Position.Node := new Tree_Node_Type'(Parent
=> Parent
.Node
,
1208 Last
:= Position
.Node
;
1210 for J
in Count_Type
'(2) .. Count loop
1212 -- Reclaim other nodes if Storage_Error. ???
1214 Last.Next := new Tree_Node_Type'(Parent
=> Parent
.Node
,
1223 (First
=> Position
.Node
,
1225 Parent
=> Parent
.Node
,
1226 Before
=> Before
.Node
);
1228 -- In order for operation Node_Count to complete in O(1) time, we cache
1229 -- the count value. Here we increment the total count by the number of
1230 -- nodes we just inserted.
1232 Container
.Count
:= Container
.Count
+ Count
;
1235 -------------------------
1236 -- Insert_Subtree_List --
1237 -------------------------
1239 procedure Insert_Subtree_List
1240 (First
: Tree_Node_Access
;
1241 Last
: Tree_Node_Access
;
1242 Parent
: Tree_Node_Access
;
1243 Before
: Tree_Node_Access
)
1245 pragma Assert
(Parent
/= null);
1246 C
: Children_Type
renames Parent
.Children
;
1249 -- This is a simple utility operation to insert a list of nodes (from
1250 -- First..Last) as children of Parent. The Before node specifies where
1251 -- the new children should be inserted relative to the existing
1254 if First
= null then
1255 pragma Assert
(Last
= null);
1259 pragma Assert
(Last
/= null);
1260 pragma Assert
(Before
= null or else Before
.Parent
= Parent
);
1262 if C
.First
= null then
1264 C
.First
.Prev
:= null;
1266 C
.Last
.Next
:= null;
1268 elsif Before
= null then -- means "insert after existing nodes"
1269 C
.Last
.Next
:= First
;
1270 First
.Prev
:= C
.Last
;
1272 C
.Last
.Next
:= null;
1274 elsif Before
= C
.First
then
1275 Last
.Next
:= C
.First
;
1276 C
.First
.Prev
:= Last
;
1278 C
.First
.Prev
:= null;
1281 Before
.Prev
.Next
:= First
;
1282 First
.Prev
:= Before
.Prev
;
1283 Last
.Next
:= Before
;
1284 Before
.Prev
:= Last
;
1286 end Insert_Subtree_List
;
1288 -------------------------
1289 -- Insert_Subtree_Node --
1290 -------------------------
1292 procedure Insert_Subtree_Node
1293 (Subtree
: Tree_Node_Access
;
1294 Parent
: Tree_Node_Access
;
1295 Before
: Tree_Node_Access
)
1298 -- This is a simple wrapper operation to insert a single child into the
1299 -- Parent's children list.
1306 end Insert_Subtree_Node
;
1312 function Is_Empty
(Container
: Tree
) return Boolean is
1314 return Container
.Root
.Children
.First
= null;
1321 function Is_Leaf
(Position
: Cursor
) return Boolean is
1323 return (if Position
= No_Element
then False
1324 else Position
.Node
.Children
.First
= null);
1331 function Is_Reachable
(From
, To
: Tree_Node_Access
) return Boolean is
1332 pragma Assert
(From
/= null);
1333 pragma Assert
(To
/= null);
1335 N
: Tree_Node_Access
;
1339 while N
/= null loop
1354 function Is_Root
(Position
: Cursor
) return Boolean is
1356 return (if Position
.Container
= null then False
1357 else Position
= Root
(Position
.Container
.all));
1366 Process
: not null access procedure (Position
: Cursor
))
1368 B
: Natural renames Container
'Unrestricted_Access.all.Busy
;
1374 (Container
=> Container
'Unrestricted_Access,
1375 Subtree
=> Root_Node
(Container
),
1376 Process
=> Process
);
1386 function Iterate
(Container
: Tree
)
1387 return Tree_Iterator_Interfaces
.Forward_Iterator
'Class
1390 return Iterate_Subtree
(Root
(Container
));
1393 ----------------------
1394 -- Iterate_Children --
1395 ----------------------
1397 procedure Iterate_Children
1399 Process
: not null access procedure (Position
: Cursor
))
1402 if Parent
= No_Element
then
1403 raise Constraint_Error
with "Parent cursor has no element";
1407 B
: Natural renames Parent
.Container
.Busy
;
1408 C
: Tree_Node_Access
;
1413 C
:= Parent
.Node
.Children
.First
;
1414 while C
/= null loop
1415 Process
(Position
=> Cursor
'(Parent.Container, Node => C));
1426 end Iterate_Children;
1428 procedure Iterate_Children
1429 (Container : Tree_Access;
1430 Subtree : Tree_Node_Access;
1431 Process : not null access procedure (Position : Cursor))
1433 Node : Tree_Node_Access;
1436 -- This is a helper function to recursively iterate over all the nodes
1437 -- in a subtree, in depth-first fashion. This particular helper just
1438 -- visits the children of this subtree, not the root of the subtree node
1439 -- itself. This is useful when starting from the ultimate root of the
1440 -- entire tree (see Iterate), as that root does not have an element.
1442 Node := Subtree.Children.First;
1443 while Node /= null loop
1444 Iterate_Subtree (Container, Node, Process);
1447 end Iterate_Children;
1449 function Iterate_Children
1452 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1454 C : constant Tree_Access := Container'Unrestricted_Access;
1455 B : Natural renames C.Busy;
1458 if Parent = No_Element then
1459 raise Constraint_Error with "Parent cursor has no element";
1462 if Parent.Container /= C then
1463 raise Program_Error with "Parent cursor not in container";
1466 return It : constant Child_Iterator :=
1467 (Limited_Controlled with
1469 Subtree => Parent.Node)
1473 end Iterate_Children;
1475 ---------------------
1476 -- Iterate_Subtree --
1477 ---------------------
1479 function Iterate_Subtree
1481 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1484 if Position = No_Element then
1485 raise Constraint_Error with "Position cursor has no element";
1488 -- Implement Vet for multiway trees???
1489 -- pragma Assert (Vet (Position), "bad subtree cursor");
1492 B : Natural renames Position.Container.Busy;
1494 return It : constant Subtree_Iterator :=
1495 (Limited_Controlled with
1496 Container => Position.Container,
1497 Subtree => Position.Node)
1502 end Iterate_Subtree;
1504 procedure Iterate_Subtree
1506 Process : not null access procedure (Position : Cursor))
1509 if Position = No_Element then
1510 raise Constraint_Error with "Position cursor has no element";
1514 B : Natural renames Position.Container.Busy;
1519 if Is_Root (Position) then
1520 Iterate_Children (Position.Container, Position.Node, Process);
1522 Iterate_Subtree (Position.Container, Position.Node, Process);
1532 end Iterate_Subtree;
1534 procedure Iterate_Subtree
1535 (Container : Tree_Access;
1536 Subtree : Tree_Node_Access;
1537 Process : not null access procedure (Position : Cursor))
1540 -- This is a helper function to recursively iterate over all the nodes
1541 -- in a subtree, in depth-first fashion. It first visits the root of the
1542 -- subtree, then visits its children.
1544 Process (Cursor'(Container
, Subtree
));
1545 Iterate_Children
(Container
, Subtree
, Process
);
1546 end Iterate_Subtree
;
1552 overriding
function Last
(Object
: Child_Iterator
) return Cursor
is
1554 return Last_Child
(Cursor
'(Object.Container, Object.Subtree));
1561 function Last_Child (Parent : Cursor) return Cursor is
1562 Node : Tree_Node_Access;
1565 if Parent = No_Element then
1566 raise Constraint_Error with "Parent cursor has no element";
1569 Node := Parent.Node.Children.Last;
1575 return (Parent.Container, Node);
1578 ------------------------
1579 -- Last_Child_Element --
1580 ------------------------
1582 function Last_Child_Element (Parent : Cursor) return Element_Type is
1584 return Element (Last_Child (Parent));
1585 end Last_Child_Element;
1591 procedure Move (Target : in out Tree; Source : in out Tree) is
1592 Node : Tree_Node_Access;
1595 if Target'Address = Source'Address then
1599 if Source.Busy > 0 then
1601 with "attempt to tamper with cursors of Source (tree is busy)";
1604 Target.Clear; -- checks busy bit
1606 Target.Root.Children := Source.Root.Children;
1607 Source.Root.Children := Children_Type'(others => null);
1609 Node
:= Target
.Root
.Children
.First
;
1610 while Node
/= null loop
1611 Node
.Parent
:= Root_Node
(Target
);
1615 Target
.Count
:= Source
.Count
;
1624 (Object
: Subtree_Iterator
;
1625 Position
: Cursor
) return Cursor
1627 Node
: Tree_Node_Access
;
1630 if Position
.Container
= null then
1634 if Position
.Container
/= Object
.Container
then
1635 raise Program_Error
with
1636 "Position cursor of Next designates wrong tree";
1639 Node
:= Position
.Node
;
1641 if Node
.Children
.First
/= null then
1642 return Cursor
'(Object.Container, Node.Children.First);
1645 while Node /= Object.Subtree loop
1646 if Node.Next /= null then
1647 return Cursor'(Object
.Container
, Node
.Next
);
1650 Node
:= Node
.Parent
;
1657 (Object
: Child_Iterator
;
1658 Position
: Cursor
) return Cursor
1661 if Position
.Container
= null then
1665 if Position
.Container
/= Object
.Container
then
1666 raise Program_Error
with
1667 "Position cursor of Next designates wrong tree";
1670 return Next_Sibling
(Position
);
1677 function Next_Sibling
(Position
: Cursor
) return Cursor
is
1679 if Position
= No_Element
then
1683 if Position
.Node
.Next
= null then
1687 return Cursor
'(Position.Container, Position.Node.Next);
1690 procedure Next_Sibling (Position : in out Cursor) is
1692 Position := Next_Sibling (Position);
1699 function Node_Count (Container : Tree) return Count_Type is
1701 -- Container.Count is the number of nodes we have actually allocated. We
1702 -- cache the value specifically so this Node_Count operation can execute
1703 -- in O(1) time, which makes it behave similarly to how the Length
1704 -- selector function behaves for other containers.
1706 -- The cached node count value only describes the nodes we have
1707 -- allocated; the root node itself is not included in that count. The
1708 -- Node_Count operation returns a value that includes the root node
1709 -- (because the RM says so), so we must add 1 to our cached value.
1711 return 1 + Container.Count;
1718 function Parent (Position : Cursor) return Cursor is
1720 if Position = No_Element then
1724 if Position.Node.Parent = null then
1728 return Cursor'(Position
.Container
, Position
.Node
.Parent
);
1735 procedure Prepend_Child
1736 (Container
: in out Tree
;
1738 New_Item
: Element_Type
;
1739 Count
: Count_Type
:= 1)
1741 First
, Last
: Tree_Node_Access
;
1744 if Parent
= No_Element
then
1745 raise Constraint_Error
with "Parent cursor has no element";
1748 if Parent
.Container
/= Container
'Unrestricted_Access then
1749 raise Program_Error
with "Parent cursor not in container";
1756 if Container
.Busy
> 0 then
1758 with "attempt to tamper with cursors (tree is busy)";
1761 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
1762 Element => New_Item,
1767 for J in Count_Type'(2) .. Count
loop
1769 -- Reclaim other nodes if Storage_Error???
1771 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
1773 Element => New_Item,
1782 Parent => Parent.Node,
1783 Before => Parent.Node.Children.First);
1785 -- In order for operation Node_Count to complete in O(1) time, we cache
1786 -- the count value. Here we increment the total count by the number of
1787 -- nodes we just inserted.
1789 Container.Count := Container.Count + Count;
1796 overriding function Previous
1797 (Object : Child_Iterator;
1798 Position : Cursor) return Cursor
1801 if Position.Container = null then
1805 if Position.Container /= Object.Container then
1806 raise Program_Error with
1807 "Position cursor of Previous designates wrong tree";
1810 return Previous_Sibling (Position);
1813 ----------------------
1814 -- Previous_Sibling --
1815 ----------------------
1817 function Previous_Sibling (Position : Cursor) return Cursor is
1820 (if Position = No_Element then No_Element
1821 elsif Position.Node.Prev = null then No_Element
1822 else Cursor'(Position
.Container
, Position
.Node
.Prev
));
1823 end Previous_Sibling
;
1825 procedure Previous_Sibling
(Position
: in out Cursor
) is
1827 Position
:= Previous_Sibling
(Position
);
1828 end Previous_Sibling
;
1834 procedure Query_Element
1836 Process
: not null access procedure (Element
: Element_Type
))
1839 if Position
= No_Element
then
1840 raise Constraint_Error
with "Position cursor has no element";
1843 if Is_Root
(Position
) then
1844 raise Program_Error
with "Position cursor designates root";
1848 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
1849 B
: Natural renames T
.Busy
;
1850 L
: Natural renames T
.Lock
;
1856 Process
(Position
.Node
.Element
);
1874 (Stream
: not null access Root_Stream_Type
'Class;
1875 Container
: out Tree
)
1877 procedure Read_Children
(Subtree
: Tree_Node_Access
);
1879 function Read_Subtree
1880 (Parent
: Tree_Node_Access
) return Tree_Node_Access
;
1882 Total_Count
: Count_Type
'Base;
1883 -- Value read from the stream that says how many elements follow
1885 Read_Count
: Count_Type
'Base;
1886 -- Actual number of elements read from the stream
1892 procedure Read_Children
(Subtree
: Tree_Node_Access
) is
1893 pragma Assert
(Subtree
/= null);
1894 pragma Assert
(Subtree
.Children
.First
= null);
1895 pragma Assert
(Subtree
.Children
.Last
= null);
1897 Count
: Count_Type
'Base;
1898 -- Number of child subtrees
1903 Count_Type
'Read (Stream
, Count
);
1906 raise Program_Error
with "attempt to read from corrupt stream";
1913 C
.First
:= Read_Subtree
(Parent
=> Subtree
);
1916 for J
in Count_Type
'(2) .. Count loop
1917 C.Last.Next := Read_Subtree (Parent => Subtree);
1918 C.Last.Next.Prev := C.Last;
1919 C.Last := C.Last.Next;
1922 -- Now that the allocation and reads have completed successfully, it
1923 -- is safe to link the children to their parent.
1925 Subtree.Children := C;
1932 function Read_Subtree
1933 (Parent : Tree_Node_Access) return Tree_Node_Access
1935 Subtree : constant Tree_Node_Access :=
1938 Element
=> Element_Type
'Input (Stream
),
1942 Read_Count
:= Read_Count
+ 1;
1944 Read_Children
(Subtree
);
1949 -- Start of processing for Read
1952 Container
.Clear
; -- checks busy bit
1954 Count_Type
'Read (Stream
, Total_Count
);
1956 if Total_Count
< 0 then
1957 raise Program_Error
with "attempt to read from corrupt stream";
1960 if Total_Count
= 0 then
1966 Read_Children
(Root_Node
(Container
));
1968 if Read_Count
/= Total_Count
then
1969 raise Program_Error
with "attempt to read from corrupt stream";
1972 Container
.Count
:= Total_Count
;
1976 (Stream
: not null access Root_Stream_Type
'Class;
1977 Position
: out Cursor
)
1980 raise Program_Error
with "attempt to read tree cursor from stream";
1984 (Stream
: not null access Root_Stream_Type
'Class;
1985 Item
: out Reference_Type
)
1988 raise Program_Error
with "attempt to stream reference";
1992 (Stream
: not null access Root_Stream_Type
'Class;
1993 Item
: out Constant_Reference_Type
)
1996 raise Program_Error
with "attempt to stream reference";
2003 function Constant_Reference
2004 (Container
: aliased Tree
;
2005 Position
: Cursor
) return Constant_Reference_Type
2008 pragma Unreferenced
(Container
);
2010 return (Element
=> Position
.Node
.Element
'Unrestricted_Access);
2011 end Constant_Reference
;
2014 (Container
: aliased Tree
;
2015 Position
: Cursor
) return Reference_Type
2018 pragma Unreferenced
(Container
);
2020 return (Element
=> Position
.Node
.Element
'Unrestricted_Access);
2023 --------------------
2024 -- Remove_Subtree --
2025 --------------------
2027 procedure Remove_Subtree
(Subtree
: Tree_Node_Access
) is
2028 C
: Children_Type
renames Subtree
.Parent
.Children
;
2031 -- This is a utility operation to remove a subtree node from its
2032 -- parent's list of children.
2034 if C
.First
= Subtree
then
2035 pragma Assert
(Subtree
.Prev
= null);
2037 if C
.Last
= Subtree
then
2038 pragma Assert
(Subtree
.Next
= null);
2043 C
.First
:= Subtree
.Next
;
2044 C
.First
.Prev
:= null;
2047 elsif C
.Last
= Subtree
then
2048 pragma Assert
(Subtree
.Next
= null);
2049 C
.Last
:= Subtree
.Prev
;
2050 C
.Last
.Next
:= null;
2053 Subtree
.Prev
.Next
:= Subtree
.Next
;
2054 Subtree
.Next
.Prev
:= Subtree
.Prev
;
2058 ----------------------
2059 -- Replace_Element --
2060 ----------------------
2062 procedure Replace_Element
2063 (Container
: in out Tree
;
2065 New_Item
: Element_Type
)
2068 if Position
= No_Element
then
2069 raise Constraint_Error
with "Position cursor has no element";
2072 if Position
.Container
/= Container
'Unrestricted_Access then
2073 raise Program_Error
with "Position cursor not in container";
2076 if Is_Root
(Position
) then
2077 raise Program_Error
with "Position cursor designates root";
2080 if Container
.Lock
> 0 then
2082 with "attempt to tamper with elements (tree is locked)";
2085 Position
.Node
.Element
:= New_Item
;
2086 end Replace_Element
;
2088 ------------------------------
2089 -- Reverse_Iterate_Children --
2090 ------------------------------
2092 procedure Reverse_Iterate_Children
2094 Process
: not null access procedure (Position
: Cursor
))
2097 if Parent
= No_Element
then
2098 raise Constraint_Error
with "Parent cursor has no element";
2102 B
: Natural renames Parent
.Container
.Busy
;
2103 C
: Tree_Node_Access
;
2108 C
:= Parent
.Node
.Children
.Last
;
2109 while C
/= null loop
2110 Process
(Position
=> Cursor
'(Parent.Container, Node => C));
2121 end Reverse_Iterate_Children;
2127 function Root (Container : Tree) return Cursor is
2129 return (Container'Unrestricted_Access, Root_Node (Container));
2136 function Root_Node (Container : Tree) return Tree_Node_Access is
2137 type Root_Node_Access is access all Root_Node_Type;
2138 for Root_Node_Access'Storage_Size use 0;
2139 pragma Convention (C, Root_Node_Access);
2141 function To_Tree_Node_Access is
2142 new Ada.Unchecked_Conversion (Root_Node_Access, Tree_Node_Access);
2144 -- Start of processing for Root_Node
2147 -- This is a utility function for converting from an access type that
2148 -- designates the distinguished root node to an access type designating
2149 -- a non-root node. The representation of a root node does not have an
2150 -- element, but is otherwise identical to a non-root node, so the
2151 -- conversion itself is safe.
2153 return To_Tree_Node_Access (Container.Root'Unrestricted_Access);
2156 ---------------------
2157 -- Splice_Children --
2158 ---------------------
2160 procedure Splice_Children
2161 (Target : in out Tree;
2162 Target_Parent : Cursor;
2164 Source : in out Tree;
2165 Source_Parent : Cursor)
2170 if Target_Parent = No_Element then
2171 raise Constraint_Error with "Target_Parent cursor has no element";
2174 if Target_Parent.Container /= Target'Unrestricted_Access then
2176 with "Target_Parent cursor not in Target container";
2179 if Before /= No_Element then
2180 if Before.Container /= Target'Unrestricted_Access then
2182 with "Before cursor not in Target container";
2185 if Before.Node.Parent /= Target_Parent.Node then
2186 raise Constraint_Error
2187 with "Before cursor not child of Target_Parent";
2191 if Source_Parent = No_Element then
2192 raise Constraint_Error with "Source_Parent cursor has no element";
2195 if Source_Parent.Container /= Source'Unrestricted_Access then
2197 with "Source_Parent cursor not in Source container";
2200 if Target'Address = Source'Address then
2201 if Target_Parent = Source_Parent then
2205 if Target.Busy > 0 then
2207 with "attempt to tamper with cursors (Target tree is busy)";
2210 if Is_Reachable (From => Target_Parent.Node,
2211 To => Source_Parent.Node)
2213 raise Constraint_Error
2214 with "Source_Parent is ancestor of Target_Parent";
2218 (Target_Parent => Target_Parent.Node,
2219 Before => Before.Node,
2220 Source_Parent => Source_Parent.Node);
2225 if Target.Busy > 0 then
2227 with "attempt to tamper with cursors (Target tree is busy)";
2230 if Source.Busy > 0 then
2232 with "attempt to tamper with cursors (Source tree is busy)";
2235 -- We cache the count of the nodes we have allocated, so that operation
2236 -- Node_Count can execute in O(1) time. But that means we must count the
2237 -- nodes in the subtree we remove from Source and insert into Target, in
2238 -- order to keep the count accurate.
2240 Count := Subtree_Node_Count (Source_Parent.Node);
2241 pragma Assert (Count >= 1);
2243 Count := Count - 1; -- because Source_Parent node does not move
2246 (Target_Parent => Target_Parent.Node,
2247 Before => Before.Node,
2248 Source_Parent => Source_Parent.Node);
2250 Source.Count := Source.Count - Count;
2251 Target.Count := Target.Count + Count;
2252 end Splice_Children;
2254 procedure Splice_Children
2255 (Container : in out Tree;
2256 Target_Parent : Cursor;
2258 Source_Parent : Cursor)
2261 if Target_Parent = No_Element then
2262 raise Constraint_Error with "Target_Parent cursor has no element";
2265 if Target_Parent.Container /= Container'Unrestricted_Access then
2267 with "Target_Parent cursor not in container";
2270 if Before /= No_Element then
2271 if Before.Container /= Container'Unrestricted_Access then
2273 with "Before cursor not in container";
2276 if Before.Node.Parent /= Target_Parent.Node then
2277 raise Constraint_Error
2278 with "Before cursor not child of Target_Parent";
2282 if Source_Parent = No_Element then
2283 raise Constraint_Error with "Source_Parent cursor has no element";
2286 if Source_Parent.Container /= Container'Unrestricted_Access then
2288 with "Source_Parent cursor not in container";
2291 if Target_Parent = Source_Parent then
2295 if Container.Busy > 0 then
2297 with "attempt to tamper with cursors (tree is busy)";
2300 if Is_Reachable (From => Target_Parent.Node,
2301 To => Source_Parent.Node)
2303 raise Constraint_Error
2304 with "Source_Parent is ancestor of Target_Parent";
2308 (Target_Parent => Target_Parent.Node,
2309 Before => Before.Node,
2310 Source_Parent => Source_Parent.Node);
2311 end Splice_Children;
2313 procedure Splice_Children
2314 (Target_Parent : Tree_Node_Access;
2315 Before : Tree_Node_Access;
2316 Source_Parent : Tree_Node_Access)
2318 CC : constant Children_Type := Source_Parent.Children;
2319 C : Tree_Node_Access;
2322 -- This is a utility operation to remove the children from
2323 -- Source parent and insert them into Target parent.
2325 Source_Parent.Children := Children_Type'(others => null);
2327 -- Fix up the Parent pointers of each child to designate
2328 -- its new Target parent.
2331 while C
/= null loop
2332 C
.Parent
:= Target_Parent
;
2339 Parent
=> Target_Parent
,
2341 end Splice_Children
;
2343 --------------------
2344 -- Splice_Subtree --
2345 --------------------
2347 procedure Splice_Subtree
2348 (Target
: in out Tree
;
2351 Source
: in out Tree
;
2352 Position
: in out Cursor
)
2354 Subtree_Count
: Count_Type
;
2357 if Parent
= No_Element
then
2358 raise Constraint_Error
with "Parent cursor has no element";
2361 if Parent
.Container
/= Target
'Unrestricted_Access then
2362 raise Program_Error
with "Parent cursor not in Target container";
2365 if Before
/= No_Element
then
2366 if Before
.Container
/= Target
'Unrestricted_Access then
2367 raise Program_Error
with "Before cursor not in Target container";
2370 if Before
.Node
.Parent
/= Parent
.Node
then
2371 raise Constraint_Error
with "Before cursor not child of Parent";
2375 if Position
= No_Element
then
2376 raise Constraint_Error
with "Position cursor has no element";
2379 if Position
.Container
/= Source
'Unrestricted_Access then
2380 raise Program_Error
with "Position cursor not in Source container";
2383 if Is_Root
(Position
) then
2384 raise Program_Error
with "Position cursor designates root";
2387 if Target
'Address = Source
'Address then
2388 if Position
.Node
.Parent
= Parent
.Node
then
2389 if Position
.Node
= Before
.Node
then
2393 if Position
.Node
.Next
= Before
.Node
then
2398 if Target
.Busy
> 0 then
2400 with "attempt to tamper with cursors (Target tree is busy)";
2403 if Is_Reachable
(From
=> Parent
.Node
, To
=> Position
.Node
) then
2404 raise Constraint_Error
with "Position is ancestor of Parent";
2407 Remove_Subtree
(Position
.Node
);
2409 Position
.Node
.Parent
:= Parent
.Node
;
2410 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2415 if Target
.Busy
> 0 then
2417 with "attempt to tamper with cursors (Target tree is busy)";
2420 if Source
.Busy
> 0 then
2422 with "attempt to tamper with cursors (Source tree is busy)";
2425 -- This is an unfortunate feature of this API: we must count the nodes
2426 -- in the subtree that we remove from the source tree, which is an O(n)
2427 -- operation. It would have been better if the Tree container did not
2428 -- have a Node_Count selector; a user that wants the number of nodes in
2429 -- the tree could simply call Subtree_Node_Count, with the understanding
2430 -- that such an operation is O(n).
2432 -- Of course, we could choose to implement the Node_Count selector as an
2433 -- O(n) operation, which would turn this splice operation into an O(1)
2436 Subtree_Count
:= Subtree_Node_Count
(Position
.Node
);
2437 pragma Assert
(Subtree_Count
<= Source
.Count
);
2439 Remove_Subtree
(Position
.Node
);
2440 Source
.Count
:= Source
.Count
- Subtree_Count
;
2442 Position
.Node
.Parent
:= Parent
.Node
;
2443 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2445 Target
.Count
:= Target
.Count
+ Subtree_Count
;
2447 Position
.Container
:= Target
'Unrestricted_Access;
2450 procedure Splice_Subtree
2451 (Container
: in out Tree
;
2457 if Parent
= No_Element
then
2458 raise Constraint_Error
with "Parent cursor has no element";
2461 if Parent
.Container
/= Container
'Unrestricted_Access then
2462 raise Program_Error
with "Parent cursor not in container";
2465 if Before
/= No_Element
then
2466 if Before
.Container
/= Container
'Unrestricted_Access then
2467 raise Program_Error
with "Before cursor not in container";
2470 if Before
.Node
.Parent
/= Parent
.Node
then
2471 raise Constraint_Error
with "Before cursor not child of Parent";
2475 if Position
= No_Element
then
2476 raise Constraint_Error
with "Position cursor has no element";
2479 if Position
.Container
/= Container
'Unrestricted_Access then
2480 raise Program_Error
with "Position cursor not in container";
2483 if Is_Root
(Position
) then
2485 -- Should this be PE instead? Need ARG confirmation. ???
2487 raise Constraint_Error
with "Position cursor designates root";
2490 if Position
.Node
.Parent
= Parent
.Node
then
2491 if Position
.Node
= Before
.Node
then
2495 if Position
.Node
.Next
= Before
.Node
then
2500 if Container
.Busy
> 0 then
2502 with "attempt to tamper with cursors (tree is busy)";
2505 if Is_Reachable
(From
=> Parent
.Node
, To
=> Position
.Node
) then
2506 raise Constraint_Error
with "Position is ancestor of Parent";
2509 Remove_Subtree
(Position
.Node
);
2511 Position
.Node
.Parent
:= Parent
.Node
;
2512 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2515 ------------------------
2516 -- Subtree_Node_Count --
2517 ------------------------
2519 function Subtree_Node_Count
(Position
: Cursor
) return Count_Type
is
2521 if Position
= No_Element
then
2525 return Subtree_Node_Count
(Position
.Node
);
2526 end Subtree_Node_Count
;
2528 function Subtree_Node_Count
2529 (Subtree
: Tree_Node_Access
) return Count_Type
2531 Result
: Count_Type
;
2532 Node
: Tree_Node_Access
;
2536 Node
:= Subtree
.Children
.First
;
2537 while Node
/= null loop
2538 Result
:= Result
+ Subtree_Node_Count
(Node
);
2543 end Subtree_Node_Count
;
2550 (Container
: in out Tree
;
2554 if I
= No_Element
then
2555 raise Constraint_Error
with "I cursor has no element";
2558 if I
.Container
/= Container
'Unrestricted_Access then
2559 raise Program_Error
with "I cursor not in container";
2563 raise Program_Error
with "I cursor designates root";
2566 if I
= J
then -- make this test sooner???
2570 if J
= No_Element
then
2571 raise Constraint_Error
with "J cursor has no element";
2574 if J
.Container
/= Container
'Unrestricted_Access then
2575 raise Program_Error
with "J cursor not in container";
2579 raise Program_Error
with "J cursor designates root";
2582 if Container
.Lock
> 0 then
2584 with "attempt to tamper with elements (tree is locked)";
2588 EI
: constant Element_Type
:= I
.Node
.Element
;
2591 I
.Node
.Element
:= J
.Node
.Element
;
2592 J
.Node
.Element
:= EI
;
2596 --------------------
2597 -- Update_Element --
2598 --------------------
2600 procedure Update_Element
2601 (Container
: in out Tree
;
2603 Process
: not null access procedure (Element
: in out Element_Type
))
2606 if Position
= No_Element
then
2607 raise Constraint_Error
with "Position cursor has no element";
2610 if Position
.Container
/= Container
'Unrestricted_Access then
2611 raise Program_Error
with "Position cursor not in container";
2614 if Is_Root
(Position
) then
2615 raise Program_Error
with "Position cursor designates root";
2619 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
2620 B
: Natural renames T
.Busy
;
2621 L
: Natural renames T
.Lock
;
2627 Process
(Position
.Node
.Element
);
2645 (Stream
: not null access Root_Stream_Type
'Class;
2648 procedure Write_Children
(Subtree
: Tree_Node_Access
);
2649 procedure Write_Subtree
(Subtree
: Tree_Node_Access
);
2651 --------------------
2652 -- Write_Children --
2653 --------------------
2655 procedure Write_Children
(Subtree
: Tree_Node_Access
) is
2656 CC
: Children_Type
renames Subtree
.Children
;
2657 C
: Tree_Node_Access
;
2660 Count_Type
'Write (Stream
, Child_Count
(CC
));
2663 while C
/= null loop
2673 procedure Write_Subtree
(Subtree
: Tree_Node_Access
) is
2675 Element_Type
'Output (Stream
, Subtree
.Element
);
2676 Write_Children
(Subtree
);
2679 -- Start of processing for Write
2682 Count_Type
'Write (Stream
, Container
.Count
);
2684 if Container
.Count
= 0 then
2688 Write_Children
(Root_Node
(Container
));
2692 (Stream
: not null access Root_Stream_Type
'Class;
2696 raise Program_Error
with "attempt to write tree cursor to stream";
2700 (Stream
: not null access Root_Stream_Type
'Class;
2701 Item
: Reference_Type
)
2704 raise Program_Error
with "attempt to stream reference";
2708 (Stream
: not null access Root_Stream_Type
'Class;
2709 Item
: Constant_Reference_Type
)
2712 raise Program_Error
with "attempt to stream reference";
2715 end Ada
.Containers
.Multiway_Trees
;