1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.BOUNDED_MULTIWAY_TREES --
9 -- Copyright (C) 2011-2013, 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
; use Ada
.Finalization
;
32 with System
; use type System
.Address
;
34 package body Ada
.Containers
.Bounded_Multiway_Trees
is
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 New_Node
: out Count_Type
);
101 procedure Allocate_Node
102 (Container
: in out Tree
;
103 Stream
: not null access Root_Stream_Type
'Class;
104 New_Node
: out Count_Type
);
106 procedure Deallocate_Node
107 (Container
: in out Tree
;
110 procedure Deallocate_Children
111 (Container
: in out Tree
;
112 Subtree
: Count_Type
;
113 Count
: in out Count_Type
);
115 procedure Deallocate_Subtree
116 (Container
: in out Tree
;
117 Subtree
: Count_Type
;
118 Count
: in out Count_Type
);
120 function Equal_Children
122 Left_Subtree
: Count_Type
;
124 Right_Subtree
: Count_Type
) return Boolean;
126 function Equal_Subtree
128 Left_Subtree
: Count_Type
;
130 Right_Subtree
: Count_Type
) return Boolean;
132 procedure Iterate_Children
134 Subtree
: Count_Type
;
135 Process
: not null access procedure (Position
: Cursor
));
137 procedure Iterate_Subtree
139 Subtree
: Count_Type
;
140 Process
: not null access procedure (Position
: Cursor
));
142 procedure Copy_Children
144 Source_Parent
: Count_Type
;
145 Target
: in out Tree
;
146 Target_Parent
: Count_Type
;
147 Count
: in out Count_Type
);
149 procedure Copy_Subtree
151 Source_Subtree
: Count_Type
;
152 Target
: in out Tree
;
153 Target_Parent
: Count_Type
;
154 Target_Subtree
: out Count_Type
;
155 Count
: in out Count_Type
);
157 function Find_In_Children
159 Subtree
: Count_Type
;
160 Item
: Element_Type
) return Count_Type
;
162 function Find_In_Subtree
164 Subtree
: Count_Type
;
165 Item
: Element_Type
) return Count_Type
;
169 Parent
: Count_Type
) return Count_Type
;
171 function Subtree_Node_Count
173 Subtree
: Count_Type
) return Count_Type
;
175 function Is_Reachable
177 From
, To
: Count_Type
) return Boolean;
179 function Root_Node
(Container
: Tree
) return Count_Type
;
181 procedure Remove_Subtree
182 (Container
: in out Tree
;
183 Subtree
: Count_Type
);
185 procedure Insert_Subtree_Node
186 (Container
: in out Tree
;
187 Subtree
: Count_Type
'Base;
189 Before
: Count_Type
'Base);
191 procedure Insert_Subtree_List
192 (Container
: in out Tree
;
193 First
: Count_Type
'Base;
194 Last
: Count_Type
'Base;
196 Before
: Count_Type
'Base);
198 procedure Splice_Children
199 (Container
: in out Tree
;
200 Target_Parent
: Count_Type
;
201 Before
: Count_Type
'Base;
202 Source_Parent
: Count_Type
);
204 procedure Splice_Children
205 (Target
: in out Tree
;
206 Target_Parent
: Count_Type
;
207 Before
: Count_Type
'Base;
208 Source
: in out Tree
;
209 Source_Parent
: Count_Type
);
211 procedure Splice_Subtree
212 (Target
: in out Tree
;
214 Before
: Count_Type
'Base;
215 Source
: in out Tree
;
216 Position
: in out Count_Type
); -- source on input, target on output
222 function "=" (Left
, Right
: Tree
) return Boolean is
224 if Left
'Address = Right
'Address then
228 if Left
.Count
/= Right
.Count
then
232 if Left
.Count
= 0 then
236 return Equal_Children
238 Left_Subtree
=> Root_Node
(Left
),
240 Right_Subtree
=> Root_Node
(Right
));
247 procedure Allocate_Node
248 (Container
: in out Tree
;
249 Initialize_Element
: not null access procedure (Index
: Count_Type
);
250 New_Node
: out Count_Type
)
253 if Container
.Free
>= 0 then
254 New_Node
:= Container
.Free
;
255 pragma Assert
(New_Node
in Container
.Elements
'Range);
257 -- We always perform the assignment first, before we change container
258 -- state, in order to defend against exceptions duration assignment.
260 Initialize_Element
(New_Node
);
262 Container
.Free
:= Container
.Nodes
(New_Node
).Next
;
265 -- A negative free store value means that the links of the nodes in
266 -- the free store have not been initialized. In this case, the nodes
267 -- are physically contiguous in the array, starting at the index that
268 -- is the absolute value of the Container.Free, and continuing until
269 -- the end of the array (Nodes'Last).
271 New_Node
:= abs Container
.Free
;
272 pragma Assert
(New_Node
in Container
.Elements
'Range);
274 -- As above, we perform this assignment first, before modifying any
277 Initialize_Element
(New_Node
);
279 Container
.Free
:= Container
.Free
- 1;
281 if abs Container
.Free
> Container
.Capacity
then
286 Initialize_Node
(Container
, New_Node
);
289 procedure Allocate_Node
290 (Container
: in out Tree
;
291 New_Item
: Element_Type
;
292 New_Node
: out Count_Type
)
294 procedure Initialize_Element
(Index
: Count_Type
);
296 procedure Initialize_Element
(Index
: Count_Type
) is
298 Container
.Elements
(Index
) := New_Item
;
299 end Initialize_Element
;
302 Allocate_Node
(Container
, Initialize_Element
'Access, New_Node
);
305 procedure Allocate_Node
306 (Container
: in out Tree
;
307 Stream
: not null access Root_Stream_Type
'Class;
308 New_Node
: out Count_Type
)
310 procedure Initialize_Element
(Index
: Count_Type
);
312 procedure Initialize_Element
(Index
: Count_Type
) is
314 Element_Type
'Read (Stream
, Container
.Elements
(Index
));
315 end Initialize_Element
;
318 Allocate_Node
(Container
, Initialize_Element
'Access, New_Node
);
321 procedure Allocate_Node
322 (Container
: in out Tree
;
323 New_Node
: out Count_Type
)
325 procedure Initialize_Element
(Index
: Count_Type
) is null;
327 Allocate_Node
(Container
, Initialize_Element
'Access, New_Node
);
334 function Ancestor_Find
336 Item
: Element_Type
) return Cursor
341 if Position
= No_Element
then
342 raise Constraint_Error
with "Position cursor has no element";
345 -- Commented-out pending ruling by ARG. ???
347 -- if Position.Container /= Container'Unrestricted_Access then
348 -- raise Program_Error with "Position cursor not in container";
351 -- AI-0136 says to raise PE if Position equals the root node. This does
352 -- not seem correct, as this value is just the limiting condition of the
353 -- search. For now we omit this check, pending a ruling from the ARG.
356 -- if Is_Root (Position) then
357 -- raise Program_Error with "Position cursor designates root";
360 R
:= Root_Node
(Position
.Container
.all);
363 if Position
.Container
.Elements
(N
) = Item
then
364 return Cursor
'(Position.Container, N);
367 N := Position.Container.Nodes (N).Parent;
377 procedure Append_Child
378 (Container : in out Tree;
380 New_Item : Element_Type;
381 Count : Count_Type := 1)
383 Nodes : Tree_Node_Array renames Container.Nodes;
384 First, Last : Count_Type;
387 if Parent = No_Element then
388 raise Constraint_Error with "Parent cursor has no element";
391 if Parent.Container /= Container'Unrestricted_Access then
392 raise Program_Error with "Parent cursor not in container";
399 if Container.Count > Container.Capacity - Count then
401 with "requested count exceeds available storage";
404 if Container.Busy > 0 then
406 with "attempt to tamper with cursors (tree is busy)";
409 if Container.Count = 0 then
410 Initialize_Root (Container);
413 Allocate_Node (Container, New_Item, First);
414 Nodes (First).Parent := Parent.Node;
417 for J in Count_Type'(2) .. Count
loop
418 Allocate_Node
(Container
, New_Item
, Nodes
(Last
).Next
);
419 Nodes
(Nodes
(Last
).Next
).Parent
:= Parent
.Node
;
420 Nodes
(Nodes
(Last
).Next
).Prev
:= Last
;
422 Last
:= Nodes
(Last
).Next
;
426 (Container
=> Container
,
429 Parent
=> Parent
.Node
,
430 Before
=> No_Node
); -- means "insert at end of list"
432 Container
.Count
:= Container
.Count
+ Count
;
439 procedure Assign
(Target
: in out Tree
; Source
: Tree
) is
440 Target_Count
: Count_Type
;
443 if Target
'Address = Source
'Address then
447 if Target
.Capacity
< Source
.Count
then
448 raise Capacity_Error
-- ???
449 with "Target capacity is less than Source count";
452 Target
.Clear
; -- Checks busy bit
454 if Source
.Count
= 0 then
458 Initialize_Root
(Target
);
460 -- Copy_Children returns the number of nodes that it allocates, but it
461 -- does this by incrementing the count value passed in, so we must
462 -- initialize the count before calling Copy_Children.
468 Source_Parent
=> Root_Node
(Source
),
470 Target_Parent
=> Root_Node
(Target
),
471 Count
=> Target_Count
);
473 pragma Assert
(Target_Count
= Source
.Count
);
474 Target
.Count
:= Source
.Count
;
481 function Child_Count
(Parent
: Cursor
) return Count_Type
is
483 if Parent
= No_Element
then
486 elsif Parent
.Container
.Count
= 0 then
487 pragma Assert
(Is_Root
(Parent
));
491 return Child_Count
(Parent
.Container
.all, Parent
.Node
);
497 Parent
: Count_Type
) return Count_Type
499 NN
: Tree_Node_Array
renames Container
.Nodes
;
500 CC
: Children_Type
renames NN
(Parent
).Children
;
503 Node
: Count_Type
'Base;
509 Result
:= Result
+ 1;
510 Node
:= NN
(Node
).Next
;
520 function Child_Depth
(Parent
, Child
: Cursor
) return Count_Type
is
525 if Parent
= No_Element
then
526 raise Constraint_Error
with "Parent cursor has no element";
529 if Child
= No_Element
then
530 raise Constraint_Error
with "Child cursor has no element";
533 if Parent
.Container
/= Child
.Container
then
534 raise Program_Error
with "Parent and Child in different containers";
537 if Parent
.Container
.Count
= 0 then
538 pragma Assert
(Is_Root
(Parent
));
539 pragma Assert
(Child
= Parent
);
545 while N
/= Parent
.Node
loop
546 Result
:= Result
+ 1;
547 N
:= Parent
.Container
.Nodes
(N
).Parent
;
550 raise Program_Error
with "Parent is not ancestor of Child";
561 procedure Clear
(Container
: in out Tree
) is
562 Container_Count
: constant Count_Type
:= Container
.Count
;
566 if Container
.Busy
> 0 then
568 with "attempt to tamper with cursors (tree is busy)";
571 if Container_Count
= 0 then
575 Container
.Count
:= 0;
577 -- Deallocate_Children returns the number of nodes that it deallocates,
578 -- but it does this by incrementing the count value that is passed in,
579 -- so we must first initialize the count return value before calling it.
584 (Container
=> Container
,
585 Subtree
=> Root_Node
(Container
),
588 pragma Assert
(Count
= Container_Count
);
591 ------------------------
592 -- Constant_Reference --
593 ------------------------
595 function Constant_Reference
596 (Container
: aliased Tree
;
597 Position
: Cursor
) return Constant_Reference_Type
600 if Position
.Container
= null then
601 raise Constraint_Error
with
602 "Position cursor has no element";
605 if Position
.Container
/= Container
'Unrestricted_Access then
606 raise Program_Error
with
607 "Position cursor designates wrong container";
610 if Position
.Node
= Root_Node
(Container
) then
611 raise Program_Error
with "Position cursor designates root";
614 -- Implement Vet for multiway tree???
615 -- pragma Assert (Vet (Position),
616 -- "Position cursor in Constant_Reference is bad");
618 return (Element
=> Container
.Elements
(Position
.Node
)'Access);
619 end Constant_Reference
;
627 Item
: Element_Type
) return Boolean
630 return Find
(Container
, Item
) /= No_Element
;
639 Capacity
: Count_Type
:= 0) return Tree
646 elsif Capacity
>= Source
.Count
then
649 raise Capacity_Error
with "Capacity value too small";
652 return Target
: Tree
(Capacity
=> C
) do
653 Initialize_Root
(Target
);
655 if Source
.Count
= 0 then
661 Source_Parent
=> Root_Node
(Source
),
663 Target_Parent
=> Root_Node
(Target
),
664 Count
=> Target
.Count
);
666 pragma Assert
(Target
.Count
= Source
.Count
);
674 procedure Copy_Children
676 Source_Parent
: Count_Type
;
677 Target
: in out Tree
;
678 Target_Parent
: Count_Type
;
679 Count
: in out Count_Type
)
681 S_Nodes
: Tree_Node_Array
renames Source
.Nodes
;
682 S_Node
: Tree_Node_Type
renames S_Nodes
(Source_Parent
);
684 T_Nodes
: Tree_Node_Array
renames Target
.Nodes
;
685 T_Node
: Tree_Node_Type
renames T_Nodes
(Target_Parent
);
687 pragma Assert
(T_Node
.Children
.First
<= 0);
688 pragma Assert
(T_Node
.Children
.Last
<= 0);
690 T_CC
: Children_Type
;
694 -- We special-case the first allocation, in order to establish the
695 -- representation invariants for type Children_Type.
697 C
:= S_Node
.Children
.First
;
699 if C
<= 0 then -- source parent has no children
707 Target_Parent
=> Target_Parent
,
708 Target_Subtree
=> T_CC
.First
,
711 T_CC
.Last
:= T_CC
.First
;
713 -- The representation invariants for the Children_Type list have been
714 -- established, so we can now copy the remaining children of Source.
716 C
:= S_Nodes
(C
).Next
;
722 Target_Parent
=> Target_Parent
,
723 Target_Subtree
=> T_Nodes
(T_CC
.Last
).Next
,
726 T_Nodes
(T_Nodes
(T_CC
.Last
).Next
).Prev
:= T_CC
.Last
;
727 T_CC
.Last
:= T_Nodes
(T_CC
.Last
).Next
;
729 C
:= S_Nodes
(C
).Next
;
732 -- We add the newly-allocated children to their parent list only after
733 -- the allocation has succeeded, in order to preserve invariants of the
736 T_Node
.Children
:= T_CC
;
743 procedure Copy_Subtree
744 (Target
: in out Tree
;
749 Target_Subtree
: Count_Type
;
750 Target_Count
: Count_Type
;
753 if Parent
= No_Element
then
754 raise Constraint_Error
with "Parent cursor has no element";
757 if Parent
.Container
/= Target
'Unrestricted_Access then
758 raise Program_Error
with "Parent cursor not in container";
761 if Before
/= No_Element
then
762 if Before
.Container
/= Target
'Unrestricted_Access then
763 raise Program_Error
with "Before cursor not in container";
766 if Before
.Container
.Nodes
(Before
.Node
).Parent
/= Parent
.Node
then
767 raise Constraint_Error
with "Before cursor not child of Parent";
771 if Source
= No_Element
then
775 if Is_Root
(Source
) then
776 raise Constraint_Error
with "Source cursor designates root";
779 if Target
.Count
= 0 then
780 Initialize_Root
(Target
);
783 -- Copy_Subtree returns a count of the number of nodes that it
784 -- allocates, but it works by incrementing the value that is passed
785 -- in. We must therefore initialize the count value before calling
791 (Source
=> Source
.Container
.all,
792 Source_Subtree
=> Source
.Node
,
794 Target_Parent
=> Parent
.Node
,
795 Target_Subtree
=> Target_Subtree
,
796 Count
=> Target_Count
);
799 (Container
=> Target
,
800 Subtree
=> Target_Subtree
,
801 Parent
=> Parent
.Node
,
802 Before
=> Before
.Node
);
804 Target
.Count
:= Target
.Count
+ Target_Count
;
807 procedure Copy_Subtree
809 Source_Subtree
: Count_Type
;
810 Target
: in out Tree
;
811 Target_Parent
: Count_Type
;
812 Target_Subtree
: out Count_Type
;
813 Count
: in out Count_Type
)
815 T_Nodes
: Tree_Node_Array
renames Target
.Nodes
;
818 -- First we allocate the root of the target subtree.
821 (Container
=> Target
,
822 New_Item
=> Source
.Elements
(Source_Subtree
),
823 New_Node
=> Target_Subtree
);
825 T_Nodes
(Target_Subtree
).Parent
:= Target_Parent
;
828 -- We now have a new subtree (for the Target tree), containing only a
829 -- copy of the corresponding element in the Source subtree. Next we copy
830 -- the children of the Source subtree as children of the new Target
835 Source_Parent
=> Source_Subtree
,
837 Target_Parent
=> Target_Subtree
,
841 -------------------------
842 -- Deallocate_Children --
843 -------------------------
845 procedure Deallocate_Children
846 (Container
: in out Tree
;
847 Subtree
: Count_Type
;
848 Count
: in out Count_Type
)
850 Nodes
: Tree_Node_Array
renames Container
.Nodes
;
851 Node
: Tree_Node_Type
renames Nodes
(Subtree
); -- parent
852 CC
: Children_Type
renames Node
.Children
;
856 while CC
.First
> 0 loop
858 CC
.First
:= Nodes
(C
).Next
;
860 Deallocate_Subtree
(Container
, C
, Count
);
864 end Deallocate_Children
;
866 ---------------------
867 -- Deallocate_Node --
868 ---------------------
870 procedure Deallocate_Node
871 (Container
: in out Tree
;
874 NN
: Tree_Node_Array
renames Container
.Nodes
;
875 pragma Assert
(X
> 0);
876 pragma Assert
(X
<= NN
'Last);
878 N
: Tree_Node_Type
renames NN
(X
);
879 pragma Assert
(N
.Parent
/= X
); -- node is active
882 -- The tree container actually contains two lists: one for the "active"
883 -- nodes that contain elements that have been inserted onto the tree,
884 -- and another for the "inactive" nodes of the free store, from which
885 -- nodes are allocated when a new child is inserted in the tree.
887 -- We desire that merely declaring a tree object should have only
888 -- minimal cost; specially, we want to avoid having to initialize the
889 -- free store (to fill in the links), especially if the capacity of the
890 -- tree object is large.
892 -- The head of the free list is indicated by Container.Free. If its
893 -- value is non-negative, then the free store has been initialized in
894 -- the "normal" way: Container.Free points to the head of the list of
895 -- free (inactive) nodes, and the value 0 means the free list is
896 -- empty. Each node on the free list has been initialized to point to
897 -- the next free node (via its Next component), and the value 0 means
898 -- that this is the last node of the free list.
900 -- If Container.Free is negative, then the links on the free store have
901 -- not been initialized. In this case the link values are implied: the
902 -- free store comprises the components of the node array started with
903 -- the absolute value of Container.Free, and continuing until the end of
904 -- the array (Nodes'Last).
906 -- We prefer to lazy-init the free store (in fact, we would prefer to
907 -- not initialize it at all, because such initialization is an O(n)
908 -- operation). The time when we need to actually initialize the nodes in
909 -- the free store is when the node that becomes inactive is not at the
910 -- end of the active list. The free store would then be discontigous and
911 -- so its nodes would need to be linked in the traditional way.
913 -- It might be possible to perform an optimization here. Suppose that
914 -- the free store can be represented as having two parts: one comprising
915 -- the non-contiguous inactive nodes linked together in the normal way,
916 -- and the other comprising the contiguous inactive nodes (that are not
917 -- linked together, at the end of the nodes array). This would allow us
918 -- to never have to initialize the free store, except in a lazy way as
919 -- nodes become inactive. ???
921 -- When an element is deleted from the list container, its node becomes
922 -- inactive, and so we set its Parent and Prev components to an
923 -- impossible value (the index of the node itself), to indicate that it
924 -- is now inactive. This provides a useful way to detect a dangling
927 N
.Parent
:= X
; -- Node is deallocated (not on active list)
930 if Container
.Free
>= 0 then
931 -- The free store has previously been initialized. All we need to do
932 -- here is link the newly-free'd node onto the free list.
934 N
.Next
:= Container
.Free
;
937 elsif X
+ 1 = abs Container
.Free
then
938 -- The free store has not been initialized, and the node becoming
939 -- inactive immediately precedes the start of the free store. All
940 -- we need to do is move the start of the free store back by one.
942 N
.Next
:= X
; -- Not strictly necessary, but marginally safer
943 Container
.Free
:= Container
.Free
+ 1;
946 -- The free store has not been initialized, and the node becoming
947 -- inactive does not immediately precede the free store. Here we
948 -- first initialize the free store (meaning the links are given
949 -- values in the traditional way), and then link the newly-free'd
950 -- node onto the head of the free store.
952 -- See the comments above for an optimization opportunity. If the
953 -- next link for a node on the free store is negative, then this
954 -- means the remaining nodes on the free store are physically
955 -- contiguous, starting at the absolute value of that index value.
958 Container
.Free
:= abs Container
.Free
;
960 if Container
.Free
> Container
.Capacity
then
964 for J
in Container
.Free
.. Container
.Capacity
- 1 loop
965 NN
(J
).Next
:= J
+ 1;
968 NN
(Container
.Capacity
).Next
:= 0;
971 NN
(X
).Next
:= Container
.Free
;
976 ------------------------
977 -- Deallocate_Subtree --
978 ------------------------
980 procedure Deallocate_Subtree
981 (Container
: in out Tree
;
982 Subtree
: Count_Type
;
983 Count
: in out Count_Type
)
986 Deallocate_Children
(Container
, Subtree
, Count
);
987 Deallocate_Node
(Container
, Subtree
);
989 end Deallocate_Subtree
;
991 ---------------------
992 -- Delete_Children --
993 ---------------------
995 procedure Delete_Children
996 (Container
: in out Tree
;
1002 if Parent
= No_Element
then
1003 raise Constraint_Error
with "Parent cursor has no element";
1006 if Parent
.Container
/= Container
'Unrestricted_Access then
1007 raise Program_Error
with "Parent cursor not in container";
1010 if Container
.Busy
> 0 then
1012 with "attempt to tamper with cursors (tree is busy)";
1015 if Container
.Count
= 0 then
1016 pragma Assert
(Is_Root
(Parent
));
1020 -- Deallocate_Children returns a count of the number of nodes that it
1021 -- deallocates, but it works by incrementing the value that is passed
1022 -- in. We must therefore initialize the count value before calling
1023 -- Deallocate_Children.
1027 Deallocate_Children
(Container
, Parent
.Node
, Count
);
1028 pragma Assert
(Count
<= Container
.Count
);
1030 Container
.Count
:= Container
.Count
- Count
;
1031 end Delete_Children
;
1037 procedure Delete_Leaf
1038 (Container
: in out Tree
;
1039 Position
: in out Cursor
)
1044 if Position
= No_Element
then
1045 raise Constraint_Error
with "Position cursor has no element";
1048 if Position
.Container
/= Container
'Unrestricted_Access then
1049 raise Program_Error
with "Position cursor not in container";
1052 if Is_Root
(Position
) then
1053 raise Program_Error
with "Position cursor designates root";
1056 if not Is_Leaf
(Position
) then
1057 raise Constraint_Error
with "Position cursor does not designate leaf";
1060 if Container
.Busy
> 0 then
1062 with "attempt to tamper with cursors (tree is busy)";
1066 Position
:= No_Element
;
1068 Remove_Subtree
(Container
, X
);
1069 Container
.Count
:= Container
.Count
- 1;
1071 Deallocate_Node
(Container
, X
);
1074 --------------------
1075 -- Delete_Subtree --
1076 --------------------
1078 procedure Delete_Subtree
1079 (Container
: in out Tree
;
1080 Position
: in out Cursor
)
1086 if Position
= No_Element
then
1087 raise Constraint_Error
with "Position cursor has no element";
1090 if Position
.Container
/= Container
'Unrestricted_Access then
1091 raise Program_Error
with "Position cursor not in container";
1094 if Is_Root
(Position
) then
1095 raise Program_Error
with "Position cursor designates root";
1098 if Container
.Busy
> 0 then
1100 with "attempt to tamper with cursors (tree is busy)";
1104 Position
:= No_Element
;
1106 Remove_Subtree
(Container
, X
);
1108 -- Deallocate_Subtree returns a count of the number of nodes that it
1109 -- deallocates, but it works by incrementing the value that is passed
1110 -- in. We must therefore initialize the count value before calling
1111 -- Deallocate_Subtree.
1115 Deallocate_Subtree
(Container
, X
, Count
);
1116 pragma Assert
(Count
<= Container
.Count
);
1118 Container
.Count
:= Container
.Count
- Count
;
1125 function Depth
(Position
: Cursor
) return Count_Type
is
1126 Result
: Count_Type
;
1127 N
: Count_Type
'Base;
1130 if Position
= No_Element
then
1134 if Is_Root
(Position
) then
1141 N
:= Position
.Container
.Nodes
(N
).Parent
;
1142 Result
:= Result
+ 1;
1152 function Element
(Position
: Cursor
) return Element_Type
is
1154 if Position
.Container
= null then
1155 raise Constraint_Error
with "Position cursor has no element";
1158 if Position
.Node
= Root_Node
(Position
.Container
.all) then
1159 raise Program_Error
with "Position cursor designates root";
1162 return Position
.Container
.Elements
(Position
.Node
);
1165 --------------------
1166 -- Equal_Children --
1167 --------------------
1169 function Equal_Children
1171 Left_Subtree
: Count_Type
;
1173 Right_Subtree
: Count_Type
) return Boolean
1175 L_NN
: Tree_Node_Array
renames Left_Tree
.Nodes
;
1176 R_NN
: Tree_Node_Array
renames Right_Tree
.Nodes
;
1178 Left_Children
: Children_Type
renames L_NN
(Left_Subtree
).Children
;
1179 Right_Children
: Children_Type
renames R_NN
(Right_Subtree
).Children
;
1181 L
, R
: Count_Type
'Base;
1184 if Child_Count
(Left_Tree
, Left_Subtree
)
1185 /= Child_Count
(Right_Tree
, Right_Subtree
)
1190 L
:= Left_Children
.First
;
1191 R
:= Right_Children
.First
;
1193 if not Equal_Subtree
(Left_Tree
, L
, Right_Tree
, R
) then
1208 function Equal_Subtree
1209 (Left_Position
: Cursor
;
1210 Right_Position
: Cursor
) return Boolean
1213 if Left_Position
= No_Element
then
1214 raise Constraint_Error
with "Left cursor has no element";
1217 if Right_Position
= No_Element
then
1218 raise Constraint_Error
with "Right cursor has no element";
1221 if Left_Position
= Right_Position
then
1225 if Is_Root
(Left_Position
) then
1226 if not Is_Root
(Right_Position
) then
1230 if Left_Position
.Container
.Count
= 0 then
1231 return Right_Position
.Container
.Count
= 0;
1234 if Right_Position
.Container
.Count
= 0 then
1238 return Equal_Children
1239 (Left_Tree
=> Left_Position
.Container
.all,
1240 Left_Subtree
=> Left_Position
.Node
,
1241 Right_Tree
=> Right_Position
.Container
.all,
1242 Right_Subtree
=> Right_Position
.Node
);
1245 if Is_Root
(Right_Position
) then
1249 return Equal_Subtree
1250 (Left_Tree
=> Left_Position
.Container
.all,
1251 Left_Subtree
=> Left_Position
.Node
,
1252 Right_Tree
=> Right_Position
.Container
.all,
1253 Right_Subtree
=> Right_Position
.Node
);
1256 function Equal_Subtree
1258 Left_Subtree
: Count_Type
;
1260 Right_Subtree
: Count_Type
) return Boolean
1263 if Left_Tree
.Elements
(Left_Subtree
) /=
1264 Right_Tree
.Elements
(Right_Subtree
)
1269 return Equal_Children
1270 (Left_Tree
=> Left_Tree
,
1271 Left_Subtree
=> Left_Subtree
,
1272 Right_Tree
=> Right_Tree
,
1273 Right_Subtree
=> Right_Subtree
);
1280 procedure Finalize
(Object
: in out Root_Iterator
) is
1281 B
: Natural renames Object
.Container
.Busy
;
1292 Item
: Element_Type
) return Cursor
1297 if Container
.Count
= 0 then
1301 Node
:= Find_In_Children
(Container
, Root_Node
(Container
), Item
);
1307 return Cursor
'(Container'Unrestricted_Access, Node);
1314 overriding function First (Object : Subtree_Iterator) return Cursor is
1316 if Object.Subtree = Root_Node (Object.Container.all) then
1317 return First_Child (Root (Object.Container.all));
1319 return Cursor'(Object
.Container
, Object
.Subtree
);
1323 overriding
function First
(Object
: Child_Iterator
) return Cursor
is
1325 return First_Child
(Cursor
'(Object.Container, Object.Subtree));
1332 function First_Child (Parent : Cursor) return Cursor is
1333 Node : Count_Type'Base;
1336 if Parent = No_Element then
1337 raise Constraint_Error with "Parent cursor has no element";
1340 if Parent.Container.Count = 0 then
1341 pragma Assert (Is_Root (Parent));
1345 Node := Parent.Container.Nodes (Parent.Node).Children.First;
1351 return Cursor'(Parent
.Container
, Node
);
1354 -------------------------
1355 -- First_Child_Element --
1356 -------------------------
1358 function First_Child_Element
(Parent
: Cursor
) return Element_Type
is
1360 return Element
(First_Child
(Parent
));
1361 end First_Child_Element
;
1363 ----------------------
1364 -- Find_In_Children --
1365 ----------------------
1367 function Find_In_Children
1369 Subtree
: Count_Type
;
1370 Item
: Element_Type
) return Count_Type
1372 N
: Count_Type
'Base;
1373 Result
: Count_Type
;
1376 N
:= Container
.Nodes
(Subtree
).Children
.First
;
1378 Result
:= Find_In_Subtree
(Container
, N
, Item
);
1384 N
:= Container
.Nodes
(N
).Next
;
1388 end Find_In_Children
;
1390 ---------------------
1391 -- Find_In_Subtree --
1392 ---------------------
1394 function Find_In_Subtree
1396 Item
: Element_Type
) return Cursor
1398 Result
: Count_Type
;
1401 if Position
= No_Element
then
1402 raise Constraint_Error
with "Position cursor has no element";
1405 -- Commented-out pending ruling by ARG. ???
1407 -- if Position.Container /= Container'Unrestricted_Access then
1408 -- raise Program_Error with "Position cursor not in container";
1411 if Position
.Container
.Count
= 0 then
1412 pragma Assert
(Is_Root
(Position
));
1416 if Is_Root
(Position
) then
1417 Result
:= Find_In_Children
1418 (Container
=> Position
.Container
.all,
1419 Subtree
=> Position
.Node
,
1423 Result
:= Find_In_Subtree
1424 (Container
=> Position
.Container
.all,
1425 Subtree
=> Position
.Node
,
1433 return Cursor
'(Position.Container, Result);
1434 end Find_In_Subtree;
1436 function Find_In_Subtree
1438 Subtree : Count_Type;
1439 Item : Element_Type) return Count_Type
1442 if Container.Elements (Subtree) = Item then
1446 return Find_In_Children (Container, Subtree, Item);
1447 end Find_In_Subtree;
1453 function Has_Element (Position : Cursor) return Boolean is
1455 if Position = No_Element then
1459 return Position.Node /= Root_Node (Position.Container.all);
1462 ---------------------
1463 -- Initialize_Node --
1464 ---------------------
1466 procedure Initialize_Node
1467 (Container : in out Tree;
1471 Container.Nodes (Index) :=
1475 Children => (others => 0));
1476 end Initialize_Node;
1478 ---------------------
1479 -- Initialize_Root --
1480 ---------------------
1482 procedure Initialize_Root (Container : in out Tree) is
1484 Initialize_Node (Container, Root_Node (Container));
1485 end Initialize_Root;
1491 procedure Insert_Child
1492 (Container : in out Tree;
1495 New_Item : Element_Type;
1496 Count : Count_Type := 1)
1499 pragma Unreferenced (Position);
1502 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1505 procedure Insert_Child
1506 (Container : in out Tree;
1509 New_Item : Element_Type;
1510 Position : out Cursor;
1511 Count : Count_Type := 1)
1513 Nodes : Tree_Node_Array renames Container.Nodes;
1517 if Parent = No_Element then
1518 raise Constraint_Error with "Parent cursor has no element";
1521 if Parent.Container /= Container'Unrestricted_Access then
1522 raise Program_Error with "Parent cursor not in container";
1525 if Before /= No_Element then
1526 if Before.Container /= Container'Unrestricted_Access then
1527 raise Program_Error with "Before cursor not in container";
1530 if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
1531 raise Constraint_Error with "Parent cursor not parent of Before";
1536 Position := No_Element; -- Need ruling from ARG ???
1540 if Container.Count > Container.Capacity - Count then
1541 raise Capacity_Error
1542 with "requested count exceeds available storage";
1545 if Container.Busy > 0 then
1547 with "attempt to tamper with cursors (tree is busy)";
1550 if Container.Count = 0 then
1551 Initialize_Root (Container);
1554 Allocate_Node (Container, New_Item, Position.Node);
1555 Nodes (Position.Node).Parent := Parent.Node;
1557 Last := Position.Node;
1558 for J in Count_Type'(2) .. Count
loop
1559 Allocate_Node
(Container
, New_Item
, Nodes
(Last
).Next
);
1560 Nodes
(Nodes
(Last
).Next
).Parent
:= Parent
.Node
;
1561 Nodes
(Nodes
(Last
).Next
).Prev
:= Last
;
1563 Last
:= Nodes
(Last
).Next
;
1567 (Container
=> Container
,
1568 First
=> Position
.Node
,
1570 Parent
=> Parent
.Node
,
1571 Before
=> Before
.Node
);
1573 Container
.Count
:= Container
.Count
+ Count
;
1575 Position
.Container
:= Parent
.Container
;
1578 procedure Insert_Child
1579 (Container
: in out Tree
;
1582 Position
: out Cursor
;
1583 Count
: Count_Type
:= 1)
1585 Nodes
: Tree_Node_Array
renames Container
.Nodes
;
1588 New_Item
: Element_Type
;
1589 pragma Unmodified
(New_Item
);
1590 -- OK to reference, see below
1593 if Parent
= No_Element
then
1594 raise Constraint_Error
with "Parent cursor has no element";
1597 if Parent
.Container
/= Container
'Unrestricted_Access then
1598 raise Program_Error
with "Parent cursor not in container";
1601 if Before
/= No_Element
then
1602 if Before
.Container
/= Container
'Unrestricted_Access then
1603 raise Program_Error
with "Before cursor not in container";
1606 if Before
.Container
.Nodes
(Before
.Node
).Parent
/= Parent
.Node
then
1607 raise Constraint_Error
with "Parent cursor not parent of Before";
1612 Position
:= No_Element
; -- Need ruling from ARG ???
1616 if Container
.Count
> Container
.Capacity
- Count
then
1617 raise Capacity_Error
1618 with "requested count exceeds available storage";
1621 if Container
.Busy
> 0 then
1623 with "attempt to tamper with cursors (tree is busy)";
1626 if Container
.Count
= 0 then
1627 Initialize_Root
(Container
);
1630 -- There is no explicit element provided, but in an instance the element
1631 -- type may be a scalar with a Default_Value aspect, or a composite
1632 -- type with such a scalar component, or components with default
1633 -- initialization, so insert the specified number of possibly
1634 -- initialized elements at the given position.
1636 Allocate_Node
(Container
, New_Item
, Position
.Node
);
1637 Nodes
(Position
.Node
).Parent
:= Parent
.Node
;
1639 Last
:= Position
.Node
;
1640 for J
in Count_Type
'(2) .. Count loop
1641 Allocate_Node (Container, Nodes (Last).Next);
1642 Nodes (Nodes (Last).Next).Parent := Parent.Node;
1643 Nodes (Nodes (Last).Next).Prev := Last;
1645 Last := Nodes (Last).Next;
1649 (Container => Container,
1650 First => Position.Node,
1652 Parent => Parent.Node,
1653 Before => Before.Node);
1655 Container.Count := Container.Count + Count;
1657 Position.Container := Parent.Container;
1660 -------------------------
1661 -- Insert_Subtree_List --
1662 -------------------------
1664 procedure Insert_Subtree_List
1665 (Container : in out Tree;
1666 First : Count_Type'Base;
1667 Last : Count_Type'Base;
1668 Parent : Count_Type;
1669 Before : Count_Type'Base)
1671 NN : Tree_Node_Array renames Container.Nodes;
1672 N : Tree_Node_Type renames NN (Parent);
1673 CC : Children_Type renames N.Children;
1676 -- This is a simple utility operation to insert a list of nodes
1677 -- (First..Last) as children of Parent. The Before node specifies where
1678 -- the new children should be inserted relative to existing children.
1681 pragma Assert (Last <= 0);
1685 pragma Assert (Last > 0);
1686 pragma Assert (Before <= 0 or else NN (Before).Parent = Parent);
1688 if CC.First <= 0 then -- no existing children
1690 NN (CC.First).Prev := 0;
1692 NN (CC.Last).Next := 0;
1694 elsif Before <= 0 then -- means "insert after existing nodes"
1695 NN (CC.Last).Next := First;
1696 NN (First).Prev := CC.Last;
1698 NN (CC.Last).Next := 0;
1700 elsif Before = CC.First then
1701 NN (Last).Next := CC.First;
1702 NN (CC.First).Prev := Last;
1704 NN (CC.First).Prev := 0;
1707 NN (NN (Before).Prev).Next := First;
1708 NN (First).Prev := NN (Before).Prev;
1709 NN (Last).Next := Before;
1710 NN (Before).Prev := Last;
1712 end Insert_Subtree_List;
1714 -------------------------
1715 -- Insert_Subtree_Node --
1716 -------------------------
1718 procedure Insert_Subtree_Node
1719 (Container : in out Tree;
1720 Subtree : Count_Type'Base;
1721 Parent : Count_Type;
1722 Before : Count_Type'Base)
1725 -- This is a simple wrapper operation to insert a single child into the
1726 -- Parent's children list.
1729 (Container => Container,
1734 end Insert_Subtree_Node;
1740 function Is_Empty (Container : Tree) return Boolean is
1742 return Container.Count = 0;
1749 function Is_Leaf (Position : Cursor) return Boolean is
1751 if Position = No_Element then
1755 if Position.Container.Count = 0 then
1756 pragma Assert (Is_Root (Position));
1760 return Position.Container.Nodes (Position.Node).Children.First <= 0;
1767 function Is_Reachable
1769 From, To : Count_Type) return Boolean
1780 Idx := Container.Nodes (Idx).Parent;
1790 function Is_Root (Position : Cursor) return Boolean is
1793 (if Position.Container = null then False
1794 else Position.Node = Root_Node (Position.Container.all));
1803 Process : not null access procedure (Position : Cursor))
1805 B : Natural renames Container'Unrestricted_Access.all.Busy;
1808 if Container.Count = 0 then
1815 (Container => Container,
1816 Subtree => Root_Node (Container),
1817 Process => Process);
1827 function Iterate (Container : Tree)
1828 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1831 return Iterate_Subtree (Root (Container));
1834 ----------------------
1835 -- Iterate_Children --
1836 ----------------------
1838 procedure Iterate_Children
1840 Process : not null access procedure (Position : Cursor))
1843 if Parent = No_Element then
1844 raise Constraint_Error with "Parent cursor has no element";
1847 if Parent.Container.Count = 0 then
1848 pragma Assert (Is_Root (Parent));
1853 B : Natural renames Parent.Container.Busy;
1855 NN : Tree_Node_Array renames Parent.Container.Nodes;
1860 C := NN (Parent.Node).Children.First;
1862 Process (Cursor'(Parent
.Container
, Node
=> C
));
1873 end Iterate_Children
;
1875 procedure Iterate_Children
1877 Subtree
: Count_Type
;
1878 Process
: not null access procedure (Position
: Cursor
))
1880 NN
: Tree_Node_Array
renames Container
.Nodes
;
1881 N
: Tree_Node_Type
renames NN
(Subtree
);
1885 -- This is a helper function to recursively iterate over all the nodes
1886 -- in a subtree, in depth-first fashion. This particular helper just
1887 -- visits the children of this subtree, not the root of the subtree
1888 -- itself. This is useful when starting from the ultimate root of the
1889 -- entire tree (see Iterate), as that root does not have an element.
1891 C
:= N
.Children
.First
;
1893 Iterate_Subtree
(Container
, C
, Process
);
1896 end Iterate_Children
;
1898 function Iterate_Children
1901 return Tree_Iterator_Interfaces
.Reversible_Iterator
'Class
1903 C
: constant Tree_Access
:= Container
'Unrestricted_Access;
1904 B
: Natural renames C
.Busy
;
1907 if Parent
= No_Element
then
1908 raise Constraint_Error
with "Parent cursor has no element";
1911 if Parent
.Container
/= C
then
1912 raise Program_Error
with "Parent cursor not in container";
1915 return It
: constant Child_Iterator
:=
1916 Child_Iterator
'(Limited_Controlled with
1918 Subtree => Parent.Node)
1922 end Iterate_Children;
1924 ---------------------
1925 -- Iterate_Subtree --
1926 ---------------------
1928 function Iterate_Subtree
1930 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1933 if Position = No_Element then
1934 raise Constraint_Error with "Position cursor has no element";
1937 -- Implement Vet for multiway trees???
1938 -- pragma Assert (Vet (Position), "bad subtree cursor");
1941 B : Natural renames Position.Container.Busy;
1943 return It : constant Subtree_Iterator :=
1944 (Limited_Controlled with
1945 Container => Position.Container,
1946 Subtree => Position.Node)
1951 end Iterate_Subtree;
1953 procedure Iterate_Subtree
1955 Process : not null access procedure (Position : Cursor))
1958 if Position = No_Element then
1959 raise Constraint_Error with "Position cursor has no element";
1962 if Position.Container.Count = 0 then
1963 pragma Assert (Is_Root (Position));
1968 T : Tree renames Position.Container.all;
1969 B : Natural renames T.Busy;
1974 if Is_Root (Position) then
1975 Iterate_Children (T, Position.Node, Process);
1977 Iterate_Subtree (T, Position.Node, Process);
1987 end Iterate_Subtree;
1989 procedure Iterate_Subtree
1991 Subtree : Count_Type;
1992 Process : not null access procedure (Position : Cursor))
1995 -- This is a helper function to recursively iterate over all the nodes
1996 -- in a subtree, in depth-first fashion. It first visits the root of the
1997 -- subtree, then visits its children.
1999 Process (Cursor'(Container
'Unrestricted_Access, Subtree
));
2000 Iterate_Children
(Container
, Subtree
, Process
);
2001 end Iterate_Subtree
;
2007 overriding
function Last
(Object
: Child_Iterator
) return Cursor
is
2009 return Last_Child
(Cursor
'(Object.Container, Object.Subtree));
2016 function Last_Child (Parent : Cursor) return Cursor is
2017 Node : Count_Type'Base;
2020 if Parent = No_Element then
2021 raise Constraint_Error with "Parent cursor has no element";
2024 if Parent.Container.Count = 0 then
2025 pragma Assert (Is_Root (Parent));
2029 Node := Parent.Container.Nodes (Parent.Node).Children.Last;
2035 return Cursor'(Parent
.Container
, Node
);
2038 ------------------------
2039 -- Last_Child_Element --
2040 ------------------------
2042 function Last_Child_Element
(Parent
: Cursor
) return Element_Type
is
2044 return Element
(Last_Child
(Parent
));
2045 end Last_Child_Element
;
2051 procedure Move
(Target
: in out Tree
; Source
: in out Tree
) is
2053 if Target
'Address = Source
'Address then
2057 if Source
.Busy
> 0 then
2059 with "attempt to tamper with cursors of Source (tree is busy)";
2062 Target
.Assign
(Source
);
2070 overriding
function Next
2071 (Object
: Subtree_Iterator
;
2072 Position
: Cursor
) return Cursor
2075 if Position
.Container
= null then
2079 if Position
.Container
/= Object
.Container
then
2080 raise Program_Error
with
2081 "Position cursor of Next designates wrong tree";
2084 pragma Assert
(Object
.Container
.Count
> 0);
2085 pragma Assert
(Position
.Node
/= Root_Node
(Object
.Container
.all));
2088 Nodes
: Tree_Node_Array
renames Object
.Container
.Nodes
;
2092 Node
:= Position
.Node
;
2094 if Nodes
(Node
).Children
.First
> 0 then
2095 return Cursor
'(Object.Container, Nodes (Node).Children.First);
2098 while Node /= Object.Subtree loop
2099 if Nodes (Node).Next > 0 then
2100 return Cursor'(Object
.Container
, Nodes
(Node
).Next
);
2103 Node
:= Nodes
(Node
).Parent
;
2110 overriding
function Next
2111 (Object
: Child_Iterator
;
2112 Position
: Cursor
) return Cursor
2115 if Position
.Container
= null then
2119 if Position
.Container
/= Object
.Container
then
2120 raise Program_Error
with
2121 "Position cursor of Next designates wrong tree";
2124 pragma Assert
(Object
.Container
.Count
> 0);
2125 pragma Assert
(Position
.Node
/= Root_Node
(Object
.Container
.all));
2127 return Next_Sibling
(Position
);
2134 function Next_Sibling
(Position
: Cursor
) return Cursor
is
2136 if Position
= No_Element
then
2140 if Position
.Container
.Count
= 0 then
2141 pragma Assert
(Is_Root
(Position
));
2146 T
: Tree
renames Position
.Container
.all;
2147 NN
: Tree_Node_Array
renames T
.Nodes
;
2148 N
: Tree_Node_Type
renames NN
(Position
.Node
);
2155 return Cursor
'(Position.Container, N.Next);
2159 procedure Next_Sibling (Position : in out Cursor) is
2161 Position := Next_Sibling (Position);
2168 function Node_Count (Container : Tree) return Count_Type is
2170 -- Container.Count is the number of nodes we have actually allocated. We
2171 -- cache the value specifically so this Node_Count operation can execute
2172 -- in O(1) time, which makes it behave similarly to how the Length
2173 -- selector function behaves for other containers.
2175 -- The cached node count value only describes the nodes we have
2176 -- allocated; the root node itself is not included in that count. The
2177 -- Node_Count operation returns a value that includes the root node
2178 -- (because the RM says so), so we must add 1 to our cached value.
2180 return 1 + Container.Count;
2187 function Parent (Position : Cursor) return Cursor is
2189 if Position = No_Element then
2193 if Position.Container.Count = 0 then
2194 pragma Assert (Is_Root (Position));
2199 T : Tree renames Position.Container.all;
2200 NN : Tree_Node_Array renames T.Nodes;
2201 N : Tree_Node_Type renames NN (Position.Node);
2204 if N.Parent < 0 then
2205 pragma Assert (Position.Node = Root_Node (T));
2209 return Cursor'(Position
.Container
, N
.Parent
);
2217 procedure Prepend_Child
2218 (Container
: in out Tree
;
2220 New_Item
: Element_Type
;
2221 Count
: Count_Type
:= 1)
2223 Nodes
: Tree_Node_Array
renames Container
.Nodes
;
2224 First
, Last
: Count_Type
;
2227 if Parent
= No_Element
then
2228 raise Constraint_Error
with "Parent cursor has no element";
2231 if Parent
.Container
/= Container
'Unrestricted_Access then
2232 raise Program_Error
with "Parent cursor not in container";
2239 if Container
.Count
> Container
.Capacity
- Count
then
2240 raise Capacity_Error
2241 with "requested count exceeds available storage";
2244 if Container
.Busy
> 0 then
2246 with "attempt to tamper with cursors (tree is busy)";
2249 if Container
.Count
= 0 then
2250 Initialize_Root
(Container
);
2253 Allocate_Node
(Container
, New_Item
, First
);
2254 Nodes
(First
).Parent
:= Parent
.Node
;
2257 for J
in Count_Type
'(2) .. Count loop
2258 Allocate_Node (Container, New_Item, Nodes (Last).Next);
2259 Nodes (Nodes (Last).Next).Parent := Parent.Node;
2260 Nodes (Nodes (Last).Next).Prev := Last;
2262 Last := Nodes (Last).Next;
2266 (Container => Container,
2269 Parent => Parent.Node,
2270 Before => Nodes (Parent.Node).Children.First);
2272 Container.Count := Container.Count + Count;
2279 overriding function Previous
2280 (Object : Child_Iterator;
2281 Position : Cursor) return Cursor
2284 if Position.Container = null then
2288 if Position.Container /= Object.Container then
2289 raise Program_Error with
2290 "Position cursor of Previous designates wrong tree";
2293 return Previous_Sibling (Position);
2296 ----------------------
2297 -- Previous_Sibling --
2298 ----------------------
2300 function Previous_Sibling (Position : Cursor) return Cursor is
2302 if Position = No_Element then
2306 if Position.Container.Count = 0 then
2307 pragma Assert (Is_Root (Position));
2312 T : Tree renames Position.Container.all;
2313 NN : Tree_Node_Array renames T.Nodes;
2314 N : Tree_Node_Type renames NN (Position.Node);
2321 return Cursor'(Position
.Container
, N
.Prev
);
2323 end Previous_Sibling
;
2325 procedure Previous_Sibling
(Position
: in out Cursor
) is
2327 Position
:= Previous_Sibling
(Position
);
2328 end Previous_Sibling
;
2334 procedure Query_Element
2336 Process
: not null access procedure (Element
: Element_Type
))
2339 if Position
= No_Element
then
2340 raise Constraint_Error
with "Position cursor has no element";
2343 if Is_Root
(Position
) then
2344 raise Program_Error
with "Position cursor designates root";
2348 T
: Tree
renames Position
.Container
.all'Unrestricted_Access.all;
2349 B
: Natural renames T
.Busy
;
2350 L
: Natural renames T
.Lock
;
2356 Process
(Element
=> T
.Elements
(Position
.Node
));
2374 (Stream
: not null access Root_Stream_Type
'Class;
2375 Container
: out Tree
)
2377 procedure Read_Children
(Subtree
: Count_Type
);
2379 function Read_Subtree
2380 (Parent
: Count_Type
) return Count_Type
;
2382 NN
: Tree_Node_Array
renames Container
.Nodes
;
2384 Total_Count
: Count_Type
'Base;
2385 -- Value read from the stream that says how many elements follow
2387 Read_Count
: Count_Type
'Base;
2388 -- Actual number of elements read from the stream
2394 procedure Read_Children
(Subtree
: Count_Type
) is
2395 Count
: Count_Type
'Base;
2396 -- number of child subtrees
2401 Count_Type
'Read (Stream
, Count
);
2404 raise Program_Error
with "attempt to read from corrupt stream";
2411 CC
.First
:= Read_Subtree
(Parent
=> Subtree
);
2412 CC
.Last
:= CC
.First
;
2414 for J
in Count_Type
'(2) .. Count loop
2415 NN (CC.Last).Next := Read_Subtree (Parent => Subtree);
2416 NN (NN (CC.Last).Next).Prev := CC.Last;
2417 CC.Last := NN (CC.Last).Next;
2420 -- Now that the allocation and reads have completed successfully, it
2421 -- is safe to link the children to their parent.
2423 NN (Subtree).Children := CC;
2430 function Read_Subtree
2431 (Parent : Count_Type) return Count_Type
2433 Subtree : Count_Type;
2436 Allocate_Node (Container, Stream, Subtree);
2437 Container.Nodes (Subtree).Parent := Parent;
2439 Read_Count := Read_Count + 1;
2441 Read_Children (Subtree);
2446 -- Start of processing for Read
2449 Container.Clear; -- checks busy bit
2451 Count_Type'Read (Stream, Total_Count);
2453 if Total_Count < 0 then
2454 raise Program_Error with "attempt to read from corrupt stream";
2457 if Total_Count = 0 then
2461 if Total_Count > Container.Capacity then
2462 raise Capacity_Error -- ???
2463 with "node count in stream exceeds container capacity";
2466 Initialize_Root (Container);
2470 Read_Children (Root_Node (Container));
2472 if Read_Count /= Total_Count then
2473 raise Program_Error with "attempt to read from corrupt stream";
2476 Container.Count := Total_Count;
2480 (Stream : not null access Root_Stream_Type'Class;
2481 Position : out Cursor)
2484 raise Program_Error with "attempt to read tree cursor from stream";
2488 (Stream : not null access Root_Stream_Type'Class;
2489 Item : out Reference_Type)
2492 raise Program_Error with "attempt to stream reference";
2496 (Stream : not null access Root_Stream_Type'Class;
2497 Item : out Constant_Reference_Type)
2500 raise Program_Error with "attempt to stream reference";
2508 (Container : aliased in out Tree;
2509 Position : Cursor) return Reference_Type
2512 if Position.Container = null then
2513 raise Constraint_Error with
2514 "Position cursor has no element";
2517 if Position.Container /= Container'Unrestricted_Access then
2518 raise Program_Error with
2519 "Position cursor designates wrong container";
2522 if Position.Node = Root_Node (Container) then
2523 raise Program_Error with "Position cursor designates root";
2526 -- Implement Vet for multiway tree???
2527 -- pragma Assert (Vet (Position),
2528 -- "Position cursor in Constant_Reference is bad");
2530 return (Element => Container.Elements (Position.Node)'Access);
2533 --------------------
2534 -- Remove_Subtree --
2535 --------------------
2537 procedure Remove_Subtree
2538 (Container : in out Tree;
2539 Subtree : Count_Type)
2541 NN : Tree_Node_Array renames Container.Nodes;
2542 N : Tree_Node_Type renames NN (Subtree);
2543 CC : Children_Type renames NN (N.Parent).Children;
2546 -- This is a utility operation to remove a subtree node from its
2547 -- parent's list of children.
2549 if CC.First = Subtree then
2550 pragma Assert (N.Prev <= 0);
2552 if CC.Last = Subtree then
2553 pragma Assert (N.Next <= 0);
2559 NN (CC.First).Prev := 0;
2562 elsif CC.Last = Subtree then
2563 pragma Assert (N.Next <= 0);
2565 NN (CC.Last).Next := 0;
2568 NN (N.Prev).Next := N.Next;
2569 NN (N.Next).Prev := N.Prev;
2573 ----------------------
2574 -- Replace_Element --
2575 ----------------------
2577 procedure Replace_Element
2578 (Container : in out Tree;
2580 New_Item : Element_Type)
2583 if Position = No_Element then
2584 raise Constraint_Error with "Position cursor has no element";
2587 if Position.Container /= Container'Unrestricted_Access then
2588 raise Program_Error with "Position cursor not in container";
2591 if Is_Root (Position) then
2592 raise Program_Error with "Position cursor designates root";
2595 if Container.Lock > 0 then
2597 with "attempt to tamper with elements (tree is locked)";
2600 Container.Elements (Position.Node) := New_Item;
2601 end Replace_Element;
2603 ------------------------------
2604 -- Reverse_Iterate_Children --
2605 ------------------------------
2607 procedure Reverse_Iterate_Children
2609 Process : not null access procedure (Position : Cursor))
2612 if Parent = No_Element then
2613 raise Constraint_Error with "Parent cursor has no element";
2616 if Parent.Container.Count = 0 then
2617 pragma Assert (Is_Root (Parent));
2622 NN : Tree_Node_Array renames Parent.Container.Nodes;
2623 B : Natural renames Parent.Container.Busy;
2629 C := NN (Parent.Node).Children.Last;
2631 Process (Cursor'(Parent
.Container
, Node
=> C
));
2642 end Reverse_Iterate_Children
;
2648 function Root
(Container
: Tree
) return Cursor
is
2650 return (Container
'Unrestricted_Access, Root_Node
(Container
));
2657 function Root_Node
(Container
: Tree
) return Count_Type
is
2658 pragma Unreferenced
(Container
);
2664 ---------------------
2665 -- Splice_Children --
2666 ---------------------
2668 procedure Splice_Children
2669 (Target
: in out Tree
;
2670 Target_Parent
: Cursor
;
2672 Source
: in out Tree
;
2673 Source_Parent
: Cursor
)
2676 if Target_Parent
= No_Element
then
2677 raise Constraint_Error
with "Target_Parent cursor has no element";
2680 if Target_Parent
.Container
/= Target
'Unrestricted_Access then
2682 with "Target_Parent cursor not in Target container";
2685 if Before
/= No_Element
then
2686 if Before
.Container
/= Target
'Unrestricted_Access then
2688 with "Before cursor not in Target container";
2691 if Target
.Nodes
(Before
.Node
).Parent
/= Target_Parent
.Node
then
2692 raise Constraint_Error
2693 with "Before cursor not child of Target_Parent";
2697 if Source_Parent
= No_Element
then
2698 raise Constraint_Error
with "Source_Parent cursor has no element";
2701 if Source_Parent
.Container
/= Source
'Unrestricted_Access then
2703 with "Source_Parent cursor not in Source container";
2706 if Source
.Count
= 0 then
2707 pragma Assert
(Is_Root
(Source_Parent
));
2711 if Target
'Address = Source
'Address then
2712 if Target_Parent
= Source_Parent
then
2716 if Target
.Busy
> 0 then
2718 with "attempt to tamper with cursors (Target tree is busy)";
2721 if Is_Reachable
(Container
=> Target
,
2722 From
=> Target_Parent
.Node
,
2723 To
=> Source_Parent
.Node
)
2725 raise Constraint_Error
2726 with "Source_Parent is ancestor of Target_Parent";
2730 (Container
=> Target
,
2731 Target_Parent
=> Target_Parent
.Node
,
2732 Before
=> Before
.Node
,
2733 Source_Parent
=> Source_Parent
.Node
);
2738 if Target
.Busy
> 0 then
2740 with "attempt to tamper with cursors (Target tree is busy)";
2743 if Source
.Busy
> 0 then
2745 with "attempt to tamper with cursors (Source tree is busy)";
2748 if Target
.Count
= 0 then
2749 Initialize_Root
(Target
);
2754 Target_Parent
=> Target_Parent
.Node
,
2755 Before
=> Before
.Node
,
2757 Source_Parent
=> Source_Parent
.Node
);
2758 end Splice_Children
;
2760 procedure Splice_Children
2761 (Container
: in out Tree
;
2762 Target_Parent
: Cursor
;
2764 Source_Parent
: Cursor
)
2767 if Target_Parent
= No_Element
then
2768 raise Constraint_Error
with "Target_Parent cursor has no element";
2771 if Target_Parent
.Container
/= Container
'Unrestricted_Access then
2773 with "Target_Parent cursor not in container";
2776 if Before
/= No_Element
then
2777 if Before
.Container
/= Container
'Unrestricted_Access then
2779 with "Before cursor not in container";
2782 if Container
.Nodes
(Before
.Node
).Parent
/= Target_Parent
.Node
then
2783 raise Constraint_Error
2784 with "Before cursor not child of Target_Parent";
2788 if Source_Parent
= No_Element
then
2789 raise Constraint_Error
with "Source_Parent cursor has no element";
2792 if Source_Parent
.Container
/= Container
'Unrestricted_Access then
2794 with "Source_Parent cursor not in container";
2797 if Target_Parent
= Source_Parent
then
2801 pragma Assert
(Container
.Count
> 0);
2803 if Container
.Busy
> 0 then
2805 with "attempt to tamper with cursors (tree is busy)";
2808 if Is_Reachable
(Container
=> Container
,
2809 From
=> Target_Parent
.Node
,
2810 To
=> Source_Parent
.Node
)
2812 raise Constraint_Error
2813 with "Source_Parent is ancestor of Target_Parent";
2817 (Container
=> Container
,
2818 Target_Parent
=> Target_Parent
.Node
,
2819 Before
=> Before
.Node
,
2820 Source_Parent
=> Source_Parent
.Node
);
2821 end Splice_Children
;
2823 procedure Splice_Children
2824 (Container
: in out Tree
;
2825 Target_Parent
: Count_Type
;
2826 Before
: Count_Type
'Base;
2827 Source_Parent
: Count_Type
)
2829 NN
: Tree_Node_Array
renames Container
.Nodes
;
2830 CC
: constant Children_Type
:= NN
(Source_Parent
).Children
;
2831 C
: Count_Type
'Base;
2834 -- This is a utility operation to remove the children from Source parent
2835 -- and insert them into Target parent.
2837 NN
(Source_Parent
).Children
:= Children_Type
'(others => 0);
2839 -- Fix up the Parent pointers of each child to designate its new Target
2844 NN (C).Parent := Target_Parent;
2849 (Container => Container,
2852 Parent => Target_Parent,
2854 end Splice_Children;
2856 procedure Splice_Children
2857 (Target : in out Tree;
2858 Target_Parent : Count_Type;
2859 Before : Count_Type'Base;
2860 Source : in out Tree;
2861 Source_Parent : Count_Type)
2863 S_NN : Tree_Node_Array renames Source.Nodes;
2864 S_CC : Children_Type renames S_NN (Source_Parent).Children;
2866 Target_Count, Source_Count : Count_Type;
2867 T, S : Count_Type'Base;
2870 -- This is a utility operation to copy the children from the Source
2871 -- parent and insert them as children of the Target parent, and then
2872 -- delete them from the Source. (This is not a true splice operation,
2873 -- but it is the best we can do in a bounded form.) The Before position
2874 -- specifies where among the Target parent's exising children the new
2875 -- children are inserted.
2877 -- Before we attempt the insertion, we must count the sources nodes in
2878 -- order to determine whether the target have enough storage
2879 -- available. Note that calculating this value is an O(n) operation.
2881 -- Here is an optimization opportunity: iterate of each children the
2882 -- source explicitly, and keep a running count of the total number of
2883 -- nodes. Compare the running total to the capacity of the target each
2884 -- pass through the loop. This is more efficient than summing the counts
2885 -- of child subtree (which is what Subtree_Node_Count does) and then
2886 -- comparing that total sum to the target's capacity. ???
2888 -- Here is another possibility. We currently treat the splice as an
2889 -- all-or-nothing proposition: either we can insert all of children of
2890 -- the source, or we raise exception with modifying the target. The
2891 -- price for not causing side-effect is an O(n) determination of the
2892 -- source count. If we are willing to tolerate side-effect, then we
2893 -- could loop over the children of the source, counting that subtree and
2894 -- then immediately inserting it in the target. The issue here is that
2895 -- the test for available storage could fail during some later pass,
2896 -- after children have already been inserted into target. ???
2898 Source_Count := Subtree_Node_Count (Source, Source_Parent) - 1;
2900 if Source_Count = 0 then
2904 if Target.Count > Target.Capacity - Source_Count then
2905 raise Capacity_Error -- ???
2906 with "Source count exceeds available storage on Target";
2909 -- Copy_Subtree returns a count of the number of nodes it inserts, but
2910 -- it does this by incrementing the value passed in. Therefore we must
2911 -- initialize the count before calling Copy_Subtree.
2919 Source_Subtree => S,
2921 Target_Parent => Target_Parent,
2922 Target_Subtree => T,
2923 Count => Target_Count);
2926 (Container => Target,
2928 Parent => Target_Parent,
2934 pragma Assert (Target_Count = Source_Count);
2935 Target.Count := Target.Count + Target_Count;
2937 -- As with Copy_Subtree, operation Deallocate_Children returns a count
2938 -- of the number of nodes it deallocates, but it works by incrementing
2939 -- the value passed in. We must therefore initialize the count before
2944 Deallocate_Children (Source, Source_Parent, Source_Count);
2945 pragma Assert (Source_Count = Target_Count);
2947 Source.Count := Source.Count - Source_Count;
2948 end Splice_Children;
2950 --------------------
2951 -- Splice_Subtree --
2952 --------------------
2954 procedure Splice_Subtree
2955 (Target : in out Tree;
2958 Source : in out Tree;
2959 Position : in out Cursor)
2962 if Parent = No_Element then
2963 raise Constraint_Error with "Parent cursor has no element";
2966 if Parent.Container /= Target'Unrestricted_Access then
2967 raise Program_Error with "Parent cursor not in Target container";
2970 if Before /= No_Element then
2971 if Before.Container /= Target'Unrestricted_Access then
2972 raise Program_Error with "Before cursor not in Target container";
2975 if Target.Nodes (Before.Node).Parent /= Parent.Node then
2976 raise Constraint_Error with "Before cursor not child of Parent";
2980 if Position = No_Element then
2981 raise Constraint_Error with "Position cursor has no element";
2984 if Position.Container /= Source'Unrestricted_Access then
2985 raise Program_Error with "Position cursor not in Source container";
2988 if Is_Root (Position) then
2989 raise Program_Error with "Position cursor designates root";
2992 if Target'Address = Source'Address then
2993 if Target.Nodes (Position.Node).Parent = Parent.Node then
2994 if Before = No_Element then
2995 if Target.Nodes (Position.Node).Next <= 0 then -- last child
2999 elsif Position.Node = Before.Node then
3002 elsif Target.Nodes (Position.Node).Next = Before.Node then
3007 if Target.Busy > 0 then
3009 with "attempt to tamper with cursors (Target tree is busy)";
3012 if Is_Reachable (Container => Target,
3013 From => Parent.Node,
3014 To => Position.Node)
3016 raise Constraint_Error with "Position is ancestor of Parent";
3019 Remove_Subtree (Target, Position.Node);
3021 Target.Nodes (Position.Node).Parent := Parent.Node;
3022 Insert_Subtree_Node (Target, Position.Node, Parent.Node, Before.Node);
3027 if Target.Busy > 0 then
3029 with "attempt to tamper with cursors (Target tree is busy)";
3032 if Source.Busy > 0 then
3034 with "attempt to tamper with cursors (Source tree is busy)";
3037 if Target.Count = 0 then
3038 Initialize_Root (Target);
3043 Parent => Parent.Node,
3044 Before => Before.Node,
3046 Position => Position.Node); -- modified during call
3048 Position.Container := Target'Unrestricted_Access;
3051 procedure Splice_Subtree
3052 (Container : in out Tree;
3058 if Parent = No_Element then
3059 raise Constraint_Error with "Parent cursor has no element";
3062 if Parent.Container /= Container'Unrestricted_Access then
3063 raise Program_Error with "Parent cursor not in container";
3066 if Before /= No_Element then
3067 if Before.Container /= Container'Unrestricted_Access then
3068 raise Program_Error with "Before cursor not in container";
3071 if Container.Nodes (Before.Node).Parent /= Parent.Node then
3072 raise Constraint_Error with "Before cursor not child of Parent";
3076 if Position = No_Element then
3077 raise Constraint_Error with "Position cursor has no element";
3080 if Position.Container /= Container'Unrestricted_Access then
3081 raise Program_Error with "Position cursor not in container";
3084 if Is_Root (Position) then
3086 -- Should this be PE instead? Need ARG confirmation. ???
3088 raise Constraint_Error with "Position cursor designates root";
3091 if Container.Nodes (Position.Node).Parent = Parent.Node then
3092 if Before = No_Element then
3093 if Container.Nodes (Position.Node).Next <= 0 then -- last child
3097 elsif Position.Node = Before.Node then
3100 elsif Container.Nodes (Position.Node).Next = Before.Node then
3105 if Container.Busy > 0 then
3107 with "attempt to tamper with cursors (tree is busy)";
3110 if Is_Reachable (Container => Container,
3111 From => Parent.Node,
3112 To => Position.Node)
3114 raise Constraint_Error with "Position is ancestor of Parent";
3117 Remove_Subtree (Container, Position.Node);
3118 Container.Nodes (Position.Node).Parent := Parent.Node;
3119 Insert_Subtree_Node (Container, Position.Node, Parent.Node, Before.Node);
3122 procedure Splice_Subtree
3123 (Target : in out Tree;
3124 Parent : Count_Type;
3125 Before : Count_Type'Base;
3126 Source : in out Tree;
3127 Position : in out Count_Type) -- Source on input, Target on output
3129 Source_Count : Count_Type := Subtree_Node_Count (Source, Position);
3130 pragma Assert (Source_Count >= 1);
3132 Target_Subtree : Count_Type;
3133 Target_Count : Count_Type;
3136 -- This is a utility operation to do the heavy lifting associated with
3137 -- splicing a subtree from one tree to another. Note that "splicing"
3138 -- is a bit of a misnomer here in the case of a bounded tree, because
3139 -- the elements must be copied from the source to the target.
3141 if Target.Count > Target.Capacity - Source_Count then
3142 raise Capacity_Error -- ???
3143 with "Source count exceeds available storage on Target";
3146 -- Copy_Subtree returns a count of the number of nodes it inserts, but
3147 -- it does this by incrementing the value passed in. Therefore we must
3148 -- initialize the count before calling Copy_Subtree.
3154 Source_Subtree => Position,
3156 Target_Parent => Parent,
3157 Target_Subtree => Target_Subtree,
3158 Count => Target_Count);
3160 pragma Assert (Target_Count = Source_Count);
3162 -- Now link the newly-allocated subtree into the target.
3165 (Container => Target,
3166 Subtree => Target_Subtree,
3170 Target.Count := Target.Count + Target_Count;
3172 -- The manipulation of the Target container is complete. Now we remove
3173 -- the subtree from the Source container.
3175 Remove_Subtree (Source, Position); -- unlink the subtree
3177 -- As with Copy_Subtree, operation Deallocate_Subtree returns a count of
3178 -- the number of nodes it deallocates, but it works by incrementing the
3179 -- value passed in. We must therefore initialize the count before
3184 Deallocate_Subtree (Source, Position, Source_Count);
3185 pragma Assert (Source_Count = Target_Count);
3187 Source.Count := Source.Count - Source_Count;
3189 Position := Target_Subtree;
3192 ------------------------
3193 -- Subtree_Node_Count --
3194 ------------------------
3196 function Subtree_Node_Count (Position : Cursor) return Count_Type is
3198 if Position = No_Element then
3202 if Position.Container.Count = 0 then
3203 pragma Assert (Is_Root (Position));
3207 return Subtree_Node_Count (Position.Container.all, Position.Node);
3208 end Subtree_Node_Count;
3210 function Subtree_Node_Count
3212 Subtree : Count_Type) return Count_Type
3214 Result : Count_Type;
3215 Node : Count_Type'Base;
3219 Node := Container.Nodes (Subtree).Children.First;
3221 Result := Result + Subtree_Node_Count (Container, Node);
3222 Node := Container.Nodes (Node).Next;
3225 end Subtree_Node_Count;
3232 (Container : in out Tree;
3236 if I = No_Element then
3237 raise Constraint_Error with "I cursor has no element";
3240 if I.Container /= Container'Unrestricted_Access then
3241 raise Program_Error with "I cursor not in container";
3245 raise Program_Error with "I cursor designates root";
3248 if I = J then -- make this test sooner???
3252 if J = No_Element then
3253 raise Constraint_Error with "J cursor has no element";
3256 if J.Container /= Container'Unrestricted_Access then
3257 raise Program_Error with "J cursor not in container";
3261 raise Program_Error with "J cursor designates root";
3264 if Container.Lock > 0 then
3266 with "attempt to tamper with elements (tree is locked)";
3270 EE : Element_Array renames Container.Elements;
3271 EI : constant Element_Type := EE (I.Node);
3274 EE (I.Node) := EE (J.Node);
3279 --------------------
3280 -- Update_Element --
3281 --------------------
3283 procedure Update_Element
3284 (Container : in out Tree;
3286 Process : not null access procedure (Element : in out Element_Type))
3289 if Position = No_Element then
3290 raise Constraint_Error with "Position cursor has no element";
3293 if Position.Container /= Container'Unrestricted_Access then
3294 raise Program_Error with "Position cursor not in container";
3297 if Is_Root (Position) then
3298 raise Program_Error with "Position cursor designates root";
3302 T : Tree renames Position.Container.all'Unrestricted_Access.all;
3303 B : Natural renames T.Busy;
3304 L : Natural renames T.Lock;
3310 Process (Element => T.Elements (Position.Node));
3328 (Stream : not null access Root_Stream_Type'Class;
3331 procedure Write_Children (Subtree : Count_Type);
3332 procedure Write_Subtree (Subtree : Count_Type);
3334 --------------------
3335 -- Write_Children --
3336 --------------------
3338 procedure Write_Children (Subtree : Count_Type) is
3339 CC : Children_Type renames Container.Nodes (Subtree).Children;
3340 C : Count_Type'Base;
3343 Count_Type'Write (Stream, Child_Count (Container, Subtree));
3348 C := Container.Nodes (C).Next;
3356 procedure Write_Subtree (Subtree : Count_Type) is
3358 Element_Type'Write (Stream, Container.Elements (Subtree));
3359 Write_Children (Subtree);
3362 -- Start of processing for Write
3365 Count_Type'Write (Stream, Container.Count);
3367 if Container.Count = 0 then
3371 Write_Children (Root_Node (Container));
3375 (Stream : not null access Root_Stream_Type'Class;
3379 raise Program_Error with "attempt to write tree cursor to stream";
3383 (Stream : not null access Root_Stream_Type'Class;
3384 Item : Reference_Type)
3387 raise Program_Error with "attempt to stream reference";
3391 (Stream : not null access Root_Stream_Type'Class;
3392 Item : Constant_Reference_Type)
3395 raise Program_Error with "attempt to stream reference";
3398 end Ada.Containers.Bounded_Multiway_Trees;