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 type Subtree_Iterator is new Root_Iterator with null record;
56 overriding function First (Object : Subtree_Iterator) return Cursor;
58 overriding function Next
59 (Object : Subtree_Iterator;
60 Position : Cursor) return Cursor;
66 type Child_Iterator is new Root_Iterator and
67 Tree_Iterator_Interfaces.Reversible_Iterator with null record;
69 overriding function First (Object : Child_Iterator) return Cursor;
71 overriding function Next
72 (Object : Child_Iterator;
73 Position : Cursor) return Cursor;
75 overriding function Last (Object : Child_Iterator) return Cursor;
77 overriding function Previous
78 (Object : Child_Iterator;
79 Position : Cursor) return Cursor;
81 -----------------------
82 -- Local Subprograms --
83 -----------------------
85 function Root_Node (Container : Tree) return Tree_Node_Access;
87 procedure Deallocate_Node is
88 new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access);
90 procedure Deallocate_Children
91 (Subtree : Tree_Node_Access;
92 Count : in out Count_Type);
94 procedure Deallocate_Subtree
95 (Subtree : in out Tree_Node_Access;
96 Count : in out Count_Type);
98 function Equal_Children
99 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
101 function Equal_Subtree
102 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
104 procedure Iterate_Children
105 (Container : Tree_Access;
106 Subtree : Tree_Node_Access;
107 Process : not null access procedure (Position : Cursor));
109 procedure Iterate_Subtree
110 (Container : Tree_Access;
111 Subtree : Tree_Node_Access;
112 Process : not null access procedure (Position : Cursor));
114 procedure Copy_Children
115 (Source : Children_Type;
116 Parent : Tree_Node_Access;
117 Count : in out Count_Type);
119 procedure Copy_Subtree
120 (Source : Tree_Node_Access;
121 Parent : Tree_Node_Access;
122 Target : out Tree_Node_Access;
123 Count : in out Count_Type);
125 function Find_In_Children
126 (Subtree : Tree_Node_Access;
127 Item : Element_Type) return Tree_Node_Access;
129 function Find_In_Subtree
130 (Subtree : Tree_Node_Access;
131 Item : Element_Type) return Tree_Node_Access;
133 function Child_Count (Children : Children_Type) return Count_Type;
135 function Subtree_Node_Count
136 (Subtree : Tree_Node_Access) return Count_Type;
138 function Is_Reachable (From, To : Tree_Node_Access) return Boolean;
140 procedure Remove_Subtree (Subtree : Tree_Node_Access);
142 procedure Insert_Subtree_Node
143 (Subtree : Tree_Node_Access;
144 Parent : Tree_Node_Access;
145 Before : Tree_Node_Access);
147 procedure Insert_Subtree_List
148 (First : Tree_Node_Access;
149 Last : Tree_Node_Access;
150 Parent : Tree_Node_Access;
151 Before : Tree_Node_Access);
153 procedure Splice_Children
154 (Target_Parent : Tree_Node_Access;
155 Before : Tree_Node_Access;
156 Source_Parent : Tree_Node_Access);
162 function "=" (Left, Right : Tree) return Boolean is
164 if Left'Address = Right'Address then
168 return Equal_Children (Root_Node (Left), Root_Node (Right));
175 procedure Adjust (Container : in out Tree) is
176 Source : constant Children_Type := Container.Root.Children;
177 Source_Count : constant Count_Type := Container.Count;
178 Target_Count : Count_Type;
181 -- We first restore the target container to its default-initialized
182 -- state, before we attempt any allocation, to ensure that invariants
183 -- are preserved in the event that the allocation fails.
185 Container.Root.Children := Children_Type'(others => null);
188 Container.Count := 0;
190 -- Copy_Children returns a count of the number of nodes that it
191 -- allocates, but it works by incrementing the value that is passed
192 -- in. We must therefore initialize the count value before calling
197 -- Now we attempt the allocation of subtrees. The invariants are
198 -- satisfied even if the allocation fails.
200 Copy_Children (Source, Root_Node (Container), Target_Count);
201 pragma Assert (Target_Count = Source_Count);
203 Container.Count := Source_Count;
210 function Ancestor_Find
212 Item : Element_Type) return Cursor
214 R, N : Tree_Node_Access;
217 if Position = No_Element then
218 raise Constraint_Error with "Position cursor has no element";
221 -- Commented-out pending official ruling from ARG. ???
223 -- if Position.Container /= Container'Unrestricted_Access then
224 -- raise Program_Error with "Position cursor not in container";
227 -- AI-0136 says to raise PE if Position equals the root node. This does
228 -- not seem correct, as this value is just the limiting condition of the
229 -- search. For now we omit this check, pending a ruling from the ARG.???
231 -- if Is_Root (Position) then
232 -- raise Program_Error with "Position cursor designates root";
235 R := Root_Node (Position.Container.all);
238 if N.Element = Item then
239 return Cursor'(Position.Container, N);
252 procedure Append_Child
253 (Container : in out Tree;
255 New_Item : Element_Type;
256 Count : Count_Type := 1)
258 First, Last : Tree_Node_Access;
261 if Parent = No_Element then
262 raise Constraint_Error with "Parent cursor has no element";
265 if Parent.Container /= Container'Unrestricted_Access then
266 raise Program_Error with "Parent cursor not in container";
273 if Container.Busy > 0 then
275 with "attempt to tamper with cursors (tree is busy)";
278 First := new Tree_Node_Type'(Parent => Parent.Node,
284 for J in Count_Type'(2) .. Count loop
286 -- Reclaim other nodes if Storage_Error. ???
288 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
299 Parent => Parent.Node,
300 Before => null); -- null means "insert at end of list"
302 -- In order for operation Node_Count to complete in O(1) time, we cache
303 -- the count value. Here we increment the total count by the number of
304 -- nodes we just inserted.
306 Container.Count := Container.Count + Count;
313 procedure Assign (Target : in out Tree; Source : Tree) is
314 Source_Count : constant Count_Type := Source.Count;
315 Target_Count : Count_Type;
318 if Target'Address = Source'Address then
322 Target.Clear; -- checks busy bit
324 -- Copy_Children returns the number of nodes that it allocates, but it
325 -- does this by incrementing the count value passed in, so we must
326 -- initialize the count before calling Copy_Children.
330 -- Note that Copy_Children inserts the newly-allocated children into
331 -- their parent list only after the allocation of all the children has
332 -- succeeded. This preserves invariants even if the allocation fails.
334 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
335 pragma Assert (Target_Count = Source_Count);
337 Target.Count := Source_Count;
344 function Child_Count (Parent : Cursor) return Count_Type is
346 return (if Parent = No_Element
347 then 0 else Child_Count (Parent.Node.Children));
350 function Child_Count (Children : Children_Type) return Count_Type is
352 Node : Tree_Node_Access;
356 Node := Children.First;
357 while Node /= null loop
358 Result := Result + 1;
369 function Child_Depth (Parent, Child : Cursor) return Count_Type is
371 N : Tree_Node_Access;
374 if Parent = No_Element then
375 raise Constraint_Error with "Parent cursor has no element";
378 if Child = No_Element then
379 raise Constraint_Error with "Child cursor has no element";
382 if Parent.Container /= Child.Container then
383 raise Program_Error with "Parent and Child in different containers";
388 while N /= Parent.Node loop
389 Result := Result + 1;
393 raise Program_Error with "Parent is not ancestor of Child";
404 procedure Clear (Container : in out Tree) is
405 Container_Count, Children_Count : Count_Type;
408 if Container.Busy > 0 then
410 with "attempt to tamper with cursors (tree is busy)";
413 -- We first set the container count to 0, in order to preserve
414 -- invariants in case the deallocation fails. (This works because
415 -- Deallocate_Children immediately removes the children from their
416 -- parent, and then does the actual deallocation.)
418 Container_Count := Container.Count;
419 Container.Count := 0;
421 -- Deallocate_Children returns the number of nodes that it deallocates,
422 -- but it does this by incrementing the count value that is passed in,
423 -- so we must first initialize the count return value before calling it.
427 -- See comment above. Deallocate_Children immediately removes the
428 -- children list from their parent node (here, the root of the tree),
429 -- and only after that does it attempt the actual deallocation. So even
430 -- if the deallocation fails, the representation invariants for the tree
433 Deallocate_Children (Root_Node (Container), Children_Count);
434 pragma Assert (Children_Count = Container_Count);
443 Item : Element_Type) return Boolean
446 return Find (Container, Item) /= No_Element;
453 function Copy (Source : Tree) return Tree is
455 return Target : Tree do
457 (Source => Source.Root.Children,
458 Parent => Root_Node (Target),
459 Count => Target.Count);
461 pragma Assert (Target.Count = Source.Count);
469 procedure Copy_Children
470 (Source : Children_Type;
471 Parent : Tree_Node_Access;
472 Count : in out Count_Type)
474 pragma Assert (Parent /= null);
475 pragma Assert (Parent.Children.First = null);
476 pragma Assert (Parent.Children.Last = null);
479 C : Tree_Node_Access;
482 -- We special-case the first allocation, in order to establish the
483 -- representation invariants for type Children_Type.
499 -- The representation invariants for the Children_Type list have been
500 -- established, so we can now copy the remaining children of Source.
507 Target => CC.Last.Next,
510 CC.Last.Next.Prev := CC.Last;
511 CC.Last := CC.Last.Next;
516 -- Add the newly-allocated children to their parent list only after the
517 -- allocation has succeeded, so as to preserve invariants of the parent.
519 Parent.Children := CC;
526 procedure Copy_Subtree
527 (Target : in out Tree;
532 Target_Subtree : Tree_Node_Access;
533 Target_Count : Count_Type;
536 if Parent = No_Element then
537 raise Constraint_Error with "Parent cursor has no element";
540 if Parent.Container /= Target'Unrestricted_Access then
541 raise Program_Error with "Parent cursor not in container";
544 if Before /= No_Element then
545 if Before.Container /= Target'Unrestricted_Access then
546 raise Program_Error with "Before cursor not in container";
549 if Before.Node.Parent /= Parent.Node then
550 raise Constraint_Error with "Before cursor not child of Parent";
554 if Source = No_Element then
558 if Is_Root (Source) then
559 raise Constraint_Error with "Source cursor designates root";
562 -- Copy_Subtree returns a count of the number of nodes that it
563 -- allocates, but it works by incrementing the value that is passed
564 -- in. We must therefore initialize the count value before calling
570 (Source => Source.Node,
571 Parent => Parent.Node,
572 Target => Target_Subtree,
573 Count => Target_Count);
575 pragma Assert (Target_Subtree /= null);
576 pragma Assert (Target_Subtree.Parent = Parent.Node);
577 pragma Assert (Target_Count >= 1);
580 (Subtree => Target_Subtree,
581 Parent => Parent.Node,
582 Before => Before.Node);
584 -- In order for operation Node_Count to complete in O(1) time, we cache
585 -- the count value. Here we increment the total count by the number of
586 -- nodes we just inserted.
588 Target.Count := Target.Count + Target_Count;
591 procedure Copy_Subtree
592 (Source : Tree_Node_Access;
593 Parent : Tree_Node_Access;
594 Target : out Tree_Node_Access;
595 Count : in out Count_Type)
598 Target := new Tree_Node_Type'(Element => Source.Element,
605 (Source => Source.Children,
610 -------------------------
611 -- Deallocate_Children --
612 -------------------------
614 procedure Deallocate_Children
615 (Subtree : Tree_Node_Access;
616 Count : in out Count_Type)
618 pragma Assert (Subtree /= null);
620 CC : Children_Type := Subtree.Children;
621 C : Tree_Node_Access;
624 -- We immediately remove the children from their parent, in order to
625 -- preserve invariants in case the deallocation fails.
627 Subtree.Children := Children_Type'(others => null);
629 while CC.First /= null loop
633 Deallocate_Subtree (C, Count);
635 end Deallocate_Children;
637 ------------------------
638 -- Deallocate_Subtree --
639 ------------------------
641 procedure Deallocate_Subtree
642 (Subtree : in out Tree_Node_Access;
643 Count : in out Count_Type)
646 Deallocate_Children (Subtree, Count);
647 Deallocate_Node (Subtree);
649 end Deallocate_Subtree;
651 ---------------------
652 -- Delete_Children --
653 ---------------------
655 procedure Delete_Children
656 (Container : in out Tree;
662 if Parent = No_Element then
663 raise Constraint_Error with "Parent cursor has no element";
666 if Parent.Container /= Container'Unrestricted_Access then
667 raise Program_Error with "Parent cursor not in container";
670 if Container.Busy > 0 then
672 with "attempt to tamper with cursors (tree is busy)";
675 -- Deallocate_Children returns a count of the number of nodes that it
676 -- deallocates, but it works by incrementing the value that is passed
677 -- in. We must therefore initialize the count value before calling
678 -- Deallocate_Children.
682 Deallocate_Children (Parent.Node, Count);
683 pragma Assert (Count <= Container.Count);
685 Container.Count := Container.Count - Count;
692 procedure Delete_Leaf
693 (Container : in out Tree;
694 Position : in out Cursor)
696 X : Tree_Node_Access;
699 if Position = No_Element then
700 raise Constraint_Error with "Position cursor has no element";
703 if Position.Container /= Container'Unrestricted_Access then
704 raise Program_Error with "Position cursor not in container";
707 if Is_Root (Position) then
708 raise Program_Error with "Position cursor designates root";
711 if not Is_Leaf (Position) then
712 raise Constraint_Error with "Position cursor does not designate leaf";
715 if Container.Busy > 0 then
717 with "attempt to tamper with cursors (tree is busy)";
721 Position := No_Element;
723 -- Restore represention invariants before attempting the actual
727 Container.Count := Container.Count - 1;
729 -- It is now safe to attempt the deallocation. This leaf node has been
730 -- disassociated from the tree, so even if the deallocation fails,
731 -- representation invariants will remain satisfied.
740 procedure Delete_Subtree
741 (Container : in out Tree;
742 Position : in out Cursor)
744 X : Tree_Node_Access;
748 if Position = No_Element then
749 raise Constraint_Error with "Position cursor has no element";
752 if Position.Container /= Container'Unrestricted_Access then
753 raise Program_Error with "Position cursor not in container";
756 if Is_Root (Position) then
757 raise Program_Error with "Position cursor designates root";
760 if Container.Busy > 0 then
762 with "attempt to tamper with cursors (tree is busy)";
766 Position := No_Element;
768 -- Here is one case where a deallocation failure can result in the
769 -- violation of a representation invariant. We disassociate the subtree
770 -- from the tree now, but we only decrement the total node count after
771 -- we attempt the deallocation. However, if the deallocation fails, the
772 -- total node count will not get decremented.
774 -- One way around this dilemma is to count the nodes in the subtree
775 -- before attempt to delete the subtree, but that is an O(n) operation,
776 -- so it does not seem worth it.
778 -- Perhaps this is much ado about nothing, since the only way
779 -- deallocation can fail is if Controlled Finalization fails: this
780 -- propagates Program_Error so all bets are off anyway. ???
784 -- Deallocate_Subtree returns a count of the number of nodes that it
785 -- deallocates, but it works by incrementing the value that is passed
786 -- in. We must therefore initialize the count value before calling
787 -- Deallocate_Subtree.
791 Deallocate_Subtree (X, Count);
792 pragma Assert (Count <= Container.Count);
794 -- See comments above. We would prefer to do this sooner, but there's no
795 -- way to satisfy that goal without a potentially severe execution
798 Container.Count := Container.Count - Count;
805 function Depth (Position : Cursor) return Count_Type is
807 N : Tree_Node_Access;
814 Result := Result + 1;
824 function Element (Position : Cursor) return Element_Type is
826 if Position.Container = null then
827 raise Constraint_Error with "Position cursor has no element";
830 if Position.Node = Root_Node (Position.Container.all) then
831 raise Program_Error with "Position cursor designates root";
834 return Position.Node.Element;
841 function Equal_Children
842 (Left_Subtree : Tree_Node_Access;
843 Right_Subtree : Tree_Node_Access) return Boolean
845 Left_Children : Children_Type renames Left_Subtree.Children;
846 Right_Children : Children_Type renames Right_Subtree.Children;
848 L, R : Tree_Node_Access;
851 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
855 L := Left_Children.First;
856 R := Right_Children.First;
858 if not Equal_Subtree (L, R) then
873 function Equal_Subtree
874 (Left_Position : Cursor;
875 Right_Position : Cursor) return Boolean
878 if Left_Position = No_Element then
879 raise Constraint_Error with "Left cursor has no element";
882 if Right_Position = No_Element then
883 raise Constraint_Error with "Right cursor has no element";
886 if Left_Position = Right_Position then
890 if Is_Root (Left_Position) then
891 if not Is_Root (Right_Position) then
895 return Equal_Children (Left_Position.Node, Right_Position.Node);
898 if Is_Root (Right_Position) then
902 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
905 function Equal_Subtree
906 (Left_Subtree : Tree_Node_Access;
907 Right_Subtree : Tree_Node_Access) return Boolean
910 if Left_Subtree.Element /= Right_Subtree.Element then
914 return Equal_Children (Left_Subtree, Right_Subtree);
921 procedure Finalize (Object : in out Root_Iterator) is
922 B : Natural renames Object.Container.Busy;
933 Item : Element_Type) return Cursor
935 N : constant Tree_Node_Access :=
936 Find_In_Children (Root_Node (Container), Item);
941 return Cursor'(Container'Unrestricted_Access, N);
949 overriding function First (Object : Subtree_Iterator) return Cursor is
951 if Object.Subtree = Root_Node (Object.Container.all) then
952 return First_Child (Root (Object.Container.all));
954 return Cursor'(Object.Container, Object.Subtree);
958 overriding function First (Object : Child_Iterator) return Cursor is
960 return First_Child (Cursor'(Object.Container, Object.Subtree));
967 function First_Child (Parent : Cursor) return Cursor is
968 Node : Tree_Node_Access;
971 if Parent = No_Element then
972 raise Constraint_Error with "Parent cursor has no element";
975 Node := Parent.Node.Children.First;
981 return Cursor'(Parent.Container, Node);
984 -------------------------
985 -- First_Child_Element --
986 -------------------------
988 function First_Child_Element (Parent : Cursor) return Element_Type is
990 return Element (First_Child (Parent));
991 end First_Child_Element;
993 ----------------------
994 -- Find_In_Children --
995 ----------------------
997 function Find_In_Children
998 (Subtree : Tree_Node_Access;
999 Item : Element_Type) return Tree_Node_Access
1001 N, Result : Tree_Node_Access;
1004 N := Subtree.Children.First;
1005 while N /= null loop
1006 Result := Find_In_Subtree (N, Item);
1008 if Result /= null then
1016 end Find_In_Children;
1018 ---------------------
1019 -- Find_In_Subtree --
1020 ---------------------
1022 function Find_In_Subtree
1024 Item : Element_Type) return Cursor
1026 Result : Tree_Node_Access;
1029 if Position = No_Element then
1030 raise Constraint_Error with "Position cursor has no element";
1033 -- Commented out pending official ruling by ARG. ???
1035 -- if Position.Container /= Container'Unrestricted_Access then
1036 -- raise Program_Error with "Position cursor not in container";
1040 (if Is_Root (Position)
1041 then Find_In_Children (Position.Node, Item)
1042 else Find_In_Subtree (Position.Node, Item));
1044 if Result = null then
1048 return Cursor'(Position.Container, Result);
1049 end Find_In_Subtree;
1051 function Find_In_Subtree
1052 (Subtree : Tree_Node_Access;
1053 Item : Element_Type) return Tree_Node_Access
1056 if Subtree.Element = Item then
1060 return Find_In_Children (Subtree, Item);
1061 end Find_In_Subtree;
1067 function Has_Element (Position : Cursor) return Boolean is
1069 return (if Position = No_Element then False
1070 else Position.Node.Parent /= null);
1077 procedure Insert_Child
1078 (Container : in out Tree;
1081 New_Item : Element_Type;
1082 Count : Count_Type := 1)
1085 pragma Unreferenced (Position);
1088 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1091 procedure Insert_Child
1092 (Container : in out Tree;
1095 New_Item : Element_Type;
1096 Position : out Cursor;
1097 Count : Count_Type := 1)
1099 Last : Tree_Node_Access;
1102 if Parent = No_Element then
1103 raise Constraint_Error with "Parent cursor has no element";
1106 if Parent.Container /= Container'Unrestricted_Access then
1107 raise Program_Error with "Parent cursor not in container";
1110 if Before /= No_Element then
1111 if Before.Container /= Container'Unrestricted_Access then
1112 raise Program_Error with "Before cursor not in container";
1115 if Before.Node.Parent /= Parent.Node then
1116 raise Constraint_Error with "Parent cursor not parent of Before";
1121 Position := No_Element; -- Need ruling from ARG ???
1125 if Container.Busy > 0 then
1127 with "attempt to tamper with cursors (tree is busy)";
1130 Position.Container := Parent.Container;
1131 Position.Node := new Tree_Node_Type'(Parent => Parent.Node,
1132 Element => New_Item,
1135 Last := Position.Node;
1137 for J in Count_Type'(2) .. Count loop
1139 -- Reclaim other nodes if Storage_Error. ???
1141 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1143 Element => New_Item,
1150 (First => Position.Node,
1152 Parent => Parent.Node,
1153 Before => Before.Node);
1155 -- In order for operation Node_Count to complete in O(1) time, we cache
1156 -- the count value. Here we increment the total count by the number of
1157 -- nodes we just inserted.
1159 Container.Count := Container.Count + Count;
1162 procedure Insert_Child
1163 (Container : in out Tree;
1166 Position : out Cursor;
1167 Count : Count_Type := 1)
1169 Last : Tree_Node_Access;
1172 if Parent = No_Element then
1173 raise Constraint_Error with "Parent cursor has no element";
1176 if Parent.Container /= Container'Unrestricted_Access then
1177 raise Program_Error with "Parent cursor not in container";
1180 if Before /= No_Element then
1181 if Before.Container /= Container'Unrestricted_Access then
1182 raise Program_Error with "Before cursor not in container";
1185 if Before.Node.Parent /= Parent.Node then
1186 raise Constraint_Error with "Parent cursor not parent of Before";
1191 Position := No_Element; -- Need ruling from ARG ???
1195 if Container.Busy > 0 then
1197 with "attempt to tamper with cursors (tree is busy)";
1200 Position.Container := Parent.Container;
1201 Position.Node := new Tree_Node_Type'(Parent => Parent.Node,
1205 Last := Position.Node;
1207 for J in Count_Type'(2) .. Count loop
1209 -- Reclaim other nodes if Storage_Error. ???
1211 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1220 (First => Position.Node,
1222 Parent => Parent.Node,
1223 Before => Before.Node);
1225 -- In order for operation Node_Count to complete in O(1) time, we cache
1226 -- the count value. Here we increment the total count by the number of
1227 -- nodes we just inserted.
1229 Container.Count := Container.Count + Count;
1232 -------------------------
1233 -- Insert_Subtree_List --
1234 -------------------------
1236 procedure Insert_Subtree_List
1237 (First : Tree_Node_Access;
1238 Last : Tree_Node_Access;
1239 Parent : Tree_Node_Access;
1240 Before : Tree_Node_Access)
1242 pragma Assert (Parent /= null);
1243 C : Children_Type renames Parent.Children;
1246 -- This is a simple utility operation to insert a list of nodes (from
1247 -- First..Last) as children of Parent. The Before node specifies where
1248 -- the new children should be inserted relative to the existing
1251 if First = null then
1252 pragma Assert (Last = null);
1256 pragma Assert (Last /= null);
1257 pragma Assert (Before = null or else Before.Parent = Parent);
1259 if C.First = null then
1261 C.First.Prev := null;
1263 C.Last.Next := null;
1265 elsif Before = null then -- means "insert after existing nodes"
1266 C.Last.Next := First;
1267 First.Prev := C.Last;
1269 C.Last.Next := null;
1271 elsif Before = C.First then
1272 Last.Next := C.First;
1273 C.First.Prev := Last;
1275 C.First.Prev := null;
1278 Before.Prev.Next := First;
1279 First.Prev := Before.Prev;
1280 Last.Next := Before;
1281 Before.Prev := Last;
1283 end Insert_Subtree_List;
1285 -------------------------
1286 -- Insert_Subtree_Node --
1287 -------------------------
1289 procedure Insert_Subtree_Node
1290 (Subtree : Tree_Node_Access;
1291 Parent : Tree_Node_Access;
1292 Before : Tree_Node_Access)
1295 -- This is a simple wrapper operation to insert a single child into the
1296 -- Parent's children list.
1303 end Insert_Subtree_Node;
1309 function Is_Empty (Container : Tree) return Boolean is
1311 return Container.Root.Children.First = null;
1318 function Is_Leaf (Position : Cursor) return Boolean is
1320 return (if Position = No_Element then False
1321 else Position.Node.Children.First = null);
1328 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1329 pragma Assert (From /= null);
1330 pragma Assert (To /= null);
1332 N : Tree_Node_Access;
1336 while N /= null loop
1351 function Is_Root (Position : Cursor) return Boolean is
1353 return (if Position.Container = null then False
1354 else Position = Root (Position.Container.all));
1363 Process : not null access procedure (Position : Cursor))
1365 B : Natural renames Container'Unrestricted_Access.all.Busy;
1371 (Container => Container'Unrestricted_Access,
1372 Subtree => Root_Node (Container),
1373 Process => Process);
1383 function Iterate (Container : Tree)
1384 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1387 return Iterate_Subtree (Root (Container));
1390 ----------------------
1391 -- Iterate_Children --
1392 ----------------------
1394 procedure Iterate_Children
1396 Process : not null access procedure (Position : Cursor))
1399 if Parent = No_Element then
1400 raise Constraint_Error with "Parent cursor has no element";
1404 B : Natural renames Parent.Container.Busy;
1405 C : Tree_Node_Access;
1410 C := Parent.Node.Children.First;
1411 while C /= null loop
1412 Process (Position => Cursor'(Parent.Container, Node => C));
1423 end Iterate_Children;
1425 procedure Iterate_Children
1426 (Container : Tree_Access;
1427 Subtree : Tree_Node_Access;
1428 Process : not null access procedure (Position : Cursor))
1430 Node : Tree_Node_Access;
1433 -- This is a helper function to recursively iterate over all the nodes
1434 -- in a subtree, in depth-first fashion. This particular helper just
1435 -- visits the children of this subtree, not the root of the subtree node
1436 -- itself. This is useful when starting from the ultimate root of the
1437 -- entire tree (see Iterate), as that root does not have an element.
1439 Node := Subtree.Children.First;
1440 while Node /= null loop
1441 Iterate_Subtree (Container, Node, Process);
1444 end Iterate_Children;
1446 function Iterate_Children
1449 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1451 C : constant Tree_Access := Container'Unrestricted_Access;
1452 B : Natural renames C.Busy;
1455 if Parent = No_Element then
1456 raise Constraint_Error with "Parent cursor has no element";
1459 if Parent.Container /= C then
1460 raise Program_Error with "Parent cursor not in container";
1463 return It : constant Child_Iterator :=
1464 (Limited_Controlled with
1466 Subtree => Parent.Node)
1470 end Iterate_Children;
1472 ---------------------
1473 -- Iterate_Subtree --
1474 ---------------------
1476 function Iterate_Subtree
1478 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1481 if Position = No_Element then
1482 raise Constraint_Error with "Position cursor has no element";
1485 -- Implement Vet for multiway trees???
1486 -- pragma Assert (Vet (Position), "bad subtree cursor");
1489 B : Natural renames Position.Container.Busy;
1491 return It : constant Subtree_Iterator :=
1492 (Limited_Controlled with
1493 Container => Position.Container,
1494 Subtree => Position.Node)
1499 end Iterate_Subtree;
1501 procedure Iterate_Subtree
1503 Process : not null access procedure (Position : Cursor))
1506 if Position = No_Element then
1507 raise Constraint_Error with "Position cursor has no element";
1511 B : Natural renames Position.Container.Busy;
1516 if Is_Root (Position) then
1517 Iterate_Children (Position.Container, Position.Node, Process);
1519 Iterate_Subtree (Position.Container, Position.Node, Process);
1529 end Iterate_Subtree;
1531 procedure Iterate_Subtree
1532 (Container : Tree_Access;
1533 Subtree : Tree_Node_Access;
1534 Process : not null access procedure (Position : Cursor))
1537 -- This is a helper function to recursively iterate over all the nodes
1538 -- in a subtree, in depth-first fashion. It first visits the root of the
1539 -- subtree, then visits its children.
1541 Process (Cursor'(Container, Subtree));
1542 Iterate_Children (Container, Subtree, Process);
1543 end Iterate_Subtree;
1549 overriding function Last (Object : Child_Iterator) return Cursor is
1551 return Last_Child (Cursor'(Object.Container, Object.Subtree));
1558 function Last_Child (Parent : Cursor) return Cursor is
1559 Node : Tree_Node_Access;
1562 if Parent = No_Element then
1563 raise Constraint_Error with "Parent cursor has no element";
1566 Node := Parent.Node.Children.Last;
1572 return (Parent.Container, Node);
1575 ------------------------
1576 -- Last_Child_Element --
1577 ------------------------
1579 function Last_Child_Element (Parent : Cursor) return Element_Type is
1581 return Element (Last_Child (Parent));
1582 end Last_Child_Element;
1588 procedure Move (Target : in out Tree; Source : in out Tree) is
1589 Node : Tree_Node_Access;
1592 if Target'Address = Source'Address then
1596 if Source.Busy > 0 then
1598 with "attempt to tamper with cursors of Source (tree is busy)";
1601 Target.Clear; -- checks busy bit
1603 Target.Root.Children := Source.Root.Children;
1604 Source.Root.Children := Children_Type'(others => null);
1606 Node := Target.Root.Children.First;
1607 while Node /= null loop
1608 Node.Parent := Root_Node (Target);
1612 Target.Count := Source.Count;
1621 (Object : Subtree_Iterator;
1622 Position : Cursor) return Cursor
1624 Node : Tree_Node_Access;
1627 if Position.Container = null then
1631 if Position.Container /= Object.Container then
1632 raise Program_Error with
1633 "Position cursor of Next designates wrong tree";
1636 Node := Position.Node;
1638 if Node.Children.First /= null then
1639 return Cursor'(Object.Container, Node.Children.First);
1642 while Node /= Object.Subtree loop
1643 if Node.Next /= null then
1644 return Cursor'(Object.Container, Node.Next);
1647 Node := Node.Parent;
1654 (Object : Child_Iterator;
1655 Position : Cursor) return Cursor
1658 if Position.Container = null then
1662 if Position.Container /= Object.Container then
1663 raise Program_Error with
1664 "Position cursor of Next designates wrong tree";
1667 return Next_Sibling (Position);
1674 function Next_Sibling (Position : Cursor) return Cursor is
1676 if Position = No_Element then
1680 if Position.Node.Next = null then
1684 return Cursor'(Position.Container, Position.Node.Next);
1687 procedure Next_Sibling (Position : in out Cursor) is
1689 Position := Next_Sibling (Position);
1696 function Node_Count (Container : Tree) return Count_Type is
1698 -- Container.Count is the number of nodes we have actually allocated. We
1699 -- cache the value specifically so this Node_Count operation can execute
1700 -- in O(1) time, which makes it behave similarly to how the Length
1701 -- selector function behaves for other containers.
1703 -- The cached node count value only describes the nodes we have
1704 -- allocated; the root node itself is not included in that count. The
1705 -- Node_Count operation returns a value that includes the root node
1706 -- (because the RM says so), so we must add 1 to our cached value.
1708 return 1 + Container.Count;
1715 function Parent (Position : Cursor) return Cursor is
1717 if Position = No_Element then
1721 if Position.Node.Parent = null then
1725 return Cursor'(Position.Container, Position.Node.Parent);
1732 procedure Prepend_Child
1733 (Container : in out Tree;
1735 New_Item : Element_Type;
1736 Count : Count_Type := 1)
1738 First, Last : Tree_Node_Access;
1741 if Parent = No_Element then
1742 raise Constraint_Error with "Parent cursor has no element";
1745 if Parent.Container /= Container'Unrestricted_Access then
1746 raise Program_Error with "Parent cursor not in container";
1753 if Container.Busy > 0 then
1755 with "attempt to tamper with cursors (tree is busy)";
1758 First := new Tree_Node_Type'(Parent => Parent.Node,
1759 Element => New_Item,
1764 for J in Count_Type'(2) .. Count loop
1766 -- Reclaim other nodes if Storage_Error???
1768 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1770 Element => New_Item,
1779 Parent => Parent.Node,
1780 Before => Parent.Node.Children.First);
1782 -- In order for operation Node_Count to complete in O(1) time, we cache
1783 -- the count value. Here we increment the total count by the number of
1784 -- nodes we just inserted.
1786 Container.Count := Container.Count + Count;
1793 overriding function Previous
1794 (Object : Child_Iterator;
1795 Position : Cursor) return Cursor
1798 if Position.Container = null then
1802 if Position.Container /= Object.Container then
1803 raise Program_Error with
1804 "Position cursor of Previous designates wrong tree";
1807 return Previous_Sibling (Position);
1810 ----------------------
1811 -- Previous_Sibling --
1812 ----------------------
1814 function Previous_Sibling (Position : Cursor) return Cursor is
1817 (if Position = No_Element then No_Element
1818 elsif Position.Node.Prev = null then No_Element
1819 else Cursor'(Position.Container, Position.Node.Prev));
1820 end Previous_Sibling;
1822 procedure Previous_Sibling (Position : in out Cursor) is
1824 Position := Previous_Sibling (Position);
1825 end Previous_Sibling;
1831 procedure Query_Element
1833 Process : not null access procedure (Element : Element_Type))
1836 if Position = No_Element then
1837 raise Constraint_Error with "Position cursor has no element";
1840 if Is_Root (Position) then
1841 raise Program_Error with "Position cursor designates root";
1845 T : Tree renames Position.Container.all'Unrestricted_Access.all;
1846 B : Natural renames T.Busy;
1847 L : Natural renames T.Lock;
1853 Process (Position.Node.Element);
1871 (Stream : not null access Root_Stream_Type'Class;
1872 Container : out Tree)
1874 procedure Read_Children (Subtree : Tree_Node_Access);
1876 function Read_Subtree
1877 (Parent : Tree_Node_Access) return Tree_Node_Access;
1879 Total_Count : Count_Type'Base;
1880 -- Value read from the stream that says how many elements follow
1882 Read_Count : Count_Type'Base;
1883 -- Actual number of elements read from the stream
1889 procedure Read_Children (Subtree : Tree_Node_Access) is
1890 pragma Assert (Subtree /= null);
1891 pragma Assert (Subtree.Children.First = null);
1892 pragma Assert (Subtree.Children.Last = null);
1894 Count : Count_Type'Base;
1895 -- Number of child subtrees
1900 Count_Type'Read (Stream, Count);
1903 raise Program_Error with "attempt to read from corrupt stream";
1910 C.First := Read_Subtree (Parent => Subtree);
1913 for J in Count_Type'(2) .. Count loop
1914 C.Last.Next := Read_Subtree (Parent => Subtree);
1915 C.Last.Next.Prev := C.Last;
1916 C.Last := C.Last.Next;
1919 -- Now that the allocation and reads have completed successfully, it
1920 -- is safe to link the children to their parent.
1922 Subtree.Children := C;
1929 function Read_Subtree
1930 (Parent : Tree_Node_Access) return Tree_Node_Access
1932 Subtree : constant Tree_Node_Access :=
1935 Element => Element_Type'Input (Stream),
1939 Read_Count := Read_Count + 1;
1941 Read_Children (Subtree);
1946 -- Start of processing for Read
1949 Container.Clear; -- checks busy bit
1951 Count_Type'Read (Stream, Total_Count);
1953 if Total_Count < 0 then
1954 raise Program_Error with "attempt to read from corrupt stream";
1957 if Total_Count = 0 then
1963 Read_Children (Root_Node (Container));
1965 if Read_Count /= Total_Count then
1966 raise Program_Error with "attempt to read from corrupt stream";
1969 Container.Count := Total_Count;
1973 (Stream : not null access Root_Stream_Type'Class;
1974 Position : out Cursor)
1977 raise Program_Error with "attempt to read tree cursor from stream";
1981 (Stream : not null access Root_Stream_Type'Class;
1982 Item : out Reference_Type)
1985 raise Program_Error with "attempt to stream reference";
1989 (Stream : not null access Root_Stream_Type'Class;
1990 Item : out Constant_Reference_Type)
1993 raise Program_Error with "attempt to stream reference";
2000 function Constant_Reference
2001 (Container : aliased Tree;
2002 Position : Cursor) return Constant_Reference_Type
2005 pragma Unreferenced (Container);
2007 return (Element => Position.Node.Element'Unrestricted_Access);
2008 end Constant_Reference;
2011 (Container : aliased Tree;
2012 Position : Cursor) return Reference_Type
2015 pragma Unreferenced (Container);
2017 return (Element => Position.Node.Element'Unrestricted_Access);
2020 --------------------
2021 -- Remove_Subtree --
2022 --------------------
2024 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2025 C : Children_Type renames Subtree.Parent.Children;
2028 -- This is a utility operation to remove a subtree node from its
2029 -- parent's list of children.
2031 if C.First = Subtree then
2032 pragma Assert (Subtree.Prev = null);
2034 if C.Last = Subtree then
2035 pragma Assert (Subtree.Next = null);
2040 C.First := Subtree.Next;
2041 C.First.Prev := null;
2044 elsif C.Last = Subtree then
2045 pragma Assert (Subtree.Next = null);
2046 C.Last := Subtree.Prev;
2047 C.Last.Next := null;
2050 Subtree.Prev.Next := Subtree.Next;
2051 Subtree.Next.Prev := Subtree.Prev;
2055 ----------------------
2056 -- Replace_Element --
2057 ----------------------
2059 procedure Replace_Element
2060 (Container : in out Tree;
2062 New_Item : Element_Type)
2065 if Position = No_Element then
2066 raise Constraint_Error with "Position cursor has no element";
2069 if Position.Container /= Container'Unrestricted_Access then
2070 raise Program_Error with "Position cursor not in container";
2073 if Is_Root (Position) then
2074 raise Program_Error with "Position cursor designates root";
2077 if Container.Lock > 0 then
2079 with "attempt to tamper with elements (tree is locked)";
2082 Position.Node.Element := New_Item;
2083 end Replace_Element;
2085 ------------------------------
2086 -- Reverse_Iterate_Children --
2087 ------------------------------
2089 procedure Reverse_Iterate_Children
2091 Process : not null access procedure (Position : Cursor))
2094 if Parent = No_Element then
2095 raise Constraint_Error with "Parent cursor has no element";
2099 B : Natural renames Parent.Container.Busy;
2100 C : Tree_Node_Access;
2105 C := Parent.Node.Children.Last;
2106 while C /= null loop
2107 Process (Position => Cursor'(Parent.Container, Node => C));
2118 end Reverse_Iterate_Children;
2124 function Root (Container : Tree) return Cursor is
2126 return (Container'Unrestricted_Access, Root_Node (Container));
2133 function Root_Node (Container : Tree) return Tree_Node_Access is
2134 type Root_Node_Access is access all Root_Node_Type;
2135 for Root_Node_Access'Storage_Size use 0;
2136 pragma Convention (C, Root_Node_Access);
2138 function To_Tree_Node_Access is
2139 new Ada.Unchecked_Conversion (Root_Node_Access, Tree_Node_Access);
2141 -- Start of processing for Root_Node
2144 -- This is a utility function for converting from an access type that
2145 -- designates the distinguished root node to an access type designating
2146 -- a non-root node. The representation of a root node does not have an
2147 -- element, but is otherwise identical to a non-root node, so the
2148 -- conversion itself is safe.
2150 return To_Tree_Node_Access (Container.Root'Unrestricted_Access);
2153 ---------------------
2154 -- Splice_Children --
2155 ---------------------
2157 procedure Splice_Children
2158 (Target : in out Tree;
2159 Target_Parent : Cursor;
2161 Source : in out Tree;
2162 Source_Parent : Cursor)
2167 if Target_Parent = No_Element then
2168 raise Constraint_Error with "Target_Parent cursor has no element";
2171 if Target_Parent.Container /= Target'Unrestricted_Access then
2173 with "Target_Parent cursor not in Target container";
2176 if Before /= No_Element then
2177 if Before.Container /= Target'Unrestricted_Access then
2179 with "Before cursor not in Target container";
2182 if Before.Node.Parent /= Target_Parent.Node then
2183 raise Constraint_Error
2184 with "Before cursor not child of Target_Parent";
2188 if Source_Parent = No_Element then
2189 raise Constraint_Error with "Source_Parent cursor has no element";
2192 if Source_Parent.Container /= Source'Unrestricted_Access then
2194 with "Source_Parent cursor not in Source container";
2197 if Target'Address = Source'Address then
2198 if Target_Parent = Source_Parent then
2202 if Target.Busy > 0 then
2204 with "attempt to tamper with cursors (Target tree is busy)";
2207 if Is_Reachable (From => Target_Parent.Node,
2208 To => Source_Parent.Node)
2210 raise Constraint_Error
2211 with "Source_Parent is ancestor of Target_Parent";
2215 (Target_Parent => Target_Parent.Node,
2216 Before => Before.Node,
2217 Source_Parent => Source_Parent.Node);
2222 if Target.Busy > 0 then
2224 with "attempt to tamper with cursors (Target tree is busy)";
2227 if Source.Busy > 0 then
2229 with "attempt to tamper with cursors (Source tree is busy)";
2232 -- We cache the count of the nodes we have allocated, so that operation
2233 -- Node_Count can execute in O(1) time. But that means we must count the
2234 -- nodes in the subtree we remove from Source and insert into Target, in
2235 -- order to keep the count accurate.
2237 Count := Subtree_Node_Count (Source_Parent.Node);
2238 pragma Assert (Count >= 1);
2240 Count := Count - 1; -- because Source_Parent node does not move
2243 (Target_Parent => Target_Parent.Node,
2244 Before => Before.Node,
2245 Source_Parent => Source_Parent.Node);
2247 Source.Count := Source.Count - Count;
2248 Target.Count := Target.Count + Count;
2249 end Splice_Children;
2251 procedure Splice_Children
2252 (Container : in out Tree;
2253 Target_Parent : Cursor;
2255 Source_Parent : Cursor)
2258 if Target_Parent = No_Element then
2259 raise Constraint_Error with "Target_Parent cursor has no element";
2262 if Target_Parent.Container /= Container'Unrestricted_Access then
2264 with "Target_Parent cursor not in container";
2267 if Before /= No_Element then
2268 if Before.Container /= Container'Unrestricted_Access then
2270 with "Before cursor not in container";
2273 if Before.Node.Parent /= Target_Parent.Node then
2274 raise Constraint_Error
2275 with "Before cursor not child of Target_Parent";
2279 if Source_Parent = No_Element then
2280 raise Constraint_Error with "Source_Parent cursor has no element";
2283 if Source_Parent.Container /= Container'Unrestricted_Access then
2285 with "Source_Parent cursor not in container";
2288 if Target_Parent = Source_Parent then
2292 if Container.Busy > 0 then
2294 with "attempt to tamper with cursors (tree is busy)";
2297 if Is_Reachable (From => Target_Parent.Node,
2298 To => Source_Parent.Node)
2300 raise Constraint_Error
2301 with "Source_Parent is ancestor of Target_Parent";
2305 (Target_Parent => Target_Parent.Node,
2306 Before => Before.Node,
2307 Source_Parent => Source_Parent.Node);
2308 end Splice_Children;
2310 procedure Splice_Children
2311 (Target_Parent : Tree_Node_Access;
2312 Before : Tree_Node_Access;
2313 Source_Parent : Tree_Node_Access)
2315 CC : constant Children_Type := Source_Parent.Children;
2316 C : Tree_Node_Access;
2319 -- This is a utility operation to remove the children from
2320 -- Source parent and insert them into Target parent.
2322 Source_Parent.Children := Children_Type'(others => null);
2324 -- Fix up the Parent pointers of each child to designate
2325 -- its new Target parent.
2328 while C /= null loop
2329 C.Parent := Target_Parent;
2336 Parent => Target_Parent,
2338 end Splice_Children;
2340 --------------------
2341 -- Splice_Subtree --
2342 --------------------
2344 procedure Splice_Subtree
2345 (Target : in out Tree;
2348 Source : in out Tree;
2349 Position : in out Cursor)
2351 Subtree_Count : Count_Type;
2354 if Parent = No_Element then
2355 raise Constraint_Error with "Parent cursor has no element";
2358 if Parent.Container /= Target'Unrestricted_Access then
2359 raise Program_Error with "Parent cursor not in Target container";
2362 if Before /= No_Element then
2363 if Before.Container /= Target'Unrestricted_Access then
2364 raise Program_Error with "Before cursor not in Target container";
2367 if Before.Node.Parent /= Parent.Node then
2368 raise Constraint_Error with "Before cursor not child of Parent";
2372 if Position = No_Element then
2373 raise Constraint_Error with "Position cursor has no element";
2376 if Position.Container /= Source'Unrestricted_Access then
2377 raise Program_Error with "Position cursor not in Source container";
2380 if Is_Root (Position) then
2381 raise Program_Error with "Position cursor designates root";
2384 if Target'Address = Source'Address then
2385 if Position.Node.Parent = Parent.Node then
2386 if Position.Node = Before.Node then
2390 if Position.Node.Next = Before.Node then
2395 if Target.Busy > 0 then
2397 with "attempt to tamper with cursors (Target tree is busy)";
2400 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2401 raise Constraint_Error with "Position is ancestor of Parent";
2404 Remove_Subtree (Position.Node);
2406 Position.Node.Parent := Parent.Node;
2407 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2412 if Target.Busy > 0 then
2414 with "attempt to tamper with cursors (Target tree is busy)";
2417 if Source.Busy > 0 then
2419 with "attempt to tamper with cursors (Source tree is busy)";
2422 -- This is an unfortunate feature of this API: we must count the nodes
2423 -- in the subtree that we remove from the source tree, which is an O(n)
2424 -- operation. It would have been better if the Tree container did not
2425 -- have a Node_Count selector; a user that wants the number of nodes in
2426 -- the tree could simply call Subtree_Node_Count, with the understanding
2427 -- that such an operation is O(n).
2429 -- Of course, we could choose to implement the Node_Count selector as an
2430 -- O(n) operation, which would turn this splice operation into an O(1)
2433 Subtree_Count := Subtree_Node_Count (Position.Node);
2434 pragma Assert (Subtree_Count <= Source.Count);
2436 Remove_Subtree (Position.Node);
2437 Source.Count := Source.Count - Subtree_Count;
2439 Position.Node.Parent := Parent.Node;
2440 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2442 Target.Count := Target.Count + Subtree_Count;
2444 Position.Container := Target'Unrestricted_Access;
2447 procedure Splice_Subtree
2448 (Container : in out Tree;
2454 if Parent = No_Element then
2455 raise Constraint_Error with "Parent cursor has no element";
2458 if Parent.Container /= Container'Unrestricted_Access then
2459 raise Program_Error with "Parent cursor not in container";
2462 if Before /= No_Element then
2463 if Before.Container /= Container'Unrestricted_Access then
2464 raise Program_Error with "Before cursor not in container";
2467 if Before.Node.Parent /= Parent.Node then
2468 raise Constraint_Error with "Before cursor not child of Parent";
2472 if Position = No_Element then
2473 raise Constraint_Error with "Position cursor has no element";
2476 if Position.Container /= Container'Unrestricted_Access then
2477 raise Program_Error with "Position cursor not in container";
2480 if Is_Root (Position) then
2482 -- Should this be PE instead? Need ARG confirmation. ???
2484 raise Constraint_Error with "Position cursor designates root";
2487 if Position.Node.Parent = Parent.Node then
2488 if Position.Node = Before.Node then
2492 if Position.Node.Next = Before.Node then
2497 if Container.Busy > 0 then
2499 with "attempt to tamper with cursors (tree is busy)";
2502 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2503 raise Constraint_Error with "Position is ancestor of Parent";
2506 Remove_Subtree (Position.Node);
2508 Position.Node.Parent := Parent.Node;
2509 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2512 ------------------------
2513 -- Subtree_Node_Count --
2514 ------------------------
2516 function Subtree_Node_Count (Position : Cursor) return Count_Type is
2518 if Position = No_Element then
2522 return Subtree_Node_Count (Position.Node);
2523 end Subtree_Node_Count;
2525 function Subtree_Node_Count
2526 (Subtree : Tree_Node_Access) return Count_Type
2528 Result : Count_Type;
2529 Node : Tree_Node_Access;
2533 Node := Subtree.Children.First;
2534 while Node /= null loop
2535 Result := Result + Subtree_Node_Count (Node);
2540 end Subtree_Node_Count;
2547 (Container : in out Tree;
2551 if I = No_Element then
2552 raise Constraint_Error with "I cursor has no element";
2555 if I.Container /= Container'Unrestricted_Access then
2556 raise Program_Error with "I cursor not in container";
2560 raise Program_Error with "I cursor designates root";
2563 if I = J then -- make this test sooner???
2567 if J = No_Element then
2568 raise Constraint_Error with "J cursor has no element";
2571 if J.Container /= Container'Unrestricted_Access then
2572 raise Program_Error with "J cursor not in container";
2576 raise Program_Error with "J cursor designates root";
2579 if Container.Lock > 0 then
2581 with "attempt to tamper with elements (tree is locked)";
2585 EI : constant Element_Type := I.Node.Element;
2588 I.Node.Element := J.Node.Element;
2589 J.Node.Element := EI;
2593 --------------------
2594 -- Update_Element --
2595 --------------------
2597 procedure Update_Element
2598 (Container : in out Tree;
2600 Process : not null access procedure (Element : in out Element_Type))
2603 if Position = No_Element then
2604 raise Constraint_Error with "Position cursor has no element";
2607 if Position.Container /= Container'Unrestricted_Access then
2608 raise Program_Error with "Position cursor not in container";
2611 if Is_Root (Position) then
2612 raise Program_Error with "Position cursor designates root";
2616 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2617 B : Natural renames T.Busy;
2618 L : Natural renames T.Lock;
2624 Process (Position.Node.Element);
2642 (Stream : not null access Root_Stream_Type'Class;
2645 procedure Write_Children (Subtree : Tree_Node_Access);
2646 procedure Write_Subtree (Subtree : Tree_Node_Access);
2648 --------------------
2649 -- Write_Children --
2650 --------------------
2652 procedure Write_Children (Subtree : Tree_Node_Access) is
2653 CC : Children_Type renames Subtree.Children;
2654 C : Tree_Node_Access;
2657 Count_Type'Write (Stream, Child_Count (CC));
2660 while C /= null loop
2670 procedure Write_Subtree (Subtree : Tree_Node_Access) is
2672 Element_Type'Output (Stream, Subtree.Element);
2673 Write_Children (Subtree);
2676 -- Start of processing for Write
2679 Count_Type'Write (Stream, Container.Count);
2681 if Container.Count = 0 then
2685 Write_Children (Root_Node (Container));
2689 (Stream : not null access Root_Stream_Type'Class;
2693 raise Program_Error with "attempt to write tree cursor to stream";
2697 (Stream : not null access Root_Stream_Type'Class;
2698 Item : Reference_Type)
2701 raise Program_Error with "attempt to stream reference";
2705 (Stream : not null access Root_Stream_Type'Class;
2706 Item : Constant_Reference_Type)
2709 raise Program_Error with "attempt to stream reference";
2712 end Ada.Containers.Multiway_Trees;