1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.BOUNDED_MULTIWAY_TREES --
9 -- Copyright (C) 2011-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 System
; use type System
.Address
;
32 package body Ada
.Containers
.Bounded_Multiway_Trees
is
34 pragma Annotate
(CodePeer
, Skip_Analysis
);
40 type Root_Iterator
is abstract new Limited_Controlled
and
41 Tree_Iterator_Interfaces
.Forward_Iterator
with
43 Container
: Tree_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 procedure Initialize_Node
(Container
: in out Tree
; Index
: Count_Type
);
85 procedure Initialize_Root
(Container
: in out Tree
);
87 procedure Allocate_Node
88 (Container
: in out Tree
;
89 Initialize_Element
: not null access procedure (Index
: Count_Type
);
90 New_Node
: out Count_Type
);
92 procedure Allocate_Node
93 (Container
: in out Tree
;
94 New_Item
: Element_Type
;
95 New_Node
: out Count_Type
);
97 procedure Allocate_Node
98 (Container
: in out Tree
;
99 Stream
: not null access Root_Stream_Type
'Class;
100 New_Node
: out Count_Type
);
102 procedure Deallocate_Node
103 (Container
: in out Tree
;
106 procedure Deallocate_Children
107 (Container
: in out Tree
;
108 Subtree
: Count_Type
;
109 Count
: in out Count_Type
);
111 procedure Deallocate_Subtree
112 (Container
: in out Tree
;
113 Subtree
: Count_Type
;
114 Count
: in out Count_Type
);
116 function Equal_Children
118 Left_Subtree
: Count_Type
;
120 Right_Subtree
: Count_Type
) return Boolean;
122 function Equal_Subtree
124 Left_Subtree
: Count_Type
;
126 Right_Subtree
: Count_Type
) return Boolean;
128 procedure Iterate_Children
130 Subtree
: Count_Type
;
131 Process
: not null access procedure (Position
: Cursor
));
133 procedure Iterate_Subtree
135 Subtree
: Count_Type
;
136 Process
: not null access procedure (Position
: Cursor
));
138 procedure Copy_Children
140 Source_Parent
: Count_Type
;
141 Target
: in out Tree
;
142 Target_Parent
: Count_Type
;
143 Count
: in out Count_Type
);
145 procedure Copy_Subtree
147 Source_Subtree
: Count_Type
;
148 Target
: in out Tree
;
149 Target_Parent
: Count_Type
;
150 Target_Subtree
: out Count_Type
;
151 Count
: in out Count_Type
);
153 function Find_In_Children
155 Subtree
: Count_Type
;
156 Item
: Element_Type
) return Count_Type
;
158 function Find_In_Subtree
160 Subtree
: Count_Type
;
161 Item
: Element_Type
) return Count_Type
;
165 Parent
: Count_Type
) return Count_Type
;
167 function Subtree_Node_Count
169 Subtree
: Count_Type
) return Count_Type
;
171 function Is_Reachable
173 From
, To
: Count_Type
) return Boolean;
175 function Root_Node
(Container
: Tree
) return Count_Type
;
177 procedure Remove_Subtree
178 (Container
: in out Tree
;
179 Subtree
: Count_Type
);
181 procedure Insert_Subtree_Node
182 (Container
: in out Tree
;
183 Subtree
: Count_Type
'Base;
185 Before
: Count_Type
'Base);
187 procedure Insert_Subtree_List
188 (Container
: in out Tree
;
189 First
: Count_Type
'Base;
190 Last
: Count_Type
'Base;
192 Before
: Count_Type
'Base);
194 procedure Splice_Children
195 (Container
: in out Tree
;
196 Target_Parent
: Count_Type
;
197 Before
: Count_Type
'Base;
198 Source_Parent
: Count_Type
);
200 procedure Splice_Children
201 (Target
: in out Tree
;
202 Target_Parent
: Count_Type
;
203 Before
: Count_Type
'Base;
204 Source
: in out Tree
;
205 Source_Parent
: Count_Type
);
207 procedure Splice_Subtree
208 (Target
: in out Tree
;
210 Before
: Count_Type
'Base;
211 Source
: in out Tree
;
212 Position
: in out Count_Type
); -- source on input, target on output
218 function "=" (Left
, Right
: Tree
) return Boolean is
220 if Left
'Address = Right
'Address then
224 if Left
.Count
/= Right
.Count
then
228 if Left
.Count
= 0 then
232 return Equal_Children
234 Left_Subtree
=> Root_Node
(Left
),
236 Right_Subtree
=> Root_Node
(Right
));
243 procedure Adjust
(Control
: in out Reference_Control_Type
) is
245 if Control
.Container
/= null then
247 C
: Tree
renames Control
.Container
.all;
248 B
: Natural renames C
.Busy
;
249 L
: Natural renames C
.Lock
;
261 procedure Allocate_Node
262 (Container
: in out Tree
;
263 Initialize_Element
: not null access procedure (Index
: Count_Type
);
264 New_Node
: out Count_Type
)
267 if Container
.Free
>= 0 then
268 New_Node
:= Container
.Free
;
269 pragma Assert
(New_Node
in Container
.Elements
'Range);
271 -- We always perform the assignment first, before we change container
272 -- state, in order to defend against exceptions duration assignment.
274 Initialize_Element
(New_Node
);
276 Container
.Free
:= Container
.Nodes
(New_Node
).Next
;
279 -- A negative free store value means that the links of the nodes in
280 -- the free store have not been initialized. In this case, the nodes
281 -- are physically contiguous in the array, starting at the index that
282 -- is the absolute value of the Container.Free, and continuing until
283 -- the end of the array (Nodes'Last).
285 New_Node
:= abs Container
.Free
;
286 pragma Assert
(New_Node
in Container
.Elements
'Range);
288 -- As above, we perform this assignment first, before modifying any
291 Initialize_Element
(New_Node
);
293 Container
.Free
:= Container
.Free
- 1;
295 if abs Container
.Free
> Container
.Capacity
then
300 Initialize_Node
(Container
, New_Node
);
303 procedure Allocate_Node
304 (Container
: in out Tree
;
305 New_Item
: Element_Type
;
306 New_Node
: out Count_Type
)
308 procedure Initialize_Element
(Index
: Count_Type
);
310 procedure Initialize_Element
(Index
: Count_Type
) is
312 Container
.Elements
(Index
) := New_Item
;
313 end Initialize_Element
;
316 Allocate_Node
(Container
, Initialize_Element
'Access, New_Node
);
319 procedure Allocate_Node
320 (Container
: in out Tree
;
321 Stream
: not null access Root_Stream_Type
'Class;
322 New_Node
: out Count_Type
)
324 procedure Initialize_Element
(Index
: Count_Type
);
326 procedure Initialize_Element
(Index
: Count_Type
) is
328 Element_Type
'Read (Stream
, Container
.Elements
(Index
));
329 end Initialize_Element
;
332 Allocate_Node
(Container
, Initialize_Element
'Access, New_Node
);
339 function Ancestor_Find
341 Item
: Element_Type
) return Cursor
346 if Position
= No_Element
then
347 raise Constraint_Error
with "Position cursor has no element";
350 -- AI-0136 says to raise PE if Position equals the root node. This does
351 -- not seem correct, as this value is just the limiting condition of the
352 -- search. For now we omit this check, pending a ruling from the ARG.
355 -- if Is_Root (Position) then
356 -- raise Program_Error with "Position cursor designates root";
359 R
:= Root_Node
(Position
.Container
.all);
362 if Position
.Container
.Elements
(N
) = Item
then
363 return Cursor
'(Position.Container, N);
366 N := Position.Container.Nodes (N).Parent;
376 procedure Append_Child
377 (Container : in out Tree;
379 New_Item : Element_Type;
380 Count : Count_Type := 1)
382 Nodes : Tree_Node_Array renames Container.Nodes;
383 First, Last : Count_Type;
386 if Parent = No_Element then
387 raise Constraint_Error with "Parent cursor has no element";
390 if Parent.Container /= Container'Unrestricted_Access then
391 raise Program_Error with "Parent cursor not in container";
398 if Container.Count > Container.Capacity - Count then
400 with "requested count exceeds available storage";
403 if Container.Busy > 0 then
405 with "attempt to tamper with cursors (tree is busy)";
408 if Container.Count = 0 then
409 Initialize_Root (Container);
412 Allocate_Node (Container, New_Item, First);
413 Nodes (First).Parent := Parent.Node;
416 for J in Count_Type'(2) .. Count
loop
417 Allocate_Node
(Container
, New_Item
, Nodes
(Last
).Next
);
418 Nodes
(Nodes
(Last
).Next
).Parent
:= Parent
.Node
;
419 Nodes
(Nodes
(Last
).Next
).Prev
:= Last
;
421 Last
:= Nodes
(Last
).Next
;
425 (Container
=> Container
,
428 Parent
=> Parent
.Node
,
429 Before
=> No_Node
); -- means "insert at end of list"
431 Container
.Count
:= Container
.Count
+ Count
;
438 procedure Assign
(Target
: in out Tree
; Source
: Tree
) is
439 Target_Count
: Count_Type
;
442 if Target
'Address = Source
'Address then
446 if Target
.Capacity
< Source
.Count
then
447 raise Capacity_Error
-- ???
448 with "Target capacity is less than Source count";
451 Target
.Clear
; -- Checks busy bit
453 if Source
.Count
= 0 then
457 Initialize_Root
(Target
);
459 -- Copy_Children returns the number of nodes that it allocates, but it
460 -- does this by incrementing the count value passed in, so we must
461 -- initialize the count before calling Copy_Children.
467 Source_Parent
=> Root_Node
(Source
),
469 Target_Parent
=> Root_Node
(Target
),
470 Count
=> Target_Count
);
472 pragma Assert
(Target_Count
= Source
.Count
);
473 Target
.Count
:= Source
.Count
;
480 function Child_Count
(Parent
: Cursor
) return Count_Type
is
482 if Parent
= No_Element
then
485 elsif Parent
.Container
.Count
= 0 then
486 pragma Assert
(Is_Root
(Parent
));
490 return Child_Count
(Parent
.Container
.all, Parent
.Node
);
496 Parent
: Count_Type
) return Count_Type
498 NN
: Tree_Node_Array
renames Container
.Nodes
;
499 CC
: Children_Type
renames NN
(Parent
).Children
;
502 Node
: Count_Type
'Base;
508 Result
:= Result
+ 1;
509 Node
:= NN
(Node
).Next
;
519 function Child_Depth
(Parent
, Child
: Cursor
) return Count_Type
is
524 if Parent
= No_Element
then
525 raise Constraint_Error
with "Parent cursor has no element";
528 if Child
= No_Element
then
529 raise Constraint_Error
with "Child cursor has no element";
532 if Parent
.Container
/= Child
.Container
then
533 raise Program_Error
with "Parent and Child in different containers";
536 if Parent
.Container
.Count
= 0 then
537 pragma Assert
(Is_Root
(Parent
));
538 pragma Assert
(Child
= Parent
);
544 while N
/= Parent
.Node
loop
545 Result
:= Result
+ 1;
546 N
:= Parent
.Container
.Nodes
(N
).Parent
;
549 raise Program_Error
with "Parent is not ancestor of Child";
560 procedure Clear
(Container
: in out Tree
) is
561 Container_Count
: constant Count_Type
:= Container
.Count
;
565 if Container
.Busy
> 0 then
567 with "attempt to tamper with cursors (tree is busy)";
570 if Container_Count
= 0 then
574 Container
.Count
:= 0;
576 -- Deallocate_Children returns the number of nodes that it deallocates,
577 -- but it does this by incrementing the count value that is passed in,
578 -- so we must first initialize the count return value before calling it.
583 (Container
=> Container
,
584 Subtree
=> Root_Node
(Container
),
587 pragma Assert
(Count
= Container_Count
);
590 ------------------------
591 -- Constant_Reference --
592 ------------------------
594 function Constant_Reference
595 (Container
: aliased Tree
;
596 Position
: Cursor
) return Constant_Reference_Type
599 if Position
.Container
= null then
600 raise Constraint_Error
with
601 "Position cursor has no element";
604 if Position
.Container
/= Container
'Unrestricted_Access then
605 raise Program_Error
with
606 "Position cursor designates wrong container";
609 if Position
.Node
= Root_Node
(Container
) then
610 raise Program_Error
with "Position cursor designates root";
613 -- Implement Vet for multiway tree???
614 -- pragma Assert (Vet (Position),
615 -- "Position cursor in Constant_Reference is bad");
618 C
: Tree
renames Position
.Container
.all;
619 B
: Natural renames C
.Busy
;
620 L
: Natural renames C
.Lock
;
623 return R
: constant Constant_Reference_Type
:=
624 (Element
=> Container
.Elements
(Position
.Node
)'Access,
625 Control
=> (Controlled
with Container
'Unrestricted_Access))
631 end Constant_Reference
;
639 Item
: Element_Type
) return Boolean
642 return Find
(Container
, Item
) /= No_Element
;
651 Capacity
: Count_Type
:= 0) return Tree
658 elsif Capacity
>= Source
.Count
then
661 raise Capacity_Error
with "Capacity value too small";
664 return Target
: Tree
(Capacity
=> C
) do
665 Initialize_Root
(Target
);
667 if Source
.Count
= 0 then
673 Source_Parent
=> Root_Node
(Source
),
675 Target_Parent
=> Root_Node
(Target
),
676 Count
=> Target
.Count
);
678 pragma Assert
(Target
.Count
= Source
.Count
);
686 procedure Copy_Children
688 Source_Parent
: Count_Type
;
689 Target
: in out Tree
;
690 Target_Parent
: Count_Type
;
691 Count
: in out Count_Type
)
693 S_Nodes
: Tree_Node_Array
renames Source
.Nodes
;
694 S_Node
: Tree_Node_Type
renames S_Nodes
(Source_Parent
);
696 T_Nodes
: Tree_Node_Array
renames Target
.Nodes
;
697 T_Node
: Tree_Node_Type
renames T_Nodes
(Target_Parent
);
699 pragma Assert
(T_Node
.Children
.First
<= 0);
700 pragma Assert
(T_Node
.Children
.Last
<= 0);
702 T_CC
: Children_Type
;
706 -- We special-case the first allocation, in order to establish the
707 -- representation invariants for type Children_Type.
709 C
:= S_Node
.Children
.First
;
711 if C
<= 0 then -- source parent has no children
719 Target_Parent
=> Target_Parent
,
720 Target_Subtree
=> T_CC
.First
,
723 T_CC
.Last
:= T_CC
.First
;
725 -- The representation invariants for the Children_Type list have been
726 -- established, so we can now copy the remaining children of Source.
728 C
:= S_Nodes
(C
).Next
;
734 Target_Parent
=> Target_Parent
,
735 Target_Subtree
=> T_Nodes
(T_CC
.Last
).Next
,
738 T_Nodes
(T_Nodes
(T_CC
.Last
).Next
).Prev
:= T_CC
.Last
;
739 T_CC
.Last
:= T_Nodes
(T_CC
.Last
).Next
;
741 C
:= S_Nodes
(C
).Next
;
744 -- We add the newly-allocated children to their parent list only after
745 -- the allocation has succeeded, in order to preserve invariants of the
748 T_Node
.Children
:= T_CC
;
755 procedure Copy_Subtree
756 (Target
: in out Tree
;
761 Target_Subtree
: Count_Type
;
762 Target_Count
: Count_Type
;
765 if Parent
= No_Element
then
766 raise Constraint_Error
with "Parent cursor has no element";
769 if Parent
.Container
/= Target
'Unrestricted_Access then
770 raise Program_Error
with "Parent cursor not in container";
773 if Before
/= No_Element
then
774 if Before
.Container
/= Target
'Unrestricted_Access then
775 raise Program_Error
with "Before cursor not in container";
778 if Before
.Container
.Nodes
(Before
.Node
).Parent
/= Parent
.Node
then
779 raise Constraint_Error
with "Before cursor not child of Parent";
783 if Source
= No_Element
then
787 if Is_Root
(Source
) then
788 raise Constraint_Error
with "Source cursor designates root";
791 if Target
.Count
= 0 then
792 Initialize_Root
(Target
);
795 -- Copy_Subtree returns a count of the number of nodes that it
796 -- allocates, but it works by incrementing the value that is passed
797 -- in. We must therefore initialize the count value before calling
803 (Source
=> Source
.Container
.all,
804 Source_Subtree
=> Source
.Node
,
806 Target_Parent
=> Parent
.Node
,
807 Target_Subtree
=> Target_Subtree
,
808 Count
=> Target_Count
);
811 (Container
=> Target
,
812 Subtree
=> Target_Subtree
,
813 Parent
=> Parent
.Node
,
814 Before
=> Before
.Node
);
816 Target
.Count
:= Target
.Count
+ Target_Count
;
819 procedure Copy_Subtree
821 Source_Subtree
: Count_Type
;
822 Target
: in out Tree
;
823 Target_Parent
: Count_Type
;
824 Target_Subtree
: out Count_Type
;
825 Count
: in out Count_Type
)
827 T_Nodes
: Tree_Node_Array
renames Target
.Nodes
;
830 -- First we allocate the root of the target subtree.
833 (Container
=> Target
,
834 New_Item
=> Source
.Elements
(Source_Subtree
),
835 New_Node
=> Target_Subtree
);
837 T_Nodes
(Target_Subtree
).Parent
:= Target_Parent
;
840 -- We now have a new subtree (for the Target tree), containing only a
841 -- copy of the corresponding element in the Source subtree. Next we copy
842 -- the children of the Source subtree as children of the new Target
847 Source_Parent
=> Source_Subtree
,
849 Target_Parent
=> Target_Subtree
,
853 -------------------------
854 -- Deallocate_Children --
855 -------------------------
857 procedure Deallocate_Children
858 (Container
: in out Tree
;
859 Subtree
: Count_Type
;
860 Count
: in out Count_Type
)
862 Nodes
: Tree_Node_Array
renames Container
.Nodes
;
863 Node
: Tree_Node_Type
renames Nodes
(Subtree
); -- parent
864 CC
: Children_Type
renames Node
.Children
;
868 while CC
.First
> 0 loop
870 CC
.First
:= Nodes
(C
).Next
;
872 Deallocate_Subtree
(Container
, C
, Count
);
876 end Deallocate_Children
;
878 ---------------------
879 -- Deallocate_Node --
880 ---------------------
882 procedure Deallocate_Node
883 (Container
: in out Tree
;
886 NN
: Tree_Node_Array
renames Container
.Nodes
;
887 pragma Assert
(X
> 0);
888 pragma Assert
(X
<= NN
'Last);
890 N
: Tree_Node_Type
renames NN
(X
);
891 pragma Assert
(N
.Parent
/= X
); -- node is active
894 -- The tree container actually contains two lists: one for the "active"
895 -- nodes that contain elements that have been inserted onto the tree,
896 -- and another for the "inactive" nodes of the free store, from which
897 -- nodes are allocated when a new child is inserted in the tree.
899 -- We desire that merely declaring a tree object should have only
900 -- minimal cost; specially, we want to avoid having to initialize the
901 -- free store (to fill in the links), especially if the capacity of the
902 -- tree object is large.
904 -- The head of the free list is indicated by Container.Free. If its
905 -- value is non-negative, then the free store has been initialized in
906 -- the "normal" way: Container.Free points to the head of the list of
907 -- free (inactive) nodes, and the value 0 means the free list is
908 -- empty. Each node on the free list has been initialized to point to
909 -- the next free node (via its Next component), and the value 0 means
910 -- that this is the last node of the free list.
912 -- If Container.Free is negative, then the links on the free store have
913 -- not been initialized. In this case the link values are implied: the
914 -- free store comprises the components of the node array started with
915 -- the absolute value of Container.Free, and continuing until the end of
916 -- the array (Nodes'Last).
918 -- We prefer to lazy-init the free store (in fact, we would prefer to
919 -- not initialize it at all, because such initialization is an O(n)
920 -- operation). The time when we need to actually initialize the nodes in
921 -- the free store is when the node that becomes inactive is not at the
922 -- end of the active list. The free store would then be discontigous and
923 -- so its nodes would need to be linked in the traditional way.
925 -- It might be possible to perform an optimization here. Suppose that
926 -- the free store can be represented as having two parts: one comprising
927 -- the non-contiguous inactive nodes linked together in the normal way,
928 -- and the other comprising the contiguous inactive nodes (that are not
929 -- linked together, at the end of the nodes array). This would allow us
930 -- to never have to initialize the free store, except in a lazy way as
931 -- nodes become inactive. ???
933 -- When an element is deleted from the list container, its node becomes
934 -- inactive, and so we set its Parent and Prev components to an
935 -- impossible value (the index of the node itself), to indicate that it
936 -- is now inactive. This provides a useful way to detect a dangling
939 N
.Parent
:= X
; -- Node is deallocated (not on active list)
942 if Container
.Free
>= 0 then
943 -- The free store has previously been initialized. All we need to do
944 -- here is link the newly-free'd node onto the free list.
946 N
.Next
:= Container
.Free
;
949 elsif X
+ 1 = abs Container
.Free
then
950 -- The free store has not been initialized, and the node becoming
951 -- inactive immediately precedes the start of the free store. All
952 -- we need to do is move the start of the free store back by one.
954 N
.Next
:= X
; -- Not strictly necessary, but marginally safer
955 Container
.Free
:= Container
.Free
+ 1;
958 -- The free store has not been initialized, and the node becoming
959 -- inactive does not immediately precede the free store. Here we
960 -- first initialize the free store (meaning the links are given
961 -- values in the traditional way), and then link the newly-free'd
962 -- node onto the head of the free store.
964 -- See the comments above for an optimization opportunity. If the
965 -- next link for a node on the free store is negative, then this
966 -- means the remaining nodes on the free store are physically
967 -- contiguous, starting at the absolute value of that index value.
970 Container
.Free
:= abs Container
.Free
;
972 if Container
.Free
> Container
.Capacity
then
976 for J
in Container
.Free
.. Container
.Capacity
- 1 loop
977 NN
(J
).Next
:= J
+ 1;
980 NN
(Container
.Capacity
).Next
:= 0;
983 NN
(X
).Next
:= Container
.Free
;
988 ------------------------
989 -- Deallocate_Subtree --
990 ------------------------
992 procedure Deallocate_Subtree
993 (Container
: in out Tree
;
994 Subtree
: Count_Type
;
995 Count
: in out Count_Type
)
998 Deallocate_Children
(Container
, Subtree
, Count
);
999 Deallocate_Node
(Container
, Subtree
);
1001 end Deallocate_Subtree
;
1003 ---------------------
1004 -- Delete_Children --
1005 ---------------------
1007 procedure Delete_Children
1008 (Container
: in out Tree
;
1014 if Parent
= No_Element
then
1015 raise Constraint_Error
with "Parent cursor has no element";
1018 if Parent
.Container
/= Container
'Unrestricted_Access then
1019 raise Program_Error
with "Parent cursor not in container";
1022 if Container
.Busy
> 0 then
1024 with "attempt to tamper with cursors (tree is busy)";
1027 if Container
.Count
= 0 then
1028 pragma Assert
(Is_Root
(Parent
));
1032 -- Deallocate_Children returns a count of the number of nodes that it
1033 -- deallocates, but it works by incrementing the value that is passed
1034 -- in. We must therefore initialize the count value before calling
1035 -- Deallocate_Children.
1039 Deallocate_Children
(Container
, Parent
.Node
, Count
);
1040 pragma Assert
(Count
<= Container
.Count
);
1042 Container
.Count
:= Container
.Count
- Count
;
1043 end Delete_Children
;
1049 procedure Delete_Leaf
1050 (Container
: in out Tree
;
1051 Position
: in out Cursor
)
1056 if Position
= No_Element
then
1057 raise Constraint_Error
with "Position cursor has no element";
1060 if Position
.Container
/= Container
'Unrestricted_Access then
1061 raise Program_Error
with "Position cursor not in container";
1064 if Is_Root
(Position
) then
1065 raise Program_Error
with "Position cursor designates root";
1068 if not Is_Leaf
(Position
) then
1069 raise Constraint_Error
with "Position cursor does not designate leaf";
1072 if Container
.Busy
> 0 then
1074 with "attempt to tamper with cursors (tree is busy)";
1078 Position
:= No_Element
;
1080 Remove_Subtree
(Container
, X
);
1081 Container
.Count
:= Container
.Count
- 1;
1083 Deallocate_Node
(Container
, X
);
1086 --------------------
1087 -- Delete_Subtree --
1088 --------------------
1090 procedure Delete_Subtree
1091 (Container
: in out Tree
;
1092 Position
: in out Cursor
)
1098 if Position
= No_Element
then
1099 raise Constraint_Error
with "Position cursor has no element";
1102 if Position
.Container
/= Container
'Unrestricted_Access then
1103 raise Program_Error
with "Position cursor not in container";
1106 if Is_Root
(Position
) then
1107 raise Program_Error
with "Position cursor designates root";
1110 if Container
.Busy
> 0 then
1112 with "attempt to tamper with cursors (tree is busy)";
1116 Position
:= No_Element
;
1118 Remove_Subtree
(Container
, X
);
1120 -- Deallocate_Subtree returns a count of the number of nodes that it
1121 -- deallocates, but it works by incrementing the value that is passed
1122 -- in. We must therefore initialize the count value before calling
1123 -- Deallocate_Subtree.
1127 Deallocate_Subtree
(Container
, X
, Count
);
1128 pragma Assert
(Count
<= Container
.Count
);
1130 Container
.Count
:= Container
.Count
- Count
;
1137 function Depth
(Position
: Cursor
) return Count_Type
is
1138 Result
: Count_Type
;
1139 N
: Count_Type
'Base;
1142 if Position
= No_Element
then
1146 if Is_Root
(Position
) then
1153 N
:= Position
.Container
.Nodes
(N
).Parent
;
1154 Result
:= Result
+ 1;
1164 function Element
(Position
: Cursor
) return Element_Type
is
1166 if Position
.Container
= null then
1167 raise Constraint_Error
with "Position cursor has no element";
1170 if Position
.Node
= Root_Node
(Position
.Container
.all) then
1171 raise Program_Error
with "Position cursor designates root";
1174 return Position
.Container
.Elements
(Position
.Node
);
1177 --------------------
1178 -- Equal_Children --
1179 --------------------
1181 function Equal_Children
1183 Left_Subtree
: Count_Type
;
1185 Right_Subtree
: Count_Type
) return Boolean
1187 L_NN
: Tree_Node_Array
renames Left_Tree
.Nodes
;
1188 R_NN
: Tree_Node_Array
renames Right_Tree
.Nodes
;
1190 Left_Children
: Children_Type
renames L_NN
(Left_Subtree
).Children
;
1191 Right_Children
: Children_Type
renames R_NN
(Right_Subtree
).Children
;
1193 L
, R
: Count_Type
'Base;
1196 if Child_Count
(Left_Tree
, Left_Subtree
)
1197 /= Child_Count
(Right_Tree
, Right_Subtree
)
1202 L
:= Left_Children
.First
;
1203 R
:= Right_Children
.First
;
1205 if not Equal_Subtree
(Left_Tree
, L
, Right_Tree
, R
) then
1220 function Equal_Subtree
1221 (Left_Position
: Cursor
;
1222 Right_Position
: Cursor
) return Boolean
1225 if Left_Position
= No_Element
then
1226 raise Constraint_Error
with "Left cursor has no element";
1229 if Right_Position
= No_Element
then
1230 raise Constraint_Error
with "Right cursor has no element";
1233 if Left_Position
= Right_Position
then
1237 if Is_Root
(Left_Position
) then
1238 if not Is_Root
(Right_Position
) then
1242 if Left_Position
.Container
.Count
= 0 then
1243 return Right_Position
.Container
.Count
= 0;
1246 if Right_Position
.Container
.Count
= 0 then
1250 return Equal_Children
1251 (Left_Tree
=> Left_Position
.Container
.all,
1252 Left_Subtree
=> Left_Position
.Node
,
1253 Right_Tree
=> Right_Position
.Container
.all,
1254 Right_Subtree
=> Right_Position
.Node
);
1257 if Is_Root
(Right_Position
) then
1261 return Equal_Subtree
1262 (Left_Tree
=> Left_Position
.Container
.all,
1263 Left_Subtree
=> Left_Position
.Node
,
1264 Right_Tree
=> Right_Position
.Container
.all,
1265 Right_Subtree
=> Right_Position
.Node
);
1268 function Equal_Subtree
1270 Left_Subtree
: Count_Type
;
1272 Right_Subtree
: Count_Type
) return Boolean
1275 if Left_Tree
.Elements
(Left_Subtree
) /=
1276 Right_Tree
.Elements
(Right_Subtree
)
1281 return Equal_Children
1282 (Left_Tree
=> Left_Tree
,
1283 Left_Subtree
=> Left_Subtree
,
1284 Right_Tree
=> Right_Tree
,
1285 Right_Subtree
=> Right_Subtree
);
1292 procedure Finalize
(Object
: in out Root_Iterator
) is
1293 B
: Natural renames Object
.Container
.Busy
;
1298 procedure Finalize
(Control
: in out Reference_Control_Type
) is
1300 if Control
.Container
/= null then
1302 C
: Tree
renames Control
.Container
.all;
1303 B
: Natural renames C
.Busy
;
1304 L
: Natural renames C
.Lock
;
1310 Control
.Container
:= null;
1320 Item
: Element_Type
) return Cursor
1325 if Container
.Count
= 0 then
1329 Node
:= Find_In_Children
(Container
, Root_Node
(Container
), Item
);
1335 return Cursor
'(Container'Unrestricted_Access, Node);
1342 overriding function First (Object : Subtree_Iterator) return Cursor is
1344 if Object.Subtree = Root_Node (Object.Container.all) then
1345 return First_Child (Root (Object.Container.all));
1347 return Cursor'(Object
.Container
, Object
.Subtree
);
1351 overriding
function First
(Object
: Child_Iterator
) return Cursor
is
1353 return First_Child
(Cursor
'(Object.Container, Object.Subtree));
1360 function First_Child (Parent : Cursor) return Cursor is
1361 Node : Count_Type'Base;
1364 if Parent = No_Element then
1365 raise Constraint_Error with "Parent cursor has no element";
1368 if Parent.Container.Count = 0 then
1369 pragma Assert (Is_Root (Parent));
1373 Node := Parent.Container.Nodes (Parent.Node).Children.First;
1379 return Cursor'(Parent
.Container
, Node
);
1382 -------------------------
1383 -- First_Child_Element --
1384 -------------------------
1386 function First_Child_Element
(Parent
: Cursor
) return Element_Type
is
1388 return Element
(First_Child
(Parent
));
1389 end First_Child_Element
;
1391 ----------------------
1392 -- Find_In_Children --
1393 ----------------------
1395 function Find_In_Children
1397 Subtree
: Count_Type
;
1398 Item
: Element_Type
) return Count_Type
1400 N
: Count_Type
'Base;
1401 Result
: Count_Type
;
1404 N
:= Container
.Nodes
(Subtree
).Children
.First
;
1406 Result
:= Find_In_Subtree
(Container
, N
, Item
);
1412 N
:= Container
.Nodes
(N
).Next
;
1416 end Find_In_Children
;
1418 ---------------------
1419 -- Find_In_Subtree --
1420 ---------------------
1422 function Find_In_Subtree
1424 Item
: Element_Type
) return Cursor
1426 Result
: Count_Type
;
1429 if Position
= No_Element
then
1430 raise Constraint_Error
with "Position cursor has no element";
1433 -- Commented-out pending ruling by ARG. ???
1435 -- if Position.Container /= Container'Unrestricted_Access then
1436 -- raise Program_Error with "Position cursor not in container";
1439 if Position
.Container
.Count
= 0 then
1440 pragma Assert
(Is_Root
(Position
));
1444 if Is_Root
(Position
) then
1445 Result
:= Find_In_Children
1446 (Container
=> Position
.Container
.all,
1447 Subtree
=> Position
.Node
,
1451 Result
:= Find_In_Subtree
1452 (Container
=> Position
.Container
.all,
1453 Subtree
=> Position
.Node
,
1461 return Cursor
'(Position.Container, Result);
1462 end Find_In_Subtree;
1464 function Find_In_Subtree
1466 Subtree : Count_Type;
1467 Item : Element_Type) return Count_Type
1470 if Container.Elements (Subtree) = Item then
1474 return Find_In_Children (Container, Subtree, Item);
1475 end Find_In_Subtree;
1481 function Has_Element (Position : Cursor) return Boolean is
1483 if Position = No_Element then
1487 return Position.Node /= Root_Node (Position.Container.all);
1490 ---------------------
1491 -- Initialize_Node --
1492 ---------------------
1494 procedure Initialize_Node
1495 (Container : in out Tree;
1499 Container.Nodes (Index) :=
1503 Children => (others => 0));
1504 end Initialize_Node;
1506 ---------------------
1507 -- Initialize_Root --
1508 ---------------------
1510 procedure Initialize_Root (Container : in out Tree) is
1512 Initialize_Node (Container, Root_Node (Container));
1513 end Initialize_Root;
1519 procedure Insert_Child
1520 (Container : in out Tree;
1523 New_Item : Element_Type;
1524 Count : Count_Type := 1)
1527 pragma Unreferenced (Position);
1530 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1533 procedure Insert_Child
1534 (Container : in out Tree;
1537 New_Item : Element_Type;
1538 Position : out Cursor;
1539 Count : Count_Type := 1)
1541 Nodes : Tree_Node_Array renames Container.Nodes;
1546 if Parent = No_Element then
1547 raise Constraint_Error with "Parent cursor has no element";
1550 if Parent.Container /= Container'Unrestricted_Access then
1551 raise Program_Error with "Parent cursor not in container";
1554 if Before /= No_Element then
1555 if Before.Container /= Container'Unrestricted_Access then
1556 raise Program_Error with "Before cursor not in container";
1559 if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
1560 raise Constraint_Error with "Parent cursor not parent of Before";
1565 Position := No_Element; -- Need ruling from ARG ???
1569 if Container.Count > Container.Capacity - Count then
1570 raise Capacity_Error
1571 with "requested count exceeds available storage";
1574 if Container.Busy > 0 then
1576 with "attempt to tamper with cursors (tree is busy)";
1579 if Container.Count = 0 then
1580 Initialize_Root (Container);
1583 Allocate_Node (Container, New_Item, First);
1584 Nodes (First).Parent := Parent.Node;
1587 for J in Count_Type'(2) .. Count
loop
1588 Allocate_Node
(Container
, New_Item
, Nodes
(Last
).Next
);
1589 Nodes
(Nodes
(Last
).Next
).Parent
:= Parent
.Node
;
1590 Nodes
(Nodes
(Last
).Next
).Prev
:= Last
;
1592 Last
:= Nodes
(Last
).Next
;
1596 (Container
=> Container
,
1599 Parent
=> Parent
.Node
,
1600 Before
=> Before
.Node
);
1602 Container
.Count
:= Container
.Count
+ Count
;
1604 Position
:= Cursor
'(Parent.Container, First);
1607 procedure Insert_Child
1608 (Container : in out Tree;
1611 Position : out Cursor;
1612 Count : Count_Type := 1)
1614 Nodes : Tree_Node_Array renames Container.Nodes;
1618 New_Item : Element_Type;
1619 pragma Unmodified (New_Item);
1620 -- OK to reference, see below
1623 if Parent = No_Element then
1624 raise Constraint_Error with "Parent cursor has no element";
1627 if Parent.Container /= Container'Unrestricted_Access then
1628 raise Program_Error with "Parent cursor not in container";
1631 if Before /= No_Element then
1632 if Before.Container /= Container'Unrestricted_Access then
1633 raise Program_Error with "Before cursor not in container";
1636 if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
1637 raise Constraint_Error with "Parent cursor not parent of Before";
1642 Position := No_Element; -- Need ruling from ARG ???
1646 if Container.Count > Container.Capacity - Count then
1647 raise Capacity_Error
1648 with "requested count exceeds available storage";
1651 if Container.Busy > 0 then
1653 with "attempt to tamper with cursors (tree is busy)";
1656 if Container.Count = 0 then
1657 Initialize_Root (Container);
1660 -- There is no explicit element provided, but in an instance the element
1661 -- type may be a scalar with a Default_Value aspect, or a composite
1662 -- type with such a scalar component, or components with default
1663 -- initialization, so insert the specified number of possibly
1664 -- initialized elements at the given position.
1666 Allocate_Node (Container, New_Item, First);
1667 Nodes (First).Parent := Parent.Node;
1670 for J in Count_Type'(2) .. Count
loop
1671 Allocate_Node
(Container
, New_Item
, Nodes
(Last
).Next
);
1672 Nodes
(Nodes
(Last
).Next
).Parent
:= Parent
.Node
;
1673 Nodes
(Nodes
(Last
).Next
).Prev
:= Last
;
1675 Last
:= Nodes
(Last
).Next
;
1679 (Container
=> Container
,
1682 Parent
=> Parent
.Node
,
1683 Before
=> Before
.Node
);
1685 Container
.Count
:= Container
.Count
+ Count
;
1687 Position
:= Cursor
'(Parent.Container, First);
1690 -------------------------
1691 -- Insert_Subtree_List --
1692 -------------------------
1694 procedure Insert_Subtree_List
1695 (Container : in out Tree;
1696 First : Count_Type'Base;
1697 Last : Count_Type'Base;
1698 Parent : Count_Type;
1699 Before : Count_Type'Base)
1701 NN : Tree_Node_Array renames Container.Nodes;
1702 N : Tree_Node_Type renames NN (Parent);
1703 CC : Children_Type renames N.Children;
1706 -- This is a simple utility operation to insert a list of nodes
1707 -- (First..Last) as children of Parent. The Before node specifies where
1708 -- the new children should be inserted relative to existing children.
1711 pragma Assert (Last <= 0);
1715 pragma Assert (Last > 0);
1716 pragma Assert (Before <= 0 or else NN (Before).Parent = Parent);
1718 if CC.First <= 0 then -- no existing children
1720 NN (CC.First).Prev := 0;
1722 NN (CC.Last).Next := 0;
1724 elsif Before <= 0 then -- means "insert after existing nodes"
1725 NN (CC.Last).Next := First;
1726 NN (First).Prev := CC.Last;
1728 NN (CC.Last).Next := 0;
1730 elsif Before = CC.First then
1731 NN (Last).Next := CC.First;
1732 NN (CC.First).Prev := Last;
1734 NN (CC.First).Prev := 0;
1737 NN (NN (Before).Prev).Next := First;
1738 NN (First).Prev := NN (Before).Prev;
1739 NN (Last).Next := Before;
1740 NN (Before).Prev := Last;
1742 end Insert_Subtree_List;
1744 -------------------------
1745 -- Insert_Subtree_Node --
1746 -------------------------
1748 procedure Insert_Subtree_Node
1749 (Container : in out Tree;
1750 Subtree : Count_Type'Base;
1751 Parent : Count_Type;
1752 Before : Count_Type'Base)
1755 -- This is a simple wrapper operation to insert a single child into the
1756 -- Parent's children list.
1759 (Container => Container,
1764 end Insert_Subtree_Node;
1770 function Is_Empty (Container : Tree) return Boolean is
1772 return Container.Count = 0;
1779 function Is_Leaf (Position : Cursor) return Boolean is
1781 if Position = No_Element then
1785 if Position.Container.Count = 0 then
1786 pragma Assert (Is_Root (Position));
1790 return Position.Container.Nodes (Position.Node).Children.First <= 0;
1797 function Is_Reachable
1799 From, To : Count_Type) return Boolean
1810 Idx := Container.Nodes (Idx).Parent;
1820 function Is_Root (Position : Cursor) return Boolean is
1823 (if Position.Container = null then False
1824 else Position.Node = Root_Node (Position.Container.all));
1833 Process : not null access procedure (Position : Cursor))
1835 B : Natural renames Container'Unrestricted_Access.all.Busy;
1838 if Container.Count = 0 then
1845 (Container => Container,
1846 Subtree => Root_Node (Container),
1847 Process => Process);
1857 function Iterate (Container : Tree)
1858 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1861 return Iterate_Subtree (Root (Container));
1864 ----------------------
1865 -- Iterate_Children --
1866 ----------------------
1868 procedure Iterate_Children
1870 Process : not null access procedure (Position : Cursor))
1873 if Parent = No_Element then
1874 raise Constraint_Error with "Parent cursor has no element";
1877 if Parent.Container.Count = 0 then
1878 pragma Assert (Is_Root (Parent));
1883 B : Natural renames Parent.Container.Busy;
1885 NN : Tree_Node_Array renames Parent.Container.Nodes;
1890 C := NN (Parent.Node).Children.First;
1892 Process (Cursor'(Parent
.Container
, Node
=> C
));
1903 end Iterate_Children
;
1905 procedure Iterate_Children
1907 Subtree
: Count_Type
;
1908 Process
: not null access procedure (Position
: Cursor
))
1910 NN
: Tree_Node_Array
renames Container
.Nodes
;
1911 N
: Tree_Node_Type
renames NN
(Subtree
);
1915 -- This is a helper function to recursively iterate over all the nodes
1916 -- in a subtree, in depth-first fashion. This particular helper just
1917 -- visits the children of this subtree, not the root of the subtree
1918 -- itself. This is useful when starting from the ultimate root of the
1919 -- entire tree (see Iterate), as that root does not have an element.
1921 C
:= N
.Children
.First
;
1923 Iterate_Subtree
(Container
, C
, Process
);
1926 end Iterate_Children
;
1928 function Iterate_Children
1931 return Tree_Iterator_Interfaces
.Reversible_Iterator
'Class
1933 C
: constant Tree_Access
:= Container
'Unrestricted_Access;
1934 B
: Natural renames C
.Busy
;
1937 if Parent
= No_Element
then
1938 raise Constraint_Error
with "Parent cursor has no element";
1941 if Parent
.Container
/= C
then
1942 raise Program_Error
with "Parent cursor not in container";
1945 return It
: constant Child_Iterator
:=
1946 Child_Iterator
'(Limited_Controlled with
1948 Subtree => Parent.Node)
1952 end Iterate_Children;
1954 ---------------------
1955 -- Iterate_Subtree --
1956 ---------------------
1958 function Iterate_Subtree
1960 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1963 if Position = No_Element then
1964 raise Constraint_Error with "Position cursor has no element";
1967 -- Implement Vet for multiway trees???
1968 -- pragma Assert (Vet (Position), "bad subtree cursor");
1971 B : Natural renames Position.Container.Busy;
1973 return It : constant Subtree_Iterator :=
1974 (Limited_Controlled with
1975 Container => Position.Container,
1976 Subtree => Position.Node)
1981 end Iterate_Subtree;
1983 procedure Iterate_Subtree
1985 Process : not null access procedure (Position : Cursor))
1988 if Position = No_Element then
1989 raise Constraint_Error with "Position cursor has no element";
1992 if Position.Container.Count = 0 then
1993 pragma Assert (Is_Root (Position));
1998 T : Tree renames Position.Container.all;
1999 B : Natural renames T.Busy;
2004 if Is_Root (Position) then
2005 Iterate_Children (T, Position.Node, Process);
2007 Iterate_Subtree (T, Position.Node, Process);
2017 end Iterate_Subtree;
2019 procedure Iterate_Subtree
2021 Subtree : Count_Type;
2022 Process : not null access procedure (Position : Cursor))
2025 -- This is a helper function to recursively iterate over all the nodes
2026 -- in a subtree, in depth-first fashion. It first visits the root of the
2027 -- subtree, then visits its children.
2029 Process (Cursor'(Container
'Unrestricted_Access, Subtree
));
2030 Iterate_Children
(Container
, Subtree
, Process
);
2031 end Iterate_Subtree
;
2037 overriding
function Last
(Object
: Child_Iterator
) return Cursor
is
2039 return Last_Child
(Cursor
'(Object.Container, Object.Subtree));
2046 function Last_Child (Parent : Cursor) return Cursor is
2047 Node : Count_Type'Base;
2050 if Parent = No_Element then
2051 raise Constraint_Error with "Parent cursor has no element";
2054 if Parent.Container.Count = 0 then
2055 pragma Assert (Is_Root (Parent));
2059 Node := Parent.Container.Nodes (Parent.Node).Children.Last;
2065 return Cursor'(Parent
.Container
, Node
);
2068 ------------------------
2069 -- Last_Child_Element --
2070 ------------------------
2072 function Last_Child_Element
(Parent
: Cursor
) return Element_Type
is
2074 return Element
(Last_Child
(Parent
));
2075 end Last_Child_Element
;
2081 procedure Move
(Target
: in out Tree
; Source
: in out Tree
) is
2083 if Target
'Address = Source
'Address then
2087 if Source
.Busy
> 0 then
2089 with "attempt to tamper with cursors of Source (tree is busy)";
2092 Target
.Assign
(Source
);
2100 overriding
function Next
2101 (Object
: Subtree_Iterator
;
2102 Position
: Cursor
) return Cursor
2105 if Position
.Container
= null then
2109 if Position
.Container
/= Object
.Container
then
2110 raise Program_Error
with
2111 "Position cursor of Next designates wrong tree";
2114 pragma Assert
(Object
.Container
.Count
> 0);
2115 pragma Assert
(Position
.Node
/= Root_Node
(Object
.Container
.all));
2118 Nodes
: Tree_Node_Array
renames Object
.Container
.Nodes
;
2122 Node
:= Position
.Node
;
2124 if Nodes
(Node
).Children
.First
> 0 then
2125 return Cursor
'(Object.Container, Nodes (Node).Children.First);
2128 while Node /= Object.Subtree loop
2129 if Nodes (Node).Next > 0 then
2130 return Cursor'(Object
.Container
, Nodes
(Node
).Next
);
2133 Node
:= Nodes
(Node
).Parent
;
2140 overriding
function Next
2141 (Object
: Child_Iterator
;
2142 Position
: Cursor
) return Cursor
2145 if Position
.Container
= null then
2149 if Position
.Container
/= Object
.Container
then
2150 raise Program_Error
with
2151 "Position cursor of Next designates wrong tree";
2154 pragma Assert
(Object
.Container
.Count
> 0);
2155 pragma Assert
(Position
.Node
/= Root_Node
(Object
.Container
.all));
2157 return Next_Sibling
(Position
);
2164 function Next_Sibling
(Position
: Cursor
) return Cursor
is
2166 if Position
= No_Element
then
2170 if Position
.Container
.Count
= 0 then
2171 pragma Assert
(Is_Root
(Position
));
2176 T
: Tree
renames Position
.Container
.all;
2177 NN
: Tree_Node_Array
renames T
.Nodes
;
2178 N
: Tree_Node_Type
renames NN
(Position
.Node
);
2185 return Cursor
'(Position.Container, N.Next);
2189 procedure Next_Sibling (Position : in out Cursor) is
2191 Position := Next_Sibling (Position);
2198 function Node_Count (Container : Tree) return Count_Type is
2200 -- Container.Count is the number of nodes we have actually allocated. We
2201 -- cache the value specifically so this Node_Count operation can execute
2202 -- in O(1) time, which makes it behave similarly to how the Length
2203 -- selector function behaves for other containers.
2205 -- The cached node count value only describes the nodes we have
2206 -- allocated; the root node itself is not included in that count. The
2207 -- Node_Count operation returns a value that includes the root node
2208 -- (because the RM says so), so we must add 1 to our cached value.
2210 return 1 + Container.Count;
2217 function Parent (Position : Cursor) return Cursor is
2219 if Position = No_Element then
2223 if Position.Container.Count = 0 then
2224 pragma Assert (Is_Root (Position));
2229 T : Tree renames Position.Container.all;
2230 NN : Tree_Node_Array renames T.Nodes;
2231 N : Tree_Node_Type renames NN (Position.Node);
2234 if N.Parent < 0 then
2235 pragma Assert (Position.Node = Root_Node (T));
2239 return Cursor'(Position
.Container
, N
.Parent
);
2247 procedure Prepend_Child
2248 (Container
: in out Tree
;
2250 New_Item
: Element_Type
;
2251 Count
: Count_Type
:= 1)
2253 Nodes
: Tree_Node_Array
renames Container
.Nodes
;
2254 First
, Last
: Count_Type
;
2257 if Parent
= No_Element
then
2258 raise Constraint_Error
with "Parent cursor has no element";
2261 if Parent
.Container
/= Container
'Unrestricted_Access then
2262 raise Program_Error
with "Parent cursor not in container";
2269 if Container
.Count
> Container
.Capacity
- Count
then
2270 raise Capacity_Error
2271 with "requested count exceeds available storage";
2274 if Container
.Busy
> 0 then
2276 with "attempt to tamper with cursors (tree is busy)";
2279 if Container
.Count
= 0 then
2280 Initialize_Root
(Container
);
2283 Allocate_Node
(Container
, New_Item
, First
);
2284 Nodes
(First
).Parent
:= Parent
.Node
;
2287 for J
in Count_Type
'(2) .. Count loop
2288 Allocate_Node (Container, New_Item, Nodes (Last).Next);
2289 Nodes (Nodes (Last).Next).Parent := Parent.Node;
2290 Nodes (Nodes (Last).Next).Prev := Last;
2292 Last := Nodes (Last).Next;
2296 (Container => Container,
2299 Parent => Parent.Node,
2300 Before => Nodes (Parent.Node).Children.First);
2302 Container.Count := Container.Count + Count;
2309 overriding function Previous
2310 (Object : Child_Iterator;
2311 Position : Cursor) return Cursor
2314 if Position.Container = null then
2318 if Position.Container /= Object.Container then
2319 raise Program_Error with
2320 "Position cursor of Previous designates wrong tree";
2323 return Previous_Sibling (Position);
2326 ----------------------
2327 -- Previous_Sibling --
2328 ----------------------
2330 function Previous_Sibling (Position : Cursor) return Cursor is
2332 if Position = No_Element then
2336 if Position.Container.Count = 0 then
2337 pragma Assert (Is_Root (Position));
2342 T : Tree renames Position.Container.all;
2343 NN : Tree_Node_Array renames T.Nodes;
2344 N : Tree_Node_Type renames NN (Position.Node);
2351 return Cursor'(Position
.Container
, N
.Prev
);
2353 end Previous_Sibling
;
2355 procedure Previous_Sibling
(Position
: in out Cursor
) is
2357 Position
:= Previous_Sibling
(Position
);
2358 end Previous_Sibling
;
2364 procedure Query_Element
2366 Process
: not null access procedure (Element
: Element_Type
))
2369 if Position
= No_Element
then
2370 raise Constraint_Error
with "Position cursor has no element";
2373 if Is_Root
(Position
) then
2374 raise Program_Error
with "Position cursor designates root";
2378 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
2379 B
: Natural renames T
.Busy
;
2380 L
: Natural renames T
.Lock
;
2386 Process
(Element
=> T
.Elements
(Position
.Node
));
2404 (Stream
: not null access Root_Stream_Type
'Class;
2405 Container
: out Tree
)
2407 procedure Read_Children
(Subtree
: Count_Type
);
2409 function Read_Subtree
2410 (Parent
: Count_Type
) return Count_Type
;
2412 NN
: Tree_Node_Array
renames Container
.Nodes
;
2414 Total_Count
: Count_Type
'Base;
2415 -- Value read from the stream that says how many elements follow
2417 Read_Count
: Count_Type
'Base;
2418 -- Actual number of elements read from the stream
2424 procedure Read_Children
(Subtree
: Count_Type
) is
2425 Count
: Count_Type
'Base;
2426 -- number of child subtrees
2431 Count_Type
'Read (Stream
, Count
);
2434 raise Program_Error
with "attempt to read from corrupt stream";
2441 CC
.First
:= Read_Subtree
(Parent
=> Subtree
);
2442 CC
.Last
:= CC
.First
;
2444 for J
in Count_Type
'(2) .. Count loop
2445 NN (CC.Last).Next := Read_Subtree (Parent => Subtree);
2446 NN (NN (CC.Last).Next).Prev := CC.Last;
2447 CC.Last := NN (CC.Last).Next;
2450 -- Now that the allocation and reads have completed successfully, it
2451 -- is safe to link the children to their parent.
2453 NN (Subtree).Children := CC;
2460 function Read_Subtree
2461 (Parent : Count_Type) return Count_Type
2463 Subtree : Count_Type;
2466 Allocate_Node (Container, Stream, Subtree);
2467 Container.Nodes (Subtree).Parent := Parent;
2469 Read_Count := Read_Count + 1;
2471 Read_Children (Subtree);
2476 -- Start of processing for Read
2479 Container.Clear; -- checks busy bit
2481 Count_Type'Read (Stream, Total_Count);
2483 if Total_Count < 0 then
2484 raise Program_Error with "attempt to read from corrupt stream";
2487 if Total_Count = 0 then
2491 if Total_Count > Container.Capacity then
2492 raise Capacity_Error -- ???
2493 with "node count in stream exceeds container capacity";
2496 Initialize_Root (Container);
2500 Read_Children (Root_Node (Container));
2502 if Read_Count /= Total_Count then
2503 raise Program_Error with "attempt to read from corrupt stream";
2506 Container.Count := Total_Count;
2510 (Stream : not null access Root_Stream_Type'Class;
2511 Position : out Cursor)
2514 raise Program_Error with "attempt to read tree cursor from stream";
2518 (Stream : not null access Root_Stream_Type'Class;
2519 Item : out Reference_Type)
2522 raise Program_Error with "attempt to stream reference";
2526 (Stream : not null access Root_Stream_Type'Class;
2527 Item : out Constant_Reference_Type)
2530 raise Program_Error with "attempt to stream reference";
2538 (Container : aliased in out Tree;
2539 Position : Cursor) return Reference_Type
2542 if Position.Container = null then
2543 raise Constraint_Error with
2544 "Position cursor has no element";
2547 if Position.Container /= Container'Unrestricted_Access then
2548 raise Program_Error with
2549 "Position cursor designates wrong container";
2552 if Position.Node = Root_Node (Container) then
2553 raise Program_Error with "Position cursor designates root";
2556 -- Implement Vet for multiway tree???
2557 -- pragma Assert (Vet (Position),
2558 -- "Position cursor in Constant_Reference is bad");
2561 C : Tree renames Position.Container.all;
2562 B : Natural renames C.Busy;
2563 L : Natural renames C.Lock;
2565 return R : constant Reference_Type :=
2566 (Element => Container.Elements (Position.Node)'Access,
2567 Control => (Controlled with Position.Container))
2576 --------------------
2577 -- Remove_Subtree --
2578 --------------------
2580 procedure Remove_Subtree
2581 (Container : in out Tree;
2582 Subtree : Count_Type)
2584 NN : Tree_Node_Array renames Container.Nodes;
2585 N : Tree_Node_Type renames NN (Subtree);
2586 CC : Children_Type renames NN (N.Parent).Children;
2589 -- This is a utility operation to remove a subtree node from its
2590 -- parent's list of children.
2592 if CC.First = Subtree then
2593 pragma Assert (N.Prev <= 0);
2595 if CC.Last = Subtree then
2596 pragma Assert (N.Next <= 0);
2602 NN (CC.First).Prev := 0;
2605 elsif CC.Last = Subtree then
2606 pragma Assert (N.Next <= 0);
2608 NN (CC.Last).Next := 0;
2611 NN (N.Prev).Next := N.Next;
2612 NN (N.Next).Prev := N.Prev;
2616 ----------------------
2617 -- Replace_Element --
2618 ----------------------
2620 procedure Replace_Element
2621 (Container : in out Tree;
2623 New_Item : Element_Type)
2626 if Position = No_Element then
2627 raise Constraint_Error with "Position cursor has no element";
2630 if Position.Container /= Container'Unrestricted_Access then
2631 raise Program_Error with "Position cursor not in container";
2634 if Is_Root (Position) then
2635 raise Program_Error with "Position cursor designates root";
2638 if Container.Lock > 0 then
2640 with "attempt to tamper with elements (tree is locked)";
2643 Container.Elements (Position.Node) := New_Item;
2644 end Replace_Element;
2646 ------------------------------
2647 -- Reverse_Iterate_Children --
2648 ------------------------------
2650 procedure Reverse_Iterate_Children
2652 Process : not null access procedure (Position : Cursor))
2655 if Parent = No_Element then
2656 raise Constraint_Error with "Parent cursor has no element";
2659 if Parent.Container.Count = 0 then
2660 pragma Assert (Is_Root (Parent));
2665 NN : Tree_Node_Array renames Parent.Container.Nodes;
2666 B : Natural renames Parent.Container.Busy;
2672 C := NN (Parent.Node).Children.Last;
2674 Process (Cursor'(Parent
.Container
, Node
=> C
));
2685 end Reverse_Iterate_Children
;
2691 function Root
(Container
: Tree
) return Cursor
is
2693 return (Container
'Unrestricted_Access, Root_Node
(Container
));
2700 function Root_Node
(Container
: Tree
) return Count_Type
is
2701 pragma Unreferenced
(Container
);
2707 ---------------------
2708 -- Splice_Children --
2709 ---------------------
2711 procedure Splice_Children
2712 (Target
: in out Tree
;
2713 Target_Parent
: Cursor
;
2715 Source
: in out Tree
;
2716 Source_Parent
: Cursor
)
2719 if Target_Parent
= No_Element
then
2720 raise Constraint_Error
with "Target_Parent cursor has no element";
2723 if Target_Parent
.Container
/= Target
'Unrestricted_Access then
2725 with "Target_Parent cursor not in Target container";
2728 if Before
/= No_Element
then
2729 if Before
.Container
/= Target
'Unrestricted_Access then
2731 with "Before cursor not in Target container";
2734 if Target
.Nodes
(Before
.Node
).Parent
/= Target_Parent
.Node
then
2735 raise Constraint_Error
2736 with "Before cursor not child of Target_Parent";
2740 if Source_Parent
= No_Element
then
2741 raise Constraint_Error
with "Source_Parent cursor has no element";
2744 if Source_Parent
.Container
/= Source
'Unrestricted_Access then
2746 with "Source_Parent cursor not in Source container";
2749 if Source
.Count
= 0 then
2750 pragma Assert
(Is_Root
(Source_Parent
));
2754 if Target
'Address = Source
'Address then
2755 if Target_Parent
= Source_Parent
then
2759 if Target
.Busy
> 0 then
2761 with "attempt to tamper with cursors (Target tree is busy)";
2764 if Is_Reachable
(Container
=> Target
,
2765 From
=> Target_Parent
.Node
,
2766 To
=> Source_Parent
.Node
)
2768 raise Constraint_Error
2769 with "Source_Parent is ancestor of Target_Parent";
2773 (Container
=> Target
,
2774 Target_Parent
=> Target_Parent
.Node
,
2775 Before
=> Before
.Node
,
2776 Source_Parent
=> Source_Parent
.Node
);
2781 if Target
.Busy
> 0 then
2783 with "attempt to tamper with cursors (Target tree is busy)";
2786 if Source
.Busy
> 0 then
2788 with "attempt to tamper with cursors (Source tree is busy)";
2791 if Target
.Count
= 0 then
2792 Initialize_Root
(Target
);
2797 Target_Parent
=> Target_Parent
.Node
,
2798 Before
=> Before
.Node
,
2800 Source_Parent
=> Source_Parent
.Node
);
2801 end Splice_Children
;
2803 procedure Splice_Children
2804 (Container
: in out Tree
;
2805 Target_Parent
: Cursor
;
2807 Source_Parent
: Cursor
)
2810 if Target_Parent
= No_Element
then
2811 raise Constraint_Error
with "Target_Parent cursor has no element";
2814 if Target_Parent
.Container
/= Container
'Unrestricted_Access then
2816 with "Target_Parent cursor not in container";
2819 if Before
/= No_Element
then
2820 if Before
.Container
/= Container
'Unrestricted_Access then
2822 with "Before cursor not in container";
2825 if Container
.Nodes
(Before
.Node
).Parent
/= Target_Parent
.Node
then
2826 raise Constraint_Error
2827 with "Before cursor not child of Target_Parent";
2831 if Source_Parent
= No_Element
then
2832 raise Constraint_Error
with "Source_Parent cursor has no element";
2835 if Source_Parent
.Container
/= Container
'Unrestricted_Access then
2837 with "Source_Parent cursor not in container";
2840 if Target_Parent
= Source_Parent
then
2844 pragma Assert
(Container
.Count
> 0);
2846 if Container
.Busy
> 0 then
2848 with "attempt to tamper with cursors (tree is busy)";
2851 if Is_Reachable
(Container
=> Container
,
2852 From
=> Target_Parent
.Node
,
2853 To
=> Source_Parent
.Node
)
2855 raise Constraint_Error
2856 with "Source_Parent is ancestor of Target_Parent";
2860 (Container
=> Container
,
2861 Target_Parent
=> Target_Parent
.Node
,
2862 Before
=> Before
.Node
,
2863 Source_Parent
=> Source_Parent
.Node
);
2864 end Splice_Children
;
2866 procedure Splice_Children
2867 (Container
: in out Tree
;
2868 Target_Parent
: Count_Type
;
2869 Before
: Count_Type
'Base;
2870 Source_Parent
: Count_Type
)
2872 NN
: Tree_Node_Array
renames Container
.Nodes
;
2873 CC
: constant Children_Type
:= NN
(Source_Parent
).Children
;
2874 C
: Count_Type
'Base;
2877 -- This is a utility operation to remove the children from Source parent
2878 -- and insert them into Target parent.
2880 NN
(Source_Parent
).Children
:= Children_Type
'(others => 0);
2882 -- Fix up the Parent pointers of each child to designate its new Target
2887 NN (C).Parent := Target_Parent;
2892 (Container => Container,
2895 Parent => Target_Parent,
2897 end Splice_Children;
2899 procedure Splice_Children
2900 (Target : in out Tree;
2901 Target_Parent : Count_Type;
2902 Before : Count_Type'Base;
2903 Source : in out Tree;
2904 Source_Parent : Count_Type)
2906 S_NN : Tree_Node_Array renames Source.Nodes;
2907 S_CC : Children_Type renames S_NN (Source_Parent).Children;
2909 Target_Count, Source_Count : Count_Type;
2910 T, S : Count_Type'Base;
2913 -- This is a utility operation to copy the children from the Source
2914 -- parent and insert them as children of the Target parent, and then
2915 -- delete them from the Source. (This is not a true splice operation,
2916 -- but it is the best we can do in a bounded form.) The Before position
2917 -- specifies where among the Target parent's exising children the new
2918 -- children are inserted.
2920 -- Before we attempt the insertion, we must count the sources nodes in
2921 -- order to determine whether the target have enough storage
2922 -- available. Note that calculating this value is an O(n) operation.
2924 -- Here is an optimization opportunity: iterate of each children the
2925 -- source explicitly, and keep a running count of the total number of
2926 -- nodes. Compare the running total to the capacity of the target each
2927 -- pass through the loop. This is more efficient than summing the counts
2928 -- of child subtree (which is what Subtree_Node_Count does) and then
2929 -- comparing that total sum to the target's capacity. ???
2931 -- Here is another possibility. We currently treat the splice as an
2932 -- all-or-nothing proposition: either we can insert all of children of
2933 -- the source, or we raise exception with modifying the target. The
2934 -- price for not causing side-effect is an O(n) determination of the
2935 -- source count. If we are willing to tolerate side-effect, then we
2936 -- could loop over the children of the source, counting that subtree and
2937 -- then immediately inserting it in the target. The issue here is that
2938 -- the test for available storage could fail during some later pass,
2939 -- after children have already been inserted into target. ???
2941 Source_Count := Subtree_Node_Count (Source, Source_Parent) - 1;
2943 if Source_Count = 0 then
2947 if Target.Count > Target.Capacity - Source_Count then
2948 raise Capacity_Error -- ???
2949 with "Source count exceeds available storage on Target";
2952 -- Copy_Subtree returns a count of the number of nodes it inserts, but
2953 -- it does this by incrementing the value passed in. Therefore we must
2954 -- initialize the count before calling Copy_Subtree.
2962 Source_Subtree => S,
2964 Target_Parent => Target_Parent,
2965 Target_Subtree => T,
2966 Count => Target_Count);
2969 (Container => Target,
2971 Parent => Target_Parent,
2977 pragma Assert (Target_Count = Source_Count);
2978 Target.Count := Target.Count + Target_Count;
2980 -- As with Copy_Subtree, operation Deallocate_Children returns a count
2981 -- of the number of nodes it deallocates, but it works by incrementing
2982 -- the value passed in. We must therefore initialize the count before
2987 Deallocate_Children (Source, Source_Parent, Source_Count);
2988 pragma Assert (Source_Count = Target_Count);
2990 Source.Count := Source.Count - Source_Count;
2991 end Splice_Children;
2993 --------------------
2994 -- Splice_Subtree --
2995 --------------------
2997 procedure Splice_Subtree
2998 (Target : in out Tree;
3001 Source : in out Tree;
3002 Position : in out Cursor)
3005 if Parent = No_Element then
3006 raise Constraint_Error with "Parent cursor has no element";
3009 if Parent.Container /= Target'Unrestricted_Access then
3010 raise Program_Error with "Parent cursor not in Target container";
3013 if Before /= No_Element then
3014 if Before.Container /= Target'Unrestricted_Access then
3015 raise Program_Error with "Before cursor not in Target container";
3018 if Target.Nodes (Before.Node).Parent /= Parent.Node then
3019 raise Constraint_Error with "Before cursor not child of Parent";
3023 if Position = No_Element then
3024 raise Constraint_Error with "Position cursor has no element";
3027 if Position.Container /= Source'Unrestricted_Access then
3028 raise Program_Error with "Position cursor not in Source container";
3031 if Is_Root (Position) then
3032 raise Program_Error with "Position cursor designates root";
3035 if Target'Address = Source'Address then
3036 if Target.Nodes (Position.Node).Parent = Parent.Node then
3037 if Before = No_Element then
3038 if Target.Nodes (Position.Node).Next <= 0 then -- last child
3042 elsif Position.Node = Before.Node then
3045 elsif Target.Nodes (Position.Node).Next = Before.Node then
3050 if Target.Busy > 0 then
3052 with "attempt to tamper with cursors (Target tree is busy)";
3055 if Is_Reachable (Container => Target,
3056 From => Parent.Node,
3057 To => Position.Node)
3059 raise Constraint_Error with "Position is ancestor of Parent";
3062 Remove_Subtree (Target, Position.Node);
3064 Target.Nodes (Position.Node).Parent := Parent.Node;
3065 Insert_Subtree_Node (Target, Position.Node, Parent.Node, Before.Node);
3070 if Target.Busy > 0 then
3072 with "attempt to tamper with cursors (Target tree is busy)";
3075 if Source.Busy > 0 then
3077 with "attempt to tamper with cursors (Source tree is busy)";
3080 if Target.Count = 0 then
3081 Initialize_Root (Target);
3086 Parent => Parent.Node,
3087 Before => Before.Node,
3089 Position => Position.Node); -- modified during call
3091 Position.Container := Target'Unrestricted_Access;
3094 procedure Splice_Subtree
3095 (Container : in out Tree;
3101 if Parent = No_Element then
3102 raise Constraint_Error with "Parent cursor has no element";
3105 if Parent.Container /= Container'Unrestricted_Access then
3106 raise Program_Error with "Parent cursor not in container";
3109 if Before /= No_Element then
3110 if Before.Container /= Container'Unrestricted_Access then
3111 raise Program_Error with "Before cursor not in container";
3114 if Container.Nodes (Before.Node).Parent /= Parent.Node then
3115 raise Constraint_Error with "Before cursor not child of Parent";
3119 if Position = No_Element then
3120 raise Constraint_Error with "Position cursor has no element";
3123 if Position.Container /= Container'Unrestricted_Access then
3124 raise Program_Error with "Position cursor not in container";
3127 if Is_Root (Position) then
3129 -- Should this be PE instead? Need ARG confirmation. ???
3131 raise Constraint_Error with "Position cursor designates root";
3134 if Container.Nodes (Position.Node).Parent = Parent.Node then
3135 if Before = No_Element then
3136 if Container.Nodes (Position.Node).Next <= 0 then -- last child
3140 elsif Position.Node = Before.Node then
3143 elsif Container.Nodes (Position.Node).Next = Before.Node then
3148 if Container.Busy > 0 then
3150 with "attempt to tamper with cursors (tree is busy)";
3153 if Is_Reachable (Container => Container,
3154 From => Parent.Node,
3155 To => Position.Node)
3157 raise Constraint_Error with "Position is ancestor of Parent";
3160 Remove_Subtree (Container, Position.Node);
3161 Container.Nodes (Position.Node).Parent := Parent.Node;
3162 Insert_Subtree_Node (Container, Position.Node, Parent.Node, Before.Node);
3165 procedure Splice_Subtree
3166 (Target : in out Tree;
3167 Parent : Count_Type;
3168 Before : Count_Type'Base;
3169 Source : in out Tree;
3170 Position : in out Count_Type) -- Source on input, Target on output
3172 Source_Count : Count_Type := Subtree_Node_Count (Source, Position);
3173 pragma Assert (Source_Count >= 1);
3175 Target_Subtree : Count_Type;
3176 Target_Count : Count_Type;
3179 -- This is a utility operation to do the heavy lifting associated with
3180 -- splicing a subtree from one tree to another. Note that "splicing"
3181 -- is a bit of a misnomer here in the case of a bounded tree, because
3182 -- the elements must be copied from the source to the target.
3184 if Target.Count > Target.Capacity - Source_Count then
3185 raise Capacity_Error -- ???
3186 with "Source count exceeds available storage on Target";
3189 -- Copy_Subtree returns a count of the number of nodes it inserts, but
3190 -- it does this by incrementing the value passed in. Therefore we must
3191 -- initialize the count before calling Copy_Subtree.
3197 Source_Subtree => Position,
3199 Target_Parent => Parent,
3200 Target_Subtree => Target_Subtree,
3201 Count => Target_Count);
3203 pragma Assert (Target_Count = Source_Count);
3205 -- Now link the newly-allocated subtree into the target.
3208 (Container => Target,
3209 Subtree => Target_Subtree,
3213 Target.Count := Target.Count + Target_Count;
3215 -- The manipulation of the Target container is complete. Now we remove
3216 -- the subtree from the Source container.
3218 Remove_Subtree (Source, Position); -- unlink the subtree
3220 -- As with Copy_Subtree, operation Deallocate_Subtree returns a count of
3221 -- the number of nodes it deallocates, but it works by incrementing the
3222 -- value passed in. We must therefore initialize the count before
3227 Deallocate_Subtree (Source, Position, Source_Count);
3228 pragma Assert (Source_Count = Target_Count);
3230 Source.Count := Source.Count - Source_Count;
3232 Position := Target_Subtree;
3235 ------------------------
3236 -- Subtree_Node_Count --
3237 ------------------------
3239 function Subtree_Node_Count (Position : Cursor) return Count_Type is
3241 if Position = No_Element then
3245 if Position.Container.Count = 0 then
3246 pragma Assert (Is_Root (Position));
3250 return Subtree_Node_Count (Position.Container.all, Position.Node);
3251 end Subtree_Node_Count;
3253 function Subtree_Node_Count
3255 Subtree : Count_Type) return Count_Type
3257 Result : Count_Type;
3258 Node : Count_Type'Base;
3262 Node := Container.Nodes (Subtree).Children.First;
3264 Result := Result + Subtree_Node_Count (Container, Node);
3265 Node := Container.Nodes (Node).Next;
3268 end Subtree_Node_Count;
3275 (Container : in out Tree;
3279 if I = No_Element then
3280 raise Constraint_Error with "I cursor has no element";
3283 if I.Container /= Container'Unrestricted_Access then
3284 raise Program_Error with "I cursor not in container";
3288 raise Program_Error with "I cursor designates root";
3291 if I = J then -- make this test sooner???
3295 if J = No_Element then
3296 raise Constraint_Error with "J cursor has no element";
3299 if J.Container /= Container'Unrestricted_Access then
3300 raise Program_Error with "J cursor not in container";
3304 raise Program_Error with "J cursor designates root";
3307 if Container.Lock > 0 then
3309 with "attempt to tamper with elements (tree is locked)";
3313 EE : Element_Array renames Container.Elements;
3314 EI : constant Element_Type := EE (I.Node);
3317 EE (I.Node) := EE (J.Node);
3322 --------------------
3323 -- Update_Element --
3324 --------------------
3326 procedure Update_Element
3327 (Container : in out Tree;
3329 Process : not null access procedure (Element : in out Element_Type))
3332 if Position = No_Element then
3333 raise Constraint_Error with "Position cursor has no element";
3336 if Position.Container /= Container'Unrestricted_Access then
3337 raise Program_Error with "Position cursor not in container";
3340 if Is_Root (Position) then
3341 raise Program_Error with "Position cursor designates root";
3345 T : Tree renames Position.Container.all'Unrestricted_Access.all;
3346 B : Natural renames T.Busy;
3347 L : Natural renames T.Lock;
3353 Process (Element => T.Elements (Position.Node));
3371 (Stream : not null access Root_Stream_Type'Class;
3374 procedure Write_Children (Subtree : Count_Type);
3375 procedure Write_Subtree (Subtree : Count_Type);
3377 --------------------
3378 -- Write_Children --
3379 --------------------
3381 procedure Write_Children (Subtree : Count_Type) is
3382 CC : Children_Type renames Container.Nodes (Subtree).Children;
3383 C : Count_Type'Base;
3386 Count_Type'Write (Stream, Child_Count (Container, Subtree));
3391 C := Container.Nodes (C).Next;
3399 procedure Write_Subtree (Subtree : Count_Type) is
3401 Element_Type'Write (Stream, Container.Elements (Subtree));
3402 Write_Children (Subtree);
3405 -- Start of processing for Write
3408 Count_Type'Write (Stream, Container.Count);
3410 if Container.Count = 0 then
3414 Write_Children (Root_Node (Container));
3418 (Stream : not null access Root_Stream_Type'Class;
3422 raise Program_Error with "attempt to write tree cursor to stream";
3426 (Stream : not null access Root_Stream_Type'Class;
3427 Item : Reference_Type)
3430 raise Program_Error with "attempt to stream reference";
3434 (Stream : not null access Root_Stream_Type'Class;
3435 Item : Constant_Reference_Type)
3438 raise Program_Error with "attempt to stream reference";
3441 end Ada.Containers.Bounded_Multiway_Trees;