1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.BOUNDED_MULTIWAY_TREES --
9 -- Copyright (C) 2011-2015, 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
.Finalization
;
31 with System
; use type System
.Address
;
33 package body Ada
.Containers
.Bounded_Multiway_Trees
is
35 pragma Warnings
(Off
, "variable ""Busy*"" is not referenced");
36 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
37 -- See comment in Ada.Containers.Helpers
45 type Root_Iterator
is abstract new Limited_Controlled
and
46 Tree_Iterator_Interfaces
.Forward_Iterator
with
48 Container
: Tree_Access
;
52 overriding
procedure Finalize
(Object
: in out Root_Iterator
);
54 -----------------------
55 -- Subtree_Iterator --
56 -----------------------
58 type Subtree_Iterator
is new Root_Iterator
with null record;
60 overriding
function First
(Object
: Subtree_Iterator
) return Cursor
;
62 overriding
function Next
63 (Object
: Subtree_Iterator
;
64 Position
: Cursor
) return Cursor
;
70 type Child_Iterator
is new Root_Iterator
and
71 Tree_Iterator_Interfaces
.Reversible_Iterator
with null record;
73 overriding
function First
(Object
: Child_Iterator
) return Cursor
;
75 overriding
function Next
76 (Object
: Child_Iterator
;
77 Position
: Cursor
) return Cursor
;
79 overriding
function Last
(Object
: Child_Iterator
) return Cursor
;
81 overriding
function Previous
82 (Object
: Child_Iterator
;
83 Position
: Cursor
) return Cursor
;
85 -----------------------
86 -- Local Subprograms --
87 -----------------------
89 procedure Initialize_Node
(Container
: in out Tree
; Index
: Count_Type
);
90 procedure Initialize_Root
(Container
: in out Tree
);
92 procedure Allocate_Node
93 (Container
: in out Tree
;
94 Initialize_Element
: not null access procedure (Index
: Count_Type
);
95 New_Node
: out Count_Type
);
97 procedure Allocate_Node
98 (Container
: in out Tree
;
99 New_Item
: Element_Type
;
100 New_Node
: out Count_Type
);
102 procedure Allocate_Node
103 (Container
: in out Tree
;
104 Stream
: not null access Root_Stream_Type
'Class;
105 New_Node
: out Count_Type
);
107 procedure Deallocate_Node
108 (Container
: in out Tree
;
111 procedure Deallocate_Children
112 (Container
: in out Tree
;
113 Subtree
: Count_Type
;
114 Count
: in out Count_Type
);
116 procedure Deallocate_Subtree
117 (Container
: in out Tree
;
118 Subtree
: Count_Type
;
119 Count
: in out Count_Type
);
121 function Equal_Children
123 Left_Subtree
: Count_Type
;
125 Right_Subtree
: Count_Type
) return Boolean;
127 function Equal_Subtree
129 Left_Subtree
: Count_Type
;
131 Right_Subtree
: Count_Type
) return Boolean;
133 procedure Iterate_Children
135 Subtree
: Count_Type
;
136 Process
: not null access procedure (Position
: Cursor
));
138 procedure Iterate_Subtree
140 Subtree
: Count_Type
;
141 Process
: not null access procedure (Position
: Cursor
));
143 procedure Copy_Children
145 Source_Parent
: Count_Type
;
146 Target
: in out Tree
;
147 Target_Parent
: Count_Type
;
148 Count
: in out Count_Type
);
150 procedure Copy_Subtree
152 Source_Subtree
: Count_Type
;
153 Target
: in out Tree
;
154 Target_Parent
: Count_Type
;
155 Target_Subtree
: out Count_Type
;
156 Count
: in out Count_Type
);
158 function Find_In_Children
160 Subtree
: Count_Type
;
161 Item
: Element_Type
) return Count_Type
;
163 function Find_In_Subtree
165 Subtree
: Count_Type
;
166 Item
: Element_Type
) return Count_Type
;
170 Parent
: Count_Type
) return Count_Type
;
172 function Subtree_Node_Count
174 Subtree
: Count_Type
) return Count_Type
;
176 function Is_Reachable
178 From
, To
: Count_Type
) return Boolean;
180 function Root_Node
(Container
: Tree
) return Count_Type
;
182 procedure Remove_Subtree
183 (Container
: in out Tree
;
184 Subtree
: Count_Type
);
186 procedure Insert_Subtree_Node
187 (Container
: in out Tree
;
188 Subtree
: Count_Type
'Base;
190 Before
: Count_Type
'Base);
192 procedure Insert_Subtree_List
193 (Container
: in out Tree
;
194 First
: Count_Type
'Base;
195 Last
: Count_Type
'Base;
197 Before
: Count_Type
'Base);
199 procedure Splice_Children
200 (Container
: in out Tree
;
201 Target_Parent
: Count_Type
;
202 Before
: Count_Type
'Base;
203 Source_Parent
: Count_Type
);
205 procedure Splice_Children
206 (Target
: in out Tree
;
207 Target_Parent
: Count_Type
;
208 Before
: Count_Type
'Base;
209 Source
: in out Tree
;
210 Source_Parent
: Count_Type
);
212 procedure Splice_Subtree
213 (Target
: in out Tree
;
215 Before
: Count_Type
'Base;
216 Source
: in out Tree
;
217 Position
: in out Count_Type
); -- source on input, target on output
223 function "=" (Left
, Right
: Tree
) return Boolean is
225 if Left
.Count
/= Right
.Count
then
229 if Left
.Count
= 0 then
233 return Equal_Children
235 Left_Subtree
=> Root_Node
(Left
),
237 Right_Subtree
=> Root_Node
(Right
));
244 procedure Allocate_Node
245 (Container
: in out Tree
;
246 Initialize_Element
: not null access procedure (Index
: Count_Type
);
247 New_Node
: out Count_Type
)
250 if Container
.Free
>= 0 then
251 New_Node
:= Container
.Free
;
252 pragma Assert
(New_Node
in Container
.Elements
'Range);
254 -- We always perform the assignment first, before we change container
255 -- state, in order to defend against exceptions duration assignment.
257 Initialize_Element
(New_Node
);
259 Container
.Free
:= Container
.Nodes
(New_Node
).Next
;
262 -- A negative free store value means that the links of the nodes in
263 -- the free store have not been initialized. In this case, the nodes
264 -- are physically contiguous in the array, starting at the index that
265 -- is the absolute value of the Container.Free, and continuing until
266 -- the end of the array (Nodes'Last).
268 New_Node
:= abs Container
.Free
;
269 pragma Assert
(New_Node
in Container
.Elements
'Range);
271 -- As above, we perform this assignment first, before modifying any
274 Initialize_Element
(New_Node
);
276 Container
.Free
:= Container
.Free
- 1;
278 if abs Container
.Free
> Container
.Capacity
then
283 Initialize_Node
(Container
, New_Node
);
286 procedure Allocate_Node
287 (Container
: in out Tree
;
288 New_Item
: Element_Type
;
289 New_Node
: out Count_Type
)
291 procedure Initialize_Element
(Index
: Count_Type
);
293 procedure Initialize_Element
(Index
: Count_Type
) is
295 Container
.Elements
(Index
) := New_Item
;
296 end Initialize_Element
;
299 Allocate_Node
(Container
, Initialize_Element
'Access, New_Node
);
302 procedure Allocate_Node
303 (Container
: in out Tree
;
304 Stream
: not null access Root_Stream_Type
'Class;
305 New_Node
: out Count_Type
)
307 procedure Initialize_Element
(Index
: Count_Type
);
309 procedure Initialize_Element
(Index
: Count_Type
) is
311 Element_Type
'Read (Stream
, Container
.Elements
(Index
));
312 end Initialize_Element
;
315 Allocate_Node
(Container
, Initialize_Element
'Access, New_Node
);
322 function Ancestor_Find
324 Item
: Element_Type
) return Cursor
329 if Checks
and then Position
= No_Element
then
330 raise Constraint_Error
with "Position cursor has no element";
333 -- AI-0136 says to raise PE if Position equals the root node. This does
334 -- not seem correct, as this value is just the limiting condition of the
335 -- search. For now we omit this check, pending a ruling from the ARG.
338 -- if Checks and then Is_Root (Position) then
339 -- raise Program_Error with "Position cursor designates root";
342 R
:= Root_Node
(Position
.Container
.all);
345 if Position
.Container
.Elements
(N
) = Item
then
346 return Cursor
'(Position.Container, N);
349 N := Position.Container.Nodes (N).Parent;
359 procedure Append_Child
360 (Container : in out Tree;
362 New_Item : Element_Type;
363 Count : Count_Type := 1)
365 Nodes : Tree_Node_Array renames Container.Nodes;
366 First, Last : Count_Type;
369 if Checks and then Parent = No_Element then
370 raise Constraint_Error with "Parent cursor has no element";
373 if Checks and then Parent.Container /= Container'Unrestricted_Access then
374 raise Program_Error with "Parent cursor not in container";
381 if Checks and then Container.Count > Container.Capacity - Count then
383 with "requested count exceeds available storage";
386 TC_Check (Container.TC);
388 if Container.Count = 0 then
389 Initialize_Root (Container);
392 Allocate_Node (Container, New_Item, First);
393 Nodes (First).Parent := Parent.Node;
396 for J in Count_Type'(2) .. Count
loop
397 Allocate_Node
(Container
, New_Item
, Nodes
(Last
).Next
);
398 Nodes
(Nodes
(Last
).Next
).Parent
:= Parent
.Node
;
399 Nodes
(Nodes
(Last
).Next
).Prev
:= Last
;
401 Last
:= Nodes
(Last
).Next
;
405 (Container
=> Container
,
408 Parent
=> Parent
.Node
,
409 Before
=> No_Node
); -- means "insert at end of list"
411 Container
.Count
:= Container
.Count
+ Count
;
418 procedure Assign
(Target
: in out Tree
; Source
: Tree
) is
419 Target_Count
: Count_Type
;
422 if Target
'Address = Source
'Address then
426 if Checks
and then Target
.Capacity
< Source
.Count
then
427 raise Capacity_Error
-- ???
428 with "Target capacity is less than Source count";
431 Target
.Clear
; -- Checks busy bit
433 if Source
.Count
= 0 then
437 Initialize_Root
(Target
);
439 -- Copy_Children returns the number of nodes that it allocates, but it
440 -- does this by incrementing the count value passed in, so we must
441 -- initialize the count before calling Copy_Children.
447 Source_Parent
=> Root_Node
(Source
),
449 Target_Parent
=> Root_Node
(Target
),
450 Count
=> Target_Count
);
452 pragma Assert
(Target_Count
= Source
.Count
);
453 Target
.Count
:= Source
.Count
;
460 function Child_Count
(Parent
: Cursor
) return Count_Type
is
462 if Parent
= No_Element
then
465 elsif Parent
.Container
.Count
= 0 then
466 pragma Assert
(Is_Root
(Parent
));
470 return Child_Count
(Parent
.Container
.all, Parent
.Node
);
476 Parent
: Count_Type
) return Count_Type
478 NN
: Tree_Node_Array
renames Container
.Nodes
;
479 CC
: Children_Type
renames NN
(Parent
).Children
;
482 Node
: Count_Type
'Base;
488 Result
:= Result
+ 1;
489 Node
:= NN
(Node
).Next
;
499 function Child_Depth
(Parent
, Child
: Cursor
) return Count_Type
is
504 if Checks
and then Parent
= No_Element
then
505 raise Constraint_Error
with "Parent cursor has no element";
508 if Checks
and then Child
= No_Element
then
509 raise Constraint_Error
with "Child cursor has no element";
512 if Checks
and then Parent
.Container
/= Child
.Container
then
513 raise Program_Error
with "Parent and Child in different containers";
516 if Parent
.Container
.Count
= 0 then
517 pragma Assert
(Is_Root
(Parent
));
518 pragma Assert
(Child
= Parent
);
524 while N
/= Parent
.Node
loop
525 Result
:= Result
+ 1;
526 N
:= Parent
.Container
.Nodes
(N
).Parent
;
528 if Checks
and then N
< 0 then
529 raise Program_Error
with "Parent is not ancestor of Child";
540 procedure Clear
(Container
: in out Tree
) is
541 Container_Count
: constant Count_Type
:= Container
.Count
;
545 TC_Check
(Container
.TC
);
547 if Container_Count
= 0 then
551 Container
.Count
:= 0;
553 -- Deallocate_Children returns the number of nodes that it deallocates,
554 -- but it does this by incrementing the count value that is passed in,
555 -- so we must first initialize the count return value before calling it.
560 (Container
=> Container
,
561 Subtree
=> Root_Node
(Container
),
564 pragma Assert
(Count
= Container_Count
);
567 ------------------------
568 -- Constant_Reference --
569 ------------------------
571 function Constant_Reference
572 (Container
: aliased Tree
;
573 Position
: Cursor
) return Constant_Reference_Type
576 if Checks
and then Position
.Container
= null then
577 raise Constraint_Error
with
578 "Position cursor has no element";
581 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
583 raise Program_Error
with
584 "Position cursor designates wrong container";
587 if Checks
and then Position
.Node
= Root_Node
(Container
) then
588 raise Program_Error
with "Position cursor designates root";
591 -- Implement Vet for multiway tree???
592 -- pragma Assert (Vet (Position),
593 -- "Position cursor in Constant_Reference is bad");
596 TC
: constant Tamper_Counts_Access
:=
597 Container
.TC
'Unrestricted_Access;
599 return R
: constant Constant_Reference_Type
:=
600 (Element
=> Container
.Elements
(Position
.Node
)'Access,
601 Control
=> (Controlled
with TC
))
606 end Constant_Reference
;
614 Item
: Element_Type
) return Boolean
617 return Find
(Container
, Item
) /= No_Element
;
626 Capacity
: Count_Type
:= 0) return Tree
633 elsif Capacity
>= Source
.Count
then
636 raise Capacity_Error
with "Capacity value too small";
639 return Target
: Tree
(Capacity
=> C
) do
640 Initialize_Root
(Target
);
642 if Source
.Count
= 0 then
648 Source_Parent
=> Root_Node
(Source
),
650 Target_Parent
=> Root_Node
(Target
),
651 Count
=> Target
.Count
);
653 pragma Assert
(Target
.Count
= Source
.Count
);
661 procedure Copy_Children
663 Source_Parent
: Count_Type
;
664 Target
: in out Tree
;
665 Target_Parent
: Count_Type
;
666 Count
: in out Count_Type
)
668 S_Nodes
: Tree_Node_Array
renames Source
.Nodes
;
669 S_Node
: Tree_Node_Type
renames S_Nodes
(Source_Parent
);
671 T_Nodes
: Tree_Node_Array
renames Target
.Nodes
;
672 T_Node
: Tree_Node_Type
renames T_Nodes
(Target_Parent
);
674 pragma Assert
(T_Node
.Children
.First
<= 0);
675 pragma Assert
(T_Node
.Children
.Last
<= 0);
677 T_CC
: Children_Type
;
681 -- We special-case the first allocation, in order to establish the
682 -- representation invariants for type Children_Type.
684 C
:= S_Node
.Children
.First
;
686 if C
<= 0 then -- source parent has no children
694 Target_Parent
=> Target_Parent
,
695 Target_Subtree
=> T_CC
.First
,
698 T_CC
.Last
:= T_CC
.First
;
700 -- The representation invariants for the Children_Type list have been
701 -- established, so we can now copy the remaining children of Source.
703 C
:= S_Nodes
(C
).Next
;
709 Target_Parent
=> Target_Parent
,
710 Target_Subtree
=> T_Nodes
(T_CC
.Last
).Next
,
713 T_Nodes
(T_Nodes
(T_CC
.Last
).Next
).Prev
:= T_CC
.Last
;
714 T_CC
.Last
:= T_Nodes
(T_CC
.Last
).Next
;
716 C
:= S_Nodes
(C
).Next
;
719 -- We add the newly-allocated children to their parent list only after
720 -- the allocation has succeeded, in order to preserve invariants of the
723 T_Node
.Children
:= T_CC
;
730 procedure Copy_Subtree
731 (Target
: in out Tree
;
736 Target_Subtree
: Count_Type
;
737 Target_Count
: Count_Type
;
740 if Checks
and then Parent
= No_Element
then
741 raise Constraint_Error
with "Parent cursor has no element";
744 if Checks
and then Parent
.Container
/= Target
'Unrestricted_Access then
745 raise Program_Error
with "Parent cursor not in container";
748 if Before
/= No_Element
then
749 if Checks
and then Before
.Container
/= Target
'Unrestricted_Access then
750 raise Program_Error
with "Before cursor not in container";
754 Before
.Container
.Nodes
(Before
.Node
).Parent
/= Parent
.Node
756 raise Constraint_Error
with "Before cursor not child of Parent";
760 if Source
= No_Element
then
764 if Checks
and then Is_Root
(Source
) then
765 raise Constraint_Error
with "Source cursor designates root";
768 if Target
.Count
= 0 then
769 Initialize_Root
(Target
);
772 -- Copy_Subtree returns a count of the number of nodes that it
773 -- allocates, but it works by incrementing the value that is passed
774 -- in. We must therefore initialize the count value before calling
780 (Source
=> Source
.Container
.all,
781 Source_Subtree
=> Source
.Node
,
783 Target_Parent
=> Parent
.Node
,
784 Target_Subtree
=> Target_Subtree
,
785 Count
=> Target_Count
);
788 (Container
=> Target
,
789 Subtree
=> Target_Subtree
,
790 Parent
=> Parent
.Node
,
791 Before
=> Before
.Node
);
793 Target
.Count
:= Target
.Count
+ Target_Count
;
796 procedure Copy_Subtree
798 Source_Subtree
: Count_Type
;
799 Target
: in out Tree
;
800 Target_Parent
: Count_Type
;
801 Target_Subtree
: out Count_Type
;
802 Count
: in out Count_Type
)
804 T_Nodes
: Tree_Node_Array
renames Target
.Nodes
;
807 -- First we allocate the root of the target subtree.
810 (Container
=> Target
,
811 New_Item
=> Source
.Elements
(Source_Subtree
),
812 New_Node
=> Target_Subtree
);
814 T_Nodes
(Target_Subtree
).Parent
:= Target_Parent
;
817 -- We now have a new subtree (for the Target tree), containing only a
818 -- copy of the corresponding element in the Source subtree. Next we copy
819 -- the children of the Source subtree as children of the new Target
824 Source_Parent
=> Source_Subtree
,
826 Target_Parent
=> Target_Subtree
,
830 -------------------------
831 -- Deallocate_Children --
832 -------------------------
834 procedure Deallocate_Children
835 (Container
: in out Tree
;
836 Subtree
: Count_Type
;
837 Count
: in out Count_Type
)
839 Nodes
: Tree_Node_Array
renames Container
.Nodes
;
840 Node
: Tree_Node_Type
renames Nodes
(Subtree
); -- parent
841 CC
: Children_Type
renames Node
.Children
;
845 while CC
.First
> 0 loop
847 CC
.First
:= Nodes
(C
).Next
;
849 Deallocate_Subtree
(Container
, C
, Count
);
853 end Deallocate_Children
;
855 ---------------------
856 -- Deallocate_Node --
857 ---------------------
859 procedure Deallocate_Node
860 (Container
: in out Tree
;
863 NN
: Tree_Node_Array
renames Container
.Nodes
;
864 pragma Assert
(X
> 0);
865 pragma Assert
(X
<= NN
'Last);
867 N
: Tree_Node_Type
renames NN
(X
);
868 pragma Assert
(N
.Parent
/= X
); -- node is active
871 -- The tree container actually contains two lists: one for the "active"
872 -- nodes that contain elements that have been inserted onto the tree,
873 -- and another for the "inactive" nodes of the free store, from which
874 -- nodes are allocated when a new child is inserted in the tree.
876 -- We desire that merely declaring a tree object should have only
877 -- minimal cost; specially, we want to avoid having to initialize the
878 -- free store (to fill in the links), especially if the capacity of the
879 -- tree object is large.
881 -- The head of the free list is indicated by Container.Free. If its
882 -- value is non-negative, then the free store has been initialized in
883 -- the "normal" way: Container.Free points to the head of the list of
884 -- free (inactive) nodes, and the value 0 means the free list is
885 -- empty. Each node on the free list has been initialized to point to
886 -- the next free node (via its Next component), and the value 0 means
887 -- that this is the last node of the free list.
889 -- If Container.Free is negative, then the links on the free store have
890 -- not been initialized. In this case the link values are implied: the
891 -- free store comprises the components of the node array started with
892 -- the absolute value of Container.Free, and continuing until the end of
893 -- the array (Nodes'Last).
895 -- We prefer to lazy-init the free store (in fact, we would prefer to
896 -- not initialize it at all, because such initialization is an O(n)
897 -- operation). The time when we need to actually initialize the nodes in
898 -- the free store is when the node that becomes inactive is not at the
899 -- end of the active list. The free store would then be discontigous and
900 -- so its nodes would need to be linked in the traditional way.
902 -- It might be possible to perform an optimization here. Suppose that
903 -- the free store can be represented as having two parts: one comprising
904 -- the non-contiguous inactive nodes linked together in the normal way,
905 -- and the other comprising the contiguous inactive nodes (that are not
906 -- linked together, at the end of the nodes array). This would allow us
907 -- to never have to initialize the free store, except in a lazy way as
908 -- nodes become inactive. ???
910 -- When an element is deleted from the list container, its node becomes
911 -- inactive, and so we set its Parent and Prev components to an
912 -- impossible value (the index of the node itself), to indicate that it
913 -- is now inactive. This provides a useful way to detect a dangling
916 N
.Parent
:= X
; -- Node is deallocated (not on active list)
919 if Container
.Free
>= 0 then
920 -- The free store has previously been initialized. All we need to do
921 -- here is link the newly-free'd node onto the free list.
923 N
.Next
:= Container
.Free
;
926 elsif X
+ 1 = abs Container
.Free
then
927 -- The free store has not been initialized, and the node becoming
928 -- inactive immediately precedes the start of the free store. All
929 -- we need to do is move the start of the free store back by one.
931 N
.Next
:= X
; -- Not strictly necessary, but marginally safer
932 Container
.Free
:= Container
.Free
+ 1;
935 -- The free store has not been initialized, and the node becoming
936 -- inactive does not immediately precede the free store. Here we
937 -- first initialize the free store (meaning the links are given
938 -- values in the traditional way), and then link the newly-free'd
939 -- node onto the head of the free store.
941 -- See the comments above for an optimization opportunity. If the
942 -- next link for a node on the free store is negative, then this
943 -- means the remaining nodes on the free store are physically
944 -- contiguous, starting at the absolute value of that index value.
947 Container
.Free
:= abs Container
.Free
;
949 if Container
.Free
> Container
.Capacity
then
953 for J
in Container
.Free
.. Container
.Capacity
- 1 loop
954 NN
(J
).Next
:= J
+ 1;
957 NN
(Container
.Capacity
).Next
:= 0;
960 NN
(X
).Next
:= Container
.Free
;
965 ------------------------
966 -- Deallocate_Subtree --
967 ------------------------
969 procedure Deallocate_Subtree
970 (Container
: in out Tree
;
971 Subtree
: Count_Type
;
972 Count
: in out Count_Type
)
975 Deallocate_Children
(Container
, Subtree
, Count
);
976 Deallocate_Node
(Container
, Subtree
);
978 end Deallocate_Subtree
;
980 ---------------------
981 -- Delete_Children --
982 ---------------------
984 procedure Delete_Children
985 (Container
: in out Tree
;
991 if Checks
and then Parent
= No_Element
then
992 raise Constraint_Error
with "Parent cursor has no element";
995 if Checks
and then Parent
.Container
/= Container
'Unrestricted_Access then
996 raise Program_Error
with "Parent cursor not in container";
999 TC_Check
(Container
.TC
);
1001 if Container
.Count
= 0 then
1002 pragma Assert
(Is_Root
(Parent
));
1006 -- Deallocate_Children returns a count of the number of nodes that it
1007 -- deallocates, but it works by incrementing the value that is passed
1008 -- in. We must therefore initialize the count value before calling
1009 -- Deallocate_Children.
1013 Deallocate_Children
(Container
, Parent
.Node
, Count
);
1014 pragma Assert
(Count
<= Container
.Count
);
1016 Container
.Count
:= Container
.Count
- Count
;
1017 end Delete_Children
;
1023 procedure Delete_Leaf
1024 (Container
: in out Tree
;
1025 Position
: in out Cursor
)
1030 if Checks
and then Position
= No_Element
then
1031 raise Constraint_Error
with "Position cursor has no element";
1034 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
1036 raise Program_Error
with "Position cursor not in container";
1039 if Checks
and then Is_Root
(Position
) then
1040 raise Program_Error
with "Position cursor designates root";
1043 if Checks
and then not Is_Leaf
(Position
) then
1044 raise Constraint_Error
with "Position cursor does not designate leaf";
1047 TC_Check
(Container
.TC
);
1050 Position
:= No_Element
;
1052 Remove_Subtree
(Container
, X
);
1053 Container
.Count
:= Container
.Count
- 1;
1055 Deallocate_Node
(Container
, X
);
1058 --------------------
1059 -- Delete_Subtree --
1060 --------------------
1062 procedure Delete_Subtree
1063 (Container
: in out Tree
;
1064 Position
: in out Cursor
)
1070 if Checks
and then Position
= No_Element
then
1071 raise Constraint_Error
with "Position cursor has no element";
1074 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
1076 raise Program_Error
with "Position cursor not in container";
1079 if Checks
and then Is_Root
(Position
) then
1080 raise Program_Error
with "Position cursor designates root";
1083 TC_Check
(Container
.TC
);
1086 Position
:= No_Element
;
1088 Remove_Subtree
(Container
, X
);
1090 -- Deallocate_Subtree returns a count of the number of nodes that it
1091 -- deallocates, but it works by incrementing the value that is passed
1092 -- in. We must therefore initialize the count value before calling
1093 -- Deallocate_Subtree.
1097 Deallocate_Subtree
(Container
, X
, Count
);
1098 pragma Assert
(Count
<= Container
.Count
);
1100 Container
.Count
:= Container
.Count
- Count
;
1107 function Depth
(Position
: Cursor
) return Count_Type
is
1108 Result
: Count_Type
;
1109 N
: Count_Type
'Base;
1112 if Position
= No_Element
then
1116 if Is_Root
(Position
) then
1123 N
:= Position
.Container
.Nodes
(N
).Parent
;
1124 Result
:= Result
+ 1;
1134 function Element
(Position
: Cursor
) return Element_Type
is
1136 if Checks
and then Position
.Container
= null then
1137 raise Constraint_Error
with "Position cursor has no element";
1140 if Checks
and then Position
.Node
= Root_Node
(Position
.Container
.all)
1142 raise Program_Error
with "Position cursor designates root";
1145 return Position
.Container
.Elements
(Position
.Node
);
1148 --------------------
1149 -- Equal_Children --
1150 --------------------
1152 function Equal_Children
1154 Left_Subtree
: Count_Type
;
1156 Right_Subtree
: Count_Type
) return Boolean
1158 L_NN
: Tree_Node_Array
renames Left_Tree
.Nodes
;
1159 R_NN
: Tree_Node_Array
renames Right_Tree
.Nodes
;
1161 Left_Children
: Children_Type
renames L_NN
(Left_Subtree
).Children
;
1162 Right_Children
: Children_Type
renames R_NN
(Right_Subtree
).Children
;
1164 L
, R
: Count_Type
'Base;
1167 if Child_Count
(Left_Tree
, Left_Subtree
)
1168 /= Child_Count
(Right_Tree
, Right_Subtree
)
1173 L
:= Left_Children
.First
;
1174 R
:= Right_Children
.First
;
1176 if not Equal_Subtree
(Left_Tree
, L
, Right_Tree
, R
) then
1191 function Equal_Subtree
1192 (Left_Position
: Cursor
;
1193 Right_Position
: Cursor
) return Boolean
1196 if Checks
and then Left_Position
= No_Element
then
1197 raise Constraint_Error
with "Left cursor has no element";
1200 if Checks
and then Right_Position
= No_Element
then
1201 raise Constraint_Error
with "Right cursor has no element";
1204 if Left_Position
= Right_Position
then
1208 if Is_Root
(Left_Position
) then
1209 if not Is_Root
(Right_Position
) then
1213 if Left_Position
.Container
.Count
= 0 then
1214 return Right_Position
.Container
.Count
= 0;
1217 if Right_Position
.Container
.Count
= 0 then
1221 return Equal_Children
1222 (Left_Tree
=> Left_Position
.Container
.all,
1223 Left_Subtree
=> Left_Position
.Node
,
1224 Right_Tree
=> Right_Position
.Container
.all,
1225 Right_Subtree
=> Right_Position
.Node
);
1228 if Is_Root
(Right_Position
) then
1232 return Equal_Subtree
1233 (Left_Tree
=> Left_Position
.Container
.all,
1234 Left_Subtree
=> Left_Position
.Node
,
1235 Right_Tree
=> Right_Position
.Container
.all,
1236 Right_Subtree
=> Right_Position
.Node
);
1239 function Equal_Subtree
1241 Left_Subtree
: Count_Type
;
1243 Right_Subtree
: Count_Type
) return Boolean
1246 if Left_Tree
.Elements
(Left_Subtree
) /=
1247 Right_Tree
.Elements
(Right_Subtree
)
1252 return Equal_Children
1253 (Left_Tree
=> Left_Tree
,
1254 Left_Subtree
=> Left_Subtree
,
1255 Right_Tree
=> Right_Tree
,
1256 Right_Subtree
=> Right_Subtree
);
1263 procedure Finalize
(Object
: in out Root_Iterator
) is
1265 Unbusy
(Object
.Container
.TC
);
1274 Item
: Element_Type
) return Cursor
1279 if Container
.Count
= 0 then
1283 Node
:= Find_In_Children
(Container
, Root_Node
(Container
), Item
);
1289 return Cursor
'(Container'Unrestricted_Access, Node);
1296 overriding function First (Object : Subtree_Iterator) return Cursor is
1298 if Object.Subtree = Root_Node (Object.Container.all) then
1299 return First_Child (Root (Object.Container.all));
1301 return Cursor'(Object
.Container
, Object
.Subtree
);
1305 overriding
function First
(Object
: Child_Iterator
) return Cursor
is
1307 return First_Child
(Cursor
'(Object.Container, Object.Subtree));
1314 function First_Child (Parent : Cursor) return Cursor is
1315 Node : Count_Type'Base;
1318 if Checks and then Parent = No_Element then
1319 raise Constraint_Error with "Parent cursor has no element";
1322 if Parent.Container.Count = 0 then
1323 pragma Assert (Is_Root (Parent));
1327 Node := Parent.Container.Nodes (Parent.Node).Children.First;
1333 return Cursor'(Parent
.Container
, Node
);
1336 -------------------------
1337 -- First_Child_Element --
1338 -------------------------
1340 function First_Child_Element
(Parent
: Cursor
) return Element_Type
is
1342 return Element
(First_Child
(Parent
));
1343 end First_Child_Element
;
1345 ----------------------
1346 -- Find_In_Children --
1347 ----------------------
1349 function Find_In_Children
1351 Subtree
: Count_Type
;
1352 Item
: Element_Type
) return Count_Type
1354 N
: Count_Type
'Base;
1355 Result
: Count_Type
;
1358 N
:= Container
.Nodes
(Subtree
).Children
.First
;
1360 Result
:= Find_In_Subtree
(Container
, N
, Item
);
1366 N
:= Container
.Nodes
(N
).Next
;
1370 end Find_In_Children
;
1372 ---------------------
1373 -- Find_In_Subtree --
1374 ---------------------
1376 function Find_In_Subtree
1378 Item
: Element_Type
) return Cursor
1380 Result
: Count_Type
;
1383 if Checks
and then Position
= No_Element
then
1384 raise Constraint_Error
with "Position cursor has no element";
1387 -- Commented-out pending ruling by ARG. ???
1389 -- if Checks and then
1390 -- Position.Container /= Container'Unrestricted_Access
1392 -- raise Program_Error with "Position cursor not in container";
1395 if Position
.Container
.Count
= 0 then
1396 pragma Assert
(Is_Root
(Position
));
1400 if Is_Root
(Position
) then
1401 Result
:= Find_In_Children
1402 (Container
=> Position
.Container
.all,
1403 Subtree
=> Position
.Node
,
1407 Result
:= Find_In_Subtree
1408 (Container
=> Position
.Container
.all,
1409 Subtree
=> Position
.Node
,
1417 return Cursor
'(Position.Container, Result);
1418 end Find_In_Subtree;
1420 function Find_In_Subtree
1422 Subtree : Count_Type;
1423 Item : Element_Type) return Count_Type
1426 if Container.Elements (Subtree) = Item then
1430 return Find_In_Children (Container, Subtree, Item);
1431 end Find_In_Subtree;
1433 ------------------------
1434 -- Get_Element_Access --
1435 ------------------------
1437 function Get_Element_Access
1438 (Position : Cursor) return not null Element_Access is
1440 return Position.Container.Elements (Position.Node)'Access;
1441 end Get_Element_Access;
1447 function Has_Element (Position : Cursor) return Boolean is
1449 if Position = No_Element then
1453 return Position.Node /= Root_Node (Position.Container.all);
1456 ---------------------
1457 -- Initialize_Node --
1458 ---------------------
1460 procedure Initialize_Node
1461 (Container : in out Tree;
1465 Container.Nodes (Index) :=
1469 Children => (others => 0));
1470 end Initialize_Node;
1472 ---------------------
1473 -- Initialize_Root --
1474 ---------------------
1476 procedure Initialize_Root (Container : in out Tree) is
1478 Initialize_Node (Container, Root_Node (Container));
1479 end Initialize_Root;
1485 procedure Insert_Child
1486 (Container : in out Tree;
1489 New_Item : Element_Type;
1490 Count : Count_Type := 1)
1493 pragma Unreferenced (Position);
1496 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1499 procedure Insert_Child
1500 (Container : in out Tree;
1503 New_Item : Element_Type;
1504 Position : out Cursor;
1505 Count : Count_Type := 1)
1507 Nodes : Tree_Node_Array renames Container.Nodes;
1512 if Checks and then Parent = No_Element then
1513 raise Constraint_Error with "Parent cursor has no element";
1516 if Checks and then Parent.Container /= Container'Unrestricted_Access then
1517 raise Program_Error with "Parent cursor not in container";
1520 if Before /= No_Element then
1521 if Checks and then Before.Container /= Container'Unrestricted_Access
1523 raise Program_Error with "Before cursor not in container";
1527 Before.Container.Nodes (Before.Node).Parent /= Parent.Node
1529 raise Constraint_Error with "Parent cursor not parent of Before";
1534 Position := No_Element; -- Need ruling from ARG ???
1538 if Checks and then Container.Count > Container.Capacity - Count then
1539 raise Capacity_Error
1540 with "requested count exceeds available storage";
1543 TC_Check (Container.TC);
1545 if Container.Count = 0 then
1546 Initialize_Root (Container);
1549 Allocate_Node (Container, New_Item, First);
1550 Nodes (First).Parent := Parent.Node;
1553 for J in Count_Type'(2) .. Count
loop
1554 Allocate_Node
(Container
, New_Item
, Nodes
(Last
).Next
);
1555 Nodes
(Nodes
(Last
).Next
).Parent
:= Parent
.Node
;
1556 Nodes
(Nodes
(Last
).Next
).Prev
:= Last
;
1558 Last
:= Nodes
(Last
).Next
;
1562 (Container
=> Container
,
1565 Parent
=> Parent
.Node
,
1566 Before
=> Before
.Node
);
1568 Container
.Count
:= Container
.Count
+ Count
;
1570 Position
:= Cursor
'(Parent.Container, First);
1573 procedure Insert_Child
1574 (Container : in out Tree;
1577 Position : out Cursor;
1578 Count : Count_Type := 1)
1580 Nodes : Tree_Node_Array renames Container.Nodes;
1584 New_Item : Element_Type;
1585 pragma Unmodified (New_Item);
1586 -- OK to reference, see below
1589 if Checks and then Parent = No_Element then
1590 raise Constraint_Error with "Parent cursor has no element";
1593 if Checks and then Parent.Container /= Container'Unrestricted_Access then
1594 raise Program_Error with "Parent cursor not in container";
1597 if Before /= No_Element then
1598 if Checks and then Before.Container /= Container'Unrestricted_Access
1600 raise Program_Error with "Before cursor not in container";
1604 Before.Container.Nodes (Before.Node).Parent /= Parent.Node
1606 raise Constraint_Error with "Parent cursor not parent of Before";
1611 Position := No_Element; -- Need ruling from ARG ???
1615 if Checks and then Container.Count > Container.Capacity - Count then
1616 raise Capacity_Error
1617 with "requested count exceeds available storage";
1620 TC_Check (Container.TC);
1622 if Container.Count = 0 then
1623 Initialize_Root (Container);
1626 -- There is no explicit element provided, but in an instance the element
1627 -- type may be a scalar with a Default_Value aspect, or a composite
1628 -- type with such a scalar component, or components with default
1629 -- initialization, so insert the specified number of possibly
1630 -- initialized elements at the given position.
1632 Allocate_Node (Container, New_Item, First);
1633 Nodes (First).Parent := Parent.Node;
1636 for J in Count_Type'(2) .. Count
loop
1637 Allocate_Node
(Container
, New_Item
, Nodes
(Last
).Next
);
1638 Nodes
(Nodes
(Last
).Next
).Parent
:= Parent
.Node
;
1639 Nodes
(Nodes
(Last
).Next
).Prev
:= Last
;
1641 Last
:= Nodes
(Last
).Next
;
1645 (Container
=> Container
,
1648 Parent
=> Parent
.Node
,
1649 Before
=> Before
.Node
);
1651 Container
.Count
:= Container
.Count
+ Count
;
1653 Position
:= Cursor
'(Parent.Container, First);
1656 -------------------------
1657 -- Insert_Subtree_List --
1658 -------------------------
1660 procedure Insert_Subtree_List
1661 (Container : in out Tree;
1662 First : Count_Type'Base;
1663 Last : Count_Type'Base;
1664 Parent : Count_Type;
1665 Before : Count_Type'Base)
1667 NN : Tree_Node_Array renames Container.Nodes;
1668 N : Tree_Node_Type renames NN (Parent);
1669 CC : Children_Type renames N.Children;
1672 -- This is a simple utility operation to insert a list of nodes
1673 -- (First..Last) as children of Parent. The Before node specifies where
1674 -- the new children should be inserted relative to existing children.
1677 pragma Assert (Last <= 0);
1681 pragma Assert (Last > 0);
1682 pragma Assert (Before <= 0 or else NN (Before).Parent = Parent);
1684 if CC.First <= 0 then -- no existing children
1686 NN (CC.First).Prev := 0;
1688 NN (CC.Last).Next := 0;
1690 elsif Before <= 0 then -- means "insert after existing nodes"
1691 NN (CC.Last).Next := First;
1692 NN (First).Prev := CC.Last;
1694 NN (CC.Last).Next := 0;
1696 elsif Before = CC.First then
1697 NN (Last).Next := CC.First;
1698 NN (CC.First).Prev := Last;
1700 NN (CC.First).Prev := 0;
1703 NN (NN (Before).Prev).Next := First;
1704 NN (First).Prev := NN (Before).Prev;
1705 NN (Last).Next := Before;
1706 NN (Before).Prev := Last;
1708 end Insert_Subtree_List;
1710 -------------------------
1711 -- Insert_Subtree_Node --
1712 -------------------------
1714 procedure Insert_Subtree_Node
1715 (Container : in out Tree;
1716 Subtree : Count_Type'Base;
1717 Parent : Count_Type;
1718 Before : Count_Type'Base)
1721 -- This is a simple wrapper operation to insert a single child into the
1722 -- Parent's children list.
1725 (Container => Container,
1730 end Insert_Subtree_Node;
1736 function Is_Empty (Container : Tree) return Boolean is
1738 return Container.Count = 0;
1745 function Is_Leaf (Position : Cursor) return Boolean is
1747 if Position = No_Element then
1751 if Position.Container.Count = 0 then
1752 pragma Assert (Is_Root (Position));
1756 return Position.Container.Nodes (Position.Node).Children.First <= 0;
1763 function Is_Reachable
1765 From, To : Count_Type) return Boolean
1776 Idx := Container.Nodes (Idx).Parent;
1786 function Is_Root (Position : Cursor) return Boolean is
1789 (if Position.Container = null then False
1790 else Position.Node = Root_Node (Position.Container.all));
1799 Process : not null access procedure (Position : Cursor))
1801 Busy : With_Busy (Container.TC'Unrestricted_Access);
1803 if Container.Count = 0 then
1808 (Container => Container,
1809 Subtree => Root_Node (Container),
1810 Process => Process);
1813 function Iterate (Container : Tree)
1814 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1817 return Iterate_Subtree (Root (Container));
1820 ----------------------
1821 -- Iterate_Children --
1822 ----------------------
1824 procedure Iterate_Children
1826 Process : not null access procedure (Position : Cursor))
1829 if Checks and then Parent = No_Element then
1830 raise Constraint_Error with "Parent cursor has no element";
1833 if Parent.Container.Count = 0 then
1834 pragma Assert (Is_Root (Parent));
1840 NN : Tree_Node_Array renames Parent.Container.Nodes;
1841 Busy : With_Busy (Parent.Container.TC'Unrestricted_Access);
1844 C := NN (Parent.Node).Children.First;
1846 Process (Cursor'(Parent
.Container
, Node
=> C
));
1850 end Iterate_Children
;
1852 procedure Iterate_Children
1854 Subtree
: Count_Type
;
1855 Process
: not null access procedure (Position
: Cursor
))
1857 NN
: Tree_Node_Array
renames Container
.Nodes
;
1858 N
: Tree_Node_Type
renames NN
(Subtree
);
1862 -- This is a helper function to recursively iterate over all the nodes
1863 -- in a subtree, in depth-first fashion. This particular helper just
1864 -- visits the children of this subtree, not the root of the subtree
1865 -- itself. This is useful when starting from the ultimate root of the
1866 -- entire tree (see Iterate), as that root does not have an element.
1868 C
:= N
.Children
.First
;
1870 Iterate_Subtree
(Container
, C
, Process
);
1873 end Iterate_Children
;
1875 function Iterate_Children
1878 return Tree_Iterator_Interfaces
.Reversible_Iterator
'Class
1880 C
: constant Tree_Access
:= Container
'Unrestricted_Access;
1882 if Checks
and then Parent
= No_Element
then
1883 raise Constraint_Error
with "Parent cursor has no element";
1886 if Checks
and then Parent
.Container
/= C
then
1887 raise Program_Error
with "Parent cursor not in container";
1890 return It
: constant Child_Iterator
:=
1891 Child_Iterator
'(Limited_Controlled with
1893 Subtree => Parent.Node)
1897 end Iterate_Children;
1899 ---------------------
1900 -- Iterate_Subtree --
1901 ---------------------
1903 function Iterate_Subtree
1905 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1907 C : constant Tree_Access := Position.Container;
1909 if Checks and then Position = No_Element then
1910 raise Constraint_Error with "Position cursor has no element";
1913 -- Implement Vet for multiway trees???
1914 -- pragma Assert (Vet (Position), "bad subtree cursor");
1916 return It : constant Subtree_Iterator :=
1917 (Limited_Controlled with
1919 Subtree => Position.Node)
1923 end Iterate_Subtree;
1925 procedure Iterate_Subtree
1927 Process : not null access procedure (Position : Cursor))
1930 if Checks and then Position = No_Element then
1931 raise Constraint_Error with "Position cursor has no element";
1934 if Position.Container.Count = 0 then
1935 pragma Assert (Is_Root (Position));
1940 T : Tree renames Position.Container.all;
1941 Busy : With_Busy (T.TC'Unrestricted_Access);
1943 if Is_Root (Position) then
1944 Iterate_Children (T, Position.Node, Process);
1946 Iterate_Subtree (T, Position.Node, Process);
1949 end Iterate_Subtree;
1951 procedure Iterate_Subtree
1953 Subtree : Count_Type;
1954 Process : not null access procedure (Position : Cursor))
1957 -- This is a helper function to recursively iterate over all the nodes
1958 -- in a subtree, in depth-first fashion. It first visits the root of the
1959 -- subtree, then visits its children.
1961 Process (Cursor'(Container
'Unrestricted_Access, Subtree
));
1962 Iterate_Children
(Container
, Subtree
, Process
);
1963 end Iterate_Subtree
;
1969 overriding
function Last
(Object
: Child_Iterator
) return Cursor
is
1971 return Last_Child
(Cursor
'(Object.Container, Object.Subtree));
1978 function Last_Child (Parent : Cursor) return Cursor is
1979 Node : Count_Type'Base;
1982 if Checks and then Parent = No_Element then
1983 raise Constraint_Error with "Parent cursor has no element";
1986 if Parent.Container.Count = 0 then
1987 pragma Assert (Is_Root (Parent));
1991 Node := Parent.Container.Nodes (Parent.Node).Children.Last;
1997 return Cursor'(Parent
.Container
, Node
);
2000 ------------------------
2001 -- Last_Child_Element --
2002 ------------------------
2004 function Last_Child_Element
(Parent
: Cursor
) return Element_Type
is
2006 return Element
(Last_Child
(Parent
));
2007 end Last_Child_Element
;
2013 procedure Move
(Target
: in out Tree
; Source
: in out Tree
) is
2015 if Target
'Address = Source
'Address then
2019 TC_Check
(Source
.TC
);
2021 Target
.Assign
(Source
);
2029 overriding
function Next
2030 (Object
: Subtree_Iterator
;
2031 Position
: Cursor
) return Cursor
2034 if Position
.Container
= null then
2038 if Checks
and then Position
.Container
/= Object
.Container
then
2039 raise Program_Error
with
2040 "Position cursor of Next designates wrong tree";
2043 pragma Assert
(Object
.Container
.Count
> 0);
2044 pragma Assert
(Position
.Node
/= Root_Node
(Object
.Container
.all));
2047 Nodes
: Tree_Node_Array
renames Object
.Container
.Nodes
;
2051 Node
:= Position
.Node
;
2053 if Nodes
(Node
).Children
.First
> 0 then
2054 return Cursor
'(Object.Container, Nodes (Node).Children.First);
2057 while Node /= Object.Subtree loop
2058 if Nodes (Node).Next > 0 then
2059 return Cursor'(Object
.Container
, Nodes
(Node
).Next
);
2062 Node
:= Nodes
(Node
).Parent
;
2069 overriding
function Next
2070 (Object
: Child_Iterator
;
2071 Position
: Cursor
) return Cursor
2074 if Position
.Container
= null then
2078 if Checks
and then Position
.Container
/= Object
.Container
then
2079 raise Program_Error
with
2080 "Position cursor of Next designates wrong tree";
2083 pragma Assert
(Object
.Container
.Count
> 0);
2084 pragma Assert
(Position
.Node
/= Root_Node
(Object
.Container
.all));
2086 return Next_Sibling
(Position
);
2093 function Next_Sibling
(Position
: Cursor
) return Cursor
is
2095 if Position
= No_Element
then
2099 if Position
.Container
.Count
= 0 then
2100 pragma Assert
(Is_Root
(Position
));
2105 T
: Tree
renames Position
.Container
.all;
2106 NN
: Tree_Node_Array
renames T
.Nodes
;
2107 N
: Tree_Node_Type
renames NN
(Position
.Node
);
2114 return Cursor
'(Position.Container, N.Next);
2118 procedure Next_Sibling (Position : in out Cursor) is
2120 Position := Next_Sibling (Position);
2127 function Node_Count (Container : Tree) return Count_Type is
2129 -- Container.Count is the number of nodes we have actually allocated. We
2130 -- cache the value specifically so this Node_Count operation can execute
2131 -- in O(1) time, which makes it behave similarly to how the Length
2132 -- selector function behaves for other containers.
2134 -- The cached node count value only describes the nodes we have
2135 -- allocated; the root node itself is not included in that count. The
2136 -- Node_Count operation returns a value that includes the root node
2137 -- (because the RM says so), so we must add 1 to our cached value.
2139 return 1 + Container.Count;
2146 function Parent (Position : Cursor) return Cursor is
2148 if Position = No_Element then
2152 if Position.Container.Count = 0 then
2153 pragma Assert (Is_Root (Position));
2158 T : Tree renames Position.Container.all;
2159 NN : Tree_Node_Array renames T.Nodes;
2160 N : Tree_Node_Type renames NN (Position.Node);
2163 if N.Parent < 0 then
2164 pragma Assert (Position.Node = Root_Node (T));
2168 return Cursor'(Position
.Container
, N
.Parent
);
2176 procedure Prepend_Child
2177 (Container
: in out Tree
;
2179 New_Item
: Element_Type
;
2180 Count
: Count_Type
:= 1)
2182 Nodes
: Tree_Node_Array
renames Container
.Nodes
;
2183 First
, Last
: Count_Type
;
2186 if Checks
and then Parent
= No_Element
then
2187 raise Constraint_Error
with "Parent cursor has no element";
2190 if Checks
and then Parent
.Container
/= Container
'Unrestricted_Access then
2191 raise Program_Error
with "Parent cursor not in container";
2198 if Checks
and then Container
.Count
> Container
.Capacity
- Count
then
2199 raise Capacity_Error
2200 with "requested count exceeds available storage";
2203 TC_Check
(Container
.TC
);
2205 if Container
.Count
= 0 then
2206 Initialize_Root
(Container
);
2209 Allocate_Node
(Container
, New_Item
, First
);
2210 Nodes
(First
).Parent
:= Parent
.Node
;
2213 for J
in Count_Type
'(2) .. Count loop
2214 Allocate_Node (Container, New_Item, Nodes (Last).Next);
2215 Nodes (Nodes (Last).Next).Parent := Parent.Node;
2216 Nodes (Nodes (Last).Next).Prev := Last;
2218 Last := Nodes (Last).Next;
2222 (Container => Container,
2225 Parent => Parent.Node,
2226 Before => Nodes (Parent.Node).Children.First);
2228 Container.Count := Container.Count + Count;
2235 overriding function Previous
2236 (Object : Child_Iterator;
2237 Position : Cursor) return Cursor
2240 if Position.Container = null then
2244 if Checks and then Position.Container /= Object.Container then
2245 raise Program_Error with
2246 "Position cursor of Previous designates wrong tree";
2249 return Previous_Sibling (Position);
2252 ----------------------
2253 -- Previous_Sibling --
2254 ----------------------
2256 function Previous_Sibling (Position : Cursor) return Cursor is
2258 if Position = No_Element then
2262 if Position.Container.Count = 0 then
2263 pragma Assert (Is_Root (Position));
2268 T : Tree renames Position.Container.all;
2269 NN : Tree_Node_Array renames T.Nodes;
2270 N : Tree_Node_Type renames NN (Position.Node);
2277 return Cursor'(Position
.Container
, N
.Prev
);
2279 end Previous_Sibling
;
2281 procedure Previous_Sibling
(Position
: in out Cursor
) is
2283 Position
:= Previous_Sibling
(Position
);
2284 end Previous_Sibling
;
2286 ----------------------
2287 -- Pseudo_Reference --
2288 ----------------------
2290 function Pseudo_Reference
2291 (Container
: aliased Tree
'Class) return Reference_Control_Type
2293 TC
: constant Tamper_Counts_Access
:= Container
.TC
'Unrestricted_Access;
2295 return R
: constant Reference_Control_Type
:= (Controlled
with TC
) do
2298 end Pseudo_Reference
;
2304 procedure Query_Element
2306 Process
: not null access procedure (Element
: Element_Type
))
2309 if Checks
and then Position
= No_Element
then
2310 raise Constraint_Error
with "Position cursor has no element";
2313 if Checks
and then Is_Root
(Position
) then
2314 raise Program_Error
with "Position cursor designates root";
2318 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
2319 Lock
: With_Lock
(T
.TC
'Unrestricted_Access);
2321 Process
(Element
=> T
.Elements
(Position
.Node
));
2330 (Stream
: not null access Root_Stream_Type
'Class;
2331 Container
: out Tree
)
2333 procedure Read_Children
(Subtree
: Count_Type
);
2335 function Read_Subtree
2336 (Parent
: Count_Type
) return Count_Type
;
2338 NN
: Tree_Node_Array
renames Container
.Nodes
;
2340 Total_Count
: Count_Type
'Base;
2341 -- Value read from the stream that says how many elements follow
2343 Read_Count
: Count_Type
'Base;
2344 -- Actual number of elements read from the stream
2350 procedure Read_Children
(Subtree
: Count_Type
) is
2351 Count
: Count_Type
'Base;
2352 -- number of child subtrees
2357 Count_Type
'Read (Stream
, Count
);
2359 if Checks
and then Count
< 0 then
2360 raise Program_Error
with "attempt to read from corrupt stream";
2367 CC
.First
:= Read_Subtree
(Parent
=> Subtree
);
2368 CC
.Last
:= CC
.First
;
2370 for J
in Count_Type
'(2) .. Count loop
2371 NN (CC.Last).Next := Read_Subtree (Parent => Subtree);
2372 NN (NN (CC.Last).Next).Prev := CC.Last;
2373 CC.Last := NN (CC.Last).Next;
2376 -- Now that the allocation and reads have completed successfully, it
2377 -- is safe to link the children to their parent.
2379 NN (Subtree).Children := CC;
2386 function Read_Subtree
2387 (Parent : Count_Type) return Count_Type
2389 Subtree : Count_Type;
2392 Allocate_Node (Container, Stream, Subtree);
2393 Container.Nodes (Subtree).Parent := Parent;
2395 Read_Count := Read_Count + 1;
2397 Read_Children (Subtree);
2402 -- Start of processing for Read
2405 Container.Clear; -- checks busy bit
2407 Count_Type'Read (Stream, Total_Count);
2409 if Checks and then Total_Count < 0 then
2410 raise Program_Error with "attempt to read from corrupt stream";
2413 if Total_Count = 0 then
2417 if Checks and then Total_Count > Container.Capacity then
2418 raise Capacity_Error -- ???
2419 with "node count in stream exceeds container capacity";
2422 Initialize_Root (Container);
2426 Read_Children (Root_Node (Container));
2428 if Checks and then Read_Count /= Total_Count then
2429 raise Program_Error with "attempt to read from corrupt stream";
2432 Container.Count := Total_Count;
2436 (Stream : not null access Root_Stream_Type'Class;
2437 Position : out Cursor)
2440 raise Program_Error with "attempt to read tree cursor from stream";
2444 (Stream : not null access Root_Stream_Type'Class;
2445 Item : out Reference_Type)
2448 raise Program_Error with "attempt to stream reference";
2452 (Stream : not null access Root_Stream_Type'Class;
2453 Item : out Constant_Reference_Type)
2456 raise Program_Error with "attempt to stream reference";
2464 (Container : aliased in out Tree;
2465 Position : Cursor) return Reference_Type
2468 if Checks and then Position.Container = null then
2469 raise Constraint_Error with
2470 "Position cursor has no element";
2473 if Checks and then Position.Container /= Container'Unrestricted_Access
2475 raise Program_Error with
2476 "Position cursor designates wrong container";
2479 if Checks and then Position.Node = Root_Node (Container) then
2480 raise Program_Error with "Position cursor designates root";
2483 -- Implement Vet for multiway tree???
2484 -- pragma Assert (Vet (Position),
2485 -- "Position cursor in Constant_Reference is bad");
2488 TC : constant Tamper_Counts_Access :=
2489 Container.TC'Unrestricted_Access;
2491 return R : constant Reference_Type :=
2492 (Element => Container.Elements (Position.Node)'Access,
2493 Control => (Controlled with TC))
2500 --------------------
2501 -- Remove_Subtree --
2502 --------------------
2504 procedure Remove_Subtree
2505 (Container : in out Tree;
2506 Subtree : Count_Type)
2508 NN : Tree_Node_Array renames Container.Nodes;
2509 N : Tree_Node_Type renames NN (Subtree);
2510 CC : Children_Type renames NN (N.Parent).Children;
2513 -- This is a utility operation to remove a subtree node from its
2514 -- parent's list of children.
2516 if CC.First = Subtree then
2517 pragma Assert (N.Prev <= 0);
2519 if CC.Last = Subtree then
2520 pragma Assert (N.Next <= 0);
2526 NN (CC.First).Prev := 0;
2529 elsif CC.Last = Subtree then
2530 pragma Assert (N.Next <= 0);
2532 NN (CC.Last).Next := 0;
2535 NN (N.Prev).Next := N.Next;
2536 NN (N.Next).Prev := N.Prev;
2540 ----------------------
2541 -- Replace_Element --
2542 ----------------------
2544 procedure Replace_Element
2545 (Container : in out Tree;
2547 New_Item : Element_Type)
2550 if Checks and then Position = No_Element then
2551 raise Constraint_Error with "Position cursor has no element";
2554 if Checks and then Position.Container /= Container'Unrestricted_Access
2556 raise Program_Error with "Position cursor not in container";
2559 if Checks and then Is_Root (Position) then
2560 raise Program_Error with "Position cursor designates root";
2563 TE_Check (Container.TC);
2565 Container.Elements (Position.Node) := New_Item;
2566 end Replace_Element;
2568 ------------------------------
2569 -- Reverse_Iterate_Children --
2570 ------------------------------
2572 procedure Reverse_Iterate_Children
2574 Process : not null access procedure (Position : Cursor))
2577 if Checks and then Parent = No_Element then
2578 raise Constraint_Error with "Parent cursor has no element";
2581 if Parent.Container.Count = 0 then
2582 pragma Assert (Is_Root (Parent));
2587 NN : Tree_Node_Array renames Parent.Container.Nodes;
2588 Busy : With_Busy (Parent.Container.TC'Unrestricted_Access);
2592 C := NN (Parent.Node).Children.Last;
2594 Process (Cursor'(Parent
.Container
, Node
=> C
));
2598 end Reverse_Iterate_Children
;
2604 function Root
(Container
: Tree
) return Cursor
is
2606 return (Container
'Unrestricted_Access, Root_Node
(Container
));
2613 function Root_Node
(Container
: Tree
) return Count_Type
is
2614 pragma Unreferenced
(Container
);
2620 ---------------------
2621 -- Splice_Children --
2622 ---------------------
2624 procedure Splice_Children
2625 (Target
: in out Tree
;
2626 Target_Parent
: Cursor
;
2628 Source
: in out Tree
;
2629 Source_Parent
: Cursor
)
2632 if Checks
and then Target_Parent
= No_Element
then
2633 raise Constraint_Error
with "Target_Parent cursor has no element";
2636 if Checks
and then Target_Parent
.Container
/= Target
'Unrestricted_Access
2639 with "Target_Parent cursor not in Target container";
2642 if Before
/= No_Element
then
2643 if Checks
and then Before
.Container
/= Target
'Unrestricted_Access then
2645 with "Before cursor not in Target container";
2649 Target
.Nodes
(Before
.Node
).Parent
/= Target_Parent
.Node
2651 raise Constraint_Error
2652 with "Before cursor not child of Target_Parent";
2656 if Checks
and then Source_Parent
= No_Element
then
2657 raise Constraint_Error
with "Source_Parent cursor has no element";
2660 if Checks
and then Source_Parent
.Container
/= Source
'Unrestricted_Access
2663 with "Source_Parent cursor not in Source container";
2666 if Source
.Count
= 0 then
2667 pragma Assert
(Is_Root
(Source_Parent
));
2671 if Target
'Address = Source
'Address then
2672 if Target_Parent
= Source_Parent
then
2676 TC_Check
(Target
.TC
);
2678 if Checks
and then Is_Reachable
(Container
=> Target
,
2679 From
=> Target_Parent
.Node
,
2680 To
=> Source_Parent
.Node
)
2682 raise Constraint_Error
2683 with "Source_Parent is ancestor of Target_Parent";
2687 (Container
=> Target
,
2688 Target_Parent
=> Target_Parent
.Node
,
2689 Before
=> Before
.Node
,
2690 Source_Parent
=> Source_Parent
.Node
);
2695 TC_Check
(Target
.TC
);
2696 TC_Check
(Source
.TC
);
2698 if Target
.Count
= 0 then
2699 Initialize_Root
(Target
);
2704 Target_Parent
=> Target_Parent
.Node
,
2705 Before
=> Before
.Node
,
2707 Source_Parent
=> Source_Parent
.Node
);
2708 end Splice_Children
;
2710 procedure Splice_Children
2711 (Container
: in out Tree
;
2712 Target_Parent
: Cursor
;
2714 Source_Parent
: Cursor
)
2717 if Checks
and then Target_Parent
= No_Element
then
2718 raise Constraint_Error
with "Target_Parent cursor has no element";
2722 Target_Parent
.Container
/= Container
'Unrestricted_Access
2725 with "Target_Parent cursor not in container";
2728 if Before
/= No_Element
then
2729 if Checks
and then Before
.Container
/= Container
'Unrestricted_Access
2732 with "Before cursor not in container";
2736 Container
.Nodes
(Before
.Node
).Parent
/= Target_Parent
.Node
2738 raise Constraint_Error
2739 with "Before cursor not child of Target_Parent";
2743 if Checks
and then Source_Parent
= No_Element
then
2744 raise Constraint_Error
with "Source_Parent cursor has no element";
2748 Source_Parent
.Container
/= Container
'Unrestricted_Access
2751 with "Source_Parent cursor not in container";
2754 if Target_Parent
= Source_Parent
then
2758 pragma Assert
(Container
.Count
> 0);
2760 TC_Check
(Container
.TC
);
2762 if Checks
and then Is_Reachable
(Container
=> Container
,
2763 From
=> Target_Parent
.Node
,
2764 To
=> Source_Parent
.Node
)
2766 raise Constraint_Error
2767 with "Source_Parent is ancestor of Target_Parent";
2771 (Container
=> Container
,
2772 Target_Parent
=> Target_Parent
.Node
,
2773 Before
=> Before
.Node
,
2774 Source_Parent
=> Source_Parent
.Node
);
2775 end Splice_Children
;
2777 procedure Splice_Children
2778 (Container
: in out Tree
;
2779 Target_Parent
: Count_Type
;
2780 Before
: Count_Type
'Base;
2781 Source_Parent
: Count_Type
)
2783 NN
: Tree_Node_Array
renames Container
.Nodes
;
2784 CC
: constant Children_Type
:= NN
(Source_Parent
).Children
;
2785 C
: Count_Type
'Base;
2788 -- This is a utility operation to remove the children from Source parent
2789 -- and insert them into Target parent.
2791 NN
(Source_Parent
).Children
:= Children_Type
'(others => 0);
2793 -- Fix up the Parent pointers of each child to designate its new Target
2798 NN (C).Parent := Target_Parent;
2803 (Container => Container,
2806 Parent => Target_Parent,
2808 end Splice_Children;
2810 procedure Splice_Children
2811 (Target : in out Tree;
2812 Target_Parent : Count_Type;
2813 Before : Count_Type'Base;
2814 Source : in out Tree;
2815 Source_Parent : Count_Type)
2817 S_NN : Tree_Node_Array renames Source.Nodes;
2818 S_CC : Children_Type renames S_NN (Source_Parent).Children;
2820 Target_Count, Source_Count : Count_Type;
2821 T, S : Count_Type'Base;
2824 -- This is a utility operation to copy the children from the Source
2825 -- parent and insert them as children of the Target parent, and then
2826 -- delete them from the Source. (This is not a true splice operation,
2827 -- but it is the best we can do in a bounded form.) The Before position
2828 -- specifies where among the Target parent's exising children the new
2829 -- children are inserted.
2831 -- Before we attempt the insertion, we must count the sources nodes in
2832 -- order to determine whether the target have enough storage
2833 -- available. Note that calculating this value is an O(n) operation.
2835 -- Here is an optimization opportunity: iterate of each children the
2836 -- source explicitly, and keep a running count of the total number of
2837 -- nodes. Compare the running total to the capacity of the target each
2838 -- pass through the loop. This is more efficient than summing the counts
2839 -- of child subtree (which is what Subtree_Node_Count does) and then
2840 -- comparing that total sum to the target's capacity. ???
2842 -- Here is another possibility. We currently treat the splice as an
2843 -- all-or-nothing proposition: either we can insert all of children of
2844 -- the source, or we raise exception with modifying the target. The
2845 -- price for not causing side-effect is an O(n) determination of the
2846 -- source count. If we are willing to tolerate side-effect, then we
2847 -- could loop over the children of the source, counting that subtree and
2848 -- then immediately inserting it in the target. The issue here is that
2849 -- the test for available storage could fail during some later pass,
2850 -- after children have already been inserted into target. ???
2852 Source_Count := Subtree_Node_Count (Source, Source_Parent) - 1;
2854 if Source_Count = 0 then
2858 if Checks and then Target.Count > Target.Capacity - Source_Count then
2859 raise Capacity_Error -- ???
2860 with "Source count exceeds available storage on Target";
2863 -- Copy_Subtree returns a count of the number of nodes it inserts, but
2864 -- it does this by incrementing the value passed in. Therefore we must
2865 -- initialize the count before calling Copy_Subtree.
2873 Source_Subtree => S,
2875 Target_Parent => Target_Parent,
2876 Target_Subtree => T,
2877 Count => Target_Count);
2880 (Container => Target,
2882 Parent => Target_Parent,
2888 pragma Assert (Target_Count = Source_Count);
2889 Target.Count := Target.Count + Target_Count;
2891 -- As with Copy_Subtree, operation Deallocate_Children returns a count
2892 -- of the number of nodes it deallocates, but it works by incrementing
2893 -- the value passed in. We must therefore initialize the count before
2898 Deallocate_Children (Source, Source_Parent, Source_Count);
2899 pragma Assert (Source_Count = Target_Count);
2901 Source.Count := Source.Count - Source_Count;
2902 end Splice_Children;
2904 --------------------
2905 -- Splice_Subtree --
2906 --------------------
2908 procedure Splice_Subtree
2909 (Target : in out Tree;
2912 Source : in out Tree;
2913 Position : in out Cursor)
2916 if Checks and then Parent = No_Element then
2917 raise Constraint_Error with "Parent cursor has no element";
2920 if Checks and then Parent.Container /= Target'Unrestricted_Access then
2921 raise Program_Error with "Parent cursor not in Target container";
2924 if Before /= No_Element then
2925 if Checks and then Before.Container /= Target'Unrestricted_Access then
2926 raise Program_Error with "Before cursor not in Target container";
2929 if Checks and then Target.Nodes (Before.Node).Parent /= Parent.Node
2931 raise Constraint_Error with "Before cursor not child of Parent";
2935 if Checks and then Position = No_Element then
2936 raise Constraint_Error with "Position cursor has no element";
2939 if Checks and then Position.Container /= Source'Unrestricted_Access then
2940 raise Program_Error with "Position cursor not in Source container";
2943 if Checks and then Is_Root (Position) then
2944 raise Program_Error with "Position cursor designates root";
2947 if Target'Address = Source'Address then
2948 if Target.Nodes (Position.Node).Parent = Parent.Node then
2949 if Before = No_Element then
2950 if Target.Nodes (Position.Node).Next <= 0 then -- last child
2954 elsif Position.Node = Before.Node then
2957 elsif Target.Nodes (Position.Node).Next = Before.Node then
2962 TC_Check (Target.TC);
2964 if Checks and then Is_Reachable (Container => Target,
2965 From => Parent.Node,
2966 To => Position.Node)
2968 raise Constraint_Error with "Position is ancestor of Parent";
2971 Remove_Subtree (Target, Position.Node);
2973 Target.Nodes (Position.Node).Parent := Parent.Node;
2974 Insert_Subtree_Node (Target, Position.Node, Parent.Node, Before.Node);
2979 TC_Check (Target.TC);
2980 TC_Check (Source.TC);
2982 if Target.Count = 0 then
2983 Initialize_Root (Target);
2988 Parent => Parent.Node,
2989 Before => Before.Node,
2991 Position => Position.Node); -- modified during call
2993 Position.Container := Target'Unrestricted_Access;
2996 procedure Splice_Subtree
2997 (Container : in out Tree;
3003 if Checks and then Parent = No_Element then
3004 raise Constraint_Error with "Parent cursor has no element";
3007 if Checks and then Parent.Container /= Container'Unrestricted_Access then
3008 raise Program_Error with "Parent cursor not in container";
3011 if Before /= No_Element then
3012 if Checks and then Before.Container /= Container'Unrestricted_Access
3014 raise Program_Error with "Before cursor not in container";
3017 if Checks and then Container.Nodes (Before.Node).Parent /= Parent.Node
3019 raise Constraint_Error with "Before cursor not child of Parent";
3023 if Checks and then Position = No_Element then
3024 raise Constraint_Error with "Position cursor has no element";
3027 if Checks and then Position.Container /= Container'Unrestricted_Access
3029 raise Program_Error with "Position cursor not in container";
3032 if Checks and then Is_Root (Position) then
3034 -- Should this be PE instead? Need ARG confirmation. ???
3036 raise Constraint_Error with "Position cursor designates root";
3039 if Container.Nodes (Position.Node).Parent = Parent.Node then
3040 if Before = No_Element then
3041 if Container.Nodes (Position.Node).Next <= 0 then -- last child
3045 elsif Position.Node = Before.Node then
3048 elsif Container.Nodes (Position.Node).Next = Before.Node then
3053 TC_Check (Container.TC);
3055 if Checks and then Is_Reachable (Container => Container,
3056 From => Parent.Node,
3057 To => Position.Node)
3059 raise Constraint_Error with "Position is ancestor of Parent";
3062 Remove_Subtree (Container, Position.Node);
3063 Container.Nodes (Position.Node).Parent := Parent.Node;
3064 Insert_Subtree_Node (Container, Position.Node, Parent.Node, Before.Node);
3067 procedure Splice_Subtree
3068 (Target : in out Tree;
3069 Parent : Count_Type;
3070 Before : Count_Type'Base;
3071 Source : in out Tree;
3072 Position : in out Count_Type) -- Source on input, Target on output
3074 Source_Count : Count_Type := Subtree_Node_Count (Source, Position);
3075 pragma Assert (Source_Count >= 1);
3077 Target_Subtree : Count_Type;
3078 Target_Count : Count_Type;
3081 -- This is a utility operation to do the heavy lifting associated with
3082 -- splicing a subtree from one tree to another. Note that "splicing"
3083 -- is a bit of a misnomer here in the case of a bounded tree, because
3084 -- the elements must be copied from the source to the target.
3086 if Checks and then Target.Count > Target.Capacity - Source_Count then
3087 raise Capacity_Error -- ???
3088 with "Source count exceeds available storage on Target";
3091 -- Copy_Subtree returns a count of the number of nodes it inserts, but
3092 -- it does this by incrementing the value passed in. Therefore we must
3093 -- initialize the count before calling Copy_Subtree.
3099 Source_Subtree => Position,
3101 Target_Parent => Parent,
3102 Target_Subtree => Target_Subtree,
3103 Count => Target_Count);
3105 pragma Assert (Target_Count = Source_Count);
3107 -- Now link the newly-allocated subtree into the target.
3110 (Container => Target,
3111 Subtree => Target_Subtree,
3115 Target.Count := Target.Count + Target_Count;
3117 -- The manipulation of the Target container is complete. Now we remove
3118 -- the subtree from the Source container.
3120 Remove_Subtree (Source, Position); -- unlink the subtree
3122 -- As with Copy_Subtree, operation Deallocate_Subtree returns a count of
3123 -- the number of nodes it deallocates, but it works by incrementing the
3124 -- value passed in. We must therefore initialize the count before
3129 Deallocate_Subtree (Source, Position, Source_Count);
3130 pragma Assert (Source_Count = Target_Count);
3132 Source.Count := Source.Count - Source_Count;
3134 Position := Target_Subtree;
3137 ------------------------
3138 -- Subtree_Node_Count --
3139 ------------------------
3141 function Subtree_Node_Count (Position : Cursor) return Count_Type is
3143 if Position = No_Element then
3147 if Position.Container.Count = 0 then
3148 pragma Assert (Is_Root (Position));
3152 return Subtree_Node_Count (Position.Container.all, Position.Node);
3153 end Subtree_Node_Count;
3155 function Subtree_Node_Count
3157 Subtree : Count_Type) return Count_Type
3159 Result : Count_Type;
3160 Node : Count_Type'Base;
3164 Node := Container.Nodes (Subtree).Children.First;
3166 Result := Result + Subtree_Node_Count (Container, Node);
3167 Node := Container.Nodes (Node).Next;
3170 end Subtree_Node_Count;
3177 (Container : in out Tree;
3181 if Checks and then I = No_Element then
3182 raise Constraint_Error with "I cursor has no element";
3185 if Checks and then I.Container /= Container'Unrestricted_Access then
3186 raise Program_Error with "I cursor not in container";
3189 if Checks and then Is_Root (I) then
3190 raise Program_Error with "I cursor designates root";
3193 if I = J then -- make this test sooner???
3197 if Checks and then J = No_Element then
3198 raise Constraint_Error with "J cursor has no element";
3201 if Checks and then J.Container /= Container'Unrestricted_Access then
3202 raise Program_Error with "J cursor not in container";
3205 if Checks and then Is_Root (J) then
3206 raise Program_Error with "J cursor designates root";
3209 TE_Check (Container.TC);
3212 EE : Element_Array renames Container.Elements;
3213 EI : constant Element_Type := EE (I.Node);
3216 EE (I.Node) := EE (J.Node);
3221 --------------------
3222 -- Update_Element --
3223 --------------------
3225 procedure Update_Element
3226 (Container : in out Tree;
3228 Process : not null access procedure (Element : in out Element_Type))
3231 if Checks and then Position = No_Element then
3232 raise Constraint_Error with "Position cursor has no element";
3235 if Checks and then Position.Container /= Container'Unrestricted_Access
3237 raise Program_Error with "Position cursor not in container";
3240 if Checks and then Is_Root (Position) then
3241 raise Program_Error with "Position cursor designates root";
3245 T : Tree renames Position.Container.all'Unrestricted_Access.all;
3246 Lock : With_Lock (T.TC'Unrestricted_Access);
3248 Process (Element => T.Elements (Position.Node));
3257 (Stream : not null access Root_Stream_Type'Class;
3260 procedure Write_Children (Subtree : Count_Type);
3261 procedure Write_Subtree (Subtree : Count_Type);
3263 --------------------
3264 -- Write_Children --
3265 --------------------
3267 procedure Write_Children (Subtree : Count_Type) is
3268 CC : Children_Type renames Container.Nodes (Subtree).Children;
3269 C : Count_Type'Base;
3272 Count_Type'Write (Stream, Child_Count (Container, Subtree));
3277 C := Container.Nodes (C).Next;
3285 procedure Write_Subtree (Subtree : Count_Type) is
3287 Element_Type'Write (Stream, Container.Elements (Subtree));
3288 Write_Children (Subtree);
3291 -- Start of processing for Write
3294 Count_Type'Write (Stream, Container.Count);
3296 if Container.Count = 0 then
3300 Write_Children (Root_Node (Container));
3304 (Stream : not null access Root_Stream_Type'Class;
3308 raise Program_Error with "attempt to write tree cursor to stream";
3312 (Stream : not null access Root_Stream_Type'Class;
3313 Item : Reference_Type)
3316 raise Program_Error with "attempt to stream reference";
3320 (Stream : not null access Root_Stream_Type'Class;
3321 Item : Constant_Reference_Type)
3324 raise Program_Error with "attempt to stream reference";
3327 end Ada.Containers.Bounded_Multiway_Trees;