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;
31 with System; use type System.Address;
33 package body Ada.Containers.Indefinite_Multiway_Trees is
35 -----------------------
36 -- Local Subprograms --
37 -----------------------
39 function Root_Node (Container : Tree) return Tree_Node_Access;
41 procedure Free_Element is
42 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
44 procedure Deallocate_Node (X : in out Tree_Node_Access);
46 procedure Deallocate_Children
47 (Subtree : Tree_Node_Access;
48 Count : in out Count_Type);
50 procedure Deallocate_Subtree
51 (Subtree : in out Tree_Node_Access;
52 Count : in out Count_Type);
54 function Equal_Children
55 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
57 function Equal_Subtree
58 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
60 procedure Iterate_Children
61 (Container : Tree_Access;
62 Subtree : Tree_Node_Access;
63 Process : not null access procedure (Position : Cursor));
65 procedure Iterate_Subtree
66 (Container : Tree_Access;
67 Subtree : Tree_Node_Access;
68 Process : not null access procedure (Position : Cursor));
70 procedure Copy_Children
71 (Source : Children_Type;
72 Parent : Tree_Node_Access;
73 Count : in out Count_Type);
75 procedure Copy_Subtree
76 (Source : Tree_Node_Access;
77 Parent : Tree_Node_Access;
78 Target : out Tree_Node_Access;
79 Count : in out Count_Type);
81 function Find_In_Children
82 (Subtree : Tree_Node_Access;
83 Item : Element_Type) return Tree_Node_Access;
85 function Find_In_Subtree
86 (Subtree : Tree_Node_Access;
87 Item : Element_Type) return Tree_Node_Access;
89 function Child_Count (Children : Children_Type) return Count_Type;
91 function Subtree_Node_Count
92 (Subtree : Tree_Node_Access) return Count_Type;
94 function Is_Reachable (From, To : Tree_Node_Access) return Boolean;
96 procedure Remove_Subtree (Subtree : Tree_Node_Access);
98 procedure Insert_Subtree_Node
99 (Subtree : Tree_Node_Access;
100 Parent : Tree_Node_Access;
101 Before : Tree_Node_Access);
103 procedure Insert_Subtree_List
104 (First : Tree_Node_Access;
105 Last : Tree_Node_Access;
106 Parent : Tree_Node_Access;
107 Before : Tree_Node_Access);
109 procedure Splice_Children
110 (Target_Parent : Tree_Node_Access;
111 Before : Tree_Node_Access;
112 Source_Parent : Tree_Node_Access);
118 function "=" (Left, Right : Tree) return Boolean is
120 if Left'Address = Right'Address then
124 return Equal_Children (Root_Node (Left), Root_Node (Right));
131 procedure Adjust (Container : in out Tree) is
132 Source : constant Children_Type := Container.Root.Children;
133 Source_Count : constant Count_Type := Container.Count;
134 Target_Count : Count_Type;
137 -- We first restore the target container to its default-initialized
138 -- state, before we attempt any allocation, to ensure that invariants
139 -- are preserved in the event that the allocation fails.
141 Container.Root.Children := Children_Type'(others => null);
144 Container.Count := 0;
146 -- Copy_Children returns a count of the number of nodes that it
147 -- allocates, but it works by incrementing the value that is passed in.
148 -- We must therefore initialize the count value before calling
153 -- Now we attempt the allocation of subtrees. The invariants are
154 -- satisfied even if the allocation fails.
156 Copy_Children (Source, Root_Node (Container), Target_Count);
157 pragma Assert (Target_Count = Source_Count);
159 Container.Count := Source_Count;
166 function Ancestor_Find
168 Item : Element_Type) return Cursor
170 R, N : Tree_Node_Access;
173 if Position = No_Element then
174 raise Constraint_Error with "Position cursor has no element";
177 -- Commented-out pending ARG ruling. ???
179 -- if Position.Container /= Container'Unrestricted_Access then
180 -- raise Program_Error with "Position cursor not in container";
183 -- AI-0136 says to raise PE if Position equals the root node. This does
184 -- not seem correct, as this value is just the limiting condition of the
185 -- search. For now we omit this check pending a ruling from the ARG.???
187 -- if Is_Root (Position) then
188 -- raise Program_Error with "Position cursor designates root";
191 R := Root_Node (Position.Container.all);
194 if N.Element.all = Item then
195 return Cursor'(Position.Container, N);
208 procedure Append_Child
209 (Container : in out Tree;
211 New_Item : Element_Type;
212 Count : Count_Type := 1)
214 First, Last : Tree_Node_Access;
215 Element : Element_Access;
218 if Parent = No_Element then
219 raise Constraint_Error with "Parent cursor has no element";
222 if Parent.Container /= Container'Unrestricted_Access then
223 raise Program_Error with "Parent cursor not in container";
230 if Container.Busy > 0 then
232 with "attempt to tamper with cursors (tree is busy)";
235 Element := new Element_Type'(New_Item);
236 First := new Tree_Node_Type'(Parent => Parent.Node,
242 for J in Count_Type'(2) .. Count loop
244 -- Reclaim other nodes if Storage_Error. ???
246 Element := new Element_Type'(New_Item);
247 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
258 Parent => Parent.Node,
259 Before => null); -- null means "insert at end of list"
261 -- In order for operation Node_Count to complete in O(1) time, we cache
262 -- the count value. Here we increment the total count by the number of
263 -- nodes we just inserted.
265 Container.Count := Container.Count + Count;
272 procedure Assign (Target : in out Tree; Source : Tree) is
273 Source_Count : constant Count_Type := Source.Count;
274 Target_Count : Count_Type;
277 if Target'Address = Source'Address then
281 Target.Clear; -- checks busy bit
283 -- Copy_Children returns the number of nodes that it allocates, but it
284 -- does this by incrementing the count value passed in, so we must
285 -- initialize the count before calling Copy_Children.
289 -- Note that Copy_Children inserts the newly-allocated children into
290 -- their parent list only after the allocation of all the children has
291 -- succeeded. This preserves invariants even if the allocation fails.
293 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
294 pragma Assert (Target_Count = Source_Count);
296 Target.Count := Source_Count;
303 function Child_Count (Parent : Cursor) return Count_Type is
305 if Parent = No_Element then
308 return Child_Count (Parent.Node.Children);
312 function Child_Count (Children : Children_Type) return Count_Type is
314 Node : Tree_Node_Access;
318 Node := Children.First;
319 while Node /= null loop
320 Result := Result + 1;
331 function Child_Depth (Parent, Child : Cursor) return Count_Type is
333 N : Tree_Node_Access;
336 if Parent = No_Element then
337 raise Constraint_Error with "Parent cursor has no element";
340 if Child = No_Element then
341 raise Constraint_Error with "Child cursor has no element";
344 if Parent.Container /= Child.Container then
345 raise Program_Error with "Parent and Child in different containers";
350 while N /= Parent.Node loop
351 Result := Result + 1;
355 raise Program_Error with "Parent is not ancestor of Child";
366 procedure Clear (Container : in out Tree) is
367 Container_Count : Count_Type;
368 Children_Count : Count_Type;
371 if Container.Busy > 0 then
373 with "attempt to tamper with cursors (tree is busy)";
376 -- We first set the container count to 0, in order to preserve
377 -- invariants in case the deallocation fails. (This works because
378 -- Deallocate_Children immediately removes the children from their
379 -- parent, and then does the actual deallocation.)
381 Container_Count := Container.Count;
382 Container.Count := 0;
384 -- Deallocate_Children returns the number of nodes that it deallocates,
385 -- but it does this by incrementing the count value that is passed in,
386 -- so we must first initialize the count return value before calling it.
390 -- See comment above. Deallocate_Children immediately removes the
391 -- children list from their parent node (here, the root of the tree),
392 -- and only after that does it attempt the actual deallocation. So even
393 -- if the deallocation fails, the representation invariants
395 Deallocate_Children (Root_Node (Container), Children_Count);
396 pragma Assert (Children_Count = Container_Count);
405 Item : Element_Type) return Boolean
408 return Find (Container, Item) /= No_Element;
415 function Copy (Source : Tree) return Tree is
417 return Target : Tree do
419 (Source => Source.Root.Children,
420 Parent => Root_Node (Target),
421 Count => Target.Count);
423 pragma Assert (Target.Count = Source.Count);
431 procedure Copy_Children
432 (Source : Children_Type;
433 Parent : Tree_Node_Access;
434 Count : in out Count_Type)
436 pragma Assert (Parent /= null);
437 pragma Assert (Parent.Children.First = null);
438 pragma Assert (Parent.Children.Last = null);
441 C : Tree_Node_Access;
444 -- We special-case the first allocation, in order to establish the
445 -- representation invariants for type Children_Type.
461 -- The representation invariants for the Children_Type list have been
462 -- established, so we can now copy the remaining children of Source.
469 Target => CC.Last.Next,
472 CC.Last.Next.Prev := CC.Last;
473 CC.Last := CC.Last.Next;
478 -- We add the newly-allocated children to their parent list only after
479 -- the allocation has succeeded, in order to preserve invariants of the
482 Parent.Children := CC;
489 procedure Copy_Subtree
490 (Target : in out Tree;
495 Target_Subtree : Tree_Node_Access;
496 Target_Count : Count_Type;
499 if Parent = No_Element then
500 raise Constraint_Error with "Parent cursor has no element";
503 if Parent.Container /= Target'Unrestricted_Access then
504 raise Program_Error with "Parent cursor not in container";
507 if Before /= No_Element then
508 if Before.Container /= Target'Unrestricted_Access then
509 raise Program_Error with "Before cursor not in container";
512 if Before.Node.Parent /= Parent.Node then
513 raise Constraint_Error with "Before cursor not child of Parent";
517 if Source = No_Element then
521 if Is_Root (Source) then
522 raise Constraint_Error with "Source cursor designates root";
525 -- Copy_Subtree returns a count of the number of nodes that it
526 -- allocates, but it works by incrementing the value that is passed in.
527 -- We must therefore initialize the count value before calling
533 (Source => Source.Node,
534 Parent => Parent.Node,
535 Target => Target_Subtree,
536 Count => Target_Count);
538 pragma Assert (Target_Subtree /= null);
539 pragma Assert (Target_Subtree.Parent = Parent.Node);
540 pragma Assert (Target_Count >= 1);
543 (Subtree => Target_Subtree,
544 Parent => Parent.Node,
545 Before => Before.Node);
547 -- In order for operation Node_Count to complete in O(1) time, we cache
548 -- the count value. Here we increment the total count by the number of
549 -- nodes we just inserted.
551 Target.Count := Target.Count + Target_Count;
554 procedure Copy_Subtree
555 (Source : Tree_Node_Access;
556 Parent : Tree_Node_Access;
557 Target : out Tree_Node_Access;
558 Count : in out Count_Type)
560 E : constant Element_Access := new Element_Type'(Source.Element.all);
563 Target := new Tree_Node_Type'(Element => E,
570 (Source => Source.Children,
575 -------------------------
576 -- Deallocate_Children --
577 -------------------------
579 procedure Deallocate_Children
580 (Subtree : Tree_Node_Access;
581 Count : in out Count_Type)
583 pragma Assert (Subtree /= null);
585 CC : Children_Type := Subtree.Children;
586 C : Tree_Node_Access;
589 -- We immediately remove the children from their parent, in order to
590 -- preserve invariants in case the deallocation fails.
592 Subtree.Children := Children_Type'(others => null);
594 while CC.First /= null loop
598 Deallocate_Subtree (C, Count);
600 end Deallocate_Children;
602 ---------------------
603 -- Deallocate_Node --
604 ---------------------
606 procedure Deallocate_Node (X : in out Tree_Node_Access) is
607 procedure Free_Node is
608 new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access);
610 -- Start of processing for Deallocate_Node
614 Free_Element (X.Element);
619 ------------------------
620 -- Deallocate_Subtree --
621 ------------------------
623 procedure Deallocate_Subtree
624 (Subtree : in out Tree_Node_Access;
625 Count : in out Count_Type)
628 Deallocate_Children (Subtree, Count);
629 Deallocate_Node (Subtree);
631 end Deallocate_Subtree;
633 ---------------------
634 -- Delete_Children --
635 ---------------------
637 procedure Delete_Children
638 (Container : in out Tree;
644 if Parent = No_Element then
645 raise Constraint_Error with "Parent cursor has no element";
648 if Parent.Container /= Container'Unrestricted_Access then
649 raise Program_Error with "Parent cursor not in container";
652 if Container.Busy > 0 then
654 with "attempt to tamper with cursors (tree is busy)";
657 -- Deallocate_Children returns a count of the number of nodes
658 -- that it deallocates, but it works by incrementing the
659 -- value that is passed in. We must therefore initialize
660 -- the count value before calling Deallocate_Children.
664 Deallocate_Children (Parent.Node, Count);
665 pragma Assert (Count <= Container.Count);
667 Container.Count := Container.Count - Count;
674 procedure Delete_Leaf
675 (Container : in out Tree;
676 Position : in out Cursor)
678 X : Tree_Node_Access;
681 if Position = No_Element then
682 raise Constraint_Error with "Position cursor has no element";
685 if Position.Container /= Container'Unrestricted_Access then
686 raise Program_Error with "Position cursor not in container";
689 if Is_Root (Position) then
690 raise Program_Error with "Position cursor designates root";
693 if not Is_Leaf (Position) then
694 raise Constraint_Error with "Position cursor does not designate leaf";
697 if Container.Busy > 0 then
699 with "attempt to tamper with cursors (tree is busy)";
703 Position := No_Element;
705 -- Restore represention invariants before attempting the actual
709 Container.Count := Container.Count - 1;
711 -- It is now safe to attempt the deallocation. This leaf node has been
712 -- disassociated from the tree, so even if the deallocation fails,
713 -- representation invariants will remain satisfied.
722 procedure Delete_Subtree
723 (Container : in out Tree;
724 Position : in out Cursor)
726 X : Tree_Node_Access;
730 if Position = No_Element then
731 raise Constraint_Error with "Position cursor has no element";
734 if Position.Container /= Container'Unrestricted_Access then
735 raise Program_Error with "Position cursor not in container";
738 if Is_Root (Position) then
739 raise Program_Error with "Position cursor designates root";
742 if Container.Busy > 0 then
744 with "attempt to tamper with cursors (tree is busy)";
748 Position := No_Element;
750 -- Here is one case where a deallocation failure can result in the
751 -- violation of a representation invariant. We disassociate the subtree
752 -- from the tree now, but we only decrement the total node count after
753 -- we attempt the deallocation. However, if the deallocation fails, the
754 -- total node count will not get decremented.
756 -- One way around this dilemma is to count the nodes in the subtree
757 -- before attempt to delete the subtree, but that is an O(n) operation,
758 -- so it does not seem worth it.
760 -- Perhaps this is much ado about nothing, since the only way
761 -- deallocation can fail is if Controlled Finalization fails: this
762 -- propagates Program_Error so all bets are off anyway. ???
766 -- Deallocate_Subtree returns a count of the number of nodes that it
767 -- deallocates, but it works by incrementing the value that is passed
768 -- in. We must therefore initialize the count value before calling
769 -- Deallocate_Subtree.
773 Deallocate_Subtree (X, Count);
774 pragma Assert (Count <= Container.Count);
776 -- See comments above. We would prefer to do this sooner, but there's no
777 -- way to satisfy that goal without an potentially severe execution
780 Container.Count := Container.Count - Count;
787 function Depth (Position : Cursor) return Count_Type is
789 N : Tree_Node_Access;
796 Result := Result + 1;
806 function Element (Position : Cursor) return Element_Type is
808 if Position.Container = null then
809 raise Constraint_Error with "Position cursor has no element";
812 if Position.Node = Root_Node (Position.Container.all) then
813 raise Program_Error with "Position cursor designates root";
816 return Position.Node.Element.all;
823 function Equal_Children
824 (Left_Subtree : Tree_Node_Access;
825 Right_Subtree : Tree_Node_Access) return Boolean
827 Left_Children : Children_Type renames Left_Subtree.Children;
828 Right_Children : Children_Type renames Right_Subtree.Children;
830 L, R : Tree_Node_Access;
833 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
837 L := Left_Children.First;
838 R := Right_Children.First;
840 if not Equal_Subtree (L, R) then
855 function Equal_Subtree
856 (Left_Position : Cursor;
857 Right_Position : Cursor) return Boolean
860 if Left_Position = No_Element then
861 raise Constraint_Error with "Left cursor has no element";
864 if Right_Position = No_Element then
865 raise Constraint_Error with "Right cursor has no element";
868 if Left_Position = Right_Position then
872 if Is_Root (Left_Position) then
873 if not Is_Root (Right_Position) then
877 return Equal_Children (Left_Position.Node, Right_Position.Node);
880 if Is_Root (Right_Position) then
884 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
887 function Equal_Subtree
888 (Left_Subtree : Tree_Node_Access;
889 Right_Subtree : Tree_Node_Access) return Boolean
892 if Left_Subtree.Element.all /= Right_Subtree.Element.all then
896 return Equal_Children (Left_Subtree, Right_Subtree);
905 Item : Element_Type) return Cursor
907 N : constant Tree_Node_Access :=
908 Find_In_Children (Root_Node (Container), Item);
915 return Cursor'(Container'Unrestricted_Access, N);
922 function First_Child (Parent : Cursor) return Cursor is
923 Node : Tree_Node_Access;
926 if Parent = No_Element then
927 raise Constraint_Error with "Parent cursor has no element";
930 Node := Parent.Node.Children.First;
936 return Cursor'(Parent.Container, Node);
939 -------------------------
940 -- First_Child_Element --
941 -------------------------
943 function First_Child_Element (Parent : Cursor) return Element_Type is
945 return Element (First_Child (Parent));
946 end First_Child_Element;
948 ----------------------
949 -- Find_In_Children --
950 ----------------------
952 function Find_In_Children
953 (Subtree : Tree_Node_Access;
954 Item : Element_Type) return Tree_Node_Access
956 N, Result : Tree_Node_Access;
959 N := Subtree.Children.First;
961 Result := Find_In_Subtree (N, Item);
963 if Result /= null then
971 end Find_In_Children;
973 ---------------------
974 -- Find_In_Subtree --
975 ---------------------
977 function Find_In_Subtree
979 Item : Element_Type) return Cursor
981 Result : Tree_Node_Access;
984 if Position = No_Element then
985 raise Constraint_Error with "Position cursor has no element";
988 -- Commented-out pending ruling from ARG. ???
990 -- if Position.Container /= Container'Unrestricted_Access then
991 -- raise Program_Error with "Position cursor not in container";
994 if Is_Root (Position) then
995 Result := Find_In_Children (Position.Node, Item);
998 Result := Find_In_Subtree (Position.Node, Item);
1001 if Result = null then
1005 return Cursor'(Position.Container, Result);
1006 end Find_In_Subtree;
1008 function Find_In_Subtree
1009 (Subtree : Tree_Node_Access;
1010 Item : Element_Type) return Tree_Node_Access
1013 if Subtree.Element.all = Item then
1017 return Find_In_Children (Subtree, Item);
1018 end Find_In_Subtree;
1024 function Has_Element (Position : Cursor) return Boolean is
1026 if Position = No_Element then
1030 return Position.Node.Parent /= null;
1037 procedure Insert_Child
1038 (Container : in out Tree;
1041 New_Item : Element_Type;
1042 Count : Count_Type := 1)
1045 pragma Unreferenced (Position);
1048 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1051 procedure Insert_Child
1052 (Container : in out Tree;
1055 New_Item : Element_Type;
1056 Position : out Cursor;
1057 Count : Count_Type := 1)
1059 Last : Tree_Node_Access;
1060 Element : Element_Access;
1063 if Parent = No_Element then
1064 raise Constraint_Error with "Parent cursor has no element";
1067 if Parent.Container /= Container'Unrestricted_Access then
1068 raise Program_Error with "Parent cursor not in container";
1071 if Before /= No_Element then
1072 if Before.Container /= Container'Unrestricted_Access then
1073 raise Program_Error with "Before cursor not in container";
1076 if Before.Node.Parent /= Parent.Node then
1077 raise Constraint_Error with "Parent cursor not parent of Before";
1082 Position := No_Element; -- Need ruling from ARG ???
1086 if Container.Busy > 0 then
1088 with "attempt to tamper with cursors (tree is busy)";
1091 Position.Container := Parent.Container;
1093 Element := new Element_Type'(New_Item);
1094 Position.Node := new Tree_Node_Type'(Parent => Parent.Node,
1098 Last := Position.Node;
1100 for J in Count_Type'(2) .. Count loop
1101 -- Reclaim other nodes if Storage_Error. ???
1103 Element := new Element_Type'(New_Item);
1104 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1113 (First => Position.Node,
1115 Parent => Parent.Node,
1116 Before => Before.Node);
1118 -- In order for operation Node_Count to complete in O(1) time, we cache
1119 -- the count value. Here we increment the total count by the number of
1120 -- nodes we just inserted.
1122 Container.Count := Container.Count + Count;
1125 -------------------------
1126 -- Insert_Subtree_List --
1127 -------------------------
1129 procedure Insert_Subtree_List
1130 (First : Tree_Node_Access;
1131 Last : Tree_Node_Access;
1132 Parent : Tree_Node_Access;
1133 Before : Tree_Node_Access)
1135 pragma Assert (Parent /= null);
1136 C : Children_Type renames Parent.Children;
1139 -- This is a simple utility operation to insert a list of nodes (from
1140 -- First..Last) as children of Parent. The Before node specifies where
1141 -- the new children should be inserted relative to the existing
1144 if First = null then
1145 pragma Assert (Last = null);
1149 pragma Assert (Last /= null);
1150 pragma Assert (Before = null or else Before.Parent = Parent);
1152 if C.First = null then
1154 C.First.Prev := null;
1156 C.Last.Next := null;
1158 elsif Before = null then -- means "insert after existing nodes"
1159 C.Last.Next := First;
1160 First.Prev := C.Last;
1162 C.Last.Next := null;
1164 elsif Before = C.First then
1165 Last.Next := C.First;
1166 C.First.Prev := Last;
1168 C.First.Prev := null;
1171 Before.Prev.Next := First;
1172 First.Prev := Before.Prev;
1173 Last.Next := Before;
1174 Before.Prev := Last;
1176 end Insert_Subtree_List;
1178 -------------------------
1179 -- Insert_Subtree_Node --
1180 -------------------------
1182 procedure Insert_Subtree_Node
1183 (Subtree : Tree_Node_Access;
1184 Parent : Tree_Node_Access;
1185 Before : Tree_Node_Access)
1188 -- This is a simple wrapper operation to insert a single child into the
1189 -- Parent's children list.
1196 end Insert_Subtree_Node;
1202 function Is_Empty (Container : Tree) return Boolean is
1204 return Container.Root.Children.First = null;
1211 function Is_Leaf (Position : Cursor) return Boolean is
1213 if Position = No_Element then
1217 return Position.Node.Children.First = null;
1224 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1225 pragma Assert (From /= null);
1226 pragma Assert (To /= null);
1228 N : Tree_Node_Access;
1232 while N /= null loop
1247 function Is_Root (Position : Cursor) return Boolean is
1249 if Position.Container = null then
1253 return Position = Root (Position.Container.all);
1262 Process : not null access procedure (Position : Cursor))
1264 T : Tree renames Container'Unrestricted_Access.all;
1265 B : Integer renames T.Busy;
1271 (Container => Container'Unrestricted_Access,
1272 Subtree => Root_Node (Container),
1273 Process => Process);
1283 ----------------------
1284 -- Iterate_Children --
1285 ----------------------
1287 procedure Iterate_Children
1289 Process : not null access procedure (Position : Cursor))
1292 if Parent = No_Element then
1293 raise Constraint_Error with "Parent cursor has no element";
1297 B : Integer renames Parent.Container.Busy;
1298 C : Tree_Node_Access;
1303 C := Parent.Node.Children.First;
1304 while C /= null loop
1305 Process (Position => Cursor'(Parent.Container, Node => C));
1316 end Iterate_Children;
1318 procedure Iterate_Children
1319 (Container : Tree_Access;
1320 Subtree : Tree_Node_Access;
1321 Process : not null access procedure (Position : Cursor))
1323 Node : Tree_Node_Access;
1326 -- This is a helper function to recursively iterate over all the nodes
1327 -- in a subtree, in depth-first fashion. This particular helper just
1328 -- visits the children of this subtree, not the root of the subtree node
1329 -- itself. This is useful when starting from the ultimate root of the
1330 -- entire tree (see Iterate), as that root does not have an element.
1332 Node := Subtree.Children.First;
1333 while Node /= null loop
1334 Iterate_Subtree (Container, Node, Process);
1337 end Iterate_Children;
1339 ---------------------
1340 -- Iterate_Subtree --
1341 ---------------------
1343 procedure Iterate_Subtree
1345 Process : not null access procedure (Position : Cursor))
1348 if Position = No_Element then
1349 raise Constraint_Error with "Position cursor has no element";
1353 B : Integer renames Position.Container.Busy;
1358 if Is_Root (Position) then
1359 Iterate_Children (Position.Container, Position.Node, Process);
1361 Iterate_Subtree (Position.Container, Position.Node, Process);
1371 end Iterate_Subtree;
1373 procedure Iterate_Subtree
1374 (Container : Tree_Access;
1375 Subtree : Tree_Node_Access;
1376 Process : not null access procedure (Position : Cursor))
1379 -- This is a helper function to recursively iterate over all the nodes
1380 -- in a subtree, in depth-first fashion. It first visits the root of the
1381 -- subtree, then visits its children.
1383 Process (Cursor'(Container, Subtree));
1384 Iterate_Children (Container, Subtree, Process);
1385 end Iterate_Subtree;
1391 function Last_Child (Parent : Cursor) return Cursor is
1392 Node : Tree_Node_Access;
1395 if Parent = No_Element then
1396 raise Constraint_Error with "Parent cursor has no element";
1399 Node := Parent.Node.Children.Last;
1405 return (Parent.Container, Node);
1408 ------------------------
1409 -- Last_Child_Element --
1410 ------------------------
1412 function Last_Child_Element (Parent : Cursor) return Element_Type is
1414 return Element (Last_Child (Parent));
1415 end Last_Child_Element;
1421 procedure Move (Target : in out Tree; Source : in out Tree) is
1422 Node : Tree_Node_Access;
1425 if Target'Address = Source'Address then
1429 if Source.Busy > 0 then
1431 with "attempt to tamper with cursors of Source (tree is busy)";
1434 Target.Clear; -- checks busy bit
1436 Target.Root.Children := Source.Root.Children;
1437 Source.Root.Children := Children_Type'(others => null);
1439 Node := Target.Root.Children.First;
1440 while Node /= null loop
1441 Node.Parent := Root_Node (Target);
1445 Target.Count := Source.Count;
1453 function Next_Sibling (Position : Cursor) return Cursor is
1455 if Position = No_Element then
1459 if Position.Node.Next = null then
1463 return Cursor'(Position.Container, Position.Node.Next);
1466 procedure Next_Sibling (Position : in out Cursor) is
1468 Position := Next_Sibling (Position);
1475 function Node_Count (Container : Tree) return Count_Type is
1477 -- Container.Count is the number of nodes we have actually allocated. We
1478 -- cache the value specifically so this Node_Count operation can execute
1479 -- in O(1) time, which makes it behave similarly to how the Length
1480 -- selector function behaves for other containers.
1482 -- The cached node count value only describes the nodes we have
1483 -- allocated; the root node itself is not included in that count. The
1484 -- Node_Count operation returns a value that includes the root node
1485 -- (because the RM says so), so we must add 1 to our cached value.
1487 return 1 + Container.Count;
1494 function Parent (Position : Cursor) return Cursor is
1496 if Position = No_Element then
1500 if Position.Node.Parent = null then
1504 return Cursor'(Position.Container, Position.Node.Parent);
1511 procedure Prepend_Child
1512 (Container : in out Tree;
1514 New_Item : Element_Type;
1515 Count : Count_Type := 1)
1517 First, Last : Tree_Node_Access;
1518 Element : Element_Access;
1521 if Parent = No_Element then
1522 raise Constraint_Error with "Parent cursor has no element";
1525 if Parent.Container /= Container'Unrestricted_Access then
1526 raise Program_Error with "Parent cursor not in container";
1533 if Container.Busy > 0 then
1535 with "attempt to tamper with cursors (tree is busy)";
1538 Element := new Element_Type'(New_Item);
1539 First := new Tree_Node_Type'(Parent => Parent.Node,
1545 for J in Count_Type'(2) .. Count loop
1547 -- Reclaim other nodes if Storage_Error. ???
1549 Element := new Element_Type'(New_Item);
1550 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1561 Parent => Parent.Node,
1562 Before => Parent.Node.Children.First);
1564 -- In order for operation Node_Count to complete in O(1) time, we cache
1565 -- the count value. Here we increment the total count by the number of
1566 -- nodes we just inserted.
1568 Container.Count := Container.Count + Count;
1571 ----------------------
1572 -- Previous_Sibling --
1573 ----------------------
1575 function Previous_Sibling (Position : Cursor) return Cursor is
1577 if Position = No_Element then
1581 if Position.Node.Prev = null then
1585 return Cursor'(Position.Container, Position.Node.Prev);
1586 end Previous_Sibling;
1588 procedure Previous_Sibling (Position : in out Cursor) is
1590 Position := Previous_Sibling (Position);
1591 end Previous_Sibling;
1597 procedure Query_Element
1599 Process : not null access procedure (Element : Element_Type))
1602 if Position = No_Element then
1603 raise Constraint_Error with "Position cursor has no element";
1606 if Is_Root (Position) then
1607 raise Program_Error with "Position cursor designates root";
1611 T : Tree renames Position.Container.all'Unrestricted_Access.all;
1612 B : Integer renames T.Busy;
1613 L : Integer renames T.Lock;
1619 Process (Position.Node.Element.all);
1637 (Stream : not null access Root_Stream_Type'Class;
1638 Container : out Tree)
1640 procedure Read_Children (Subtree : Tree_Node_Access);
1642 function Read_Subtree
1643 (Parent : Tree_Node_Access) return Tree_Node_Access;
1645 Total_Count : Count_Type'Base;
1646 -- Value read from the stream that says how many elements follow
1648 Read_Count : Count_Type'Base;
1649 -- Actual number of elements read from the stream
1655 procedure Read_Children (Subtree : Tree_Node_Access) is
1656 pragma Assert (Subtree /= null);
1657 pragma Assert (Subtree.Children.First = null);
1658 pragma Assert (Subtree.Children.Last = null);
1660 Count : Count_Type'Base;
1661 -- Number of child subtrees
1666 Count_Type'Read (Stream, Count);
1669 raise Program_Error with "attempt to read from corrupt stream";
1676 C.First := Read_Subtree (Parent => Subtree);
1679 for J in Count_Type'(2) .. Count loop
1680 C.Last.Next := Read_Subtree (Parent => Subtree);
1681 C.Last.Next.Prev := C.Last;
1682 C.Last := C.Last.Next;
1685 -- Now that the allocation and reads have completed successfully, it
1686 -- is safe to link the children to their parent.
1688 Subtree.Children := C;
1695 function Read_Subtree
1696 (Parent : Tree_Node_Access) return Tree_Node_Access
1698 Element : constant Element_Access :=
1699 new Element_Type'(Element_Type'Input (Stream));
1701 Subtree : constant Tree_Node_Access :=
1708 Read_Count := Read_Count + 1;
1710 Read_Children (Subtree);
1715 -- Start of processing for Read
1718 Container.Clear; -- checks busy bit
1720 Count_Type'Read (Stream, Total_Count);
1722 if Total_Count < 0 then
1723 raise Program_Error with "attempt to read from corrupt stream";
1726 if Total_Count = 0 then
1732 Read_Children (Root_Node (Container));
1734 if Read_Count /= Total_Count then
1735 raise Program_Error with "attempt to read from corrupt stream";
1738 Container.Count := Total_Count;
1742 (Stream : not null access Root_Stream_Type'Class;
1743 Position : out Cursor)
1746 raise Program_Error with "attempt to read tree cursor from stream";
1749 --------------------
1750 -- Remove_Subtree --
1751 --------------------
1753 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
1754 C : Children_Type renames Subtree.Parent.Children;
1757 -- This is a utility operation to remove a subtree node from its
1758 -- parent's list of children.
1760 if C.First = Subtree then
1761 pragma Assert (Subtree.Prev = null);
1763 if C.Last = Subtree then
1764 pragma Assert (Subtree.Next = null);
1769 C.First := Subtree.Next;
1770 C.First.Prev := null;
1773 elsif C.Last = Subtree then
1774 pragma Assert (Subtree.Next = null);
1775 C.Last := Subtree.Prev;
1776 C.Last.Next := null;
1779 Subtree.Prev.Next := Subtree.Next;
1780 Subtree.Next.Prev := Subtree.Prev;
1784 ----------------------
1785 -- Replace_Element --
1786 ----------------------
1788 procedure Replace_Element
1789 (Container : in out Tree;
1791 New_Item : Element_Type)
1793 E, X : Element_Access;
1796 if Position = No_Element then
1797 raise Constraint_Error with "Position cursor has no element";
1800 if Position.Container /= Container'Unrestricted_Access then
1801 raise Program_Error with "Position cursor not in container";
1804 if Is_Root (Position) then
1805 raise Program_Error with "Position cursor designates root";
1808 if Container.Lock > 0 then
1810 with "attempt to tamper with elements (tree is locked)";
1813 E := new Element_Type'(New_Item);
1815 X := Position.Node.Element;
1816 Position.Node.Element := E;
1819 end Replace_Element;
1821 ------------------------------
1822 -- Reverse_Iterate_Children --
1823 ------------------------------
1825 procedure Reverse_Iterate_Children
1827 Process : not null access procedure (Position : Cursor))
1830 if Parent = No_Element then
1831 raise Constraint_Error with "Parent cursor has no element";
1835 B : Integer renames Parent.Container.Busy;
1836 C : Tree_Node_Access;
1841 C := Parent.Node.Children.Last;
1842 while C /= null loop
1843 Process (Position => Cursor'(Parent.Container, Node => C));
1854 end Reverse_Iterate_Children;
1860 function Root (Container : Tree) return Cursor is
1862 return (Container'Unrestricted_Access, Root_Node (Container));
1869 function Root_Node (Container : Tree) return Tree_Node_Access is
1871 return Container.Root'Unrestricted_Access;
1874 ---------------------
1875 -- Splice_Children --
1876 ---------------------
1878 procedure Splice_Children
1879 (Target : in out Tree;
1880 Target_Parent : Cursor;
1882 Source : in out Tree;
1883 Source_Parent : Cursor)
1888 if Target_Parent = No_Element then
1889 raise Constraint_Error with "Target_Parent cursor has no element";
1892 if Target_Parent.Container /= Target'Unrestricted_Access then
1894 with "Target_Parent cursor not in Target container";
1897 if Before /= No_Element then
1898 if Before.Container /= Target'Unrestricted_Access then
1900 with "Before cursor not in Target container";
1903 if Before.Node.Parent /= Target_Parent.Node then
1904 raise Constraint_Error
1905 with "Before cursor not child of Target_Parent";
1909 if Source_Parent = No_Element then
1910 raise Constraint_Error with "Source_Parent cursor has no element";
1913 if Source_Parent.Container /= Source'Unrestricted_Access then
1915 with "Source_Parent cursor not in Source container";
1918 if Target'Address = Source'Address then
1919 if Target_Parent = Source_Parent then
1923 if Target.Busy > 0 then
1925 with "attempt to tamper with cursors (Target tree is busy)";
1928 if Is_Reachable (From => Target_Parent.Node,
1929 To => Source_Parent.Node)
1931 raise Constraint_Error
1932 with "Source_Parent is ancestor of Target_Parent";
1936 (Target_Parent => Target_Parent.Node,
1937 Before => Before.Node,
1938 Source_Parent => Source_Parent.Node);
1943 if Target.Busy > 0 then
1945 with "attempt to tamper with cursors (Target tree is busy)";
1948 if Source.Busy > 0 then
1950 with "attempt to tamper with cursors (Source tree is busy)";
1953 -- We cache the count of the nodes we have allocated, so that operation
1954 -- Node_Count can execute in O(1) time. But that means we must count the
1955 -- nodes in the subtree we remove from Source and insert into Target, in
1956 -- order to keep the count accurate.
1958 Count := Subtree_Node_Count (Source_Parent.Node);
1959 pragma Assert (Count >= 1);
1961 Count := Count - 1; -- because Source_Parent node does not move
1964 (Target_Parent => Target_Parent.Node,
1965 Before => Before.Node,
1966 Source_Parent => Source_Parent.Node);
1968 Source.Count := Source.Count - Count;
1969 Target.Count := Target.Count + Count;
1970 end Splice_Children;
1972 procedure Splice_Children
1973 (Container : in out Tree;
1974 Target_Parent : Cursor;
1976 Source_Parent : Cursor)
1979 if Target_Parent = No_Element then
1980 raise Constraint_Error with "Target_Parent cursor has no element";
1983 if Target_Parent.Container /= Container'Unrestricted_Access then
1985 with "Target_Parent cursor not in container";
1988 if Before /= No_Element then
1989 if Before.Container /= Container'Unrestricted_Access then
1991 with "Before cursor not in container";
1994 if Before.Node.Parent /= Target_Parent.Node then
1995 raise Constraint_Error
1996 with "Before cursor not child of Target_Parent";
2000 if Source_Parent = No_Element then
2001 raise Constraint_Error with "Source_Parent cursor has no element";
2004 if Source_Parent.Container /= Container'Unrestricted_Access then
2006 with "Source_Parent cursor not in container";
2009 if Target_Parent = Source_Parent then
2013 if Container.Busy > 0 then
2015 with "attempt to tamper with cursors (tree is busy)";
2018 if Is_Reachable (From => Target_Parent.Node,
2019 To => Source_Parent.Node)
2021 raise Constraint_Error
2022 with "Source_Parent is ancestor of Target_Parent";
2026 (Target_Parent => Target_Parent.Node,
2027 Before => Before.Node,
2028 Source_Parent => Source_Parent.Node);
2029 end Splice_Children;
2031 procedure Splice_Children
2032 (Target_Parent : Tree_Node_Access;
2033 Before : Tree_Node_Access;
2034 Source_Parent : Tree_Node_Access)
2036 CC : constant Children_Type := Source_Parent.Children;
2037 C : Tree_Node_Access;
2040 -- This is a utility operation to remove the children from Source parent
2041 -- and insert them into Target parent.
2043 Source_Parent.Children := Children_Type'(others => null);
2045 -- Fix up the Parent pointers of each child to designate its new Target
2049 while C /= null loop
2050 C.Parent := Target_Parent;
2057 Parent => Target_Parent,
2059 end Splice_Children;
2061 --------------------
2062 -- Splice_Subtree --
2063 --------------------
2065 procedure Splice_Subtree
2066 (Target : in out Tree;
2069 Source : in out Tree;
2070 Position : in out Cursor)
2072 Subtree_Count : Count_Type;
2075 if Parent = No_Element then
2076 raise Constraint_Error with "Parent cursor has no element";
2079 if Parent.Container /= Target'Unrestricted_Access then
2080 raise Program_Error with "Parent cursor not in Target container";
2083 if Before /= No_Element then
2084 if Before.Container /= Target'Unrestricted_Access then
2085 raise Program_Error with "Before cursor not in Target container";
2088 if Before.Node.Parent /= Parent.Node then
2089 raise Constraint_Error with "Before cursor not child of Parent";
2093 if Position = No_Element then
2094 raise Constraint_Error with "Position cursor has no element";
2097 if Position.Container /= Source'Unrestricted_Access then
2098 raise Program_Error with "Position cursor not in Source container";
2101 if Is_Root (Position) then
2102 raise Program_Error with "Position cursor designates root";
2105 if Target'Address = Source'Address then
2106 if Position.Node.Parent = Parent.Node then
2107 if Position.Node = Before.Node then
2111 if Position.Node.Next = Before.Node then
2116 if Target.Busy > 0 then
2118 with "attempt to tamper with cursors (Target tree is busy)";
2121 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2122 raise Constraint_Error with "Position is ancestor of Parent";
2125 Remove_Subtree (Position.Node);
2127 Position.Node.Parent := Parent.Node;
2128 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2133 if Target.Busy > 0 then
2135 with "attempt to tamper with cursors (Target tree is busy)";
2138 if Source.Busy > 0 then
2140 with "attempt to tamper with cursors (Source tree is busy)";
2143 -- This is an unfortunate feature of this API: we must count the nodes
2144 -- in the subtree that we remove from the source tree, which is an O(n)
2145 -- operation. It would have been better if the Tree container did not
2146 -- have a Node_Count selector; a user that wants the number of nodes in
2147 -- the tree could simply call Subtree_Node_Count, with the understanding
2148 -- that such an operation is O(n).
2150 -- Of course, we could choose to implement the Node_Count selector as an
2151 -- O(n) operation, which would turn this splice operation into an O(1)
2154 Subtree_Count := Subtree_Node_Count (Position.Node);
2155 pragma Assert (Subtree_Count <= Source.Count);
2157 Remove_Subtree (Position.Node);
2158 Source.Count := Source.Count - Subtree_Count;
2160 Position.Node.Parent := Parent.Node;
2161 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2163 Target.Count := Target.Count + Subtree_Count;
2165 Position.Container := Target'Unrestricted_Access;
2168 procedure Splice_Subtree
2169 (Container : in out Tree;
2175 if Parent = No_Element then
2176 raise Constraint_Error with "Parent cursor has no element";
2179 if Parent.Container /= Container'Unrestricted_Access then
2180 raise Program_Error with "Parent cursor not in container";
2183 if Before /= No_Element then
2184 if Before.Container /= Container'Unrestricted_Access then
2185 raise Program_Error with "Before cursor not in container";
2188 if Before.Node.Parent /= Parent.Node then
2189 raise Constraint_Error with "Before cursor not child of Parent";
2193 if Position = No_Element then
2194 raise Constraint_Error with "Position cursor has no element";
2197 if Position.Container /= Container'Unrestricted_Access then
2198 raise Program_Error with "Position cursor not in container";
2201 if Is_Root (Position) then
2203 -- Should this be PE instead? Need ARG confirmation. ???
2205 raise Constraint_Error with "Position cursor designates root";
2208 if Position.Node.Parent = Parent.Node then
2209 if Position.Node = Before.Node then
2213 if Position.Node.Next = Before.Node then
2218 if Container.Busy > 0 then
2220 with "attempt to tamper with cursors (tree is busy)";
2223 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2224 raise Constraint_Error with "Position is ancestor of Parent";
2227 Remove_Subtree (Position.Node);
2229 Position.Node.Parent := Parent.Node;
2230 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2233 ------------------------
2234 -- Subtree_Node_Count --
2235 ------------------------
2237 function Subtree_Node_Count (Position : Cursor) return Count_Type is
2239 if Position = No_Element then
2243 return Subtree_Node_Count (Position.Node);
2244 end Subtree_Node_Count;
2246 function Subtree_Node_Count
2247 (Subtree : Tree_Node_Access) return Count_Type
2249 Result : Count_Type;
2250 Node : Tree_Node_Access;
2254 Node := Subtree.Children.First;
2255 while Node /= null loop
2256 Result := Result + Subtree_Node_Count (Node);
2261 end Subtree_Node_Count;
2268 (Container : in out Tree;
2272 if I = No_Element then
2273 raise Constraint_Error with "I cursor has no element";
2276 if I.Container /= Container'Unrestricted_Access then
2277 raise Program_Error with "I cursor not in container";
2281 raise Program_Error with "I cursor designates root";
2284 if I = J then -- make this test sooner???
2288 if J = No_Element then
2289 raise Constraint_Error with "J cursor has no element";
2292 if J.Container /= Container'Unrestricted_Access then
2293 raise Program_Error with "J cursor not in container";
2297 raise Program_Error with "J cursor designates root";
2300 if Container.Lock > 0 then
2302 with "attempt to tamper with elements (tree is locked)";
2306 EI : constant Element_Access := I.Node.Element;
2309 I.Node.Element := J.Node.Element;
2310 J.Node.Element := EI;
2314 --------------------
2315 -- Update_Element --
2316 --------------------
2318 procedure Update_Element
2319 (Container : in out Tree;
2321 Process : not null access procedure (Element : in out Element_Type))
2324 if Position = No_Element then
2325 raise Constraint_Error with "Position cursor has no element";
2328 if Position.Container /= Container'Unrestricted_Access then
2329 raise Program_Error with "Position cursor not in container";
2332 if Is_Root (Position) then
2333 raise Program_Error with "Position cursor designates root";
2337 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2338 B : Integer renames T.Busy;
2339 L : Integer renames T.Lock;
2345 Process (Position.Node.Element.all);
2363 (Stream : not null access Root_Stream_Type'Class;
2366 procedure Write_Children (Subtree : Tree_Node_Access);
2367 procedure Write_Subtree (Subtree : Tree_Node_Access);
2369 --------------------
2370 -- Write_Children --
2371 --------------------
2373 procedure Write_Children (Subtree : Tree_Node_Access) is
2374 CC : Children_Type renames Subtree.Children;
2375 C : Tree_Node_Access;
2378 Count_Type'Write (Stream, Child_Count (CC));
2381 while C /= null loop
2391 procedure Write_Subtree (Subtree : Tree_Node_Access) is
2393 Element_Type'Output (Stream, Subtree.Element.all);
2394 Write_Children (Subtree);
2397 -- Start of processing for Write
2400 Count_Type'Write (Stream, Container.Count);
2402 if Container.Count = 0 then
2406 Write_Children (Root_Node (Container));
2410 (Stream : not null access Root_Stream_Type'Class;
2414 raise Program_Error with "attempt to write tree cursor to stream";
2417 end Ada.Containers.Indefinite_Multiway_Trees;