1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.INDEFINITE_MULTIWAY_TREES --
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_Deallocation;
32 with System; use type System.Address;
34 package body Ada.Containers.Indefinite_Multiway_Trees is
40 type Root_Iterator is abstract new Limited_Controlled and
41 Tree_Iterator_Interfaces.Forward_Iterator with
43 Container : Tree_Access;
44 Subtree : Tree_Node_Access;
47 overriding procedure Finalize (Object : in out Root_Iterator);
49 -----------------------
50 -- Subtree_Iterator --
51 -----------------------
53 type Subtree_Iterator is new Root_Iterator with null record;
55 overriding function First (Object : Subtree_Iterator) return Cursor;
57 overriding function Next
58 (Object : Subtree_Iterator;
59 Position : Cursor) return Cursor;
65 type Child_Iterator is new Root_Iterator and
66 Tree_Iterator_Interfaces.Reversible_Iterator with null record;
68 overriding function First (Object : Child_Iterator) return Cursor;
70 overriding function Next
71 (Object : Child_Iterator;
72 Position : Cursor) return Cursor;
74 overriding function Last (Object : Child_Iterator) return Cursor;
76 overriding function Previous
77 (Object : Child_Iterator;
78 Position : Cursor) return Cursor;
80 -----------------------
81 -- Local Subprograms --
82 -----------------------
84 function Root_Node (Container : Tree) return Tree_Node_Access;
86 procedure Free_Element is
87 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
89 procedure Deallocate_Node (X : in out Tree_Node_Access);
91 procedure Deallocate_Children
92 (Subtree : Tree_Node_Access;
93 Count : in out Count_Type);
95 procedure Deallocate_Subtree
96 (Subtree : in out Tree_Node_Access;
97 Count : in out Count_Type);
99 function Equal_Children
100 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
102 function Equal_Subtree
103 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
105 procedure Iterate_Children
106 (Container : Tree_Access;
107 Subtree : Tree_Node_Access;
108 Process : not null access procedure (Position : Cursor));
110 procedure Iterate_Subtree
111 (Container : Tree_Access;
112 Subtree : Tree_Node_Access;
113 Process : not null access procedure (Position : Cursor));
115 procedure Copy_Children
116 (Source : Children_Type;
117 Parent : Tree_Node_Access;
118 Count : in out Count_Type);
120 procedure Copy_Subtree
121 (Source : Tree_Node_Access;
122 Parent : Tree_Node_Access;
123 Target : out Tree_Node_Access;
124 Count : in out Count_Type);
126 function Find_In_Children
127 (Subtree : Tree_Node_Access;
128 Item : Element_Type) return Tree_Node_Access;
130 function Find_In_Subtree
131 (Subtree : Tree_Node_Access;
132 Item : Element_Type) return Tree_Node_Access;
134 function Child_Count (Children : Children_Type) return Count_Type;
136 function Subtree_Node_Count
137 (Subtree : Tree_Node_Access) return Count_Type;
139 function Is_Reachable (From, To : Tree_Node_Access) return Boolean;
141 procedure Remove_Subtree (Subtree : Tree_Node_Access);
143 procedure Insert_Subtree_Node
144 (Subtree : Tree_Node_Access;
145 Parent : Tree_Node_Access;
146 Before : Tree_Node_Access);
148 procedure Insert_Subtree_List
149 (First : Tree_Node_Access;
150 Last : Tree_Node_Access;
151 Parent : Tree_Node_Access;
152 Before : Tree_Node_Access);
154 procedure Splice_Children
155 (Target_Parent : Tree_Node_Access;
156 Before : Tree_Node_Access;
157 Source_Parent : Tree_Node_Access);
163 function "=" (Left, Right : Tree) return Boolean is
165 if Left'Address = Right'Address then
169 return Equal_Children (Root_Node (Left), Root_Node (Right));
176 procedure Adjust (Container : in out Tree) is
177 Source : constant Children_Type := Container.Root.Children;
178 Source_Count : constant Count_Type := Container.Count;
179 Target_Count : Count_Type;
182 -- We first restore the target container to its default-initialized
183 -- state, before we attempt any allocation, to ensure that invariants
184 -- are preserved in the event that the allocation fails.
186 Container.Root.Children := Children_Type'(others => null);
189 Container.Count := 0;
191 -- Copy_Children returns a count of the number of nodes that it
192 -- allocates, but it works by incrementing the value that is passed in.
193 -- We must therefore initialize the count value before calling
198 -- Now we attempt the allocation of subtrees. The invariants are
199 -- satisfied even if the allocation fails.
201 Copy_Children (Source, Root_Node (Container), Target_Count);
202 pragma Assert (Target_Count = Source_Count);
204 Container.Count := Source_Count;
211 function Ancestor_Find
213 Item : Element_Type) return Cursor
215 R, N : Tree_Node_Access;
218 if Position = No_Element then
219 raise Constraint_Error with "Position cursor has no element";
222 -- Commented-out pending ARG ruling. ???
224 -- if Position.Container /= Container'Unrestricted_Access then
225 -- raise Program_Error with "Position cursor not in container";
228 -- AI-0136 says to raise PE if Position equals the root node. This does
229 -- not seem correct, as this value is just the limiting condition of the
230 -- search. For now we omit this check pending a ruling from the ARG.???
232 -- if Is_Root (Position) then
233 -- raise Program_Error with "Position cursor designates root";
236 R := Root_Node (Position.Container.all);
239 if N.Element.all = Item then
240 return Cursor'(Position.Container, N);
253 procedure Append_Child
254 (Container : in out Tree;
256 New_Item : Element_Type;
257 Count : Count_Type := 1)
259 First, Last : Tree_Node_Access;
260 Element : Element_Access;
263 if Parent = No_Element then
264 raise Constraint_Error with "Parent cursor has no element";
267 if Parent.Container /= Container'Unrestricted_Access then
268 raise Program_Error with "Parent cursor not in container";
275 if Container.Busy > 0 then
277 with "attempt to tamper with cursors (tree is busy)";
280 Element := new Element_Type'(New_Item);
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 Element := new Element_Type'(New_Item);
292 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
303 Parent => Parent.Node,
304 Before => null); -- null means "insert at end of list"
306 -- In order for operation Node_Count to complete in O(1) time, we cache
307 -- the count value. Here we increment the total count by the number of
308 -- nodes we just inserted.
310 Container.Count := Container.Count + Count;
317 procedure Assign (Target : in out Tree; Source : Tree) is
318 Source_Count : constant Count_Type := Source.Count;
319 Target_Count : Count_Type;
322 if Target'Address = Source'Address then
326 Target.Clear; -- checks busy bit
328 -- Copy_Children returns the number of nodes that it allocates, but it
329 -- does this by incrementing the count value passed in, so we must
330 -- initialize the count before calling Copy_Children.
334 -- Note that Copy_Children inserts the newly-allocated children into
335 -- their parent list only after the allocation of all the children has
336 -- succeeded. This preserves invariants even if the allocation fails.
338 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
339 pragma Assert (Target_Count = Source_Count);
341 Target.Count := Source_Count;
348 function Child_Count (Parent : Cursor) return Count_Type is
350 if Parent = No_Element then
353 return Child_Count (Parent.Node.Children);
357 function Child_Count (Children : Children_Type) return Count_Type is
359 Node : Tree_Node_Access;
363 Node := Children.First;
364 while Node /= null loop
365 Result := Result + 1;
376 function Child_Depth (Parent, Child : Cursor) return Count_Type is
378 N : Tree_Node_Access;
381 if Parent = No_Element then
382 raise Constraint_Error with "Parent cursor has no element";
385 if Child = No_Element then
386 raise Constraint_Error with "Child cursor has no element";
389 if Parent.Container /= Child.Container then
390 raise Program_Error with "Parent and Child in different containers";
395 while N /= Parent.Node loop
396 Result := Result + 1;
400 raise Program_Error with "Parent is not ancestor of Child";
411 procedure Clear (Container : in out Tree) is
412 Container_Count : Count_Type;
413 Children_Count : Count_Type;
416 if Container.Busy > 0 then
418 with "attempt to tamper with cursors (tree is busy)";
421 -- We first set the container count to 0, in order to preserve
422 -- invariants in case the deallocation fails. (This works because
423 -- Deallocate_Children immediately removes the children from their
424 -- parent, and then does the actual deallocation.)
426 Container_Count := Container.Count;
427 Container.Count := 0;
429 -- Deallocate_Children returns the number of nodes that it deallocates,
430 -- but it does this by incrementing the count value that is passed in,
431 -- so we must first initialize the count return value before calling it.
435 -- See comment above. Deallocate_Children immediately removes the
436 -- children list from their parent node (here, the root of the tree),
437 -- and only after that does it attempt the actual deallocation. So even
438 -- if the deallocation fails, the representation invariants
440 Deallocate_Children (Root_Node (Container), Children_Count);
441 pragma Assert (Children_Count = Container_Count);
450 Item : Element_Type) return Boolean
453 return Find (Container, Item) /= No_Element;
460 function Copy (Source : Tree) return Tree is
462 return Target : Tree do
464 (Source => Source.Root.Children,
465 Parent => Root_Node (Target),
466 Count => Target.Count);
468 pragma Assert (Target.Count = Source.Count);
476 procedure Copy_Children
477 (Source : Children_Type;
478 Parent : Tree_Node_Access;
479 Count : in out Count_Type)
481 pragma Assert (Parent /= null);
482 pragma Assert (Parent.Children.First = null);
483 pragma Assert (Parent.Children.Last = null);
486 C : Tree_Node_Access;
489 -- We special-case the first allocation, in order to establish the
490 -- representation invariants for type Children_Type.
506 -- The representation invariants for the Children_Type list have been
507 -- established, so we can now copy the remaining children of Source.
514 Target => CC.Last.Next,
517 CC.Last.Next.Prev := CC.Last;
518 CC.Last := CC.Last.Next;
523 -- We add the newly-allocated children to their parent list only after
524 -- the allocation has succeeded, in order to preserve invariants of the
527 Parent.Children := CC;
534 procedure Copy_Subtree
535 (Target : in out Tree;
540 Target_Subtree : Tree_Node_Access;
541 Target_Count : Count_Type;
544 if Parent = No_Element then
545 raise Constraint_Error with "Parent cursor has no element";
548 if Parent.Container /= Target'Unrestricted_Access then
549 raise Program_Error with "Parent cursor not in container";
552 if Before /= No_Element then
553 if Before.Container /= Target'Unrestricted_Access then
554 raise Program_Error with "Before cursor not in container";
557 if Before.Node.Parent /= Parent.Node then
558 raise Constraint_Error with "Before cursor not child of Parent";
562 if Source = No_Element then
566 if Is_Root (Source) then
567 raise Constraint_Error with "Source cursor designates root";
570 -- Copy_Subtree returns a count of the number of nodes that it
571 -- allocates, but it works by incrementing the value that is passed in.
572 -- We must therefore initialize the count value before calling
578 (Source => Source.Node,
579 Parent => Parent.Node,
580 Target => Target_Subtree,
581 Count => Target_Count);
583 pragma Assert (Target_Subtree /= null);
584 pragma Assert (Target_Subtree.Parent = Parent.Node);
585 pragma Assert (Target_Count >= 1);
588 (Subtree => Target_Subtree,
589 Parent => Parent.Node,
590 Before => Before.Node);
592 -- In order for operation Node_Count to complete in O(1) time, we cache
593 -- the count value. Here we increment the total count by the number of
594 -- nodes we just inserted.
596 Target.Count := Target.Count + Target_Count;
599 procedure Copy_Subtree
600 (Source : Tree_Node_Access;
601 Parent : Tree_Node_Access;
602 Target : out Tree_Node_Access;
603 Count : in out Count_Type)
605 E : constant Element_Access := new Element_Type'(Source.Element.all);
608 Target := new Tree_Node_Type'(Element => E,
615 (Source => Source.Children,
620 -------------------------
621 -- Deallocate_Children --
622 -------------------------
624 procedure Deallocate_Children
625 (Subtree : Tree_Node_Access;
626 Count : in out Count_Type)
628 pragma Assert (Subtree /= null);
630 CC : Children_Type := Subtree.Children;
631 C : Tree_Node_Access;
634 -- We immediately remove the children from their parent, in order to
635 -- preserve invariants in case the deallocation fails.
637 Subtree.Children := Children_Type'(others => null);
639 while CC.First /= null loop
643 Deallocate_Subtree (C, Count);
645 end Deallocate_Children;
647 ---------------------
648 -- Deallocate_Node --
649 ---------------------
651 procedure Deallocate_Node (X : in out Tree_Node_Access) is
652 procedure Free_Node is
653 new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access);
655 -- Start of processing for Deallocate_Node
659 Free_Element (X.Element);
664 ------------------------
665 -- Deallocate_Subtree --
666 ------------------------
668 procedure Deallocate_Subtree
669 (Subtree : in out Tree_Node_Access;
670 Count : in out Count_Type)
673 Deallocate_Children (Subtree, Count);
674 Deallocate_Node (Subtree);
676 end Deallocate_Subtree;
678 ---------------------
679 -- Delete_Children --
680 ---------------------
682 procedure Delete_Children
683 (Container : in out Tree;
689 if Parent = No_Element then
690 raise Constraint_Error with "Parent cursor has no element";
693 if Parent.Container /= Container'Unrestricted_Access then
694 raise Program_Error with "Parent cursor not in container";
697 if Container.Busy > 0 then
699 with "attempt to tamper with cursors (tree is busy)";
702 -- Deallocate_Children returns a count of the number of nodes
703 -- that it deallocates, but it works by incrementing the
704 -- value that is passed in. We must therefore initialize
705 -- the count value before calling Deallocate_Children.
709 Deallocate_Children (Parent.Node, Count);
710 pragma Assert (Count <= Container.Count);
712 Container.Count := Container.Count - Count;
719 procedure Delete_Leaf
720 (Container : in out Tree;
721 Position : in out Cursor)
723 X : Tree_Node_Access;
726 if Position = No_Element then
727 raise Constraint_Error with "Position cursor has no element";
730 if Position.Container /= Container'Unrestricted_Access then
731 raise Program_Error with "Position cursor not in container";
734 if Is_Root (Position) then
735 raise Program_Error with "Position cursor designates root";
738 if not Is_Leaf (Position) then
739 raise Constraint_Error with "Position cursor does not designate leaf";
742 if Container.Busy > 0 then
744 with "attempt to tamper with cursors (tree is busy)";
748 Position := No_Element;
750 -- Restore represention invariants before attempting the actual
754 Container.Count := Container.Count - 1;
756 -- It is now safe to attempt the deallocation. This leaf node has been
757 -- disassociated from the tree, so even if the deallocation fails,
758 -- representation invariants will remain satisfied.
767 procedure Delete_Subtree
768 (Container : in out Tree;
769 Position : in out Cursor)
771 X : Tree_Node_Access;
775 if Position = No_Element then
776 raise Constraint_Error with "Position cursor has no element";
779 if Position.Container /= Container'Unrestricted_Access then
780 raise Program_Error with "Position cursor not in container";
783 if Is_Root (Position) then
784 raise Program_Error with "Position cursor designates root";
787 if Container.Busy > 0 then
789 with "attempt to tamper with cursors (tree is busy)";
793 Position := No_Element;
795 -- Here is one case where a deallocation failure can result in the
796 -- violation of a representation invariant. We disassociate the subtree
797 -- from the tree now, but we only decrement the total node count after
798 -- we attempt the deallocation. However, if the deallocation fails, the
799 -- total node count will not get decremented.
801 -- One way around this dilemma is to count the nodes in the subtree
802 -- before attempt to delete the subtree, but that is an O(n) operation,
803 -- so it does not seem worth it.
805 -- Perhaps this is much ado about nothing, since the only way
806 -- deallocation can fail is if Controlled Finalization fails: this
807 -- propagates Program_Error so all bets are off anyway. ???
811 -- Deallocate_Subtree returns a count of the number of nodes that it
812 -- deallocates, but it works by incrementing the value that is passed
813 -- in. We must therefore initialize the count value before calling
814 -- Deallocate_Subtree.
818 Deallocate_Subtree (X, Count);
819 pragma Assert (Count <= Container.Count);
821 -- See comments above. We would prefer to do this sooner, but there's no
822 -- way to satisfy that goal without an potentially severe execution
825 Container.Count := Container.Count - Count;
832 function Depth (Position : Cursor) return Count_Type is
834 N : Tree_Node_Access;
841 Result := Result + 1;
851 function Element (Position : Cursor) return Element_Type is
853 if Position.Container = null then
854 raise Constraint_Error with "Position cursor has no element";
857 if Position.Node = Root_Node (Position.Container.all) then
858 raise Program_Error with "Position cursor designates root";
861 return Position.Node.Element.all;
868 function Equal_Children
869 (Left_Subtree : Tree_Node_Access;
870 Right_Subtree : Tree_Node_Access) return Boolean
872 Left_Children : Children_Type renames Left_Subtree.Children;
873 Right_Children : Children_Type renames Right_Subtree.Children;
875 L, R : Tree_Node_Access;
878 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
882 L := Left_Children.First;
883 R := Right_Children.First;
885 if not Equal_Subtree (L, R) then
900 function Equal_Subtree
901 (Left_Position : Cursor;
902 Right_Position : Cursor) return Boolean
905 if Left_Position = No_Element then
906 raise Constraint_Error with "Left cursor has no element";
909 if Right_Position = No_Element then
910 raise Constraint_Error with "Right cursor has no element";
913 if Left_Position = Right_Position then
917 if Is_Root (Left_Position) then
918 if not Is_Root (Right_Position) then
922 return Equal_Children (Left_Position.Node, Right_Position.Node);
925 if Is_Root (Right_Position) then
929 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
932 function Equal_Subtree
933 (Left_Subtree : Tree_Node_Access;
934 Right_Subtree : Tree_Node_Access) return Boolean
937 if Left_Subtree.Element.all /= Right_Subtree.Element.all then
941 return Equal_Children (Left_Subtree, Right_Subtree);
948 procedure Finalize (Object : in out Root_Iterator) is
949 B : Natural renames Object.Container.Busy;
960 Item : Element_Type) return Cursor
962 N : constant Tree_Node_Access :=
963 Find_In_Children (Root_Node (Container), Item);
970 return Cursor'(Container'Unrestricted_Access, N);
977 overriding function First (Object : Subtree_Iterator) return Cursor is
979 if Object.Subtree = Root_Node (Object.Container.all) then
980 return First_Child (Root (Object.Container.all));
982 return Cursor'(Object.Container, Object.Subtree);
986 overriding function First (Object : Child_Iterator) return Cursor is
988 return First_Child (Cursor'(Object.Container, Object.Subtree));
995 function First_Child (Parent : Cursor) return Cursor is
996 Node : Tree_Node_Access;
999 if Parent = No_Element then
1000 raise Constraint_Error with "Parent cursor has no element";
1003 Node := Parent.Node.Children.First;
1009 return Cursor'(Parent.Container, Node);
1012 -------------------------
1013 -- First_Child_Element --
1014 -------------------------
1016 function First_Child_Element (Parent : Cursor) return Element_Type is
1018 return Element (First_Child (Parent));
1019 end First_Child_Element;
1021 ----------------------
1022 -- Find_In_Children --
1023 ----------------------
1025 function Find_In_Children
1026 (Subtree : Tree_Node_Access;
1027 Item : Element_Type) return Tree_Node_Access
1029 N, Result : Tree_Node_Access;
1032 N := Subtree.Children.First;
1033 while N /= null loop
1034 Result := Find_In_Subtree (N, Item);
1036 if Result /= null then
1044 end Find_In_Children;
1046 ---------------------
1047 -- Find_In_Subtree --
1048 ---------------------
1050 function Find_In_Subtree
1052 Item : Element_Type) return Cursor
1054 Result : Tree_Node_Access;
1057 if Position = No_Element then
1058 raise Constraint_Error with "Position cursor has no element";
1061 -- Commented-out pending ruling from ARG. ???
1063 -- if Position.Container /= Container'Unrestricted_Access then
1064 -- raise Program_Error with "Position cursor not in container";
1067 if Is_Root (Position) then
1068 Result := Find_In_Children (Position.Node, Item);
1071 Result := Find_In_Subtree (Position.Node, Item);
1074 if Result = null then
1078 return Cursor'(Position.Container, Result);
1079 end Find_In_Subtree;
1081 function Find_In_Subtree
1082 (Subtree : Tree_Node_Access;
1083 Item : Element_Type) return Tree_Node_Access
1086 if Subtree.Element.all = Item then
1090 return Find_In_Children (Subtree, Item);
1091 end Find_In_Subtree;
1097 function Has_Element (Position : Cursor) return Boolean is
1099 if Position = No_Element then
1103 return Position.Node.Parent /= null;
1110 procedure Insert_Child
1111 (Container : in out Tree;
1114 New_Item : Element_Type;
1115 Count : Count_Type := 1)
1118 pragma Unreferenced (Position);
1121 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1124 procedure Insert_Child
1125 (Container : in out Tree;
1128 New_Item : Element_Type;
1129 Position : out Cursor;
1130 Count : Count_Type := 1)
1132 Last : Tree_Node_Access;
1133 Element : Element_Access;
1136 if Parent = No_Element then
1137 raise Constraint_Error with "Parent cursor has no element";
1140 if Parent.Container /= Container'Unrestricted_Access then
1141 raise Program_Error with "Parent cursor not in container";
1144 if Before /= No_Element then
1145 if Before.Container /= Container'Unrestricted_Access then
1146 raise Program_Error with "Before cursor not in container";
1149 if Before.Node.Parent /= Parent.Node then
1150 raise Constraint_Error with "Parent cursor not parent of Before";
1155 Position := No_Element; -- Need ruling from ARG ???
1159 if Container.Busy > 0 then
1161 with "attempt to tamper with cursors (tree is busy)";
1164 Position.Container := Parent.Container;
1166 Element := new Element_Type'(New_Item);
1167 Position.Node := new Tree_Node_Type'(Parent => Parent.Node,
1171 Last := Position.Node;
1173 for J in Count_Type'(2) .. Count loop
1174 -- Reclaim other nodes if Storage_Error. ???
1176 Element := new Element_Type'(New_Item);
1177 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1186 (First => Position.Node,
1188 Parent => Parent.Node,
1189 Before => Before.Node);
1191 -- In order for operation Node_Count to complete in O(1) time, we cache
1192 -- the count value. Here we increment the total count by the number of
1193 -- nodes we just inserted.
1195 Container.Count := Container.Count + Count;
1198 -------------------------
1199 -- Insert_Subtree_List --
1200 -------------------------
1202 procedure Insert_Subtree_List
1203 (First : Tree_Node_Access;
1204 Last : Tree_Node_Access;
1205 Parent : Tree_Node_Access;
1206 Before : Tree_Node_Access)
1208 pragma Assert (Parent /= null);
1209 C : Children_Type renames Parent.Children;
1212 -- This is a simple utility operation to insert a list of nodes (from
1213 -- First..Last) as children of Parent. The Before node specifies where
1214 -- the new children should be inserted relative to the existing
1217 if First = null then
1218 pragma Assert (Last = null);
1222 pragma Assert (Last /= null);
1223 pragma Assert (Before = null or else Before.Parent = Parent);
1225 if C.First = null then
1227 C.First.Prev := null;
1229 C.Last.Next := null;
1231 elsif Before = null then -- means "insert after existing nodes"
1232 C.Last.Next := First;
1233 First.Prev := C.Last;
1235 C.Last.Next := null;
1237 elsif Before = C.First then
1238 Last.Next := C.First;
1239 C.First.Prev := Last;
1241 C.First.Prev := null;
1244 Before.Prev.Next := First;
1245 First.Prev := Before.Prev;
1246 Last.Next := Before;
1247 Before.Prev := Last;
1249 end Insert_Subtree_List;
1251 -------------------------
1252 -- Insert_Subtree_Node --
1253 -------------------------
1255 procedure Insert_Subtree_Node
1256 (Subtree : Tree_Node_Access;
1257 Parent : Tree_Node_Access;
1258 Before : Tree_Node_Access)
1261 -- This is a simple wrapper operation to insert a single child into the
1262 -- Parent's children list.
1269 end Insert_Subtree_Node;
1275 function Is_Empty (Container : Tree) return Boolean is
1277 return Container.Root.Children.First = null;
1284 function Is_Leaf (Position : Cursor) return Boolean is
1286 if Position = No_Element then
1290 return Position.Node.Children.First = null;
1297 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1298 pragma Assert (From /= null);
1299 pragma Assert (To /= null);
1301 N : Tree_Node_Access;
1305 while N /= null loop
1320 function Is_Root (Position : Cursor) return Boolean is
1322 if Position.Container = null then
1326 return Position = Root (Position.Container.all);
1335 Process : not null access procedure (Position : Cursor))
1337 B : Natural renames Container'Unrestricted_Access.all.Busy;
1343 (Container => Container'Unrestricted_Access,
1344 Subtree => Root_Node (Container),
1345 Process => Process);
1355 function Iterate (Container : Tree)
1356 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1359 return Iterate_Subtree (Root (Container));
1362 ----------------------
1363 -- Iterate_Children --
1364 ----------------------
1366 procedure Iterate_Children
1368 Process : not null access procedure (Position : Cursor))
1371 if Parent = No_Element then
1372 raise Constraint_Error with "Parent cursor has no element";
1376 B : Natural renames Parent.Container.Busy;
1377 C : Tree_Node_Access;
1382 C := Parent.Node.Children.First;
1383 while C /= null loop
1384 Process (Position => Cursor'(Parent.Container, Node => C));
1395 end Iterate_Children;
1397 procedure Iterate_Children
1398 (Container : Tree_Access;
1399 Subtree : Tree_Node_Access;
1400 Process : not null access procedure (Position : Cursor))
1402 Node : Tree_Node_Access;
1405 -- This is a helper function to recursively iterate over all the nodes
1406 -- in a subtree, in depth-first fashion. This particular helper just
1407 -- visits the children of this subtree, not the root of the subtree node
1408 -- itself. This is useful when starting from the ultimate root of the
1409 -- entire tree (see Iterate), as that root does not have an element.
1411 Node := Subtree.Children.First;
1412 while Node /= null loop
1413 Iterate_Subtree (Container, Node, Process);
1416 end Iterate_Children;
1418 function Iterate_Children
1421 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1423 C : constant Tree_Access := Container'Unrestricted_Access;
1424 B : Natural renames C.Busy;
1427 if Parent = No_Element then
1428 raise Constraint_Error with "Parent cursor has no element";
1431 if Parent.Container /= C then
1432 raise Program_Error with "Parent cursor not in container";
1435 return It : constant Child_Iterator :=
1436 Child_Iterator'(Limited_Controlled with
1438 Subtree => Parent.Node)
1442 end Iterate_Children;
1444 ---------------------
1445 -- Iterate_Subtree --
1446 ---------------------
1448 function Iterate_Subtree
1450 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1453 if Position = No_Element then
1454 raise Constraint_Error with "Position cursor has no element";
1457 -- Implement Vet for multiway trees???
1458 -- pragma Assert (Vet (Position), "bad subtree cursor");
1461 B : Natural renames Position.Container.Busy;
1463 return It : constant Subtree_Iterator :=
1464 (Limited_Controlled with
1465 Container => Position.Container,
1466 Subtree => Position.Node)
1471 end Iterate_Subtree;
1473 procedure Iterate_Subtree
1475 Process : not null access procedure (Position : Cursor))
1478 if Position = No_Element then
1479 raise Constraint_Error with "Position cursor has no element";
1483 B : Natural renames Position.Container.Busy;
1488 if Is_Root (Position) then
1489 Iterate_Children (Position.Container, Position.Node, Process);
1491 Iterate_Subtree (Position.Container, Position.Node, Process);
1501 end Iterate_Subtree;
1503 procedure Iterate_Subtree
1504 (Container : Tree_Access;
1505 Subtree : Tree_Node_Access;
1506 Process : not null access procedure (Position : Cursor))
1509 -- This is a helper function to recursively iterate over all the nodes
1510 -- in a subtree, in depth-first fashion. It first visits the root of the
1511 -- subtree, then visits its children.
1513 Process (Cursor'(Container, Subtree));
1514 Iterate_Children (Container, Subtree, Process);
1515 end Iterate_Subtree;
1521 overriding function Last (Object : Child_Iterator) return Cursor is
1523 return Last_Child (Cursor'(Object.Container, Object.Subtree));
1530 function Last_Child (Parent : Cursor) return Cursor is
1531 Node : Tree_Node_Access;
1534 if Parent = No_Element then
1535 raise Constraint_Error with "Parent cursor has no element";
1538 Node := Parent.Node.Children.Last;
1544 return (Parent.Container, Node);
1547 ------------------------
1548 -- Last_Child_Element --
1549 ------------------------
1551 function Last_Child_Element (Parent : Cursor) return Element_Type is
1553 return Element (Last_Child (Parent));
1554 end Last_Child_Element;
1560 procedure Move (Target : in out Tree; Source : in out Tree) is
1561 Node : Tree_Node_Access;
1564 if Target'Address = Source'Address then
1568 if Source.Busy > 0 then
1570 with "attempt to tamper with cursors of Source (tree is busy)";
1573 Target.Clear; -- checks busy bit
1575 Target.Root.Children := Source.Root.Children;
1576 Source.Root.Children := Children_Type'(others => null);
1578 Node := Target.Root.Children.First;
1579 while Node /= null loop
1580 Node.Parent := Root_Node (Target);
1584 Target.Count := Source.Count;
1593 (Object : Subtree_Iterator;
1594 Position : Cursor) return Cursor
1596 Node : Tree_Node_Access;
1599 if Position.Container = null then
1603 if Position.Container /= Object.Container then
1604 raise Program_Error with
1605 "Position cursor of Next designates wrong tree";
1608 Node := Position.Node;
1610 if Node.Children.First /= null then
1611 return Cursor'(Object.Container, Node.Children.First);
1614 while Node /= Object.Subtree loop
1615 if Node.Next /= null then
1616 return Cursor'(Object.Container, Node.Next);
1619 Node := Node.Parent;
1626 (Object : Child_Iterator;
1627 Position : Cursor) return Cursor
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 return Next_Sibling (Position);
1646 function Next_Sibling (Position : Cursor) return Cursor is
1648 if Position = No_Element then
1652 if Position.Node.Next = null then
1656 return Cursor'(Position.Container, Position.Node.Next);
1659 procedure Next_Sibling (Position : in out Cursor) is
1661 Position := Next_Sibling (Position);
1668 function Node_Count (Container : Tree) return Count_Type is
1670 -- Container.Count is the number of nodes we have actually allocated. We
1671 -- cache the value specifically so this Node_Count operation can execute
1672 -- in O(1) time, which makes it behave similarly to how the Length
1673 -- selector function behaves for other containers.
1675 -- The cached node count value only describes the nodes we have
1676 -- allocated; the root node itself is not included in that count. The
1677 -- Node_Count operation returns a value that includes the root node
1678 -- (because the RM says so), so we must add 1 to our cached value.
1680 return 1 + Container.Count;
1687 function Parent (Position : Cursor) return Cursor is
1689 if Position = No_Element then
1693 if Position.Node.Parent = null then
1697 return Cursor'(Position.Container, Position.Node.Parent);
1704 procedure Prepend_Child
1705 (Container : in out Tree;
1707 New_Item : Element_Type;
1708 Count : Count_Type := 1)
1710 First, Last : Tree_Node_Access;
1711 Element : Element_Access;
1714 if Parent = No_Element then
1715 raise Constraint_Error with "Parent cursor has no element";
1718 if Parent.Container /= Container'Unrestricted_Access then
1719 raise Program_Error with "Parent cursor not in container";
1726 if Container.Busy > 0 then
1728 with "attempt to tamper with cursors (tree is busy)";
1731 Element := new Element_Type'(New_Item);
1732 First := new Tree_Node_Type'(Parent => Parent.Node,
1738 for J in Count_Type'(2) .. Count loop
1740 -- Reclaim other nodes if Storage_Error. ???
1742 Element := new Element_Type'(New_Item);
1743 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1754 Parent => Parent.Node,
1755 Before => Parent.Node.Children.First);
1757 -- In order for operation Node_Count to complete in O(1) time, we cache
1758 -- the count value. Here we increment the total count by the number of
1759 -- nodes we just inserted.
1761 Container.Count := Container.Count + Count;
1768 overriding function Previous
1769 (Object : Child_Iterator;
1770 Position : Cursor) return Cursor
1773 if Position.Container = null then
1777 if Position.Container /= Object.Container then
1778 raise Program_Error with
1779 "Position cursor of Previous designates wrong tree";
1782 return Previous_Sibling (Position);
1785 ----------------------
1786 -- Previous_Sibling --
1787 ----------------------
1789 function Previous_Sibling (Position : Cursor) return Cursor is
1791 if Position = No_Element then
1795 if Position.Node.Prev = null then
1799 return Cursor'(Position.Container, Position.Node.Prev);
1800 end Previous_Sibling;
1802 procedure Previous_Sibling (Position : in out Cursor) is
1804 Position := Previous_Sibling (Position);
1805 end Previous_Sibling;
1811 procedure Query_Element
1813 Process : not null access procedure (Element : Element_Type))
1816 if Position = No_Element then
1817 raise Constraint_Error with "Position cursor has no element";
1820 if Is_Root (Position) then
1821 raise Program_Error with "Position cursor designates root";
1825 T : Tree renames Position.Container.all'Unrestricted_Access.all;
1826 B : Natural renames T.Busy;
1827 L : Natural renames T.Lock;
1833 Process (Position.Node.Element.all);
1851 (Stream : not null access Root_Stream_Type'Class;
1852 Container : out Tree)
1854 procedure Read_Children (Subtree : Tree_Node_Access);
1856 function Read_Subtree
1857 (Parent : Tree_Node_Access) return Tree_Node_Access;
1859 Total_Count : Count_Type'Base;
1860 -- Value read from the stream that says how many elements follow
1862 Read_Count : Count_Type'Base;
1863 -- Actual number of elements read from the stream
1869 procedure Read_Children (Subtree : Tree_Node_Access) is
1870 pragma Assert (Subtree /= null);
1871 pragma Assert (Subtree.Children.First = null);
1872 pragma Assert (Subtree.Children.Last = null);
1874 Count : Count_Type'Base;
1875 -- Number of child subtrees
1880 Count_Type'Read (Stream, Count);
1883 raise Program_Error with "attempt to read from corrupt stream";
1890 C.First := Read_Subtree (Parent => Subtree);
1893 for J in Count_Type'(2) .. Count loop
1894 C.Last.Next := Read_Subtree (Parent => Subtree);
1895 C.Last.Next.Prev := C.Last;
1896 C.Last := C.Last.Next;
1899 -- Now that the allocation and reads have completed successfully, it
1900 -- is safe to link the children to their parent.
1902 Subtree.Children := C;
1909 function Read_Subtree
1910 (Parent : Tree_Node_Access) return Tree_Node_Access
1912 Element : constant Element_Access :=
1913 new Element_Type'(Element_Type'Input (Stream));
1915 Subtree : constant Tree_Node_Access :=
1922 Read_Count := Read_Count + 1;
1924 Read_Children (Subtree);
1929 -- Start of processing for Read
1932 Container.Clear; -- checks busy bit
1934 Count_Type'Read (Stream, Total_Count);
1936 if Total_Count < 0 then
1937 raise Program_Error with "attempt to read from corrupt stream";
1940 if Total_Count = 0 then
1946 Read_Children (Root_Node (Container));
1948 if Read_Count /= Total_Count then
1949 raise Program_Error with "attempt to read from corrupt stream";
1952 Container.Count := Total_Count;
1956 (Stream : not null access Root_Stream_Type'Class;
1957 Position : out Cursor)
1960 raise Program_Error with "attempt to read tree cursor from stream";
1964 (Stream : not null access Root_Stream_Type'Class;
1965 Item : out Reference_Type)
1968 raise Program_Error with "attempt to stream reference";
1972 (Stream : not null access Root_Stream_Type'Class;
1973 Item : out Constant_Reference_Type)
1976 raise Program_Error with "attempt to stream reference";
1983 function Constant_Reference
1984 (Container : aliased Tree;
1985 Position : Cursor) return Constant_Reference_Type
1988 pragma Unreferenced (Container);
1990 return (Element => Position.Node.Element.all'Unchecked_Access);
1991 end Constant_Reference;
1994 (Container : aliased Tree;
1995 Position : Cursor) return Reference_Type
1998 pragma Unreferenced (Container);
2000 return (Element => Position.Node.Element.all'Unchecked_Access);
2003 --------------------
2004 -- Remove_Subtree --
2005 --------------------
2007 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2008 C : Children_Type renames Subtree.Parent.Children;
2011 -- This is a utility operation to remove a subtree node from its
2012 -- parent's list of children.
2014 if C.First = Subtree then
2015 pragma Assert (Subtree.Prev = null);
2017 if C.Last = Subtree then
2018 pragma Assert (Subtree.Next = null);
2023 C.First := Subtree.Next;
2024 C.First.Prev := null;
2027 elsif C.Last = Subtree then
2028 pragma Assert (Subtree.Next = null);
2029 C.Last := Subtree.Prev;
2030 C.Last.Next := null;
2033 Subtree.Prev.Next := Subtree.Next;
2034 Subtree.Next.Prev := Subtree.Prev;
2038 ----------------------
2039 -- Replace_Element --
2040 ----------------------
2042 procedure Replace_Element
2043 (Container : in out Tree;
2045 New_Item : Element_Type)
2047 E, X : Element_Access;
2050 if Position = No_Element then
2051 raise Constraint_Error with "Position cursor has no element";
2054 if Position.Container /= Container'Unrestricted_Access then
2055 raise Program_Error with "Position cursor not in container";
2058 if Is_Root (Position) then
2059 raise Program_Error with "Position cursor designates root";
2062 if Container.Lock > 0 then
2064 with "attempt to tamper with elements (tree is locked)";
2067 E := new Element_Type'(New_Item);
2069 X := Position.Node.Element;
2070 Position.Node.Element := E;
2073 end Replace_Element;
2075 ------------------------------
2076 -- Reverse_Iterate_Children --
2077 ------------------------------
2079 procedure Reverse_Iterate_Children
2081 Process : not null access procedure (Position : Cursor))
2084 if Parent = No_Element then
2085 raise Constraint_Error with "Parent cursor has no element";
2089 B : Natural renames Parent.Container.Busy;
2090 C : Tree_Node_Access;
2095 C := Parent.Node.Children.Last;
2096 while C /= null loop
2097 Process (Position => Cursor'(Parent.Container, Node => C));
2108 end Reverse_Iterate_Children;
2114 function Root (Container : Tree) return Cursor is
2116 return (Container'Unrestricted_Access, Root_Node (Container));
2123 function Root_Node (Container : Tree) return Tree_Node_Access is
2125 return Container.Root'Unrestricted_Access;
2128 ---------------------
2129 -- Splice_Children --
2130 ---------------------
2132 procedure Splice_Children
2133 (Target : in out Tree;
2134 Target_Parent : Cursor;
2136 Source : in out Tree;
2137 Source_Parent : Cursor)
2142 if Target_Parent = No_Element then
2143 raise Constraint_Error with "Target_Parent cursor has no element";
2146 if Target_Parent.Container /= Target'Unrestricted_Access then
2148 with "Target_Parent cursor not in Target container";
2151 if Before /= No_Element then
2152 if Before.Container /= Target'Unrestricted_Access then
2154 with "Before cursor not in Target container";
2157 if Before.Node.Parent /= Target_Parent.Node then
2158 raise Constraint_Error
2159 with "Before cursor not child of Target_Parent";
2163 if Source_Parent = No_Element then
2164 raise Constraint_Error with "Source_Parent cursor has no element";
2167 if Source_Parent.Container /= Source'Unrestricted_Access then
2169 with "Source_Parent cursor not in Source container";
2172 if Target'Address = Source'Address then
2173 if Target_Parent = Source_Parent then
2177 if Target.Busy > 0 then
2179 with "attempt to tamper with cursors (Target tree is busy)";
2182 if Is_Reachable (From => Target_Parent.Node,
2183 To => Source_Parent.Node)
2185 raise Constraint_Error
2186 with "Source_Parent is ancestor of Target_Parent";
2190 (Target_Parent => Target_Parent.Node,
2191 Before => Before.Node,
2192 Source_Parent => Source_Parent.Node);
2197 if Target.Busy > 0 then
2199 with "attempt to tamper with cursors (Target tree is busy)";
2202 if Source.Busy > 0 then
2204 with "attempt to tamper with cursors (Source tree is busy)";
2207 -- We cache the count of the nodes we have allocated, so that operation
2208 -- Node_Count can execute in O(1) time. But that means we must count the
2209 -- nodes in the subtree we remove from Source and insert into Target, in
2210 -- order to keep the count accurate.
2212 Count := Subtree_Node_Count (Source_Parent.Node);
2213 pragma Assert (Count >= 1);
2215 Count := Count - 1; -- because Source_Parent node does not move
2218 (Target_Parent => Target_Parent.Node,
2219 Before => Before.Node,
2220 Source_Parent => Source_Parent.Node);
2222 Source.Count := Source.Count - Count;
2223 Target.Count := Target.Count + Count;
2224 end Splice_Children;
2226 procedure Splice_Children
2227 (Container : in out Tree;
2228 Target_Parent : Cursor;
2230 Source_Parent : Cursor)
2233 if Target_Parent = No_Element then
2234 raise Constraint_Error with "Target_Parent cursor has no element";
2237 if Target_Parent.Container /= Container'Unrestricted_Access then
2239 with "Target_Parent cursor not in container";
2242 if Before /= No_Element then
2243 if Before.Container /= Container'Unrestricted_Access then
2245 with "Before cursor not in container";
2248 if Before.Node.Parent /= Target_Parent.Node then
2249 raise Constraint_Error
2250 with "Before cursor not child of Target_Parent";
2254 if Source_Parent = No_Element then
2255 raise Constraint_Error with "Source_Parent cursor has no element";
2258 if Source_Parent.Container /= Container'Unrestricted_Access then
2260 with "Source_Parent cursor not in container";
2263 if Target_Parent = Source_Parent then
2267 if Container.Busy > 0 then
2269 with "attempt to tamper with cursors (tree is busy)";
2272 if Is_Reachable (From => Target_Parent.Node,
2273 To => Source_Parent.Node)
2275 raise Constraint_Error
2276 with "Source_Parent is ancestor of Target_Parent";
2280 (Target_Parent => Target_Parent.Node,
2281 Before => Before.Node,
2282 Source_Parent => Source_Parent.Node);
2283 end Splice_Children;
2285 procedure Splice_Children
2286 (Target_Parent : Tree_Node_Access;
2287 Before : Tree_Node_Access;
2288 Source_Parent : Tree_Node_Access)
2290 CC : constant Children_Type := Source_Parent.Children;
2291 C : Tree_Node_Access;
2294 -- This is a utility operation to remove the children from Source parent
2295 -- and insert them into Target parent.
2297 Source_Parent.Children := Children_Type'(others => null);
2299 -- Fix up the Parent pointers of each child to designate its new Target
2303 while C /= null loop
2304 C.Parent := Target_Parent;
2311 Parent => Target_Parent,
2313 end Splice_Children;
2315 --------------------
2316 -- Splice_Subtree --
2317 --------------------
2319 procedure Splice_Subtree
2320 (Target : in out Tree;
2323 Source : in out Tree;
2324 Position : in out Cursor)
2326 Subtree_Count : Count_Type;
2329 if Parent = No_Element then
2330 raise Constraint_Error with "Parent cursor has no element";
2333 if Parent.Container /= Target'Unrestricted_Access then
2334 raise Program_Error with "Parent cursor not in Target container";
2337 if Before /= No_Element then
2338 if Before.Container /= Target'Unrestricted_Access then
2339 raise Program_Error with "Before cursor not in Target container";
2342 if Before.Node.Parent /= Parent.Node then
2343 raise Constraint_Error with "Before cursor not child of Parent";
2347 if Position = No_Element then
2348 raise Constraint_Error with "Position cursor has no element";
2351 if Position.Container /= Source'Unrestricted_Access then
2352 raise Program_Error with "Position cursor not in Source container";
2355 if Is_Root (Position) then
2356 raise Program_Error with "Position cursor designates root";
2359 if Target'Address = Source'Address then
2360 if Position.Node.Parent = Parent.Node then
2361 if Position.Node = Before.Node then
2365 if Position.Node.Next = Before.Node then
2370 if Target.Busy > 0 then
2372 with "attempt to tamper with cursors (Target tree is busy)";
2375 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2376 raise Constraint_Error with "Position is ancestor of Parent";
2379 Remove_Subtree (Position.Node);
2381 Position.Node.Parent := Parent.Node;
2382 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2387 if Target.Busy > 0 then
2389 with "attempt to tamper with cursors (Target tree is busy)";
2392 if Source.Busy > 0 then
2394 with "attempt to tamper with cursors (Source tree is busy)";
2397 -- This is an unfortunate feature of this API: we must count the nodes
2398 -- in the subtree that we remove from the source tree, which is an O(n)
2399 -- operation. It would have been better if the Tree container did not
2400 -- have a Node_Count selector; a user that wants the number of nodes in
2401 -- the tree could simply call Subtree_Node_Count, with the understanding
2402 -- that such an operation is O(n).
2404 -- Of course, we could choose to implement the Node_Count selector as an
2405 -- O(n) operation, which would turn this splice operation into an O(1)
2408 Subtree_Count := Subtree_Node_Count (Position.Node);
2409 pragma Assert (Subtree_Count <= Source.Count);
2411 Remove_Subtree (Position.Node);
2412 Source.Count := Source.Count - Subtree_Count;
2414 Position.Node.Parent := Parent.Node;
2415 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2417 Target.Count := Target.Count + Subtree_Count;
2419 Position.Container := Target'Unrestricted_Access;
2422 procedure Splice_Subtree
2423 (Container : in out Tree;
2429 if Parent = No_Element then
2430 raise Constraint_Error with "Parent cursor has no element";
2433 if Parent.Container /= Container'Unrestricted_Access then
2434 raise Program_Error with "Parent cursor not in container";
2437 if Before /= No_Element then
2438 if Before.Container /= Container'Unrestricted_Access then
2439 raise Program_Error with "Before cursor not in container";
2442 if Before.Node.Parent /= Parent.Node then
2443 raise Constraint_Error with "Before cursor not child of Parent";
2447 if Position = No_Element then
2448 raise Constraint_Error with "Position cursor has no element";
2451 if Position.Container /= Container'Unrestricted_Access then
2452 raise Program_Error with "Position cursor not in container";
2455 if Is_Root (Position) then
2457 -- Should this be PE instead? Need ARG confirmation. ???
2459 raise Constraint_Error with "Position cursor designates root";
2462 if Position.Node.Parent = Parent.Node then
2463 if Position.Node = Before.Node then
2467 if Position.Node.Next = Before.Node then
2472 if Container.Busy > 0 then
2474 with "attempt to tamper with cursors (tree is busy)";
2477 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2478 raise Constraint_Error with "Position is ancestor of Parent";
2481 Remove_Subtree (Position.Node);
2483 Position.Node.Parent := Parent.Node;
2484 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2487 ------------------------
2488 -- Subtree_Node_Count --
2489 ------------------------
2491 function Subtree_Node_Count (Position : Cursor) return Count_Type is
2493 if Position = No_Element then
2497 return Subtree_Node_Count (Position.Node);
2498 end Subtree_Node_Count;
2500 function Subtree_Node_Count
2501 (Subtree : Tree_Node_Access) return Count_Type
2503 Result : Count_Type;
2504 Node : Tree_Node_Access;
2508 Node := Subtree.Children.First;
2509 while Node /= null loop
2510 Result := Result + Subtree_Node_Count (Node);
2515 end Subtree_Node_Count;
2522 (Container : in out Tree;
2526 if I = No_Element then
2527 raise Constraint_Error with "I cursor has no element";
2530 if I.Container /= Container'Unrestricted_Access then
2531 raise Program_Error with "I cursor not in container";
2535 raise Program_Error with "I cursor designates root";
2538 if I = J then -- make this test sooner???
2542 if J = No_Element then
2543 raise Constraint_Error with "J cursor has no element";
2546 if J.Container /= Container'Unrestricted_Access then
2547 raise Program_Error with "J cursor not in container";
2551 raise Program_Error with "J cursor designates root";
2554 if Container.Lock > 0 then
2556 with "attempt to tamper with elements (tree is locked)";
2560 EI : constant Element_Access := I.Node.Element;
2563 I.Node.Element := J.Node.Element;
2564 J.Node.Element := EI;
2568 --------------------
2569 -- Update_Element --
2570 --------------------
2572 procedure Update_Element
2573 (Container : in out Tree;
2575 Process : not null access procedure (Element : in out Element_Type))
2578 if Position = No_Element then
2579 raise Constraint_Error with "Position cursor has no element";
2582 if Position.Container /= Container'Unrestricted_Access then
2583 raise Program_Error with "Position cursor not in container";
2586 if Is_Root (Position) then
2587 raise Program_Error with "Position cursor designates root";
2591 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2592 B : Natural renames T.Busy;
2593 L : Natural renames T.Lock;
2599 Process (Position.Node.Element.all);
2617 (Stream : not null access Root_Stream_Type'Class;
2620 procedure Write_Children (Subtree : Tree_Node_Access);
2621 procedure Write_Subtree (Subtree : Tree_Node_Access);
2623 --------------------
2624 -- Write_Children --
2625 --------------------
2627 procedure Write_Children (Subtree : Tree_Node_Access) is
2628 CC : Children_Type renames Subtree.Children;
2629 C : Tree_Node_Access;
2632 Count_Type'Write (Stream, Child_Count (CC));
2635 while C /= null loop
2645 procedure Write_Subtree (Subtree : Tree_Node_Access) is
2647 Element_Type'Output (Stream, Subtree.Element.all);
2648 Write_Children (Subtree);
2651 -- Start of processing for Write
2654 Count_Type'Write (Stream, Container.Count);
2656 if Container.Count = 0 then
2660 Write_Children (Root_Node (Container));
2664 (Stream : not null access Root_Stream_Type'Class;
2668 raise Program_Error with "attempt to write tree cursor to stream";
2672 (Stream : not null access Root_Stream_Type'Class;
2673 Item : Reference_Type)
2676 raise Program_Error with "attempt to stream reference";
2680 (Stream : not null access Root_Stream_Type'Class;
2681 Item : Constant_Reference_Type)
2684 raise Program_Error with "attempt to stream reference";
2687 end Ada.Containers.Indefinite_Multiway_Trees;