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);
444 ------------------------
445 -- Constant_Reference --
446 ------------------------
448 function Constant_Reference
449 (Container : aliased Tree;
450 Position : Cursor) return Constant_Reference_Type
453 if Position.Container = null then
454 raise Constraint_Error with
455 "Position cursor has no element";
458 if Position.Container /= Container'Unrestricted_Access then
459 raise Program_Error with
460 "Position cursor designates wrong container";
463 if Position.Node = Root_Node (Container) then
464 raise Program_Error with "Position cursor designates root";
467 if Position.Node.Element = null then
468 raise Program_Error with "Node has no element";
471 -- Implement Vet for multiway tree???
472 -- pragma Assert (Vet (Position),
473 -- "Position cursor in Constant_Reference is bad");
475 return (Element => Position.Node.Element.all'Access);
476 end Constant_Reference;
484 Item : Element_Type) return Boolean
487 return Find (Container, Item) /= No_Element;
494 function Copy (Source : Tree) return Tree is
496 return Target : Tree do
498 (Source => Source.Root.Children,
499 Parent => Root_Node (Target),
500 Count => Target.Count);
502 pragma Assert (Target.Count = Source.Count);
510 procedure Copy_Children
511 (Source : Children_Type;
512 Parent : Tree_Node_Access;
513 Count : in out Count_Type)
515 pragma Assert (Parent /= null);
516 pragma Assert (Parent.Children.First = null);
517 pragma Assert (Parent.Children.Last = null);
520 C : Tree_Node_Access;
523 -- We special-case the first allocation, in order to establish the
524 -- representation invariants for type Children_Type.
540 -- The representation invariants for the Children_Type list have been
541 -- established, so we can now copy the remaining children of Source.
548 Target => CC.Last.Next,
551 CC.Last.Next.Prev := CC.Last;
552 CC.Last := CC.Last.Next;
557 -- We add the newly-allocated children to their parent list only after
558 -- the allocation has succeeded, in order to preserve invariants of the
561 Parent.Children := CC;
568 procedure Copy_Subtree
569 (Target : in out Tree;
574 Target_Subtree : Tree_Node_Access;
575 Target_Count : Count_Type;
578 if Parent = No_Element then
579 raise Constraint_Error with "Parent cursor has no element";
582 if Parent.Container /= Target'Unrestricted_Access then
583 raise Program_Error with "Parent cursor not in container";
586 if Before /= No_Element then
587 if Before.Container /= Target'Unrestricted_Access then
588 raise Program_Error with "Before cursor not in container";
591 if Before.Node.Parent /= Parent.Node then
592 raise Constraint_Error with "Before cursor not child of Parent";
596 if Source = No_Element then
600 if Is_Root (Source) then
601 raise Constraint_Error with "Source cursor designates root";
604 -- Copy_Subtree returns a count of the number of nodes that it
605 -- allocates, but it works by incrementing the value that is passed in.
606 -- We must therefore initialize the count value before calling
612 (Source => Source.Node,
613 Parent => Parent.Node,
614 Target => Target_Subtree,
615 Count => Target_Count);
617 pragma Assert (Target_Subtree /= null);
618 pragma Assert (Target_Subtree.Parent = Parent.Node);
619 pragma Assert (Target_Count >= 1);
622 (Subtree => Target_Subtree,
623 Parent => Parent.Node,
624 Before => Before.Node);
626 -- In order for operation Node_Count to complete in O(1) time, we cache
627 -- the count value. Here we increment the total count by the number of
628 -- nodes we just inserted.
630 Target.Count := Target.Count + Target_Count;
633 procedure Copy_Subtree
634 (Source : Tree_Node_Access;
635 Parent : Tree_Node_Access;
636 Target : out Tree_Node_Access;
637 Count : in out Count_Type)
639 E : constant Element_Access := new Element_Type'(Source.Element.all);
642 Target := new Tree_Node_Type'(Element => E,
649 (Source => Source.Children,
654 -------------------------
655 -- Deallocate_Children --
656 -------------------------
658 procedure Deallocate_Children
659 (Subtree : Tree_Node_Access;
660 Count : in out Count_Type)
662 pragma Assert (Subtree /= null);
664 CC : Children_Type := Subtree.Children;
665 C : Tree_Node_Access;
668 -- We immediately remove the children from their parent, in order to
669 -- preserve invariants in case the deallocation fails.
671 Subtree.Children := Children_Type'(others => null);
673 while CC.First /= null loop
677 Deallocate_Subtree (C, Count);
679 end Deallocate_Children;
681 ---------------------
682 -- Deallocate_Node --
683 ---------------------
685 procedure Deallocate_Node (X : in out Tree_Node_Access) is
686 procedure Free_Node is
687 new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access);
689 -- Start of processing for Deallocate_Node
693 Free_Element (X.Element);
698 ------------------------
699 -- Deallocate_Subtree --
700 ------------------------
702 procedure Deallocate_Subtree
703 (Subtree : in out Tree_Node_Access;
704 Count : in out Count_Type)
707 Deallocate_Children (Subtree, Count);
708 Deallocate_Node (Subtree);
710 end Deallocate_Subtree;
712 ---------------------
713 -- Delete_Children --
714 ---------------------
716 procedure Delete_Children
717 (Container : in out Tree;
723 if Parent = No_Element then
724 raise Constraint_Error with "Parent cursor has no element";
727 if Parent.Container /= Container'Unrestricted_Access then
728 raise Program_Error with "Parent cursor not in container";
731 if Container.Busy > 0 then
733 with "attempt to tamper with cursors (tree is busy)";
736 -- Deallocate_Children returns a count of the number of nodes
737 -- that it deallocates, but it works by incrementing the
738 -- value that is passed in. We must therefore initialize
739 -- the count value before calling Deallocate_Children.
743 Deallocate_Children (Parent.Node, Count);
744 pragma Assert (Count <= Container.Count);
746 Container.Count := Container.Count - Count;
753 procedure Delete_Leaf
754 (Container : in out Tree;
755 Position : in out Cursor)
757 X : Tree_Node_Access;
760 if Position = No_Element then
761 raise Constraint_Error with "Position cursor has no element";
764 if Position.Container /= Container'Unrestricted_Access then
765 raise Program_Error with "Position cursor not in container";
768 if Is_Root (Position) then
769 raise Program_Error with "Position cursor designates root";
772 if not Is_Leaf (Position) then
773 raise Constraint_Error with "Position cursor does not designate leaf";
776 if Container.Busy > 0 then
778 with "attempt to tamper with cursors (tree is busy)";
782 Position := No_Element;
784 -- Restore represention invariants before attempting the actual
788 Container.Count := Container.Count - 1;
790 -- It is now safe to attempt the deallocation. This leaf node has been
791 -- disassociated from the tree, so even if the deallocation fails,
792 -- representation invariants will remain satisfied.
801 procedure Delete_Subtree
802 (Container : in out Tree;
803 Position : in out Cursor)
805 X : Tree_Node_Access;
809 if Position = No_Element then
810 raise Constraint_Error with "Position cursor has no element";
813 if Position.Container /= Container'Unrestricted_Access then
814 raise Program_Error with "Position cursor not in container";
817 if Is_Root (Position) then
818 raise Program_Error with "Position cursor designates root";
821 if Container.Busy > 0 then
823 with "attempt to tamper with cursors (tree is busy)";
827 Position := No_Element;
829 -- Here is one case where a deallocation failure can result in the
830 -- violation of a representation invariant. We disassociate the subtree
831 -- from the tree now, but we only decrement the total node count after
832 -- we attempt the deallocation. However, if the deallocation fails, the
833 -- total node count will not get decremented.
835 -- One way around this dilemma is to count the nodes in the subtree
836 -- before attempt to delete the subtree, but that is an O(n) operation,
837 -- so it does not seem worth it.
839 -- Perhaps this is much ado about nothing, since the only way
840 -- deallocation can fail is if Controlled Finalization fails: this
841 -- propagates Program_Error so all bets are off anyway. ???
845 -- Deallocate_Subtree returns a count of the number of nodes that it
846 -- deallocates, but it works by incrementing the value that is passed
847 -- in. We must therefore initialize the count value before calling
848 -- Deallocate_Subtree.
852 Deallocate_Subtree (X, Count);
853 pragma Assert (Count <= Container.Count);
855 -- See comments above. We would prefer to do this sooner, but there's no
856 -- way to satisfy that goal without an potentially severe execution
859 Container.Count := Container.Count - Count;
866 function Depth (Position : Cursor) return Count_Type is
868 N : Tree_Node_Access;
875 Result := Result + 1;
885 function Element (Position : Cursor) return Element_Type is
887 if Position.Container = null then
888 raise Constraint_Error with "Position cursor has no element";
891 if Position.Node = Root_Node (Position.Container.all) then
892 raise Program_Error with "Position cursor designates root";
895 return Position.Node.Element.all;
902 function Equal_Children
903 (Left_Subtree : Tree_Node_Access;
904 Right_Subtree : Tree_Node_Access) return Boolean
906 Left_Children : Children_Type renames Left_Subtree.Children;
907 Right_Children : Children_Type renames Right_Subtree.Children;
909 L, R : Tree_Node_Access;
912 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
916 L := Left_Children.First;
917 R := Right_Children.First;
919 if not Equal_Subtree (L, R) then
934 function Equal_Subtree
935 (Left_Position : Cursor;
936 Right_Position : Cursor) return Boolean
939 if Left_Position = No_Element then
940 raise Constraint_Error with "Left cursor has no element";
943 if Right_Position = No_Element then
944 raise Constraint_Error with "Right cursor has no element";
947 if Left_Position = Right_Position then
951 if Is_Root (Left_Position) then
952 if not Is_Root (Right_Position) then
956 return Equal_Children (Left_Position.Node, Right_Position.Node);
959 if Is_Root (Right_Position) then
963 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
966 function Equal_Subtree
967 (Left_Subtree : Tree_Node_Access;
968 Right_Subtree : Tree_Node_Access) return Boolean
971 if Left_Subtree.Element.all /= Right_Subtree.Element.all then
975 return Equal_Children (Left_Subtree, Right_Subtree);
982 procedure Finalize (Object : in out Root_Iterator) is
983 B : Natural renames Object.Container.Busy;
994 Item : Element_Type) return Cursor
996 N : constant Tree_Node_Access :=
997 Find_In_Children (Root_Node (Container), Item);
1004 return Cursor'(Container'Unrestricted_Access, N);
1011 overriding function First (Object : Subtree_Iterator) return Cursor is
1013 if Object.Subtree = Root_Node (Object.Container.all) then
1014 return First_Child (Root (Object.Container.all));
1016 return Cursor'(Object.Container, Object.Subtree);
1020 overriding function First (Object : Child_Iterator) return Cursor is
1022 return First_Child (Cursor'(Object.Container, Object.Subtree));
1029 function First_Child (Parent : Cursor) return Cursor is
1030 Node : Tree_Node_Access;
1033 if Parent = No_Element then
1034 raise Constraint_Error with "Parent cursor has no element";
1037 Node := Parent.Node.Children.First;
1043 return Cursor'(Parent.Container, Node);
1046 -------------------------
1047 -- First_Child_Element --
1048 -------------------------
1050 function First_Child_Element (Parent : Cursor) return Element_Type is
1052 return Element (First_Child (Parent));
1053 end First_Child_Element;
1055 ----------------------
1056 -- Find_In_Children --
1057 ----------------------
1059 function Find_In_Children
1060 (Subtree : Tree_Node_Access;
1061 Item : Element_Type) return Tree_Node_Access
1063 N, Result : Tree_Node_Access;
1066 N := Subtree.Children.First;
1067 while N /= null loop
1068 Result := Find_In_Subtree (N, Item);
1070 if Result /= null then
1078 end Find_In_Children;
1080 ---------------------
1081 -- Find_In_Subtree --
1082 ---------------------
1084 function Find_In_Subtree
1086 Item : Element_Type) return Cursor
1088 Result : Tree_Node_Access;
1091 if Position = No_Element then
1092 raise Constraint_Error with "Position cursor has no element";
1095 -- Commented-out pending ruling from ARG. ???
1097 -- if Position.Container /= Container'Unrestricted_Access then
1098 -- raise Program_Error with "Position cursor not in container";
1101 if Is_Root (Position) then
1102 Result := Find_In_Children (Position.Node, Item);
1105 Result := Find_In_Subtree (Position.Node, Item);
1108 if Result = null then
1112 return Cursor'(Position.Container, Result);
1113 end Find_In_Subtree;
1115 function Find_In_Subtree
1116 (Subtree : Tree_Node_Access;
1117 Item : Element_Type) return Tree_Node_Access
1120 if Subtree.Element.all = Item then
1124 return Find_In_Children (Subtree, Item);
1125 end Find_In_Subtree;
1131 function Has_Element (Position : Cursor) return Boolean is
1133 if Position = No_Element then
1137 return Position.Node.Parent /= null;
1144 procedure Insert_Child
1145 (Container : in out Tree;
1148 New_Item : Element_Type;
1149 Count : Count_Type := 1)
1152 pragma Unreferenced (Position);
1155 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1158 procedure Insert_Child
1159 (Container : in out Tree;
1162 New_Item : Element_Type;
1163 Position : out Cursor;
1164 Count : Count_Type := 1)
1166 Last : Tree_Node_Access;
1167 Element : Element_Access;
1170 if Parent = No_Element then
1171 raise Constraint_Error with "Parent cursor has no element";
1174 if Parent.Container /= Container'Unrestricted_Access then
1175 raise Program_Error with "Parent cursor not in container";
1178 if Before /= No_Element then
1179 if Before.Container /= Container'Unrestricted_Access then
1180 raise Program_Error with "Before cursor not in container";
1183 if Before.Node.Parent /= Parent.Node then
1184 raise Constraint_Error with "Parent cursor not parent of Before";
1189 Position := No_Element; -- Need ruling from ARG ???
1193 if Container.Busy > 0 then
1195 with "attempt to tamper with cursors (tree is busy)";
1198 Position.Container := Parent.Container;
1200 Element := new Element_Type'(New_Item);
1201 Position.Node := new Tree_Node_Type'(Parent => Parent.Node,
1205 Last := Position.Node;
1207 for J in Count_Type'(2) .. Count loop
1208 -- Reclaim other nodes if Storage_Error. ???
1210 Element := new Element_Type'(New_Item);
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 if Position = No_Element then
1324 return Position.Node.Children.First = null;
1331 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1332 pragma Assert (From /= null);
1333 pragma Assert (To /= null);
1335 N : Tree_Node_Access;
1339 while N /= null loop
1354 function Is_Root (Position : Cursor) return Boolean is
1356 if Position.Container = null then
1360 return Position = Root (Position.Container.all);
1369 Process : not null access procedure (Position : Cursor))
1371 B : Natural renames Container'Unrestricted_Access.all.Busy;
1377 (Container => Container'Unrestricted_Access,
1378 Subtree => Root_Node (Container),
1379 Process => Process);
1389 function Iterate (Container : Tree)
1390 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1393 return Iterate_Subtree (Root (Container));
1396 ----------------------
1397 -- Iterate_Children --
1398 ----------------------
1400 procedure Iterate_Children
1402 Process : not null access procedure (Position : Cursor))
1405 if Parent = No_Element then
1406 raise Constraint_Error with "Parent cursor has no element";
1410 B : Natural renames Parent.Container.Busy;
1411 C : Tree_Node_Access;
1416 C := Parent.Node.Children.First;
1417 while C /= null loop
1418 Process (Position => Cursor'(Parent.Container, Node => C));
1429 end Iterate_Children;
1431 procedure Iterate_Children
1432 (Container : Tree_Access;
1433 Subtree : Tree_Node_Access;
1434 Process : not null access procedure (Position : Cursor))
1436 Node : Tree_Node_Access;
1439 -- This is a helper function to recursively iterate over all the nodes
1440 -- in a subtree, in depth-first fashion. This particular helper just
1441 -- visits the children of this subtree, not the root of the subtree node
1442 -- itself. This is useful when starting from the ultimate root of the
1443 -- entire tree (see Iterate), as that root does not have an element.
1445 Node := Subtree.Children.First;
1446 while Node /= null loop
1447 Iterate_Subtree (Container, Node, Process);
1450 end Iterate_Children;
1452 function Iterate_Children
1455 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1457 C : constant Tree_Access := Container'Unrestricted_Access;
1458 B : Natural renames C.Busy;
1461 if Parent = No_Element then
1462 raise Constraint_Error with "Parent cursor has no element";
1465 if Parent.Container /= C then
1466 raise Program_Error with "Parent cursor not in container";
1469 return It : constant Child_Iterator :=
1470 Child_Iterator'(Limited_Controlled with
1472 Subtree => Parent.Node)
1476 end Iterate_Children;
1478 ---------------------
1479 -- Iterate_Subtree --
1480 ---------------------
1482 function Iterate_Subtree
1484 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1487 if Position = No_Element then
1488 raise Constraint_Error with "Position cursor has no element";
1491 -- Implement Vet for multiway trees???
1492 -- pragma Assert (Vet (Position), "bad subtree cursor");
1495 B : Natural renames Position.Container.Busy;
1497 return It : constant Subtree_Iterator :=
1498 (Limited_Controlled with
1499 Container => Position.Container,
1500 Subtree => Position.Node)
1505 end Iterate_Subtree;
1507 procedure Iterate_Subtree
1509 Process : not null access procedure (Position : Cursor))
1512 if Position = No_Element then
1513 raise Constraint_Error with "Position cursor has no element";
1517 B : Natural renames Position.Container.Busy;
1522 if Is_Root (Position) then
1523 Iterate_Children (Position.Container, Position.Node, Process);
1525 Iterate_Subtree (Position.Container, Position.Node, Process);
1535 end Iterate_Subtree;
1537 procedure Iterate_Subtree
1538 (Container : Tree_Access;
1539 Subtree : Tree_Node_Access;
1540 Process : not null access procedure (Position : Cursor))
1543 -- This is a helper function to recursively iterate over all the nodes
1544 -- in a subtree, in depth-first fashion. It first visits the root of the
1545 -- subtree, then visits its children.
1547 Process (Cursor'(Container, Subtree));
1548 Iterate_Children (Container, Subtree, Process);
1549 end Iterate_Subtree;
1555 overriding function Last (Object : Child_Iterator) return Cursor is
1557 return Last_Child (Cursor'(Object.Container, Object.Subtree));
1564 function Last_Child (Parent : Cursor) return Cursor is
1565 Node : Tree_Node_Access;
1568 if Parent = No_Element then
1569 raise Constraint_Error with "Parent cursor has no element";
1572 Node := Parent.Node.Children.Last;
1578 return (Parent.Container, Node);
1581 ------------------------
1582 -- Last_Child_Element --
1583 ------------------------
1585 function Last_Child_Element (Parent : Cursor) return Element_Type is
1587 return Element (Last_Child (Parent));
1588 end Last_Child_Element;
1594 procedure Move (Target : in out Tree; Source : in out Tree) is
1595 Node : Tree_Node_Access;
1598 if Target'Address = Source'Address then
1602 if Source.Busy > 0 then
1604 with "attempt to tamper with cursors of Source (tree is busy)";
1607 Target.Clear; -- checks busy bit
1609 Target.Root.Children := Source.Root.Children;
1610 Source.Root.Children := Children_Type'(others => null);
1612 Node := Target.Root.Children.First;
1613 while Node /= null loop
1614 Node.Parent := Root_Node (Target);
1618 Target.Count := Source.Count;
1627 (Object : Subtree_Iterator;
1628 Position : Cursor) return Cursor
1630 Node : Tree_Node_Access;
1633 if Position.Container = null then
1637 if Position.Container /= Object.Container then
1638 raise Program_Error with
1639 "Position cursor of Next designates wrong tree";
1642 Node := Position.Node;
1644 if Node.Children.First /= null then
1645 return Cursor'(Object.Container, Node.Children.First);
1648 while Node /= Object.Subtree loop
1649 if Node.Next /= null then
1650 return Cursor'(Object.Container, Node.Next);
1653 Node := Node.Parent;
1660 (Object : Child_Iterator;
1661 Position : Cursor) return Cursor
1664 if Position.Container = null then
1668 if Position.Container /= Object.Container then
1669 raise Program_Error with
1670 "Position cursor of Next designates wrong tree";
1673 return Next_Sibling (Position);
1680 function Next_Sibling (Position : Cursor) return Cursor is
1682 if Position = No_Element then
1686 if Position.Node.Next = null then
1690 return Cursor'(Position.Container, Position.Node.Next);
1693 procedure Next_Sibling (Position : in out Cursor) is
1695 Position := Next_Sibling (Position);
1702 function Node_Count (Container : Tree) return Count_Type is
1704 -- Container.Count is the number of nodes we have actually allocated. We
1705 -- cache the value specifically so this Node_Count operation can execute
1706 -- in O(1) time, which makes it behave similarly to how the Length
1707 -- selector function behaves for other containers.
1709 -- The cached node count value only describes the nodes we have
1710 -- allocated; the root node itself is not included in that count. The
1711 -- Node_Count operation returns a value that includes the root node
1712 -- (because the RM says so), so we must add 1 to our cached value.
1714 return 1 + Container.Count;
1721 function Parent (Position : Cursor) return Cursor is
1723 if Position = No_Element then
1727 if Position.Node.Parent = null then
1731 return Cursor'(Position.Container, Position.Node.Parent);
1738 procedure Prepend_Child
1739 (Container : in out Tree;
1741 New_Item : Element_Type;
1742 Count : Count_Type := 1)
1744 First, Last : Tree_Node_Access;
1745 Element : Element_Access;
1748 if Parent = No_Element then
1749 raise Constraint_Error with "Parent cursor has no element";
1752 if Parent.Container /= Container'Unrestricted_Access then
1753 raise Program_Error with "Parent cursor not in container";
1760 if Container.Busy > 0 then
1762 with "attempt to tamper with cursors (tree is busy)";
1765 Element := new Element_Type'(New_Item);
1766 First := new Tree_Node_Type'(Parent => Parent.Node,
1772 for J in Count_Type'(2) .. Count loop
1774 -- Reclaim other nodes if Storage_Error. ???
1776 Element := new Element_Type'(New_Item);
1777 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1788 Parent => Parent.Node,
1789 Before => Parent.Node.Children.First);
1791 -- In order for operation Node_Count to complete in O(1) time, we cache
1792 -- the count value. Here we increment the total count by the number of
1793 -- nodes we just inserted.
1795 Container.Count := Container.Count + Count;
1802 overriding function Previous
1803 (Object : Child_Iterator;
1804 Position : Cursor) return Cursor
1807 if Position.Container = null then
1811 if Position.Container /= Object.Container then
1812 raise Program_Error with
1813 "Position cursor of Previous designates wrong tree";
1816 return Previous_Sibling (Position);
1819 ----------------------
1820 -- Previous_Sibling --
1821 ----------------------
1823 function Previous_Sibling (Position : Cursor) return Cursor is
1825 if Position = No_Element then
1829 if Position.Node.Prev = null then
1833 return Cursor'(Position.Container, Position.Node.Prev);
1834 end Previous_Sibling;
1836 procedure Previous_Sibling (Position : in out Cursor) is
1838 Position := Previous_Sibling (Position);
1839 end Previous_Sibling;
1845 procedure Query_Element
1847 Process : not null access procedure (Element : Element_Type))
1850 if Position = No_Element then
1851 raise Constraint_Error with "Position cursor has no element";
1854 if Is_Root (Position) then
1855 raise Program_Error with "Position cursor designates root";
1859 T : Tree renames Position.Container.all'Unrestricted_Access.all;
1860 B : Natural renames T.Busy;
1861 L : Natural renames T.Lock;
1867 Process (Position.Node.Element.all);
1885 (Stream : not null access Root_Stream_Type'Class;
1886 Container : out Tree)
1888 procedure Read_Children (Subtree : Tree_Node_Access);
1890 function Read_Subtree
1891 (Parent : Tree_Node_Access) return Tree_Node_Access;
1893 Total_Count : Count_Type'Base;
1894 -- Value read from the stream that says how many elements follow
1896 Read_Count : Count_Type'Base;
1897 -- Actual number of elements read from the stream
1903 procedure Read_Children (Subtree : Tree_Node_Access) is
1904 pragma Assert (Subtree /= null);
1905 pragma Assert (Subtree.Children.First = null);
1906 pragma Assert (Subtree.Children.Last = null);
1908 Count : Count_Type'Base;
1909 -- Number of child subtrees
1914 Count_Type'Read (Stream, Count);
1917 raise Program_Error with "attempt to read from corrupt stream";
1924 C.First := Read_Subtree (Parent => Subtree);
1927 for J in Count_Type'(2) .. Count loop
1928 C.Last.Next := Read_Subtree (Parent => Subtree);
1929 C.Last.Next.Prev := C.Last;
1930 C.Last := C.Last.Next;
1933 -- Now that the allocation and reads have completed successfully, it
1934 -- is safe to link the children to their parent.
1936 Subtree.Children := C;
1943 function Read_Subtree
1944 (Parent : Tree_Node_Access) return Tree_Node_Access
1946 Element : constant Element_Access :=
1947 new Element_Type'(Element_Type'Input (Stream));
1949 Subtree : constant Tree_Node_Access :=
1956 Read_Count := Read_Count + 1;
1958 Read_Children (Subtree);
1963 -- Start of processing for Read
1966 Container.Clear; -- checks busy bit
1968 Count_Type'Read (Stream, Total_Count);
1970 if Total_Count < 0 then
1971 raise Program_Error with "attempt to read from corrupt stream";
1974 if Total_Count = 0 then
1980 Read_Children (Root_Node (Container));
1982 if Read_Count /= Total_Count then
1983 raise Program_Error with "attempt to read from corrupt stream";
1986 Container.Count := Total_Count;
1990 (Stream : not null access Root_Stream_Type'Class;
1991 Position : out Cursor)
1994 raise Program_Error with "attempt to read tree cursor from stream";
1998 (Stream : not null access Root_Stream_Type'Class;
1999 Item : out Reference_Type)
2002 raise Program_Error with "attempt to stream reference";
2006 (Stream : not null access Root_Stream_Type'Class;
2007 Item : out Constant_Reference_Type)
2010 raise Program_Error with "attempt to stream reference";
2018 (Container : aliased in out Tree;
2019 Position : Cursor) return Reference_Type
2022 if Position.Container = null then
2023 raise Constraint_Error with
2024 "Position cursor has no element";
2027 if Position.Container /= Container'Unrestricted_Access then
2028 raise Program_Error with
2029 "Position cursor designates wrong container";
2032 if Position.Node = Root_Node (Container) then
2033 raise Program_Error with "Position cursor designates root";
2036 if Position.Node.Element = null then
2037 raise Program_Error with "Node has no element";
2040 -- Implement Vet for multiway tree???
2041 -- pragma Assert (Vet (Position),
2042 -- "Position cursor in Constant_Reference is bad");
2044 return (Element => Position.Node.Element.all'Access);
2047 --------------------
2048 -- Remove_Subtree --
2049 --------------------
2051 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2052 C : Children_Type renames Subtree.Parent.Children;
2055 -- This is a utility operation to remove a subtree node from its
2056 -- parent's list of children.
2058 if C.First = Subtree then
2059 pragma Assert (Subtree.Prev = null);
2061 if C.Last = Subtree then
2062 pragma Assert (Subtree.Next = null);
2067 C.First := Subtree.Next;
2068 C.First.Prev := null;
2071 elsif C.Last = Subtree then
2072 pragma Assert (Subtree.Next = null);
2073 C.Last := Subtree.Prev;
2074 C.Last.Next := null;
2077 Subtree.Prev.Next := Subtree.Next;
2078 Subtree.Next.Prev := Subtree.Prev;
2082 ----------------------
2083 -- Replace_Element --
2084 ----------------------
2086 procedure Replace_Element
2087 (Container : in out Tree;
2089 New_Item : Element_Type)
2091 E, X : Element_Access;
2094 if Position = No_Element then
2095 raise Constraint_Error with "Position cursor has no element";
2098 if Position.Container /= Container'Unrestricted_Access then
2099 raise Program_Error with "Position cursor not in container";
2102 if Is_Root (Position) then
2103 raise Program_Error with "Position cursor designates root";
2106 if Container.Lock > 0 then
2108 with "attempt to tamper with elements (tree is locked)";
2111 E := new Element_Type'(New_Item);
2113 X := Position.Node.Element;
2114 Position.Node.Element := E;
2117 end Replace_Element;
2119 ------------------------------
2120 -- Reverse_Iterate_Children --
2121 ------------------------------
2123 procedure Reverse_Iterate_Children
2125 Process : not null access procedure (Position : Cursor))
2128 if Parent = No_Element then
2129 raise Constraint_Error with "Parent cursor has no element";
2133 B : Natural renames Parent.Container.Busy;
2134 C : Tree_Node_Access;
2139 C := Parent.Node.Children.Last;
2140 while C /= null loop
2141 Process (Position => Cursor'(Parent.Container, Node => C));
2152 end Reverse_Iterate_Children;
2158 function Root (Container : Tree) return Cursor is
2160 return (Container'Unrestricted_Access, Root_Node (Container));
2167 function Root_Node (Container : Tree) return Tree_Node_Access is
2169 return Container.Root'Unrestricted_Access;
2172 ---------------------
2173 -- Splice_Children --
2174 ---------------------
2176 procedure Splice_Children
2177 (Target : in out Tree;
2178 Target_Parent : Cursor;
2180 Source : in out Tree;
2181 Source_Parent : Cursor)
2186 if Target_Parent = No_Element then
2187 raise Constraint_Error with "Target_Parent cursor has no element";
2190 if Target_Parent.Container /= Target'Unrestricted_Access then
2192 with "Target_Parent cursor not in Target container";
2195 if Before /= No_Element then
2196 if Before.Container /= Target'Unrestricted_Access then
2198 with "Before cursor not in Target container";
2201 if Before.Node.Parent /= Target_Parent.Node then
2202 raise Constraint_Error
2203 with "Before cursor not child of Target_Parent";
2207 if Source_Parent = No_Element then
2208 raise Constraint_Error with "Source_Parent cursor has no element";
2211 if Source_Parent.Container /= Source'Unrestricted_Access then
2213 with "Source_Parent cursor not in Source container";
2216 if Target'Address = Source'Address then
2217 if Target_Parent = Source_Parent then
2221 if Target.Busy > 0 then
2223 with "attempt to tamper with cursors (Target tree is busy)";
2226 if Is_Reachable (From => Target_Parent.Node,
2227 To => Source_Parent.Node)
2229 raise Constraint_Error
2230 with "Source_Parent is ancestor of Target_Parent";
2234 (Target_Parent => Target_Parent.Node,
2235 Before => Before.Node,
2236 Source_Parent => Source_Parent.Node);
2241 if Target.Busy > 0 then
2243 with "attempt to tamper with cursors (Target tree is busy)";
2246 if Source.Busy > 0 then
2248 with "attempt to tamper with cursors (Source tree is busy)";
2251 -- We cache the count of the nodes we have allocated, so that operation
2252 -- Node_Count can execute in O(1) time. But that means we must count the
2253 -- nodes in the subtree we remove from Source and insert into Target, in
2254 -- order to keep the count accurate.
2256 Count := Subtree_Node_Count (Source_Parent.Node);
2257 pragma Assert (Count >= 1);
2259 Count := Count - 1; -- because Source_Parent node does not move
2262 (Target_Parent => Target_Parent.Node,
2263 Before => Before.Node,
2264 Source_Parent => Source_Parent.Node);
2266 Source.Count := Source.Count - Count;
2267 Target.Count := Target.Count + Count;
2268 end Splice_Children;
2270 procedure Splice_Children
2271 (Container : in out Tree;
2272 Target_Parent : Cursor;
2274 Source_Parent : Cursor)
2277 if Target_Parent = No_Element then
2278 raise Constraint_Error with "Target_Parent cursor has no element";
2281 if Target_Parent.Container /= Container'Unrestricted_Access then
2283 with "Target_Parent cursor not in container";
2286 if Before /= No_Element then
2287 if Before.Container /= Container'Unrestricted_Access then
2289 with "Before cursor not in container";
2292 if Before.Node.Parent /= Target_Parent.Node then
2293 raise Constraint_Error
2294 with "Before cursor not child of Target_Parent";
2298 if Source_Parent = No_Element then
2299 raise Constraint_Error with "Source_Parent cursor has no element";
2302 if Source_Parent.Container /= Container'Unrestricted_Access then
2304 with "Source_Parent cursor not in container";
2307 if Target_Parent = Source_Parent then
2311 if Container.Busy > 0 then
2313 with "attempt to tamper with cursors (tree is busy)";
2316 if Is_Reachable (From => Target_Parent.Node,
2317 To => Source_Parent.Node)
2319 raise Constraint_Error
2320 with "Source_Parent is ancestor of Target_Parent";
2324 (Target_Parent => Target_Parent.Node,
2325 Before => Before.Node,
2326 Source_Parent => Source_Parent.Node);
2327 end Splice_Children;
2329 procedure Splice_Children
2330 (Target_Parent : Tree_Node_Access;
2331 Before : Tree_Node_Access;
2332 Source_Parent : Tree_Node_Access)
2334 CC : constant Children_Type := Source_Parent.Children;
2335 C : Tree_Node_Access;
2338 -- This is a utility operation to remove the children from Source parent
2339 -- and insert them into Target parent.
2341 Source_Parent.Children := Children_Type'(others => null);
2343 -- Fix up the Parent pointers of each child to designate its new Target
2347 while C /= null loop
2348 C.Parent := Target_Parent;
2355 Parent => Target_Parent,
2357 end Splice_Children;
2359 --------------------
2360 -- Splice_Subtree --
2361 --------------------
2363 procedure Splice_Subtree
2364 (Target : in out Tree;
2367 Source : in out Tree;
2368 Position : in out Cursor)
2370 Subtree_Count : Count_Type;
2373 if Parent = No_Element then
2374 raise Constraint_Error with "Parent cursor has no element";
2377 if Parent.Container /= Target'Unrestricted_Access then
2378 raise Program_Error with "Parent cursor not in Target container";
2381 if Before /= No_Element then
2382 if Before.Container /= Target'Unrestricted_Access then
2383 raise Program_Error with "Before cursor not in Target container";
2386 if Before.Node.Parent /= Parent.Node then
2387 raise Constraint_Error with "Before cursor not child of Parent";
2391 if Position = No_Element then
2392 raise Constraint_Error with "Position cursor has no element";
2395 if Position.Container /= Source'Unrestricted_Access then
2396 raise Program_Error with "Position cursor not in Source container";
2399 if Is_Root (Position) then
2400 raise Program_Error with "Position cursor designates root";
2403 if Target'Address = Source'Address then
2404 if Position.Node.Parent = Parent.Node then
2405 if Position.Node = Before.Node then
2409 if Position.Node.Next = Before.Node then
2414 if Target.Busy > 0 then
2416 with "attempt to tamper with cursors (Target tree is busy)";
2419 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2420 raise Constraint_Error with "Position is ancestor of Parent";
2423 Remove_Subtree (Position.Node);
2425 Position.Node.Parent := Parent.Node;
2426 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2431 if Target.Busy > 0 then
2433 with "attempt to tamper with cursors (Target tree is busy)";
2436 if Source.Busy > 0 then
2438 with "attempt to tamper with cursors (Source tree is busy)";
2441 -- This is an unfortunate feature of this API: we must count the nodes
2442 -- in the subtree that we remove from the source tree, which is an O(n)
2443 -- operation. It would have been better if the Tree container did not
2444 -- have a Node_Count selector; a user that wants the number of nodes in
2445 -- the tree could simply call Subtree_Node_Count, with the understanding
2446 -- that such an operation is O(n).
2448 -- Of course, we could choose to implement the Node_Count selector as an
2449 -- O(n) operation, which would turn this splice operation into an O(1)
2452 Subtree_Count := Subtree_Node_Count (Position.Node);
2453 pragma Assert (Subtree_Count <= Source.Count);
2455 Remove_Subtree (Position.Node);
2456 Source.Count := Source.Count - Subtree_Count;
2458 Position.Node.Parent := Parent.Node;
2459 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2461 Target.Count := Target.Count + Subtree_Count;
2463 Position.Container := Target'Unrestricted_Access;
2466 procedure Splice_Subtree
2467 (Container : in out Tree;
2473 if Parent = No_Element then
2474 raise Constraint_Error with "Parent cursor has no element";
2477 if Parent.Container /= Container'Unrestricted_Access then
2478 raise Program_Error with "Parent cursor not in container";
2481 if Before /= No_Element then
2482 if Before.Container /= Container'Unrestricted_Access then
2483 raise Program_Error with "Before cursor not in container";
2486 if Before.Node.Parent /= Parent.Node then
2487 raise Constraint_Error with "Before cursor not child of Parent";
2491 if Position = No_Element then
2492 raise Constraint_Error with "Position cursor has no element";
2495 if Position.Container /= Container'Unrestricted_Access then
2496 raise Program_Error with "Position cursor not in container";
2499 if Is_Root (Position) then
2501 -- Should this be PE instead? Need ARG confirmation. ???
2503 raise Constraint_Error with "Position cursor designates root";
2506 if Position.Node.Parent = Parent.Node then
2507 if Position.Node = Before.Node then
2511 if Position.Node.Next = Before.Node then
2516 if Container.Busy > 0 then
2518 with "attempt to tamper with cursors (tree is busy)";
2521 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2522 raise Constraint_Error with "Position is ancestor of Parent";
2525 Remove_Subtree (Position.Node);
2527 Position.Node.Parent := Parent.Node;
2528 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2531 ------------------------
2532 -- Subtree_Node_Count --
2533 ------------------------
2535 function Subtree_Node_Count (Position : Cursor) return Count_Type is
2537 if Position = No_Element then
2541 return Subtree_Node_Count (Position.Node);
2542 end Subtree_Node_Count;
2544 function Subtree_Node_Count
2545 (Subtree : Tree_Node_Access) return Count_Type
2547 Result : Count_Type;
2548 Node : Tree_Node_Access;
2552 Node := Subtree.Children.First;
2553 while Node /= null loop
2554 Result := Result + Subtree_Node_Count (Node);
2559 end Subtree_Node_Count;
2566 (Container : in out Tree;
2570 if I = No_Element then
2571 raise Constraint_Error with "I cursor has no element";
2574 if I.Container /= Container'Unrestricted_Access then
2575 raise Program_Error with "I cursor not in container";
2579 raise Program_Error with "I cursor designates root";
2582 if I = J then -- make this test sooner???
2586 if J = No_Element then
2587 raise Constraint_Error with "J cursor has no element";
2590 if J.Container /= Container'Unrestricted_Access then
2591 raise Program_Error with "J cursor not in container";
2595 raise Program_Error with "J cursor designates root";
2598 if Container.Lock > 0 then
2600 with "attempt to tamper with elements (tree is locked)";
2604 EI : constant Element_Access := I.Node.Element;
2607 I.Node.Element := J.Node.Element;
2608 J.Node.Element := EI;
2612 --------------------
2613 -- Update_Element --
2614 --------------------
2616 procedure Update_Element
2617 (Container : in out Tree;
2619 Process : not null access procedure (Element : in out Element_Type))
2622 if Position = No_Element then
2623 raise Constraint_Error with "Position cursor has no element";
2626 if Position.Container /= Container'Unrestricted_Access then
2627 raise Program_Error with "Position cursor not in container";
2630 if Is_Root (Position) then
2631 raise Program_Error with "Position cursor designates root";
2635 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2636 B : Natural renames T.Busy;
2637 L : Natural renames T.Lock;
2643 Process (Position.Node.Element.all);
2661 (Stream : not null access Root_Stream_Type'Class;
2664 procedure Write_Children (Subtree : Tree_Node_Access);
2665 procedure Write_Subtree (Subtree : Tree_Node_Access);
2667 --------------------
2668 -- Write_Children --
2669 --------------------
2671 procedure Write_Children (Subtree : Tree_Node_Access) is
2672 CC : Children_Type renames Subtree.Children;
2673 C : Tree_Node_Access;
2676 Count_Type'Write (Stream, Child_Count (CC));
2679 while C /= null loop
2689 procedure Write_Subtree (Subtree : Tree_Node_Access) is
2691 Element_Type'Output (Stream, Subtree.Element.all);
2692 Write_Children (Subtree);
2695 -- Start of processing for Write
2698 Count_Type'Write (Stream, Container.Count);
2700 if Container.Count = 0 then
2704 Write_Children (Root_Node (Container));
2708 (Stream : not null access Root_Stream_Type'Class;
2712 raise Program_Error with "attempt to write tree cursor to stream";
2716 (Stream : not null access Root_Stream_Type'Class;
2717 Item : Reference_Type)
2720 raise Program_Error with "attempt to stream reference";
2724 (Stream : not null access Root_Stream_Type'Class;
2725 Item : Constant_Reference_Type)
2728 raise Program_Error with "attempt to stream reference";
2731 end Ada.Containers.Indefinite_Multiway_Trees;