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-2014, 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;
209 procedure Adjust (Control : in out Reference_Control_Type) is
211 if Control.Container /= null then
213 C : Tree renames Control.Container.all;
214 B : Natural renames C.Busy;
215 L : Natural renames C.Lock;
227 function Ancestor_Find
229 Item : Element_Type) return Cursor
231 R, N : Tree_Node_Access;
234 if Position = No_Element then
235 raise Constraint_Error with "Position cursor has no element";
238 -- Commented-out pending official ruling from ARG. ???
240 -- if Position.Container /= Container'Unrestricted_Access then
241 -- raise Program_Error with "Position cursor not in container";
244 -- AI-0136 says to raise PE if Position equals the root node. This does
245 -- not seem correct, as this value is just the limiting condition of the
246 -- search. For now we omit this check, pending a ruling from the ARG.???
248 -- if Is_Root (Position) then
249 -- raise Program_Error with "Position cursor designates root";
252 R := Root_Node (Position.Container.all);
255 if N.Element = Item then
256 return Cursor'(Position
.Container
, N
);
269 procedure Append_Child
270 (Container
: in out Tree
;
272 New_Item
: Element_Type
;
273 Count
: Count_Type
:= 1)
275 First
: Tree_Node_Access
;
276 Last
: Tree_Node_Access
;
279 if Parent
= No_Element
then
280 raise Constraint_Error
with "Parent cursor has no element";
283 if Parent
.Container
/= Container
'Unrestricted_Access then
284 raise Program_Error
with "Parent cursor not in container";
291 if Container
.Busy
> 0 then
293 with "attempt to tamper with cursors (tree is busy)";
296 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
301 for J in Count_Type'(2) .. Count
loop
303 -- Reclaim other nodes if Storage_Error. ???
305 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
316 Parent => Parent.Node,
317 Before => null); -- null means "insert at end of list"
319 -- In order for operation Node_Count to complete in O(1) time, we cache
320 -- the count value. Here we increment the total count by the number of
321 -- nodes we just inserted.
323 Container.Count := Container.Count + Count;
330 procedure Assign (Target : in out Tree; Source : Tree) is
331 Source_Count : constant Count_Type := Source.Count;
332 Target_Count : Count_Type;
335 if Target'Address = Source'Address then
339 Target.Clear; -- checks busy bit
341 -- Copy_Children returns the number of nodes that it allocates, but it
342 -- does this by incrementing the count value passed in, so we must
343 -- initialize the count before calling Copy_Children.
347 -- Note that Copy_Children inserts the newly-allocated children into
348 -- their parent list only after the allocation of all the children has
349 -- succeeded. This preserves invariants even if the allocation fails.
351 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
352 pragma Assert (Target_Count = Source_Count);
354 Target.Count := Source_Count;
361 function Child_Count (Parent : Cursor) return Count_Type is
363 return (if Parent = No_Element
364 then 0 else Child_Count (Parent.Node.Children));
367 function Child_Count (Children : Children_Type) return Count_Type is
369 Node : Tree_Node_Access;
373 Node := Children.First;
374 while Node /= null loop
375 Result := Result + 1;
386 function Child_Depth (Parent, Child : Cursor) return Count_Type is
388 N : Tree_Node_Access;
391 if Parent = No_Element then
392 raise Constraint_Error with "Parent cursor has no element";
395 if Child = No_Element then
396 raise Constraint_Error with "Child cursor has no element";
399 if Parent.Container /= Child.Container then
400 raise Program_Error with "Parent and Child in different containers";
405 while N /= Parent.Node loop
406 Result := Result + 1;
410 raise Program_Error with "Parent is not ancestor of Child";
421 procedure Clear (Container : in out Tree) is
422 Container_Count, Children_Count : Count_Type;
425 if Container.Busy > 0 then
427 with "attempt to tamper with cursors (tree is busy)";
430 -- We first set the container count to 0, in order to preserve
431 -- invariants in case the deallocation fails. (This works because
432 -- Deallocate_Children immediately removes the children from their
433 -- parent, and then does the actual deallocation.)
435 Container_Count := Container.Count;
436 Container.Count := 0;
438 -- Deallocate_Children returns the number of nodes that it deallocates,
439 -- but it does this by incrementing the count value that is passed in,
440 -- so we must first initialize the count return value before calling it.
444 -- See comment above. Deallocate_Children immediately removes the
445 -- children list from their parent node (here, the root of the tree),
446 -- and only after that does it attempt the actual deallocation. So even
447 -- if the deallocation fails, the representation invariants for the tree
450 Deallocate_Children (Root_Node (Container), Children_Count);
451 pragma Assert (Children_Count = Container_Count);
454 ------------------------
455 -- Constant_Reference --
456 ------------------------
458 function Constant_Reference
459 (Container : aliased Tree;
460 Position : Cursor) return Constant_Reference_Type
463 if Position.Container = null then
464 raise Constraint_Error with
465 "Position cursor has no element";
468 if Position.Container /= Container'Unrestricted_Access then
469 raise Program_Error with
470 "Position cursor designates wrong container";
473 if Position.Node = Root_Node (Container) then
474 raise Program_Error with "Position cursor designates root";
477 -- Implement Vet for multiway tree???
478 -- pragma Assert (Vet (Position),
479 -- "Position cursor in Constant_Reference is bad");
482 C : Tree renames Position.Container.all;
483 B : Natural renames C.Busy;
484 L : Natural renames C.Lock;
486 return R : constant Constant_Reference_Type :=
487 (Element => Position.Node.Element'Access,
488 Control => (Controlled with Container'Unrestricted_Access))
494 end Constant_Reference;
502 Item : Element_Type) return Boolean
505 return Find (Container, Item) /= No_Element;
512 function Copy (Source : Tree) return Tree is
514 return Target : Tree do
516 (Source => Source.Root.Children,
517 Parent => Root_Node (Target),
518 Count => Target.Count);
520 pragma Assert (Target.Count = Source.Count);
528 procedure Copy_Children
529 (Source : Children_Type;
530 Parent : Tree_Node_Access;
531 Count : in out Count_Type)
533 pragma Assert (Parent /= null);
534 pragma Assert (Parent.Children.First = null);
535 pragma Assert (Parent.Children.Last = null);
538 C : Tree_Node_Access;
541 -- We special-case the first allocation, in order to establish the
542 -- representation invariants for type Children_Type.
558 -- The representation invariants for the Children_Type list have been
559 -- established, so we can now copy the remaining children of Source.
566 Target => CC.Last.Next,
569 CC.Last.Next.Prev := CC.Last;
570 CC.Last := CC.Last.Next;
575 -- Add the newly-allocated children to their parent list only after the
576 -- allocation has succeeded, so as to preserve invariants of the parent.
578 Parent.Children := CC;
585 procedure Copy_Subtree
586 (Target : in out Tree;
591 Target_Subtree : Tree_Node_Access;
592 Target_Count : Count_Type;
595 if Parent = No_Element then
596 raise Constraint_Error with "Parent cursor has no element";
599 if Parent.Container /= Target'Unrestricted_Access then
600 raise Program_Error with "Parent cursor not in container";
603 if Before /= No_Element then
604 if Before.Container /= Target'Unrestricted_Access then
605 raise Program_Error with "Before cursor not in container";
608 if Before.Node.Parent /= Parent.Node then
609 raise Constraint_Error with "Before cursor not child of Parent";
613 if Source = No_Element then
617 if Is_Root (Source) then
618 raise Constraint_Error with "Source cursor designates root";
621 -- Copy_Subtree returns a count of the number of nodes that it
622 -- allocates, but it works by incrementing the value that is passed
623 -- in. We must therefore initialize the count value before calling
629 (Source => Source.Node,
630 Parent => Parent.Node,
631 Target => Target_Subtree,
632 Count => Target_Count);
634 pragma Assert (Target_Subtree /= null);
635 pragma Assert (Target_Subtree.Parent = Parent.Node);
636 pragma Assert (Target_Count >= 1);
639 (Subtree => Target_Subtree,
640 Parent => Parent.Node,
641 Before => Before.Node);
643 -- In order for operation Node_Count to complete in O(1) time, we cache
644 -- the count value. Here we increment the total count by the number of
645 -- nodes we just inserted.
647 Target.Count := Target.Count + Target_Count;
650 procedure Copy_Subtree
651 (Source : Tree_Node_Access;
652 Parent : Tree_Node_Access;
653 Target : out Tree_Node_Access;
654 Count : in out Count_Type)
657 Target := new Tree_Node_Type'(Element
=> Source
.Element
,
664 (Source
=> Source
.Children
,
669 -------------------------
670 -- Deallocate_Children --
671 -------------------------
673 procedure Deallocate_Children
674 (Subtree
: Tree_Node_Access
;
675 Count
: in out Count_Type
)
677 pragma Assert
(Subtree
/= null);
679 CC
: Children_Type
:= Subtree
.Children
;
680 C
: Tree_Node_Access
;
683 -- We immediately remove the children from their parent, in order to
684 -- preserve invariants in case the deallocation fails.
686 Subtree
.Children
:= Children_Type
'(others => null);
688 while CC.First /= null loop
692 Deallocate_Subtree (C, Count);
694 end Deallocate_Children;
696 ------------------------
697 -- Deallocate_Subtree --
698 ------------------------
700 procedure Deallocate_Subtree
701 (Subtree : in out Tree_Node_Access;
702 Count : in out Count_Type)
705 Deallocate_Children (Subtree, Count);
706 Deallocate_Node (Subtree);
708 end Deallocate_Subtree;
710 ---------------------
711 -- Delete_Children --
712 ---------------------
714 procedure Delete_Children
715 (Container : in out Tree;
721 if Parent = No_Element then
722 raise Constraint_Error with "Parent cursor has no element";
725 if Parent.Container /= Container'Unrestricted_Access then
726 raise Program_Error with "Parent cursor not in container";
729 if Container.Busy > 0 then
731 with "attempt to tamper with cursors (tree is busy)";
734 -- Deallocate_Children returns a count of the number of nodes that it
735 -- deallocates, but it works by incrementing the value that is passed
736 -- in. We must therefore initialize the count value before calling
737 -- Deallocate_Children.
741 Deallocate_Children (Parent.Node, Count);
742 pragma Assert (Count <= Container.Count);
744 Container.Count := Container.Count - Count;
751 procedure Delete_Leaf
752 (Container : in out Tree;
753 Position : in out Cursor)
755 X : Tree_Node_Access;
758 if Position = No_Element then
759 raise Constraint_Error with "Position cursor has no element";
762 if Position.Container /= Container'Unrestricted_Access then
763 raise Program_Error with "Position cursor not in container";
766 if Is_Root (Position) then
767 raise Program_Error with "Position cursor designates root";
770 if not Is_Leaf (Position) then
771 raise Constraint_Error with "Position cursor does not designate leaf";
774 if Container.Busy > 0 then
776 with "attempt to tamper with cursors (tree is busy)";
780 Position := No_Element;
782 -- Restore represention invariants before attempting the actual
786 Container.Count := Container.Count - 1;
788 -- It is now safe to attempt the deallocation. This leaf node has been
789 -- disassociated from the tree, so even if the deallocation fails,
790 -- representation invariants will remain satisfied.
799 procedure Delete_Subtree
800 (Container : in out Tree;
801 Position : in out Cursor)
803 X : Tree_Node_Access;
807 if Position = No_Element then
808 raise Constraint_Error with "Position cursor has no element";
811 if Position.Container /= Container'Unrestricted_Access then
812 raise Program_Error with "Position cursor not in container";
815 if Is_Root (Position) then
816 raise Program_Error with "Position cursor designates root";
819 if Container.Busy > 0 then
821 with "attempt to tamper with cursors (tree is busy)";
825 Position := No_Element;
827 -- Here is one case where a deallocation failure can result in the
828 -- violation of a representation invariant. We disassociate the subtree
829 -- from the tree now, but we only decrement the total node count after
830 -- we attempt the deallocation. However, if the deallocation fails, the
831 -- total node count will not get decremented.
833 -- One way around this dilemma is to count the nodes in the subtree
834 -- before attempt to delete the subtree, but that is an O(n) operation,
835 -- so it does not seem worth it.
837 -- Perhaps this is much ado about nothing, since the only way
838 -- deallocation can fail is if Controlled Finalization fails: this
839 -- propagates Program_Error so all bets are off anyway. ???
843 -- Deallocate_Subtree returns a count of the number of nodes that it
844 -- deallocates, but it works by incrementing the value that is passed
845 -- in. We must therefore initialize the count value before calling
846 -- Deallocate_Subtree.
850 Deallocate_Subtree (X, Count);
851 pragma Assert (Count <= Container.Count);
853 -- See comments above. We would prefer to do this sooner, but there's no
854 -- way to satisfy that goal without a potentially severe execution
857 Container.Count := Container.Count - Count;
864 function Depth (Position : Cursor) return Count_Type is
866 N : Tree_Node_Access;
873 Result := Result + 1;
883 function Element (Position : Cursor) return Element_Type is
885 if Position.Container = null then
886 raise Constraint_Error with "Position cursor has no element";
889 if Position.Node = Root_Node (Position.Container.all) then
890 raise Program_Error with "Position cursor designates root";
893 return Position.Node.Element;
900 function Equal_Children
901 (Left_Subtree : Tree_Node_Access;
902 Right_Subtree : Tree_Node_Access) return Boolean
904 Left_Children : Children_Type renames Left_Subtree.Children;
905 Right_Children : Children_Type renames Right_Subtree.Children;
907 L, R : Tree_Node_Access;
910 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
914 L := Left_Children.First;
915 R := Right_Children.First;
917 if not Equal_Subtree (L, R) then
932 function Equal_Subtree
933 (Left_Position : Cursor;
934 Right_Position : Cursor) return Boolean
937 if Left_Position = No_Element then
938 raise Constraint_Error with "Left cursor has no element";
941 if Right_Position = No_Element then
942 raise Constraint_Error with "Right cursor has no element";
945 if Left_Position = Right_Position then
949 if Is_Root (Left_Position) then
950 if not Is_Root (Right_Position) then
954 return Equal_Children (Left_Position.Node, Right_Position.Node);
957 if Is_Root (Right_Position) then
961 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
964 function Equal_Subtree
965 (Left_Subtree : Tree_Node_Access;
966 Right_Subtree : Tree_Node_Access) return Boolean
969 if Left_Subtree.Element /= Right_Subtree.Element then
973 return Equal_Children (Left_Subtree, Right_Subtree);
980 procedure Finalize (Object : in out Root_Iterator) is
981 B : Natural renames Object.Container.Busy;
986 procedure Finalize (Control : in out Reference_Control_Type) is
988 if Control.Container /= null then
990 C : Tree renames Control.Container.all;
991 B : Natural renames C.Busy;
992 L : Natural renames C.Lock;
998 Control.Container := null;
1008 Item : Element_Type) return Cursor
1010 N : constant Tree_Node_Access :=
1011 Find_In_Children (Root_Node (Container), Item);
1016 return Cursor'(Container
'Unrestricted_Access, N
);
1024 overriding
function First
(Object
: Subtree_Iterator
) return Cursor
is
1026 if Object
.Subtree
= Root_Node
(Object
.Container
.all) then
1027 return First_Child
(Root
(Object
.Container
.all));
1029 return Cursor
'(Object.Container, Object.Subtree);
1033 overriding function First (Object : Child_Iterator) return Cursor is
1035 return First_Child (Cursor'(Object
.Container
, Object
.Subtree
));
1042 function First_Child
(Parent
: Cursor
) return Cursor
is
1043 Node
: Tree_Node_Access
;
1046 if Parent
= No_Element
then
1047 raise Constraint_Error
with "Parent cursor has no element";
1050 Node
:= Parent
.Node
.Children
.First
;
1056 return Cursor
'(Parent.Container, Node);
1059 -------------------------
1060 -- First_Child_Element --
1061 -------------------------
1063 function First_Child_Element (Parent : Cursor) return Element_Type is
1065 return Element (First_Child (Parent));
1066 end First_Child_Element;
1068 ----------------------
1069 -- Find_In_Children --
1070 ----------------------
1072 function Find_In_Children
1073 (Subtree : Tree_Node_Access;
1074 Item : Element_Type) return Tree_Node_Access
1076 N, Result : Tree_Node_Access;
1079 N := Subtree.Children.First;
1080 while N /= null loop
1081 Result := Find_In_Subtree (N, Item);
1083 if Result /= null then
1091 end Find_In_Children;
1093 ---------------------
1094 -- Find_In_Subtree --
1095 ---------------------
1097 function Find_In_Subtree
1099 Item : Element_Type) return Cursor
1101 Result : Tree_Node_Access;
1104 if Position = No_Element then
1105 raise Constraint_Error with "Position cursor has no element";
1108 -- Commented out pending official ruling by ARG. ???
1110 -- if Position.Container /= Container'Unrestricted_Access then
1111 -- raise Program_Error with "Position cursor not in container";
1115 (if Is_Root (Position)
1116 then Find_In_Children (Position.Node, Item)
1117 else Find_In_Subtree (Position.Node, Item));
1119 if Result = null then
1123 return Cursor'(Position
.Container
, Result
);
1124 end Find_In_Subtree
;
1126 function Find_In_Subtree
1127 (Subtree
: Tree_Node_Access
;
1128 Item
: Element_Type
) return Tree_Node_Access
1131 if Subtree
.Element
= Item
then
1135 return Find_In_Children
(Subtree
, Item
);
1136 end Find_In_Subtree
;
1142 function Has_Element
(Position
: Cursor
) return Boolean is
1144 return (if Position
= No_Element
then False
1145 else Position
.Node
.Parent
/= null);
1152 procedure Insert_Child
1153 (Container
: in out Tree
;
1156 New_Item
: Element_Type
;
1157 Count
: Count_Type
:= 1)
1160 pragma Unreferenced
(Position
);
1163 Insert_Child
(Container
, Parent
, Before
, New_Item
, Position
, Count
);
1166 procedure Insert_Child
1167 (Container
: in out Tree
;
1170 New_Item
: Element_Type
;
1171 Position
: out Cursor
;
1172 Count
: Count_Type
:= 1)
1174 First
: Tree_Node_Access
;
1175 Last
: Tree_Node_Access
;
1178 if Parent
= No_Element
then
1179 raise Constraint_Error
with "Parent cursor has no element";
1182 if Parent
.Container
/= Container
'Unrestricted_Access then
1183 raise Program_Error
with "Parent cursor not in container";
1186 if Before
/= No_Element
then
1187 if Before
.Container
/= Container
'Unrestricted_Access then
1188 raise Program_Error
with "Before cursor not in container";
1191 if Before
.Node
.Parent
/= Parent
.Node
then
1192 raise Constraint_Error
with "Parent cursor not parent of Before";
1197 Position
:= No_Element
; -- Need ruling from ARG ???
1201 if Container
.Busy
> 0 then
1203 with "attempt to tamper with cursors (tree is busy)";
1206 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
1207 Element => New_Item,
1211 for J in Count_Type'(2) .. Count
loop
1213 -- Reclaim other nodes if Storage_Error. ???
1215 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
1217 Element => New_Item,
1226 Parent => Parent.Node,
1227 Before => Before.Node);
1229 -- In order for operation Node_Count to complete in O(1) time, we cache
1230 -- the count value. Here we increment the total count by the number of
1231 -- nodes we just inserted.
1233 Container.Count := Container.Count + Count;
1235 Position := Cursor'(Parent
.Container
, First
);
1238 procedure Insert_Child
1239 (Container
: in out Tree
;
1242 Position
: out Cursor
;
1243 Count
: Count_Type
:= 1)
1245 First
: Tree_Node_Access
;
1246 Last
: Tree_Node_Access
;
1249 if Parent
= No_Element
then
1250 raise Constraint_Error
with "Parent cursor has no element";
1253 if Parent
.Container
/= Container
'Unrestricted_Access then
1254 raise Program_Error
with "Parent cursor not in container";
1257 if Before
/= No_Element
then
1258 if Before
.Container
/= Container
'Unrestricted_Access then
1259 raise Program_Error
with "Before cursor not in container";
1262 if Before
.Node
.Parent
/= Parent
.Node
then
1263 raise Constraint_Error
with "Parent cursor not parent of Before";
1268 Position
:= No_Element
; -- Need ruling from ARG ???
1272 if Container
.Busy
> 0 then
1274 with "attempt to tamper with cursors (tree is busy)";
1277 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
1282 for J in Count_Type'(2) .. Count
loop
1284 -- Reclaim other nodes if Storage_Error. ???
1286 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
1297 Parent => Parent.Node,
1298 Before => Before.Node);
1300 -- In order for operation Node_Count to complete in O(1) time, we cache
1301 -- the count value. Here we increment the total count by the number of
1302 -- nodes we just inserted.
1304 Container.Count := Container.Count + Count;
1306 Position := Cursor'(Parent
.Container
, First
);
1309 -------------------------
1310 -- Insert_Subtree_List --
1311 -------------------------
1313 procedure Insert_Subtree_List
1314 (First
: Tree_Node_Access
;
1315 Last
: Tree_Node_Access
;
1316 Parent
: Tree_Node_Access
;
1317 Before
: Tree_Node_Access
)
1319 pragma Assert
(Parent
/= null);
1320 C
: Children_Type
renames Parent
.Children
;
1323 -- This is a simple utility operation to insert a list of nodes (from
1324 -- First..Last) as children of Parent. The Before node specifies where
1325 -- the new children should be inserted relative to the existing
1328 if First
= null then
1329 pragma Assert
(Last
= null);
1333 pragma Assert
(Last
/= null);
1334 pragma Assert
(Before
= null or else Before
.Parent
= Parent
);
1336 if C
.First
= null then
1338 C
.First
.Prev
:= null;
1340 C
.Last
.Next
:= null;
1342 elsif Before
= null then -- means "insert after existing nodes"
1343 C
.Last
.Next
:= First
;
1344 First
.Prev
:= C
.Last
;
1346 C
.Last
.Next
:= null;
1348 elsif Before
= C
.First
then
1349 Last
.Next
:= C
.First
;
1350 C
.First
.Prev
:= Last
;
1352 C
.First
.Prev
:= null;
1355 Before
.Prev
.Next
:= First
;
1356 First
.Prev
:= Before
.Prev
;
1357 Last
.Next
:= Before
;
1358 Before
.Prev
:= Last
;
1360 end Insert_Subtree_List
;
1362 -------------------------
1363 -- Insert_Subtree_Node --
1364 -------------------------
1366 procedure Insert_Subtree_Node
1367 (Subtree
: Tree_Node_Access
;
1368 Parent
: Tree_Node_Access
;
1369 Before
: Tree_Node_Access
)
1372 -- This is a simple wrapper operation to insert a single child into the
1373 -- Parent's children list.
1380 end Insert_Subtree_Node
;
1386 function Is_Empty
(Container
: Tree
) return Boolean is
1388 return Container
.Root
.Children
.First
= null;
1395 function Is_Leaf
(Position
: Cursor
) return Boolean is
1397 return (if Position
= No_Element
then False
1398 else Position
.Node
.Children
.First
= null);
1405 function Is_Reachable
(From
, To
: Tree_Node_Access
) return Boolean is
1406 pragma Assert
(From
/= null);
1407 pragma Assert
(To
/= null);
1409 N
: Tree_Node_Access
;
1413 while N
/= null loop
1428 function Is_Root
(Position
: Cursor
) return Boolean is
1430 return (if Position
.Container
= null then False
1431 else Position
= Root
(Position
.Container
.all));
1440 Process
: not null access procedure (Position
: Cursor
))
1442 B
: Natural renames Container
'Unrestricted_Access.all.Busy
;
1448 (Container
=> Container
'Unrestricted_Access,
1449 Subtree
=> Root_Node
(Container
),
1450 Process
=> Process
);
1460 function Iterate
(Container
: Tree
)
1461 return Tree_Iterator_Interfaces
.Forward_Iterator
'Class
1464 return Iterate_Subtree
(Root
(Container
));
1467 ----------------------
1468 -- Iterate_Children --
1469 ----------------------
1471 procedure Iterate_Children
1473 Process
: not null access procedure (Position
: Cursor
))
1476 if Parent
= No_Element
then
1477 raise Constraint_Error
with "Parent cursor has no element";
1481 B
: Natural renames Parent
.Container
.Busy
;
1482 C
: Tree_Node_Access
;
1487 C
:= Parent
.Node
.Children
.First
;
1488 while C
/= null loop
1489 Process
(Position
=> Cursor
'(Parent.Container, Node => C));
1500 end Iterate_Children;
1502 procedure Iterate_Children
1503 (Container : Tree_Access;
1504 Subtree : Tree_Node_Access;
1505 Process : not null access procedure (Position : Cursor))
1507 Node : Tree_Node_Access;
1510 -- This is a helper function to recursively iterate over all the nodes
1511 -- in a subtree, in depth-first fashion. This particular helper just
1512 -- visits the children of this subtree, not the root of the subtree node
1513 -- itself. This is useful when starting from the ultimate root of the
1514 -- entire tree (see Iterate), as that root does not have an element.
1516 Node := Subtree.Children.First;
1517 while Node /= null loop
1518 Iterate_Subtree (Container, Node, Process);
1521 end Iterate_Children;
1523 function Iterate_Children
1526 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1528 C : constant Tree_Access := Container'Unrestricted_Access;
1529 B : Natural renames C.Busy;
1532 if Parent = No_Element then
1533 raise Constraint_Error with "Parent cursor has no element";
1536 if Parent.Container /= C then
1537 raise Program_Error with "Parent cursor not in container";
1540 return It : constant Child_Iterator :=
1541 (Limited_Controlled with
1543 Subtree => Parent.Node)
1547 end Iterate_Children;
1549 ---------------------
1550 -- Iterate_Subtree --
1551 ---------------------
1553 function Iterate_Subtree
1555 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1558 if Position = No_Element then
1559 raise Constraint_Error with "Position cursor has no element";
1562 -- Implement Vet for multiway trees???
1563 -- pragma Assert (Vet (Position), "bad subtree cursor");
1566 B : Natural renames Position.Container.Busy;
1568 return It : constant Subtree_Iterator :=
1569 (Limited_Controlled with
1570 Container => Position.Container,
1571 Subtree => Position.Node)
1576 end Iterate_Subtree;
1578 procedure Iterate_Subtree
1580 Process : not null access procedure (Position : Cursor))
1583 if Position = No_Element then
1584 raise Constraint_Error with "Position cursor has no element";
1588 B : Natural renames Position.Container.Busy;
1593 if Is_Root (Position) then
1594 Iterate_Children (Position.Container, Position.Node, Process);
1596 Iterate_Subtree (Position.Container, Position.Node, Process);
1606 end Iterate_Subtree;
1608 procedure Iterate_Subtree
1609 (Container : Tree_Access;
1610 Subtree : Tree_Node_Access;
1611 Process : not null access procedure (Position : Cursor))
1614 -- This is a helper function to recursively iterate over all the nodes
1615 -- in a subtree, in depth-first fashion. It first visits the root of the
1616 -- subtree, then visits its children.
1618 Process (Cursor'(Container
, Subtree
));
1619 Iterate_Children
(Container
, Subtree
, Process
);
1620 end Iterate_Subtree
;
1626 overriding
function Last
(Object
: Child_Iterator
) return Cursor
is
1628 return Last_Child
(Cursor
'(Object.Container, Object.Subtree));
1635 function Last_Child (Parent : Cursor) return Cursor is
1636 Node : Tree_Node_Access;
1639 if Parent = No_Element then
1640 raise Constraint_Error with "Parent cursor has no element";
1643 Node := Parent.Node.Children.Last;
1649 return (Parent.Container, Node);
1652 ------------------------
1653 -- Last_Child_Element --
1654 ------------------------
1656 function Last_Child_Element (Parent : Cursor) return Element_Type is
1658 return Element (Last_Child (Parent));
1659 end Last_Child_Element;
1665 procedure Move (Target : in out Tree; Source : in out Tree) is
1666 Node : Tree_Node_Access;
1669 if Target'Address = Source'Address then
1673 if Source.Busy > 0 then
1675 with "attempt to tamper with cursors of Source (tree is busy)";
1678 Target.Clear; -- checks busy bit
1680 Target.Root.Children := Source.Root.Children;
1681 Source.Root.Children := Children_Type'(others => null);
1683 Node
:= Target
.Root
.Children
.First
;
1684 while Node
/= null loop
1685 Node
.Parent
:= Root_Node
(Target
);
1689 Target
.Count
:= Source
.Count
;
1698 (Object
: Subtree_Iterator
;
1699 Position
: Cursor
) return Cursor
1701 Node
: Tree_Node_Access
;
1704 if Position
.Container
= null then
1708 if Position
.Container
/= Object
.Container
then
1709 raise Program_Error
with
1710 "Position cursor of Next designates wrong tree";
1713 Node
:= Position
.Node
;
1715 if Node
.Children
.First
/= null then
1716 return Cursor
'(Object.Container, Node.Children.First);
1719 while Node /= Object.Subtree loop
1720 if Node.Next /= null then
1721 return Cursor'(Object
.Container
, Node
.Next
);
1724 Node
:= Node
.Parent
;
1731 (Object
: Child_Iterator
;
1732 Position
: Cursor
) return Cursor
1735 if Position
.Container
= null then
1739 if Position
.Container
/= Object
.Container
then
1740 raise Program_Error
with
1741 "Position cursor of Next designates wrong tree";
1744 return Next_Sibling
(Position
);
1751 function Next_Sibling
(Position
: Cursor
) return Cursor
is
1753 if Position
= No_Element
then
1757 if Position
.Node
.Next
= null then
1761 return Cursor
'(Position.Container, Position.Node.Next);
1764 procedure Next_Sibling (Position : in out Cursor) is
1766 Position := Next_Sibling (Position);
1773 function Node_Count (Container : Tree) return Count_Type is
1775 -- Container.Count is the number of nodes we have actually allocated. We
1776 -- cache the value specifically so this Node_Count operation can execute
1777 -- in O(1) time, which makes it behave similarly to how the Length
1778 -- selector function behaves for other containers.
1780 -- The cached node count value only describes the nodes we have
1781 -- allocated; the root node itself is not included in that count. The
1782 -- Node_Count operation returns a value that includes the root node
1783 -- (because the RM says so), so we must add 1 to our cached value.
1785 return 1 + Container.Count;
1792 function Parent (Position : Cursor) return Cursor is
1794 if Position = No_Element then
1798 if Position.Node.Parent = null then
1802 return Cursor'(Position
.Container
, Position
.Node
.Parent
);
1809 procedure Prepend_Child
1810 (Container
: in out Tree
;
1812 New_Item
: Element_Type
;
1813 Count
: Count_Type
:= 1)
1815 First
, Last
: Tree_Node_Access
;
1818 if Parent
= No_Element
then
1819 raise Constraint_Error
with "Parent cursor has no element";
1822 if Parent
.Container
/= Container
'Unrestricted_Access then
1823 raise Program_Error
with "Parent cursor not in container";
1830 if Container
.Busy
> 0 then
1832 with "attempt to tamper with cursors (tree is busy)";
1835 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
1836 Element => New_Item,
1841 for J in Count_Type'(2) .. Count
loop
1843 -- Reclaim other nodes if Storage_Error???
1845 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
1847 Element => New_Item,
1856 Parent => Parent.Node,
1857 Before => Parent.Node.Children.First);
1859 -- In order for operation Node_Count to complete in O(1) time, we cache
1860 -- the count value. Here we increment the total count by the number of
1861 -- nodes we just inserted.
1863 Container.Count := Container.Count + Count;
1870 overriding function Previous
1871 (Object : Child_Iterator;
1872 Position : Cursor) return Cursor
1875 if Position.Container = null then
1879 if Position.Container /= Object.Container then
1880 raise Program_Error with
1881 "Position cursor of Previous designates wrong tree";
1884 return Previous_Sibling (Position);
1887 ----------------------
1888 -- Previous_Sibling --
1889 ----------------------
1891 function Previous_Sibling (Position : Cursor) return Cursor is
1894 (if Position = No_Element then No_Element
1895 elsif Position.Node.Prev = null then No_Element
1896 else Cursor'(Position
.Container
, Position
.Node
.Prev
));
1897 end Previous_Sibling
;
1899 procedure Previous_Sibling
(Position
: in out Cursor
) is
1901 Position
:= Previous_Sibling
(Position
);
1902 end Previous_Sibling
;
1908 procedure Query_Element
1910 Process
: not null access procedure (Element
: Element_Type
))
1913 if Position
= No_Element
then
1914 raise Constraint_Error
with "Position cursor has no element";
1917 if Is_Root
(Position
) then
1918 raise Program_Error
with "Position cursor designates root";
1922 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
1923 B
: Natural renames T
.Busy
;
1924 L
: Natural renames T
.Lock
;
1930 Process
(Position
.Node
.Element
);
1949 (Stream
: not null access Root_Stream_Type
'Class;
1950 Container
: out Tree
)
1952 procedure Read_Children
(Subtree
: Tree_Node_Access
);
1954 function Read_Subtree
1955 (Parent
: Tree_Node_Access
) return Tree_Node_Access
;
1957 Total_Count
: Count_Type
'Base;
1958 -- Value read from the stream that says how many elements follow
1960 Read_Count
: Count_Type
'Base;
1961 -- Actual number of elements read from the stream
1967 procedure Read_Children
(Subtree
: Tree_Node_Access
) is
1968 pragma Assert
(Subtree
/= null);
1969 pragma Assert
(Subtree
.Children
.First
= null);
1970 pragma Assert
(Subtree
.Children
.Last
= null);
1972 Count
: Count_Type
'Base;
1973 -- Number of child subtrees
1978 Count_Type
'Read (Stream
, Count
);
1981 raise Program_Error
with "attempt to read from corrupt stream";
1988 C
.First
:= Read_Subtree
(Parent
=> Subtree
);
1991 for J
in Count_Type
'(2) .. Count loop
1992 C.Last.Next := Read_Subtree (Parent => Subtree);
1993 C.Last.Next.Prev := C.Last;
1994 C.Last := C.Last.Next;
1997 -- Now that the allocation and reads have completed successfully, it
1998 -- is safe to link the children to their parent.
2000 Subtree.Children := C;
2007 function Read_Subtree
2008 (Parent : Tree_Node_Access) return Tree_Node_Access
2010 Subtree : constant Tree_Node_Access :=
2013 Element
=> Element_Type
'Input (Stream
),
2017 Read_Count
:= Read_Count
+ 1;
2019 Read_Children
(Subtree
);
2024 -- Start of processing for Read
2027 Container
.Clear
; -- checks busy bit
2029 Count_Type
'Read (Stream
, Total_Count
);
2031 if Total_Count
< 0 then
2032 raise Program_Error
with "attempt to read from corrupt stream";
2035 if Total_Count
= 0 then
2041 Read_Children
(Root_Node
(Container
));
2043 if Read_Count
/= Total_Count
then
2044 raise Program_Error
with "attempt to read from corrupt stream";
2047 Container
.Count
:= Total_Count
;
2051 (Stream
: not null access Root_Stream_Type
'Class;
2052 Position
: out Cursor
)
2055 raise Program_Error
with "attempt to read tree cursor from stream";
2059 (Stream
: not null access Root_Stream_Type
'Class;
2060 Item
: out Reference_Type
)
2063 raise Program_Error
with "attempt to stream reference";
2067 (Stream
: not null access Root_Stream_Type
'Class;
2068 Item
: out Constant_Reference_Type
)
2071 raise Program_Error
with "attempt to stream reference";
2079 (Container
: aliased in out Tree
;
2080 Position
: Cursor
) return Reference_Type
2083 if Position
.Container
= null then
2084 raise Constraint_Error
with
2085 "Position cursor has no element";
2088 if Position
.Container
/= Container
'Unrestricted_Access then
2089 raise Program_Error
with
2090 "Position cursor designates wrong container";
2093 if Position
.Node
= Root_Node
(Container
) then
2094 raise Program_Error
with "Position cursor designates root";
2097 -- Implement Vet for multiway tree???
2098 -- pragma Assert (Vet (Position),
2099 -- "Position cursor in Constant_Reference is bad");
2102 C
: Tree
renames Position
.Container
.all;
2103 B
: Natural renames C
.Busy
;
2104 L
: Natural renames C
.Lock
;
2106 return R
: constant Reference_Type
:=
2107 (Element
=> Position
.Node
.Element
'Access,
2108 Control
=> (Controlled
with Position
.Container
))
2116 --------------------
2117 -- Remove_Subtree --
2118 --------------------
2120 procedure Remove_Subtree
(Subtree
: Tree_Node_Access
) is
2121 C
: Children_Type
renames Subtree
.Parent
.Children
;
2124 -- This is a utility operation to remove a subtree node from its
2125 -- parent's list of children.
2127 if C
.First
= Subtree
then
2128 pragma Assert
(Subtree
.Prev
= null);
2130 if C
.Last
= Subtree
then
2131 pragma Assert
(Subtree
.Next
= null);
2136 C
.First
:= Subtree
.Next
;
2137 C
.First
.Prev
:= null;
2140 elsif C
.Last
= Subtree
then
2141 pragma Assert
(Subtree
.Next
= null);
2142 C
.Last
:= Subtree
.Prev
;
2143 C
.Last
.Next
:= null;
2146 Subtree
.Prev
.Next
:= Subtree
.Next
;
2147 Subtree
.Next
.Prev
:= Subtree
.Prev
;
2151 ----------------------
2152 -- Replace_Element --
2153 ----------------------
2155 procedure Replace_Element
2156 (Container
: in out Tree
;
2158 New_Item
: Element_Type
)
2161 if Position
= No_Element
then
2162 raise Constraint_Error
with "Position cursor has no element";
2165 if Position
.Container
/= Container
'Unrestricted_Access then
2166 raise Program_Error
with "Position cursor not in container";
2169 if Is_Root
(Position
) then
2170 raise Program_Error
with "Position cursor designates root";
2173 if Container
.Lock
> 0 then
2175 with "attempt to tamper with elements (tree is locked)";
2178 Position
.Node
.Element
:= New_Item
;
2179 end Replace_Element
;
2181 ------------------------------
2182 -- Reverse_Iterate_Children --
2183 ------------------------------
2185 procedure Reverse_Iterate_Children
2187 Process
: not null access procedure (Position
: Cursor
))
2190 if Parent
= No_Element
then
2191 raise Constraint_Error
with "Parent cursor has no element";
2195 B
: Natural renames Parent
.Container
.Busy
;
2196 C
: Tree_Node_Access
;
2201 C
:= Parent
.Node
.Children
.Last
;
2202 while C
/= null loop
2203 Process
(Position
=> Cursor
'(Parent.Container, Node => C));
2214 end Reverse_Iterate_Children;
2220 function Root (Container : Tree) return Cursor is
2222 return (Container'Unrestricted_Access, Root_Node (Container));
2229 function Root_Node (Container : Tree) return Tree_Node_Access is
2230 type Root_Node_Access is access all Root_Node_Type;
2231 for Root_Node_Access'Storage_Size use 0;
2232 pragma Convention (C, Root_Node_Access);
2234 function To_Tree_Node_Access is
2235 new Ada.Unchecked_Conversion (Root_Node_Access, Tree_Node_Access);
2237 -- Start of processing for Root_Node
2240 -- This is a utility function for converting from an access type that
2241 -- designates the distinguished root node to an access type designating
2242 -- a non-root node. The representation of a root node does not have an
2243 -- element, but is otherwise identical to a non-root node, so the
2244 -- conversion itself is safe.
2246 return To_Tree_Node_Access (Container.Root'Unrestricted_Access);
2249 ---------------------
2250 -- Splice_Children --
2251 ---------------------
2253 procedure Splice_Children
2254 (Target : in out Tree;
2255 Target_Parent : Cursor;
2257 Source : in out Tree;
2258 Source_Parent : Cursor)
2263 if Target_Parent = No_Element then
2264 raise Constraint_Error with "Target_Parent cursor has no element";
2267 if Target_Parent.Container /= Target'Unrestricted_Access then
2269 with "Target_Parent cursor not in Target container";
2272 if Before /= No_Element then
2273 if Before.Container /= Target'Unrestricted_Access then
2275 with "Before cursor not in Target container";
2278 if Before.Node.Parent /= Target_Parent.Node then
2279 raise Constraint_Error
2280 with "Before cursor not child of Target_Parent";
2284 if Source_Parent = No_Element then
2285 raise Constraint_Error with "Source_Parent cursor has no element";
2288 if Source_Parent.Container /= Source'Unrestricted_Access then
2290 with "Source_Parent cursor not in Source container";
2293 if Target'Address = Source'Address then
2294 if Target_Parent = Source_Parent then
2298 if Target.Busy > 0 then
2300 with "attempt to tamper with cursors (Target tree is busy)";
2303 if Is_Reachable (From => Target_Parent.Node,
2304 To => Source_Parent.Node)
2306 raise Constraint_Error
2307 with "Source_Parent is ancestor of Target_Parent";
2311 (Target_Parent => Target_Parent.Node,
2312 Before => Before.Node,
2313 Source_Parent => Source_Parent.Node);
2318 if Target.Busy > 0 then
2320 with "attempt to tamper with cursors (Target tree is busy)";
2323 if Source.Busy > 0 then
2325 with "attempt to tamper with cursors (Source tree is busy)";
2328 -- We cache the count of the nodes we have allocated, so that operation
2329 -- Node_Count can execute in O(1) time. But that means we must count the
2330 -- nodes in the subtree we remove from Source and insert into Target, in
2331 -- order to keep the count accurate.
2333 Count := Subtree_Node_Count (Source_Parent.Node);
2334 pragma Assert (Count >= 1);
2336 Count := Count - 1; -- because Source_Parent node does not move
2339 (Target_Parent => Target_Parent.Node,
2340 Before => Before.Node,
2341 Source_Parent => Source_Parent.Node);
2343 Source.Count := Source.Count - Count;
2344 Target.Count := Target.Count + Count;
2345 end Splice_Children;
2347 procedure Splice_Children
2348 (Container : in out Tree;
2349 Target_Parent : Cursor;
2351 Source_Parent : Cursor)
2354 if Target_Parent = No_Element then
2355 raise Constraint_Error with "Target_Parent cursor has no element";
2358 if Target_Parent.Container /= Container'Unrestricted_Access then
2360 with "Target_Parent cursor not in container";
2363 if Before /= No_Element then
2364 if Before.Container /= Container'Unrestricted_Access then
2366 with "Before cursor not in container";
2369 if Before.Node.Parent /= Target_Parent.Node then
2370 raise Constraint_Error
2371 with "Before cursor not child of Target_Parent";
2375 if Source_Parent = No_Element then
2376 raise Constraint_Error with "Source_Parent cursor has no element";
2379 if Source_Parent.Container /= Container'Unrestricted_Access then
2381 with "Source_Parent cursor not in container";
2384 if Target_Parent = Source_Parent then
2388 if Container.Busy > 0 then
2390 with "attempt to tamper with cursors (tree is busy)";
2393 if Is_Reachable (From => Target_Parent.Node,
2394 To => Source_Parent.Node)
2396 raise Constraint_Error
2397 with "Source_Parent is ancestor of Target_Parent";
2401 (Target_Parent => Target_Parent.Node,
2402 Before => Before.Node,
2403 Source_Parent => Source_Parent.Node);
2404 end Splice_Children;
2406 procedure Splice_Children
2407 (Target_Parent : Tree_Node_Access;
2408 Before : Tree_Node_Access;
2409 Source_Parent : Tree_Node_Access)
2411 CC : constant Children_Type := Source_Parent.Children;
2412 C : Tree_Node_Access;
2415 -- This is a utility operation to remove the children from
2416 -- Source parent and insert them into Target parent.
2418 Source_Parent.Children := Children_Type'(others => null);
2420 -- Fix up the Parent pointers of each child to designate
2421 -- its new Target parent.
2424 while C
/= null loop
2425 C
.Parent
:= Target_Parent
;
2432 Parent
=> Target_Parent
,
2434 end Splice_Children
;
2436 --------------------
2437 -- Splice_Subtree --
2438 --------------------
2440 procedure Splice_Subtree
2441 (Target
: in out Tree
;
2444 Source
: in out Tree
;
2445 Position
: in out Cursor
)
2447 Subtree_Count
: Count_Type
;
2450 if Parent
= No_Element
then
2451 raise Constraint_Error
with "Parent cursor has no element";
2454 if Parent
.Container
/= Target
'Unrestricted_Access then
2455 raise Program_Error
with "Parent cursor not in Target container";
2458 if Before
/= No_Element
then
2459 if Before
.Container
/= Target
'Unrestricted_Access then
2460 raise Program_Error
with "Before cursor not in Target container";
2463 if Before
.Node
.Parent
/= Parent
.Node
then
2464 raise Constraint_Error
with "Before cursor not child of Parent";
2468 if Position
= No_Element
then
2469 raise Constraint_Error
with "Position cursor has no element";
2472 if Position
.Container
/= Source
'Unrestricted_Access then
2473 raise Program_Error
with "Position cursor not in Source container";
2476 if Is_Root
(Position
) then
2477 raise Program_Error
with "Position cursor designates root";
2480 if Target
'Address = Source
'Address then
2481 if Position
.Node
.Parent
= Parent
.Node
then
2482 if Position
.Node
= Before
.Node
then
2486 if Position
.Node
.Next
= Before
.Node
then
2491 if Target
.Busy
> 0 then
2493 with "attempt to tamper with cursors (Target tree is busy)";
2496 if Is_Reachable
(From
=> Parent
.Node
, To
=> Position
.Node
) then
2497 raise Constraint_Error
with "Position is ancestor of Parent";
2500 Remove_Subtree
(Position
.Node
);
2502 Position
.Node
.Parent
:= Parent
.Node
;
2503 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2508 if Target
.Busy
> 0 then
2510 with "attempt to tamper with cursors (Target tree is busy)";
2513 if Source
.Busy
> 0 then
2515 with "attempt to tamper with cursors (Source tree is busy)";
2518 -- This is an unfortunate feature of this API: we must count the nodes
2519 -- in the subtree that we remove from the source tree, which is an O(n)
2520 -- operation. It would have been better if the Tree container did not
2521 -- have a Node_Count selector; a user that wants the number of nodes in
2522 -- the tree could simply call Subtree_Node_Count, with the understanding
2523 -- that such an operation is O(n).
2525 -- Of course, we could choose to implement the Node_Count selector as an
2526 -- O(n) operation, which would turn this splice operation into an O(1)
2529 Subtree_Count
:= Subtree_Node_Count
(Position
.Node
);
2530 pragma Assert
(Subtree_Count
<= Source
.Count
);
2532 Remove_Subtree
(Position
.Node
);
2533 Source
.Count
:= Source
.Count
- Subtree_Count
;
2535 Position
.Node
.Parent
:= Parent
.Node
;
2536 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2538 Target
.Count
:= Target
.Count
+ Subtree_Count
;
2540 Position
.Container
:= Target
'Unrestricted_Access;
2543 procedure Splice_Subtree
2544 (Container
: in out Tree
;
2550 if Parent
= No_Element
then
2551 raise Constraint_Error
with "Parent cursor has no element";
2554 if Parent
.Container
/= Container
'Unrestricted_Access then
2555 raise Program_Error
with "Parent cursor not in container";
2558 if Before
/= No_Element
then
2559 if Before
.Container
/= Container
'Unrestricted_Access then
2560 raise Program_Error
with "Before cursor not in container";
2563 if Before
.Node
.Parent
/= Parent
.Node
then
2564 raise Constraint_Error
with "Before cursor not child of Parent";
2568 if Position
= No_Element
then
2569 raise Constraint_Error
with "Position cursor has no element";
2572 if Position
.Container
/= Container
'Unrestricted_Access then
2573 raise Program_Error
with "Position cursor not in container";
2576 if Is_Root
(Position
) then
2578 -- Should this be PE instead? Need ARG confirmation. ???
2580 raise Constraint_Error
with "Position cursor designates root";
2583 if Position
.Node
.Parent
= Parent
.Node
then
2584 if Position
.Node
= Before
.Node
then
2588 if Position
.Node
.Next
= Before
.Node
then
2593 if Container
.Busy
> 0 then
2595 with "attempt to tamper with cursors (tree is busy)";
2598 if Is_Reachable
(From
=> Parent
.Node
, To
=> Position
.Node
) then
2599 raise Constraint_Error
with "Position is ancestor of Parent";
2602 Remove_Subtree
(Position
.Node
);
2604 Position
.Node
.Parent
:= Parent
.Node
;
2605 Insert_Subtree_Node
(Position
.Node
, Parent
.Node
, Before
.Node
);
2608 ------------------------
2609 -- Subtree_Node_Count --
2610 ------------------------
2612 function Subtree_Node_Count
(Position
: Cursor
) return Count_Type
is
2614 if Position
= No_Element
then
2618 return Subtree_Node_Count
(Position
.Node
);
2619 end Subtree_Node_Count
;
2621 function Subtree_Node_Count
2622 (Subtree
: Tree_Node_Access
) return Count_Type
2624 Result
: Count_Type
;
2625 Node
: Tree_Node_Access
;
2629 Node
:= Subtree
.Children
.First
;
2630 while Node
/= null loop
2631 Result
:= Result
+ Subtree_Node_Count
(Node
);
2636 end Subtree_Node_Count
;
2643 (Container
: in out Tree
;
2647 if I
= No_Element
then
2648 raise Constraint_Error
with "I cursor has no element";
2651 if I
.Container
/= Container
'Unrestricted_Access then
2652 raise Program_Error
with "I cursor not in container";
2656 raise Program_Error
with "I cursor designates root";
2659 if I
= J
then -- make this test sooner???
2663 if J
= No_Element
then
2664 raise Constraint_Error
with "J cursor has no element";
2667 if J
.Container
/= Container
'Unrestricted_Access then
2668 raise Program_Error
with "J cursor not in container";
2672 raise Program_Error
with "J cursor designates root";
2675 if Container
.Lock
> 0 then
2677 with "attempt to tamper with elements (tree is locked)";
2681 EI
: constant Element_Type
:= I
.Node
.Element
;
2684 I
.Node
.Element
:= J
.Node
.Element
;
2685 J
.Node
.Element
:= EI
;
2689 --------------------
2690 -- Update_Element --
2691 --------------------
2693 procedure Update_Element
2694 (Container
: in out Tree
;
2696 Process
: not null access procedure (Element
: in out Element_Type
))
2699 if Position
= No_Element
then
2700 raise Constraint_Error
with "Position cursor has no element";
2703 if Position
.Container
/= Container
'Unrestricted_Access then
2704 raise Program_Error
with "Position cursor not in container";
2707 if Is_Root
(Position
) then
2708 raise Program_Error
with "Position cursor designates root";
2712 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
2713 B
: Natural renames T
.Busy
;
2714 L
: Natural renames T
.Lock
;
2720 Process
(Position
.Node
.Element
);
2739 (Stream
: not null access Root_Stream_Type
'Class;
2742 procedure Write_Children
(Subtree
: Tree_Node_Access
);
2743 procedure Write_Subtree
(Subtree
: Tree_Node_Access
);
2745 --------------------
2746 -- Write_Children --
2747 --------------------
2749 procedure Write_Children
(Subtree
: Tree_Node_Access
) is
2750 CC
: Children_Type
renames Subtree
.Children
;
2751 C
: Tree_Node_Access
;
2754 Count_Type
'Write (Stream
, Child_Count
(CC
));
2757 while C
/= null loop
2767 procedure Write_Subtree
(Subtree
: Tree_Node_Access
) is
2769 Element_Type
'Output (Stream
, Subtree
.Element
);
2770 Write_Children
(Subtree
);
2773 -- Start of processing for Write
2776 Count_Type
'Write (Stream
, Container
.Count
);
2778 if Container
.Count
= 0 then
2782 Write_Children
(Root_Node
(Container
));
2786 (Stream
: not null access Root_Stream_Type
'Class;
2790 raise Program_Error
with "attempt to write tree cursor to stream";
2794 (Stream
: not null access Root_Stream_Type
'Class;
2795 Item
: Reference_Type
)
2798 raise Program_Error
with "attempt to stream reference";
2802 (Stream
: not null access Root_Stream_Type
'Class;
2803 Item
: Constant_Reference_Type
)
2806 raise Program_Error
with "attempt to stream reference";
2809 end Ada
.Containers
.Multiway_Trees
;