Daily bump.
[official-gcc.git] / gcc / ada / a-cimutr.adb
blobe249c6a68d69f8b662941c1cbb65005bb2653683
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- ADA.CONTAINERS.INDEFINITE_MULTIWAY_TREES --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2012, 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 =>
509 (Controlled with Container'Unrestricted_Access))
511 B := B + 1;
512 L := L + 1;
513 end return;
514 end;
515 end Constant_Reference;
517 --------------
518 -- Contains --
519 --------------
521 function Contains
522 (Container : Tree;
523 Item : Element_Type) return Boolean
525 begin
526 return Find (Container, Item) /= No_Element;
527 end Contains;
529 ----------
530 -- Copy --
531 ----------
533 function Copy (Source : Tree) return Tree is
534 begin
535 return Target : Tree do
536 Copy_Children
537 (Source => Source.Root.Children,
538 Parent => Root_Node (Target),
539 Count => Target.Count);
541 pragma Assert (Target.Count = Source.Count);
542 end return;
543 end Copy;
545 -------------------
546 -- Copy_Children --
547 -------------------
549 procedure Copy_Children
550 (Source : Children_Type;
551 Parent : Tree_Node_Access;
552 Count : in out Count_Type)
554 pragma Assert (Parent /= null);
555 pragma Assert (Parent.Children.First = null);
556 pragma Assert (Parent.Children.Last = null);
558 CC : Children_Type;
559 C : Tree_Node_Access;
561 begin
562 -- We special-case the first allocation, in order to establish the
563 -- representation invariants for type Children_Type.
565 C := Source.First;
567 if C = null then
568 return;
569 end if;
571 Copy_Subtree
572 (Source => C,
573 Parent => Parent,
574 Target => CC.First,
575 Count => Count);
577 CC.Last := CC.First;
579 -- The representation invariants for the Children_Type list have been
580 -- established, so we can now copy the remaining children of Source.
582 C := C.Next;
583 while C /= null loop
584 Copy_Subtree
585 (Source => C,
586 Parent => Parent,
587 Target => CC.Last.Next,
588 Count => Count);
590 CC.Last.Next.Prev := CC.Last;
591 CC.Last := CC.Last.Next;
593 C := C.Next;
594 end loop;
596 -- We add the newly-allocated children to their parent list only after
597 -- the allocation has succeeded, in order to preserve invariants of the
598 -- parent.
600 Parent.Children := CC;
601 end Copy_Children;
603 ------------------
604 -- Copy_Subtree --
605 ------------------
607 procedure Copy_Subtree
608 (Target : in out Tree;
609 Parent : Cursor;
610 Before : Cursor;
611 Source : Cursor)
613 Target_Subtree : Tree_Node_Access;
614 Target_Count : Count_Type;
616 begin
617 if Parent = No_Element then
618 raise Constraint_Error with "Parent cursor has no element";
619 end if;
621 if Parent.Container /= Target'Unrestricted_Access then
622 raise Program_Error with "Parent cursor not in container";
623 end if;
625 if Before /= No_Element then
626 if Before.Container /= Target'Unrestricted_Access then
627 raise Program_Error with "Before cursor not in container";
628 end if;
630 if Before.Node.Parent /= Parent.Node then
631 raise Constraint_Error with "Before cursor not child of Parent";
632 end if;
633 end if;
635 if Source = No_Element then
636 return;
637 end if;
639 if Is_Root (Source) then
640 raise Constraint_Error with "Source cursor designates root";
641 end if;
643 -- Copy_Subtree returns a count of the number of nodes that it
644 -- allocates, but it works by incrementing the value that is passed in.
645 -- We must therefore initialize the count value before calling
646 -- Copy_Subtree.
648 Target_Count := 0;
650 Copy_Subtree
651 (Source => Source.Node,
652 Parent => Parent.Node,
653 Target => Target_Subtree,
654 Count => Target_Count);
656 pragma Assert (Target_Subtree /= null);
657 pragma Assert (Target_Subtree.Parent = Parent.Node);
658 pragma Assert (Target_Count >= 1);
660 Insert_Subtree_Node
661 (Subtree => Target_Subtree,
662 Parent => Parent.Node,
663 Before => Before.Node);
665 -- In order for operation Node_Count to complete in O(1) time, we cache
666 -- the count value. Here we increment the total count by the number of
667 -- nodes we just inserted.
669 Target.Count := Target.Count + Target_Count;
670 end Copy_Subtree;
672 procedure Copy_Subtree
673 (Source : Tree_Node_Access;
674 Parent : Tree_Node_Access;
675 Target : out Tree_Node_Access;
676 Count : in out Count_Type)
678 E : constant Element_Access := new Element_Type'(Source.Element.all);
680 begin
681 Target := new Tree_Node_Type'(Element => E,
682 Parent => Parent,
683 others => <>);
685 Count := Count + 1;
687 Copy_Children
688 (Source => Source.Children,
689 Parent => Target,
690 Count => Count);
691 end Copy_Subtree;
693 -------------------------
694 -- Deallocate_Children --
695 -------------------------
697 procedure Deallocate_Children
698 (Subtree : Tree_Node_Access;
699 Count : in out Count_Type)
701 pragma Assert (Subtree /= null);
703 CC : Children_Type := Subtree.Children;
704 C : Tree_Node_Access;
706 begin
707 -- We immediately remove the children from their parent, in order to
708 -- preserve invariants in case the deallocation fails.
710 Subtree.Children := Children_Type'(others => null);
712 while CC.First /= null loop
713 C := CC.First;
714 CC.First := C.Next;
716 Deallocate_Subtree (C, Count);
717 end loop;
718 end Deallocate_Children;
720 ---------------------
721 -- Deallocate_Node --
722 ---------------------
724 procedure Deallocate_Node (X : in out Tree_Node_Access) is
725 procedure Free_Node is
726 new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access);
728 -- Start of processing for Deallocate_Node
730 begin
731 if X /= null then
732 Free_Element (X.Element);
733 Free_Node (X);
734 end if;
735 end Deallocate_Node;
737 ------------------------
738 -- Deallocate_Subtree --
739 ------------------------
741 procedure Deallocate_Subtree
742 (Subtree : in out Tree_Node_Access;
743 Count : in out Count_Type)
745 begin
746 Deallocate_Children (Subtree, Count);
747 Deallocate_Node (Subtree);
748 Count := Count + 1;
749 end Deallocate_Subtree;
751 ---------------------
752 -- Delete_Children --
753 ---------------------
755 procedure Delete_Children
756 (Container : in out Tree;
757 Parent : Cursor)
759 Count : Count_Type;
761 begin
762 if Parent = No_Element then
763 raise Constraint_Error with "Parent cursor has no element";
764 end if;
766 if Parent.Container /= Container'Unrestricted_Access then
767 raise Program_Error with "Parent cursor not in container";
768 end if;
770 if Container.Busy > 0 then
771 raise Program_Error
772 with "attempt to tamper with cursors (tree is busy)";
773 end if;
775 -- Deallocate_Children returns a count of the number of nodes
776 -- that it deallocates, but it works by incrementing the
777 -- value that is passed in. We must therefore initialize
778 -- the count value before calling Deallocate_Children.
780 Count := 0;
782 Deallocate_Children (Parent.Node, Count);
783 pragma Assert (Count <= Container.Count);
785 Container.Count := Container.Count - Count;
786 end Delete_Children;
788 -----------------
789 -- Delete_Leaf --
790 -----------------
792 procedure Delete_Leaf
793 (Container : in out Tree;
794 Position : in out Cursor)
796 X : Tree_Node_Access;
798 begin
799 if Position = No_Element then
800 raise Constraint_Error with "Position cursor has no element";
801 end if;
803 if Position.Container /= Container'Unrestricted_Access then
804 raise Program_Error with "Position cursor not in container";
805 end if;
807 if Is_Root (Position) then
808 raise Program_Error with "Position cursor designates root";
809 end if;
811 if not Is_Leaf (Position) then
812 raise Constraint_Error with "Position cursor does not designate leaf";
813 end if;
815 if Container.Busy > 0 then
816 raise Program_Error
817 with "attempt to tamper with cursors (tree is busy)";
818 end if;
820 X := Position.Node;
821 Position := No_Element;
823 -- Restore represention invariants before attempting the actual
824 -- deallocation.
826 Remove_Subtree (X);
827 Container.Count := Container.Count - 1;
829 -- It is now safe to attempt the deallocation. This leaf node has been
830 -- disassociated from the tree, so even if the deallocation fails,
831 -- representation invariants will remain satisfied.
833 Deallocate_Node (X);
834 end Delete_Leaf;
836 --------------------
837 -- Delete_Subtree --
838 --------------------
840 procedure Delete_Subtree
841 (Container : in out Tree;
842 Position : in out Cursor)
844 X : Tree_Node_Access;
845 Count : Count_Type;
847 begin
848 if Position = No_Element then
849 raise Constraint_Error with "Position cursor has no element";
850 end if;
852 if Position.Container /= Container'Unrestricted_Access then
853 raise Program_Error with "Position cursor not in container";
854 end if;
856 if Is_Root (Position) then
857 raise Program_Error with "Position cursor designates root";
858 end if;
860 if Container.Busy > 0 then
861 raise Program_Error
862 with "attempt to tamper with cursors (tree is busy)";
863 end if;
865 X := Position.Node;
866 Position := No_Element;
868 -- Here is one case where a deallocation failure can result in the
869 -- violation of a representation invariant. We disassociate the subtree
870 -- from the tree now, but we only decrement the total node count after
871 -- we attempt the deallocation. However, if the deallocation fails, the
872 -- total node count will not get decremented.
874 -- One way around this dilemma is to count the nodes in the subtree
875 -- before attempt to delete the subtree, but that is an O(n) operation,
876 -- so it does not seem worth it.
878 -- Perhaps this is much ado about nothing, since the only way
879 -- deallocation can fail is if Controlled Finalization fails: this
880 -- propagates Program_Error so all bets are off anyway. ???
882 Remove_Subtree (X);
884 -- Deallocate_Subtree returns a count of the number of nodes that it
885 -- deallocates, but it works by incrementing the value that is passed
886 -- in. We must therefore initialize the count value before calling
887 -- Deallocate_Subtree.
889 Count := 0;
891 Deallocate_Subtree (X, Count);
892 pragma Assert (Count <= Container.Count);
894 -- See comments above. We would prefer to do this sooner, but there's no
895 -- way to satisfy that goal without an potentially severe execution
896 -- penalty.
898 Container.Count := Container.Count - Count;
899 end Delete_Subtree;
901 -----------
902 -- Depth --
903 -----------
905 function Depth (Position : Cursor) return Count_Type is
906 Result : Count_Type;
907 N : Tree_Node_Access;
909 begin
910 Result := 0;
911 N := Position.Node;
912 while N /= null loop
913 N := N.Parent;
914 Result := Result + 1;
915 end loop;
917 return Result;
918 end Depth;
920 -------------
921 -- Element --
922 -------------
924 function Element (Position : Cursor) return Element_Type is
925 begin
926 if Position.Container = null then
927 raise Constraint_Error with "Position cursor has no element";
928 end if;
930 if Position.Node = Root_Node (Position.Container.all) then
931 raise Program_Error with "Position cursor designates root";
932 end if;
934 return Position.Node.Element.all;
935 end Element;
937 --------------------
938 -- Equal_Children --
939 --------------------
941 function Equal_Children
942 (Left_Subtree : Tree_Node_Access;
943 Right_Subtree : Tree_Node_Access) return Boolean
945 Left_Children : Children_Type renames Left_Subtree.Children;
946 Right_Children : Children_Type renames Right_Subtree.Children;
948 L, R : Tree_Node_Access;
950 begin
951 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
952 return False;
953 end if;
955 L := Left_Children.First;
956 R := Right_Children.First;
957 while L /= null loop
958 if not Equal_Subtree (L, R) then
959 return False;
960 end if;
962 L := L.Next;
963 R := R.Next;
964 end loop;
966 return True;
967 end Equal_Children;
969 -------------------
970 -- Equal_Subtree --
971 -------------------
973 function Equal_Subtree
974 (Left_Position : Cursor;
975 Right_Position : Cursor) return Boolean
977 begin
978 if Left_Position = No_Element then
979 raise Constraint_Error with "Left cursor has no element";
980 end if;
982 if Right_Position = No_Element then
983 raise Constraint_Error with "Right cursor has no element";
984 end if;
986 if Left_Position = Right_Position then
987 return True;
988 end if;
990 if Is_Root (Left_Position) then
991 if not Is_Root (Right_Position) then
992 return False;
993 end if;
995 return Equal_Children (Left_Position.Node, Right_Position.Node);
996 end if;
998 if Is_Root (Right_Position) then
999 return False;
1000 end if;
1002 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
1003 end Equal_Subtree;
1005 function Equal_Subtree
1006 (Left_Subtree : Tree_Node_Access;
1007 Right_Subtree : Tree_Node_Access) return Boolean
1009 begin
1010 if Left_Subtree.Element.all /= Right_Subtree.Element.all then
1011 return False;
1012 end if;
1014 return Equal_Children (Left_Subtree, Right_Subtree);
1015 end Equal_Subtree;
1017 --------------
1018 -- Finalize --
1019 --------------
1021 procedure Finalize (Object : in out Root_Iterator) is
1022 B : Natural renames Object.Container.Busy;
1023 begin
1024 B := B - 1;
1025 end Finalize;
1027 procedure Finalize (Control : in out Reference_Control_Type) is
1028 begin
1029 if Control.Container /= null then
1030 declare
1031 C : Tree renames Control.Container.all;
1032 B : Natural renames C.Busy;
1033 L : Natural renames C.Lock;
1034 begin
1035 B := B - 1;
1036 L := L - 1;
1037 end;
1039 Control.Container := null;
1040 end if;
1041 end Finalize;
1043 ----------
1044 -- Find --
1045 ----------
1047 function Find
1048 (Container : Tree;
1049 Item : Element_Type) return Cursor
1051 N : constant Tree_Node_Access :=
1052 Find_In_Children (Root_Node (Container), Item);
1054 begin
1055 if N = null then
1056 return No_Element;
1057 end if;
1059 return Cursor'(Container'Unrestricted_Access, N);
1060 end Find;
1062 -----------
1063 -- First --
1064 -----------
1066 overriding function First (Object : Subtree_Iterator) return Cursor is
1067 begin
1068 if Object.Subtree = Root_Node (Object.Container.all) then
1069 return First_Child (Root (Object.Container.all));
1070 else
1071 return Cursor'(Object.Container, Object.Subtree);
1072 end if;
1073 end First;
1075 overriding function First (Object : Child_Iterator) return Cursor is
1076 begin
1077 return First_Child (Cursor'(Object.Container, Object.Subtree));
1078 end First;
1080 -----------------
1081 -- First_Child --
1082 -----------------
1084 function First_Child (Parent : Cursor) return Cursor is
1085 Node : Tree_Node_Access;
1087 begin
1088 if Parent = No_Element then
1089 raise Constraint_Error with "Parent cursor has no element";
1090 end if;
1092 Node := Parent.Node.Children.First;
1094 if Node = null then
1095 return No_Element;
1096 end if;
1098 return Cursor'(Parent.Container, Node);
1099 end First_Child;
1101 -------------------------
1102 -- First_Child_Element --
1103 -------------------------
1105 function First_Child_Element (Parent : Cursor) return Element_Type is
1106 begin
1107 return Element (First_Child (Parent));
1108 end First_Child_Element;
1110 ----------------------
1111 -- Find_In_Children --
1112 ----------------------
1114 function Find_In_Children
1115 (Subtree : Tree_Node_Access;
1116 Item : Element_Type) return Tree_Node_Access
1118 N, Result : Tree_Node_Access;
1120 begin
1121 N := Subtree.Children.First;
1122 while N /= null loop
1123 Result := Find_In_Subtree (N, Item);
1125 if Result /= null then
1126 return Result;
1127 end if;
1129 N := N.Next;
1130 end loop;
1132 return null;
1133 end Find_In_Children;
1135 ---------------------
1136 -- Find_In_Subtree --
1137 ---------------------
1139 function Find_In_Subtree
1140 (Position : Cursor;
1141 Item : Element_Type) return Cursor
1143 Result : Tree_Node_Access;
1145 begin
1146 if Position = No_Element then
1147 raise Constraint_Error with "Position cursor has no element";
1148 end if;
1150 -- Commented-out pending ruling from ARG. ???
1152 -- if Position.Container /= Container'Unrestricted_Access then
1153 -- raise Program_Error with "Position cursor not in container";
1154 -- end if;
1156 if Is_Root (Position) then
1157 Result := Find_In_Children (Position.Node, Item);
1159 else
1160 Result := Find_In_Subtree (Position.Node, Item);
1161 end if;
1163 if Result = null then
1164 return No_Element;
1165 end if;
1167 return Cursor'(Position.Container, Result);
1168 end Find_In_Subtree;
1170 function Find_In_Subtree
1171 (Subtree : Tree_Node_Access;
1172 Item : Element_Type) return Tree_Node_Access
1174 begin
1175 if Subtree.Element.all = Item then
1176 return Subtree;
1177 end if;
1179 return Find_In_Children (Subtree, Item);
1180 end Find_In_Subtree;
1182 -----------------
1183 -- Has_Element --
1184 -----------------
1186 function Has_Element (Position : Cursor) return Boolean is
1187 begin
1188 if Position = No_Element then
1189 return False;
1190 end if;
1192 return Position.Node.Parent /= null;
1193 end Has_Element;
1195 ------------------
1196 -- Insert_Child --
1197 ------------------
1199 procedure Insert_Child
1200 (Container : in out Tree;
1201 Parent : Cursor;
1202 Before : Cursor;
1203 New_Item : Element_Type;
1204 Count : Count_Type := 1)
1206 Position : Cursor;
1207 pragma Unreferenced (Position);
1209 begin
1210 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1211 end Insert_Child;
1213 procedure Insert_Child
1214 (Container : in out Tree;
1215 Parent : Cursor;
1216 Before : Cursor;
1217 New_Item : Element_Type;
1218 Position : out Cursor;
1219 Count : Count_Type := 1)
1221 Last : Tree_Node_Access;
1222 Element : Element_Access;
1224 begin
1225 if Parent = No_Element then
1226 raise Constraint_Error with "Parent cursor has no element";
1227 end if;
1229 if Parent.Container /= Container'Unrestricted_Access then
1230 raise Program_Error with "Parent cursor not in container";
1231 end if;
1233 if Before /= No_Element then
1234 if Before.Container /= Container'Unrestricted_Access then
1235 raise Program_Error with "Before cursor not in container";
1236 end if;
1238 if Before.Node.Parent /= Parent.Node then
1239 raise Constraint_Error with "Parent cursor not parent of Before";
1240 end if;
1241 end if;
1243 if Count = 0 then
1244 Position := No_Element; -- Need ruling from ARG ???
1245 return;
1246 end if;
1248 if Container.Busy > 0 then
1249 raise Program_Error
1250 with "attempt to tamper with cursors (tree is busy)";
1251 end if;
1253 Position.Container := Parent.Container;
1255 declare
1256 -- The element allocator may need an accessibility check in the case
1257 -- the actual type is class-wide or has access discriminants (see
1258 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
1259 -- allocator in the loop below, because the one in this block would
1260 -- have failed already.
1262 pragma Unsuppress (Accessibility_Check);
1264 begin
1265 Element := new Element_Type'(New_Item);
1266 end;
1268 Position.Node := new Tree_Node_Type'(Parent => Parent.Node,
1269 Element => Element,
1270 others => <>);
1272 Last := Position.Node;
1274 for J in Count_Type'(2) .. Count loop
1275 -- Reclaim other nodes if Storage_Error. ???
1277 Element := new Element_Type'(New_Item);
1278 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1279 Prev => Last,
1280 Element => Element,
1281 others => <>);
1283 Last := Last.Next;
1284 end loop;
1286 Insert_Subtree_List
1287 (First => Position.Node,
1288 Last => Last,
1289 Parent => Parent.Node,
1290 Before => Before.Node);
1292 -- In order for operation Node_Count to complete in O(1) time, we cache
1293 -- the count value. Here we increment the total count by the number of
1294 -- nodes we just inserted.
1296 Container.Count := Container.Count + Count;
1297 end Insert_Child;
1299 -------------------------
1300 -- Insert_Subtree_List --
1301 -------------------------
1303 procedure Insert_Subtree_List
1304 (First : Tree_Node_Access;
1305 Last : Tree_Node_Access;
1306 Parent : Tree_Node_Access;
1307 Before : Tree_Node_Access)
1309 pragma Assert (Parent /= null);
1310 C : Children_Type renames Parent.Children;
1312 begin
1313 -- This is a simple utility operation to insert a list of nodes (from
1314 -- First..Last) as children of Parent. The Before node specifies where
1315 -- the new children should be inserted relative to the existing
1316 -- children.
1318 if First = null then
1319 pragma Assert (Last = null);
1320 return;
1321 end if;
1323 pragma Assert (Last /= null);
1324 pragma Assert (Before = null or else Before.Parent = Parent);
1326 if C.First = null then
1327 C.First := First;
1328 C.First.Prev := null;
1329 C.Last := Last;
1330 C.Last.Next := null;
1332 elsif Before = null then -- means "insert after existing nodes"
1333 C.Last.Next := First;
1334 First.Prev := C.Last;
1335 C.Last := Last;
1336 C.Last.Next := null;
1338 elsif Before = C.First then
1339 Last.Next := C.First;
1340 C.First.Prev := Last;
1341 C.First := First;
1342 C.First.Prev := null;
1344 else
1345 Before.Prev.Next := First;
1346 First.Prev := Before.Prev;
1347 Last.Next := Before;
1348 Before.Prev := Last;
1349 end if;
1350 end Insert_Subtree_List;
1352 -------------------------
1353 -- Insert_Subtree_Node --
1354 -------------------------
1356 procedure Insert_Subtree_Node
1357 (Subtree : Tree_Node_Access;
1358 Parent : Tree_Node_Access;
1359 Before : Tree_Node_Access)
1361 begin
1362 -- This is a simple wrapper operation to insert a single child into the
1363 -- Parent's children list.
1365 Insert_Subtree_List
1366 (First => Subtree,
1367 Last => Subtree,
1368 Parent => Parent,
1369 Before => Before);
1370 end Insert_Subtree_Node;
1372 --------------
1373 -- Is_Empty --
1374 --------------
1376 function Is_Empty (Container : Tree) return Boolean is
1377 begin
1378 return Container.Root.Children.First = null;
1379 end Is_Empty;
1381 -------------
1382 -- Is_Leaf --
1383 -------------
1385 function Is_Leaf (Position : Cursor) return Boolean is
1386 begin
1387 if Position = No_Element then
1388 return False;
1389 end if;
1391 return Position.Node.Children.First = null;
1392 end Is_Leaf;
1394 ------------------
1395 -- Is_Reachable --
1396 ------------------
1398 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1399 pragma Assert (From /= null);
1400 pragma Assert (To /= null);
1402 N : Tree_Node_Access;
1404 begin
1405 N := From;
1406 while N /= null loop
1407 if N = To then
1408 return True;
1409 end if;
1411 N := N.Parent;
1412 end loop;
1414 return False;
1415 end Is_Reachable;
1417 -------------
1418 -- Is_Root --
1419 -------------
1421 function Is_Root (Position : Cursor) return Boolean is
1422 begin
1423 if Position.Container = null then
1424 return False;
1425 end if;
1427 return Position = Root (Position.Container.all);
1428 end Is_Root;
1430 -------------
1431 -- Iterate --
1432 -------------
1434 procedure Iterate
1435 (Container : Tree;
1436 Process : not null access procedure (Position : Cursor))
1438 B : Natural renames Container'Unrestricted_Access.all.Busy;
1440 begin
1441 B := B + 1;
1443 Iterate_Children
1444 (Container => Container'Unrestricted_Access,
1445 Subtree => Root_Node (Container),
1446 Process => Process);
1448 B := B - 1;
1450 exception
1451 when others =>
1452 B := B - 1;
1453 raise;
1454 end Iterate;
1456 function Iterate (Container : Tree)
1457 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1459 begin
1460 return Iterate_Subtree (Root (Container));
1461 end Iterate;
1463 ----------------------
1464 -- Iterate_Children --
1465 ----------------------
1467 procedure Iterate_Children
1468 (Parent : Cursor;
1469 Process : not null access procedure (Position : Cursor))
1471 begin
1472 if Parent = No_Element then
1473 raise Constraint_Error with "Parent cursor has no element";
1474 end if;
1476 declare
1477 B : Natural renames Parent.Container.Busy;
1478 C : Tree_Node_Access;
1480 begin
1481 B := B + 1;
1483 C := Parent.Node.Children.First;
1484 while C /= null loop
1485 Process (Position => Cursor'(Parent.Container, Node => C));
1486 C := C.Next;
1487 end loop;
1489 B := B - 1;
1491 exception
1492 when others =>
1493 B := B - 1;
1494 raise;
1495 end;
1496 end Iterate_Children;
1498 procedure Iterate_Children
1499 (Container : Tree_Access;
1500 Subtree : Tree_Node_Access;
1501 Process : not null access procedure (Position : Cursor))
1503 Node : Tree_Node_Access;
1505 begin
1506 -- This is a helper function to recursively iterate over all the nodes
1507 -- in a subtree, in depth-first fashion. This particular helper just
1508 -- visits the children of this subtree, not the root of the subtree node
1509 -- itself. This is useful when starting from the ultimate root of the
1510 -- entire tree (see Iterate), as that root does not have an element.
1512 Node := Subtree.Children.First;
1513 while Node /= null loop
1514 Iterate_Subtree (Container, Node, Process);
1515 Node := Node.Next;
1516 end loop;
1517 end Iterate_Children;
1519 function Iterate_Children
1520 (Container : Tree;
1521 Parent : Cursor)
1522 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1524 C : constant Tree_Access := Container'Unrestricted_Access;
1525 B : Natural renames C.Busy;
1527 begin
1528 if Parent = No_Element then
1529 raise Constraint_Error with "Parent cursor has no element";
1530 end if;
1532 if Parent.Container /= C then
1533 raise Program_Error with "Parent cursor not in container";
1534 end if;
1536 return It : constant Child_Iterator :=
1537 Child_Iterator'(Limited_Controlled with
1538 Container => C,
1539 Subtree => Parent.Node)
1541 B := B + 1;
1542 end return;
1543 end Iterate_Children;
1545 ---------------------
1546 -- Iterate_Subtree --
1547 ---------------------
1549 function Iterate_Subtree
1550 (Position : Cursor)
1551 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1553 begin
1554 if Position = No_Element then
1555 raise Constraint_Error with "Position cursor has no element";
1556 end if;
1558 -- Implement Vet for multiway trees???
1559 -- pragma Assert (Vet (Position), "bad subtree cursor");
1561 declare
1562 B : Natural renames Position.Container.Busy;
1563 begin
1564 return It : constant Subtree_Iterator :=
1565 (Limited_Controlled with
1566 Container => Position.Container,
1567 Subtree => Position.Node)
1569 B := B + 1;
1570 end return;
1571 end;
1572 end Iterate_Subtree;
1574 procedure Iterate_Subtree
1575 (Position : Cursor;
1576 Process : not null access procedure (Position : Cursor))
1578 begin
1579 if Position = No_Element then
1580 raise Constraint_Error with "Position cursor has no element";
1581 end if;
1583 declare
1584 B : Natural renames Position.Container.Busy;
1586 begin
1587 B := B + 1;
1589 if Is_Root (Position) then
1590 Iterate_Children (Position.Container, Position.Node, Process);
1591 else
1592 Iterate_Subtree (Position.Container, Position.Node, Process);
1593 end if;
1595 B := B - 1;
1597 exception
1598 when others =>
1599 B := B - 1;
1600 raise;
1601 end;
1602 end Iterate_Subtree;
1604 procedure Iterate_Subtree
1605 (Container : Tree_Access;
1606 Subtree : Tree_Node_Access;
1607 Process : not null access procedure (Position : Cursor))
1609 begin
1610 -- This is a helper function to recursively iterate over all the nodes
1611 -- in a subtree, in depth-first fashion. It first visits the root of the
1612 -- subtree, then visits its children.
1614 Process (Cursor'(Container, Subtree));
1615 Iterate_Children (Container, Subtree, Process);
1616 end Iterate_Subtree;
1618 ----------
1619 -- Last --
1620 ----------
1622 overriding function Last (Object : Child_Iterator) return Cursor is
1623 begin
1624 return Last_Child (Cursor'(Object.Container, Object.Subtree));
1625 end Last;
1627 ----------------
1628 -- Last_Child --
1629 ----------------
1631 function Last_Child (Parent : Cursor) return Cursor is
1632 Node : Tree_Node_Access;
1634 begin
1635 if Parent = No_Element then
1636 raise Constraint_Error with "Parent cursor has no element";
1637 end if;
1639 Node := Parent.Node.Children.Last;
1641 if Node = null then
1642 return No_Element;
1643 end if;
1645 return (Parent.Container, Node);
1646 end Last_Child;
1648 ------------------------
1649 -- Last_Child_Element --
1650 ------------------------
1652 function Last_Child_Element (Parent : Cursor) return Element_Type is
1653 begin
1654 return Element (Last_Child (Parent));
1655 end Last_Child_Element;
1657 ----------
1658 -- Move --
1659 ----------
1661 procedure Move (Target : in out Tree; Source : in out Tree) is
1662 Node : Tree_Node_Access;
1664 begin
1665 if Target'Address = Source'Address then
1666 return;
1667 end if;
1669 if Source.Busy > 0 then
1670 raise Program_Error
1671 with "attempt to tamper with cursors of Source (tree is busy)";
1672 end if;
1674 Target.Clear; -- checks busy bit
1676 Target.Root.Children := Source.Root.Children;
1677 Source.Root.Children := Children_Type'(others => null);
1679 Node := Target.Root.Children.First;
1680 while Node /= null loop
1681 Node.Parent := Root_Node (Target);
1682 Node := Node.Next;
1683 end loop;
1685 Target.Count := Source.Count;
1686 Source.Count := 0;
1687 end Move;
1689 ----------
1690 -- Next --
1691 ----------
1693 function Next
1694 (Object : Subtree_Iterator;
1695 Position : Cursor) return Cursor
1697 Node : Tree_Node_Access;
1699 begin
1700 if Position.Container = null then
1701 return No_Element;
1702 end if;
1704 if Position.Container /= Object.Container then
1705 raise Program_Error with
1706 "Position cursor of Next designates wrong tree";
1707 end if;
1709 Node := Position.Node;
1711 if Node.Children.First /= null then
1712 return Cursor'(Object.Container, Node.Children.First);
1713 end if;
1715 while Node /= Object.Subtree loop
1716 if Node.Next /= null then
1717 return Cursor'(Object.Container, Node.Next);
1718 end if;
1720 Node := Node.Parent;
1721 end loop;
1723 return No_Element;
1724 end Next;
1726 function Next
1727 (Object : Child_Iterator;
1728 Position : Cursor) return Cursor
1730 begin
1731 if Position.Container = null then
1732 return No_Element;
1733 end if;
1735 if Position.Container /= Object.Container then
1736 raise Program_Error with
1737 "Position cursor of Next designates wrong tree";
1738 end if;
1740 return Next_Sibling (Position);
1741 end Next;
1743 ------------------
1744 -- Next_Sibling --
1745 ------------------
1747 function Next_Sibling (Position : Cursor) return Cursor is
1748 begin
1749 if Position = No_Element then
1750 return No_Element;
1751 end if;
1753 if Position.Node.Next = null then
1754 return No_Element;
1755 end if;
1757 return Cursor'(Position.Container, Position.Node.Next);
1758 end Next_Sibling;
1760 procedure Next_Sibling (Position : in out Cursor) is
1761 begin
1762 Position := Next_Sibling (Position);
1763 end Next_Sibling;
1765 ----------------
1766 -- Node_Count --
1767 ----------------
1769 function Node_Count (Container : Tree) return Count_Type is
1770 begin
1771 -- Container.Count is the number of nodes we have actually allocated. We
1772 -- cache the value specifically so this Node_Count operation can execute
1773 -- in O(1) time, which makes it behave similarly to how the Length
1774 -- selector function behaves for other containers.
1776 -- The cached node count value only describes the nodes we have
1777 -- allocated; the root node itself is not included in that count. The
1778 -- Node_Count operation returns a value that includes the root node
1779 -- (because the RM says so), so we must add 1 to our cached value.
1781 return 1 + Container.Count;
1782 end Node_Count;
1784 ------------
1785 -- Parent --
1786 ------------
1788 function Parent (Position : Cursor) return Cursor is
1789 begin
1790 if Position = No_Element then
1791 return No_Element;
1792 end if;
1794 if Position.Node.Parent = null then
1795 return No_Element;
1796 end if;
1798 return Cursor'(Position.Container, Position.Node.Parent);
1799 end Parent;
1801 -------------------
1802 -- Prepent_Child --
1803 -------------------
1805 procedure Prepend_Child
1806 (Container : in out Tree;
1807 Parent : Cursor;
1808 New_Item : Element_Type;
1809 Count : Count_Type := 1)
1811 First, Last : Tree_Node_Access;
1812 Element : Element_Access;
1814 begin
1815 if Parent = No_Element then
1816 raise Constraint_Error with "Parent cursor has no element";
1817 end if;
1819 if Parent.Container /= Container'Unrestricted_Access then
1820 raise Program_Error with "Parent cursor not in container";
1821 end if;
1823 if Count = 0 then
1824 return;
1825 end if;
1827 if Container.Busy > 0 then
1828 raise Program_Error
1829 with "attempt to tamper with cursors (tree is busy)";
1830 end if;
1832 declare
1833 -- The element allocator may need an accessibility check in the case
1834 -- the actual type is class-wide or has access discriminants (see
1835 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
1836 -- allocator in the loop below, because the one in this block would
1837 -- have failed already.
1839 pragma Unsuppress (Accessibility_Check);
1841 begin
1842 Element := new Element_Type'(New_Item);
1843 end;
1845 First := new Tree_Node_Type'(Parent => Parent.Node,
1846 Element => Element,
1847 others => <>);
1849 Last := First;
1851 for J in Count_Type'(2) .. Count loop
1853 -- Reclaim other nodes if Storage_Error. ???
1855 Element := new Element_Type'(New_Item);
1856 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1857 Prev => Last,
1858 Element => Element,
1859 others => <>);
1861 Last := Last.Next;
1862 end loop;
1864 Insert_Subtree_List
1865 (First => First,
1866 Last => Last,
1867 Parent => Parent.Node,
1868 Before => Parent.Node.Children.First);
1870 -- In order for operation Node_Count to complete in O(1) time, we cache
1871 -- the count value. Here we increment the total count by the number of
1872 -- nodes we just inserted.
1874 Container.Count := Container.Count + Count;
1875 end Prepend_Child;
1877 --------------
1878 -- Previous --
1879 --------------
1881 overriding function Previous
1882 (Object : Child_Iterator;
1883 Position : Cursor) return Cursor
1885 begin
1886 if Position.Container = null then
1887 return No_Element;
1888 end if;
1890 if Position.Container /= Object.Container then
1891 raise Program_Error with
1892 "Position cursor of Previous designates wrong tree";
1893 end if;
1895 return Previous_Sibling (Position);
1896 end Previous;
1898 ----------------------
1899 -- Previous_Sibling --
1900 ----------------------
1902 function Previous_Sibling (Position : Cursor) return Cursor is
1903 begin
1904 if Position = No_Element then
1905 return No_Element;
1906 end if;
1908 if Position.Node.Prev = null then
1909 return No_Element;
1910 end if;
1912 return Cursor'(Position.Container, Position.Node.Prev);
1913 end Previous_Sibling;
1915 procedure Previous_Sibling (Position : in out Cursor) is
1916 begin
1917 Position := Previous_Sibling (Position);
1918 end Previous_Sibling;
1920 -------------------
1921 -- Query_Element --
1922 -------------------
1924 procedure Query_Element
1925 (Position : Cursor;
1926 Process : not null access procedure (Element : Element_Type))
1928 begin
1929 if Position = No_Element then
1930 raise Constraint_Error with "Position cursor has no element";
1931 end if;
1933 if Is_Root (Position) then
1934 raise Program_Error with "Position cursor designates root";
1935 end if;
1937 declare
1938 T : Tree renames Position.Container.all'Unrestricted_Access.all;
1939 B : Natural renames T.Busy;
1940 L : Natural renames T.Lock;
1942 begin
1943 B := B + 1;
1944 L := L + 1;
1946 Process (Position.Node.Element.all);
1948 L := L - 1;
1949 B := B - 1;
1951 exception
1952 when others =>
1953 L := L - 1;
1954 B := B - 1;
1955 raise;
1956 end;
1957 end Query_Element;
1959 ----------
1960 -- Read --
1961 ----------
1963 procedure Read
1964 (Stream : not null access Root_Stream_Type'Class;
1965 Container : out Tree)
1967 procedure Read_Children (Subtree : Tree_Node_Access);
1969 function Read_Subtree
1970 (Parent : Tree_Node_Access) return Tree_Node_Access;
1972 Total_Count : Count_Type'Base;
1973 -- Value read from the stream that says how many elements follow
1975 Read_Count : Count_Type'Base;
1976 -- Actual number of elements read from the stream
1978 -------------------
1979 -- Read_Children --
1980 -------------------
1982 procedure Read_Children (Subtree : Tree_Node_Access) is
1983 pragma Assert (Subtree /= null);
1984 pragma Assert (Subtree.Children.First = null);
1985 pragma Assert (Subtree.Children.Last = null);
1987 Count : Count_Type'Base;
1988 -- Number of child subtrees
1990 C : Children_Type;
1992 begin
1993 Count_Type'Read (Stream, Count);
1995 if Count < 0 then
1996 raise Program_Error with "attempt to read from corrupt stream";
1997 end if;
1999 if Count = 0 then
2000 return;
2001 end if;
2003 C.First := Read_Subtree (Parent => Subtree);
2004 C.Last := C.First;
2006 for J in Count_Type'(2) .. Count loop
2007 C.Last.Next := Read_Subtree (Parent => Subtree);
2008 C.Last.Next.Prev := C.Last;
2009 C.Last := C.Last.Next;
2010 end loop;
2012 -- Now that the allocation and reads have completed successfully, it
2013 -- is safe to link the children to their parent.
2015 Subtree.Children := C;
2016 end Read_Children;
2018 ------------------
2019 -- Read_Subtree --
2020 ------------------
2022 function Read_Subtree
2023 (Parent : Tree_Node_Access) return Tree_Node_Access
2025 Element : constant Element_Access :=
2026 new Element_Type'(Element_Type'Input (Stream));
2028 Subtree : constant Tree_Node_Access :=
2029 new Tree_Node_Type'
2030 (Parent => Parent,
2031 Element => Element,
2032 others => <>);
2034 begin
2035 Read_Count := Read_Count + 1;
2037 Read_Children (Subtree);
2039 return Subtree;
2040 end Read_Subtree;
2042 -- Start of processing for Read
2044 begin
2045 Container.Clear; -- checks busy bit
2047 Count_Type'Read (Stream, Total_Count);
2049 if Total_Count < 0 then
2050 raise Program_Error with "attempt to read from corrupt stream";
2051 end if;
2053 if Total_Count = 0 then
2054 return;
2055 end if;
2057 Read_Count := 0;
2059 Read_Children (Root_Node (Container));
2061 if Read_Count /= Total_Count then
2062 raise Program_Error with "attempt to read from corrupt stream";
2063 end if;
2065 Container.Count := Total_Count;
2066 end Read;
2068 procedure Read
2069 (Stream : not null access Root_Stream_Type'Class;
2070 Position : out Cursor)
2072 begin
2073 raise Program_Error with "attempt to read tree cursor from stream";
2074 end Read;
2076 procedure Read
2077 (Stream : not null access Root_Stream_Type'Class;
2078 Item : out Reference_Type)
2080 begin
2081 raise Program_Error with "attempt to stream reference";
2082 end Read;
2084 procedure Read
2085 (Stream : not null access Root_Stream_Type'Class;
2086 Item : out Constant_Reference_Type)
2088 begin
2089 raise Program_Error with "attempt to stream reference";
2090 end Read;
2092 ---------------
2093 -- Reference --
2094 ---------------
2096 function Reference
2097 (Container : aliased in out Tree;
2098 Position : Cursor) return Reference_Type
2100 begin
2101 if Position.Container = null then
2102 raise Constraint_Error with
2103 "Position cursor has no element";
2104 end if;
2106 if Position.Container /= Container'Unrestricted_Access then
2107 raise Program_Error with
2108 "Position cursor designates wrong container";
2109 end if;
2111 if Position.Node = Root_Node (Container) then
2112 raise Program_Error with "Position cursor designates root";
2113 end if;
2115 if Position.Node.Element = null then
2116 raise Program_Error with "Node has no element";
2117 end if;
2119 -- Implement Vet for multiway tree???
2120 -- pragma Assert (Vet (Position),
2121 -- "Position cursor in Constant_Reference is bad");
2123 declare
2124 C : Tree renames Position.Container.all;
2125 B : Natural renames C.Busy;
2126 L : Natural renames C.Lock;
2127 begin
2128 return R : constant Reference_Type :=
2129 (Element => Position.Node.Element.all'Access,
2130 Control => (Controlled with Position.Container))
2132 B := B + 1;
2133 L := L + 1;
2134 end return;
2135 end;
2136 end Reference;
2138 --------------------
2139 -- Remove_Subtree --
2140 --------------------
2142 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2143 C : Children_Type renames Subtree.Parent.Children;
2145 begin
2146 -- This is a utility operation to remove a subtree node from its
2147 -- parent's list of children.
2149 if C.First = Subtree then
2150 pragma Assert (Subtree.Prev = null);
2152 if C.Last = Subtree then
2153 pragma Assert (Subtree.Next = null);
2154 C.First := null;
2155 C.Last := null;
2157 else
2158 C.First := Subtree.Next;
2159 C.First.Prev := null;
2160 end if;
2162 elsif C.Last = Subtree then
2163 pragma Assert (Subtree.Next = null);
2164 C.Last := Subtree.Prev;
2165 C.Last.Next := null;
2167 else
2168 Subtree.Prev.Next := Subtree.Next;
2169 Subtree.Next.Prev := Subtree.Prev;
2170 end if;
2171 end Remove_Subtree;
2173 ----------------------
2174 -- Replace_Element --
2175 ----------------------
2177 procedure Replace_Element
2178 (Container : in out Tree;
2179 Position : Cursor;
2180 New_Item : Element_Type)
2182 E, X : Element_Access;
2184 begin
2185 if Position = No_Element then
2186 raise Constraint_Error with "Position cursor has no element";
2187 end if;
2189 if Position.Container /= Container'Unrestricted_Access then
2190 raise Program_Error with "Position cursor not in container";
2191 end if;
2193 if Is_Root (Position) then
2194 raise Program_Error with "Position cursor designates root";
2195 end if;
2197 if Container.Lock > 0 then
2198 raise Program_Error
2199 with "attempt to tamper with elements (tree is locked)";
2200 end if;
2202 declare
2203 -- The element allocator may need an accessibility check in the case
2204 -- the actual type is class-wide or has access discriminants (see
2205 -- RM 4.8(10.1) and AI12-0035).
2207 pragma Unsuppress (Accessibility_Check);
2209 begin
2210 E := new Element_Type'(New_Item);
2211 end;
2213 X := Position.Node.Element;
2214 Position.Node.Element := E;
2216 Free_Element (X);
2217 end Replace_Element;
2219 ------------------------------
2220 -- Reverse_Iterate_Children --
2221 ------------------------------
2223 procedure Reverse_Iterate_Children
2224 (Parent : Cursor;
2225 Process : not null access procedure (Position : Cursor))
2227 begin
2228 if Parent = No_Element then
2229 raise Constraint_Error with "Parent cursor has no element";
2230 end if;
2232 declare
2233 B : Natural renames Parent.Container.Busy;
2234 C : Tree_Node_Access;
2236 begin
2237 B := B + 1;
2239 C := Parent.Node.Children.Last;
2240 while C /= null loop
2241 Process (Position => Cursor'(Parent.Container, Node => C));
2242 C := C.Prev;
2243 end loop;
2245 B := B - 1;
2247 exception
2248 when others =>
2249 B := B - 1;
2250 raise;
2251 end;
2252 end Reverse_Iterate_Children;
2254 ----------
2255 -- Root --
2256 ----------
2258 function Root (Container : Tree) return Cursor is
2259 begin
2260 return (Container'Unrestricted_Access, Root_Node (Container));
2261 end Root;
2263 ---------------
2264 -- Root_Node --
2265 ---------------
2267 function Root_Node (Container : Tree) return Tree_Node_Access is
2268 begin
2269 return Container.Root'Unrestricted_Access;
2270 end Root_Node;
2272 ---------------------
2273 -- Splice_Children --
2274 ---------------------
2276 procedure Splice_Children
2277 (Target : in out Tree;
2278 Target_Parent : Cursor;
2279 Before : Cursor;
2280 Source : in out Tree;
2281 Source_Parent : Cursor)
2283 Count : Count_Type;
2285 begin
2286 if Target_Parent = No_Element then
2287 raise Constraint_Error with "Target_Parent cursor has no element";
2288 end if;
2290 if Target_Parent.Container /= Target'Unrestricted_Access then
2291 raise Program_Error
2292 with "Target_Parent cursor not in Target container";
2293 end if;
2295 if Before /= No_Element then
2296 if Before.Container /= Target'Unrestricted_Access then
2297 raise Program_Error
2298 with "Before cursor not in Target container";
2299 end if;
2301 if Before.Node.Parent /= Target_Parent.Node then
2302 raise Constraint_Error
2303 with "Before cursor not child of Target_Parent";
2304 end if;
2305 end if;
2307 if Source_Parent = No_Element then
2308 raise Constraint_Error with "Source_Parent cursor has no element";
2309 end if;
2311 if Source_Parent.Container /= Source'Unrestricted_Access then
2312 raise Program_Error
2313 with "Source_Parent cursor not in Source container";
2314 end if;
2316 if Target'Address = Source'Address then
2317 if Target_Parent = Source_Parent then
2318 return;
2319 end if;
2321 if Target.Busy > 0 then
2322 raise Program_Error
2323 with "attempt to tamper with cursors (Target tree is busy)";
2324 end if;
2326 if Is_Reachable (From => Target_Parent.Node,
2327 To => Source_Parent.Node)
2328 then
2329 raise Constraint_Error
2330 with "Source_Parent is ancestor of Target_Parent";
2331 end if;
2333 Splice_Children
2334 (Target_Parent => Target_Parent.Node,
2335 Before => Before.Node,
2336 Source_Parent => Source_Parent.Node);
2338 return;
2339 end if;
2341 if Target.Busy > 0 then
2342 raise Program_Error
2343 with "attempt to tamper with cursors (Target tree is busy)";
2344 end if;
2346 if Source.Busy > 0 then
2347 raise Program_Error
2348 with "attempt to tamper with cursors (Source tree is busy)";
2349 end if;
2351 -- We cache the count of the nodes we have allocated, so that operation
2352 -- Node_Count can execute in O(1) time. But that means we must count the
2353 -- nodes in the subtree we remove from Source and insert into Target, in
2354 -- order to keep the count accurate.
2356 Count := Subtree_Node_Count (Source_Parent.Node);
2357 pragma Assert (Count >= 1);
2359 Count := Count - 1; -- because Source_Parent node does not move
2361 Splice_Children
2362 (Target_Parent => Target_Parent.Node,
2363 Before => Before.Node,
2364 Source_Parent => Source_Parent.Node);
2366 Source.Count := Source.Count - Count;
2367 Target.Count := Target.Count + Count;
2368 end Splice_Children;
2370 procedure Splice_Children
2371 (Container : in out Tree;
2372 Target_Parent : Cursor;
2373 Before : Cursor;
2374 Source_Parent : Cursor)
2376 begin
2377 if Target_Parent = No_Element then
2378 raise Constraint_Error with "Target_Parent cursor has no element";
2379 end if;
2381 if Target_Parent.Container /= Container'Unrestricted_Access then
2382 raise Program_Error
2383 with "Target_Parent cursor not in container";
2384 end if;
2386 if Before /= No_Element then
2387 if Before.Container /= Container'Unrestricted_Access then
2388 raise Program_Error
2389 with "Before cursor not in container";
2390 end if;
2392 if Before.Node.Parent /= Target_Parent.Node then
2393 raise Constraint_Error
2394 with "Before cursor not child of Target_Parent";
2395 end if;
2396 end if;
2398 if Source_Parent = No_Element then
2399 raise Constraint_Error with "Source_Parent cursor has no element";
2400 end if;
2402 if Source_Parent.Container /= Container'Unrestricted_Access then
2403 raise Program_Error
2404 with "Source_Parent cursor not in container";
2405 end if;
2407 if Target_Parent = Source_Parent then
2408 return;
2409 end if;
2411 if Container.Busy > 0 then
2412 raise Program_Error
2413 with "attempt to tamper with cursors (tree is busy)";
2414 end if;
2416 if Is_Reachable (From => Target_Parent.Node,
2417 To => Source_Parent.Node)
2418 then
2419 raise Constraint_Error
2420 with "Source_Parent is ancestor of Target_Parent";
2421 end if;
2423 Splice_Children
2424 (Target_Parent => Target_Parent.Node,
2425 Before => Before.Node,
2426 Source_Parent => Source_Parent.Node);
2427 end Splice_Children;
2429 procedure Splice_Children
2430 (Target_Parent : Tree_Node_Access;
2431 Before : Tree_Node_Access;
2432 Source_Parent : Tree_Node_Access)
2434 CC : constant Children_Type := Source_Parent.Children;
2435 C : Tree_Node_Access;
2437 begin
2438 -- This is a utility operation to remove the children from Source parent
2439 -- and insert them into Target parent.
2441 Source_Parent.Children := Children_Type'(others => null);
2443 -- Fix up the Parent pointers of each child to designate its new Target
2444 -- parent.
2446 C := CC.First;
2447 while C /= null loop
2448 C.Parent := Target_Parent;
2449 C := C.Next;
2450 end loop;
2452 Insert_Subtree_List
2453 (First => CC.First,
2454 Last => CC.Last,
2455 Parent => Target_Parent,
2456 Before => Before);
2457 end Splice_Children;
2459 --------------------
2460 -- Splice_Subtree --
2461 --------------------
2463 procedure Splice_Subtree
2464 (Target : in out Tree;
2465 Parent : Cursor;
2466 Before : Cursor;
2467 Source : in out Tree;
2468 Position : in out Cursor)
2470 Subtree_Count : Count_Type;
2472 begin
2473 if Parent = No_Element then
2474 raise Constraint_Error with "Parent cursor has no element";
2475 end if;
2477 if Parent.Container /= Target'Unrestricted_Access then
2478 raise Program_Error with "Parent cursor not in Target container";
2479 end if;
2481 if Before /= No_Element then
2482 if Before.Container /= Target'Unrestricted_Access then
2483 raise Program_Error with "Before cursor not in Target container";
2484 end if;
2486 if Before.Node.Parent /= Parent.Node then
2487 raise Constraint_Error with "Before cursor not child of Parent";
2488 end if;
2489 end if;
2491 if Position = No_Element then
2492 raise Constraint_Error with "Position cursor has no element";
2493 end if;
2495 if Position.Container /= Source'Unrestricted_Access then
2496 raise Program_Error with "Position cursor not in Source container";
2497 end if;
2499 if Is_Root (Position) then
2500 raise Program_Error with "Position cursor designates root";
2501 end if;
2503 if Target'Address = Source'Address then
2504 if Position.Node.Parent = Parent.Node then
2505 if Position.Node = Before.Node then
2506 return;
2507 end if;
2509 if Position.Node.Next = Before.Node then
2510 return;
2511 end if;
2512 end if;
2514 if Target.Busy > 0 then
2515 raise Program_Error
2516 with "attempt to tamper with cursors (Target tree is busy)";
2517 end if;
2519 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2520 raise Constraint_Error with "Position is ancestor of Parent";
2521 end if;
2523 Remove_Subtree (Position.Node);
2525 Position.Node.Parent := Parent.Node;
2526 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2528 return;
2529 end if;
2531 if Target.Busy > 0 then
2532 raise Program_Error
2533 with "attempt to tamper with cursors (Target tree is busy)";
2534 end if;
2536 if Source.Busy > 0 then
2537 raise Program_Error
2538 with "attempt to tamper with cursors (Source tree is busy)";
2539 end if;
2541 -- This is an unfortunate feature of this API: we must count the nodes
2542 -- in the subtree that we remove from the source tree, which is an O(n)
2543 -- operation. It would have been better if the Tree container did not
2544 -- have a Node_Count selector; a user that wants the number of nodes in
2545 -- the tree could simply call Subtree_Node_Count, with the understanding
2546 -- that such an operation is O(n).
2548 -- Of course, we could choose to implement the Node_Count selector as an
2549 -- O(n) operation, which would turn this splice operation into an O(1)
2550 -- operation. ???
2552 Subtree_Count := Subtree_Node_Count (Position.Node);
2553 pragma Assert (Subtree_Count <= Source.Count);
2555 Remove_Subtree (Position.Node);
2556 Source.Count := Source.Count - Subtree_Count;
2558 Position.Node.Parent := Parent.Node;
2559 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2561 Target.Count := Target.Count + Subtree_Count;
2563 Position.Container := Target'Unrestricted_Access;
2564 end Splice_Subtree;
2566 procedure Splice_Subtree
2567 (Container : in out Tree;
2568 Parent : Cursor;
2569 Before : Cursor;
2570 Position : Cursor)
2572 begin
2573 if Parent = No_Element then
2574 raise Constraint_Error with "Parent cursor has no element";
2575 end if;
2577 if Parent.Container /= Container'Unrestricted_Access then
2578 raise Program_Error with "Parent cursor not in container";
2579 end if;
2581 if Before /= No_Element then
2582 if Before.Container /= Container'Unrestricted_Access then
2583 raise Program_Error with "Before cursor not in container";
2584 end if;
2586 if Before.Node.Parent /= Parent.Node then
2587 raise Constraint_Error with "Before cursor not child of Parent";
2588 end if;
2589 end if;
2591 if Position = No_Element then
2592 raise Constraint_Error with "Position cursor has no element";
2593 end if;
2595 if Position.Container /= Container'Unrestricted_Access then
2596 raise Program_Error with "Position cursor not in container";
2597 end if;
2599 if Is_Root (Position) then
2601 -- Should this be PE instead? Need ARG confirmation. ???
2603 raise Constraint_Error with "Position cursor designates root";
2604 end if;
2606 if Position.Node.Parent = Parent.Node then
2607 if Position.Node = Before.Node then
2608 return;
2609 end if;
2611 if Position.Node.Next = Before.Node then
2612 return;
2613 end if;
2614 end if;
2616 if Container.Busy > 0 then
2617 raise Program_Error
2618 with "attempt to tamper with cursors (tree is busy)";
2619 end if;
2621 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2622 raise Constraint_Error with "Position is ancestor of Parent";
2623 end if;
2625 Remove_Subtree (Position.Node);
2627 Position.Node.Parent := Parent.Node;
2628 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2629 end Splice_Subtree;
2631 ------------------------
2632 -- Subtree_Node_Count --
2633 ------------------------
2635 function Subtree_Node_Count (Position : Cursor) return Count_Type is
2636 begin
2637 if Position = No_Element then
2638 return 0;
2639 end if;
2641 return Subtree_Node_Count (Position.Node);
2642 end Subtree_Node_Count;
2644 function Subtree_Node_Count
2645 (Subtree : Tree_Node_Access) return Count_Type
2647 Result : Count_Type;
2648 Node : Tree_Node_Access;
2650 begin
2651 Result := 1;
2652 Node := Subtree.Children.First;
2653 while Node /= null loop
2654 Result := Result + Subtree_Node_Count (Node);
2655 Node := Node.Next;
2656 end loop;
2658 return Result;
2659 end Subtree_Node_Count;
2661 ----------
2662 -- Swap --
2663 ----------
2665 procedure Swap
2666 (Container : in out Tree;
2667 I, J : Cursor)
2669 begin
2670 if I = No_Element then
2671 raise Constraint_Error with "I cursor has no element";
2672 end if;
2674 if I.Container /= Container'Unrestricted_Access then
2675 raise Program_Error with "I cursor not in container";
2676 end if;
2678 if Is_Root (I) then
2679 raise Program_Error with "I cursor designates root";
2680 end if;
2682 if I = J then -- make this test sooner???
2683 return;
2684 end if;
2686 if J = No_Element then
2687 raise Constraint_Error with "J cursor has no element";
2688 end if;
2690 if J.Container /= Container'Unrestricted_Access then
2691 raise Program_Error with "J cursor not in container";
2692 end if;
2694 if Is_Root (J) then
2695 raise Program_Error with "J cursor designates root";
2696 end if;
2698 if Container.Lock > 0 then
2699 raise Program_Error
2700 with "attempt to tamper with elements (tree is locked)";
2701 end if;
2703 declare
2704 EI : constant Element_Access := I.Node.Element;
2706 begin
2707 I.Node.Element := J.Node.Element;
2708 J.Node.Element := EI;
2709 end;
2710 end Swap;
2712 --------------------
2713 -- Update_Element --
2714 --------------------
2716 procedure Update_Element
2717 (Container : in out Tree;
2718 Position : Cursor;
2719 Process : not null access procedure (Element : in out Element_Type))
2721 begin
2722 if Position = No_Element then
2723 raise Constraint_Error with "Position cursor has no element";
2724 end if;
2726 if Position.Container /= Container'Unrestricted_Access then
2727 raise Program_Error with "Position cursor not in container";
2728 end if;
2730 if Is_Root (Position) then
2731 raise Program_Error with "Position cursor designates root";
2732 end if;
2734 declare
2735 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2736 B : Natural renames T.Busy;
2737 L : Natural renames T.Lock;
2739 begin
2740 B := B + 1;
2741 L := L + 1;
2743 Process (Position.Node.Element.all);
2745 L := L - 1;
2746 B := B - 1;
2748 exception
2749 when others =>
2750 L := L - 1;
2751 B := B - 1;
2752 raise;
2753 end;
2754 end Update_Element;
2756 -----------
2757 -- Write --
2758 -----------
2760 procedure Write
2761 (Stream : not null access Root_Stream_Type'Class;
2762 Container : Tree)
2764 procedure Write_Children (Subtree : Tree_Node_Access);
2765 procedure Write_Subtree (Subtree : Tree_Node_Access);
2767 --------------------
2768 -- Write_Children --
2769 --------------------
2771 procedure Write_Children (Subtree : Tree_Node_Access) is
2772 CC : Children_Type renames Subtree.Children;
2773 C : Tree_Node_Access;
2775 begin
2776 Count_Type'Write (Stream, Child_Count (CC));
2778 C := CC.First;
2779 while C /= null loop
2780 Write_Subtree (C);
2781 C := C.Next;
2782 end loop;
2783 end Write_Children;
2785 -------------------
2786 -- Write_Subtree --
2787 -------------------
2789 procedure Write_Subtree (Subtree : Tree_Node_Access) is
2790 begin
2791 Element_Type'Output (Stream, Subtree.Element.all);
2792 Write_Children (Subtree);
2793 end Write_Subtree;
2795 -- Start of processing for Write
2797 begin
2798 Count_Type'Write (Stream, Container.Count);
2800 if Container.Count = 0 then
2801 return;
2802 end if;
2804 Write_Children (Root_Node (Container));
2805 end Write;
2807 procedure Write
2808 (Stream : not null access Root_Stream_Type'Class;
2809 Position : Cursor)
2811 begin
2812 raise Program_Error with "attempt to write tree cursor to stream";
2813 end Write;
2815 procedure Write
2816 (Stream : not null access Root_Stream_Type'Class;
2817 Item : Reference_Type)
2819 begin
2820 raise Program_Error with "attempt to stream reference";
2821 end Write;
2823 procedure Write
2824 (Stream : not null access Root_Stream_Type'Class;
2825 Item : Constant_Reference_Type)
2827 begin
2828 raise Program_Error with "attempt to stream reference";
2829 end Write;
2831 end Ada.Containers.Indefinite_Multiway_Trees;