1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . M U L T I W A Y _ T R E E S --
9 -- Copyright (C) 2004-2011, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Unchecked_Conversion;
31 with Ada.Unchecked_Deallocation;
33 with System; use type System.Address;
35 package body Ada.Containers.Multiway_Trees is
41 type Root_Iterator is abstract new Limited_Controlled and
42 Tree_Iterator_Interfaces.Forward_Iterator with
44 Container : Tree_Access;
45 Subtree : Tree_Node_Access;
48 overriding procedure Finalize (Object : in out Root_Iterator);
50 -----------------------
51 -- Subtree_Iterator --
52 -----------------------
54 -- ??? these headers are a bit odd, but for sure they do not substitute
55 -- for documenting things, what *is* a Subtree_Iterator?
57 type Subtree_Iterator is new Root_Iterator with null record;
59 overriding function First (Object : Subtree_Iterator) return Cursor;
61 overriding function Next
62 (Object : Subtree_Iterator;
63 Position : Cursor) return Cursor;
69 type Child_Iterator is new Root_Iterator and
70 Tree_Iterator_Interfaces.Reversible_Iterator with null record;
72 overriding function First (Object : Child_Iterator) return Cursor;
74 overriding function Next
75 (Object : Child_Iterator;
76 Position : Cursor) return Cursor;
78 overriding function Last (Object : Child_Iterator) return Cursor;
80 overriding function Previous
81 (Object : Child_Iterator;
82 Position : Cursor) return Cursor;
84 -----------------------
85 -- Local Subprograms --
86 -----------------------
88 function Root_Node (Container : Tree) return Tree_Node_Access;
90 procedure Deallocate_Node is
91 new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access);
93 procedure Deallocate_Children
94 (Subtree : Tree_Node_Access;
95 Count : in out Count_Type);
97 procedure Deallocate_Subtree
98 (Subtree : in out Tree_Node_Access;
99 Count : in out Count_Type);
101 function Equal_Children
102 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
104 function Equal_Subtree
105 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
107 procedure Iterate_Children
108 (Container : Tree_Access;
109 Subtree : Tree_Node_Access;
110 Process : not null access procedure (Position : Cursor));
112 procedure Iterate_Subtree
113 (Container : Tree_Access;
114 Subtree : Tree_Node_Access;
115 Process : not null access procedure (Position : Cursor));
117 procedure Copy_Children
118 (Source : Children_Type;
119 Parent : Tree_Node_Access;
120 Count : in out Count_Type);
122 procedure Copy_Subtree
123 (Source : Tree_Node_Access;
124 Parent : Tree_Node_Access;
125 Target : out Tree_Node_Access;
126 Count : in out Count_Type);
128 function Find_In_Children
129 (Subtree : Tree_Node_Access;
130 Item : Element_Type) return Tree_Node_Access;
132 function Find_In_Subtree
133 (Subtree : Tree_Node_Access;
134 Item : Element_Type) return Tree_Node_Access;
136 function Child_Count (Children : Children_Type) return Count_Type;
138 function Subtree_Node_Count
139 (Subtree : Tree_Node_Access) return Count_Type;
141 function Is_Reachable (From, To : Tree_Node_Access) return Boolean;
143 procedure Remove_Subtree (Subtree : Tree_Node_Access);
145 procedure Insert_Subtree_Node
146 (Subtree : Tree_Node_Access;
147 Parent : Tree_Node_Access;
148 Before : Tree_Node_Access);
150 procedure Insert_Subtree_List
151 (First : Tree_Node_Access;
152 Last : Tree_Node_Access;
153 Parent : Tree_Node_Access;
154 Before : Tree_Node_Access);
156 procedure Splice_Children
157 (Target_Parent : Tree_Node_Access;
158 Before : Tree_Node_Access;
159 Source_Parent : Tree_Node_Access);
165 function "=" (Left, Right : Tree) return Boolean is
167 if Left'Address = Right'Address then
171 return Equal_Children (Root_Node (Left), Root_Node (Right));
178 procedure Adjust (Container : in out Tree) is
179 Source : constant Children_Type := Container.Root.Children;
180 Source_Count : constant Count_Type := Container.Count;
181 Target_Count : Count_Type;
184 -- We first restore the target container to its default-initialized
185 -- state, before we attempt any allocation, to ensure that invariants
186 -- are preserved in the event that the allocation fails.
188 Container.Root.Children := Children_Type'(others => null);
191 Container.Count := 0;
193 -- Copy_Children returns a count of the number of nodes that it
194 -- allocates, but it works by incrementing the value that is passed
195 -- in. We must therefore initialize the count value before calling
200 -- Now we attempt the allocation of subtrees. The invariants are
201 -- satisfied even if the allocation fails.
203 Copy_Children (Source, Root_Node (Container), Target_Count);
204 pragma Assert (Target_Count = Source_Count);
206 Container.Count := Source_Count;
213 function Ancestor_Find
215 Item : Element_Type) return Cursor
217 R, N : Tree_Node_Access;
220 if Position = No_Element then
221 raise Constraint_Error with "Position cursor has no element";
224 -- Commented-out pending official ruling from ARG. ???
226 -- if Position.Container /= Container'Unrestricted_Access then
227 -- raise Program_Error with "Position cursor not in container";
230 -- AI-0136 says to raise PE if Position equals the root node. This does
231 -- not seem correct, as this value is just the limiting condition of the
232 -- search. For now we omit this check, pending a ruling from the ARG.???
234 -- if Is_Root (Position) then
235 -- raise Program_Error with "Position cursor designates root";
238 R := Root_Node (Position.Container.all);
241 if N.Element = Item then
242 return Cursor'(Position.Container, N);
255 procedure Append_Child
256 (Container : in out Tree;
258 New_Item : Element_Type;
259 Count : Count_Type := 1)
261 First, Last : Tree_Node_Access;
264 if Parent = No_Element then
265 raise Constraint_Error with "Parent cursor has no element";
268 if Parent.Container /= Container'Unrestricted_Access then
269 raise Program_Error with "Parent cursor not in container";
276 if Container.Busy > 0 then
278 with "attempt to tamper with cursors (tree is busy)";
281 First := new Tree_Node_Type'(Parent => Parent.Node,
287 for J in Count_Type'(2) .. Count loop
289 -- Reclaim other nodes if Storage_Error. ???
291 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
302 Parent => Parent.Node,
303 Before => null); -- null means "insert at end of list"
305 -- In order for operation Node_Count to complete in O(1) time, we cache
306 -- the count value. Here we increment the total count by the number of
307 -- nodes we just inserted.
309 Container.Count := Container.Count + Count;
316 procedure Assign (Target : in out Tree; Source : Tree) is
317 Source_Count : constant Count_Type := Source.Count;
318 Target_Count : Count_Type;
321 if Target'Address = Source'Address then
325 Target.Clear; -- checks busy bit
327 -- Copy_Children returns the number of nodes that it allocates, but it
328 -- does this by incrementing the count value passed in, so we must
329 -- initialize the count before calling Copy_Children.
333 -- Note that Copy_Children inserts the newly-allocated children into
334 -- their parent list only after the allocation of all the children has
335 -- succeeded. This preserves invariants even if the allocation fails.
337 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
338 pragma Assert (Target_Count = Source_Count);
340 Target.Count := Source_Count;
347 function Child_Count (Parent : Cursor) return Count_Type is
349 return (if Parent = No_Element
350 then 0 else Child_Count (Parent.Node.Children));
353 function Child_Count (Children : Children_Type) return Count_Type is
355 Node : Tree_Node_Access;
359 Node := Children.First;
360 while Node /= null loop
361 Result := Result + 1;
372 function Child_Depth (Parent, Child : Cursor) return Count_Type is
374 N : Tree_Node_Access;
377 if Parent = No_Element then
378 raise Constraint_Error with "Parent cursor has no element";
381 if Child = No_Element then
382 raise Constraint_Error with "Child cursor has no element";
385 if Parent.Container /= Child.Container then
386 raise Program_Error with "Parent and Child in different containers";
391 while N /= Parent.Node loop
392 Result := Result + 1;
396 raise Program_Error with "Parent is not ancestor of Child";
407 procedure Clear (Container : in out Tree) is
408 Container_Count, Children_Count : Count_Type;
411 if Container.Busy > 0 then
413 with "attempt to tamper with cursors (tree is busy)";
416 -- We first set the container count to 0, in order to preserve
417 -- invariants in case the deallocation fails. (This works because
418 -- Deallocate_Children immediately removes the children from their
419 -- parent, and then does the actual deallocation.)
421 Container_Count := Container.Count;
422 Container.Count := 0;
424 -- Deallocate_Children returns the number of nodes that it deallocates,
425 -- but it does this by incrementing the count value that is passed in,
426 -- so we must first initialize the count return value before calling it.
430 -- See comment above. Deallocate_Children immediately removes the
431 -- children list from their parent node (here, the root of the tree),
432 -- and only after that does it attempt the actual deallocation. So even
433 -- if the deallocation fails, the representation invariants for the tree
436 Deallocate_Children (Root_Node (Container), Children_Count);
437 pragma Assert (Children_Count = Container_Count);
440 ------------------------
441 -- Constant_Reference --
442 ------------------------
444 function Constant_Reference
445 (Container : aliased Tree;
446 Position : Cursor) return Constant_Reference_Type
449 if Position.Container = null then
450 raise Constraint_Error with
451 "Position cursor has no element";
454 if Position.Container /= Container'Unrestricted_Access then
455 raise Program_Error with
456 "Position cursor designates wrong container";
459 if Position.Node = Root_Node (Container) then
460 raise Program_Error with "Position cursor designates root";
463 -- Implement Vet for multiway tree???
464 -- pragma Assert (Vet (Position),
465 -- "Position cursor in Constant_Reference is bad");
467 return (Element => Position.Node.Element'Access);
468 end Constant_Reference;
476 Item : Element_Type) return Boolean
479 return Find (Container, Item) /= No_Element;
486 function Copy (Source : Tree) return Tree is
488 return Target : Tree do
490 (Source => Source.Root.Children,
491 Parent => Root_Node (Target),
492 Count => Target.Count);
494 pragma Assert (Target.Count = Source.Count);
502 procedure Copy_Children
503 (Source : Children_Type;
504 Parent : Tree_Node_Access;
505 Count : in out Count_Type)
507 pragma Assert (Parent /= null);
508 pragma Assert (Parent.Children.First = null);
509 pragma Assert (Parent.Children.Last = null);
512 C : Tree_Node_Access;
515 -- We special-case the first allocation, in order to establish the
516 -- representation invariants for type Children_Type.
532 -- The representation invariants for the Children_Type list have been
533 -- established, so we can now copy the remaining children of Source.
540 Target => CC.Last.Next,
543 CC.Last.Next.Prev := CC.Last;
544 CC.Last := CC.Last.Next;
549 -- Add the newly-allocated children to their parent list only after the
550 -- allocation has succeeded, so as to preserve invariants of the parent.
552 Parent.Children := CC;
559 procedure Copy_Subtree
560 (Target : in out Tree;
565 Target_Subtree : Tree_Node_Access;
566 Target_Count : Count_Type;
569 if Parent = No_Element then
570 raise Constraint_Error with "Parent cursor has no element";
573 if Parent.Container /= Target'Unrestricted_Access then
574 raise Program_Error with "Parent cursor not in container";
577 if Before /= No_Element then
578 if Before.Container /= Target'Unrestricted_Access then
579 raise Program_Error with "Before cursor not in container";
582 if Before.Node.Parent /= Parent.Node then
583 raise Constraint_Error with "Before cursor not child of Parent";
587 if Source = No_Element then
591 if Is_Root (Source) then
592 raise Constraint_Error with "Source cursor designates root";
595 -- Copy_Subtree returns a count of the number of nodes that it
596 -- allocates, but it works by incrementing the value that is passed
597 -- in. We must therefore initialize the count value before calling
603 (Source => Source.Node,
604 Parent => Parent.Node,
605 Target => Target_Subtree,
606 Count => Target_Count);
608 pragma Assert (Target_Subtree /= null);
609 pragma Assert (Target_Subtree.Parent = Parent.Node);
610 pragma Assert (Target_Count >= 1);
613 (Subtree => Target_Subtree,
614 Parent => Parent.Node,
615 Before => Before.Node);
617 -- In order for operation Node_Count to complete in O(1) time, we cache
618 -- the count value. Here we increment the total count by the number of
619 -- nodes we just inserted.
621 Target.Count := Target.Count + Target_Count;
624 procedure Copy_Subtree
625 (Source : Tree_Node_Access;
626 Parent : Tree_Node_Access;
627 Target : out Tree_Node_Access;
628 Count : in out Count_Type)
631 Target := new Tree_Node_Type'(Element => Source.Element,
638 (Source => Source.Children,
643 -------------------------
644 -- Deallocate_Children --
645 -------------------------
647 procedure Deallocate_Children
648 (Subtree : Tree_Node_Access;
649 Count : in out Count_Type)
651 pragma Assert (Subtree /= null);
653 CC : Children_Type := Subtree.Children;
654 C : Tree_Node_Access;
657 -- We immediately remove the children from their parent, in order to
658 -- preserve invariants in case the deallocation fails.
660 Subtree.Children := Children_Type'(others => null);
662 while CC.First /= null loop
666 Deallocate_Subtree (C, Count);
668 end Deallocate_Children;
670 ------------------------
671 -- Deallocate_Subtree --
672 ------------------------
674 procedure Deallocate_Subtree
675 (Subtree : in out Tree_Node_Access;
676 Count : in out Count_Type)
679 Deallocate_Children (Subtree, Count);
680 Deallocate_Node (Subtree);
682 end Deallocate_Subtree;
684 ---------------------
685 -- Delete_Children --
686 ---------------------
688 procedure Delete_Children
689 (Container : in out Tree;
695 if Parent = No_Element then
696 raise Constraint_Error with "Parent cursor has no element";
699 if Parent.Container /= Container'Unrestricted_Access then
700 raise Program_Error with "Parent cursor not in container";
703 if Container.Busy > 0 then
705 with "attempt to tamper with cursors (tree is busy)";
708 -- Deallocate_Children returns a count of the number of nodes that it
709 -- deallocates, but it works by incrementing the value that is passed
710 -- in. We must therefore initialize the count value before calling
711 -- Deallocate_Children.
715 Deallocate_Children (Parent.Node, Count);
716 pragma Assert (Count <= Container.Count);
718 Container.Count := Container.Count - Count;
725 procedure Delete_Leaf
726 (Container : in out Tree;
727 Position : in out Cursor)
729 X : Tree_Node_Access;
732 if Position = No_Element then
733 raise Constraint_Error with "Position cursor has no element";
736 if Position.Container /= Container'Unrestricted_Access then
737 raise Program_Error with "Position cursor not in container";
740 if Is_Root (Position) then
741 raise Program_Error with "Position cursor designates root";
744 if not Is_Leaf (Position) then
745 raise Constraint_Error with "Position cursor does not designate leaf";
748 if Container.Busy > 0 then
750 with "attempt to tamper with cursors (tree is busy)";
754 Position := No_Element;
756 -- Restore represention invariants before attempting the actual
760 Container.Count := Container.Count - 1;
762 -- It is now safe to attempt the deallocation. This leaf node has been
763 -- disassociated from the tree, so even if the deallocation fails,
764 -- representation invariants will remain satisfied.
773 procedure Delete_Subtree
774 (Container : in out Tree;
775 Position : in out Cursor)
777 X : Tree_Node_Access;
781 if Position = No_Element then
782 raise Constraint_Error with "Position cursor has no element";
785 if Position.Container /= Container'Unrestricted_Access then
786 raise Program_Error with "Position cursor not in container";
789 if Is_Root (Position) then
790 raise Program_Error with "Position cursor designates root";
793 if Container.Busy > 0 then
795 with "attempt to tamper with cursors (tree is busy)";
799 Position := No_Element;
801 -- Here is one case where a deallocation failure can result in the
802 -- violation of a representation invariant. We disassociate the subtree
803 -- from the tree now, but we only decrement the total node count after
804 -- we attempt the deallocation. However, if the deallocation fails, the
805 -- total node count will not get decremented.
807 -- One way around this dilemma is to count the nodes in the subtree
808 -- before attempt to delete the subtree, but that is an O(n) operation,
809 -- so it does not seem worth it.
811 -- Perhaps this is much ado about nothing, since the only way
812 -- deallocation can fail is if Controlled Finalization fails: this
813 -- propagates Program_Error so all bets are off anyway. ???
817 -- Deallocate_Subtree returns a count of the number of nodes that it
818 -- deallocates, but it works by incrementing the value that is passed
819 -- in. We must therefore initialize the count value before calling
820 -- Deallocate_Subtree.
824 Deallocate_Subtree (X, Count);
825 pragma Assert (Count <= Container.Count);
827 -- See comments above. We would prefer to do this sooner, but there's no
828 -- way to satisfy that goal without a potentially severe execution
831 Container.Count := Container.Count - Count;
838 function Depth (Position : Cursor) return Count_Type is
840 N : Tree_Node_Access;
847 Result := Result + 1;
857 function Element (Position : Cursor) return Element_Type is
859 if Position.Container = null then
860 raise Constraint_Error with "Position cursor has no element";
863 if Position.Node = Root_Node (Position.Container.all) then
864 raise Program_Error with "Position cursor designates root";
867 return Position.Node.Element;
874 function Equal_Children
875 (Left_Subtree : Tree_Node_Access;
876 Right_Subtree : Tree_Node_Access) return Boolean
878 Left_Children : Children_Type renames Left_Subtree.Children;
879 Right_Children : Children_Type renames Right_Subtree.Children;
881 L, R : Tree_Node_Access;
884 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
888 L := Left_Children.First;
889 R := Right_Children.First;
891 if not Equal_Subtree (L, R) then
906 function Equal_Subtree
907 (Left_Position : Cursor;
908 Right_Position : Cursor) return Boolean
911 if Left_Position = No_Element then
912 raise Constraint_Error with "Left cursor has no element";
915 if Right_Position = No_Element then
916 raise Constraint_Error with "Right cursor has no element";
919 if Left_Position = Right_Position then
923 if Is_Root (Left_Position) then
924 if not Is_Root (Right_Position) then
928 return Equal_Children (Left_Position.Node, Right_Position.Node);
931 if Is_Root (Right_Position) then
935 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
938 function Equal_Subtree
939 (Left_Subtree : Tree_Node_Access;
940 Right_Subtree : Tree_Node_Access) return Boolean
943 if Left_Subtree.Element /= Right_Subtree.Element then
947 return Equal_Children (Left_Subtree, Right_Subtree);
954 procedure Finalize (Object : in out Root_Iterator) is
955 B : Natural renames Object.Container.Busy;
966 Item : Element_Type) return Cursor
968 N : constant Tree_Node_Access :=
969 Find_In_Children (Root_Node (Container), Item);
974 return Cursor'(Container'Unrestricted_Access, N);
982 overriding function First (Object : Subtree_Iterator) return Cursor is
984 if Object.Subtree = Root_Node (Object.Container.all) then
985 return First_Child (Root (Object.Container.all));
987 return Cursor'(Object.Container, Object.Subtree);
991 overriding function First (Object : Child_Iterator) return Cursor is
993 return First_Child (Cursor'(Object.Container, Object.Subtree));
1000 function First_Child (Parent : Cursor) return Cursor is
1001 Node : Tree_Node_Access;
1004 if Parent = No_Element then
1005 raise Constraint_Error with "Parent cursor has no element";
1008 Node := Parent.Node.Children.First;
1014 return Cursor'(Parent.Container, Node);
1017 -------------------------
1018 -- First_Child_Element --
1019 -------------------------
1021 function First_Child_Element (Parent : Cursor) return Element_Type is
1023 return Element (First_Child (Parent));
1024 end First_Child_Element;
1026 ----------------------
1027 -- Find_In_Children --
1028 ----------------------
1030 function Find_In_Children
1031 (Subtree : Tree_Node_Access;
1032 Item : Element_Type) return Tree_Node_Access
1034 N, Result : Tree_Node_Access;
1037 N := Subtree.Children.First;
1038 while N /= null loop
1039 Result := Find_In_Subtree (N, Item);
1041 if Result /= null then
1049 end Find_In_Children;
1051 ---------------------
1052 -- Find_In_Subtree --
1053 ---------------------
1055 function Find_In_Subtree
1057 Item : Element_Type) return Cursor
1059 Result : Tree_Node_Access;
1062 if Position = No_Element then
1063 raise Constraint_Error with "Position cursor has no element";
1066 -- Commented out pending official ruling by ARG. ???
1068 -- if Position.Container /= Container'Unrestricted_Access then
1069 -- raise Program_Error with "Position cursor not in container";
1073 (if Is_Root (Position)
1074 then Find_In_Children (Position.Node, Item)
1075 else Find_In_Subtree (Position.Node, Item));
1077 if Result = null then
1081 return Cursor'(Position.Container, Result);
1082 end Find_In_Subtree;
1084 function Find_In_Subtree
1085 (Subtree : Tree_Node_Access;
1086 Item : Element_Type) return Tree_Node_Access
1089 if Subtree.Element = Item then
1093 return Find_In_Children (Subtree, Item);
1094 end Find_In_Subtree;
1100 function Has_Element (Position : Cursor) return Boolean is
1102 return (if Position = No_Element then False
1103 else Position.Node.Parent /= null);
1110 procedure Insert_Child
1111 (Container : in out Tree;
1114 New_Item : Element_Type;
1115 Count : Count_Type := 1)
1118 pragma Unreferenced (Position);
1121 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1124 procedure Insert_Child
1125 (Container : in out Tree;
1128 New_Item : Element_Type;
1129 Position : out Cursor;
1130 Count : Count_Type := 1)
1132 Last : Tree_Node_Access;
1135 if Parent = No_Element then
1136 raise Constraint_Error with "Parent cursor has no element";
1139 if Parent.Container /= Container'Unrestricted_Access then
1140 raise Program_Error with "Parent cursor not in container";
1143 if Before /= No_Element then
1144 if Before.Container /= Container'Unrestricted_Access then
1145 raise Program_Error with "Before cursor not in container";
1148 if Before.Node.Parent /= Parent.Node then
1149 raise Constraint_Error with "Parent cursor not parent of Before";
1154 Position := No_Element; -- Need ruling from ARG ???
1158 if Container.Busy > 0 then
1160 with "attempt to tamper with cursors (tree is busy)";
1163 Position.Container := Parent.Container;
1164 Position.Node := new Tree_Node_Type'(Parent => Parent.Node,
1165 Element => New_Item,
1168 Last := Position.Node;
1170 for J in Count_Type'(2) .. Count loop
1172 -- Reclaim other nodes if Storage_Error. ???
1174 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1176 Element => New_Item,
1183 (First => Position.Node,
1185 Parent => Parent.Node,
1186 Before => Before.Node);
1188 -- In order for operation Node_Count to complete in O(1) time, we cache
1189 -- the count value. Here we increment the total count by the number of
1190 -- nodes we just inserted.
1192 Container.Count := Container.Count + Count;
1195 procedure Insert_Child
1196 (Container : in out Tree;
1199 Position : out Cursor;
1200 Count : Count_Type := 1)
1202 Last : Tree_Node_Access;
1205 if Parent = No_Element then
1206 raise Constraint_Error with "Parent cursor has no element";
1209 if Parent.Container /= Container'Unrestricted_Access then
1210 raise Program_Error with "Parent cursor not in container";
1213 if Before /= No_Element then
1214 if Before.Container /= Container'Unrestricted_Access then
1215 raise Program_Error with "Before cursor not in container";
1218 if Before.Node.Parent /= Parent.Node then
1219 raise Constraint_Error with "Parent cursor not parent of Before";
1224 Position := No_Element; -- Need ruling from ARG ???
1228 if Container.Busy > 0 then
1230 with "attempt to tamper with cursors (tree is busy)";
1233 Position.Container := Parent.Container;
1234 Position.Node := new Tree_Node_Type'(Parent => Parent.Node,
1238 Last := Position.Node;
1240 for J in Count_Type'(2) .. Count loop
1242 -- Reclaim other nodes if Storage_Error. ???
1244 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1253 (First => Position.Node,
1255 Parent => Parent.Node,
1256 Before => Before.Node);
1258 -- In order for operation Node_Count to complete in O(1) time, we cache
1259 -- the count value. Here we increment the total count by the number of
1260 -- nodes we just inserted.
1262 Container.Count := Container.Count + Count;
1265 -------------------------
1266 -- Insert_Subtree_List --
1267 -------------------------
1269 procedure Insert_Subtree_List
1270 (First : Tree_Node_Access;
1271 Last : Tree_Node_Access;
1272 Parent : Tree_Node_Access;
1273 Before : Tree_Node_Access)
1275 pragma Assert (Parent /= null);
1276 C : Children_Type renames Parent.Children;
1279 -- This is a simple utility operation to insert a list of nodes (from
1280 -- First..Last) as children of Parent. The Before node specifies where
1281 -- the new children should be inserted relative to the existing
1284 if First = null then
1285 pragma Assert (Last = null);
1289 pragma Assert (Last /= null);
1290 pragma Assert (Before = null or else Before.Parent = Parent);
1292 if C.First = null then
1294 C.First.Prev := null;
1296 C.Last.Next := null;
1298 elsif Before = null then -- means "insert after existing nodes"
1299 C.Last.Next := First;
1300 First.Prev := C.Last;
1302 C.Last.Next := null;
1304 elsif Before = C.First then
1305 Last.Next := C.First;
1306 C.First.Prev := Last;
1308 C.First.Prev := null;
1311 Before.Prev.Next := First;
1312 First.Prev := Before.Prev;
1313 Last.Next := Before;
1314 Before.Prev := Last;
1316 end Insert_Subtree_List;
1318 -------------------------
1319 -- Insert_Subtree_Node --
1320 -------------------------
1322 procedure Insert_Subtree_Node
1323 (Subtree : Tree_Node_Access;
1324 Parent : Tree_Node_Access;
1325 Before : Tree_Node_Access)
1328 -- This is a simple wrapper operation to insert a single child into the
1329 -- Parent's children list.
1336 end Insert_Subtree_Node;
1342 function Is_Empty (Container : Tree) return Boolean is
1344 return Container.Root.Children.First = null;
1351 function Is_Leaf (Position : Cursor) return Boolean is
1353 return (if Position = No_Element then False
1354 else Position.Node.Children.First = null);
1361 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1362 pragma Assert (From /= null);
1363 pragma Assert (To /= null);
1365 N : Tree_Node_Access;
1369 while N /= null loop
1384 function Is_Root (Position : Cursor) return Boolean is
1386 return (if Position.Container = null then False
1387 else Position = Root (Position.Container.all));
1396 Process : not null access procedure (Position : Cursor))
1398 B : Natural renames Container'Unrestricted_Access.all.Busy;
1404 (Container => Container'Unrestricted_Access,
1405 Subtree => Root_Node (Container),
1406 Process => Process);
1416 function Iterate (Container : Tree)
1417 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1420 return Iterate_Subtree (Root (Container));
1423 ----------------------
1424 -- Iterate_Children --
1425 ----------------------
1427 procedure Iterate_Children
1429 Process : not null access procedure (Position : Cursor))
1432 if Parent = No_Element then
1433 raise Constraint_Error with "Parent cursor has no element";
1437 B : Natural renames Parent.Container.Busy;
1438 C : Tree_Node_Access;
1443 C := Parent.Node.Children.First;
1444 while C /= null loop
1445 Process (Position => Cursor'(Parent.Container, Node => C));
1456 end Iterate_Children;
1458 procedure Iterate_Children
1459 (Container : Tree_Access;
1460 Subtree : Tree_Node_Access;
1461 Process : not null access procedure (Position : Cursor))
1463 Node : Tree_Node_Access;
1466 -- This is a helper function to recursively iterate over all the nodes
1467 -- in a subtree, in depth-first fashion. This particular helper just
1468 -- visits the children of this subtree, not the root of the subtree node
1469 -- itself. This is useful when starting from the ultimate root of the
1470 -- entire tree (see Iterate), as that root does not have an element.
1472 Node := Subtree.Children.First;
1473 while Node /= null loop
1474 Iterate_Subtree (Container, Node, Process);
1477 end Iterate_Children;
1479 function Iterate_Children
1482 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1484 C : constant Tree_Access := Container'Unrestricted_Access;
1485 B : Natural renames C.Busy;
1488 if Parent = No_Element then
1489 raise Constraint_Error with "Parent cursor has no element";
1492 if Parent.Container /= C then
1493 raise Program_Error with "Parent cursor not in container";
1496 return It : constant Child_Iterator :=
1497 (Limited_Controlled with
1499 Subtree => Parent.Node)
1503 end Iterate_Children;
1505 ---------------------
1506 -- Iterate_Subtree --
1507 ---------------------
1509 function Iterate_Subtree
1511 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1514 if Position = No_Element then
1515 raise Constraint_Error with "Position cursor has no element";
1518 -- Implement Vet for multiway trees???
1519 -- pragma Assert (Vet (Position), "bad subtree cursor");
1522 B : Natural renames Position.Container.Busy;
1524 return It : constant Subtree_Iterator :=
1525 (Limited_Controlled with
1526 Container => Position.Container,
1527 Subtree => Position.Node)
1532 end Iterate_Subtree;
1534 procedure Iterate_Subtree
1536 Process : not null access procedure (Position : Cursor))
1539 if Position = No_Element then
1540 raise Constraint_Error with "Position cursor has no element";
1544 B : Natural renames Position.Container.Busy;
1549 if Is_Root (Position) then
1550 Iterate_Children (Position.Container, Position.Node, Process);
1552 Iterate_Subtree (Position.Container, Position.Node, Process);
1562 end Iterate_Subtree;
1564 procedure Iterate_Subtree
1565 (Container : Tree_Access;
1566 Subtree : Tree_Node_Access;
1567 Process : not null access procedure (Position : Cursor))
1570 -- This is a helper function to recursively iterate over all the nodes
1571 -- in a subtree, in depth-first fashion. It first visits the root of the
1572 -- subtree, then visits its children.
1574 Process (Cursor'(Container, Subtree));
1575 Iterate_Children (Container, Subtree, Process);
1576 end Iterate_Subtree;
1582 overriding function Last (Object : Child_Iterator) return Cursor is
1584 return Last_Child (Cursor'(Object.Container, Object.Subtree));
1591 function Last_Child (Parent : Cursor) return Cursor is
1592 Node : Tree_Node_Access;
1595 if Parent = No_Element then
1596 raise Constraint_Error with "Parent cursor has no element";
1599 Node := Parent.Node.Children.Last;
1605 return (Parent.Container, Node);
1608 ------------------------
1609 -- Last_Child_Element --
1610 ------------------------
1612 function Last_Child_Element (Parent : Cursor) return Element_Type is
1614 return Element (Last_Child (Parent));
1615 end Last_Child_Element;
1621 procedure Move (Target : in out Tree; Source : in out Tree) is
1622 Node : Tree_Node_Access;
1625 if Target'Address = Source'Address then
1629 if Source.Busy > 0 then
1631 with "attempt to tamper with cursors of Source (tree is busy)";
1634 Target.Clear; -- checks busy bit
1636 Target.Root.Children := Source.Root.Children;
1637 Source.Root.Children := Children_Type'(others => null);
1639 Node := Target.Root.Children.First;
1640 while Node /= null loop
1641 Node.Parent := Root_Node (Target);
1645 Target.Count := Source.Count;
1654 (Object : Subtree_Iterator;
1655 Position : Cursor) return Cursor
1657 Node : Tree_Node_Access;
1660 if Position.Container = null then
1664 if Position.Container /= Object.Container then
1665 raise Program_Error with
1666 "Position cursor of Next designates wrong tree";
1669 Node := Position.Node;
1671 if Node.Children.First /= null then
1672 return Cursor'(Object.Container, Node.Children.First);
1675 while Node /= Object.Subtree loop
1676 if Node.Next /= null then
1677 return Cursor'(Object.Container, Node.Next);
1680 Node := Node.Parent;
1687 (Object : Child_Iterator;
1688 Position : Cursor) return Cursor
1691 if Position.Container = null then
1695 if Position.Container /= Object.Container then
1696 raise Program_Error with
1697 "Position cursor of Next designates wrong tree";
1700 return Next_Sibling (Position);
1707 function Next_Sibling (Position : Cursor) return Cursor is
1709 if Position = No_Element then
1713 if Position.Node.Next = null then
1717 return Cursor'(Position.Container, Position.Node.Next);
1720 procedure Next_Sibling (Position : in out Cursor) is
1722 Position := Next_Sibling (Position);
1729 function Node_Count (Container : Tree) return Count_Type is
1731 -- Container.Count is the number of nodes we have actually allocated. We
1732 -- cache the value specifically so this Node_Count operation can execute
1733 -- in O(1) time, which makes it behave similarly to how the Length
1734 -- selector function behaves for other containers.
1736 -- The cached node count value only describes the nodes we have
1737 -- allocated; the root node itself is not included in that count. The
1738 -- Node_Count operation returns a value that includes the root node
1739 -- (because the RM says so), so we must add 1 to our cached value.
1741 return 1 + Container.Count;
1748 function Parent (Position : Cursor) return Cursor is
1750 if Position = No_Element then
1754 if Position.Node.Parent = null then
1758 return Cursor'(Position.Container, Position.Node.Parent);
1765 procedure Prepend_Child
1766 (Container : in out Tree;
1768 New_Item : Element_Type;
1769 Count : Count_Type := 1)
1771 First, Last : Tree_Node_Access;
1774 if Parent = No_Element then
1775 raise Constraint_Error with "Parent cursor has no element";
1778 if Parent.Container /= Container'Unrestricted_Access then
1779 raise Program_Error with "Parent cursor not in container";
1786 if Container.Busy > 0 then
1788 with "attempt to tamper with cursors (tree is busy)";
1791 First := new Tree_Node_Type'(Parent => Parent.Node,
1792 Element => New_Item,
1797 for J in Count_Type'(2) .. Count loop
1799 -- Reclaim other nodes if Storage_Error???
1801 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1803 Element => New_Item,
1812 Parent => Parent.Node,
1813 Before => Parent.Node.Children.First);
1815 -- In order for operation Node_Count to complete in O(1) time, we cache
1816 -- the count value. Here we increment the total count by the number of
1817 -- nodes we just inserted.
1819 Container.Count := Container.Count + Count;
1826 overriding function Previous
1827 (Object : Child_Iterator;
1828 Position : Cursor) return Cursor
1831 if Position.Container = null then
1835 if Position.Container /= Object.Container then
1836 raise Program_Error with
1837 "Position cursor of Previous designates wrong tree";
1840 return Previous_Sibling (Position);
1843 ----------------------
1844 -- Previous_Sibling --
1845 ----------------------
1847 function Previous_Sibling (Position : Cursor) return Cursor is
1850 (if Position = No_Element then No_Element
1851 elsif Position.Node.Prev = null then No_Element
1852 else Cursor'(Position.Container, Position.Node.Prev));
1853 end Previous_Sibling;
1855 procedure Previous_Sibling (Position : in out Cursor) is
1857 Position := Previous_Sibling (Position);
1858 end Previous_Sibling;
1864 procedure Query_Element
1866 Process : not null access procedure (Element : Element_Type))
1869 if Position = No_Element then
1870 raise Constraint_Error with "Position cursor has no element";
1873 if Is_Root (Position) then
1874 raise Program_Error with "Position cursor designates root";
1878 T : Tree renames Position.Container.all'Unrestricted_Access.all;
1879 B : Natural renames T.Busy;
1880 L : Natural renames T.Lock;
1886 Process (Position.Node.Element);
1904 (Stream : not null access Root_Stream_Type'Class;
1905 Container : out Tree)
1907 procedure Read_Children (Subtree : Tree_Node_Access);
1909 function Read_Subtree
1910 (Parent : Tree_Node_Access) return Tree_Node_Access;
1912 Total_Count : Count_Type'Base;
1913 -- Value read from the stream that says how many elements follow
1915 Read_Count : Count_Type'Base;
1916 -- Actual number of elements read from the stream
1922 procedure Read_Children (Subtree : Tree_Node_Access) is
1923 pragma Assert (Subtree /= null);
1924 pragma Assert (Subtree.Children.First = null);
1925 pragma Assert (Subtree.Children.Last = null);
1927 Count : Count_Type'Base;
1928 -- Number of child subtrees
1933 Count_Type'Read (Stream, Count);
1936 raise Program_Error with "attempt to read from corrupt stream";
1943 C.First := Read_Subtree (Parent => Subtree);
1946 for J in Count_Type'(2) .. Count loop
1947 C.Last.Next := Read_Subtree (Parent => Subtree);
1948 C.Last.Next.Prev := C.Last;
1949 C.Last := C.Last.Next;
1952 -- Now that the allocation and reads have completed successfully, it
1953 -- is safe to link the children to their parent.
1955 Subtree.Children := C;
1962 function Read_Subtree
1963 (Parent : Tree_Node_Access) return Tree_Node_Access
1965 Subtree : constant Tree_Node_Access :=
1968 Element => Element_Type'Input (Stream),
1972 Read_Count := Read_Count + 1;
1974 Read_Children (Subtree);
1979 -- Start of processing for Read
1982 Container.Clear; -- checks busy bit
1984 Count_Type'Read (Stream, Total_Count);
1986 if Total_Count < 0 then
1987 raise Program_Error with "attempt to read from corrupt stream";
1990 if Total_Count = 0 then
1996 Read_Children (Root_Node (Container));
1998 if Read_Count /= Total_Count then
1999 raise Program_Error with "attempt to read from corrupt stream";
2002 Container.Count := Total_Count;
2006 (Stream : not null access Root_Stream_Type'Class;
2007 Position : out Cursor)
2010 raise Program_Error with "attempt to read tree cursor from stream";
2014 (Stream : not null access Root_Stream_Type'Class;
2015 Item : out Reference_Type)
2018 raise Program_Error with "attempt to stream reference";
2022 (Stream : not null access Root_Stream_Type'Class;
2023 Item : out Constant_Reference_Type)
2026 raise Program_Error with "attempt to stream reference";
2034 (Container : aliased in out Tree;
2035 Position : Cursor) return Reference_Type
2038 if Position.Container = null then
2039 raise Constraint_Error with
2040 "Position cursor has no element";
2043 if Position.Container /= Container'Unrestricted_Access then
2044 raise Program_Error with
2045 "Position cursor designates wrong container";
2048 if Position.Node = Root_Node (Container) then
2049 raise Program_Error with "Position cursor designates root";
2052 -- Implement Vet for multiway tree???
2053 -- pragma Assert (Vet (Position),
2054 -- "Position cursor in Constant_Reference is bad");
2056 return (Element => Position.Node.Element'Access);
2059 --------------------
2060 -- Remove_Subtree --
2061 --------------------
2063 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2064 C : Children_Type renames Subtree.Parent.Children;
2067 -- This is a utility operation to remove a subtree node from its
2068 -- parent's list of children.
2070 if C.First = Subtree then
2071 pragma Assert (Subtree.Prev = null);
2073 if C.Last = Subtree then
2074 pragma Assert (Subtree.Next = null);
2079 C.First := Subtree.Next;
2080 C.First.Prev := null;
2083 elsif C.Last = Subtree then
2084 pragma Assert (Subtree.Next = null);
2085 C.Last := Subtree.Prev;
2086 C.Last.Next := null;
2089 Subtree.Prev.Next := Subtree.Next;
2090 Subtree.Next.Prev := Subtree.Prev;
2094 ----------------------
2095 -- Replace_Element --
2096 ----------------------
2098 procedure Replace_Element
2099 (Container : in out Tree;
2101 New_Item : Element_Type)
2104 if Position = No_Element then
2105 raise Constraint_Error with "Position cursor has no element";
2108 if Position.Container /= Container'Unrestricted_Access then
2109 raise Program_Error with "Position cursor not in container";
2112 if Is_Root (Position) then
2113 raise Program_Error with "Position cursor designates root";
2116 if Container.Lock > 0 then
2118 with "attempt to tamper with elements (tree is locked)";
2121 Position.Node.Element := New_Item;
2122 end Replace_Element;
2124 ------------------------------
2125 -- Reverse_Iterate_Children --
2126 ------------------------------
2128 procedure Reverse_Iterate_Children
2130 Process : not null access procedure (Position : Cursor))
2133 if Parent = No_Element then
2134 raise Constraint_Error with "Parent cursor has no element";
2138 B : Natural renames Parent.Container.Busy;
2139 C : Tree_Node_Access;
2144 C := Parent.Node.Children.Last;
2145 while C /= null loop
2146 Process (Position => Cursor'(Parent.Container, Node => C));
2157 end Reverse_Iterate_Children;
2163 function Root (Container : Tree) return Cursor is
2165 return (Container'Unrestricted_Access, Root_Node (Container));
2172 function Root_Node (Container : Tree) return Tree_Node_Access is
2173 type Root_Node_Access is access all Root_Node_Type;
2174 for Root_Node_Access'Storage_Size use 0;
2175 pragma Convention (C, Root_Node_Access);
2177 function To_Tree_Node_Access is
2178 new Ada.Unchecked_Conversion (Root_Node_Access, Tree_Node_Access);
2180 -- Start of processing for Root_Node
2183 -- This is a utility function for converting from an access type that
2184 -- designates the distinguished root node to an access type designating
2185 -- a non-root node. The representation of a root node does not have an
2186 -- element, but is otherwise identical to a non-root node, so the
2187 -- conversion itself is safe.
2189 return To_Tree_Node_Access (Container.Root'Unrestricted_Access);
2192 ---------------------
2193 -- Splice_Children --
2194 ---------------------
2196 procedure Splice_Children
2197 (Target : in out Tree;
2198 Target_Parent : Cursor;
2200 Source : in out Tree;
2201 Source_Parent : Cursor)
2206 if Target_Parent = No_Element then
2207 raise Constraint_Error with "Target_Parent cursor has no element";
2210 if Target_Parent.Container /= Target'Unrestricted_Access then
2212 with "Target_Parent cursor not in Target container";
2215 if Before /= No_Element then
2216 if Before.Container /= Target'Unrestricted_Access then
2218 with "Before cursor not in Target container";
2221 if Before.Node.Parent /= Target_Parent.Node then
2222 raise Constraint_Error
2223 with "Before cursor not child of Target_Parent";
2227 if Source_Parent = No_Element then
2228 raise Constraint_Error with "Source_Parent cursor has no element";
2231 if Source_Parent.Container /= Source'Unrestricted_Access then
2233 with "Source_Parent cursor not in Source container";
2236 if Target'Address = Source'Address then
2237 if Target_Parent = Source_Parent then
2241 if Target.Busy > 0 then
2243 with "attempt to tamper with cursors (Target tree is busy)";
2246 if Is_Reachable (From => Target_Parent.Node,
2247 To => Source_Parent.Node)
2249 raise Constraint_Error
2250 with "Source_Parent is ancestor of Target_Parent";
2254 (Target_Parent => Target_Parent.Node,
2255 Before => Before.Node,
2256 Source_Parent => Source_Parent.Node);
2261 if Target.Busy > 0 then
2263 with "attempt to tamper with cursors (Target tree is busy)";
2266 if Source.Busy > 0 then
2268 with "attempt to tamper with cursors (Source tree is busy)";
2271 -- We cache the count of the nodes we have allocated, so that operation
2272 -- Node_Count can execute in O(1) time. But that means we must count the
2273 -- nodes in the subtree we remove from Source and insert into Target, in
2274 -- order to keep the count accurate.
2276 Count := Subtree_Node_Count (Source_Parent.Node);
2277 pragma Assert (Count >= 1);
2279 Count := Count - 1; -- because Source_Parent node does not move
2282 (Target_Parent => Target_Parent.Node,
2283 Before => Before.Node,
2284 Source_Parent => Source_Parent.Node);
2286 Source.Count := Source.Count - Count;
2287 Target.Count := Target.Count + Count;
2288 end Splice_Children;
2290 procedure Splice_Children
2291 (Container : in out Tree;
2292 Target_Parent : Cursor;
2294 Source_Parent : Cursor)
2297 if Target_Parent = No_Element then
2298 raise Constraint_Error with "Target_Parent cursor has no element";
2301 if Target_Parent.Container /= Container'Unrestricted_Access then
2303 with "Target_Parent cursor not in container";
2306 if Before /= No_Element then
2307 if Before.Container /= Container'Unrestricted_Access then
2309 with "Before cursor not in container";
2312 if Before.Node.Parent /= Target_Parent.Node then
2313 raise Constraint_Error
2314 with "Before cursor not child of Target_Parent";
2318 if Source_Parent = No_Element then
2319 raise Constraint_Error with "Source_Parent cursor has no element";
2322 if Source_Parent.Container /= Container'Unrestricted_Access then
2324 with "Source_Parent cursor not in container";
2327 if Target_Parent = Source_Parent then
2331 if Container.Busy > 0 then
2333 with "attempt to tamper with cursors (tree is busy)";
2336 if Is_Reachable (From => Target_Parent.Node,
2337 To => Source_Parent.Node)
2339 raise Constraint_Error
2340 with "Source_Parent is ancestor of Target_Parent";
2344 (Target_Parent => Target_Parent.Node,
2345 Before => Before.Node,
2346 Source_Parent => Source_Parent.Node);
2347 end Splice_Children;
2349 procedure Splice_Children
2350 (Target_Parent : Tree_Node_Access;
2351 Before : Tree_Node_Access;
2352 Source_Parent : Tree_Node_Access)
2354 CC : constant Children_Type := Source_Parent.Children;
2355 C : Tree_Node_Access;
2358 -- This is a utility operation to remove the children from
2359 -- Source parent and insert them into Target parent.
2361 Source_Parent.Children := Children_Type'(others => null);
2363 -- Fix up the Parent pointers of each child to designate
2364 -- its new Target parent.
2367 while C /= null loop
2368 C.Parent := Target_Parent;
2375 Parent => Target_Parent,
2377 end Splice_Children;
2379 --------------------
2380 -- Splice_Subtree --
2381 --------------------
2383 procedure Splice_Subtree
2384 (Target : in out Tree;
2387 Source : in out Tree;
2388 Position : in out Cursor)
2390 Subtree_Count : Count_Type;
2393 if Parent = No_Element then
2394 raise Constraint_Error with "Parent cursor has no element";
2397 if Parent.Container /= Target'Unrestricted_Access then
2398 raise Program_Error with "Parent cursor not in Target container";
2401 if Before /= No_Element then
2402 if Before.Container /= Target'Unrestricted_Access then
2403 raise Program_Error with "Before cursor not in Target container";
2406 if Before.Node.Parent /= Parent.Node then
2407 raise Constraint_Error with "Before cursor not child of Parent";
2411 if Position = No_Element then
2412 raise Constraint_Error with "Position cursor has no element";
2415 if Position.Container /= Source'Unrestricted_Access then
2416 raise Program_Error with "Position cursor not in Source container";
2419 if Is_Root (Position) then
2420 raise Program_Error with "Position cursor designates root";
2423 if Target'Address = Source'Address then
2424 if Position.Node.Parent = Parent.Node then
2425 if Position.Node = Before.Node then
2429 if Position.Node.Next = Before.Node then
2434 if Target.Busy > 0 then
2436 with "attempt to tamper with cursors (Target tree is busy)";
2439 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2440 raise Constraint_Error with "Position is ancestor of Parent";
2443 Remove_Subtree (Position.Node);
2445 Position.Node.Parent := Parent.Node;
2446 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2451 if Target.Busy > 0 then
2453 with "attempt to tamper with cursors (Target tree is busy)";
2456 if Source.Busy > 0 then
2458 with "attempt to tamper with cursors (Source tree is busy)";
2461 -- This is an unfortunate feature of this API: we must count the nodes
2462 -- in the subtree that we remove from the source tree, which is an O(n)
2463 -- operation. It would have been better if the Tree container did not
2464 -- have a Node_Count selector; a user that wants the number of nodes in
2465 -- the tree could simply call Subtree_Node_Count, with the understanding
2466 -- that such an operation is O(n).
2468 -- Of course, we could choose to implement the Node_Count selector as an
2469 -- O(n) operation, which would turn this splice operation into an O(1)
2472 Subtree_Count := Subtree_Node_Count (Position.Node);
2473 pragma Assert (Subtree_Count <= Source.Count);
2475 Remove_Subtree (Position.Node);
2476 Source.Count := Source.Count - Subtree_Count;
2478 Position.Node.Parent := Parent.Node;
2479 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2481 Target.Count := Target.Count + Subtree_Count;
2483 Position.Container := Target'Unrestricted_Access;
2486 procedure Splice_Subtree
2487 (Container : in out Tree;
2493 if Parent = No_Element then
2494 raise Constraint_Error with "Parent cursor has no element";
2497 if Parent.Container /= Container'Unrestricted_Access then
2498 raise Program_Error with "Parent cursor not in container";
2501 if Before /= No_Element then
2502 if Before.Container /= Container'Unrestricted_Access then
2503 raise Program_Error with "Before cursor not in container";
2506 if Before.Node.Parent /= Parent.Node then
2507 raise Constraint_Error with "Before cursor not child of Parent";
2511 if Position = No_Element then
2512 raise Constraint_Error with "Position cursor has no element";
2515 if Position.Container /= Container'Unrestricted_Access then
2516 raise Program_Error with "Position cursor not in container";
2519 if Is_Root (Position) then
2521 -- Should this be PE instead? Need ARG confirmation. ???
2523 raise Constraint_Error with "Position cursor designates root";
2526 if Position.Node.Parent = Parent.Node then
2527 if Position.Node = Before.Node then
2531 if Position.Node.Next = Before.Node then
2536 if Container.Busy > 0 then
2538 with "attempt to tamper with cursors (tree is busy)";
2541 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2542 raise Constraint_Error with "Position is ancestor of Parent";
2545 Remove_Subtree (Position.Node);
2547 Position.Node.Parent := Parent.Node;
2548 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2551 ------------------------
2552 -- Subtree_Node_Count --
2553 ------------------------
2555 function Subtree_Node_Count (Position : Cursor) return Count_Type is
2557 if Position = No_Element then
2561 return Subtree_Node_Count (Position.Node);
2562 end Subtree_Node_Count;
2564 function Subtree_Node_Count
2565 (Subtree : Tree_Node_Access) return Count_Type
2567 Result : Count_Type;
2568 Node : Tree_Node_Access;
2572 Node := Subtree.Children.First;
2573 while Node /= null loop
2574 Result := Result + Subtree_Node_Count (Node);
2579 end Subtree_Node_Count;
2586 (Container : in out Tree;
2590 if I = No_Element then
2591 raise Constraint_Error with "I cursor has no element";
2594 if I.Container /= Container'Unrestricted_Access then
2595 raise Program_Error with "I cursor not in container";
2599 raise Program_Error with "I cursor designates root";
2602 if I = J then -- make this test sooner???
2606 if J = No_Element then
2607 raise Constraint_Error with "J cursor has no element";
2610 if J.Container /= Container'Unrestricted_Access then
2611 raise Program_Error with "J cursor not in container";
2615 raise Program_Error with "J cursor designates root";
2618 if Container.Lock > 0 then
2620 with "attempt to tamper with elements (tree is locked)";
2624 EI : constant Element_Type := I.Node.Element;
2627 I.Node.Element := J.Node.Element;
2628 J.Node.Element := EI;
2632 --------------------
2633 -- Update_Element --
2634 --------------------
2636 procedure Update_Element
2637 (Container : in out Tree;
2639 Process : not null access procedure (Element : in out Element_Type))
2642 if Position = No_Element then
2643 raise Constraint_Error with "Position cursor has no element";
2646 if Position.Container /= Container'Unrestricted_Access then
2647 raise Program_Error with "Position cursor not in container";
2650 if Is_Root (Position) then
2651 raise Program_Error with "Position cursor designates root";
2655 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2656 B : Natural renames T.Busy;
2657 L : Natural renames T.Lock;
2663 Process (Position.Node.Element);
2681 (Stream : not null access Root_Stream_Type'Class;
2684 procedure Write_Children (Subtree : Tree_Node_Access);
2685 procedure Write_Subtree (Subtree : Tree_Node_Access);
2687 --------------------
2688 -- Write_Children --
2689 --------------------
2691 procedure Write_Children (Subtree : Tree_Node_Access) is
2692 CC : Children_Type renames Subtree.Children;
2693 C : Tree_Node_Access;
2696 Count_Type'Write (Stream, Child_Count (CC));
2699 while C /= null loop
2709 procedure Write_Subtree (Subtree : Tree_Node_Access) is
2711 Element_Type'Output (Stream, Subtree.Element);
2712 Write_Children (Subtree);
2715 -- Start of processing for Write
2718 Count_Type'Write (Stream, Container.Count);
2720 if Container.Count = 0 then
2724 Write_Children (Root_Node (Container));
2728 (Stream : not null access Root_Stream_Type'Class;
2732 raise Program_Error with "attempt to write tree cursor to stream";
2736 (Stream : not null access Root_Stream_Type'Class;
2737 Item : Reference_Type)
2740 raise Program_Error with "attempt to stream reference";
2744 (Stream : not null access Root_Stream_Type'Class;
2745 Item : Constant_Reference_Type)
2748 raise Program_Error with "attempt to stream reference";
2751 end Ada.Containers.Multiway_Trees;