Implement -mmemcpy-strategy= and -mmemset-strategy= options
[official-gcc.git] / gcc / ada / a-comutr.adb
blob426c6f0675b1686bb6b863f928d4019f73d0fe25
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . M U L T I W A Y _ T R E E S --
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_Conversion;
31 with Ada.Unchecked_Deallocation;
33 with System; use type System.Address;
35 package body Ada.Containers.Multiway_Trees is
37 --------------------
38 -- Root_Iterator --
39 --------------------
41 type Root_Iterator is abstract new Limited_Controlled and
42 Tree_Iterator_Interfaces.Forward_Iterator with
43 record
44 Container : Tree_Access;
45 Subtree : Tree_Node_Access;
46 end record;
48 overriding procedure Finalize (Object : in out Root_Iterator);
50 -----------------------
51 -- Subtree_Iterator --
52 -----------------------
54 -- ??? these headers are a bit odd, but for sure they do not substitute
55 -- for documenting things, what *is* a Subtree_Iterator?
57 type Subtree_Iterator is new Root_Iterator with null record;
59 overriding function First (Object : Subtree_Iterator) return Cursor;
61 overriding function Next
62 (Object : Subtree_Iterator;
63 Position : Cursor) return Cursor;
65 ---------------------
66 -- Child_Iterator --
67 ---------------------
69 type Child_Iterator is new Root_Iterator and
70 Tree_Iterator_Interfaces.Reversible_Iterator with null record;
72 overriding function First (Object : Child_Iterator) return Cursor;
74 overriding function Next
75 (Object : Child_Iterator;
76 Position : Cursor) return Cursor;
78 overriding function Last (Object : Child_Iterator) return Cursor;
80 overriding function Previous
81 (Object : Child_Iterator;
82 Position : Cursor) return Cursor;
84 -----------------------
85 -- Local Subprograms --
86 -----------------------
88 function Root_Node (Container : Tree) return Tree_Node_Access;
90 procedure Deallocate_Node is
91 new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access);
93 procedure Deallocate_Children
94 (Subtree : Tree_Node_Access;
95 Count : in out Count_Type);
97 procedure Deallocate_Subtree
98 (Subtree : in out Tree_Node_Access;
99 Count : in out Count_Type);
101 function Equal_Children
102 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
104 function Equal_Subtree
105 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
107 procedure Iterate_Children
108 (Container : Tree_Access;
109 Subtree : Tree_Node_Access;
110 Process : not null access procedure (Position : Cursor));
112 procedure Iterate_Subtree
113 (Container : Tree_Access;
114 Subtree : Tree_Node_Access;
115 Process : not null access procedure (Position : Cursor));
117 procedure Copy_Children
118 (Source : Children_Type;
119 Parent : Tree_Node_Access;
120 Count : in out Count_Type);
122 procedure Copy_Subtree
123 (Source : Tree_Node_Access;
124 Parent : Tree_Node_Access;
125 Target : out Tree_Node_Access;
126 Count : in out Count_Type);
128 function Find_In_Children
129 (Subtree : Tree_Node_Access;
130 Item : Element_Type) return Tree_Node_Access;
132 function Find_In_Subtree
133 (Subtree : Tree_Node_Access;
134 Item : Element_Type) return Tree_Node_Access;
136 function Child_Count (Children : Children_Type) return Count_Type;
138 function Subtree_Node_Count
139 (Subtree : Tree_Node_Access) return Count_Type;
141 function Is_Reachable (From, To : Tree_Node_Access) return Boolean;
143 procedure Remove_Subtree (Subtree : Tree_Node_Access);
145 procedure Insert_Subtree_Node
146 (Subtree : Tree_Node_Access;
147 Parent : Tree_Node_Access;
148 Before : Tree_Node_Access);
150 procedure Insert_Subtree_List
151 (First : Tree_Node_Access;
152 Last : Tree_Node_Access;
153 Parent : Tree_Node_Access;
154 Before : Tree_Node_Access);
156 procedure Splice_Children
157 (Target_Parent : Tree_Node_Access;
158 Before : Tree_Node_Access;
159 Source_Parent : Tree_Node_Access);
161 ---------
162 -- "=" --
163 ---------
165 function "=" (Left, Right : Tree) return Boolean is
166 begin
167 if Left'Address = Right'Address then
168 return True;
169 end if;
171 return Equal_Children (Root_Node (Left), Root_Node (Right));
172 end "=";
174 ------------
175 -- Adjust --
176 ------------
178 procedure Adjust (Container : in out Tree) is
179 Source : constant Children_Type := Container.Root.Children;
180 Source_Count : constant Count_Type := Container.Count;
181 Target_Count : Count_Type;
183 begin
184 -- We first restore the target container to its default-initialized
185 -- state, before we attempt any allocation, to ensure that invariants
186 -- are preserved in the event that the allocation fails.
188 Container.Root.Children := Children_Type'(others => null);
189 Container.Busy := 0;
190 Container.Lock := 0;
191 Container.Count := 0;
193 -- Copy_Children returns a count of the number of nodes that it
194 -- allocates, but it works by incrementing the value that is passed
195 -- in. We must therefore initialize the count value before calling
196 -- Copy_Children.
198 Target_Count := 0;
200 -- Now we attempt the allocation of subtrees. The invariants are
201 -- satisfied even if the allocation fails.
203 Copy_Children (Source, Root_Node (Container), Target_Count);
204 pragma Assert (Target_Count = Source_Count);
206 Container.Count := Source_Count;
207 end Adjust;
209 procedure Adjust (Control : in out Reference_Control_Type) is
210 begin
211 if Control.Container /= null then
212 declare
213 C : Tree renames Control.Container.all;
214 B : Natural renames C.Busy;
215 L : Natural renames C.Lock;
216 begin
217 B := B + 1;
218 L := L + 1;
219 end;
220 end if;
221 end Adjust;
223 -------------------
224 -- Ancestor_Find --
225 -------------------
227 function Ancestor_Find
228 (Position : Cursor;
229 Item : Element_Type) return Cursor
231 R, N : Tree_Node_Access;
233 begin
234 if Position = No_Element then
235 raise Constraint_Error with "Position cursor has no element";
236 end if;
238 -- Commented-out pending official ruling from ARG. ???
240 -- if Position.Container /= Container'Unrestricted_Access then
241 -- raise Program_Error with "Position cursor not in container";
242 -- end if;
244 -- AI-0136 says to raise PE if Position equals the root node. This does
245 -- not seem correct, as this value is just the limiting condition of the
246 -- search. For now we omit this check, pending a ruling from the ARG.???
248 -- if Is_Root (Position) then
249 -- raise Program_Error with "Position cursor designates root";
250 -- end if;
252 R := Root_Node (Position.Container.all);
253 N := Position.Node;
254 while N /= R loop
255 if N.Element = Item then
256 return Cursor'(Position.Container, N);
257 end if;
259 N := N.Parent;
260 end loop;
262 return No_Element;
263 end Ancestor_Find;
265 ------------------
266 -- Append_Child --
267 ------------------
269 procedure Append_Child
270 (Container : in out Tree;
271 Parent : Cursor;
272 New_Item : Element_Type;
273 Count : Count_Type := 1)
275 First, Last : Tree_Node_Access;
277 begin
278 if Parent = No_Element then
279 raise Constraint_Error with "Parent cursor has no element";
280 end if;
282 if Parent.Container /= Container'Unrestricted_Access then
283 raise Program_Error with "Parent cursor not in container";
284 end if;
286 if Count = 0 then
287 return;
288 end if;
290 if Container.Busy > 0 then
291 raise Program_Error
292 with "attempt to tamper with cursors (tree is busy)";
293 end if;
295 First := new Tree_Node_Type'(Parent => Parent.Node,
296 Element => New_Item,
297 others => <>);
299 Last := First;
301 for J in Count_Type'(2) .. Count loop
303 -- Reclaim other nodes if Storage_Error. ???
305 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
306 Prev => Last,
307 Element => New_Item,
308 others => <>);
310 Last := Last.Next;
311 end loop;
313 Insert_Subtree_List
314 (First => First,
315 Last => Last,
316 Parent => Parent.Node,
317 Before => null); -- null means "insert at end of list"
319 -- In order for operation Node_Count to complete in O(1) time, we cache
320 -- the count value. Here we increment the total count by the number of
321 -- nodes we just inserted.
323 Container.Count := Container.Count + Count;
324 end Append_Child;
326 ------------
327 -- Assign --
328 ------------
330 procedure Assign (Target : in out Tree; Source : Tree) is
331 Source_Count : constant Count_Type := Source.Count;
332 Target_Count : Count_Type;
334 begin
335 if Target'Address = Source'Address then
336 return;
337 end if;
339 Target.Clear; -- checks busy bit
341 -- Copy_Children returns the number of nodes that it allocates, but it
342 -- does this by incrementing the count value passed in, so we must
343 -- initialize the count before calling Copy_Children.
345 Target_Count := 0;
347 -- Note that Copy_Children inserts the newly-allocated children into
348 -- their parent list only after the allocation of all the children has
349 -- succeeded. This preserves invariants even if the allocation fails.
351 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
352 pragma Assert (Target_Count = Source_Count);
354 Target.Count := Source_Count;
355 end Assign;
357 -----------------
358 -- Child_Count --
359 -----------------
361 function Child_Count (Parent : Cursor) return Count_Type is
362 begin
363 return (if Parent = No_Element
364 then 0 else Child_Count (Parent.Node.Children));
365 end Child_Count;
367 function Child_Count (Children : Children_Type) return Count_Type is
368 Result : Count_Type;
369 Node : Tree_Node_Access;
371 begin
372 Result := 0;
373 Node := Children.First;
374 while Node /= null loop
375 Result := Result + 1;
376 Node := Node.Next;
377 end loop;
379 return Result;
380 end Child_Count;
382 -----------------
383 -- Child_Depth --
384 -----------------
386 function Child_Depth (Parent, Child : Cursor) return Count_Type is
387 Result : Count_Type;
388 N : Tree_Node_Access;
390 begin
391 if Parent = No_Element then
392 raise Constraint_Error with "Parent cursor has no element";
393 end if;
395 if Child = No_Element then
396 raise Constraint_Error with "Child cursor has no element";
397 end if;
399 if Parent.Container /= Child.Container then
400 raise Program_Error with "Parent and Child in different containers";
401 end if;
403 Result := 0;
404 N := Child.Node;
405 while N /= Parent.Node loop
406 Result := Result + 1;
407 N := N.Parent;
409 if N = null then
410 raise Program_Error with "Parent is not ancestor of Child";
411 end if;
412 end loop;
414 return Result;
415 end Child_Depth;
417 -----------
418 -- Clear --
419 -----------
421 procedure Clear (Container : in out Tree) is
422 Container_Count, Children_Count : Count_Type;
424 begin
425 if Container.Busy > 0 then
426 raise Program_Error
427 with "attempt to tamper with cursors (tree is busy)";
428 end if;
430 -- We first set the container count to 0, in order to preserve
431 -- invariants in case the deallocation fails. (This works because
432 -- Deallocate_Children immediately removes the children from their
433 -- parent, and then does the actual deallocation.)
435 Container_Count := Container.Count;
436 Container.Count := 0;
438 -- Deallocate_Children returns the number of nodes that it deallocates,
439 -- but it does this by incrementing the count value that is passed in,
440 -- so we must first initialize the count return value before calling it.
442 Children_Count := 0;
444 -- See comment above. Deallocate_Children immediately removes the
445 -- children list from their parent node (here, the root of the tree),
446 -- and only after that does it attempt the actual deallocation. So even
447 -- if the deallocation fails, the representation invariants for the tree
448 -- are preserved.
450 Deallocate_Children (Root_Node (Container), Children_Count);
451 pragma Assert (Children_Count = Container_Count);
452 end Clear;
454 ------------------------
455 -- Constant_Reference --
456 ------------------------
458 function Constant_Reference
459 (Container : aliased Tree;
460 Position : Cursor) return Constant_Reference_Type
462 begin
463 if Position.Container = null then
464 raise Constraint_Error with
465 "Position cursor has no element";
466 end if;
468 if Position.Container /= Container'Unrestricted_Access then
469 raise Program_Error with
470 "Position cursor designates wrong container";
471 end if;
473 if Position.Node = Root_Node (Container) then
474 raise Program_Error with "Position cursor designates root";
475 end if;
477 -- Implement Vet for multiway tree???
478 -- pragma Assert (Vet (Position),
479 -- "Position cursor in Constant_Reference is bad");
481 declare
482 C : Tree renames Position.Container.all;
483 B : Natural renames C.Busy;
484 L : Natural renames C.Lock;
485 begin
486 return R : constant Constant_Reference_Type :=
487 (Element => Position.Node.Element'Access,
488 Control => (Controlled with Container'Unrestricted_Access))
490 B := B + 1;
491 L := L + 1;
492 end return;
493 end;
494 end Constant_Reference;
496 --------------
497 -- Contains --
498 --------------
500 function Contains
501 (Container : Tree;
502 Item : Element_Type) return Boolean
504 begin
505 return Find (Container, Item) /= No_Element;
506 end Contains;
508 ----------
509 -- Copy --
510 ----------
512 function Copy (Source : Tree) return Tree is
513 begin
514 return Target : Tree do
515 Copy_Children
516 (Source => Source.Root.Children,
517 Parent => Root_Node (Target),
518 Count => Target.Count);
520 pragma Assert (Target.Count = Source.Count);
521 end return;
522 end Copy;
524 -------------------
525 -- Copy_Children --
526 -------------------
528 procedure Copy_Children
529 (Source : Children_Type;
530 Parent : Tree_Node_Access;
531 Count : in out Count_Type)
533 pragma Assert (Parent /= null);
534 pragma Assert (Parent.Children.First = null);
535 pragma Assert (Parent.Children.Last = null);
537 CC : Children_Type;
538 C : Tree_Node_Access;
540 begin
541 -- We special-case the first allocation, in order to establish the
542 -- representation invariants for type Children_Type.
544 C := Source.First;
546 if C = null then
547 return;
548 end if;
550 Copy_Subtree
551 (Source => C,
552 Parent => Parent,
553 Target => CC.First,
554 Count => Count);
556 CC.Last := CC.First;
558 -- The representation invariants for the Children_Type list have been
559 -- established, so we can now copy the remaining children of Source.
561 C := C.Next;
562 while C /= null loop
563 Copy_Subtree
564 (Source => C,
565 Parent => Parent,
566 Target => CC.Last.Next,
567 Count => Count);
569 CC.Last.Next.Prev := CC.Last;
570 CC.Last := CC.Last.Next;
572 C := C.Next;
573 end loop;
575 -- Add the newly-allocated children to their parent list only after the
576 -- allocation has succeeded, so as to preserve invariants of the parent.
578 Parent.Children := CC;
579 end Copy_Children;
581 ------------------
582 -- Copy_Subtree --
583 ------------------
585 procedure Copy_Subtree
586 (Target : in out Tree;
587 Parent : Cursor;
588 Before : Cursor;
589 Source : Cursor)
591 Target_Subtree : Tree_Node_Access;
592 Target_Count : Count_Type;
594 begin
595 if Parent = No_Element then
596 raise Constraint_Error with "Parent cursor has no element";
597 end if;
599 if Parent.Container /= Target'Unrestricted_Access then
600 raise Program_Error with "Parent cursor not in container";
601 end if;
603 if Before /= No_Element then
604 if Before.Container /= Target'Unrestricted_Access then
605 raise Program_Error with "Before cursor not in container";
606 end if;
608 if Before.Node.Parent /= Parent.Node then
609 raise Constraint_Error with "Before cursor not child of Parent";
610 end if;
611 end if;
613 if Source = No_Element then
614 return;
615 end if;
617 if Is_Root (Source) then
618 raise Constraint_Error with "Source cursor designates root";
619 end if;
621 -- Copy_Subtree returns a count of the number of nodes that it
622 -- allocates, but it works by incrementing the value that is passed
623 -- in. We must therefore initialize the count value before calling
624 -- Copy_Subtree.
626 Target_Count := 0;
628 Copy_Subtree
629 (Source => Source.Node,
630 Parent => Parent.Node,
631 Target => Target_Subtree,
632 Count => Target_Count);
634 pragma Assert (Target_Subtree /= null);
635 pragma Assert (Target_Subtree.Parent = Parent.Node);
636 pragma Assert (Target_Count >= 1);
638 Insert_Subtree_Node
639 (Subtree => Target_Subtree,
640 Parent => Parent.Node,
641 Before => Before.Node);
643 -- In order for operation Node_Count to complete in O(1) time, we cache
644 -- the count value. Here we increment the total count by the number of
645 -- nodes we just inserted.
647 Target.Count := Target.Count + Target_Count;
648 end Copy_Subtree;
650 procedure Copy_Subtree
651 (Source : Tree_Node_Access;
652 Parent : Tree_Node_Access;
653 Target : out Tree_Node_Access;
654 Count : in out Count_Type)
656 begin
657 Target := new Tree_Node_Type'(Element => Source.Element,
658 Parent => Parent,
659 others => <>);
661 Count := Count + 1;
663 Copy_Children
664 (Source => Source.Children,
665 Parent => Target,
666 Count => Count);
667 end Copy_Subtree;
669 -------------------------
670 -- Deallocate_Children --
671 -------------------------
673 procedure Deallocate_Children
674 (Subtree : Tree_Node_Access;
675 Count : in out Count_Type)
677 pragma Assert (Subtree /= null);
679 CC : Children_Type := Subtree.Children;
680 C : Tree_Node_Access;
682 begin
683 -- We immediately remove the children from their parent, in order to
684 -- preserve invariants in case the deallocation fails.
686 Subtree.Children := Children_Type'(others => null);
688 while CC.First /= null loop
689 C := CC.First;
690 CC.First := C.Next;
692 Deallocate_Subtree (C, Count);
693 end loop;
694 end Deallocate_Children;
696 ------------------------
697 -- Deallocate_Subtree --
698 ------------------------
700 procedure Deallocate_Subtree
701 (Subtree : in out Tree_Node_Access;
702 Count : in out Count_Type)
704 begin
705 Deallocate_Children (Subtree, Count);
706 Deallocate_Node (Subtree);
707 Count := Count + 1;
708 end Deallocate_Subtree;
710 ---------------------
711 -- Delete_Children --
712 ---------------------
714 procedure Delete_Children
715 (Container : in out Tree;
716 Parent : Cursor)
718 Count : Count_Type;
720 begin
721 if Parent = No_Element then
722 raise Constraint_Error with "Parent cursor has no element";
723 end if;
725 if Parent.Container /= Container'Unrestricted_Access then
726 raise Program_Error with "Parent cursor not in container";
727 end if;
729 if Container.Busy > 0 then
730 raise Program_Error
731 with "attempt to tamper with cursors (tree is busy)";
732 end if;
734 -- Deallocate_Children returns a count of the number of nodes that it
735 -- deallocates, but it works by incrementing the value that is passed
736 -- in. We must therefore initialize the count value before calling
737 -- Deallocate_Children.
739 Count := 0;
741 Deallocate_Children (Parent.Node, Count);
742 pragma Assert (Count <= Container.Count);
744 Container.Count := Container.Count - Count;
745 end Delete_Children;
747 -----------------
748 -- Delete_Leaf --
749 -----------------
751 procedure Delete_Leaf
752 (Container : in out Tree;
753 Position : in out Cursor)
755 X : Tree_Node_Access;
757 begin
758 if Position = No_Element then
759 raise Constraint_Error with "Position cursor has no element";
760 end if;
762 if Position.Container /= Container'Unrestricted_Access then
763 raise Program_Error with "Position cursor not in container";
764 end if;
766 if Is_Root (Position) then
767 raise Program_Error with "Position cursor designates root";
768 end if;
770 if not Is_Leaf (Position) then
771 raise Constraint_Error with "Position cursor does not designate leaf";
772 end if;
774 if Container.Busy > 0 then
775 raise Program_Error
776 with "attempt to tamper with cursors (tree is busy)";
777 end if;
779 X := Position.Node;
780 Position := No_Element;
782 -- Restore represention invariants before attempting the actual
783 -- deallocation.
785 Remove_Subtree (X);
786 Container.Count := Container.Count - 1;
788 -- It is now safe to attempt the deallocation. This leaf node has been
789 -- disassociated from the tree, so even if the deallocation fails,
790 -- representation invariants will remain satisfied.
792 Deallocate_Node (X);
793 end Delete_Leaf;
795 --------------------
796 -- Delete_Subtree --
797 --------------------
799 procedure Delete_Subtree
800 (Container : in out Tree;
801 Position : in out Cursor)
803 X : Tree_Node_Access;
804 Count : Count_Type;
806 begin
807 if Position = No_Element then
808 raise Constraint_Error with "Position cursor has no element";
809 end if;
811 if Position.Container /= Container'Unrestricted_Access then
812 raise Program_Error with "Position cursor not in container";
813 end if;
815 if Is_Root (Position) then
816 raise Program_Error with "Position cursor designates root";
817 end if;
819 if Container.Busy > 0 then
820 raise Program_Error
821 with "attempt to tamper with cursors (tree is busy)";
822 end if;
824 X := Position.Node;
825 Position := No_Element;
827 -- Here is one case where a deallocation failure can result in the
828 -- violation of a representation invariant. We disassociate the subtree
829 -- from the tree now, but we only decrement the total node count after
830 -- we attempt the deallocation. However, if the deallocation fails, the
831 -- total node count will not get decremented.
833 -- One way around this dilemma is to count the nodes in the subtree
834 -- before attempt to delete the subtree, but that is an O(n) operation,
835 -- so it does not seem worth it.
837 -- Perhaps this is much ado about nothing, since the only way
838 -- deallocation can fail is if Controlled Finalization fails: this
839 -- propagates Program_Error so all bets are off anyway. ???
841 Remove_Subtree (X);
843 -- Deallocate_Subtree returns a count of the number of nodes that it
844 -- deallocates, but it works by incrementing the value that is passed
845 -- in. We must therefore initialize the count value before calling
846 -- Deallocate_Subtree.
848 Count := 0;
850 Deallocate_Subtree (X, Count);
851 pragma Assert (Count <= Container.Count);
853 -- See comments above. We would prefer to do this sooner, but there's no
854 -- way to satisfy that goal without a potentially severe execution
855 -- penalty.
857 Container.Count := Container.Count - Count;
858 end Delete_Subtree;
860 -----------
861 -- Depth --
862 -----------
864 function Depth (Position : Cursor) return Count_Type is
865 Result : Count_Type;
866 N : Tree_Node_Access;
868 begin
869 Result := 0;
870 N := Position.Node;
871 while N /= null loop
872 N := N.Parent;
873 Result := Result + 1;
874 end loop;
876 return Result;
877 end Depth;
879 -------------
880 -- Element --
881 -------------
883 function Element (Position : Cursor) return Element_Type is
884 begin
885 if Position.Container = null then
886 raise Constraint_Error with "Position cursor has no element";
887 end if;
889 if Position.Node = Root_Node (Position.Container.all) then
890 raise Program_Error with "Position cursor designates root";
891 end if;
893 return Position.Node.Element;
894 end Element;
896 --------------------
897 -- Equal_Children --
898 --------------------
900 function Equal_Children
901 (Left_Subtree : Tree_Node_Access;
902 Right_Subtree : Tree_Node_Access) return Boolean
904 Left_Children : Children_Type renames Left_Subtree.Children;
905 Right_Children : Children_Type renames Right_Subtree.Children;
907 L, R : Tree_Node_Access;
909 begin
910 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
911 return False;
912 end if;
914 L := Left_Children.First;
915 R := Right_Children.First;
916 while L /= null loop
917 if not Equal_Subtree (L, R) then
918 return False;
919 end if;
921 L := L.Next;
922 R := R.Next;
923 end loop;
925 return True;
926 end Equal_Children;
928 -------------------
929 -- Equal_Subtree --
930 -------------------
932 function Equal_Subtree
933 (Left_Position : Cursor;
934 Right_Position : Cursor) return Boolean
936 begin
937 if Left_Position = No_Element then
938 raise Constraint_Error with "Left cursor has no element";
939 end if;
941 if Right_Position = No_Element then
942 raise Constraint_Error with "Right cursor has no element";
943 end if;
945 if Left_Position = Right_Position then
946 return True;
947 end if;
949 if Is_Root (Left_Position) then
950 if not Is_Root (Right_Position) then
951 return False;
952 end if;
954 return Equal_Children (Left_Position.Node, Right_Position.Node);
955 end if;
957 if Is_Root (Right_Position) then
958 return False;
959 end if;
961 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
962 end Equal_Subtree;
964 function Equal_Subtree
965 (Left_Subtree : Tree_Node_Access;
966 Right_Subtree : Tree_Node_Access) return Boolean
968 begin
969 if Left_Subtree.Element /= Right_Subtree.Element then
970 return False;
971 end if;
973 return Equal_Children (Left_Subtree, Right_Subtree);
974 end Equal_Subtree;
976 --------------
977 -- Finalize --
978 --------------
980 procedure Finalize (Object : in out Root_Iterator) is
981 B : Natural renames Object.Container.Busy;
982 begin
983 B := B - 1;
984 end Finalize;
986 procedure Finalize (Control : in out Reference_Control_Type) is
987 begin
988 if Control.Container /= null then
989 declare
990 C : Tree renames Control.Container.all;
991 B : Natural renames C.Busy;
992 L : Natural renames C.Lock;
993 begin
994 B := B - 1;
995 L := L - 1;
996 end;
998 Control.Container := null;
999 end if;
1000 end Finalize;
1002 ----------
1003 -- Find --
1004 ----------
1006 function Find
1007 (Container : Tree;
1008 Item : Element_Type) return Cursor
1010 N : constant Tree_Node_Access :=
1011 Find_In_Children (Root_Node (Container), Item);
1012 begin
1013 if N = null then
1014 return No_Element;
1015 else
1016 return Cursor'(Container'Unrestricted_Access, N);
1017 end if;
1018 end Find;
1020 -----------
1021 -- First --
1022 -----------
1024 overriding function First (Object : Subtree_Iterator) return Cursor is
1025 begin
1026 if Object.Subtree = Root_Node (Object.Container.all) then
1027 return First_Child (Root (Object.Container.all));
1028 else
1029 return Cursor'(Object.Container, Object.Subtree);
1030 end if;
1031 end First;
1033 overriding function First (Object : Child_Iterator) return Cursor is
1034 begin
1035 return First_Child (Cursor'(Object.Container, Object.Subtree));
1036 end First;
1038 -----------------
1039 -- First_Child --
1040 -----------------
1042 function First_Child (Parent : Cursor) return Cursor is
1043 Node : Tree_Node_Access;
1045 begin
1046 if Parent = No_Element then
1047 raise Constraint_Error with "Parent cursor has no element";
1048 end if;
1050 Node := Parent.Node.Children.First;
1052 if Node = null then
1053 return No_Element;
1054 end if;
1056 return Cursor'(Parent.Container, Node);
1057 end First_Child;
1059 -------------------------
1060 -- First_Child_Element --
1061 -------------------------
1063 function First_Child_Element (Parent : Cursor) return Element_Type is
1064 begin
1065 return Element (First_Child (Parent));
1066 end First_Child_Element;
1068 ----------------------
1069 -- Find_In_Children --
1070 ----------------------
1072 function Find_In_Children
1073 (Subtree : Tree_Node_Access;
1074 Item : Element_Type) return Tree_Node_Access
1076 N, Result : Tree_Node_Access;
1078 begin
1079 N := Subtree.Children.First;
1080 while N /= null loop
1081 Result := Find_In_Subtree (N, Item);
1083 if Result /= null then
1084 return Result;
1085 end if;
1087 N := N.Next;
1088 end loop;
1090 return null;
1091 end Find_In_Children;
1093 ---------------------
1094 -- Find_In_Subtree --
1095 ---------------------
1097 function Find_In_Subtree
1098 (Position : Cursor;
1099 Item : Element_Type) return Cursor
1101 Result : Tree_Node_Access;
1103 begin
1104 if Position = No_Element then
1105 raise Constraint_Error with "Position cursor has no element";
1106 end if;
1108 -- Commented out pending official ruling by ARG. ???
1110 -- if Position.Container /= Container'Unrestricted_Access then
1111 -- raise Program_Error with "Position cursor not in container";
1112 -- end if;
1114 Result :=
1115 (if Is_Root (Position)
1116 then Find_In_Children (Position.Node, Item)
1117 else Find_In_Subtree (Position.Node, Item));
1119 if Result = null then
1120 return No_Element;
1121 end if;
1123 return Cursor'(Position.Container, Result);
1124 end Find_In_Subtree;
1126 function Find_In_Subtree
1127 (Subtree : Tree_Node_Access;
1128 Item : Element_Type) return Tree_Node_Access
1130 begin
1131 if Subtree.Element = Item then
1132 return Subtree;
1133 end if;
1135 return Find_In_Children (Subtree, Item);
1136 end Find_In_Subtree;
1138 -----------------
1139 -- Has_Element --
1140 -----------------
1142 function Has_Element (Position : Cursor) return Boolean is
1143 begin
1144 return (if Position = No_Element then False
1145 else Position.Node.Parent /= null);
1146 end Has_Element;
1148 ------------------
1149 -- Insert_Child --
1150 ------------------
1152 procedure Insert_Child
1153 (Container : in out Tree;
1154 Parent : Cursor;
1155 Before : Cursor;
1156 New_Item : Element_Type;
1157 Count : Count_Type := 1)
1159 Position : Cursor;
1160 pragma Unreferenced (Position);
1162 begin
1163 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1164 end Insert_Child;
1166 procedure Insert_Child
1167 (Container : in out Tree;
1168 Parent : Cursor;
1169 Before : Cursor;
1170 New_Item : Element_Type;
1171 Position : out Cursor;
1172 Count : Count_Type := 1)
1174 Last : Tree_Node_Access;
1176 begin
1177 if Parent = No_Element then
1178 raise Constraint_Error with "Parent cursor has no element";
1179 end if;
1181 if Parent.Container /= Container'Unrestricted_Access then
1182 raise Program_Error with "Parent cursor not in container";
1183 end if;
1185 if Before /= No_Element then
1186 if Before.Container /= Container'Unrestricted_Access then
1187 raise Program_Error with "Before cursor not in container";
1188 end if;
1190 if Before.Node.Parent /= Parent.Node then
1191 raise Constraint_Error with "Parent cursor not parent of Before";
1192 end if;
1193 end if;
1195 if Count = 0 then
1196 Position := No_Element; -- Need ruling from ARG ???
1197 return;
1198 end if;
1200 if Container.Busy > 0 then
1201 raise Program_Error
1202 with "attempt to tamper with cursors (tree is busy)";
1203 end if;
1205 Position.Container := Parent.Container;
1206 Position.Node := new Tree_Node_Type'(Parent => Parent.Node,
1207 Element => New_Item,
1208 others => <>);
1210 Last := Position.Node;
1212 for J in Count_Type'(2) .. Count loop
1214 -- Reclaim other nodes if Storage_Error. ???
1216 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1217 Prev => Last,
1218 Element => New_Item,
1219 others => <>);
1221 Last := Last.Next;
1222 end loop;
1224 Insert_Subtree_List
1225 (First => Position.Node,
1226 Last => Last,
1227 Parent => Parent.Node,
1228 Before => Before.Node);
1230 -- In order for operation Node_Count to complete in O(1) time, we cache
1231 -- the count value. Here we increment the total count by the number of
1232 -- nodes we just inserted.
1234 Container.Count := Container.Count + Count;
1235 end Insert_Child;
1237 procedure Insert_Child
1238 (Container : in out Tree;
1239 Parent : Cursor;
1240 Before : Cursor;
1241 Position : out Cursor;
1242 Count : Count_Type := 1)
1244 Last : Tree_Node_Access;
1246 begin
1247 if Parent = No_Element then
1248 raise Constraint_Error with "Parent cursor has no element";
1249 end if;
1251 if Parent.Container /= Container'Unrestricted_Access then
1252 raise Program_Error with "Parent cursor not in container";
1253 end if;
1255 if Before /= No_Element then
1256 if Before.Container /= Container'Unrestricted_Access then
1257 raise Program_Error with "Before cursor not in container";
1258 end if;
1260 if Before.Node.Parent /= Parent.Node then
1261 raise Constraint_Error with "Parent cursor not parent of Before";
1262 end if;
1263 end if;
1265 if Count = 0 then
1266 Position := No_Element; -- Need ruling from ARG ???
1267 return;
1268 end if;
1270 if Container.Busy > 0 then
1271 raise Program_Error
1272 with "attempt to tamper with cursors (tree is busy)";
1273 end if;
1275 Position.Container := Parent.Container;
1276 Position.Node := new Tree_Node_Type'(Parent => Parent.Node,
1277 Element => <>,
1278 others => <>);
1280 Last := Position.Node;
1282 for J in Count_Type'(2) .. Count loop
1284 -- Reclaim other nodes if Storage_Error. ???
1286 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1287 Prev => Last,
1288 Element => <>,
1289 others => <>);
1291 Last := Last.Next;
1292 end loop;
1294 Insert_Subtree_List
1295 (First => Position.Node,
1296 Last => Last,
1297 Parent => Parent.Node,
1298 Before => Before.Node);
1300 -- In order for operation Node_Count to complete in O(1) time, we cache
1301 -- the count value. Here we increment the total count by the number of
1302 -- nodes we just inserted.
1304 Container.Count := Container.Count + Count;
1305 end Insert_Child;
1307 -------------------------
1308 -- Insert_Subtree_List --
1309 -------------------------
1311 procedure Insert_Subtree_List
1312 (First : Tree_Node_Access;
1313 Last : Tree_Node_Access;
1314 Parent : Tree_Node_Access;
1315 Before : Tree_Node_Access)
1317 pragma Assert (Parent /= null);
1318 C : Children_Type renames Parent.Children;
1320 begin
1321 -- This is a simple utility operation to insert a list of nodes (from
1322 -- First..Last) as children of Parent. The Before node specifies where
1323 -- the new children should be inserted relative to the existing
1324 -- children.
1326 if First = null then
1327 pragma Assert (Last = null);
1328 return;
1329 end if;
1331 pragma Assert (Last /= null);
1332 pragma Assert (Before = null or else Before.Parent = Parent);
1334 if C.First = null then
1335 C.First := First;
1336 C.First.Prev := null;
1337 C.Last := Last;
1338 C.Last.Next := null;
1340 elsif Before = null then -- means "insert after existing nodes"
1341 C.Last.Next := First;
1342 First.Prev := C.Last;
1343 C.Last := Last;
1344 C.Last.Next := null;
1346 elsif Before = C.First then
1347 Last.Next := C.First;
1348 C.First.Prev := Last;
1349 C.First := First;
1350 C.First.Prev := null;
1352 else
1353 Before.Prev.Next := First;
1354 First.Prev := Before.Prev;
1355 Last.Next := Before;
1356 Before.Prev := Last;
1357 end if;
1358 end Insert_Subtree_List;
1360 -------------------------
1361 -- Insert_Subtree_Node --
1362 -------------------------
1364 procedure Insert_Subtree_Node
1365 (Subtree : Tree_Node_Access;
1366 Parent : Tree_Node_Access;
1367 Before : Tree_Node_Access)
1369 begin
1370 -- This is a simple wrapper operation to insert a single child into the
1371 -- Parent's children list.
1373 Insert_Subtree_List
1374 (First => Subtree,
1375 Last => Subtree,
1376 Parent => Parent,
1377 Before => Before);
1378 end Insert_Subtree_Node;
1380 --------------
1381 -- Is_Empty --
1382 --------------
1384 function Is_Empty (Container : Tree) return Boolean is
1385 begin
1386 return Container.Root.Children.First = null;
1387 end Is_Empty;
1389 -------------
1390 -- Is_Leaf --
1391 -------------
1393 function Is_Leaf (Position : Cursor) return Boolean is
1394 begin
1395 return (if Position = No_Element then False
1396 else Position.Node.Children.First = null);
1397 end Is_Leaf;
1399 ------------------
1400 -- Is_Reachable --
1401 ------------------
1403 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1404 pragma Assert (From /= null);
1405 pragma Assert (To /= null);
1407 N : Tree_Node_Access;
1409 begin
1410 N := From;
1411 while N /= null loop
1412 if N = To then
1413 return True;
1414 end if;
1416 N := N.Parent;
1417 end loop;
1419 return False;
1420 end Is_Reachable;
1422 -------------
1423 -- Is_Root --
1424 -------------
1426 function Is_Root (Position : Cursor) return Boolean is
1427 begin
1428 return (if Position.Container = null then False
1429 else Position = Root (Position.Container.all));
1430 end Is_Root;
1432 -------------
1433 -- Iterate --
1434 -------------
1436 procedure Iterate
1437 (Container : Tree;
1438 Process : not null access procedure (Position : Cursor))
1440 B : Natural renames Container'Unrestricted_Access.all.Busy;
1442 begin
1443 B := B + 1;
1445 Iterate_Children
1446 (Container => Container'Unrestricted_Access,
1447 Subtree => Root_Node (Container),
1448 Process => Process);
1450 B := B - 1;
1452 exception
1453 when others =>
1454 B := B - 1;
1455 raise;
1456 end Iterate;
1458 function Iterate (Container : Tree)
1459 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1461 begin
1462 return Iterate_Subtree (Root (Container));
1463 end Iterate;
1465 ----------------------
1466 -- Iterate_Children --
1467 ----------------------
1469 procedure Iterate_Children
1470 (Parent : Cursor;
1471 Process : not null access procedure (Position : Cursor))
1473 begin
1474 if Parent = No_Element then
1475 raise Constraint_Error with "Parent cursor has no element";
1476 end if;
1478 declare
1479 B : Natural renames Parent.Container.Busy;
1480 C : Tree_Node_Access;
1482 begin
1483 B := B + 1;
1485 C := Parent.Node.Children.First;
1486 while C /= null loop
1487 Process (Position => Cursor'(Parent.Container, Node => C));
1488 C := C.Next;
1489 end loop;
1491 B := B - 1;
1493 exception
1494 when others =>
1495 B := B - 1;
1496 raise;
1497 end;
1498 end Iterate_Children;
1500 procedure Iterate_Children
1501 (Container : Tree_Access;
1502 Subtree : Tree_Node_Access;
1503 Process : not null access procedure (Position : Cursor))
1505 Node : Tree_Node_Access;
1507 begin
1508 -- This is a helper function to recursively iterate over all the nodes
1509 -- in a subtree, in depth-first fashion. This particular helper just
1510 -- visits the children of this subtree, not the root of the subtree node
1511 -- itself. This is useful when starting from the ultimate root of the
1512 -- entire tree (see Iterate), as that root does not have an element.
1514 Node := Subtree.Children.First;
1515 while Node /= null loop
1516 Iterate_Subtree (Container, Node, Process);
1517 Node := Node.Next;
1518 end loop;
1519 end Iterate_Children;
1521 function Iterate_Children
1522 (Container : Tree;
1523 Parent : Cursor)
1524 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1526 C : constant Tree_Access := Container'Unrestricted_Access;
1527 B : Natural renames C.Busy;
1529 begin
1530 if Parent = No_Element then
1531 raise Constraint_Error with "Parent cursor has no element";
1532 end if;
1534 if Parent.Container /= C then
1535 raise Program_Error with "Parent cursor not in container";
1536 end if;
1538 return It : constant Child_Iterator :=
1539 (Limited_Controlled with
1540 Container => C,
1541 Subtree => Parent.Node)
1543 B := B + 1;
1544 end return;
1545 end Iterate_Children;
1547 ---------------------
1548 -- Iterate_Subtree --
1549 ---------------------
1551 function Iterate_Subtree
1552 (Position : Cursor)
1553 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1555 begin
1556 if Position = No_Element then
1557 raise Constraint_Error with "Position cursor has no element";
1558 end if;
1560 -- Implement Vet for multiway trees???
1561 -- pragma Assert (Vet (Position), "bad subtree cursor");
1563 declare
1564 B : Natural renames Position.Container.Busy;
1565 begin
1566 return It : constant Subtree_Iterator :=
1567 (Limited_Controlled with
1568 Container => Position.Container,
1569 Subtree => Position.Node)
1571 B := B + 1;
1572 end return;
1573 end;
1574 end Iterate_Subtree;
1576 procedure Iterate_Subtree
1577 (Position : Cursor;
1578 Process : not null access procedure (Position : Cursor))
1580 begin
1581 if Position = No_Element then
1582 raise Constraint_Error with "Position cursor has no element";
1583 end if;
1585 declare
1586 B : Natural renames Position.Container.Busy;
1588 begin
1589 B := B + 1;
1591 if Is_Root (Position) then
1592 Iterate_Children (Position.Container, Position.Node, Process);
1593 else
1594 Iterate_Subtree (Position.Container, Position.Node, Process);
1595 end if;
1597 B := B - 1;
1599 exception
1600 when others =>
1601 B := B - 1;
1602 raise;
1603 end;
1604 end Iterate_Subtree;
1606 procedure Iterate_Subtree
1607 (Container : Tree_Access;
1608 Subtree : Tree_Node_Access;
1609 Process : not null access procedure (Position : Cursor))
1611 begin
1612 -- This is a helper function to recursively iterate over all the nodes
1613 -- in a subtree, in depth-first fashion. It first visits the root of the
1614 -- subtree, then visits its children.
1616 Process (Cursor'(Container, Subtree));
1617 Iterate_Children (Container, Subtree, Process);
1618 end Iterate_Subtree;
1620 ----------
1621 -- Last --
1622 ----------
1624 overriding function Last (Object : Child_Iterator) return Cursor is
1625 begin
1626 return Last_Child (Cursor'(Object.Container, Object.Subtree));
1627 end Last;
1629 ----------------
1630 -- Last_Child --
1631 ----------------
1633 function Last_Child (Parent : Cursor) return Cursor is
1634 Node : Tree_Node_Access;
1636 begin
1637 if Parent = No_Element then
1638 raise Constraint_Error with "Parent cursor has no element";
1639 end if;
1641 Node := Parent.Node.Children.Last;
1643 if Node = null then
1644 return No_Element;
1645 end if;
1647 return (Parent.Container, Node);
1648 end Last_Child;
1650 ------------------------
1651 -- Last_Child_Element --
1652 ------------------------
1654 function Last_Child_Element (Parent : Cursor) return Element_Type is
1655 begin
1656 return Element (Last_Child (Parent));
1657 end Last_Child_Element;
1659 ----------
1660 -- Move --
1661 ----------
1663 procedure Move (Target : in out Tree; Source : in out Tree) is
1664 Node : Tree_Node_Access;
1666 begin
1667 if Target'Address = Source'Address then
1668 return;
1669 end if;
1671 if Source.Busy > 0 then
1672 raise Program_Error
1673 with "attempt to tamper with cursors of Source (tree is busy)";
1674 end if;
1676 Target.Clear; -- checks busy bit
1678 Target.Root.Children := Source.Root.Children;
1679 Source.Root.Children := Children_Type'(others => null);
1681 Node := Target.Root.Children.First;
1682 while Node /= null loop
1683 Node.Parent := Root_Node (Target);
1684 Node := Node.Next;
1685 end loop;
1687 Target.Count := Source.Count;
1688 Source.Count := 0;
1689 end Move;
1691 ----------
1692 -- Next --
1693 ----------
1695 function Next
1696 (Object : Subtree_Iterator;
1697 Position : Cursor) return Cursor
1699 Node : Tree_Node_Access;
1701 begin
1702 if Position.Container = null then
1703 return No_Element;
1704 end if;
1706 if Position.Container /= Object.Container then
1707 raise Program_Error with
1708 "Position cursor of Next designates wrong tree";
1709 end if;
1711 Node := Position.Node;
1713 if Node.Children.First /= null then
1714 return Cursor'(Object.Container, Node.Children.First);
1715 end if;
1717 while Node /= Object.Subtree loop
1718 if Node.Next /= null then
1719 return Cursor'(Object.Container, Node.Next);
1720 end if;
1722 Node := Node.Parent;
1723 end loop;
1725 return No_Element;
1726 end Next;
1728 function Next
1729 (Object : Child_Iterator;
1730 Position : Cursor) return Cursor
1732 begin
1733 if Position.Container = null then
1734 return No_Element;
1735 end if;
1737 if Position.Container /= Object.Container then
1738 raise Program_Error with
1739 "Position cursor of Next designates wrong tree";
1740 end if;
1742 return Next_Sibling (Position);
1743 end Next;
1745 ------------------
1746 -- Next_Sibling --
1747 ------------------
1749 function Next_Sibling (Position : Cursor) return Cursor is
1750 begin
1751 if Position = No_Element then
1752 return No_Element;
1753 end if;
1755 if Position.Node.Next = null then
1756 return No_Element;
1757 end if;
1759 return Cursor'(Position.Container, Position.Node.Next);
1760 end Next_Sibling;
1762 procedure Next_Sibling (Position : in out Cursor) is
1763 begin
1764 Position := Next_Sibling (Position);
1765 end Next_Sibling;
1767 ----------------
1768 -- Node_Count --
1769 ----------------
1771 function Node_Count (Container : Tree) return Count_Type is
1772 begin
1773 -- Container.Count is the number of nodes we have actually allocated. We
1774 -- cache the value specifically so this Node_Count operation can execute
1775 -- in O(1) time, which makes it behave similarly to how the Length
1776 -- selector function behaves for other containers.
1778 -- The cached node count value only describes the nodes we have
1779 -- allocated; the root node itself is not included in that count. The
1780 -- Node_Count operation returns a value that includes the root node
1781 -- (because the RM says so), so we must add 1 to our cached value.
1783 return 1 + Container.Count;
1784 end Node_Count;
1786 ------------
1787 -- Parent --
1788 ------------
1790 function Parent (Position : Cursor) return Cursor is
1791 begin
1792 if Position = No_Element then
1793 return No_Element;
1794 end if;
1796 if Position.Node.Parent = null then
1797 return No_Element;
1798 end if;
1800 return Cursor'(Position.Container, Position.Node.Parent);
1801 end Parent;
1803 -------------------
1804 -- Prepent_Child --
1805 -------------------
1807 procedure Prepend_Child
1808 (Container : in out Tree;
1809 Parent : Cursor;
1810 New_Item : Element_Type;
1811 Count : Count_Type := 1)
1813 First, Last : Tree_Node_Access;
1815 begin
1816 if Parent = No_Element then
1817 raise Constraint_Error with "Parent cursor has no element";
1818 end if;
1820 if Parent.Container /= Container'Unrestricted_Access then
1821 raise Program_Error with "Parent cursor not in container";
1822 end if;
1824 if Count = 0 then
1825 return;
1826 end if;
1828 if Container.Busy > 0 then
1829 raise Program_Error
1830 with "attempt to tamper with cursors (tree is busy)";
1831 end if;
1833 First := new Tree_Node_Type'(Parent => Parent.Node,
1834 Element => New_Item,
1835 others => <>);
1837 Last := First;
1839 for J in Count_Type'(2) .. Count loop
1841 -- Reclaim other nodes if Storage_Error???
1843 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1844 Prev => Last,
1845 Element => New_Item,
1846 others => <>);
1848 Last := Last.Next;
1849 end loop;
1851 Insert_Subtree_List
1852 (First => First,
1853 Last => Last,
1854 Parent => Parent.Node,
1855 Before => Parent.Node.Children.First);
1857 -- In order for operation Node_Count to complete in O(1) time, we cache
1858 -- the count value. Here we increment the total count by the number of
1859 -- nodes we just inserted.
1861 Container.Count := Container.Count + Count;
1862 end Prepend_Child;
1864 --------------
1865 -- Previous --
1866 --------------
1868 overriding function Previous
1869 (Object : Child_Iterator;
1870 Position : Cursor) return Cursor
1872 begin
1873 if Position.Container = null then
1874 return No_Element;
1875 end if;
1877 if Position.Container /= Object.Container then
1878 raise Program_Error with
1879 "Position cursor of Previous designates wrong tree";
1880 end if;
1882 return Previous_Sibling (Position);
1883 end Previous;
1885 ----------------------
1886 -- Previous_Sibling --
1887 ----------------------
1889 function Previous_Sibling (Position : Cursor) return Cursor is
1890 begin
1891 return
1892 (if Position = No_Element then No_Element
1893 elsif Position.Node.Prev = null then No_Element
1894 else Cursor'(Position.Container, Position.Node.Prev));
1895 end Previous_Sibling;
1897 procedure Previous_Sibling (Position : in out Cursor) is
1898 begin
1899 Position := Previous_Sibling (Position);
1900 end Previous_Sibling;
1902 -------------------
1903 -- Query_Element --
1904 -------------------
1906 procedure Query_Element
1907 (Position : Cursor;
1908 Process : not null access procedure (Element : Element_Type))
1910 begin
1911 if Position = No_Element then
1912 raise Constraint_Error with "Position cursor has no element";
1913 end if;
1915 if Is_Root (Position) then
1916 raise Program_Error with "Position cursor designates root";
1917 end if;
1919 declare
1920 T : Tree renames Position.Container.all'Unrestricted_Access.all;
1921 B : Natural renames T.Busy;
1922 L : Natural renames T.Lock;
1924 begin
1925 B := B + 1;
1926 L := L + 1;
1928 Process (Position.Node.Element);
1930 L := L - 1;
1931 B := B - 1;
1933 exception
1934 when others =>
1935 L := L - 1;
1936 B := B - 1;
1937 raise;
1938 end;
1939 end Query_Element;
1941 ----------
1942 -- Read --
1943 ----------
1945 procedure Read
1946 (Stream : not null access Root_Stream_Type'Class;
1947 Container : out Tree)
1949 procedure Read_Children (Subtree : Tree_Node_Access);
1951 function Read_Subtree
1952 (Parent : Tree_Node_Access) return Tree_Node_Access;
1954 Total_Count : Count_Type'Base;
1955 -- Value read from the stream that says how many elements follow
1957 Read_Count : Count_Type'Base;
1958 -- Actual number of elements read from the stream
1960 -------------------
1961 -- Read_Children --
1962 -------------------
1964 procedure Read_Children (Subtree : Tree_Node_Access) is
1965 pragma Assert (Subtree /= null);
1966 pragma Assert (Subtree.Children.First = null);
1967 pragma Assert (Subtree.Children.Last = null);
1969 Count : Count_Type'Base;
1970 -- Number of child subtrees
1972 C : Children_Type;
1974 begin
1975 Count_Type'Read (Stream, Count);
1977 if Count < 0 then
1978 raise Program_Error with "attempt to read from corrupt stream";
1979 end if;
1981 if Count = 0 then
1982 return;
1983 end if;
1985 C.First := Read_Subtree (Parent => Subtree);
1986 C.Last := C.First;
1988 for J in Count_Type'(2) .. Count loop
1989 C.Last.Next := Read_Subtree (Parent => Subtree);
1990 C.Last.Next.Prev := C.Last;
1991 C.Last := C.Last.Next;
1992 end loop;
1994 -- Now that the allocation and reads have completed successfully, it
1995 -- is safe to link the children to their parent.
1997 Subtree.Children := C;
1998 end Read_Children;
2000 ------------------
2001 -- Read_Subtree --
2002 ------------------
2004 function Read_Subtree
2005 (Parent : Tree_Node_Access) return Tree_Node_Access
2007 Subtree : constant Tree_Node_Access :=
2008 new Tree_Node_Type'
2009 (Parent => Parent,
2010 Element => Element_Type'Input (Stream),
2011 others => <>);
2013 begin
2014 Read_Count := Read_Count + 1;
2016 Read_Children (Subtree);
2018 return Subtree;
2019 end Read_Subtree;
2021 -- Start of processing for Read
2023 begin
2024 Container.Clear; -- checks busy bit
2026 Count_Type'Read (Stream, Total_Count);
2028 if Total_Count < 0 then
2029 raise Program_Error with "attempt to read from corrupt stream";
2030 end if;
2032 if Total_Count = 0 then
2033 return;
2034 end if;
2036 Read_Count := 0;
2038 Read_Children (Root_Node (Container));
2040 if Read_Count /= Total_Count then
2041 raise Program_Error with "attempt to read from corrupt stream";
2042 end if;
2044 Container.Count := Total_Count;
2045 end Read;
2047 procedure Read
2048 (Stream : not null access Root_Stream_Type'Class;
2049 Position : out Cursor)
2051 begin
2052 raise Program_Error with "attempt to read tree cursor from stream";
2053 end Read;
2055 procedure Read
2056 (Stream : not null access Root_Stream_Type'Class;
2057 Item : out Reference_Type)
2059 begin
2060 raise Program_Error with "attempt to stream reference";
2061 end Read;
2063 procedure Read
2064 (Stream : not null access Root_Stream_Type'Class;
2065 Item : out Constant_Reference_Type)
2067 begin
2068 raise Program_Error with "attempt to stream reference";
2069 end Read;
2071 ---------------
2072 -- Reference --
2073 ---------------
2075 function Reference
2076 (Container : aliased in out Tree;
2077 Position : Cursor) return Reference_Type
2079 begin
2080 if Position.Container = null then
2081 raise Constraint_Error with
2082 "Position cursor has no element";
2083 end if;
2085 if Position.Container /= Container'Unrestricted_Access then
2086 raise Program_Error with
2087 "Position cursor designates wrong container";
2088 end if;
2090 if Position.Node = Root_Node (Container) then
2091 raise Program_Error with "Position cursor designates root";
2092 end if;
2094 -- Implement Vet for multiway tree???
2095 -- pragma Assert (Vet (Position),
2096 -- "Position cursor in Constant_Reference is bad");
2098 declare
2099 C : Tree renames Position.Container.all;
2100 B : Natural renames C.Busy;
2101 L : Natural renames C.Lock;
2102 begin
2103 return R : constant Reference_Type :=
2104 (Element => Position.Node.Element'Access,
2105 Control => (Controlled with Position.Container))
2107 B := B + 1;
2108 L := L + 1;
2109 end return;
2110 end;
2111 end Reference;
2113 --------------------
2114 -- Remove_Subtree --
2115 --------------------
2117 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2118 C : Children_Type renames Subtree.Parent.Children;
2120 begin
2121 -- This is a utility operation to remove a subtree node from its
2122 -- parent's list of children.
2124 if C.First = Subtree then
2125 pragma Assert (Subtree.Prev = null);
2127 if C.Last = Subtree then
2128 pragma Assert (Subtree.Next = null);
2129 C.First := null;
2130 C.Last := null;
2132 else
2133 C.First := Subtree.Next;
2134 C.First.Prev := null;
2135 end if;
2137 elsif C.Last = Subtree then
2138 pragma Assert (Subtree.Next = null);
2139 C.Last := Subtree.Prev;
2140 C.Last.Next := null;
2142 else
2143 Subtree.Prev.Next := Subtree.Next;
2144 Subtree.Next.Prev := Subtree.Prev;
2145 end if;
2146 end Remove_Subtree;
2148 ----------------------
2149 -- Replace_Element --
2150 ----------------------
2152 procedure Replace_Element
2153 (Container : in out Tree;
2154 Position : Cursor;
2155 New_Item : Element_Type)
2157 begin
2158 if Position = No_Element then
2159 raise Constraint_Error with "Position cursor has no element";
2160 end if;
2162 if Position.Container /= Container'Unrestricted_Access then
2163 raise Program_Error with "Position cursor not in container";
2164 end if;
2166 if Is_Root (Position) then
2167 raise Program_Error with "Position cursor designates root";
2168 end if;
2170 if Container.Lock > 0 then
2171 raise Program_Error
2172 with "attempt to tamper with elements (tree is locked)";
2173 end if;
2175 Position.Node.Element := New_Item;
2176 end Replace_Element;
2178 ------------------------------
2179 -- Reverse_Iterate_Children --
2180 ------------------------------
2182 procedure Reverse_Iterate_Children
2183 (Parent : Cursor;
2184 Process : not null access procedure (Position : Cursor))
2186 begin
2187 if Parent = No_Element then
2188 raise Constraint_Error with "Parent cursor has no element";
2189 end if;
2191 declare
2192 B : Natural renames Parent.Container.Busy;
2193 C : Tree_Node_Access;
2195 begin
2196 B := B + 1;
2198 C := Parent.Node.Children.Last;
2199 while C /= null loop
2200 Process (Position => Cursor'(Parent.Container, Node => C));
2201 C := C.Prev;
2202 end loop;
2204 B := B - 1;
2206 exception
2207 when others =>
2208 B := B - 1;
2209 raise;
2210 end;
2211 end Reverse_Iterate_Children;
2213 ----------
2214 -- Root --
2215 ----------
2217 function Root (Container : Tree) return Cursor is
2218 begin
2219 return (Container'Unrestricted_Access, Root_Node (Container));
2220 end Root;
2222 ---------------
2223 -- Root_Node --
2224 ---------------
2226 function Root_Node (Container : Tree) return Tree_Node_Access is
2227 type Root_Node_Access is access all Root_Node_Type;
2228 for Root_Node_Access'Storage_Size use 0;
2229 pragma Convention (C, Root_Node_Access);
2231 function To_Tree_Node_Access is
2232 new Ada.Unchecked_Conversion (Root_Node_Access, Tree_Node_Access);
2234 -- Start of processing for Root_Node
2236 begin
2237 -- This is a utility function for converting from an access type that
2238 -- designates the distinguished root node to an access type designating
2239 -- a non-root node. The representation of a root node does not have an
2240 -- element, but is otherwise identical to a non-root node, so the
2241 -- conversion itself is safe.
2243 return To_Tree_Node_Access (Container.Root'Unrestricted_Access);
2244 end Root_Node;
2246 ---------------------
2247 -- Splice_Children --
2248 ---------------------
2250 procedure Splice_Children
2251 (Target : in out Tree;
2252 Target_Parent : Cursor;
2253 Before : Cursor;
2254 Source : in out Tree;
2255 Source_Parent : Cursor)
2257 Count : Count_Type;
2259 begin
2260 if Target_Parent = No_Element then
2261 raise Constraint_Error with "Target_Parent cursor has no element";
2262 end if;
2264 if Target_Parent.Container /= Target'Unrestricted_Access then
2265 raise Program_Error
2266 with "Target_Parent cursor not in Target container";
2267 end if;
2269 if Before /= No_Element then
2270 if Before.Container /= Target'Unrestricted_Access then
2271 raise Program_Error
2272 with "Before cursor not in Target container";
2273 end if;
2275 if Before.Node.Parent /= Target_Parent.Node then
2276 raise Constraint_Error
2277 with "Before cursor not child of Target_Parent";
2278 end if;
2279 end if;
2281 if Source_Parent = No_Element then
2282 raise Constraint_Error with "Source_Parent cursor has no element";
2283 end if;
2285 if Source_Parent.Container /= Source'Unrestricted_Access then
2286 raise Program_Error
2287 with "Source_Parent cursor not in Source container";
2288 end if;
2290 if Target'Address = Source'Address then
2291 if Target_Parent = Source_Parent then
2292 return;
2293 end if;
2295 if Target.Busy > 0 then
2296 raise Program_Error
2297 with "attempt to tamper with cursors (Target tree is busy)";
2298 end if;
2300 if Is_Reachable (From => Target_Parent.Node,
2301 To => Source_Parent.Node)
2302 then
2303 raise Constraint_Error
2304 with "Source_Parent is ancestor of Target_Parent";
2305 end if;
2307 Splice_Children
2308 (Target_Parent => Target_Parent.Node,
2309 Before => Before.Node,
2310 Source_Parent => Source_Parent.Node);
2312 return;
2313 end if;
2315 if Target.Busy > 0 then
2316 raise Program_Error
2317 with "attempt to tamper with cursors (Target tree is busy)";
2318 end if;
2320 if Source.Busy > 0 then
2321 raise Program_Error
2322 with "attempt to tamper with cursors (Source tree is busy)";
2323 end if;
2325 -- We cache the count of the nodes we have allocated, so that operation
2326 -- Node_Count can execute in O(1) time. But that means we must count the
2327 -- nodes in the subtree we remove from Source and insert into Target, in
2328 -- order to keep the count accurate.
2330 Count := Subtree_Node_Count (Source_Parent.Node);
2331 pragma Assert (Count >= 1);
2333 Count := Count - 1; -- because Source_Parent node does not move
2335 Splice_Children
2336 (Target_Parent => Target_Parent.Node,
2337 Before => Before.Node,
2338 Source_Parent => Source_Parent.Node);
2340 Source.Count := Source.Count - Count;
2341 Target.Count := Target.Count + Count;
2342 end Splice_Children;
2344 procedure Splice_Children
2345 (Container : in out Tree;
2346 Target_Parent : Cursor;
2347 Before : Cursor;
2348 Source_Parent : Cursor)
2350 begin
2351 if Target_Parent = No_Element then
2352 raise Constraint_Error with "Target_Parent cursor has no element";
2353 end if;
2355 if Target_Parent.Container /= Container'Unrestricted_Access then
2356 raise Program_Error
2357 with "Target_Parent cursor not in container";
2358 end if;
2360 if Before /= No_Element then
2361 if Before.Container /= Container'Unrestricted_Access then
2362 raise Program_Error
2363 with "Before cursor not in container";
2364 end if;
2366 if Before.Node.Parent /= Target_Parent.Node then
2367 raise Constraint_Error
2368 with "Before cursor not child of Target_Parent";
2369 end if;
2370 end if;
2372 if Source_Parent = No_Element then
2373 raise Constraint_Error with "Source_Parent cursor has no element";
2374 end if;
2376 if Source_Parent.Container /= Container'Unrestricted_Access then
2377 raise Program_Error
2378 with "Source_Parent cursor not in container";
2379 end if;
2381 if Target_Parent = Source_Parent then
2382 return;
2383 end if;
2385 if Container.Busy > 0 then
2386 raise Program_Error
2387 with "attempt to tamper with cursors (tree is busy)";
2388 end if;
2390 if Is_Reachable (From => Target_Parent.Node,
2391 To => Source_Parent.Node)
2392 then
2393 raise Constraint_Error
2394 with "Source_Parent is ancestor of Target_Parent";
2395 end if;
2397 Splice_Children
2398 (Target_Parent => Target_Parent.Node,
2399 Before => Before.Node,
2400 Source_Parent => Source_Parent.Node);
2401 end Splice_Children;
2403 procedure Splice_Children
2404 (Target_Parent : Tree_Node_Access;
2405 Before : Tree_Node_Access;
2406 Source_Parent : Tree_Node_Access)
2408 CC : constant Children_Type := Source_Parent.Children;
2409 C : Tree_Node_Access;
2411 begin
2412 -- This is a utility operation to remove the children from
2413 -- Source parent and insert them into Target parent.
2415 Source_Parent.Children := Children_Type'(others => null);
2417 -- Fix up the Parent pointers of each child to designate
2418 -- its new Target parent.
2420 C := CC.First;
2421 while C /= null loop
2422 C.Parent := Target_Parent;
2423 C := C.Next;
2424 end loop;
2426 Insert_Subtree_List
2427 (First => CC.First,
2428 Last => CC.Last,
2429 Parent => Target_Parent,
2430 Before => Before);
2431 end Splice_Children;
2433 --------------------
2434 -- Splice_Subtree --
2435 --------------------
2437 procedure Splice_Subtree
2438 (Target : in out Tree;
2439 Parent : Cursor;
2440 Before : Cursor;
2441 Source : in out Tree;
2442 Position : in out Cursor)
2444 Subtree_Count : Count_Type;
2446 begin
2447 if Parent = No_Element then
2448 raise Constraint_Error with "Parent cursor has no element";
2449 end if;
2451 if Parent.Container /= Target'Unrestricted_Access then
2452 raise Program_Error with "Parent cursor not in Target container";
2453 end if;
2455 if Before /= No_Element then
2456 if Before.Container /= Target'Unrestricted_Access then
2457 raise Program_Error with "Before cursor not in Target container";
2458 end if;
2460 if Before.Node.Parent /= Parent.Node then
2461 raise Constraint_Error with "Before cursor not child of Parent";
2462 end if;
2463 end if;
2465 if Position = No_Element then
2466 raise Constraint_Error with "Position cursor has no element";
2467 end if;
2469 if Position.Container /= Source'Unrestricted_Access then
2470 raise Program_Error with "Position cursor not in Source container";
2471 end if;
2473 if Is_Root (Position) then
2474 raise Program_Error with "Position cursor designates root";
2475 end if;
2477 if Target'Address = Source'Address then
2478 if Position.Node.Parent = Parent.Node then
2479 if Position.Node = Before.Node then
2480 return;
2481 end if;
2483 if Position.Node.Next = Before.Node then
2484 return;
2485 end if;
2486 end if;
2488 if Target.Busy > 0 then
2489 raise Program_Error
2490 with "attempt to tamper with cursors (Target tree is busy)";
2491 end if;
2493 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2494 raise Constraint_Error with "Position is ancestor of Parent";
2495 end if;
2497 Remove_Subtree (Position.Node);
2499 Position.Node.Parent := Parent.Node;
2500 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2502 return;
2503 end if;
2505 if Target.Busy > 0 then
2506 raise Program_Error
2507 with "attempt to tamper with cursors (Target tree is busy)";
2508 end if;
2510 if Source.Busy > 0 then
2511 raise Program_Error
2512 with "attempt to tamper with cursors (Source tree is busy)";
2513 end if;
2515 -- This is an unfortunate feature of this API: we must count the nodes
2516 -- in the subtree that we remove from the source tree, which is an O(n)
2517 -- operation. It would have been better if the Tree container did not
2518 -- have a Node_Count selector; a user that wants the number of nodes in
2519 -- the tree could simply call Subtree_Node_Count, with the understanding
2520 -- that such an operation is O(n).
2522 -- Of course, we could choose to implement the Node_Count selector as an
2523 -- O(n) operation, which would turn this splice operation into an O(1)
2524 -- operation. ???
2526 Subtree_Count := Subtree_Node_Count (Position.Node);
2527 pragma Assert (Subtree_Count <= Source.Count);
2529 Remove_Subtree (Position.Node);
2530 Source.Count := Source.Count - Subtree_Count;
2532 Position.Node.Parent := Parent.Node;
2533 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2535 Target.Count := Target.Count + Subtree_Count;
2537 Position.Container := Target'Unrestricted_Access;
2538 end Splice_Subtree;
2540 procedure Splice_Subtree
2541 (Container : in out Tree;
2542 Parent : Cursor;
2543 Before : Cursor;
2544 Position : Cursor)
2546 begin
2547 if Parent = No_Element then
2548 raise Constraint_Error with "Parent cursor has no element";
2549 end if;
2551 if Parent.Container /= Container'Unrestricted_Access then
2552 raise Program_Error with "Parent cursor not in container";
2553 end if;
2555 if Before /= No_Element then
2556 if Before.Container /= Container'Unrestricted_Access then
2557 raise Program_Error with "Before cursor not in container";
2558 end if;
2560 if Before.Node.Parent /= Parent.Node then
2561 raise Constraint_Error with "Before cursor not child of Parent";
2562 end if;
2563 end if;
2565 if Position = No_Element then
2566 raise Constraint_Error with "Position cursor has no element";
2567 end if;
2569 if Position.Container /= Container'Unrestricted_Access then
2570 raise Program_Error with "Position cursor not in container";
2571 end if;
2573 if Is_Root (Position) then
2575 -- Should this be PE instead? Need ARG confirmation. ???
2577 raise Constraint_Error with "Position cursor designates root";
2578 end if;
2580 if Position.Node.Parent = Parent.Node then
2581 if Position.Node = Before.Node then
2582 return;
2583 end if;
2585 if Position.Node.Next = Before.Node then
2586 return;
2587 end if;
2588 end if;
2590 if Container.Busy > 0 then
2591 raise Program_Error
2592 with "attempt to tamper with cursors (tree is busy)";
2593 end if;
2595 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2596 raise Constraint_Error with "Position is ancestor of Parent";
2597 end if;
2599 Remove_Subtree (Position.Node);
2601 Position.Node.Parent := Parent.Node;
2602 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2603 end Splice_Subtree;
2605 ------------------------
2606 -- Subtree_Node_Count --
2607 ------------------------
2609 function Subtree_Node_Count (Position : Cursor) return Count_Type is
2610 begin
2611 if Position = No_Element then
2612 return 0;
2613 end if;
2615 return Subtree_Node_Count (Position.Node);
2616 end Subtree_Node_Count;
2618 function Subtree_Node_Count
2619 (Subtree : Tree_Node_Access) return Count_Type
2621 Result : Count_Type;
2622 Node : Tree_Node_Access;
2624 begin
2625 Result := 1;
2626 Node := Subtree.Children.First;
2627 while Node /= null loop
2628 Result := Result + Subtree_Node_Count (Node);
2629 Node := Node.Next;
2630 end loop;
2632 return Result;
2633 end Subtree_Node_Count;
2635 ----------
2636 -- Swap --
2637 ----------
2639 procedure Swap
2640 (Container : in out Tree;
2641 I, J : Cursor)
2643 begin
2644 if I = No_Element then
2645 raise Constraint_Error with "I cursor has no element";
2646 end if;
2648 if I.Container /= Container'Unrestricted_Access then
2649 raise Program_Error with "I cursor not in container";
2650 end if;
2652 if Is_Root (I) then
2653 raise Program_Error with "I cursor designates root";
2654 end if;
2656 if I = J then -- make this test sooner???
2657 return;
2658 end if;
2660 if J = No_Element then
2661 raise Constraint_Error with "J cursor has no element";
2662 end if;
2664 if J.Container /= Container'Unrestricted_Access then
2665 raise Program_Error with "J cursor not in container";
2666 end if;
2668 if Is_Root (J) then
2669 raise Program_Error with "J cursor designates root";
2670 end if;
2672 if Container.Lock > 0 then
2673 raise Program_Error
2674 with "attempt to tamper with elements (tree is locked)";
2675 end if;
2677 declare
2678 EI : constant Element_Type := I.Node.Element;
2680 begin
2681 I.Node.Element := J.Node.Element;
2682 J.Node.Element := EI;
2683 end;
2684 end Swap;
2686 --------------------
2687 -- Update_Element --
2688 --------------------
2690 procedure Update_Element
2691 (Container : in out Tree;
2692 Position : Cursor;
2693 Process : not null access procedure (Element : in out Element_Type))
2695 begin
2696 if Position = No_Element then
2697 raise Constraint_Error with "Position cursor has no element";
2698 end if;
2700 if Position.Container /= Container'Unrestricted_Access then
2701 raise Program_Error with "Position cursor not in container";
2702 end if;
2704 if Is_Root (Position) then
2705 raise Program_Error with "Position cursor designates root";
2706 end if;
2708 declare
2709 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2710 B : Natural renames T.Busy;
2711 L : Natural renames T.Lock;
2713 begin
2714 B := B + 1;
2715 L := L + 1;
2717 Process (Position.Node.Element);
2719 L := L - 1;
2720 B := B - 1;
2722 exception
2723 when others =>
2724 L := L - 1;
2725 B := B - 1;
2726 raise;
2727 end;
2728 end Update_Element;
2730 -----------
2731 -- Write --
2732 -----------
2734 procedure Write
2735 (Stream : not null access Root_Stream_Type'Class;
2736 Container : Tree)
2738 procedure Write_Children (Subtree : Tree_Node_Access);
2739 procedure Write_Subtree (Subtree : Tree_Node_Access);
2741 --------------------
2742 -- Write_Children --
2743 --------------------
2745 procedure Write_Children (Subtree : Tree_Node_Access) is
2746 CC : Children_Type renames Subtree.Children;
2747 C : Tree_Node_Access;
2749 begin
2750 Count_Type'Write (Stream, Child_Count (CC));
2752 C := CC.First;
2753 while C /= null loop
2754 Write_Subtree (C);
2755 C := C.Next;
2756 end loop;
2757 end Write_Children;
2759 -------------------
2760 -- Write_Subtree --
2761 -------------------
2763 procedure Write_Subtree (Subtree : Tree_Node_Access) is
2764 begin
2765 Element_Type'Output (Stream, Subtree.Element);
2766 Write_Children (Subtree);
2767 end Write_Subtree;
2769 -- Start of processing for Write
2771 begin
2772 Count_Type'Write (Stream, Container.Count);
2774 if Container.Count = 0 then
2775 return;
2776 end if;
2778 Write_Children (Root_Node (Container));
2779 end Write;
2781 procedure Write
2782 (Stream : not null access Root_Stream_Type'Class;
2783 Position : Cursor)
2785 begin
2786 raise Program_Error with "attempt to write tree cursor to stream";
2787 end Write;
2789 procedure Write
2790 (Stream : not null access Root_Stream_Type'Class;
2791 Item : Reference_Type)
2793 begin
2794 raise Program_Error with "attempt to stream reference";
2795 end Write;
2797 procedure Write
2798 (Stream : not null access Root_Stream_Type'Class;
2799 Item : Constant_Reference_Type)
2801 begin
2802 raise Program_Error with "attempt to stream reference";
2803 end Write;
2805 end Ada.Containers.Multiway_Trees;