more autogen definiton
[official-gcc.git] / gcc / ada / a-cimutr.adb
blob050c0395deeb23b0186a5251cd9a756d7c567432
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 Element := new Element_Type'(New_Item);
295 First := new Tree_Node_Type'(Parent => Parent.Node,
296 Element => Element,
297 others => <>);
299 Last := First;
301 for J in Count_Type'(2) .. Count loop
303 -- Reclaim other nodes if Storage_Error. ???
305 Element := new Element_Type'(New_Item);
306 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
307 Prev => Last,
308 Element => Element,
309 others => <>);
311 Last := Last.Next;
312 end loop;
314 Insert_Subtree_List
315 (First => First,
316 Last => Last,
317 Parent => Parent.Node,
318 Before => null); -- null means "insert at end of list"
320 -- In order for operation Node_Count to complete in O(1) time, we cache
321 -- the count value. Here we increment the total count by the number of
322 -- nodes we just inserted.
324 Container.Count := Container.Count + Count;
325 end Append_Child;
327 ------------
328 -- Assign --
329 ------------
331 procedure Assign (Target : in out Tree; Source : Tree) is
332 Source_Count : constant Count_Type := Source.Count;
333 Target_Count : Count_Type;
335 begin
336 if Target'Address = Source'Address then
337 return;
338 end if;
340 Target.Clear; -- checks busy bit
342 -- Copy_Children returns the number of nodes that it allocates, but it
343 -- does this by incrementing the count value passed in, so we must
344 -- initialize the count before calling Copy_Children.
346 Target_Count := 0;
348 -- Note that Copy_Children inserts the newly-allocated children into
349 -- their parent list only after the allocation of all the children has
350 -- succeeded. This preserves invariants even if the allocation fails.
352 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
353 pragma Assert (Target_Count = Source_Count);
355 Target.Count := Source_Count;
356 end Assign;
358 -----------------
359 -- Child_Count --
360 -----------------
362 function Child_Count (Parent : Cursor) return Count_Type is
363 begin
364 if Parent = No_Element then
365 return 0;
366 else
367 return Child_Count (Parent.Node.Children);
368 end if;
369 end Child_Count;
371 function Child_Count (Children : Children_Type) return Count_Type is
372 Result : Count_Type;
373 Node : Tree_Node_Access;
375 begin
376 Result := 0;
377 Node := Children.First;
378 while Node /= null loop
379 Result := Result + 1;
380 Node := Node.Next;
381 end loop;
383 return Result;
384 end Child_Count;
386 -----------------
387 -- Child_Depth --
388 -----------------
390 function Child_Depth (Parent, Child : Cursor) return Count_Type is
391 Result : Count_Type;
392 N : Tree_Node_Access;
394 begin
395 if Parent = No_Element then
396 raise Constraint_Error with "Parent cursor has no element";
397 end if;
399 if Child = No_Element then
400 raise Constraint_Error with "Child cursor has no element";
401 end if;
403 if Parent.Container /= Child.Container then
404 raise Program_Error with "Parent and Child in different containers";
405 end if;
407 Result := 0;
408 N := Child.Node;
409 while N /= Parent.Node loop
410 Result := Result + 1;
411 N := N.Parent;
413 if N = null then
414 raise Program_Error with "Parent is not ancestor of Child";
415 end if;
416 end loop;
418 return Result;
419 end Child_Depth;
421 -----------
422 -- Clear --
423 -----------
425 procedure Clear (Container : in out Tree) is
426 Container_Count : Count_Type;
427 Children_Count : Count_Type;
429 begin
430 if Container.Busy > 0 then
431 raise Program_Error
432 with "attempt to tamper with cursors (tree is busy)";
433 end if;
435 -- We first set the container count to 0, in order to preserve
436 -- invariants in case the deallocation fails. (This works because
437 -- Deallocate_Children immediately removes the children from their
438 -- parent, and then does the actual deallocation.)
440 Container_Count := Container.Count;
441 Container.Count := 0;
443 -- Deallocate_Children returns the number of nodes that it deallocates,
444 -- but it does this by incrementing the count value that is passed in,
445 -- so we must first initialize the count return value before calling it.
447 Children_Count := 0;
449 -- See comment above. Deallocate_Children immediately removes the
450 -- children list from their parent node (here, the root of the tree),
451 -- and only after that does it attempt the actual deallocation. So even
452 -- if the deallocation fails, the representation invariants
454 Deallocate_Children (Root_Node (Container), Children_Count);
455 pragma Assert (Children_Count = Container_Count);
456 end Clear;
458 ------------------------
459 -- Constant_Reference --
460 ------------------------
462 function Constant_Reference
463 (Container : aliased Tree;
464 Position : Cursor) return Constant_Reference_Type
466 begin
467 if Position.Container = null then
468 raise Constraint_Error with
469 "Position cursor has no element";
470 end if;
472 if Position.Container /= Container'Unrestricted_Access then
473 raise Program_Error with
474 "Position cursor designates wrong container";
475 end if;
477 if Position.Node = Root_Node (Container) then
478 raise Program_Error with "Position cursor designates root";
479 end if;
481 if Position.Node.Element = null then
482 raise Program_Error with "Node has no element";
483 end if;
485 -- Implement Vet for multiway tree???
486 -- pragma Assert (Vet (Position),
487 -- "Position cursor in Constant_Reference is bad");
489 declare
490 C : Tree renames Position.Container.all;
491 B : Natural renames C.Busy;
492 L : Natural renames C.Lock;
493 begin
494 return R : constant Constant_Reference_Type :=
495 (Element => Position.Node.Element.all'Access,
496 Control =>
497 (Controlled with Container'Unrestricted_Access))
499 B := B + 1;
500 L := L + 1;
501 end return;
502 end;
503 end Constant_Reference;
505 --------------
506 -- Contains --
507 --------------
509 function Contains
510 (Container : Tree;
511 Item : Element_Type) return Boolean
513 begin
514 return Find (Container, Item) /= No_Element;
515 end Contains;
517 ----------
518 -- Copy --
519 ----------
521 function Copy (Source : Tree) return Tree is
522 begin
523 return Target : Tree do
524 Copy_Children
525 (Source => Source.Root.Children,
526 Parent => Root_Node (Target),
527 Count => Target.Count);
529 pragma Assert (Target.Count = Source.Count);
530 end return;
531 end Copy;
533 -------------------
534 -- Copy_Children --
535 -------------------
537 procedure Copy_Children
538 (Source : Children_Type;
539 Parent : Tree_Node_Access;
540 Count : in out Count_Type)
542 pragma Assert (Parent /= null);
543 pragma Assert (Parent.Children.First = null);
544 pragma Assert (Parent.Children.Last = null);
546 CC : Children_Type;
547 C : Tree_Node_Access;
549 begin
550 -- We special-case the first allocation, in order to establish the
551 -- representation invariants for type Children_Type.
553 C := Source.First;
555 if C = null then
556 return;
557 end if;
559 Copy_Subtree
560 (Source => C,
561 Parent => Parent,
562 Target => CC.First,
563 Count => Count);
565 CC.Last := CC.First;
567 -- The representation invariants for the Children_Type list have been
568 -- established, so we can now copy the remaining children of Source.
570 C := C.Next;
571 while C /= null loop
572 Copy_Subtree
573 (Source => C,
574 Parent => Parent,
575 Target => CC.Last.Next,
576 Count => Count);
578 CC.Last.Next.Prev := CC.Last;
579 CC.Last := CC.Last.Next;
581 C := C.Next;
582 end loop;
584 -- We add the newly-allocated children to their parent list only after
585 -- the allocation has succeeded, in order to preserve invariants of the
586 -- parent.
588 Parent.Children := CC;
589 end Copy_Children;
591 ------------------
592 -- Copy_Subtree --
593 ------------------
595 procedure Copy_Subtree
596 (Target : in out Tree;
597 Parent : Cursor;
598 Before : Cursor;
599 Source : Cursor)
601 Target_Subtree : Tree_Node_Access;
602 Target_Count : Count_Type;
604 begin
605 if Parent = No_Element then
606 raise Constraint_Error with "Parent cursor has no element";
607 end if;
609 if Parent.Container /= Target'Unrestricted_Access then
610 raise Program_Error with "Parent cursor not in container";
611 end if;
613 if Before /= No_Element then
614 if Before.Container /= Target'Unrestricted_Access then
615 raise Program_Error with "Before cursor not in container";
616 end if;
618 if Before.Node.Parent /= Parent.Node then
619 raise Constraint_Error with "Before cursor not child of Parent";
620 end if;
621 end if;
623 if Source = No_Element then
624 return;
625 end if;
627 if Is_Root (Source) then
628 raise Constraint_Error with "Source cursor designates root";
629 end if;
631 -- Copy_Subtree returns a count of the number of nodes that it
632 -- allocates, but it works by incrementing the value that is passed in.
633 -- We must therefore initialize the count value before calling
634 -- Copy_Subtree.
636 Target_Count := 0;
638 Copy_Subtree
639 (Source => Source.Node,
640 Parent => Parent.Node,
641 Target => Target_Subtree,
642 Count => Target_Count);
644 pragma Assert (Target_Subtree /= null);
645 pragma Assert (Target_Subtree.Parent = Parent.Node);
646 pragma Assert (Target_Count >= 1);
648 Insert_Subtree_Node
649 (Subtree => Target_Subtree,
650 Parent => Parent.Node,
651 Before => Before.Node);
653 -- In order for operation Node_Count to complete in O(1) time, we cache
654 -- the count value. Here we increment the total count by the number of
655 -- nodes we just inserted.
657 Target.Count := Target.Count + Target_Count;
658 end Copy_Subtree;
660 procedure Copy_Subtree
661 (Source : Tree_Node_Access;
662 Parent : Tree_Node_Access;
663 Target : out Tree_Node_Access;
664 Count : in out Count_Type)
666 E : constant Element_Access := new Element_Type'(Source.Element.all);
668 begin
669 Target := new Tree_Node_Type'(Element => E,
670 Parent => Parent,
671 others => <>);
673 Count := Count + 1;
675 Copy_Children
676 (Source => Source.Children,
677 Parent => Target,
678 Count => Count);
679 end Copy_Subtree;
681 -------------------------
682 -- Deallocate_Children --
683 -------------------------
685 procedure Deallocate_Children
686 (Subtree : Tree_Node_Access;
687 Count : in out Count_Type)
689 pragma Assert (Subtree /= null);
691 CC : Children_Type := Subtree.Children;
692 C : Tree_Node_Access;
694 begin
695 -- We immediately remove the children from their parent, in order to
696 -- preserve invariants in case the deallocation fails.
698 Subtree.Children := Children_Type'(others => null);
700 while CC.First /= null loop
701 C := CC.First;
702 CC.First := C.Next;
704 Deallocate_Subtree (C, Count);
705 end loop;
706 end Deallocate_Children;
708 ---------------------
709 -- Deallocate_Node --
710 ---------------------
712 procedure Deallocate_Node (X : in out Tree_Node_Access) is
713 procedure Free_Node is
714 new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access);
716 -- Start of processing for Deallocate_Node
718 begin
719 if X /= null then
720 Free_Element (X.Element);
721 Free_Node (X);
722 end if;
723 end Deallocate_Node;
725 ------------------------
726 -- Deallocate_Subtree --
727 ------------------------
729 procedure Deallocate_Subtree
730 (Subtree : in out Tree_Node_Access;
731 Count : in out Count_Type)
733 begin
734 Deallocate_Children (Subtree, Count);
735 Deallocate_Node (Subtree);
736 Count := Count + 1;
737 end Deallocate_Subtree;
739 ---------------------
740 -- Delete_Children --
741 ---------------------
743 procedure Delete_Children
744 (Container : in out Tree;
745 Parent : Cursor)
747 Count : Count_Type;
749 begin
750 if Parent = No_Element then
751 raise Constraint_Error with "Parent cursor has no element";
752 end if;
754 if Parent.Container /= Container'Unrestricted_Access then
755 raise Program_Error with "Parent cursor not in container";
756 end if;
758 if Container.Busy > 0 then
759 raise Program_Error
760 with "attempt to tamper with cursors (tree is busy)";
761 end if;
763 -- Deallocate_Children returns a count of the number of nodes
764 -- that it deallocates, but it works by incrementing the
765 -- value that is passed in. We must therefore initialize
766 -- the count value before calling Deallocate_Children.
768 Count := 0;
770 Deallocate_Children (Parent.Node, Count);
771 pragma Assert (Count <= Container.Count);
773 Container.Count := Container.Count - Count;
774 end Delete_Children;
776 -----------------
777 -- Delete_Leaf --
778 -----------------
780 procedure Delete_Leaf
781 (Container : in out Tree;
782 Position : in out Cursor)
784 X : Tree_Node_Access;
786 begin
787 if Position = No_Element then
788 raise Constraint_Error with "Position cursor has no element";
789 end if;
791 if Position.Container /= Container'Unrestricted_Access then
792 raise Program_Error with "Position cursor not in container";
793 end if;
795 if Is_Root (Position) then
796 raise Program_Error with "Position cursor designates root";
797 end if;
799 if not Is_Leaf (Position) then
800 raise Constraint_Error with "Position cursor does not designate leaf";
801 end if;
803 if Container.Busy > 0 then
804 raise Program_Error
805 with "attempt to tamper with cursors (tree is busy)";
806 end if;
808 X := Position.Node;
809 Position := No_Element;
811 -- Restore represention invariants before attempting the actual
812 -- deallocation.
814 Remove_Subtree (X);
815 Container.Count := Container.Count - 1;
817 -- It is now safe to attempt the deallocation. This leaf node has been
818 -- disassociated from the tree, so even if the deallocation fails,
819 -- representation invariants will remain satisfied.
821 Deallocate_Node (X);
822 end Delete_Leaf;
824 --------------------
825 -- Delete_Subtree --
826 --------------------
828 procedure Delete_Subtree
829 (Container : in out Tree;
830 Position : in out Cursor)
832 X : Tree_Node_Access;
833 Count : Count_Type;
835 begin
836 if Position = No_Element then
837 raise Constraint_Error with "Position cursor has no element";
838 end if;
840 if Position.Container /= Container'Unrestricted_Access then
841 raise Program_Error with "Position cursor not in container";
842 end if;
844 if Is_Root (Position) then
845 raise Program_Error with "Position cursor designates root";
846 end if;
848 if Container.Busy > 0 then
849 raise Program_Error
850 with "attempt to tamper with cursors (tree is busy)";
851 end if;
853 X := Position.Node;
854 Position := No_Element;
856 -- Here is one case where a deallocation failure can result in the
857 -- violation of a representation invariant. We disassociate the subtree
858 -- from the tree now, but we only decrement the total node count after
859 -- we attempt the deallocation. However, if the deallocation fails, the
860 -- total node count will not get decremented.
862 -- One way around this dilemma is to count the nodes in the subtree
863 -- before attempt to delete the subtree, but that is an O(n) operation,
864 -- so it does not seem worth it.
866 -- Perhaps this is much ado about nothing, since the only way
867 -- deallocation can fail is if Controlled Finalization fails: this
868 -- propagates Program_Error so all bets are off anyway. ???
870 Remove_Subtree (X);
872 -- Deallocate_Subtree returns a count of the number of nodes that it
873 -- deallocates, but it works by incrementing the value that is passed
874 -- in. We must therefore initialize the count value before calling
875 -- Deallocate_Subtree.
877 Count := 0;
879 Deallocate_Subtree (X, Count);
880 pragma Assert (Count <= Container.Count);
882 -- See comments above. We would prefer to do this sooner, but there's no
883 -- way to satisfy that goal without an potentially severe execution
884 -- penalty.
886 Container.Count := Container.Count - Count;
887 end Delete_Subtree;
889 -----------
890 -- Depth --
891 -----------
893 function Depth (Position : Cursor) return Count_Type is
894 Result : Count_Type;
895 N : Tree_Node_Access;
897 begin
898 Result := 0;
899 N := Position.Node;
900 while N /= null loop
901 N := N.Parent;
902 Result := Result + 1;
903 end loop;
905 return Result;
906 end Depth;
908 -------------
909 -- Element --
910 -------------
912 function Element (Position : Cursor) return Element_Type is
913 begin
914 if Position.Container = null then
915 raise Constraint_Error with "Position cursor has no element";
916 end if;
918 if Position.Node = Root_Node (Position.Container.all) then
919 raise Program_Error with "Position cursor designates root";
920 end if;
922 return Position.Node.Element.all;
923 end Element;
925 --------------------
926 -- Equal_Children --
927 --------------------
929 function Equal_Children
930 (Left_Subtree : Tree_Node_Access;
931 Right_Subtree : Tree_Node_Access) return Boolean
933 Left_Children : Children_Type renames Left_Subtree.Children;
934 Right_Children : Children_Type renames Right_Subtree.Children;
936 L, R : Tree_Node_Access;
938 begin
939 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
940 return False;
941 end if;
943 L := Left_Children.First;
944 R := Right_Children.First;
945 while L /= null loop
946 if not Equal_Subtree (L, R) then
947 return False;
948 end if;
950 L := L.Next;
951 R := R.Next;
952 end loop;
954 return True;
955 end Equal_Children;
957 -------------------
958 -- Equal_Subtree --
959 -------------------
961 function Equal_Subtree
962 (Left_Position : Cursor;
963 Right_Position : Cursor) return Boolean
965 begin
966 if Left_Position = No_Element then
967 raise Constraint_Error with "Left cursor has no element";
968 end if;
970 if Right_Position = No_Element then
971 raise Constraint_Error with "Right cursor has no element";
972 end if;
974 if Left_Position = Right_Position then
975 return True;
976 end if;
978 if Is_Root (Left_Position) then
979 if not Is_Root (Right_Position) then
980 return False;
981 end if;
983 return Equal_Children (Left_Position.Node, Right_Position.Node);
984 end if;
986 if Is_Root (Right_Position) then
987 return False;
988 end if;
990 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
991 end Equal_Subtree;
993 function Equal_Subtree
994 (Left_Subtree : Tree_Node_Access;
995 Right_Subtree : Tree_Node_Access) return Boolean
997 begin
998 if Left_Subtree.Element.all /= Right_Subtree.Element.all then
999 return False;
1000 end if;
1002 return Equal_Children (Left_Subtree, Right_Subtree);
1003 end Equal_Subtree;
1005 --------------
1006 -- Finalize --
1007 --------------
1009 procedure Finalize (Object : in out Root_Iterator) is
1010 B : Natural renames Object.Container.Busy;
1011 begin
1012 B := B - 1;
1013 end Finalize;
1015 procedure Finalize (Control : in out Reference_Control_Type) is
1016 begin
1017 if Control.Container /= null then
1018 declare
1019 C : Tree renames Control.Container.all;
1020 B : Natural renames C.Busy;
1021 L : Natural renames C.Lock;
1022 begin
1023 B := B - 1;
1024 L := L - 1;
1025 end;
1027 Control.Container := null;
1028 end if;
1029 end Finalize;
1031 ----------
1032 -- Find --
1033 ----------
1035 function Find
1036 (Container : Tree;
1037 Item : Element_Type) return Cursor
1039 N : constant Tree_Node_Access :=
1040 Find_In_Children (Root_Node (Container), Item);
1042 begin
1043 if N = null then
1044 return No_Element;
1045 end if;
1047 return Cursor'(Container'Unrestricted_Access, N);
1048 end Find;
1050 -----------
1051 -- First --
1052 -----------
1054 overriding function First (Object : Subtree_Iterator) return Cursor is
1055 begin
1056 if Object.Subtree = Root_Node (Object.Container.all) then
1057 return First_Child (Root (Object.Container.all));
1058 else
1059 return Cursor'(Object.Container, Object.Subtree);
1060 end if;
1061 end First;
1063 overriding function First (Object : Child_Iterator) return Cursor is
1064 begin
1065 return First_Child (Cursor'(Object.Container, Object.Subtree));
1066 end First;
1068 -----------------
1069 -- First_Child --
1070 -----------------
1072 function First_Child (Parent : Cursor) return Cursor is
1073 Node : Tree_Node_Access;
1075 begin
1076 if Parent = No_Element then
1077 raise Constraint_Error with "Parent cursor has no element";
1078 end if;
1080 Node := Parent.Node.Children.First;
1082 if Node = null then
1083 return No_Element;
1084 end if;
1086 return Cursor'(Parent.Container, Node);
1087 end First_Child;
1089 -------------------------
1090 -- First_Child_Element --
1091 -------------------------
1093 function First_Child_Element (Parent : Cursor) return Element_Type is
1094 begin
1095 return Element (First_Child (Parent));
1096 end First_Child_Element;
1098 ----------------------
1099 -- Find_In_Children --
1100 ----------------------
1102 function Find_In_Children
1103 (Subtree : Tree_Node_Access;
1104 Item : Element_Type) return Tree_Node_Access
1106 N, Result : Tree_Node_Access;
1108 begin
1109 N := Subtree.Children.First;
1110 while N /= null loop
1111 Result := Find_In_Subtree (N, Item);
1113 if Result /= null then
1114 return Result;
1115 end if;
1117 N := N.Next;
1118 end loop;
1120 return null;
1121 end Find_In_Children;
1123 ---------------------
1124 -- Find_In_Subtree --
1125 ---------------------
1127 function Find_In_Subtree
1128 (Position : Cursor;
1129 Item : Element_Type) return Cursor
1131 Result : Tree_Node_Access;
1133 begin
1134 if Position = No_Element then
1135 raise Constraint_Error with "Position cursor has no element";
1136 end if;
1138 -- Commented-out pending ruling from ARG. ???
1140 -- if Position.Container /= Container'Unrestricted_Access then
1141 -- raise Program_Error with "Position cursor not in container";
1142 -- end if;
1144 if Is_Root (Position) then
1145 Result := Find_In_Children (Position.Node, Item);
1147 else
1148 Result := Find_In_Subtree (Position.Node, Item);
1149 end if;
1151 if Result = null then
1152 return No_Element;
1153 end if;
1155 return Cursor'(Position.Container, Result);
1156 end Find_In_Subtree;
1158 function Find_In_Subtree
1159 (Subtree : Tree_Node_Access;
1160 Item : Element_Type) return Tree_Node_Access
1162 begin
1163 if Subtree.Element.all = Item then
1164 return Subtree;
1165 end if;
1167 return Find_In_Children (Subtree, Item);
1168 end Find_In_Subtree;
1170 -----------------
1171 -- Has_Element --
1172 -----------------
1174 function Has_Element (Position : Cursor) return Boolean is
1175 begin
1176 if Position = No_Element then
1177 return False;
1178 end if;
1180 return Position.Node.Parent /= null;
1181 end Has_Element;
1183 ------------------
1184 -- Insert_Child --
1185 ------------------
1187 procedure Insert_Child
1188 (Container : in out Tree;
1189 Parent : Cursor;
1190 Before : Cursor;
1191 New_Item : Element_Type;
1192 Count : Count_Type := 1)
1194 Position : Cursor;
1195 pragma Unreferenced (Position);
1197 begin
1198 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1199 end Insert_Child;
1201 procedure Insert_Child
1202 (Container : in out Tree;
1203 Parent : Cursor;
1204 Before : Cursor;
1205 New_Item : Element_Type;
1206 Position : out Cursor;
1207 Count : Count_Type := 1)
1209 Last : Tree_Node_Access;
1210 Element : Element_Access;
1212 begin
1213 if Parent = No_Element then
1214 raise Constraint_Error with "Parent cursor has no element";
1215 end if;
1217 if Parent.Container /= Container'Unrestricted_Access then
1218 raise Program_Error with "Parent cursor not in container";
1219 end if;
1221 if Before /= No_Element then
1222 if Before.Container /= Container'Unrestricted_Access then
1223 raise Program_Error with "Before cursor not in container";
1224 end if;
1226 if Before.Node.Parent /= Parent.Node then
1227 raise Constraint_Error with "Parent cursor not parent of Before";
1228 end if;
1229 end if;
1231 if Count = 0 then
1232 Position := No_Element; -- Need ruling from ARG ???
1233 return;
1234 end if;
1236 if Container.Busy > 0 then
1237 raise Program_Error
1238 with "attempt to tamper with cursors (tree is busy)";
1239 end if;
1241 Position.Container := Parent.Container;
1243 Element := new Element_Type'(New_Item);
1244 Position.Node := new Tree_Node_Type'(Parent => Parent.Node,
1245 Element => Element,
1246 others => <>);
1248 Last := Position.Node;
1250 for J in Count_Type'(2) .. Count loop
1251 -- Reclaim other nodes if Storage_Error. ???
1253 Element := new Element_Type'(New_Item);
1254 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1255 Prev => Last,
1256 Element => Element,
1257 others => <>);
1259 Last := Last.Next;
1260 end loop;
1262 Insert_Subtree_List
1263 (First => Position.Node,
1264 Last => Last,
1265 Parent => Parent.Node,
1266 Before => Before.Node);
1268 -- In order for operation Node_Count to complete in O(1) time, we cache
1269 -- the count value. Here we increment the total count by the number of
1270 -- nodes we just inserted.
1272 Container.Count := Container.Count + Count;
1273 end Insert_Child;
1275 -------------------------
1276 -- Insert_Subtree_List --
1277 -------------------------
1279 procedure Insert_Subtree_List
1280 (First : Tree_Node_Access;
1281 Last : Tree_Node_Access;
1282 Parent : Tree_Node_Access;
1283 Before : Tree_Node_Access)
1285 pragma Assert (Parent /= null);
1286 C : Children_Type renames Parent.Children;
1288 begin
1289 -- This is a simple utility operation to insert a list of nodes (from
1290 -- First..Last) as children of Parent. The Before node specifies where
1291 -- the new children should be inserted relative to the existing
1292 -- children.
1294 if First = null then
1295 pragma Assert (Last = null);
1296 return;
1297 end if;
1299 pragma Assert (Last /= null);
1300 pragma Assert (Before = null or else Before.Parent = Parent);
1302 if C.First = null then
1303 C.First := First;
1304 C.First.Prev := null;
1305 C.Last := Last;
1306 C.Last.Next := null;
1308 elsif Before = null then -- means "insert after existing nodes"
1309 C.Last.Next := First;
1310 First.Prev := C.Last;
1311 C.Last := Last;
1312 C.Last.Next := null;
1314 elsif Before = C.First then
1315 Last.Next := C.First;
1316 C.First.Prev := Last;
1317 C.First := First;
1318 C.First.Prev := null;
1320 else
1321 Before.Prev.Next := First;
1322 First.Prev := Before.Prev;
1323 Last.Next := Before;
1324 Before.Prev := Last;
1325 end if;
1326 end Insert_Subtree_List;
1328 -------------------------
1329 -- Insert_Subtree_Node --
1330 -------------------------
1332 procedure Insert_Subtree_Node
1333 (Subtree : Tree_Node_Access;
1334 Parent : Tree_Node_Access;
1335 Before : Tree_Node_Access)
1337 begin
1338 -- This is a simple wrapper operation to insert a single child into the
1339 -- Parent's children list.
1341 Insert_Subtree_List
1342 (First => Subtree,
1343 Last => Subtree,
1344 Parent => Parent,
1345 Before => Before);
1346 end Insert_Subtree_Node;
1348 --------------
1349 -- Is_Empty --
1350 --------------
1352 function Is_Empty (Container : Tree) return Boolean is
1353 begin
1354 return Container.Root.Children.First = null;
1355 end Is_Empty;
1357 -------------
1358 -- Is_Leaf --
1359 -------------
1361 function Is_Leaf (Position : Cursor) return Boolean is
1362 begin
1363 if Position = No_Element then
1364 return False;
1365 end if;
1367 return Position.Node.Children.First = null;
1368 end Is_Leaf;
1370 ------------------
1371 -- Is_Reachable --
1372 ------------------
1374 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1375 pragma Assert (From /= null);
1376 pragma Assert (To /= null);
1378 N : Tree_Node_Access;
1380 begin
1381 N := From;
1382 while N /= null loop
1383 if N = To then
1384 return True;
1385 end if;
1387 N := N.Parent;
1388 end loop;
1390 return False;
1391 end Is_Reachable;
1393 -------------
1394 -- Is_Root --
1395 -------------
1397 function Is_Root (Position : Cursor) return Boolean is
1398 begin
1399 if Position.Container = null then
1400 return False;
1401 end if;
1403 return Position = Root (Position.Container.all);
1404 end Is_Root;
1406 -------------
1407 -- Iterate --
1408 -------------
1410 procedure Iterate
1411 (Container : Tree;
1412 Process : not null access procedure (Position : Cursor))
1414 B : Natural renames Container'Unrestricted_Access.all.Busy;
1416 begin
1417 B := B + 1;
1419 Iterate_Children
1420 (Container => Container'Unrestricted_Access,
1421 Subtree => Root_Node (Container),
1422 Process => Process);
1424 B := B - 1;
1426 exception
1427 when others =>
1428 B := B - 1;
1429 raise;
1430 end Iterate;
1432 function Iterate (Container : Tree)
1433 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1435 begin
1436 return Iterate_Subtree (Root (Container));
1437 end Iterate;
1439 ----------------------
1440 -- Iterate_Children --
1441 ----------------------
1443 procedure Iterate_Children
1444 (Parent : Cursor;
1445 Process : not null access procedure (Position : Cursor))
1447 begin
1448 if Parent = No_Element then
1449 raise Constraint_Error with "Parent cursor has no element";
1450 end if;
1452 declare
1453 B : Natural renames Parent.Container.Busy;
1454 C : Tree_Node_Access;
1456 begin
1457 B := B + 1;
1459 C := Parent.Node.Children.First;
1460 while C /= null loop
1461 Process (Position => Cursor'(Parent.Container, Node => C));
1462 C := C.Next;
1463 end loop;
1465 B := B - 1;
1467 exception
1468 when others =>
1469 B := B - 1;
1470 raise;
1471 end;
1472 end Iterate_Children;
1474 procedure Iterate_Children
1475 (Container : Tree_Access;
1476 Subtree : Tree_Node_Access;
1477 Process : not null access procedure (Position : Cursor))
1479 Node : Tree_Node_Access;
1481 begin
1482 -- This is a helper function to recursively iterate over all the nodes
1483 -- in a subtree, in depth-first fashion. This particular helper just
1484 -- visits the children of this subtree, not the root of the subtree node
1485 -- itself. This is useful when starting from the ultimate root of the
1486 -- entire tree (see Iterate), as that root does not have an element.
1488 Node := Subtree.Children.First;
1489 while Node /= null loop
1490 Iterate_Subtree (Container, Node, Process);
1491 Node := Node.Next;
1492 end loop;
1493 end Iterate_Children;
1495 function Iterate_Children
1496 (Container : Tree;
1497 Parent : Cursor)
1498 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1500 C : constant Tree_Access := Container'Unrestricted_Access;
1501 B : Natural renames C.Busy;
1503 begin
1504 if Parent = No_Element then
1505 raise Constraint_Error with "Parent cursor has no element";
1506 end if;
1508 if Parent.Container /= C then
1509 raise Program_Error with "Parent cursor not in container";
1510 end if;
1512 return It : constant Child_Iterator :=
1513 Child_Iterator'(Limited_Controlled with
1514 Container => C,
1515 Subtree => Parent.Node)
1517 B := B + 1;
1518 end return;
1519 end Iterate_Children;
1521 ---------------------
1522 -- Iterate_Subtree --
1523 ---------------------
1525 function Iterate_Subtree
1526 (Position : Cursor)
1527 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1529 begin
1530 if Position = No_Element then
1531 raise Constraint_Error with "Position cursor has no element";
1532 end if;
1534 -- Implement Vet for multiway trees???
1535 -- pragma Assert (Vet (Position), "bad subtree cursor");
1537 declare
1538 B : Natural renames Position.Container.Busy;
1539 begin
1540 return It : constant Subtree_Iterator :=
1541 (Limited_Controlled with
1542 Container => Position.Container,
1543 Subtree => Position.Node)
1545 B := B + 1;
1546 end return;
1547 end;
1548 end Iterate_Subtree;
1550 procedure Iterate_Subtree
1551 (Position : Cursor;
1552 Process : not null access procedure (Position : Cursor))
1554 begin
1555 if Position = No_Element then
1556 raise Constraint_Error with "Position cursor has no element";
1557 end if;
1559 declare
1560 B : Natural renames Position.Container.Busy;
1562 begin
1563 B := B + 1;
1565 if Is_Root (Position) then
1566 Iterate_Children (Position.Container, Position.Node, Process);
1567 else
1568 Iterate_Subtree (Position.Container, Position.Node, Process);
1569 end if;
1571 B := B - 1;
1573 exception
1574 when others =>
1575 B := B - 1;
1576 raise;
1577 end;
1578 end Iterate_Subtree;
1580 procedure Iterate_Subtree
1581 (Container : Tree_Access;
1582 Subtree : Tree_Node_Access;
1583 Process : not null access procedure (Position : Cursor))
1585 begin
1586 -- This is a helper function to recursively iterate over all the nodes
1587 -- in a subtree, in depth-first fashion. It first visits the root of the
1588 -- subtree, then visits its children.
1590 Process (Cursor'(Container, Subtree));
1591 Iterate_Children (Container, Subtree, Process);
1592 end Iterate_Subtree;
1594 ----------
1595 -- Last --
1596 ----------
1598 overriding function Last (Object : Child_Iterator) return Cursor is
1599 begin
1600 return Last_Child (Cursor'(Object.Container, Object.Subtree));
1601 end Last;
1603 ----------------
1604 -- Last_Child --
1605 ----------------
1607 function Last_Child (Parent : Cursor) return Cursor is
1608 Node : Tree_Node_Access;
1610 begin
1611 if Parent = No_Element then
1612 raise Constraint_Error with "Parent cursor has no element";
1613 end if;
1615 Node := Parent.Node.Children.Last;
1617 if Node = null then
1618 return No_Element;
1619 end if;
1621 return (Parent.Container, Node);
1622 end Last_Child;
1624 ------------------------
1625 -- Last_Child_Element --
1626 ------------------------
1628 function Last_Child_Element (Parent : Cursor) return Element_Type is
1629 begin
1630 return Element (Last_Child (Parent));
1631 end Last_Child_Element;
1633 ----------
1634 -- Move --
1635 ----------
1637 procedure Move (Target : in out Tree; Source : in out Tree) is
1638 Node : Tree_Node_Access;
1640 begin
1641 if Target'Address = Source'Address then
1642 return;
1643 end if;
1645 if Source.Busy > 0 then
1646 raise Program_Error
1647 with "attempt to tamper with cursors of Source (tree is busy)";
1648 end if;
1650 Target.Clear; -- checks busy bit
1652 Target.Root.Children := Source.Root.Children;
1653 Source.Root.Children := Children_Type'(others => null);
1655 Node := Target.Root.Children.First;
1656 while Node /= null loop
1657 Node.Parent := Root_Node (Target);
1658 Node := Node.Next;
1659 end loop;
1661 Target.Count := Source.Count;
1662 Source.Count := 0;
1663 end Move;
1665 ----------
1666 -- Next --
1667 ----------
1669 function Next
1670 (Object : Subtree_Iterator;
1671 Position : Cursor) return Cursor
1673 Node : Tree_Node_Access;
1675 begin
1676 if Position.Container = null then
1677 return No_Element;
1678 end if;
1680 if Position.Container /= Object.Container then
1681 raise Program_Error with
1682 "Position cursor of Next designates wrong tree";
1683 end if;
1685 Node := Position.Node;
1687 if Node.Children.First /= null then
1688 return Cursor'(Object.Container, Node.Children.First);
1689 end if;
1691 while Node /= Object.Subtree loop
1692 if Node.Next /= null then
1693 return Cursor'(Object.Container, Node.Next);
1694 end if;
1696 Node := Node.Parent;
1697 end loop;
1699 return No_Element;
1700 end Next;
1702 function Next
1703 (Object : Child_Iterator;
1704 Position : Cursor) return Cursor
1706 begin
1707 if Position.Container = null then
1708 return No_Element;
1709 end if;
1711 if Position.Container /= Object.Container then
1712 raise Program_Error with
1713 "Position cursor of Next designates wrong tree";
1714 end if;
1716 return Next_Sibling (Position);
1717 end Next;
1719 ------------------
1720 -- Next_Sibling --
1721 ------------------
1723 function Next_Sibling (Position : Cursor) return Cursor is
1724 begin
1725 if Position = No_Element then
1726 return No_Element;
1727 end if;
1729 if Position.Node.Next = null then
1730 return No_Element;
1731 end if;
1733 return Cursor'(Position.Container, Position.Node.Next);
1734 end Next_Sibling;
1736 procedure Next_Sibling (Position : in out Cursor) is
1737 begin
1738 Position := Next_Sibling (Position);
1739 end Next_Sibling;
1741 ----------------
1742 -- Node_Count --
1743 ----------------
1745 function Node_Count (Container : Tree) return Count_Type is
1746 begin
1747 -- Container.Count is the number of nodes we have actually allocated. We
1748 -- cache the value specifically so this Node_Count operation can execute
1749 -- in O(1) time, which makes it behave similarly to how the Length
1750 -- selector function behaves for other containers.
1752 -- The cached node count value only describes the nodes we have
1753 -- allocated; the root node itself is not included in that count. The
1754 -- Node_Count operation returns a value that includes the root node
1755 -- (because the RM says so), so we must add 1 to our cached value.
1757 return 1 + Container.Count;
1758 end Node_Count;
1760 ------------
1761 -- Parent --
1762 ------------
1764 function Parent (Position : Cursor) return Cursor is
1765 begin
1766 if Position = No_Element then
1767 return No_Element;
1768 end if;
1770 if Position.Node.Parent = null then
1771 return No_Element;
1772 end if;
1774 return Cursor'(Position.Container, Position.Node.Parent);
1775 end Parent;
1777 -------------------
1778 -- Prepent_Child --
1779 -------------------
1781 procedure Prepend_Child
1782 (Container : in out Tree;
1783 Parent : Cursor;
1784 New_Item : Element_Type;
1785 Count : Count_Type := 1)
1787 First, Last : Tree_Node_Access;
1788 Element : Element_Access;
1790 begin
1791 if Parent = No_Element then
1792 raise Constraint_Error with "Parent cursor has no element";
1793 end if;
1795 if Parent.Container /= Container'Unrestricted_Access then
1796 raise Program_Error with "Parent cursor not in container";
1797 end if;
1799 if Count = 0 then
1800 return;
1801 end if;
1803 if Container.Busy > 0 then
1804 raise Program_Error
1805 with "attempt to tamper with cursors (tree is busy)";
1806 end if;
1808 Element := new Element_Type'(New_Item);
1809 First := new Tree_Node_Type'(Parent => Parent.Node,
1810 Element => Element,
1811 others => <>);
1813 Last := First;
1815 for J in Count_Type'(2) .. Count loop
1817 -- Reclaim other nodes if Storage_Error. ???
1819 Element := new Element_Type'(New_Item);
1820 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1821 Prev => Last,
1822 Element => Element,
1823 others => <>);
1825 Last := Last.Next;
1826 end loop;
1828 Insert_Subtree_List
1829 (First => First,
1830 Last => Last,
1831 Parent => Parent.Node,
1832 Before => Parent.Node.Children.First);
1834 -- In order for operation Node_Count to complete in O(1) time, we cache
1835 -- the count value. Here we increment the total count by the number of
1836 -- nodes we just inserted.
1838 Container.Count := Container.Count + Count;
1839 end Prepend_Child;
1841 --------------
1842 -- Previous --
1843 --------------
1845 overriding function Previous
1846 (Object : Child_Iterator;
1847 Position : Cursor) return Cursor
1849 begin
1850 if Position.Container = null then
1851 return No_Element;
1852 end if;
1854 if Position.Container /= Object.Container then
1855 raise Program_Error with
1856 "Position cursor of Previous designates wrong tree";
1857 end if;
1859 return Previous_Sibling (Position);
1860 end Previous;
1862 ----------------------
1863 -- Previous_Sibling --
1864 ----------------------
1866 function Previous_Sibling (Position : Cursor) return Cursor is
1867 begin
1868 if Position = No_Element then
1869 return No_Element;
1870 end if;
1872 if Position.Node.Prev = null then
1873 return No_Element;
1874 end if;
1876 return Cursor'(Position.Container, Position.Node.Prev);
1877 end Previous_Sibling;
1879 procedure Previous_Sibling (Position : in out Cursor) is
1880 begin
1881 Position := Previous_Sibling (Position);
1882 end Previous_Sibling;
1884 -------------------
1885 -- Query_Element --
1886 -------------------
1888 procedure Query_Element
1889 (Position : Cursor;
1890 Process : not null access procedure (Element : Element_Type))
1892 begin
1893 if Position = No_Element then
1894 raise Constraint_Error with "Position cursor has no element";
1895 end if;
1897 if Is_Root (Position) then
1898 raise Program_Error with "Position cursor designates root";
1899 end if;
1901 declare
1902 T : Tree renames Position.Container.all'Unrestricted_Access.all;
1903 B : Natural renames T.Busy;
1904 L : Natural renames T.Lock;
1906 begin
1907 B := B + 1;
1908 L := L + 1;
1910 Process (Position.Node.Element.all);
1912 L := L - 1;
1913 B := B - 1;
1915 exception
1916 when others =>
1917 L := L - 1;
1918 B := B - 1;
1919 raise;
1920 end;
1921 end Query_Element;
1923 ----------
1924 -- Read --
1925 ----------
1927 procedure Read
1928 (Stream : not null access Root_Stream_Type'Class;
1929 Container : out Tree)
1931 procedure Read_Children (Subtree : Tree_Node_Access);
1933 function Read_Subtree
1934 (Parent : Tree_Node_Access) return Tree_Node_Access;
1936 Total_Count : Count_Type'Base;
1937 -- Value read from the stream that says how many elements follow
1939 Read_Count : Count_Type'Base;
1940 -- Actual number of elements read from the stream
1942 -------------------
1943 -- Read_Children --
1944 -------------------
1946 procedure Read_Children (Subtree : Tree_Node_Access) is
1947 pragma Assert (Subtree /= null);
1948 pragma Assert (Subtree.Children.First = null);
1949 pragma Assert (Subtree.Children.Last = null);
1951 Count : Count_Type'Base;
1952 -- Number of child subtrees
1954 C : Children_Type;
1956 begin
1957 Count_Type'Read (Stream, Count);
1959 if Count < 0 then
1960 raise Program_Error with "attempt to read from corrupt stream";
1961 end if;
1963 if Count = 0 then
1964 return;
1965 end if;
1967 C.First := Read_Subtree (Parent => Subtree);
1968 C.Last := C.First;
1970 for J in Count_Type'(2) .. Count loop
1971 C.Last.Next := Read_Subtree (Parent => Subtree);
1972 C.Last.Next.Prev := C.Last;
1973 C.Last := C.Last.Next;
1974 end loop;
1976 -- Now that the allocation and reads have completed successfully, it
1977 -- is safe to link the children to their parent.
1979 Subtree.Children := C;
1980 end Read_Children;
1982 ------------------
1983 -- Read_Subtree --
1984 ------------------
1986 function Read_Subtree
1987 (Parent : Tree_Node_Access) return Tree_Node_Access
1989 Element : constant Element_Access :=
1990 new Element_Type'(Element_Type'Input (Stream));
1992 Subtree : constant Tree_Node_Access :=
1993 new Tree_Node_Type'
1994 (Parent => Parent,
1995 Element => Element,
1996 others => <>);
1998 begin
1999 Read_Count := Read_Count + 1;
2001 Read_Children (Subtree);
2003 return Subtree;
2004 end Read_Subtree;
2006 -- Start of processing for Read
2008 begin
2009 Container.Clear; -- checks busy bit
2011 Count_Type'Read (Stream, Total_Count);
2013 if Total_Count < 0 then
2014 raise Program_Error with "attempt to read from corrupt stream";
2015 end if;
2017 if Total_Count = 0 then
2018 return;
2019 end if;
2021 Read_Count := 0;
2023 Read_Children (Root_Node (Container));
2025 if Read_Count /= Total_Count then
2026 raise Program_Error with "attempt to read from corrupt stream";
2027 end if;
2029 Container.Count := Total_Count;
2030 end Read;
2032 procedure Read
2033 (Stream : not null access Root_Stream_Type'Class;
2034 Position : out Cursor)
2036 begin
2037 raise Program_Error with "attempt to read tree cursor from stream";
2038 end Read;
2040 procedure Read
2041 (Stream : not null access Root_Stream_Type'Class;
2042 Item : out Reference_Type)
2044 begin
2045 raise Program_Error with "attempt to stream reference";
2046 end Read;
2048 procedure Read
2049 (Stream : not null access Root_Stream_Type'Class;
2050 Item : out Constant_Reference_Type)
2052 begin
2053 raise Program_Error with "attempt to stream reference";
2054 end Read;
2056 ---------------
2057 -- Reference --
2058 ---------------
2060 function Reference
2061 (Container : aliased in out Tree;
2062 Position : Cursor) return Reference_Type
2064 begin
2065 if Position.Container = null then
2066 raise Constraint_Error with
2067 "Position cursor has no element";
2068 end if;
2070 if Position.Container /= Container'Unrestricted_Access then
2071 raise Program_Error with
2072 "Position cursor designates wrong container";
2073 end if;
2075 if Position.Node = Root_Node (Container) then
2076 raise Program_Error with "Position cursor designates root";
2077 end if;
2079 if Position.Node.Element = null then
2080 raise Program_Error with "Node has no element";
2081 end if;
2083 -- Implement Vet for multiway tree???
2084 -- pragma Assert (Vet (Position),
2085 -- "Position cursor in Constant_Reference is bad");
2087 declare
2088 C : Tree renames Position.Container.all;
2089 B : Natural renames C.Busy;
2090 L : Natural renames C.Lock;
2091 begin
2092 return R : constant Reference_Type :=
2093 (Element => Position.Node.Element.all'Access,
2094 Control => (Controlled with Position.Container))
2096 B := B + 1;
2097 L := L + 1;
2098 end return;
2099 end;
2100 end Reference;
2102 --------------------
2103 -- Remove_Subtree --
2104 --------------------
2106 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2107 C : Children_Type renames Subtree.Parent.Children;
2109 begin
2110 -- This is a utility operation to remove a subtree node from its
2111 -- parent's list of children.
2113 if C.First = Subtree then
2114 pragma Assert (Subtree.Prev = null);
2116 if C.Last = Subtree then
2117 pragma Assert (Subtree.Next = null);
2118 C.First := null;
2119 C.Last := null;
2121 else
2122 C.First := Subtree.Next;
2123 C.First.Prev := null;
2124 end if;
2126 elsif C.Last = Subtree then
2127 pragma Assert (Subtree.Next = null);
2128 C.Last := Subtree.Prev;
2129 C.Last.Next := null;
2131 else
2132 Subtree.Prev.Next := Subtree.Next;
2133 Subtree.Next.Prev := Subtree.Prev;
2134 end if;
2135 end Remove_Subtree;
2137 ----------------------
2138 -- Replace_Element --
2139 ----------------------
2141 procedure Replace_Element
2142 (Container : in out Tree;
2143 Position : Cursor;
2144 New_Item : Element_Type)
2146 E, X : Element_Access;
2148 begin
2149 if Position = No_Element then
2150 raise Constraint_Error with "Position cursor has no element";
2151 end if;
2153 if Position.Container /= Container'Unrestricted_Access then
2154 raise Program_Error with "Position cursor not in container";
2155 end if;
2157 if Is_Root (Position) then
2158 raise Program_Error with "Position cursor designates root";
2159 end if;
2161 if Container.Lock > 0 then
2162 raise Program_Error
2163 with "attempt to tamper with elements (tree is locked)";
2164 end if;
2166 E := new Element_Type'(New_Item);
2168 X := Position.Node.Element;
2169 Position.Node.Element := E;
2171 Free_Element (X);
2172 end Replace_Element;
2174 ------------------------------
2175 -- Reverse_Iterate_Children --
2176 ------------------------------
2178 procedure Reverse_Iterate_Children
2179 (Parent : Cursor;
2180 Process : not null access procedure (Position : Cursor))
2182 begin
2183 if Parent = No_Element then
2184 raise Constraint_Error with "Parent cursor has no element";
2185 end if;
2187 declare
2188 B : Natural renames Parent.Container.Busy;
2189 C : Tree_Node_Access;
2191 begin
2192 B := B + 1;
2194 C := Parent.Node.Children.Last;
2195 while C /= null loop
2196 Process (Position => Cursor'(Parent.Container, Node => C));
2197 C := C.Prev;
2198 end loop;
2200 B := B - 1;
2202 exception
2203 when others =>
2204 B := B - 1;
2205 raise;
2206 end;
2207 end Reverse_Iterate_Children;
2209 ----------
2210 -- Root --
2211 ----------
2213 function Root (Container : Tree) return Cursor is
2214 begin
2215 return (Container'Unrestricted_Access, Root_Node (Container));
2216 end Root;
2218 ---------------
2219 -- Root_Node --
2220 ---------------
2222 function Root_Node (Container : Tree) return Tree_Node_Access is
2223 begin
2224 return Container.Root'Unrestricted_Access;
2225 end Root_Node;
2227 ---------------------
2228 -- Splice_Children --
2229 ---------------------
2231 procedure Splice_Children
2232 (Target : in out Tree;
2233 Target_Parent : Cursor;
2234 Before : Cursor;
2235 Source : in out Tree;
2236 Source_Parent : Cursor)
2238 Count : Count_Type;
2240 begin
2241 if Target_Parent = No_Element then
2242 raise Constraint_Error with "Target_Parent cursor has no element";
2243 end if;
2245 if Target_Parent.Container /= Target'Unrestricted_Access then
2246 raise Program_Error
2247 with "Target_Parent cursor not in Target container";
2248 end if;
2250 if Before /= No_Element then
2251 if Before.Container /= Target'Unrestricted_Access then
2252 raise Program_Error
2253 with "Before cursor not in Target container";
2254 end if;
2256 if Before.Node.Parent /= Target_Parent.Node then
2257 raise Constraint_Error
2258 with "Before cursor not child of Target_Parent";
2259 end if;
2260 end if;
2262 if Source_Parent = No_Element then
2263 raise Constraint_Error with "Source_Parent cursor has no element";
2264 end if;
2266 if Source_Parent.Container /= Source'Unrestricted_Access then
2267 raise Program_Error
2268 with "Source_Parent cursor not in Source container";
2269 end if;
2271 if Target'Address = Source'Address then
2272 if Target_Parent = Source_Parent then
2273 return;
2274 end if;
2276 if Target.Busy > 0 then
2277 raise Program_Error
2278 with "attempt to tamper with cursors (Target tree is busy)";
2279 end if;
2281 if Is_Reachable (From => Target_Parent.Node,
2282 To => Source_Parent.Node)
2283 then
2284 raise Constraint_Error
2285 with "Source_Parent is ancestor of Target_Parent";
2286 end if;
2288 Splice_Children
2289 (Target_Parent => Target_Parent.Node,
2290 Before => Before.Node,
2291 Source_Parent => Source_Parent.Node);
2293 return;
2294 end if;
2296 if Target.Busy > 0 then
2297 raise Program_Error
2298 with "attempt to tamper with cursors (Target tree is busy)";
2299 end if;
2301 if Source.Busy > 0 then
2302 raise Program_Error
2303 with "attempt to tamper with cursors (Source tree is busy)";
2304 end if;
2306 -- We cache the count of the nodes we have allocated, so that operation
2307 -- Node_Count can execute in O(1) time. But that means we must count the
2308 -- nodes in the subtree we remove from Source and insert into Target, in
2309 -- order to keep the count accurate.
2311 Count := Subtree_Node_Count (Source_Parent.Node);
2312 pragma Assert (Count >= 1);
2314 Count := Count - 1; -- because Source_Parent node does not move
2316 Splice_Children
2317 (Target_Parent => Target_Parent.Node,
2318 Before => Before.Node,
2319 Source_Parent => Source_Parent.Node);
2321 Source.Count := Source.Count - Count;
2322 Target.Count := Target.Count + Count;
2323 end Splice_Children;
2325 procedure Splice_Children
2326 (Container : in out Tree;
2327 Target_Parent : Cursor;
2328 Before : Cursor;
2329 Source_Parent : Cursor)
2331 begin
2332 if Target_Parent = No_Element then
2333 raise Constraint_Error with "Target_Parent cursor has no element";
2334 end if;
2336 if Target_Parent.Container /= Container'Unrestricted_Access then
2337 raise Program_Error
2338 with "Target_Parent cursor not in container";
2339 end if;
2341 if Before /= No_Element then
2342 if Before.Container /= Container'Unrestricted_Access then
2343 raise Program_Error
2344 with "Before cursor not in container";
2345 end if;
2347 if Before.Node.Parent /= Target_Parent.Node then
2348 raise Constraint_Error
2349 with "Before cursor not child of Target_Parent";
2350 end if;
2351 end if;
2353 if Source_Parent = No_Element then
2354 raise Constraint_Error with "Source_Parent cursor has no element";
2355 end if;
2357 if Source_Parent.Container /= Container'Unrestricted_Access then
2358 raise Program_Error
2359 with "Source_Parent cursor not in container";
2360 end if;
2362 if Target_Parent = Source_Parent then
2363 return;
2364 end if;
2366 if Container.Busy > 0 then
2367 raise Program_Error
2368 with "attempt to tamper with cursors (tree is busy)";
2369 end if;
2371 if Is_Reachable (From => Target_Parent.Node,
2372 To => Source_Parent.Node)
2373 then
2374 raise Constraint_Error
2375 with "Source_Parent is ancestor of Target_Parent";
2376 end if;
2378 Splice_Children
2379 (Target_Parent => Target_Parent.Node,
2380 Before => Before.Node,
2381 Source_Parent => Source_Parent.Node);
2382 end Splice_Children;
2384 procedure Splice_Children
2385 (Target_Parent : Tree_Node_Access;
2386 Before : Tree_Node_Access;
2387 Source_Parent : Tree_Node_Access)
2389 CC : constant Children_Type := Source_Parent.Children;
2390 C : Tree_Node_Access;
2392 begin
2393 -- This is a utility operation to remove the children from Source parent
2394 -- and insert them into Target parent.
2396 Source_Parent.Children := Children_Type'(others => null);
2398 -- Fix up the Parent pointers of each child to designate its new Target
2399 -- parent.
2401 C := CC.First;
2402 while C /= null loop
2403 C.Parent := Target_Parent;
2404 C := C.Next;
2405 end loop;
2407 Insert_Subtree_List
2408 (First => CC.First,
2409 Last => CC.Last,
2410 Parent => Target_Parent,
2411 Before => Before);
2412 end Splice_Children;
2414 --------------------
2415 -- Splice_Subtree --
2416 --------------------
2418 procedure Splice_Subtree
2419 (Target : in out Tree;
2420 Parent : Cursor;
2421 Before : Cursor;
2422 Source : in out Tree;
2423 Position : in out Cursor)
2425 Subtree_Count : Count_Type;
2427 begin
2428 if Parent = No_Element then
2429 raise Constraint_Error with "Parent cursor has no element";
2430 end if;
2432 if Parent.Container /= Target'Unrestricted_Access then
2433 raise Program_Error with "Parent cursor not in Target container";
2434 end if;
2436 if Before /= No_Element then
2437 if Before.Container /= Target'Unrestricted_Access then
2438 raise Program_Error with "Before cursor not in Target container";
2439 end if;
2441 if Before.Node.Parent /= Parent.Node then
2442 raise Constraint_Error with "Before cursor not child of Parent";
2443 end if;
2444 end if;
2446 if Position = No_Element then
2447 raise Constraint_Error with "Position cursor has no element";
2448 end if;
2450 if Position.Container /= Source'Unrestricted_Access then
2451 raise Program_Error with "Position cursor not in Source container";
2452 end if;
2454 if Is_Root (Position) then
2455 raise Program_Error with "Position cursor designates root";
2456 end if;
2458 if Target'Address = Source'Address then
2459 if Position.Node.Parent = Parent.Node then
2460 if Position.Node = Before.Node then
2461 return;
2462 end if;
2464 if Position.Node.Next = Before.Node then
2465 return;
2466 end if;
2467 end if;
2469 if Target.Busy > 0 then
2470 raise Program_Error
2471 with "attempt to tamper with cursors (Target tree is busy)";
2472 end if;
2474 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2475 raise Constraint_Error with "Position is ancestor of Parent";
2476 end if;
2478 Remove_Subtree (Position.Node);
2480 Position.Node.Parent := Parent.Node;
2481 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2483 return;
2484 end if;
2486 if Target.Busy > 0 then
2487 raise Program_Error
2488 with "attempt to tamper with cursors (Target tree is busy)";
2489 end if;
2491 if Source.Busy > 0 then
2492 raise Program_Error
2493 with "attempt to tamper with cursors (Source tree is busy)";
2494 end if;
2496 -- This is an unfortunate feature of this API: we must count the nodes
2497 -- in the subtree that we remove from the source tree, which is an O(n)
2498 -- operation. It would have been better if the Tree container did not
2499 -- have a Node_Count selector; a user that wants the number of nodes in
2500 -- the tree could simply call Subtree_Node_Count, with the understanding
2501 -- that such an operation is O(n).
2503 -- Of course, we could choose to implement the Node_Count selector as an
2504 -- O(n) operation, which would turn this splice operation into an O(1)
2505 -- operation. ???
2507 Subtree_Count := Subtree_Node_Count (Position.Node);
2508 pragma Assert (Subtree_Count <= Source.Count);
2510 Remove_Subtree (Position.Node);
2511 Source.Count := Source.Count - Subtree_Count;
2513 Position.Node.Parent := Parent.Node;
2514 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2516 Target.Count := Target.Count + Subtree_Count;
2518 Position.Container := Target'Unrestricted_Access;
2519 end Splice_Subtree;
2521 procedure Splice_Subtree
2522 (Container : in out Tree;
2523 Parent : Cursor;
2524 Before : Cursor;
2525 Position : Cursor)
2527 begin
2528 if Parent = No_Element then
2529 raise Constraint_Error with "Parent cursor has no element";
2530 end if;
2532 if Parent.Container /= Container'Unrestricted_Access then
2533 raise Program_Error with "Parent cursor not in container";
2534 end if;
2536 if Before /= No_Element then
2537 if Before.Container /= Container'Unrestricted_Access then
2538 raise Program_Error with "Before cursor not in container";
2539 end if;
2541 if Before.Node.Parent /= Parent.Node then
2542 raise Constraint_Error with "Before cursor not child of Parent";
2543 end if;
2544 end if;
2546 if Position = No_Element then
2547 raise Constraint_Error with "Position cursor has no element";
2548 end if;
2550 if Position.Container /= Container'Unrestricted_Access then
2551 raise Program_Error with "Position cursor not in container";
2552 end if;
2554 if Is_Root (Position) then
2556 -- Should this be PE instead? Need ARG confirmation. ???
2558 raise Constraint_Error with "Position cursor designates root";
2559 end if;
2561 if Position.Node.Parent = Parent.Node then
2562 if Position.Node = Before.Node then
2563 return;
2564 end if;
2566 if Position.Node.Next = Before.Node then
2567 return;
2568 end if;
2569 end if;
2571 if Container.Busy > 0 then
2572 raise Program_Error
2573 with "attempt to tamper with cursors (tree is busy)";
2574 end if;
2576 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2577 raise Constraint_Error with "Position is ancestor of Parent";
2578 end if;
2580 Remove_Subtree (Position.Node);
2582 Position.Node.Parent := Parent.Node;
2583 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2584 end Splice_Subtree;
2586 ------------------------
2587 -- Subtree_Node_Count --
2588 ------------------------
2590 function Subtree_Node_Count (Position : Cursor) return Count_Type is
2591 begin
2592 if Position = No_Element then
2593 return 0;
2594 end if;
2596 return Subtree_Node_Count (Position.Node);
2597 end Subtree_Node_Count;
2599 function Subtree_Node_Count
2600 (Subtree : Tree_Node_Access) return Count_Type
2602 Result : Count_Type;
2603 Node : Tree_Node_Access;
2605 begin
2606 Result := 1;
2607 Node := Subtree.Children.First;
2608 while Node /= null loop
2609 Result := Result + Subtree_Node_Count (Node);
2610 Node := Node.Next;
2611 end loop;
2613 return Result;
2614 end Subtree_Node_Count;
2616 ----------
2617 -- Swap --
2618 ----------
2620 procedure Swap
2621 (Container : in out Tree;
2622 I, J : Cursor)
2624 begin
2625 if I = No_Element then
2626 raise Constraint_Error with "I cursor has no element";
2627 end if;
2629 if I.Container /= Container'Unrestricted_Access then
2630 raise Program_Error with "I cursor not in container";
2631 end if;
2633 if Is_Root (I) then
2634 raise Program_Error with "I cursor designates root";
2635 end if;
2637 if I = J then -- make this test sooner???
2638 return;
2639 end if;
2641 if J = No_Element then
2642 raise Constraint_Error with "J cursor has no element";
2643 end if;
2645 if J.Container /= Container'Unrestricted_Access then
2646 raise Program_Error with "J cursor not in container";
2647 end if;
2649 if Is_Root (J) then
2650 raise Program_Error with "J cursor designates root";
2651 end if;
2653 if Container.Lock > 0 then
2654 raise Program_Error
2655 with "attempt to tamper with elements (tree is locked)";
2656 end if;
2658 declare
2659 EI : constant Element_Access := I.Node.Element;
2661 begin
2662 I.Node.Element := J.Node.Element;
2663 J.Node.Element := EI;
2664 end;
2665 end Swap;
2667 --------------------
2668 -- Update_Element --
2669 --------------------
2671 procedure Update_Element
2672 (Container : in out Tree;
2673 Position : Cursor;
2674 Process : not null access procedure (Element : in out Element_Type))
2676 begin
2677 if Position = No_Element then
2678 raise Constraint_Error with "Position cursor has no element";
2679 end if;
2681 if Position.Container /= Container'Unrestricted_Access then
2682 raise Program_Error with "Position cursor not in container";
2683 end if;
2685 if Is_Root (Position) then
2686 raise Program_Error with "Position cursor designates root";
2687 end if;
2689 declare
2690 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2691 B : Natural renames T.Busy;
2692 L : Natural renames T.Lock;
2694 begin
2695 B := B + 1;
2696 L := L + 1;
2698 Process (Position.Node.Element.all);
2700 L := L - 1;
2701 B := B - 1;
2703 exception
2704 when others =>
2705 L := L - 1;
2706 B := B - 1;
2707 raise;
2708 end;
2709 end Update_Element;
2711 -----------
2712 -- Write --
2713 -----------
2715 procedure Write
2716 (Stream : not null access Root_Stream_Type'Class;
2717 Container : Tree)
2719 procedure Write_Children (Subtree : Tree_Node_Access);
2720 procedure Write_Subtree (Subtree : Tree_Node_Access);
2722 --------------------
2723 -- Write_Children --
2724 --------------------
2726 procedure Write_Children (Subtree : Tree_Node_Access) is
2727 CC : Children_Type renames Subtree.Children;
2728 C : Tree_Node_Access;
2730 begin
2731 Count_Type'Write (Stream, Child_Count (CC));
2733 C := CC.First;
2734 while C /= null loop
2735 Write_Subtree (C);
2736 C := C.Next;
2737 end loop;
2738 end Write_Children;
2740 -------------------
2741 -- Write_Subtree --
2742 -------------------
2744 procedure Write_Subtree (Subtree : Tree_Node_Access) is
2745 begin
2746 Element_Type'Output (Stream, Subtree.Element.all);
2747 Write_Children (Subtree);
2748 end Write_Subtree;
2750 -- Start of processing for Write
2752 begin
2753 Count_Type'Write (Stream, Container.Count);
2755 if Container.Count = 0 then
2756 return;
2757 end if;
2759 Write_Children (Root_Node (Container));
2760 end Write;
2762 procedure Write
2763 (Stream : not null access Root_Stream_Type'Class;
2764 Position : Cursor)
2766 begin
2767 raise Program_Error with "attempt to write tree cursor to stream";
2768 end Write;
2770 procedure Write
2771 (Stream : not null access Root_Stream_Type'Class;
2772 Item : Reference_Type)
2774 begin
2775 raise Program_Error with "attempt to stream reference";
2776 end Write;
2778 procedure Write
2779 (Stream : not null access Root_Stream_Type'Class;
2780 Item : Constant_Reference_Type)
2782 begin
2783 raise Program_Error with "attempt to stream reference";
2784 end Write;
2786 end Ada.Containers.Indefinite_Multiway_Trees;