gcc/
[official-gcc.git] / gcc / ada / a-cimutr.adb
blob2405a172eb8da0e13548653fa24316c7791c9600
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- ADA.CONTAINERS.INDEFINITE_MULTIWAY_TREES --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2013, Free Software Foundation, Inc. --
10 -- --
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. --
17 -- --
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. --
21 -- --
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/>. --
26 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Unchecked_Deallocation;
32 with System; use type System.Address;
34 package body Ada.Containers.Indefinite_Multiway_Trees is
36 --------------------
37 -- Root_Iterator --
38 --------------------
40 type Root_Iterator is abstract new Limited_Controlled and
41 Tree_Iterator_Interfaces.Forward_Iterator with
42 record
43 Container : Tree_Access;
44 Subtree : Tree_Node_Access;
45 end record;
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;
61 ---------------------
62 -- Child_Iterator --
63 ---------------------
65 type Child_Iterator is new Root_Iterator and
66 Tree_Iterator_Interfaces.Reversible_Iterator with null record;
68 overriding function First (Object : Child_Iterator) return Cursor;
70 overriding function Next
71 (Object : Child_Iterator;
72 Position : Cursor) return Cursor;
74 overriding function Last (Object : Child_Iterator) return Cursor;
76 overriding function Previous
77 (Object : Child_Iterator;
78 Position : Cursor) return Cursor;
80 -----------------------
81 -- Local Subprograms --
82 -----------------------
84 function Root_Node (Container : Tree) return Tree_Node_Access;
86 procedure Free_Element is
87 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
89 procedure Deallocate_Node (X : in out Tree_Node_Access);
91 procedure Deallocate_Children
92 (Subtree : Tree_Node_Access;
93 Count : in out Count_Type);
95 procedure Deallocate_Subtree
96 (Subtree : in out Tree_Node_Access;
97 Count : in out Count_Type);
99 function Equal_Children
100 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
102 function Equal_Subtree
103 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
105 procedure Iterate_Children
106 (Container : Tree_Access;
107 Subtree : Tree_Node_Access;
108 Process : not null access procedure (Position : Cursor));
110 procedure Iterate_Subtree
111 (Container : Tree_Access;
112 Subtree : Tree_Node_Access;
113 Process : not null access procedure (Position : Cursor));
115 procedure Copy_Children
116 (Source : Children_Type;
117 Parent : Tree_Node_Access;
118 Count : in out Count_Type);
120 procedure Copy_Subtree
121 (Source : Tree_Node_Access;
122 Parent : Tree_Node_Access;
123 Target : out Tree_Node_Access;
124 Count : in out Count_Type);
126 function Find_In_Children
127 (Subtree : Tree_Node_Access;
128 Item : Element_Type) return Tree_Node_Access;
130 function Find_In_Subtree
131 (Subtree : Tree_Node_Access;
132 Item : Element_Type) return Tree_Node_Access;
134 function Child_Count (Children : Children_Type) return Count_Type;
136 function Subtree_Node_Count
137 (Subtree : Tree_Node_Access) return Count_Type;
139 function Is_Reachable (From, To : Tree_Node_Access) return Boolean;
141 procedure Remove_Subtree (Subtree : Tree_Node_Access);
143 procedure Insert_Subtree_Node
144 (Subtree : Tree_Node_Access;
145 Parent : Tree_Node_Access;
146 Before : Tree_Node_Access);
148 procedure Insert_Subtree_List
149 (First : Tree_Node_Access;
150 Last : Tree_Node_Access;
151 Parent : Tree_Node_Access;
152 Before : Tree_Node_Access);
154 procedure Splice_Children
155 (Target_Parent : Tree_Node_Access;
156 Before : Tree_Node_Access;
157 Source_Parent : Tree_Node_Access);
159 ---------
160 -- "=" --
161 ---------
163 function "=" (Left, Right : Tree) return Boolean is
164 begin
165 if Left'Address = Right'Address then
166 return True;
167 end if;
169 return Equal_Children (Root_Node (Left), Root_Node (Right));
170 end "=";
172 ------------
173 -- Adjust --
174 ------------
176 procedure Adjust (Container : in out Tree) is
177 Source : constant Children_Type := Container.Root.Children;
178 Source_Count : constant Count_Type := Container.Count;
179 Target_Count : Count_Type;
181 begin
182 -- We first restore the target container to its default-initialized
183 -- state, before we attempt any allocation, to ensure that invariants
184 -- are preserved in the event that the allocation fails.
186 Container.Root.Children := Children_Type'(others => null);
187 Container.Busy := 0;
188 Container.Lock := 0;
189 Container.Count := 0;
191 -- Copy_Children returns a count of the number of nodes that it
192 -- allocates, but it works by incrementing the value that is passed in.
193 -- We must therefore initialize the count value before calling
194 -- Copy_Children.
196 Target_Count := 0;
198 -- Now we attempt the allocation of subtrees. The invariants are
199 -- satisfied even if the allocation fails.
201 Copy_Children (Source, Root_Node (Container), Target_Count);
202 pragma Assert (Target_Count = Source_Count);
204 Container.Count := Source_Count;
205 end Adjust;
207 procedure Adjust (Control : in out Reference_Control_Type) is
208 begin
209 if Control.Container /= null then
210 declare
211 C : Tree renames Control.Container.all;
212 B : Natural renames C.Busy;
213 L : Natural renames C.Lock;
214 begin
215 B := B + 1;
216 L := L + 1;
217 end;
218 end if;
219 end Adjust;
221 -------------------
222 -- Ancestor_Find --
223 -------------------
225 function Ancestor_Find
226 (Position : Cursor;
227 Item : Element_Type) return Cursor
229 R, N : Tree_Node_Access;
231 begin
232 if Position = No_Element then
233 raise Constraint_Error with "Position cursor has no element";
234 end if;
236 -- Commented-out pending ARG ruling. ???
238 -- if Position.Container /= Container'Unrestricted_Access then
239 -- raise Program_Error with "Position cursor not in container";
240 -- end if;
242 -- AI-0136 says to raise PE if Position equals the root node. This does
243 -- not seem correct, as this value is just the limiting condition of the
244 -- search. For now we omit this check pending a ruling from the ARG.???
246 -- if Is_Root (Position) then
247 -- raise Program_Error with "Position cursor designates root";
248 -- end if;
250 R := Root_Node (Position.Container.all);
251 N := Position.Node;
252 while N /= R loop
253 if N.Element.all = Item then
254 return Cursor'(Position.Container, N);
255 end if;
257 N := N.Parent;
258 end loop;
260 return No_Element;
261 end Ancestor_Find;
263 ------------------
264 -- Append_Child --
265 ------------------
267 procedure Append_Child
268 (Container : in out Tree;
269 Parent : Cursor;
270 New_Item : Element_Type;
271 Count : Count_Type := 1)
273 First, Last : Tree_Node_Access;
274 Element : Element_Access;
276 begin
277 if Parent = No_Element then
278 raise Constraint_Error with "Parent cursor has no element";
279 end if;
281 if Parent.Container /= Container'Unrestricted_Access then
282 raise Program_Error with "Parent cursor not in container";
283 end if;
285 if Count = 0 then
286 return;
287 end if;
289 if Container.Busy > 0 then
290 raise Program_Error
291 with "attempt to tamper with cursors (tree is busy)";
292 end if;
294 declare
295 -- The element allocator may need an accessibility check in the case
296 -- the actual type is class-wide or has access discriminants (see
297 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
298 -- allocator in the loop below, because the one in this block would
299 -- have failed already.
301 pragma Unsuppress (Accessibility_Check);
303 begin
304 Element := new Element_Type'(New_Item);
305 end;
307 First := new Tree_Node_Type'(Parent => Parent.Node,
308 Element => Element,
309 others => <>);
311 Last := First;
313 for J in Count_Type'(2) .. Count loop
315 -- Reclaim other nodes if Storage_Error. ???
317 Element := new Element_Type'(New_Item);
318 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
319 Prev => Last,
320 Element => Element,
321 others => <>);
323 Last := Last.Next;
324 end loop;
326 Insert_Subtree_List
327 (First => First,
328 Last => Last,
329 Parent => Parent.Node,
330 Before => null); -- null means "insert at end of list"
332 -- In order for operation Node_Count to complete in O(1) time, we cache
333 -- the count value. Here we increment the total count by the number of
334 -- nodes we just inserted.
336 Container.Count := Container.Count + Count;
337 end Append_Child;
339 ------------
340 -- Assign --
341 ------------
343 procedure Assign (Target : in out Tree; Source : Tree) is
344 Source_Count : constant Count_Type := Source.Count;
345 Target_Count : Count_Type;
347 begin
348 if Target'Address = Source'Address then
349 return;
350 end if;
352 Target.Clear; -- checks busy bit
354 -- Copy_Children returns the number of nodes that it allocates, but it
355 -- does this by incrementing the count value passed in, so we must
356 -- initialize the count before calling Copy_Children.
358 Target_Count := 0;
360 -- Note that Copy_Children inserts the newly-allocated children into
361 -- their parent list only after the allocation of all the children has
362 -- succeeded. This preserves invariants even if the allocation fails.
364 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
365 pragma Assert (Target_Count = Source_Count);
367 Target.Count := Source_Count;
368 end Assign;
370 -----------------
371 -- Child_Count --
372 -----------------
374 function Child_Count (Parent : Cursor) return Count_Type is
375 begin
376 if Parent = No_Element then
377 return 0;
378 else
379 return Child_Count (Parent.Node.Children);
380 end if;
381 end Child_Count;
383 function Child_Count (Children : Children_Type) return Count_Type is
384 Result : Count_Type;
385 Node : Tree_Node_Access;
387 begin
388 Result := 0;
389 Node := Children.First;
390 while Node /= null loop
391 Result := Result + 1;
392 Node := Node.Next;
393 end loop;
395 return Result;
396 end Child_Count;
398 -----------------
399 -- Child_Depth --
400 -----------------
402 function Child_Depth (Parent, Child : Cursor) return Count_Type is
403 Result : Count_Type;
404 N : Tree_Node_Access;
406 begin
407 if Parent = No_Element then
408 raise Constraint_Error with "Parent cursor has no element";
409 end if;
411 if Child = No_Element then
412 raise Constraint_Error with "Child cursor has no element";
413 end if;
415 if Parent.Container /= Child.Container then
416 raise Program_Error with "Parent and Child in different containers";
417 end if;
419 Result := 0;
420 N := Child.Node;
421 while N /= Parent.Node loop
422 Result := Result + 1;
423 N := N.Parent;
425 if N = null then
426 raise Program_Error with "Parent is not ancestor of Child";
427 end if;
428 end loop;
430 return Result;
431 end Child_Depth;
433 -----------
434 -- Clear --
435 -----------
437 procedure Clear (Container : in out Tree) is
438 Container_Count : Count_Type;
439 Children_Count : Count_Type;
441 begin
442 if Container.Busy > 0 then
443 raise Program_Error
444 with "attempt to tamper with cursors (tree is busy)";
445 end if;
447 -- We first set the container count to 0, in order to preserve
448 -- invariants in case the deallocation fails. (This works because
449 -- Deallocate_Children immediately removes the children from their
450 -- parent, and then does the actual deallocation.)
452 Container_Count := Container.Count;
453 Container.Count := 0;
455 -- Deallocate_Children returns the number of nodes that it deallocates,
456 -- but it does this by incrementing the count value that is passed in,
457 -- so we must first initialize the count return value before calling it.
459 Children_Count := 0;
461 -- See comment above. Deallocate_Children immediately removes the
462 -- children list from their parent node (here, the root of the tree),
463 -- and only after that does it attempt the actual deallocation. So even
464 -- if the deallocation fails, the representation invariants
466 Deallocate_Children (Root_Node (Container), Children_Count);
467 pragma Assert (Children_Count = Container_Count);
468 end Clear;
470 ------------------------
471 -- Constant_Reference --
472 ------------------------
474 function Constant_Reference
475 (Container : aliased Tree;
476 Position : Cursor) return Constant_Reference_Type
478 begin
479 if Position.Container = null then
480 raise Constraint_Error with
481 "Position cursor has no element";
482 end if;
484 if Position.Container /= Container'Unrestricted_Access then
485 raise Program_Error with
486 "Position cursor designates wrong container";
487 end if;
489 if Position.Node = Root_Node (Container) then
490 raise Program_Error with "Position cursor designates root";
491 end if;
493 if Position.Node.Element = null then
494 raise Program_Error with "Node has no element";
495 end if;
497 -- Implement Vet for multiway tree???
498 -- pragma Assert (Vet (Position),
499 -- "Position cursor in Constant_Reference is bad");
501 declare
502 C : Tree renames Position.Container.all;
503 B : Natural renames C.Busy;
504 L : Natural renames C.Lock;
505 begin
506 return R : constant Constant_Reference_Type :=
507 (Element => Position.Node.Element.all'Access,
508 Control => (Controlled with Container'Unrestricted_Access))
510 B := B + 1;
511 L := L + 1;
512 end return;
513 end;
514 end Constant_Reference;
516 --------------
517 -- Contains --
518 --------------
520 function Contains
521 (Container : Tree;
522 Item : Element_Type) return Boolean
524 begin
525 return Find (Container, Item) /= No_Element;
526 end Contains;
528 ----------
529 -- Copy --
530 ----------
532 function Copy (Source : Tree) return Tree is
533 begin
534 return Target : Tree do
535 Copy_Children
536 (Source => Source.Root.Children,
537 Parent => Root_Node (Target),
538 Count => Target.Count);
540 pragma Assert (Target.Count = Source.Count);
541 end return;
542 end Copy;
544 -------------------
545 -- Copy_Children --
546 -------------------
548 procedure Copy_Children
549 (Source : Children_Type;
550 Parent : Tree_Node_Access;
551 Count : in out Count_Type)
553 pragma Assert (Parent /= null);
554 pragma Assert (Parent.Children.First = null);
555 pragma Assert (Parent.Children.Last = null);
557 CC : Children_Type;
558 C : Tree_Node_Access;
560 begin
561 -- We special-case the first allocation, in order to establish the
562 -- representation invariants for type Children_Type.
564 C := Source.First;
566 if C = null then
567 return;
568 end if;
570 Copy_Subtree
571 (Source => C,
572 Parent => Parent,
573 Target => CC.First,
574 Count => Count);
576 CC.Last := CC.First;
578 -- The representation invariants for the Children_Type list have been
579 -- established, so we can now copy the remaining children of Source.
581 C := C.Next;
582 while C /= null loop
583 Copy_Subtree
584 (Source => C,
585 Parent => Parent,
586 Target => CC.Last.Next,
587 Count => Count);
589 CC.Last.Next.Prev := CC.Last;
590 CC.Last := CC.Last.Next;
592 C := C.Next;
593 end loop;
595 -- We add the newly-allocated children to their parent list only after
596 -- the allocation has succeeded, in order to preserve invariants of the
597 -- parent.
599 Parent.Children := CC;
600 end Copy_Children;
602 ------------------
603 -- Copy_Subtree --
604 ------------------
606 procedure Copy_Subtree
607 (Target : in out Tree;
608 Parent : Cursor;
609 Before : Cursor;
610 Source : Cursor)
612 Target_Subtree : Tree_Node_Access;
613 Target_Count : Count_Type;
615 begin
616 if Parent = No_Element then
617 raise Constraint_Error with "Parent cursor has no element";
618 end if;
620 if Parent.Container /= Target'Unrestricted_Access then
621 raise Program_Error with "Parent cursor not in container";
622 end if;
624 if Before /= No_Element then
625 if Before.Container /= Target'Unrestricted_Access then
626 raise Program_Error with "Before cursor not in container";
627 end if;
629 if Before.Node.Parent /= Parent.Node then
630 raise Constraint_Error with "Before cursor not child of Parent";
631 end if;
632 end if;
634 if Source = No_Element then
635 return;
636 end if;
638 if Is_Root (Source) then
639 raise Constraint_Error with "Source cursor designates root";
640 end if;
642 -- Copy_Subtree returns a count of the number of nodes that it
643 -- allocates, but it works by incrementing the value that is passed in.
644 -- We must therefore initialize the count value before calling
645 -- Copy_Subtree.
647 Target_Count := 0;
649 Copy_Subtree
650 (Source => Source.Node,
651 Parent => Parent.Node,
652 Target => Target_Subtree,
653 Count => Target_Count);
655 pragma Assert (Target_Subtree /= null);
656 pragma Assert (Target_Subtree.Parent = Parent.Node);
657 pragma Assert (Target_Count >= 1);
659 Insert_Subtree_Node
660 (Subtree => Target_Subtree,
661 Parent => Parent.Node,
662 Before => Before.Node);
664 -- In order for operation Node_Count to complete in O(1) time, we cache
665 -- the count value. Here we increment the total count by the number of
666 -- nodes we just inserted.
668 Target.Count := Target.Count + Target_Count;
669 end Copy_Subtree;
671 procedure Copy_Subtree
672 (Source : Tree_Node_Access;
673 Parent : Tree_Node_Access;
674 Target : out Tree_Node_Access;
675 Count : in out Count_Type)
677 E : constant Element_Access := new Element_Type'(Source.Element.all);
679 begin
680 Target := new Tree_Node_Type'(Element => E,
681 Parent => Parent,
682 others => <>);
684 Count := Count + 1;
686 Copy_Children
687 (Source => Source.Children,
688 Parent => Target,
689 Count => Count);
690 end Copy_Subtree;
692 -------------------------
693 -- Deallocate_Children --
694 -------------------------
696 procedure Deallocate_Children
697 (Subtree : Tree_Node_Access;
698 Count : in out Count_Type)
700 pragma Assert (Subtree /= null);
702 CC : Children_Type := Subtree.Children;
703 C : Tree_Node_Access;
705 begin
706 -- We immediately remove the children from their parent, in order to
707 -- preserve invariants in case the deallocation fails.
709 Subtree.Children := Children_Type'(others => null);
711 while CC.First /= null loop
712 C := CC.First;
713 CC.First := C.Next;
715 Deallocate_Subtree (C, Count);
716 end loop;
717 end Deallocate_Children;
719 ---------------------
720 -- Deallocate_Node --
721 ---------------------
723 procedure Deallocate_Node (X : in out Tree_Node_Access) is
724 procedure Free_Node is
725 new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access);
727 -- Start of processing for Deallocate_Node
729 begin
730 if X /= null then
731 Free_Element (X.Element);
732 Free_Node (X);
733 end if;
734 end Deallocate_Node;
736 ------------------------
737 -- Deallocate_Subtree --
738 ------------------------
740 procedure Deallocate_Subtree
741 (Subtree : in out Tree_Node_Access;
742 Count : in out Count_Type)
744 begin
745 Deallocate_Children (Subtree, Count);
746 Deallocate_Node (Subtree);
747 Count := Count + 1;
748 end Deallocate_Subtree;
750 ---------------------
751 -- Delete_Children --
752 ---------------------
754 procedure Delete_Children
755 (Container : in out Tree;
756 Parent : Cursor)
758 Count : Count_Type;
760 begin
761 if Parent = No_Element then
762 raise Constraint_Error with "Parent cursor has no element";
763 end if;
765 if Parent.Container /= Container'Unrestricted_Access then
766 raise Program_Error with "Parent cursor not in container";
767 end if;
769 if Container.Busy > 0 then
770 raise Program_Error
771 with "attempt to tamper with cursors (tree is busy)";
772 end if;
774 -- Deallocate_Children returns a count of the number of nodes
775 -- that it deallocates, but it works by incrementing the
776 -- value that is passed in. We must therefore initialize
777 -- the count value before calling Deallocate_Children.
779 Count := 0;
781 Deallocate_Children (Parent.Node, Count);
782 pragma Assert (Count <= Container.Count);
784 Container.Count := Container.Count - Count;
785 end Delete_Children;
787 -----------------
788 -- Delete_Leaf --
789 -----------------
791 procedure Delete_Leaf
792 (Container : in out Tree;
793 Position : in out Cursor)
795 X : Tree_Node_Access;
797 begin
798 if Position = No_Element then
799 raise Constraint_Error with "Position cursor has no element";
800 end if;
802 if Position.Container /= Container'Unrestricted_Access then
803 raise Program_Error with "Position cursor not in container";
804 end if;
806 if Is_Root (Position) then
807 raise Program_Error with "Position cursor designates root";
808 end if;
810 if not Is_Leaf (Position) then
811 raise Constraint_Error with "Position cursor does not designate leaf";
812 end if;
814 if Container.Busy > 0 then
815 raise Program_Error
816 with "attempt to tamper with cursors (tree is busy)";
817 end if;
819 X := Position.Node;
820 Position := No_Element;
822 -- Restore represention invariants before attempting the actual
823 -- deallocation.
825 Remove_Subtree (X);
826 Container.Count := Container.Count - 1;
828 -- It is now safe to attempt the deallocation. This leaf node has been
829 -- disassociated from the tree, so even if the deallocation fails,
830 -- representation invariants will remain satisfied.
832 Deallocate_Node (X);
833 end Delete_Leaf;
835 --------------------
836 -- Delete_Subtree --
837 --------------------
839 procedure Delete_Subtree
840 (Container : in out Tree;
841 Position : in out Cursor)
843 X : Tree_Node_Access;
844 Count : Count_Type;
846 begin
847 if Position = No_Element then
848 raise Constraint_Error with "Position cursor has no element";
849 end if;
851 if Position.Container /= Container'Unrestricted_Access then
852 raise Program_Error with "Position cursor not in container";
853 end if;
855 if Is_Root (Position) then
856 raise Program_Error with "Position cursor designates root";
857 end if;
859 if Container.Busy > 0 then
860 raise Program_Error
861 with "attempt to tamper with cursors (tree is busy)";
862 end if;
864 X := Position.Node;
865 Position := No_Element;
867 -- Here is one case where a deallocation failure can result in the
868 -- violation of a representation invariant. We disassociate the subtree
869 -- from the tree now, but we only decrement the total node count after
870 -- we attempt the deallocation. However, if the deallocation fails, the
871 -- total node count will not get decremented.
873 -- One way around this dilemma is to count the nodes in the subtree
874 -- before attempt to delete the subtree, but that is an O(n) operation,
875 -- so it does not seem worth it.
877 -- Perhaps this is much ado about nothing, since the only way
878 -- deallocation can fail is if Controlled Finalization fails: this
879 -- propagates Program_Error so all bets are off anyway. ???
881 Remove_Subtree (X);
883 -- Deallocate_Subtree returns a count of the number of nodes that it
884 -- deallocates, but it works by incrementing the value that is passed
885 -- in. We must therefore initialize the count value before calling
886 -- Deallocate_Subtree.
888 Count := 0;
890 Deallocate_Subtree (X, Count);
891 pragma Assert (Count <= Container.Count);
893 -- See comments above. We would prefer to do this sooner, but there's no
894 -- way to satisfy that goal without an potentially severe execution
895 -- penalty.
897 Container.Count := Container.Count - Count;
898 end Delete_Subtree;
900 -----------
901 -- Depth --
902 -----------
904 function Depth (Position : Cursor) return Count_Type is
905 Result : Count_Type;
906 N : Tree_Node_Access;
908 begin
909 Result := 0;
910 N := Position.Node;
911 while N /= null loop
912 N := N.Parent;
913 Result := Result + 1;
914 end loop;
916 return Result;
917 end Depth;
919 -------------
920 -- Element --
921 -------------
923 function Element (Position : Cursor) return Element_Type is
924 begin
925 if Position.Container = null then
926 raise Constraint_Error with "Position cursor has no element";
927 end if;
929 if Position.Node = Root_Node (Position.Container.all) then
930 raise Program_Error with "Position cursor designates root";
931 end if;
933 return Position.Node.Element.all;
934 end Element;
936 --------------------
937 -- Equal_Children --
938 --------------------
940 function Equal_Children
941 (Left_Subtree : Tree_Node_Access;
942 Right_Subtree : Tree_Node_Access) return Boolean
944 Left_Children : Children_Type renames Left_Subtree.Children;
945 Right_Children : Children_Type renames Right_Subtree.Children;
947 L, R : Tree_Node_Access;
949 begin
950 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
951 return False;
952 end if;
954 L := Left_Children.First;
955 R := Right_Children.First;
956 while L /= null loop
957 if not Equal_Subtree (L, R) then
958 return False;
959 end if;
961 L := L.Next;
962 R := R.Next;
963 end loop;
965 return True;
966 end Equal_Children;
968 -------------------
969 -- Equal_Subtree --
970 -------------------
972 function Equal_Subtree
973 (Left_Position : Cursor;
974 Right_Position : Cursor) return Boolean
976 begin
977 if Left_Position = No_Element then
978 raise Constraint_Error with "Left cursor has no element";
979 end if;
981 if Right_Position = No_Element then
982 raise Constraint_Error with "Right cursor has no element";
983 end if;
985 if Left_Position = Right_Position then
986 return True;
987 end if;
989 if Is_Root (Left_Position) then
990 if not Is_Root (Right_Position) then
991 return False;
992 end if;
994 return Equal_Children (Left_Position.Node, Right_Position.Node);
995 end if;
997 if Is_Root (Right_Position) then
998 return False;
999 end if;
1001 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
1002 end Equal_Subtree;
1004 function Equal_Subtree
1005 (Left_Subtree : Tree_Node_Access;
1006 Right_Subtree : Tree_Node_Access) return Boolean
1008 begin
1009 if Left_Subtree.Element.all /= Right_Subtree.Element.all then
1010 return False;
1011 end if;
1013 return Equal_Children (Left_Subtree, Right_Subtree);
1014 end Equal_Subtree;
1016 --------------
1017 -- Finalize --
1018 --------------
1020 procedure Finalize (Object : in out Root_Iterator) is
1021 B : Natural renames Object.Container.Busy;
1022 begin
1023 B := B - 1;
1024 end Finalize;
1026 procedure Finalize (Control : in out Reference_Control_Type) is
1027 begin
1028 if Control.Container /= null then
1029 declare
1030 C : Tree renames Control.Container.all;
1031 B : Natural renames C.Busy;
1032 L : Natural renames C.Lock;
1033 begin
1034 B := B - 1;
1035 L := L - 1;
1036 end;
1038 Control.Container := null;
1039 end if;
1040 end Finalize;
1042 ----------
1043 -- Find --
1044 ----------
1046 function Find
1047 (Container : Tree;
1048 Item : Element_Type) return Cursor
1050 N : constant Tree_Node_Access :=
1051 Find_In_Children (Root_Node (Container), Item);
1053 begin
1054 if N = null then
1055 return No_Element;
1056 end if;
1058 return Cursor'(Container'Unrestricted_Access, N);
1059 end Find;
1061 -----------
1062 -- First --
1063 -----------
1065 overriding function First (Object : Subtree_Iterator) return Cursor is
1066 begin
1067 if Object.Subtree = Root_Node (Object.Container.all) then
1068 return First_Child (Root (Object.Container.all));
1069 else
1070 return Cursor'(Object.Container, Object.Subtree);
1071 end if;
1072 end First;
1074 overriding function First (Object : Child_Iterator) return Cursor is
1075 begin
1076 return First_Child (Cursor'(Object.Container, Object.Subtree));
1077 end First;
1079 -----------------
1080 -- First_Child --
1081 -----------------
1083 function First_Child (Parent : Cursor) return Cursor is
1084 Node : Tree_Node_Access;
1086 begin
1087 if Parent = No_Element then
1088 raise Constraint_Error with "Parent cursor has no element";
1089 end if;
1091 Node := Parent.Node.Children.First;
1093 if Node = null then
1094 return No_Element;
1095 end if;
1097 return Cursor'(Parent.Container, Node);
1098 end First_Child;
1100 -------------------------
1101 -- First_Child_Element --
1102 -------------------------
1104 function First_Child_Element (Parent : Cursor) return Element_Type is
1105 begin
1106 return Element (First_Child (Parent));
1107 end First_Child_Element;
1109 ----------------------
1110 -- Find_In_Children --
1111 ----------------------
1113 function Find_In_Children
1114 (Subtree : Tree_Node_Access;
1115 Item : Element_Type) return Tree_Node_Access
1117 N, Result : Tree_Node_Access;
1119 begin
1120 N := Subtree.Children.First;
1121 while N /= null loop
1122 Result := Find_In_Subtree (N, Item);
1124 if Result /= null then
1125 return Result;
1126 end if;
1128 N := N.Next;
1129 end loop;
1131 return null;
1132 end Find_In_Children;
1134 ---------------------
1135 -- Find_In_Subtree --
1136 ---------------------
1138 function Find_In_Subtree
1139 (Position : Cursor;
1140 Item : Element_Type) return Cursor
1142 Result : Tree_Node_Access;
1144 begin
1145 if Position = No_Element then
1146 raise Constraint_Error with "Position cursor has no element";
1147 end if;
1149 -- Commented-out pending ruling from ARG. ???
1151 -- if Position.Container /= Container'Unrestricted_Access then
1152 -- raise Program_Error with "Position cursor not in container";
1153 -- end if;
1155 if Is_Root (Position) then
1156 Result := Find_In_Children (Position.Node, Item);
1158 else
1159 Result := Find_In_Subtree (Position.Node, Item);
1160 end if;
1162 if Result = null then
1163 return No_Element;
1164 end if;
1166 return Cursor'(Position.Container, Result);
1167 end Find_In_Subtree;
1169 function Find_In_Subtree
1170 (Subtree : Tree_Node_Access;
1171 Item : Element_Type) return Tree_Node_Access
1173 begin
1174 if Subtree.Element.all = Item then
1175 return Subtree;
1176 end if;
1178 return Find_In_Children (Subtree, Item);
1179 end Find_In_Subtree;
1181 -----------------
1182 -- Has_Element --
1183 -----------------
1185 function Has_Element (Position : Cursor) return Boolean is
1186 begin
1187 if Position = No_Element then
1188 return False;
1189 end if;
1191 return Position.Node.Parent /= null;
1192 end Has_Element;
1194 ------------------
1195 -- Insert_Child --
1196 ------------------
1198 procedure Insert_Child
1199 (Container : in out Tree;
1200 Parent : Cursor;
1201 Before : Cursor;
1202 New_Item : Element_Type;
1203 Count : Count_Type := 1)
1205 Position : Cursor;
1206 pragma Unreferenced (Position);
1208 begin
1209 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1210 end Insert_Child;
1212 procedure Insert_Child
1213 (Container : in out Tree;
1214 Parent : Cursor;
1215 Before : Cursor;
1216 New_Item : Element_Type;
1217 Position : out Cursor;
1218 Count : Count_Type := 1)
1220 Last : Tree_Node_Access;
1221 Element : Element_Access;
1223 begin
1224 if Parent = No_Element then
1225 raise Constraint_Error with "Parent cursor has no element";
1226 end if;
1228 if Parent.Container /= Container'Unrestricted_Access then
1229 raise Program_Error with "Parent cursor not in container";
1230 end if;
1232 if Before /= No_Element then
1233 if Before.Container /= Container'Unrestricted_Access then
1234 raise Program_Error with "Before cursor not in container";
1235 end if;
1237 if Before.Node.Parent /= Parent.Node then
1238 raise Constraint_Error with "Parent cursor not parent of Before";
1239 end if;
1240 end if;
1242 if Count = 0 then
1243 Position := No_Element; -- Need ruling from ARG ???
1244 return;
1245 end if;
1247 if Container.Busy > 0 then
1248 raise Program_Error
1249 with "attempt to tamper with cursors (tree is busy)";
1250 end if;
1252 Position.Container := Parent.Container;
1254 declare
1255 -- The element allocator may need an accessibility check in the case
1256 -- the actual type is class-wide or has access discriminants (see
1257 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
1258 -- allocator in the loop below, because the one in this block would
1259 -- have failed already.
1261 pragma Unsuppress (Accessibility_Check);
1263 begin
1264 Element := new Element_Type'(New_Item);
1265 end;
1267 Position.Node := new Tree_Node_Type'(Parent => Parent.Node,
1268 Element => Element,
1269 others => <>);
1271 Last := Position.Node;
1273 for J in Count_Type'(2) .. Count loop
1274 -- Reclaim other nodes if Storage_Error. ???
1276 Element := new Element_Type'(New_Item);
1277 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1278 Prev => Last,
1279 Element => Element,
1280 others => <>);
1282 Last := Last.Next;
1283 end loop;
1285 Insert_Subtree_List
1286 (First => Position.Node,
1287 Last => Last,
1288 Parent => Parent.Node,
1289 Before => Before.Node);
1291 -- In order for operation Node_Count to complete in O(1) time, we cache
1292 -- the count value. Here we increment the total count by the number of
1293 -- nodes we just inserted.
1295 Container.Count := Container.Count + Count;
1296 end Insert_Child;
1298 -------------------------
1299 -- Insert_Subtree_List --
1300 -------------------------
1302 procedure Insert_Subtree_List
1303 (First : Tree_Node_Access;
1304 Last : Tree_Node_Access;
1305 Parent : Tree_Node_Access;
1306 Before : Tree_Node_Access)
1308 pragma Assert (Parent /= null);
1309 C : Children_Type renames Parent.Children;
1311 begin
1312 -- This is a simple utility operation to insert a list of nodes (from
1313 -- First..Last) as children of Parent. The Before node specifies where
1314 -- the new children should be inserted relative to the existing
1315 -- children.
1317 if First = null then
1318 pragma Assert (Last = null);
1319 return;
1320 end if;
1322 pragma Assert (Last /= null);
1323 pragma Assert (Before = null or else Before.Parent = Parent);
1325 if C.First = null then
1326 C.First := First;
1327 C.First.Prev := null;
1328 C.Last := Last;
1329 C.Last.Next := null;
1331 elsif Before = null then -- means "insert after existing nodes"
1332 C.Last.Next := First;
1333 First.Prev := C.Last;
1334 C.Last := Last;
1335 C.Last.Next := null;
1337 elsif Before = C.First then
1338 Last.Next := C.First;
1339 C.First.Prev := Last;
1340 C.First := First;
1341 C.First.Prev := null;
1343 else
1344 Before.Prev.Next := First;
1345 First.Prev := Before.Prev;
1346 Last.Next := Before;
1347 Before.Prev := Last;
1348 end if;
1349 end Insert_Subtree_List;
1351 -------------------------
1352 -- Insert_Subtree_Node --
1353 -------------------------
1355 procedure Insert_Subtree_Node
1356 (Subtree : Tree_Node_Access;
1357 Parent : Tree_Node_Access;
1358 Before : Tree_Node_Access)
1360 begin
1361 -- This is a simple wrapper operation to insert a single child into the
1362 -- Parent's children list.
1364 Insert_Subtree_List
1365 (First => Subtree,
1366 Last => Subtree,
1367 Parent => Parent,
1368 Before => Before);
1369 end Insert_Subtree_Node;
1371 --------------
1372 -- Is_Empty --
1373 --------------
1375 function Is_Empty (Container : Tree) return Boolean is
1376 begin
1377 return Container.Root.Children.First = null;
1378 end Is_Empty;
1380 -------------
1381 -- Is_Leaf --
1382 -------------
1384 function Is_Leaf (Position : Cursor) return Boolean is
1385 begin
1386 if Position = No_Element then
1387 return False;
1388 end if;
1390 return Position.Node.Children.First = null;
1391 end Is_Leaf;
1393 ------------------
1394 -- Is_Reachable --
1395 ------------------
1397 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1398 pragma Assert (From /= null);
1399 pragma Assert (To /= null);
1401 N : Tree_Node_Access;
1403 begin
1404 N := From;
1405 while N /= null loop
1406 if N = To then
1407 return True;
1408 end if;
1410 N := N.Parent;
1411 end loop;
1413 return False;
1414 end Is_Reachable;
1416 -------------
1417 -- Is_Root --
1418 -------------
1420 function Is_Root (Position : Cursor) return Boolean is
1421 begin
1422 if Position.Container = null then
1423 return False;
1424 end if;
1426 return Position = Root (Position.Container.all);
1427 end Is_Root;
1429 -------------
1430 -- Iterate --
1431 -------------
1433 procedure Iterate
1434 (Container : Tree;
1435 Process : not null access procedure (Position : Cursor))
1437 B : Natural renames Container'Unrestricted_Access.all.Busy;
1439 begin
1440 B := B + 1;
1442 Iterate_Children
1443 (Container => Container'Unrestricted_Access,
1444 Subtree => Root_Node (Container),
1445 Process => Process);
1447 B := B - 1;
1449 exception
1450 when others =>
1451 B := B - 1;
1452 raise;
1453 end Iterate;
1455 function Iterate (Container : Tree)
1456 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1458 begin
1459 return Iterate_Subtree (Root (Container));
1460 end Iterate;
1462 ----------------------
1463 -- Iterate_Children --
1464 ----------------------
1466 procedure Iterate_Children
1467 (Parent : Cursor;
1468 Process : not null access procedure (Position : Cursor))
1470 begin
1471 if Parent = No_Element then
1472 raise Constraint_Error with "Parent cursor has no element";
1473 end if;
1475 declare
1476 B : Natural renames Parent.Container.Busy;
1477 C : Tree_Node_Access;
1479 begin
1480 B := B + 1;
1482 C := Parent.Node.Children.First;
1483 while C /= null loop
1484 Process (Position => Cursor'(Parent.Container, Node => C));
1485 C := C.Next;
1486 end loop;
1488 B := B - 1;
1490 exception
1491 when others =>
1492 B := B - 1;
1493 raise;
1494 end;
1495 end Iterate_Children;
1497 procedure Iterate_Children
1498 (Container : Tree_Access;
1499 Subtree : Tree_Node_Access;
1500 Process : not null access procedure (Position : Cursor))
1502 Node : Tree_Node_Access;
1504 begin
1505 -- This is a helper function to recursively iterate over all the nodes
1506 -- in a subtree, in depth-first fashion. This particular helper just
1507 -- visits the children of this subtree, not the root of the subtree node
1508 -- itself. This is useful when starting from the ultimate root of the
1509 -- entire tree (see Iterate), as that root does not have an element.
1511 Node := Subtree.Children.First;
1512 while Node /= null loop
1513 Iterate_Subtree (Container, Node, Process);
1514 Node := Node.Next;
1515 end loop;
1516 end Iterate_Children;
1518 function Iterate_Children
1519 (Container : Tree;
1520 Parent : Cursor)
1521 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1523 C : constant Tree_Access := Container'Unrestricted_Access;
1524 B : Natural renames C.Busy;
1526 begin
1527 if Parent = No_Element then
1528 raise Constraint_Error with "Parent cursor has no element";
1529 end if;
1531 if Parent.Container /= C then
1532 raise Program_Error with "Parent cursor not in container";
1533 end if;
1535 return It : constant Child_Iterator :=
1536 Child_Iterator'(Limited_Controlled with
1537 Container => C,
1538 Subtree => Parent.Node)
1540 B := B + 1;
1541 end return;
1542 end Iterate_Children;
1544 ---------------------
1545 -- Iterate_Subtree --
1546 ---------------------
1548 function Iterate_Subtree
1549 (Position : Cursor)
1550 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1552 begin
1553 if Position = No_Element then
1554 raise Constraint_Error with "Position cursor has no element";
1555 end if;
1557 -- Implement Vet for multiway trees???
1558 -- pragma Assert (Vet (Position), "bad subtree cursor");
1560 declare
1561 B : Natural renames Position.Container.Busy;
1562 begin
1563 return It : constant Subtree_Iterator :=
1564 (Limited_Controlled with
1565 Container => Position.Container,
1566 Subtree => Position.Node)
1568 B := B + 1;
1569 end return;
1570 end;
1571 end Iterate_Subtree;
1573 procedure Iterate_Subtree
1574 (Position : Cursor;
1575 Process : not null access procedure (Position : Cursor))
1577 begin
1578 if Position = No_Element then
1579 raise Constraint_Error with "Position cursor has no element";
1580 end if;
1582 declare
1583 B : Natural renames Position.Container.Busy;
1585 begin
1586 B := B + 1;
1588 if Is_Root (Position) then
1589 Iterate_Children (Position.Container, Position.Node, Process);
1590 else
1591 Iterate_Subtree (Position.Container, Position.Node, Process);
1592 end if;
1594 B := B - 1;
1596 exception
1597 when others =>
1598 B := B - 1;
1599 raise;
1600 end;
1601 end Iterate_Subtree;
1603 procedure Iterate_Subtree
1604 (Container : Tree_Access;
1605 Subtree : Tree_Node_Access;
1606 Process : not null access procedure (Position : Cursor))
1608 begin
1609 -- This is a helper function to recursively iterate over all the nodes
1610 -- in a subtree, in depth-first fashion. It first visits the root of the
1611 -- subtree, then visits its children.
1613 Process (Cursor'(Container, Subtree));
1614 Iterate_Children (Container, Subtree, Process);
1615 end Iterate_Subtree;
1617 ----------
1618 -- Last --
1619 ----------
1621 overriding function Last (Object : Child_Iterator) return Cursor is
1622 begin
1623 return Last_Child (Cursor'(Object.Container, Object.Subtree));
1624 end Last;
1626 ----------------
1627 -- Last_Child --
1628 ----------------
1630 function Last_Child (Parent : Cursor) return Cursor is
1631 Node : Tree_Node_Access;
1633 begin
1634 if Parent = No_Element then
1635 raise Constraint_Error with "Parent cursor has no element";
1636 end if;
1638 Node := Parent.Node.Children.Last;
1640 if Node = null then
1641 return No_Element;
1642 end if;
1644 return (Parent.Container, Node);
1645 end Last_Child;
1647 ------------------------
1648 -- Last_Child_Element --
1649 ------------------------
1651 function Last_Child_Element (Parent : Cursor) return Element_Type is
1652 begin
1653 return Element (Last_Child (Parent));
1654 end Last_Child_Element;
1656 ----------
1657 -- Move --
1658 ----------
1660 procedure Move (Target : in out Tree; Source : in out Tree) is
1661 Node : Tree_Node_Access;
1663 begin
1664 if Target'Address = Source'Address then
1665 return;
1666 end if;
1668 if Source.Busy > 0 then
1669 raise Program_Error
1670 with "attempt to tamper with cursors of Source (tree is busy)";
1671 end if;
1673 Target.Clear; -- checks busy bit
1675 Target.Root.Children := Source.Root.Children;
1676 Source.Root.Children := Children_Type'(others => null);
1678 Node := Target.Root.Children.First;
1679 while Node /= null loop
1680 Node.Parent := Root_Node (Target);
1681 Node := Node.Next;
1682 end loop;
1684 Target.Count := Source.Count;
1685 Source.Count := 0;
1686 end Move;
1688 ----------
1689 -- Next --
1690 ----------
1692 function Next
1693 (Object : Subtree_Iterator;
1694 Position : Cursor) return Cursor
1696 Node : Tree_Node_Access;
1698 begin
1699 if Position.Container = null then
1700 return No_Element;
1701 end if;
1703 if Position.Container /= Object.Container then
1704 raise Program_Error with
1705 "Position cursor of Next designates wrong tree";
1706 end if;
1708 Node := Position.Node;
1710 if Node.Children.First /= null then
1711 return Cursor'(Object.Container, Node.Children.First);
1712 end if;
1714 while Node /= Object.Subtree loop
1715 if Node.Next /= null then
1716 return Cursor'(Object.Container, Node.Next);
1717 end if;
1719 Node := Node.Parent;
1720 end loop;
1722 return No_Element;
1723 end Next;
1725 function Next
1726 (Object : Child_Iterator;
1727 Position : Cursor) return Cursor
1729 begin
1730 if Position.Container = null then
1731 return No_Element;
1732 end if;
1734 if Position.Container /= Object.Container then
1735 raise Program_Error with
1736 "Position cursor of Next designates wrong tree";
1737 end if;
1739 return Next_Sibling (Position);
1740 end Next;
1742 ------------------
1743 -- Next_Sibling --
1744 ------------------
1746 function Next_Sibling (Position : Cursor) return Cursor is
1747 begin
1748 if Position = No_Element then
1749 return No_Element;
1750 end if;
1752 if Position.Node.Next = null then
1753 return No_Element;
1754 end if;
1756 return Cursor'(Position.Container, Position.Node.Next);
1757 end Next_Sibling;
1759 procedure Next_Sibling (Position : in out Cursor) is
1760 begin
1761 Position := Next_Sibling (Position);
1762 end Next_Sibling;
1764 ----------------
1765 -- Node_Count --
1766 ----------------
1768 function Node_Count (Container : Tree) return Count_Type is
1769 begin
1770 -- Container.Count is the number of nodes we have actually allocated. We
1771 -- cache the value specifically so this Node_Count operation can execute
1772 -- in O(1) time, which makes it behave similarly to how the Length
1773 -- selector function behaves for other containers.
1775 -- The cached node count value only describes the nodes we have
1776 -- allocated; the root node itself is not included in that count. The
1777 -- Node_Count operation returns a value that includes the root node
1778 -- (because the RM says so), so we must add 1 to our cached value.
1780 return 1 + Container.Count;
1781 end Node_Count;
1783 ------------
1784 -- Parent --
1785 ------------
1787 function Parent (Position : Cursor) return Cursor is
1788 begin
1789 if Position = No_Element then
1790 return No_Element;
1791 end if;
1793 if Position.Node.Parent = null then
1794 return No_Element;
1795 end if;
1797 return Cursor'(Position.Container, Position.Node.Parent);
1798 end Parent;
1800 -------------------
1801 -- Prepent_Child --
1802 -------------------
1804 procedure Prepend_Child
1805 (Container : in out Tree;
1806 Parent : Cursor;
1807 New_Item : Element_Type;
1808 Count : Count_Type := 1)
1810 First, Last : Tree_Node_Access;
1811 Element : Element_Access;
1813 begin
1814 if Parent = No_Element then
1815 raise Constraint_Error with "Parent cursor has no element";
1816 end if;
1818 if Parent.Container /= Container'Unrestricted_Access then
1819 raise Program_Error with "Parent cursor not in container";
1820 end if;
1822 if Count = 0 then
1823 return;
1824 end if;
1826 if Container.Busy > 0 then
1827 raise Program_Error
1828 with "attempt to tamper with cursors (tree is busy)";
1829 end if;
1831 declare
1832 -- The element allocator may need an accessibility check in the case
1833 -- the actual type is class-wide or has access discriminants (see
1834 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
1835 -- allocator in the loop below, because the one in this block would
1836 -- have failed already.
1838 pragma Unsuppress (Accessibility_Check);
1840 begin
1841 Element := new Element_Type'(New_Item);
1842 end;
1844 First := new Tree_Node_Type'(Parent => Parent.Node,
1845 Element => Element,
1846 others => <>);
1848 Last := First;
1850 for J in Count_Type'(2) .. Count loop
1852 -- Reclaim other nodes if Storage_Error. ???
1854 Element := new Element_Type'(New_Item);
1855 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1856 Prev => Last,
1857 Element => Element,
1858 others => <>);
1860 Last := Last.Next;
1861 end loop;
1863 Insert_Subtree_List
1864 (First => First,
1865 Last => Last,
1866 Parent => Parent.Node,
1867 Before => Parent.Node.Children.First);
1869 -- In order for operation Node_Count to complete in O(1) time, we cache
1870 -- the count value. Here we increment the total count by the number of
1871 -- nodes we just inserted.
1873 Container.Count := Container.Count + Count;
1874 end Prepend_Child;
1876 --------------
1877 -- Previous --
1878 --------------
1880 overriding function Previous
1881 (Object : Child_Iterator;
1882 Position : Cursor) return Cursor
1884 begin
1885 if Position.Container = null then
1886 return No_Element;
1887 end if;
1889 if Position.Container /= Object.Container then
1890 raise Program_Error with
1891 "Position cursor of Previous designates wrong tree";
1892 end if;
1894 return Previous_Sibling (Position);
1895 end Previous;
1897 ----------------------
1898 -- Previous_Sibling --
1899 ----------------------
1901 function Previous_Sibling (Position : Cursor) return Cursor is
1902 begin
1903 if Position = No_Element then
1904 return No_Element;
1905 end if;
1907 if Position.Node.Prev = null then
1908 return No_Element;
1909 end if;
1911 return Cursor'(Position.Container, Position.Node.Prev);
1912 end Previous_Sibling;
1914 procedure Previous_Sibling (Position : in out Cursor) is
1915 begin
1916 Position := Previous_Sibling (Position);
1917 end Previous_Sibling;
1919 -------------------
1920 -- Query_Element --
1921 -------------------
1923 procedure Query_Element
1924 (Position : Cursor;
1925 Process : not null access procedure (Element : Element_Type))
1927 begin
1928 if Position = No_Element then
1929 raise Constraint_Error with "Position cursor has no element";
1930 end if;
1932 if Is_Root (Position) then
1933 raise Program_Error with "Position cursor designates root";
1934 end if;
1936 declare
1937 T : Tree renames Position.Container.all'Unrestricted_Access.all;
1938 B : Natural renames T.Busy;
1939 L : Natural renames T.Lock;
1941 begin
1942 B := B + 1;
1943 L := L + 1;
1945 Process (Position.Node.Element.all);
1947 L := L - 1;
1948 B := B - 1;
1950 exception
1951 when others =>
1952 L := L - 1;
1953 B := B - 1;
1954 raise;
1955 end;
1956 end Query_Element;
1958 ----------
1959 -- Read --
1960 ----------
1962 procedure Read
1963 (Stream : not null access Root_Stream_Type'Class;
1964 Container : out Tree)
1966 procedure Read_Children (Subtree : Tree_Node_Access);
1968 function Read_Subtree
1969 (Parent : Tree_Node_Access) return Tree_Node_Access;
1971 Total_Count : Count_Type'Base;
1972 -- Value read from the stream that says how many elements follow
1974 Read_Count : Count_Type'Base;
1975 -- Actual number of elements read from the stream
1977 -------------------
1978 -- Read_Children --
1979 -------------------
1981 procedure Read_Children (Subtree : Tree_Node_Access) is
1982 pragma Assert (Subtree /= null);
1983 pragma Assert (Subtree.Children.First = null);
1984 pragma Assert (Subtree.Children.Last = null);
1986 Count : Count_Type'Base;
1987 -- Number of child subtrees
1989 C : Children_Type;
1991 begin
1992 Count_Type'Read (Stream, Count);
1994 if Count < 0 then
1995 raise Program_Error with "attempt to read from corrupt stream";
1996 end if;
1998 if Count = 0 then
1999 return;
2000 end if;
2002 C.First := Read_Subtree (Parent => Subtree);
2003 C.Last := C.First;
2005 for J in Count_Type'(2) .. Count loop
2006 C.Last.Next := Read_Subtree (Parent => Subtree);
2007 C.Last.Next.Prev := C.Last;
2008 C.Last := C.Last.Next;
2009 end loop;
2011 -- Now that the allocation and reads have completed successfully, it
2012 -- is safe to link the children to their parent.
2014 Subtree.Children := C;
2015 end Read_Children;
2017 ------------------
2018 -- Read_Subtree --
2019 ------------------
2021 function Read_Subtree
2022 (Parent : Tree_Node_Access) return Tree_Node_Access
2024 Element : constant Element_Access :=
2025 new Element_Type'(Element_Type'Input (Stream));
2027 Subtree : constant Tree_Node_Access :=
2028 new Tree_Node_Type'
2029 (Parent => Parent, Element => Element, others => <>);
2031 begin
2032 Read_Count := Read_Count + 1;
2034 Read_Children (Subtree);
2036 return Subtree;
2037 end Read_Subtree;
2039 -- Start of processing for Read
2041 begin
2042 Container.Clear; -- checks busy bit
2044 Count_Type'Read (Stream, Total_Count);
2046 if Total_Count < 0 then
2047 raise Program_Error with "attempt to read from corrupt stream";
2048 end if;
2050 if Total_Count = 0 then
2051 return;
2052 end if;
2054 Read_Count := 0;
2056 Read_Children (Root_Node (Container));
2058 if Read_Count /= Total_Count then
2059 raise Program_Error with "attempt to read from corrupt stream";
2060 end if;
2062 Container.Count := Total_Count;
2063 end Read;
2065 procedure Read
2066 (Stream : not null access Root_Stream_Type'Class;
2067 Position : out Cursor)
2069 begin
2070 raise Program_Error with "attempt to read tree cursor from stream";
2071 end Read;
2073 procedure Read
2074 (Stream : not null access Root_Stream_Type'Class;
2075 Item : out Reference_Type)
2077 begin
2078 raise Program_Error with "attempt to stream reference";
2079 end Read;
2081 procedure Read
2082 (Stream : not null access Root_Stream_Type'Class;
2083 Item : out Constant_Reference_Type)
2085 begin
2086 raise Program_Error with "attempt to stream reference";
2087 end Read;
2089 ---------------
2090 -- Reference --
2091 ---------------
2093 function Reference
2094 (Container : aliased in out Tree;
2095 Position : Cursor) return Reference_Type
2097 begin
2098 if Position.Container = null then
2099 raise Constraint_Error with
2100 "Position cursor has no element";
2101 end if;
2103 if Position.Container /= Container'Unrestricted_Access then
2104 raise Program_Error with
2105 "Position cursor designates wrong container";
2106 end if;
2108 if Position.Node = Root_Node (Container) then
2109 raise Program_Error with "Position cursor designates root";
2110 end if;
2112 if Position.Node.Element = null then
2113 raise Program_Error with "Node has no element";
2114 end if;
2116 -- Implement Vet for multiway tree???
2117 -- pragma Assert (Vet (Position),
2118 -- "Position cursor in Constant_Reference is bad");
2120 declare
2121 C : Tree renames Position.Container.all;
2122 B : Natural renames C.Busy;
2123 L : Natural renames C.Lock;
2124 begin
2125 return R : constant Reference_Type :=
2126 (Element => Position.Node.Element.all'Access,
2127 Control => (Controlled with Position.Container))
2129 B := B + 1;
2130 L := L + 1;
2131 end return;
2132 end;
2133 end Reference;
2135 --------------------
2136 -- Remove_Subtree --
2137 --------------------
2139 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2140 C : Children_Type renames Subtree.Parent.Children;
2142 begin
2143 -- This is a utility operation to remove a subtree node from its
2144 -- parent's list of children.
2146 if C.First = Subtree then
2147 pragma Assert (Subtree.Prev = null);
2149 if C.Last = Subtree then
2150 pragma Assert (Subtree.Next = null);
2151 C.First := null;
2152 C.Last := null;
2154 else
2155 C.First := Subtree.Next;
2156 C.First.Prev := null;
2157 end if;
2159 elsif C.Last = Subtree then
2160 pragma Assert (Subtree.Next = null);
2161 C.Last := Subtree.Prev;
2162 C.Last.Next := null;
2164 else
2165 Subtree.Prev.Next := Subtree.Next;
2166 Subtree.Next.Prev := Subtree.Prev;
2167 end if;
2168 end Remove_Subtree;
2170 ----------------------
2171 -- Replace_Element --
2172 ----------------------
2174 procedure Replace_Element
2175 (Container : in out Tree;
2176 Position : Cursor;
2177 New_Item : Element_Type)
2179 E, X : Element_Access;
2181 begin
2182 if Position = No_Element then
2183 raise Constraint_Error with "Position cursor has no element";
2184 end if;
2186 if Position.Container /= Container'Unrestricted_Access then
2187 raise Program_Error with "Position cursor not in container";
2188 end if;
2190 if Is_Root (Position) then
2191 raise Program_Error with "Position cursor designates root";
2192 end if;
2194 if Container.Lock > 0 then
2195 raise Program_Error
2196 with "attempt to tamper with elements (tree is locked)";
2197 end if;
2199 declare
2200 -- The element allocator may need an accessibility check in the case
2201 -- the actual type is class-wide or has access discriminants (see
2202 -- RM 4.8(10.1) and AI12-0035).
2204 pragma Unsuppress (Accessibility_Check);
2206 begin
2207 E := new Element_Type'(New_Item);
2208 end;
2210 X := Position.Node.Element;
2211 Position.Node.Element := E;
2213 Free_Element (X);
2214 end Replace_Element;
2216 ------------------------------
2217 -- Reverse_Iterate_Children --
2218 ------------------------------
2220 procedure Reverse_Iterate_Children
2221 (Parent : Cursor;
2222 Process : not null access procedure (Position : Cursor))
2224 begin
2225 if Parent = No_Element then
2226 raise Constraint_Error with "Parent cursor has no element";
2227 end if;
2229 declare
2230 B : Natural renames Parent.Container.Busy;
2231 C : Tree_Node_Access;
2233 begin
2234 B := B + 1;
2236 C := Parent.Node.Children.Last;
2237 while C /= null loop
2238 Process (Position => Cursor'(Parent.Container, Node => C));
2239 C := C.Prev;
2240 end loop;
2242 B := B - 1;
2244 exception
2245 when others =>
2246 B := B - 1;
2247 raise;
2248 end;
2249 end Reverse_Iterate_Children;
2251 ----------
2252 -- Root --
2253 ----------
2255 function Root (Container : Tree) return Cursor is
2256 begin
2257 return (Container'Unrestricted_Access, Root_Node (Container));
2258 end Root;
2260 ---------------
2261 -- Root_Node --
2262 ---------------
2264 function Root_Node (Container : Tree) return Tree_Node_Access is
2265 begin
2266 return Container.Root'Unrestricted_Access;
2267 end Root_Node;
2269 ---------------------
2270 -- Splice_Children --
2271 ---------------------
2273 procedure Splice_Children
2274 (Target : in out Tree;
2275 Target_Parent : Cursor;
2276 Before : Cursor;
2277 Source : in out Tree;
2278 Source_Parent : Cursor)
2280 Count : Count_Type;
2282 begin
2283 if Target_Parent = No_Element then
2284 raise Constraint_Error with "Target_Parent cursor has no element";
2285 end if;
2287 if Target_Parent.Container /= Target'Unrestricted_Access then
2288 raise Program_Error
2289 with "Target_Parent cursor not in Target container";
2290 end if;
2292 if Before /= No_Element then
2293 if Before.Container /= Target'Unrestricted_Access then
2294 raise Program_Error
2295 with "Before cursor not in Target container";
2296 end if;
2298 if Before.Node.Parent /= Target_Parent.Node then
2299 raise Constraint_Error
2300 with "Before cursor not child of Target_Parent";
2301 end if;
2302 end if;
2304 if Source_Parent = No_Element then
2305 raise Constraint_Error with "Source_Parent cursor has no element";
2306 end if;
2308 if Source_Parent.Container /= Source'Unrestricted_Access then
2309 raise Program_Error
2310 with "Source_Parent cursor not in Source container";
2311 end if;
2313 if Target'Address = Source'Address then
2314 if Target_Parent = Source_Parent then
2315 return;
2316 end if;
2318 if Target.Busy > 0 then
2319 raise Program_Error
2320 with "attempt to tamper with cursors (Target tree is busy)";
2321 end if;
2323 if Is_Reachable (From => Target_Parent.Node,
2324 To => Source_Parent.Node)
2325 then
2326 raise Constraint_Error
2327 with "Source_Parent is ancestor of Target_Parent";
2328 end if;
2330 Splice_Children
2331 (Target_Parent => Target_Parent.Node,
2332 Before => Before.Node,
2333 Source_Parent => Source_Parent.Node);
2335 return;
2336 end if;
2338 if Target.Busy > 0 then
2339 raise Program_Error
2340 with "attempt to tamper with cursors (Target tree is busy)";
2341 end if;
2343 if Source.Busy > 0 then
2344 raise Program_Error
2345 with "attempt to tamper with cursors (Source tree is busy)";
2346 end if;
2348 -- We cache the count of the nodes we have allocated, so that operation
2349 -- Node_Count can execute in O(1) time. But that means we must count the
2350 -- nodes in the subtree we remove from Source and insert into Target, in
2351 -- order to keep the count accurate.
2353 Count := Subtree_Node_Count (Source_Parent.Node);
2354 pragma Assert (Count >= 1);
2356 Count := Count - 1; -- because Source_Parent node does not move
2358 Splice_Children
2359 (Target_Parent => Target_Parent.Node,
2360 Before => Before.Node,
2361 Source_Parent => Source_Parent.Node);
2363 Source.Count := Source.Count - Count;
2364 Target.Count := Target.Count + Count;
2365 end Splice_Children;
2367 procedure Splice_Children
2368 (Container : in out Tree;
2369 Target_Parent : Cursor;
2370 Before : Cursor;
2371 Source_Parent : Cursor)
2373 begin
2374 if Target_Parent = No_Element then
2375 raise Constraint_Error with "Target_Parent cursor has no element";
2376 end if;
2378 if Target_Parent.Container /= Container'Unrestricted_Access then
2379 raise Program_Error
2380 with "Target_Parent cursor not in container";
2381 end if;
2383 if Before /= No_Element then
2384 if Before.Container /= Container'Unrestricted_Access then
2385 raise Program_Error
2386 with "Before cursor not in container";
2387 end if;
2389 if Before.Node.Parent /= Target_Parent.Node then
2390 raise Constraint_Error
2391 with "Before cursor not child of Target_Parent";
2392 end if;
2393 end if;
2395 if Source_Parent = No_Element then
2396 raise Constraint_Error with "Source_Parent cursor has no element";
2397 end if;
2399 if Source_Parent.Container /= Container'Unrestricted_Access then
2400 raise Program_Error
2401 with "Source_Parent cursor not in container";
2402 end if;
2404 if Target_Parent = Source_Parent then
2405 return;
2406 end if;
2408 if Container.Busy > 0 then
2409 raise Program_Error
2410 with "attempt to tamper with cursors (tree is busy)";
2411 end if;
2413 if Is_Reachable (From => Target_Parent.Node,
2414 To => Source_Parent.Node)
2415 then
2416 raise Constraint_Error
2417 with "Source_Parent is ancestor of Target_Parent";
2418 end if;
2420 Splice_Children
2421 (Target_Parent => Target_Parent.Node,
2422 Before => Before.Node,
2423 Source_Parent => Source_Parent.Node);
2424 end Splice_Children;
2426 procedure Splice_Children
2427 (Target_Parent : Tree_Node_Access;
2428 Before : Tree_Node_Access;
2429 Source_Parent : Tree_Node_Access)
2431 CC : constant Children_Type := Source_Parent.Children;
2432 C : Tree_Node_Access;
2434 begin
2435 -- This is a utility operation to remove the children from Source parent
2436 -- and insert them into Target parent.
2438 Source_Parent.Children := Children_Type'(others => null);
2440 -- Fix up the Parent pointers of each child to designate its new Target
2441 -- parent.
2443 C := CC.First;
2444 while C /= null loop
2445 C.Parent := Target_Parent;
2446 C := C.Next;
2447 end loop;
2449 Insert_Subtree_List
2450 (First => CC.First,
2451 Last => CC.Last,
2452 Parent => Target_Parent,
2453 Before => Before);
2454 end Splice_Children;
2456 --------------------
2457 -- Splice_Subtree --
2458 --------------------
2460 procedure Splice_Subtree
2461 (Target : in out Tree;
2462 Parent : Cursor;
2463 Before : Cursor;
2464 Source : in out Tree;
2465 Position : in out Cursor)
2467 Subtree_Count : Count_Type;
2469 begin
2470 if Parent = No_Element then
2471 raise Constraint_Error with "Parent cursor has no element";
2472 end if;
2474 if Parent.Container /= Target'Unrestricted_Access then
2475 raise Program_Error with "Parent cursor not in Target container";
2476 end if;
2478 if Before /= No_Element then
2479 if Before.Container /= Target'Unrestricted_Access then
2480 raise Program_Error with "Before cursor not in Target container";
2481 end if;
2483 if Before.Node.Parent /= Parent.Node then
2484 raise Constraint_Error with "Before cursor not child of Parent";
2485 end if;
2486 end if;
2488 if Position = No_Element then
2489 raise Constraint_Error with "Position cursor has no element";
2490 end if;
2492 if Position.Container /= Source'Unrestricted_Access then
2493 raise Program_Error with "Position cursor not in Source container";
2494 end if;
2496 if Is_Root (Position) then
2497 raise Program_Error with "Position cursor designates root";
2498 end if;
2500 if Target'Address = Source'Address then
2501 if Position.Node.Parent = Parent.Node then
2502 if Position.Node = Before.Node then
2503 return;
2504 end if;
2506 if Position.Node.Next = Before.Node then
2507 return;
2508 end if;
2509 end if;
2511 if Target.Busy > 0 then
2512 raise Program_Error
2513 with "attempt to tamper with cursors (Target tree is busy)";
2514 end if;
2516 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2517 raise Constraint_Error with "Position is ancestor of Parent";
2518 end if;
2520 Remove_Subtree (Position.Node);
2522 Position.Node.Parent := Parent.Node;
2523 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2525 return;
2526 end if;
2528 if Target.Busy > 0 then
2529 raise Program_Error
2530 with "attempt to tamper with cursors (Target tree is busy)";
2531 end if;
2533 if Source.Busy > 0 then
2534 raise Program_Error
2535 with "attempt to tamper with cursors (Source tree is busy)";
2536 end if;
2538 -- This is an unfortunate feature of this API: we must count the nodes
2539 -- in the subtree that we remove from the source tree, which is an O(n)
2540 -- operation. It would have been better if the Tree container did not
2541 -- have a Node_Count selector; a user that wants the number of nodes in
2542 -- the tree could simply call Subtree_Node_Count, with the understanding
2543 -- that such an operation is O(n).
2545 -- Of course, we could choose to implement the Node_Count selector as an
2546 -- O(n) operation, which would turn this splice operation into an O(1)
2547 -- operation. ???
2549 Subtree_Count := Subtree_Node_Count (Position.Node);
2550 pragma Assert (Subtree_Count <= Source.Count);
2552 Remove_Subtree (Position.Node);
2553 Source.Count := Source.Count - Subtree_Count;
2555 Position.Node.Parent := Parent.Node;
2556 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2558 Target.Count := Target.Count + Subtree_Count;
2560 Position.Container := Target'Unrestricted_Access;
2561 end Splice_Subtree;
2563 procedure Splice_Subtree
2564 (Container : in out Tree;
2565 Parent : Cursor;
2566 Before : Cursor;
2567 Position : Cursor)
2569 begin
2570 if Parent = No_Element then
2571 raise Constraint_Error with "Parent cursor has no element";
2572 end if;
2574 if Parent.Container /= Container'Unrestricted_Access then
2575 raise Program_Error with "Parent cursor not in container";
2576 end if;
2578 if Before /= No_Element then
2579 if Before.Container /= Container'Unrestricted_Access then
2580 raise Program_Error with "Before cursor not in container";
2581 end if;
2583 if Before.Node.Parent /= Parent.Node then
2584 raise Constraint_Error with "Before cursor not child of Parent";
2585 end if;
2586 end if;
2588 if Position = No_Element then
2589 raise Constraint_Error with "Position cursor has no element";
2590 end if;
2592 if Position.Container /= Container'Unrestricted_Access then
2593 raise Program_Error with "Position cursor not in container";
2594 end if;
2596 if Is_Root (Position) then
2598 -- Should this be PE instead? Need ARG confirmation. ???
2600 raise Constraint_Error with "Position cursor designates root";
2601 end if;
2603 if Position.Node.Parent = Parent.Node then
2604 if Position.Node = Before.Node then
2605 return;
2606 end if;
2608 if Position.Node.Next = Before.Node then
2609 return;
2610 end if;
2611 end if;
2613 if Container.Busy > 0 then
2614 raise Program_Error
2615 with "attempt to tamper with cursors (tree is busy)";
2616 end if;
2618 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2619 raise Constraint_Error with "Position is ancestor of Parent";
2620 end if;
2622 Remove_Subtree (Position.Node);
2624 Position.Node.Parent := Parent.Node;
2625 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2626 end Splice_Subtree;
2628 ------------------------
2629 -- Subtree_Node_Count --
2630 ------------------------
2632 function Subtree_Node_Count (Position : Cursor) return Count_Type is
2633 begin
2634 if Position = No_Element then
2635 return 0;
2636 end if;
2638 return Subtree_Node_Count (Position.Node);
2639 end Subtree_Node_Count;
2641 function Subtree_Node_Count
2642 (Subtree : Tree_Node_Access) return Count_Type
2644 Result : Count_Type;
2645 Node : Tree_Node_Access;
2647 begin
2648 Result := 1;
2649 Node := Subtree.Children.First;
2650 while Node /= null loop
2651 Result := Result + Subtree_Node_Count (Node);
2652 Node := Node.Next;
2653 end loop;
2655 return Result;
2656 end Subtree_Node_Count;
2658 ----------
2659 -- Swap --
2660 ----------
2662 procedure Swap
2663 (Container : in out Tree;
2664 I, J : Cursor)
2666 begin
2667 if I = No_Element then
2668 raise Constraint_Error with "I cursor has no element";
2669 end if;
2671 if I.Container /= Container'Unrestricted_Access then
2672 raise Program_Error with "I cursor not in container";
2673 end if;
2675 if Is_Root (I) then
2676 raise Program_Error with "I cursor designates root";
2677 end if;
2679 if I = J then -- make this test sooner???
2680 return;
2681 end if;
2683 if J = No_Element then
2684 raise Constraint_Error with "J cursor has no element";
2685 end if;
2687 if J.Container /= Container'Unrestricted_Access then
2688 raise Program_Error with "J cursor not in container";
2689 end if;
2691 if Is_Root (J) then
2692 raise Program_Error with "J cursor designates root";
2693 end if;
2695 if Container.Lock > 0 then
2696 raise Program_Error
2697 with "attempt to tamper with elements (tree is locked)";
2698 end if;
2700 declare
2701 EI : constant Element_Access := I.Node.Element;
2703 begin
2704 I.Node.Element := J.Node.Element;
2705 J.Node.Element := EI;
2706 end;
2707 end Swap;
2709 --------------------
2710 -- Update_Element --
2711 --------------------
2713 procedure Update_Element
2714 (Container : in out Tree;
2715 Position : Cursor;
2716 Process : not null access procedure (Element : in out Element_Type))
2718 begin
2719 if Position = No_Element then
2720 raise Constraint_Error with "Position cursor has no element";
2721 end if;
2723 if Position.Container /= Container'Unrestricted_Access then
2724 raise Program_Error with "Position cursor not in container";
2725 end if;
2727 if Is_Root (Position) then
2728 raise Program_Error with "Position cursor designates root";
2729 end if;
2731 declare
2732 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2733 B : Natural renames T.Busy;
2734 L : Natural renames T.Lock;
2736 begin
2737 B := B + 1;
2738 L := L + 1;
2740 Process (Position.Node.Element.all);
2742 L := L - 1;
2743 B := B - 1;
2745 exception
2746 when others =>
2747 L := L - 1;
2748 B := B - 1;
2750 raise;
2751 end;
2752 end Update_Element;
2754 -----------
2755 -- Write --
2756 -----------
2758 procedure Write
2759 (Stream : not null access Root_Stream_Type'Class;
2760 Container : Tree)
2762 procedure Write_Children (Subtree : Tree_Node_Access);
2763 procedure Write_Subtree (Subtree : Tree_Node_Access);
2765 --------------------
2766 -- Write_Children --
2767 --------------------
2769 procedure Write_Children (Subtree : Tree_Node_Access) is
2770 CC : Children_Type renames Subtree.Children;
2771 C : Tree_Node_Access;
2773 begin
2774 Count_Type'Write (Stream, Child_Count (CC));
2776 C := CC.First;
2777 while C /= null loop
2778 Write_Subtree (C);
2779 C := C.Next;
2780 end loop;
2781 end Write_Children;
2783 -------------------
2784 -- Write_Subtree --
2785 -------------------
2787 procedure Write_Subtree (Subtree : Tree_Node_Access) is
2788 begin
2789 Element_Type'Output (Stream, Subtree.Element.all);
2790 Write_Children (Subtree);
2791 end Write_Subtree;
2793 -- Start of processing for Write
2795 begin
2796 Count_Type'Write (Stream, Container.Count);
2798 if Container.Count = 0 then
2799 return;
2800 end if;
2802 Write_Children (Root_Node (Container));
2803 end Write;
2805 procedure Write
2806 (Stream : not null access Root_Stream_Type'Class;
2807 Position : Cursor)
2809 begin
2810 raise Program_Error with "attempt to write tree cursor to stream";
2811 end Write;
2813 procedure Write
2814 (Stream : not null access Root_Stream_Type'Class;
2815 Item : Reference_Type)
2817 begin
2818 raise Program_Error with "attempt to stream reference";
2819 end Write;
2821 procedure Write
2822 (Stream : not null access Root_Stream_Type'Class;
2823 Item : Constant_Reference_Type)
2825 begin
2826 raise Program_Error with "attempt to stream reference";
2827 end Write;
2829 end Ada.Containers.Indefinite_Multiway_Trees;