1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.INDEFINITE_MULTIWAY_TREES --
9 -- Copyright (C) 2004-2012, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada
.Unchecked_Deallocation
;
32 with System
; use type System
.Address
;
34 package body Ada
.Containers
.Indefinite_Multiway_Trees
is
40 type Root_Iterator
is abstract new Limited_Controlled
and
41 Tree_Iterator_Interfaces
.Forward_Iterator
with
43 Container
: Tree_Access
;
44 Subtree
: Tree_Node_Access
;
47 overriding
procedure Finalize
(Object
: in out Root_Iterator
);
49 -----------------------
50 -- Subtree_Iterator --
51 -----------------------
53 type Subtree_Iterator
is new Root_Iterator
with null record;
55 overriding
function First
(Object
: Subtree_Iterator
) return Cursor
;
57 overriding
function Next
58 (Object
: Subtree_Iterator
;
59 Position
: Cursor
) return Cursor
;
65 type Child_Iterator
is new Root_Iterator
and
66 Tree_Iterator_Interfaces
.Reversible_Iterator
with null record;
68 overriding
function First
(Object
: Child_Iterator
) return Cursor
;
70 overriding
function Next
71 (Object
: Child_Iterator
;
72 Position
: Cursor
) return Cursor
;
74 overriding
function Last
(Object
: Child_Iterator
) return Cursor
;
76 overriding
function Previous
77 (Object
: Child_Iterator
;
78 Position
: Cursor
) return Cursor
;
80 -----------------------
81 -- Local Subprograms --
82 -----------------------
84 function Root_Node
(Container
: Tree
) return Tree_Node_Access
;
86 procedure Free_Element
is
87 new Ada
.Unchecked_Deallocation
(Element_Type
, Element_Access
);
89 procedure Deallocate_Node
(X
: in out Tree_Node_Access
);
91 procedure Deallocate_Children
92 (Subtree
: Tree_Node_Access
;
93 Count
: in out Count_Type
);
95 procedure Deallocate_Subtree
96 (Subtree
: in out Tree_Node_Access
;
97 Count
: in out Count_Type
);
99 function Equal_Children
100 (Left_Subtree
, Right_Subtree
: Tree_Node_Access
) return Boolean;
102 function Equal_Subtree
103 (Left_Subtree
, Right_Subtree
: Tree_Node_Access
) return Boolean;
105 procedure Iterate_Children
106 (Container
: Tree_Access
;
107 Subtree
: Tree_Node_Access
;
108 Process
: not null access procedure (Position
: Cursor
));
110 procedure Iterate_Subtree
111 (Container
: Tree_Access
;
112 Subtree
: Tree_Node_Access
;
113 Process
: not null access procedure (Position
: Cursor
));
115 procedure Copy_Children
116 (Source
: Children_Type
;
117 Parent
: Tree_Node_Access
;
118 Count
: in out Count_Type
);
120 procedure Copy_Subtree
121 (Source
: Tree_Node_Access
;
122 Parent
: Tree_Node_Access
;
123 Target
: out Tree_Node_Access
;
124 Count
: in out Count_Type
);
126 function Find_In_Children
127 (Subtree
: Tree_Node_Access
;
128 Item
: Element_Type
) return Tree_Node_Access
;
130 function Find_In_Subtree
131 (Subtree
: Tree_Node_Access
;
132 Item
: Element_Type
) return Tree_Node_Access
;
134 function Child_Count
(Children
: Children_Type
) return Count_Type
;
136 function Subtree_Node_Count
137 (Subtree
: Tree_Node_Access
) return Count_Type
;
139 function Is_Reachable
(From
, To
: Tree_Node_Access
) return Boolean;
141 procedure Remove_Subtree
(Subtree
: Tree_Node_Access
);
143 procedure Insert_Subtree_Node
144 (Subtree
: Tree_Node_Access
;
145 Parent
: Tree_Node_Access
;
146 Before
: Tree_Node_Access
);
148 procedure Insert_Subtree_List
149 (First
: Tree_Node_Access
;
150 Last
: Tree_Node_Access
;
151 Parent
: Tree_Node_Access
;
152 Before
: Tree_Node_Access
);
154 procedure Splice_Children
155 (Target_Parent
: Tree_Node_Access
;
156 Before
: Tree_Node_Access
;
157 Source_Parent
: Tree_Node_Access
);
163 function "=" (Left
, Right
: Tree
) return Boolean is
165 if Left
'Address = Right
'Address then
169 return Equal_Children
(Root_Node
(Left
), Root_Node
(Right
));
176 procedure Adjust
(Container
: in out Tree
) is
177 Source
: constant Children_Type
:= Container
.Root
.Children
;
178 Source_Count
: constant Count_Type
:= Container
.Count
;
179 Target_Count
: Count_Type
;
182 -- We first restore the target container to its default-initialized
183 -- state, before we attempt any allocation, to ensure that invariants
184 -- are preserved in the event that the allocation fails.
186 Container
.Root
.Children
:= Children_Type
'(others => null);
189 Container.Count := 0;
191 -- Copy_Children returns a count of the number of nodes that it
192 -- allocates, but it works by incrementing the value that is passed in.
193 -- We must therefore initialize the count value before calling
198 -- Now we attempt the allocation of subtrees. The invariants are
199 -- satisfied even if the allocation fails.
201 Copy_Children (Source, Root_Node (Container), Target_Count);
202 pragma Assert (Target_Count = Source_Count);
204 Container.Count := Source_Count;
207 procedure Adjust (Control : in out Reference_Control_Type) is
209 if Control.Container /= null then
211 C : Tree renames Control.Container.all;
212 B : Natural renames C.Busy;
213 L : Natural renames C.Lock;
225 function Ancestor_Find
227 Item : Element_Type) return Cursor
229 R, N : Tree_Node_Access;
232 if Position = No_Element then
233 raise Constraint_Error with "Position cursor has no element";
236 -- Commented-out pending ARG ruling. ???
238 -- if Position.Container /= Container'Unrestricted_Access then
239 -- raise Program_Error with "Position cursor not in container";
242 -- AI-0136 says to raise PE if Position equals the root node. This does
243 -- not seem correct, as this value is just the limiting condition of the
244 -- search. For now we omit this check pending a ruling from the ARG.???
246 -- if Is_Root (Position) then
247 -- raise Program_Error with "Position cursor designates root";
250 R := Root_Node (Position.Container.all);
253 if N.Element.all = Item then
254 return Cursor'(Position
.Container
, N
);
267 procedure Append_Child
268 (Container
: in out Tree
;
270 New_Item
: Element_Type
;
271 Count
: Count_Type
:= 1)
273 First
, Last
: Tree_Node_Access
;
274 Element
: Element_Access
;
277 if Parent
= No_Element
then
278 raise Constraint_Error
with "Parent cursor has no element";
281 if Parent
.Container
/= Container
'Unrestricted_Access then
282 raise Program_Error
with "Parent cursor not in container";
289 if Container
.Busy
> 0 then
291 with "attempt to tamper with cursors (tree is busy)";
295 -- The element allocator may need an accessibility check in the case
296 -- the actual type is class-wide or has access discriminants (see
297 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
298 -- allocator in the loop below, because the one in this block would
299 -- have failed already.
301 pragma Unsuppress
(Accessibility_Check
);
304 Element
:= new Element_Type
'(New_Item);
307 First := new Tree_Node_Type'(Parent
=> Parent
.Node
,
313 for J
in Count_Type
'(2) .. Count loop
315 -- Reclaim other nodes if Storage_Error. ???
317 Element := new Element_Type'(New_Item
);
318 Last
.Next
:= new Tree_Node_Type
'(Parent => Parent.Node,
329 Parent => Parent.Node,
330 Before => null); -- null means "insert at end of list"
332 -- In order for operation Node_Count to complete in O(1) time, we cache
333 -- the count value. Here we increment the total count by the number of
334 -- nodes we just inserted.
336 Container.Count := Container.Count + Count;
343 procedure Assign (Target : in out Tree; Source : Tree) is
344 Source_Count : constant Count_Type := Source.Count;
345 Target_Count : Count_Type;
348 if Target'Address = Source'Address then
352 Target.Clear; -- checks busy bit
354 -- Copy_Children returns the number of nodes that it allocates, but it
355 -- does this by incrementing the count value passed in, so we must
356 -- initialize the count before calling Copy_Children.
360 -- Note that Copy_Children inserts the newly-allocated children into
361 -- their parent list only after the allocation of all the children has
362 -- succeeded. This preserves invariants even if the allocation fails.
364 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
365 pragma Assert (Target_Count = Source_Count);
367 Target.Count := Source_Count;
374 function Child_Count (Parent : Cursor) return Count_Type is
376 if Parent = No_Element then
379 return Child_Count (Parent.Node.Children);
383 function Child_Count (Children : Children_Type) return Count_Type is
385 Node : Tree_Node_Access;
389 Node := Children.First;
390 while Node /= null loop
391 Result := Result + 1;
402 function Child_Depth (Parent, Child : Cursor) return Count_Type is
404 N : Tree_Node_Access;
407 if Parent = No_Element then
408 raise Constraint_Error with "Parent cursor has no element";
411 if Child = No_Element then
412 raise Constraint_Error with "Child cursor has no element";
415 if Parent.Container /= Child.Container then
416 raise Program_Error with "Parent and Child in different containers";
421 while N /= Parent.Node loop
422 Result := Result + 1;
426 raise Program_Error with "Parent is not ancestor of Child";
437 procedure Clear (Container : in out Tree) is
438 Container_Count : Count_Type;
439 Children_Count : Count_Type;
442 if Container.Busy > 0 then
444 with "attempt to tamper with cursors (tree is busy)";
447 -- We first set the container count to 0, in order to preserve
448 -- invariants in case the deallocation fails. (This works because
449 -- Deallocate_Children immediately removes the children from their
450 -- parent, and then does the actual deallocation.)
452 Container_Count := Container.Count;
453 Container.Count := 0;
455 -- Deallocate_Children returns the number of nodes that it deallocates,
456 -- but it does this by incrementing the count value that is passed in,
457 -- so we must first initialize the count return value before calling it.
461 -- See comment above. Deallocate_Children immediately removes the
462 -- children list from their parent node (here, the root of the tree),
463 -- and only after that does it attempt the actual deallocation. So even
464 -- if the deallocation fails, the representation invariants
466 Deallocate_Children (Root_Node (Container), Children_Count);
467 pragma Assert (Children_Count = Container_Count);
470 ------------------------
471 -- Constant_Reference --
472 ------------------------
474 function Constant_Reference
475 (Container : aliased Tree;
476 Position : Cursor) return Constant_Reference_Type
479 if Position.Container = null then
480 raise Constraint_Error with
481 "Position cursor has no element";
484 if Position.Container /= Container'Unrestricted_Access then
485 raise Program_Error with
486 "Position cursor designates wrong container";
489 if Position.Node = Root_Node (Container) then
490 raise Program_Error with "Position cursor designates root";
493 if Position.Node.Element = null then
494 raise Program_Error with "Node has no element";
497 -- Implement Vet for multiway tree???
498 -- pragma Assert (Vet (Position),
499 -- "Position cursor in Constant_Reference is bad");
502 C : Tree renames Position.Container.all;
503 B : Natural renames C.Busy;
504 L : Natural renames C.Lock;
506 return R : constant Constant_Reference_Type :=
507 (Element => Position.Node.Element.all'Access,
508 Control => (Controlled with Container'Unrestricted_Access))
514 end Constant_Reference;
522 Item : Element_Type) return Boolean
525 return Find (Container, Item) /= No_Element;
532 function Copy (Source : Tree) return Tree is
534 return Target : Tree do
536 (Source => Source.Root.Children,
537 Parent => Root_Node (Target),
538 Count => Target.Count);
540 pragma Assert (Target.Count = Source.Count);
548 procedure Copy_Children
549 (Source : Children_Type;
550 Parent : Tree_Node_Access;
551 Count : in out Count_Type)
553 pragma Assert (Parent /= null);
554 pragma Assert (Parent.Children.First = null);
555 pragma Assert (Parent.Children.Last = null);
558 C : Tree_Node_Access;
561 -- We special-case the first allocation, in order to establish the
562 -- representation invariants for type Children_Type.
578 -- The representation invariants for the Children_Type list have been
579 -- established, so we can now copy the remaining children of Source.
586 Target => CC.Last.Next,
589 CC.Last.Next.Prev := CC.Last;
590 CC.Last := CC.Last.Next;
595 -- We add the newly-allocated children to their parent list only after
596 -- the allocation has succeeded, in order to preserve invariants of the
599 Parent.Children := CC;
606 procedure Copy_Subtree
607 (Target : in out Tree;
612 Target_Subtree : Tree_Node_Access;
613 Target_Count : Count_Type;
616 if Parent = No_Element then
617 raise Constraint_Error with "Parent cursor has no element";
620 if Parent.Container /= Target'Unrestricted_Access then
621 raise Program_Error with "Parent cursor not in container";
624 if Before /= No_Element then
625 if Before.Container /= Target'Unrestricted_Access then
626 raise Program_Error with "Before cursor not in container";
629 if Before.Node.Parent /= Parent.Node then
630 raise Constraint_Error with "Before cursor not child of Parent";
634 if Source = No_Element then
638 if Is_Root (Source) then
639 raise Constraint_Error with "Source cursor designates root";
642 -- Copy_Subtree returns a count of the number of nodes that it
643 -- allocates, but it works by incrementing the value that is passed in.
644 -- We must therefore initialize the count value before calling
650 (Source => Source.Node,
651 Parent => Parent.Node,
652 Target => Target_Subtree,
653 Count => Target_Count);
655 pragma Assert (Target_Subtree /= null);
656 pragma Assert (Target_Subtree.Parent = Parent.Node);
657 pragma Assert (Target_Count >= 1);
660 (Subtree => Target_Subtree,
661 Parent => Parent.Node,
662 Before => Before.Node);
664 -- In order for operation Node_Count to complete in O(1) time, we cache
665 -- the count value. Here we increment the total count by the number of
666 -- nodes we just inserted.
668 Target.Count := Target.Count + Target_Count;
671 procedure Copy_Subtree
672 (Source : Tree_Node_Access;
673 Parent : Tree_Node_Access;
674 Target : out Tree_Node_Access;
675 Count : in out Count_Type)
677 E : constant Element_Access := new Element_Type'(Source
.Element
.all);
680 Target
:= new Tree_Node_Type
'(Element => E,
687 (Source => Source.Children,
692 -------------------------
693 -- Deallocate_Children --
694 -------------------------
696 procedure Deallocate_Children
697 (Subtree : Tree_Node_Access;
698 Count : in out Count_Type)
700 pragma Assert (Subtree /= null);
702 CC : Children_Type := Subtree.Children;
703 C : Tree_Node_Access;
706 -- We immediately remove the children from their parent, in order to
707 -- preserve invariants in case the deallocation fails.
709 Subtree.Children := Children_Type'(others => null);
711 while CC
.First
/= null loop
715 Deallocate_Subtree
(C
, Count
);
717 end Deallocate_Children
;
719 ---------------------
720 -- Deallocate_Node --
721 ---------------------
723 procedure Deallocate_Node
(X
: in out Tree_Node_Access
) is
724 procedure Free_Node
is
725 new Ada
.Unchecked_Deallocation
(Tree_Node_Type
, Tree_Node_Access
);
727 -- Start of processing for Deallocate_Node
731 Free_Element
(X
.Element
);
736 ------------------------
737 -- Deallocate_Subtree --
738 ------------------------
740 procedure Deallocate_Subtree
741 (Subtree
: in out Tree_Node_Access
;
742 Count
: in out Count_Type
)
745 Deallocate_Children
(Subtree
, Count
);
746 Deallocate_Node
(Subtree
);
748 end Deallocate_Subtree
;
750 ---------------------
751 -- Delete_Children --
752 ---------------------
754 procedure Delete_Children
755 (Container
: in out Tree
;
761 if Parent
= No_Element
then
762 raise Constraint_Error
with "Parent cursor has no element";
765 if Parent
.Container
/= Container
'Unrestricted_Access then
766 raise Program_Error
with "Parent cursor not in container";
769 if Container
.Busy
> 0 then
771 with "attempt to tamper with cursors (tree is busy)";
774 -- Deallocate_Children returns a count of the number of nodes
775 -- that it deallocates, but it works by incrementing the
776 -- value that is passed in. We must therefore initialize
777 -- the count value before calling Deallocate_Children.
781 Deallocate_Children
(Parent
.Node
, Count
);
782 pragma Assert
(Count
<= Container
.Count
);
784 Container
.Count
:= Container
.Count
- Count
;
791 procedure Delete_Leaf
792 (Container
: in out Tree
;
793 Position
: in out Cursor
)
795 X
: Tree_Node_Access
;
798 if Position
= No_Element
then
799 raise Constraint_Error
with "Position cursor has no element";
802 if Position
.Container
/= Container
'Unrestricted_Access then
803 raise Program_Error
with "Position cursor not in container";
806 if Is_Root
(Position
) then
807 raise Program_Error
with "Position cursor designates root";
810 if not Is_Leaf
(Position
) then
811 raise Constraint_Error
with "Position cursor does not designate leaf";
814 if Container
.Busy
> 0 then
816 with "attempt to tamper with cursors (tree is busy)";
820 Position
:= No_Element
;
822 -- Restore represention invariants before attempting the actual
826 Container
.Count
:= Container
.Count
- 1;
828 -- It is now safe to attempt the deallocation. This leaf node has been
829 -- disassociated from the tree, so even if the deallocation fails,
830 -- representation invariants will remain satisfied.
839 procedure Delete_Subtree
840 (Container
: in out Tree
;
841 Position
: in out Cursor
)
843 X
: Tree_Node_Access
;
847 if Position
= No_Element
then
848 raise Constraint_Error
with "Position cursor has no element";
851 if Position
.Container
/= Container
'Unrestricted_Access then
852 raise Program_Error
with "Position cursor not in container";
855 if Is_Root
(Position
) then
856 raise Program_Error
with "Position cursor designates root";
859 if Container
.Busy
> 0 then
861 with "attempt to tamper with cursors (tree is busy)";
865 Position
:= No_Element
;
867 -- Here is one case where a deallocation failure can result in the
868 -- violation of a representation invariant. We disassociate the subtree
869 -- from the tree now, but we only decrement the total node count after
870 -- we attempt the deallocation. However, if the deallocation fails, the
871 -- total node count will not get decremented.
873 -- One way around this dilemma is to count the nodes in the subtree
874 -- before attempt to delete the subtree, but that is an O(n) operation,
875 -- so it does not seem worth it.
877 -- Perhaps this is much ado about nothing, since the only way
878 -- deallocation can fail is if Controlled Finalization fails: this
879 -- propagates Program_Error so all bets are off anyway. ???
883 -- Deallocate_Subtree returns a count of the number of nodes that it
884 -- deallocates, but it works by incrementing the value that is passed
885 -- in. We must therefore initialize the count value before calling
886 -- Deallocate_Subtree.
890 Deallocate_Subtree
(X
, Count
);
891 pragma Assert
(Count
<= Container
.Count
);
893 -- See comments above. We would prefer to do this sooner, but there's no
894 -- way to satisfy that goal without an potentially severe execution
897 Container
.Count
:= Container
.Count
- Count
;
904 function Depth
(Position
: Cursor
) return Count_Type
is
906 N
: Tree_Node_Access
;
913 Result
:= Result
+ 1;
923 function Element
(Position
: Cursor
) return Element_Type
is
925 if Position
.Container
= null then
926 raise Constraint_Error
with "Position cursor has no element";
929 if Position
.Node
= Root_Node
(Position
.Container
.all) then
930 raise Program_Error
with "Position cursor designates root";
933 return Position
.Node
.Element
.all;
940 function Equal_Children
941 (Left_Subtree
: Tree_Node_Access
;
942 Right_Subtree
: Tree_Node_Access
) return Boolean
944 Left_Children
: Children_Type
renames Left_Subtree
.Children
;
945 Right_Children
: Children_Type
renames Right_Subtree
.Children
;
947 L
, R
: Tree_Node_Access
;
950 if Child_Count
(Left_Children
) /= Child_Count
(Right_Children
) then
954 L
:= Left_Children
.First
;
955 R
:= Right_Children
.First
;
957 if not Equal_Subtree
(L
, R
) then
972 function Equal_Subtree
973 (Left_Position
: Cursor
;
974 Right_Position
: Cursor
) return Boolean
977 if Left_Position
= No_Element
then
978 raise Constraint_Error
with "Left cursor has no element";
981 if Right_Position
= No_Element
then
982 raise Constraint_Error
with "Right cursor has no element";
985 if Left_Position
= Right_Position
then
989 if Is_Root
(Left_Position
) then
990 if not Is_Root
(Right_Position
) then
994 return Equal_Children
(Left_Position
.Node
, Right_Position
.Node
);
997 if Is_Root
(Right_Position
) then
1001 return Equal_Subtree
(Left_Position
.Node
, Right_Position
.Node
);
1004 function Equal_Subtree
1005 (Left_Subtree
: Tree_Node_Access
;
1006 Right_Subtree
: Tree_Node_Access
) return Boolean
1009 if Left_Subtree
.Element
.all /= Right_Subtree
.Element
.all then
1013 return Equal_Children
(Left_Subtree
, Right_Subtree
);
1020 procedure Finalize
(Object
: in out Root_Iterator
) is
1021 B
: Natural renames Object
.Container
.Busy
;
1026 procedure Finalize
(Control
: in out Reference_Control_Type
) is
1028 if Control
.Container
/= null then
1030 C
: Tree
renames Control
.Container
.all;
1031 B
: Natural renames C
.Busy
;
1032 L
: Natural renames C
.Lock
;
1038 Control
.Container
:= null;
1048 Item
: Element_Type
) return Cursor
1050 N
: constant Tree_Node_Access
:=
1051 Find_In_Children
(Root_Node
(Container
), Item
);
1058 return Cursor
'(Container'Unrestricted_Access, N);
1065 overriding function First (Object : Subtree_Iterator) return Cursor is
1067 if Object.Subtree = Root_Node (Object.Container.all) then
1068 return First_Child (Root (Object.Container.all));
1070 return Cursor'(Object
.Container
, Object
.Subtree
);
1074 overriding
function First
(Object
: Child_Iterator
) return Cursor
is
1076 return First_Child
(Cursor
'(Object.Container, Object.Subtree));
1083 function First_Child (Parent : Cursor) return Cursor is
1084 Node : Tree_Node_Access;
1087 if Parent = No_Element then
1088 raise Constraint_Error with "Parent cursor has no element";
1091 Node := Parent.Node.Children.First;
1097 return Cursor'(Parent
.Container
, Node
);
1100 -------------------------
1101 -- First_Child_Element --
1102 -------------------------
1104 function First_Child_Element
(Parent
: Cursor
) return Element_Type
is
1106 return Element
(First_Child
(Parent
));
1107 end First_Child_Element
;
1109 ----------------------
1110 -- Find_In_Children --
1111 ----------------------
1113 function Find_In_Children
1114 (Subtree
: Tree_Node_Access
;
1115 Item
: Element_Type
) return Tree_Node_Access
1117 N
, Result
: Tree_Node_Access
;
1120 N
:= Subtree
.Children
.First
;
1121 while N
/= null loop
1122 Result
:= Find_In_Subtree
(N
, Item
);
1124 if Result
/= null then
1132 end Find_In_Children
;
1134 ---------------------
1135 -- Find_In_Subtree --
1136 ---------------------
1138 function Find_In_Subtree
1140 Item
: Element_Type
) return Cursor
1142 Result
: Tree_Node_Access
;
1145 if Position
= No_Element
then
1146 raise Constraint_Error
with "Position cursor has no element";
1149 -- Commented-out pending ruling from ARG. ???
1151 -- if Position.Container /= Container'Unrestricted_Access then
1152 -- raise Program_Error with "Position cursor not in container";
1155 if Is_Root
(Position
) then
1156 Result
:= Find_In_Children
(Position
.Node
, Item
);
1159 Result
:= Find_In_Subtree
(Position
.Node
, Item
);
1162 if Result
= null then
1166 return Cursor
'(Position.Container, Result);
1167 end Find_In_Subtree;
1169 function Find_In_Subtree
1170 (Subtree : Tree_Node_Access;
1171 Item : Element_Type) return Tree_Node_Access
1174 if Subtree.Element.all = Item then
1178 return Find_In_Children (Subtree, Item);
1179 end Find_In_Subtree;
1185 function Has_Element (Position : Cursor) return Boolean is
1187 if Position = No_Element then
1191 return Position.Node.Parent /= null;
1198 procedure Insert_Child
1199 (Container : in out Tree;
1202 New_Item : Element_Type;
1203 Count : Count_Type := 1)
1206 pragma Unreferenced (Position);
1209 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1212 procedure Insert_Child
1213 (Container : in out Tree;
1216 New_Item : Element_Type;
1217 Position : out Cursor;
1218 Count : Count_Type := 1)
1220 Last : Tree_Node_Access;
1221 Element : Element_Access;
1224 if Parent = No_Element then
1225 raise Constraint_Error with "Parent cursor has no element";
1228 if Parent.Container /= Container'Unrestricted_Access then
1229 raise Program_Error with "Parent cursor not in container";
1232 if Before /= No_Element then
1233 if Before.Container /= Container'Unrestricted_Access then
1234 raise Program_Error with "Before cursor not in container";
1237 if Before.Node.Parent /= Parent.Node then
1238 raise Constraint_Error with "Parent cursor not parent of Before";
1243 Position := No_Element; -- Need ruling from ARG ???
1247 if Container.Busy > 0 then
1249 with "attempt to tamper with cursors (tree is busy)";
1252 Position.Container := Parent.Container;
1255 -- The element allocator may need an accessibility check in the case
1256 -- the actual type is class-wide or has access discriminants (see
1257 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
1258 -- allocator in the loop below, because the one in this block would
1259 -- have failed already.
1261 pragma Unsuppress (Accessibility_Check);
1264 Element := new Element_Type'(New_Item
);
1267 Position
.Node
:= new Tree_Node_Type
'(Parent => Parent.Node,
1271 Last := Position.Node;
1273 for J in Count_Type'(2) .. Count
loop
1274 -- Reclaim other nodes if Storage_Error. ???
1276 Element
:= new Element_Type
'(New_Item);
1277 Last.Next := new Tree_Node_Type'(Parent
=> Parent
.Node
,
1286 (First
=> Position
.Node
,
1288 Parent
=> Parent
.Node
,
1289 Before
=> Before
.Node
);
1291 -- In order for operation Node_Count to complete in O(1) time, we cache
1292 -- the count value. Here we increment the total count by the number of
1293 -- nodes we just inserted.
1295 Container
.Count
:= Container
.Count
+ Count
;
1298 -------------------------
1299 -- Insert_Subtree_List --
1300 -------------------------
1302 procedure Insert_Subtree_List
1303 (First
: Tree_Node_Access
;
1304 Last
: Tree_Node_Access
;
1305 Parent
: Tree_Node_Access
;
1306 Before
: Tree_Node_Access
)
1308 pragma Assert
(Parent
/= null);
1309 C
: Children_Type
renames Parent
.Children
;
1312 -- This is a simple utility operation to insert a list of nodes (from
1313 -- First..Last) as children of Parent. The Before node specifies where
1314 -- the new children should be inserted relative to the existing
1317 if First
= null then
1318 pragma Assert
(Last
= null);
1322 pragma Assert
(Last
/= null);
1323 pragma Assert
(Before
= null or else Before
.Parent
= Parent
);
1325 if C
.First
= null then
1327 C
.First
.Prev
:= null;
1329 C
.Last
.Next
:= null;
1331 elsif Before
= null then -- means "insert after existing nodes"
1332 C
.Last
.Next
:= First
;
1333 First
.Prev
:= C
.Last
;
1335 C
.Last
.Next
:= null;
1337 elsif Before
= C
.First
then
1338 Last
.Next
:= C
.First
;
1339 C
.First
.Prev
:= Last
;
1341 C
.First
.Prev
:= null;
1344 Before
.Prev
.Next
:= First
;
1345 First
.Prev
:= Before
.Prev
;
1346 Last
.Next
:= Before
;
1347 Before
.Prev
:= Last
;
1349 end Insert_Subtree_List
;
1351 -------------------------
1352 -- Insert_Subtree_Node --
1353 -------------------------
1355 procedure Insert_Subtree_Node
1356 (Subtree
: Tree_Node_Access
;
1357 Parent
: Tree_Node_Access
;
1358 Before
: Tree_Node_Access
)
1361 -- This is a simple wrapper operation to insert a single child into the
1362 -- Parent's children list.
1369 end Insert_Subtree_Node
;
1375 function Is_Empty
(Container
: Tree
) return Boolean is
1377 return Container
.Root
.Children
.First
= null;
1384 function Is_Leaf
(Position
: Cursor
) return Boolean is
1386 if Position
= No_Element
then
1390 return Position
.Node
.Children
.First
= null;
1397 function Is_Reachable
(From
, To
: Tree_Node_Access
) return Boolean is
1398 pragma Assert
(From
/= null);
1399 pragma Assert
(To
/= null);
1401 N
: Tree_Node_Access
;
1405 while N
/= null loop
1420 function Is_Root
(Position
: Cursor
) return Boolean is
1422 if Position
.Container
= null then
1426 return Position
= Root
(Position
.Container
.all);
1435 Process
: not null access procedure (Position
: Cursor
))
1437 B
: Natural renames Container
'Unrestricted_Access.all.Busy
;
1443 (Container
=> Container
'Unrestricted_Access,
1444 Subtree
=> Root_Node
(Container
),
1445 Process
=> Process
);
1455 function Iterate
(Container
: Tree
)
1456 return Tree_Iterator_Interfaces
.Forward_Iterator
'Class
1459 return Iterate_Subtree
(Root
(Container
));
1462 ----------------------
1463 -- Iterate_Children --
1464 ----------------------
1466 procedure Iterate_Children
1468 Process
: not null access procedure (Position
: Cursor
))
1471 if Parent
= No_Element
then
1472 raise Constraint_Error
with "Parent cursor has no element";
1476 B
: Natural renames Parent
.Container
.Busy
;
1477 C
: Tree_Node_Access
;
1482 C
:= Parent
.Node
.Children
.First
;
1483 while C
/= null loop
1484 Process
(Position
=> Cursor
'(Parent.Container, Node => C));
1495 end Iterate_Children;
1497 procedure Iterate_Children
1498 (Container : Tree_Access;
1499 Subtree : Tree_Node_Access;
1500 Process : not null access procedure (Position : Cursor))
1502 Node : Tree_Node_Access;
1505 -- This is a helper function to recursively iterate over all the nodes
1506 -- in a subtree, in depth-first fashion. This particular helper just
1507 -- visits the children of this subtree, not the root of the subtree node
1508 -- itself. This is useful when starting from the ultimate root of the
1509 -- entire tree (see Iterate), as that root does not have an element.
1511 Node := Subtree.Children.First;
1512 while Node /= null loop
1513 Iterate_Subtree (Container, Node, Process);
1516 end Iterate_Children;
1518 function Iterate_Children
1521 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1523 C : constant Tree_Access := Container'Unrestricted_Access;
1524 B : Natural renames C.Busy;
1527 if Parent = No_Element then
1528 raise Constraint_Error with "Parent cursor has no element";
1531 if Parent.Container /= C then
1532 raise Program_Error with "Parent cursor not in container";
1535 return It : constant Child_Iterator :=
1536 Child_Iterator'(Limited_Controlled
with
1538 Subtree
=> Parent
.Node
)
1542 end Iterate_Children
;
1544 ---------------------
1545 -- Iterate_Subtree --
1546 ---------------------
1548 function Iterate_Subtree
1550 return Tree_Iterator_Interfaces
.Forward_Iterator
'Class
1553 if Position
= No_Element
then
1554 raise Constraint_Error
with "Position cursor has no element";
1557 -- Implement Vet for multiway trees???
1558 -- pragma Assert (Vet (Position), "bad subtree cursor");
1561 B
: Natural renames Position
.Container
.Busy
;
1563 return It
: constant Subtree_Iterator
:=
1564 (Limited_Controlled
with
1565 Container
=> Position
.Container
,
1566 Subtree
=> Position
.Node
)
1571 end Iterate_Subtree
;
1573 procedure Iterate_Subtree
1575 Process
: not null access procedure (Position
: Cursor
))
1578 if Position
= No_Element
then
1579 raise Constraint_Error
with "Position cursor has no element";
1583 B
: Natural renames Position
.Container
.Busy
;
1588 if Is_Root
(Position
) then
1589 Iterate_Children
(Position
.Container
, Position
.Node
, Process
);
1591 Iterate_Subtree
(Position
.Container
, Position
.Node
, Process
);
1601 end Iterate_Subtree
;
1603 procedure Iterate_Subtree
1604 (Container
: Tree_Access
;
1605 Subtree
: Tree_Node_Access
;
1606 Process
: not null access procedure (Position
: Cursor
))
1609 -- This is a helper function to recursively iterate over all the nodes
1610 -- in a subtree, in depth-first fashion. It first visits the root of the
1611 -- subtree, then visits its children.
1613 Process
(Cursor
'(Container, Subtree));
1614 Iterate_Children (Container, Subtree, Process);
1615 end Iterate_Subtree;
1621 overriding function Last (Object : Child_Iterator) return Cursor is
1623 return Last_Child (Cursor'(Object
.Container
, Object
.Subtree
));
1630 function Last_Child
(Parent
: Cursor
) return Cursor
is
1631 Node
: Tree_Node_Access
;
1634 if Parent
= No_Element
then
1635 raise Constraint_Error
with "Parent cursor has no element";
1638 Node
:= Parent
.Node
.Children
.Last
;
1644 return (Parent
.Container
, Node
);
1647 ------------------------
1648 -- Last_Child_Element --
1649 ------------------------
1651 function Last_Child_Element
(Parent
: Cursor
) return Element_Type
is
1653 return Element
(Last_Child
(Parent
));
1654 end Last_Child_Element
;
1660 procedure Move
(Target
: in out Tree
; Source
: in out Tree
) is
1661 Node
: Tree_Node_Access
;
1664 if Target
'Address = Source
'Address then
1668 if Source
.Busy
> 0 then
1670 with "attempt to tamper with cursors of Source (tree is busy)";
1673 Target
.Clear
; -- checks busy bit
1675 Target
.Root
.Children
:= Source
.Root
.Children
;
1676 Source
.Root
.Children
:= Children_Type
'(others => null);
1678 Node := Target.Root.Children.First;
1679 while Node /= null loop
1680 Node.Parent := Root_Node (Target);
1684 Target.Count := Source.Count;
1693 (Object : Subtree_Iterator;
1694 Position : Cursor) return Cursor
1696 Node : Tree_Node_Access;
1699 if Position.Container = null then
1703 if Position.Container /= Object.Container then
1704 raise Program_Error with
1705 "Position cursor of Next designates wrong tree";
1708 Node := Position.Node;
1710 if Node.Children.First /= null then
1711 return Cursor'(Object
.Container
, Node
.Children
.First
);
1714 while Node
/= Object
.Subtree
loop
1715 if Node
.Next
/= null then
1716 return Cursor
'(Object.Container, Node.Next);
1719 Node := Node.Parent;
1726 (Object : Child_Iterator;
1727 Position : Cursor) return Cursor
1730 if Position.Container = null then
1734 if Position.Container /= Object.Container then
1735 raise Program_Error with
1736 "Position cursor of Next designates wrong tree";
1739 return Next_Sibling (Position);
1746 function Next_Sibling (Position : Cursor) return Cursor is
1748 if Position = No_Element then
1752 if Position.Node.Next = null then
1756 return Cursor'(Position
.Container
, Position
.Node
.Next
);
1759 procedure Next_Sibling
(Position
: in out Cursor
) is
1761 Position
:= Next_Sibling
(Position
);
1768 function Node_Count
(Container
: Tree
) return Count_Type
is
1770 -- Container.Count is the number of nodes we have actually allocated. We
1771 -- cache the value specifically so this Node_Count operation can execute
1772 -- in O(1) time, which makes it behave similarly to how the Length
1773 -- selector function behaves for other containers.
1775 -- The cached node count value only describes the nodes we have
1776 -- allocated; the root node itself is not included in that count. The
1777 -- Node_Count operation returns a value that includes the root node
1778 -- (because the RM says so), so we must add 1 to our cached value.
1780 return 1 + Container
.Count
;
1787 function Parent
(Position
: Cursor
) return Cursor
is
1789 if Position
= No_Element
then
1793 if Position
.Node
.Parent
= null then
1797 return Cursor
'(Position.Container, Position.Node.Parent);
1804 procedure Prepend_Child
1805 (Container : in out Tree;
1807 New_Item : Element_Type;
1808 Count : Count_Type := 1)
1810 First, Last : Tree_Node_Access;
1811 Element : Element_Access;
1814 if Parent = No_Element then
1815 raise Constraint_Error with "Parent cursor has no element";
1818 if Parent.Container /= Container'Unrestricted_Access then
1819 raise Program_Error with "Parent cursor not in container";
1826 if Container.Busy > 0 then
1828 with "attempt to tamper with cursors (tree is busy)";
1832 -- The element allocator may need an accessibility check in the case
1833 -- the actual type is class-wide or has access discriminants (see
1834 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
1835 -- allocator in the loop below, because the one in this block would
1836 -- have failed already.
1838 pragma Unsuppress (Accessibility_Check);
1841 Element := new Element_Type'(New_Item
);
1844 First
:= new Tree_Node_Type
'(Parent => Parent.Node,
1850 for J in Count_Type'(2) .. Count
loop
1852 -- Reclaim other nodes if Storage_Error. ???
1854 Element
:= new Element_Type
'(New_Item);
1855 Last.Next := new Tree_Node_Type'(Parent
=> Parent
.Node
,
1866 Parent
=> Parent
.Node
,
1867 Before
=> Parent
.Node
.Children
.First
);
1869 -- In order for operation Node_Count to complete in O(1) time, we cache
1870 -- the count value. Here we increment the total count by the number of
1871 -- nodes we just inserted.
1873 Container
.Count
:= Container
.Count
+ Count
;
1880 overriding
function Previous
1881 (Object
: Child_Iterator
;
1882 Position
: Cursor
) return Cursor
1885 if Position
.Container
= null then
1889 if Position
.Container
/= Object
.Container
then
1890 raise Program_Error
with
1891 "Position cursor of Previous designates wrong tree";
1894 return Previous_Sibling
(Position
);
1897 ----------------------
1898 -- Previous_Sibling --
1899 ----------------------
1901 function Previous_Sibling
(Position
: Cursor
) return Cursor
is
1903 if Position
= No_Element
then
1907 if Position
.Node
.Prev
= null then
1911 return Cursor
'(Position.Container, Position.Node.Prev);
1912 end Previous_Sibling;
1914 procedure Previous_Sibling (Position : in out Cursor) is
1916 Position := Previous_Sibling (Position);
1917 end Previous_Sibling;
1923 procedure Query_Element
1925 Process : not null access procedure (Element : Element_Type))
1928 if Position = No_Element then
1929 raise Constraint_Error with "Position cursor has no element";
1932 if Is_Root (Position) then
1933 raise Program_Error with "Position cursor designates root";
1937 T : Tree renames Position.Container.all'Unrestricted_Access.all;
1938 B : Natural renames T.Busy;
1939 L : Natural renames T.Lock;
1945 Process (Position.Node.Element.all);
1963 (Stream : not null access Root_Stream_Type'Class;
1964 Container : out Tree)
1966 procedure Read_Children (Subtree : Tree_Node_Access);
1968 function Read_Subtree
1969 (Parent : Tree_Node_Access) return Tree_Node_Access;
1971 Total_Count : Count_Type'Base;
1972 -- Value read from the stream that says how many elements follow
1974 Read_Count : Count_Type'Base;
1975 -- Actual number of elements read from the stream
1981 procedure Read_Children (Subtree : Tree_Node_Access) is
1982 pragma Assert (Subtree /= null);
1983 pragma Assert (Subtree.Children.First = null);
1984 pragma Assert (Subtree.Children.Last = null);
1986 Count : Count_Type'Base;
1987 -- Number of child subtrees
1992 Count_Type'Read (Stream, Count);
1995 raise Program_Error with "attempt to read from corrupt stream";
2002 C.First := Read_Subtree (Parent => Subtree);
2005 for J in Count_Type'(2) .. Count
loop
2006 C
.Last
.Next
:= Read_Subtree
(Parent
=> Subtree
);
2007 C
.Last
.Next
.Prev
:= C
.Last
;
2008 C
.Last
:= C
.Last
.Next
;
2011 -- Now that the allocation and reads have completed successfully, it
2012 -- is safe to link the children to their parent.
2014 Subtree
.Children
:= C
;
2021 function Read_Subtree
2022 (Parent
: Tree_Node_Access
) return Tree_Node_Access
2024 Element
: constant Element_Access
:=
2025 new Element_Type
'(Element_Type'Input (Stream));
2027 Subtree : constant Tree_Node_Access :=
2029 (Parent
=> Parent
, Element
=> Element
, others => <>);
2032 Read_Count
:= Read_Count
+ 1;
2034 Read_Children
(Subtree
);
2039 -- Start of processing for Read
2042 Container
.Clear
; -- checks busy bit
2044 Count_Type
'Read (Stream
, Total_Count
);
2046 if Total_Count
< 0 then
2047 raise Program_Error
with "attempt to read from corrupt stream";
2050 if Total_Count
= 0 then
2056 Read_Children
(Root_Node
(Container
));
2058 if Read_Count
/= Total_Count
then
2059 raise Program_Error
with "attempt to read from corrupt stream";
2062 Container
.Count
:= Total_Count
;
2066 (Stream
: not null access Root_Stream_Type
'Class;
2067 Position
: out Cursor
)
2070 raise Program_Error
with "attempt to read tree cursor from stream";
2074 (Stream
: not null access Root_Stream_Type
'Class;
2075 Item
: out Reference_Type
)
2078 raise Program_Error
with "attempt to stream reference";
2082 (Stream
: not null access Root_Stream_Type
'Class;
2083 Item
: out Constant_Reference_Type
)
2086 raise Program_Error
with "attempt to stream reference";
2094 (Container
: aliased in out Tree
;
2095 Position
: Cursor
) return Reference_Type
2098 if Position
.Container
= null then
2099 raise Constraint_Error
with
2100 "Position cursor has no element";
2103 if Position
.Container
/= Container
'Unrestricted_Access then
2104 raise Program_Error
with
2105 "Position cursor designates wrong container";
2108 if Position
.Node
= Root_Node
(Container
) then
2109 raise Program_Error
with "Position cursor designates root";
2112 if Position
.Node
.Element
= null then
2113 raise Program_Error
with "Node has no element";
2116 -- Implement Vet for multiway tree???
2117 -- pragma Assert (Vet (Position),
2118 -- "Position cursor in Constant_Reference is bad");
2121 C
: Tree
renames Position
.Container
.all;
2122 B
: Natural renames C
.Busy
;
2123 L
: Natural renames C
.Lock
;
2125 return R
: constant Reference_Type
:=
2126 (Element
=> Position
.Node
.Element
.all'Access,
2127 Control
=> (Controlled
with Position
.Container
))
2135 --------------------
2136 -- Remove_Subtree --
2137 --------------------
2139 procedure Remove_Subtree
(Subtree
: Tree_Node_Access
) is
2140 C
: Children_Type
renames Subtree
.Parent
.Children
;
2143 -- This is a utility operation to remove a subtree node from its
2144 -- parent's list of children.
2146 if C
.First
= Subtree
then
2147 pragma Assert
(Subtree
.Prev
= null);
2149 if C
.Last
= Subtree
then
2150 pragma Assert
(Subtree
.Next
= null);
2155 C
.First
:= Subtree
.Next
;
2156 C
.First
.Prev
:= null;
2159 elsif C
.Last
= Subtree
then
2160 pragma Assert
(Subtree
.Next
= null);
2161 C
.Last
:= Subtree
.Prev
;
2162 C
.Last
.Next
:= null;
2165 Subtree
.Prev
.Next
:= Subtree
.Next
;
2166 Subtree
.Next
.Prev
:= Subtree
.Prev
;
2170 ----------------------
2171 -- Replace_Element --
2172 ----------------------
2174 procedure Replace_Element
2175 (Container
: in out Tree
;
2177 New_Item
: Element_Type
)
2179 E
, X
: Element_Access
;
2182 if Position
= No_Element
then
2183 raise Constraint_Error
with "Position cursor has no element";
2186 if Position
.Container
/= Container
'Unrestricted_Access then
2187 raise Program_Error
with "Position cursor not in container";
2190 if Is_Root
(Position
) then
2191 raise Program_Error
with "Position cursor designates root";
2194 if Container
.Lock
> 0 then
2196 with "attempt to tamper with elements (tree is locked)";
2200 -- The element allocator may need an accessibility check in the case
2201 -- the actual type is class-wide or has access discriminants (see
2202 -- RM 4.8(10.1) and AI12-0035).
2204 pragma Unsuppress
(Accessibility_Check
);
2207 E
:= new Element_Type
'(New_Item);
2210 X := Position.Node.Element;
2211 Position.Node.Element := E;
2214 end Replace_Element;
2216 ------------------------------
2217 -- Reverse_Iterate_Children --
2218 ------------------------------
2220 procedure Reverse_Iterate_Children
2222 Process : not null access procedure (Position : Cursor))
2225 if Parent = No_Element then
2226 raise Constraint_Error with "Parent cursor has no element";
2230 B : Natural renames Parent.Container.Busy;
2231 C : Tree_Node_Access;
2236 C := Parent.Node.Children.Last;
2237 while C /= null loop
2238 Process (Position => Cursor'(Parent
.Container
, Node
=> C
));
2249 end Reverse_Iterate_Children
;
2255 function Root
(Container
: Tree
) return Cursor
is
2257 return (Container
'Unrestricted_Access, Root_Node
(Container
));
2264 function Root_Node
(Container
: Tree
) return Tree_Node_Access
is
2266 return Container
.Root
'Unrestricted_Access;
2269 ---------------------
2270 -- Splice_Children --
2271 ---------------------
2273 procedure Splice_Children
2274 (Target
: in out Tree
;
2275 Target_Parent
: Cursor
;
2277 Source
: in out Tree
;
2278 Source_Parent
: Cursor
)
2283 if Target_Parent
= No_Element
then
2284 raise Constraint_Error
with "Target_Parent cursor has no element";
2287 if Target_Parent
.Container
/= Target
'Unrestricted_Access then
2289 with "Target_Parent cursor not in Target container";
2292 if Before
/= No_Element
then
2293 if Before
.Container
/= Target
'Unrestricted_Access then
2295 with "Before cursor not in Target container";
2298 if Before
.Node
.Parent
/= Target_Parent
.Node
then
2299 raise Constraint_Error
2300 with "Before cursor not child of Target_Parent";
2304 if Source_Parent
= No_Element
then
2305 raise Constraint_Error
with "Source_Parent cursor has no element";
2308 if Source_Parent
.Container
/= Source
'Unrestricted_Access then
2310 with "Source_Parent cursor not in Source container";
2313 if Target
'Address = Source
'Address then
2314 if Target_Parent
= Source_Parent
then
2318 if Target
.Busy
> 0 then
2320 with "attempt to tamper with cursors (Target tree is busy)";
2323 if Is_Reachable
(From
=> Target_Parent
.Node
,
2324 To
=> Source_Parent
.Node
)
2326 raise Constraint_Error
2327 with "Source_Parent is ancestor of Target_Parent";
2331 (Target_Parent
=> Target_Parent
.Node
,
2332 Before
=> Before
.Node
,
2333 Source_Parent
=> Source_Parent
.Node
);
2338 if Target
.Busy
> 0 then
2340 with "attempt to tamper with cursors (Target tree is busy)";
2343 if Source
.Busy
> 0 then
2345 with "attempt to tamper with cursors (Source tree is busy)";
2348 -- We cache the count of the nodes we have allocated, so that operation
2349 -- Node_Count can execute in O(1) time. But that means we must count the
2350 -- nodes in the subtree we remove from Source and insert into Target, in
2351 -- order to keep the count accurate.
2353 Count
:= Subtree_Node_Count
(Source_Parent
.Node
);
2354 pragma Assert
(Count
>= 1);
2356 Count
:= Count
- 1; -- because Source_Parent node does not move
2359 (Target_Parent
=> Target_Parent
.Node
,
2360 Before
=> Before
.Node
,
2361 Source_Parent
=> Source_Parent
.Node
);
2363 Source
.Count
:= Source
.Count
- Count
;
2364 Target
.Count
:= Target
.Count
+ Count
;
2365 end Splice_Children
;
2367 procedure Splice_Children
2368 (Container
: in out Tree
;
2369 Target_Parent
: Cursor
;
2371 Source_Parent
: Cursor
)
2374 if Target_Parent
= No_Element
then
2375 raise Constraint_Error
with "Target_Parent cursor has no element";
2378 if Target_Parent
.Container
/= Container
'Unrestricted_Access then
2380 with "Target_Parent cursor not in container";
2383 if Before
/= No_Element
then
2384 if Before
.Container
/= Container
'Unrestricted_Access then
2386 with "Before cursor not in container";
2389 if Before
.Node
.Parent
/= Target_Parent
.Node
then
2390 raise Constraint_Error
2391 with "Before cursor not child of Target_Parent";
2395 if Source_Parent
= No_Element
then
2396 raise Constraint_Error
with "Source_Parent cursor has no element";
2399 if Source_Parent
.Container
/= Container
'Unrestricted_Access then
2401 with "Source_Parent cursor not in container";
2404 if Target_Parent
= Source_Parent
then
2408 if Container
.Busy
> 0 then
2410 with "attempt to tamper with cursors (tree is busy)";
2413 if Is_Reachable
(From
=> Target_Parent
.Node
,
2414 To
=> Source_Parent
.Node
)
2416 raise Constraint_Error
2417 with "Source_Parent is ancestor of Target_Parent";
2421 (Target_Parent
=> Target_Parent
.Node
,
2422 Before
=> Before
.Node
,
2423 Source_Parent
=> Source_Parent
.Node
);
2424 end Splice_Children
;
2426 procedure Splice_Children
2427 (Target_Parent
: Tree_Node_Access
;
2428 Before
: Tree_Node_Access
;
2429 Source_Parent
: Tree_Node_Access
)
2431 CC
: constant Children_Type
:= Source_Parent
.Children
;
2432 C
: Tree_Node_Access
;
2435 -- This is a utility operation to remove the children from Source parent
2436 -- and insert them into Target parent.
2438 Source_Parent
.Children
:= Children_Type
'(others => null);
2440 -- Fix up the Parent pointers of each child to designate its new Target
2444 while C /= null loop
2445 C.Parent := Target_Parent;
2452 Parent => Target_Parent,
2454 end Splice_Children;
2456 --------------------
2457 -- Splice_Subtree --
2458 --------------------
2460 procedure Splice_Subtree
2461 (Target : in out Tree;
2464 Source : in out Tree;
2465 Position : in out Cursor)
2467 Subtree_Count : Count_Type;
2470 if Parent = No_Element then
2471 raise Constraint_Error with "Parent cursor has no element";
2474 if Parent.Container /= Target'Unrestricted_Access then
2475 raise Program_Error with "Parent cursor not in Target container";
2478 if Before /= No_Element then
2479 if Before.Container /= Target'Unrestricted_Access then
2480 raise Program_Error with "Before cursor not in Target container";
2483 if Before.Node.Parent /= Parent.Node then
2484 raise Constraint_Error with "Before cursor not child of Parent";
2488 if Position = No_Element then
2489 raise Constraint_Error with "Position cursor has no element";
2492 if Position.Container /= Source'Unrestricted_Access then
2493 raise Program_Error with "Position cursor not in Source container";
2496 if Is_Root (Position) then
2497 raise Program_Error with "Position cursor designates root";
2500 if Target'Address = Source'Address then
2501 if Position.Node.Parent = Parent.Node then
2502 if Position.Node = Before.Node then
2506 if Position.Node.Next = Before.Node then
2511 if Target.Busy > 0 then
2513 with "attempt to tamper with cursors (Target tree is busy)";
2516 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2517 raise Constraint_Error with "Position is ancestor of Parent";
2520 Remove_Subtree (Position.Node);
2522 Position.Node.Parent := Parent.Node;
2523 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2528 if Target.Busy > 0 then
2530 with "attempt to tamper with cursors (Target tree is busy)";
2533 if Source.Busy > 0 then
2535 with "attempt to tamper with cursors (Source tree is busy)";
2538 -- This is an unfortunate feature of this API: we must count the nodes
2539 -- in the subtree that we remove from the source tree, which is an O(n)
2540 -- operation. It would have been better if the Tree container did not
2541 -- have a Node_Count selector; a user that wants the number of nodes in
2542 -- the tree could simply call Subtree_Node_Count, with the understanding
2543 -- that such an operation is O(n).
2545 -- Of course, we could choose to implement the Node_Count selector as an
2546 -- O(n) operation, which would turn this splice operation into an O(1)
2549 Subtree_Count := Subtree_Node_Count (Position.Node);
2550 pragma Assert (Subtree_Count <= Source.Count);
2552 Remove_Subtree (Position.Node);
2553 Source.Count := Source.Count - Subtree_Count;
2555 Position.Node.Parent := Parent.Node;
2556 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2558 Target.Count := Target.Count + Subtree_Count;
2560 Position.Container := Target'Unrestricted_Access;
2563 procedure Splice_Subtree
2564 (Container : in out Tree;
2570 if Parent = No_Element then
2571 raise Constraint_Error with "Parent cursor has no element";
2574 if Parent.Container /= Container'Unrestricted_Access then
2575 raise Program_Error with "Parent cursor not in container";
2578 if Before /= No_Element then
2579 if Before.Container /= Container'Unrestricted_Access then
2580 raise Program_Error with "Before cursor not in container";
2583 if Before.Node.Parent /= Parent.Node then
2584 raise Constraint_Error with "Before cursor not child of Parent";
2588 if Position = No_Element then
2589 raise Constraint_Error with "Position cursor has no element";
2592 if Position.Container /= Container'Unrestricted_Access then
2593 raise Program_Error with "Position cursor not in container";
2596 if Is_Root (Position) then
2598 -- Should this be PE instead? Need ARG confirmation. ???
2600 raise Constraint_Error with "Position cursor designates root";
2603 if Position.Node.Parent = Parent.Node then
2604 if Position.Node = Before.Node then
2608 if Position.Node.Next = Before.Node then
2613 if Container.Busy > 0 then
2615 with "attempt to tamper with cursors (tree is busy)";
2618 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2619 raise Constraint_Error with "Position is ancestor of Parent";
2622 Remove_Subtree (Position.Node);
2624 Position.Node.Parent := Parent.Node;
2625 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2628 ------------------------
2629 -- Subtree_Node_Count --
2630 ------------------------
2632 function Subtree_Node_Count (Position : Cursor) return Count_Type is
2634 if Position = No_Element then
2638 return Subtree_Node_Count (Position.Node);
2639 end Subtree_Node_Count;
2641 function Subtree_Node_Count
2642 (Subtree : Tree_Node_Access) return Count_Type
2644 Result : Count_Type;
2645 Node : Tree_Node_Access;
2649 Node := Subtree.Children.First;
2650 while Node /= null loop
2651 Result := Result + Subtree_Node_Count (Node);
2656 end Subtree_Node_Count;
2663 (Container : in out Tree;
2667 if I = No_Element then
2668 raise Constraint_Error with "I cursor has no element";
2671 if I.Container /= Container'Unrestricted_Access then
2672 raise Program_Error with "I cursor not in container";
2676 raise Program_Error with "I cursor designates root";
2679 if I = J then -- make this test sooner???
2683 if J = No_Element then
2684 raise Constraint_Error with "J cursor has no element";
2687 if J.Container /= Container'Unrestricted_Access then
2688 raise Program_Error with "J cursor not in container";
2692 raise Program_Error with "J cursor designates root";
2695 if Container.Lock > 0 then
2697 with "attempt to tamper with elements (tree is locked)";
2701 EI : constant Element_Access := I.Node.Element;
2704 I.Node.Element := J.Node.Element;
2705 J.Node.Element := EI;
2709 --------------------
2710 -- Update_Element --
2711 --------------------
2713 procedure Update_Element
2714 (Container : in out Tree;
2716 Process : not null access procedure (Element : in out Element_Type))
2719 if Position = No_Element then
2720 raise Constraint_Error with "Position cursor has no element";
2723 if Position.Container /= Container'Unrestricted_Access then
2724 raise Program_Error with "Position cursor not in container";
2727 if Is_Root (Position) then
2728 raise Program_Error with "Position cursor designates root";
2732 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2733 B : Natural renames T.Busy;
2734 L : Natural renames T.Lock;
2740 Process (Position.Node.Element.all);
2758 (Stream : not null access Root_Stream_Type'Class;
2761 procedure Write_Children (Subtree : Tree_Node_Access);
2762 procedure Write_Subtree (Subtree : Tree_Node_Access);
2764 --------------------
2765 -- Write_Children --
2766 --------------------
2768 procedure Write_Children (Subtree : Tree_Node_Access) is
2769 CC : Children_Type renames Subtree.Children;
2770 C : Tree_Node_Access;
2773 Count_Type'Write (Stream, Child_Count (CC));
2776 while C /= null loop
2786 procedure Write_Subtree (Subtree : Tree_Node_Access) is
2788 Element_Type'Output (Stream, Subtree.Element.all);
2789 Write_Children (Subtree);
2792 -- Start of processing for Write
2795 Count_Type'Write (Stream, Container.Count);
2797 if Container.Count = 0 then
2801 Write_Children (Root_Node (Container));
2805 (Stream : not null access Root_Stream_Type'Class;
2809 raise Program_Error with "attempt to write tree cursor to stream";
2813 (Stream : not null access Root_Stream_Type'Class;
2814 Item : Reference_Type)
2817 raise Program_Error with "attempt to stream reference";
2821 (Stream : not null access Root_Stream_Type'Class;
2822 Item : Constant_Reference_Type)
2825 raise Program_Error with "attempt to stream reference";
2828 end Ada.Containers.Indefinite_Multiway_Trees;