2015-09-28 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / ada / a-comutr.adb
blob14d879e00aba3a9cc1627f68696912374ed989b9
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-2014, 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 pragma Annotate (CodePeer, Skip_Analysis);
39 --------------------
40 -- Root_Iterator --
41 --------------------
43 type Root_Iterator is abstract new Limited_Controlled and
44 Tree_Iterator_Interfaces.Forward_Iterator with
45 record
46 Container : Tree_Access;
47 Subtree : Tree_Node_Access;
48 end record;
50 overriding procedure Finalize (Object : in out Root_Iterator);
52 -----------------------
53 -- Subtree_Iterator --
54 -----------------------
56 -- ??? these headers are a bit odd, but for sure they do not substitute
57 -- for documenting things, what *is* a Subtree_Iterator?
59 type Subtree_Iterator is new Root_Iterator with null record;
61 overriding function First (Object : Subtree_Iterator) return Cursor;
63 overriding function Next
64 (Object : Subtree_Iterator;
65 Position : Cursor) return Cursor;
67 ---------------------
68 -- Child_Iterator --
69 ---------------------
71 type Child_Iterator is new Root_Iterator and
72 Tree_Iterator_Interfaces.Reversible_Iterator with null record;
74 overriding function First (Object : Child_Iterator) return Cursor;
76 overriding function Next
77 (Object : Child_Iterator;
78 Position : Cursor) return Cursor;
80 overriding function Last (Object : Child_Iterator) return Cursor;
82 overriding function Previous
83 (Object : Child_Iterator;
84 Position : Cursor) return Cursor;
86 -----------------------
87 -- Local Subprograms --
88 -----------------------
90 function Root_Node (Container : Tree) return Tree_Node_Access;
92 procedure Deallocate_Node is
93 new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access);
95 procedure Deallocate_Children
96 (Subtree : Tree_Node_Access;
97 Count : in out Count_Type);
99 procedure Deallocate_Subtree
100 (Subtree : in out Tree_Node_Access;
101 Count : in out Count_Type);
103 function Equal_Children
104 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
106 function Equal_Subtree
107 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
109 procedure Iterate_Children
110 (Container : Tree_Access;
111 Subtree : Tree_Node_Access;
112 Process : not null access procedure (Position : Cursor));
114 procedure Iterate_Subtree
115 (Container : Tree_Access;
116 Subtree : Tree_Node_Access;
117 Process : not null access procedure (Position : Cursor));
119 procedure Copy_Children
120 (Source : Children_Type;
121 Parent : Tree_Node_Access;
122 Count : in out Count_Type);
124 procedure Copy_Subtree
125 (Source : Tree_Node_Access;
126 Parent : Tree_Node_Access;
127 Target : out Tree_Node_Access;
128 Count : in out Count_Type);
130 function Find_In_Children
131 (Subtree : Tree_Node_Access;
132 Item : Element_Type) return Tree_Node_Access;
134 function Find_In_Subtree
135 (Subtree : Tree_Node_Access;
136 Item : Element_Type) return Tree_Node_Access;
138 function Child_Count (Children : Children_Type) return Count_Type;
140 function Subtree_Node_Count
141 (Subtree : Tree_Node_Access) return Count_Type;
143 function Is_Reachable (From, To : Tree_Node_Access) return Boolean;
145 procedure Remove_Subtree (Subtree : Tree_Node_Access);
147 procedure Insert_Subtree_Node
148 (Subtree : Tree_Node_Access;
149 Parent : Tree_Node_Access;
150 Before : Tree_Node_Access);
152 procedure Insert_Subtree_List
153 (First : Tree_Node_Access;
154 Last : Tree_Node_Access;
155 Parent : Tree_Node_Access;
156 Before : Tree_Node_Access);
158 procedure Splice_Children
159 (Target_Parent : Tree_Node_Access;
160 Before : Tree_Node_Access;
161 Source_Parent : Tree_Node_Access);
163 ---------
164 -- "=" --
165 ---------
167 function "=" (Left, Right : Tree) return Boolean is
168 begin
169 if Left'Address = Right'Address then
170 return True;
171 end if;
173 return Equal_Children (Root_Node (Left), Root_Node (Right));
174 end "=";
176 ------------
177 -- Adjust --
178 ------------
180 procedure Adjust (Container : in out Tree) is
181 Source : constant Children_Type := Container.Root.Children;
182 Source_Count : constant Count_Type := Container.Count;
183 Target_Count : Count_Type;
185 begin
186 -- We first restore the target container to its default-initialized
187 -- state, before we attempt any allocation, to ensure that invariants
188 -- are preserved in the event that the allocation fails.
190 Container.Root.Children := Children_Type'(others => null);
191 Container.Busy := 0;
192 Container.Lock := 0;
193 Container.Count := 0;
195 -- Copy_Children returns a count of the number of nodes that it
196 -- allocates, but it works by incrementing the value that is passed
197 -- in. We must therefore initialize the count value before calling
198 -- Copy_Children.
200 Target_Count := 0;
202 -- Now we attempt the allocation of subtrees. The invariants are
203 -- satisfied even if the allocation fails.
205 Copy_Children (Source, Root_Node (Container), Target_Count);
206 pragma Assert (Target_Count = Source_Count);
208 Container.Count := Source_Count;
209 end Adjust;
211 procedure Adjust (Control : in out Reference_Control_Type) is
212 begin
213 if Control.Container /= null then
214 declare
215 C : Tree renames Control.Container.all;
216 B : Natural renames C.Busy;
217 L : Natural renames C.Lock;
218 begin
219 B := B + 1;
220 L := L + 1;
221 end;
222 end if;
223 end Adjust;
225 -------------------
226 -- Ancestor_Find --
227 -------------------
229 function Ancestor_Find
230 (Position : Cursor;
231 Item : Element_Type) return Cursor
233 R, N : Tree_Node_Access;
235 begin
236 if Position = No_Element then
237 raise Constraint_Error with "Position cursor has no element";
238 end if;
240 -- Commented-out pending official ruling from ARG. ???
242 -- if Position.Container /= Container'Unrestricted_Access then
243 -- raise Program_Error with "Position cursor not in container";
244 -- end if;
246 -- AI-0136 says to raise PE if Position equals the root node. This does
247 -- not seem correct, as this value is just the limiting condition of the
248 -- search. For now we omit this check, pending a ruling from the ARG.???
250 -- if Is_Root (Position) then
251 -- raise Program_Error with "Position cursor designates root";
252 -- end if;
254 R := Root_Node (Position.Container.all);
255 N := Position.Node;
256 while N /= R loop
257 if N.Element = Item then
258 return Cursor'(Position.Container, N);
259 end if;
261 N := N.Parent;
262 end loop;
264 return No_Element;
265 end Ancestor_Find;
267 ------------------
268 -- Append_Child --
269 ------------------
271 procedure Append_Child
272 (Container : in out Tree;
273 Parent : Cursor;
274 New_Item : Element_Type;
275 Count : Count_Type := 1)
277 First : Tree_Node_Access;
278 Last : Tree_Node_Access;
280 begin
281 if Parent = No_Element then
282 raise Constraint_Error with "Parent cursor has no element";
283 end if;
285 if Parent.Container /= Container'Unrestricted_Access then
286 raise Program_Error with "Parent cursor not in container";
287 end if;
289 if Count = 0 then
290 return;
291 end if;
293 if Container.Busy > 0 then
294 raise Program_Error
295 with "attempt to tamper with cursors (tree is busy)";
296 end if;
298 First := new Tree_Node_Type'(Parent => Parent.Node,
299 Element => New_Item,
300 others => <>);
302 Last := First;
303 for J in Count_Type'(2) .. Count loop
305 -- Reclaim other nodes if Storage_Error. ???
307 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
308 Prev => Last,
309 Element => New_Item,
310 others => <>);
312 Last := Last.Next;
313 end loop;
315 Insert_Subtree_List
316 (First => First,
317 Last => Last,
318 Parent => Parent.Node,
319 Before => null); -- null means "insert at end of list"
321 -- In order for operation Node_Count to complete in O(1) time, we cache
322 -- the count value. Here we increment the total count by the number of
323 -- nodes we just inserted.
325 Container.Count := Container.Count + Count;
326 end Append_Child;
328 ------------
329 -- Assign --
330 ------------
332 procedure Assign (Target : in out Tree; Source : Tree) is
333 Source_Count : constant Count_Type := Source.Count;
334 Target_Count : Count_Type;
336 begin
337 if Target'Address = Source'Address then
338 return;
339 end if;
341 Target.Clear; -- checks busy bit
343 -- Copy_Children returns the number of nodes that it allocates, but it
344 -- does this by incrementing the count value passed in, so we must
345 -- initialize the count before calling Copy_Children.
347 Target_Count := 0;
349 -- Note that Copy_Children inserts the newly-allocated children into
350 -- their parent list only after the allocation of all the children has
351 -- succeeded. This preserves invariants even if the allocation fails.
353 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
354 pragma Assert (Target_Count = Source_Count);
356 Target.Count := Source_Count;
357 end Assign;
359 -----------------
360 -- Child_Count --
361 -----------------
363 function Child_Count (Parent : Cursor) return Count_Type is
364 begin
365 return (if Parent = No_Element
366 then 0 else Child_Count (Parent.Node.Children));
367 end Child_Count;
369 function Child_Count (Children : Children_Type) return Count_Type is
370 Result : Count_Type;
371 Node : Tree_Node_Access;
373 begin
374 Result := 0;
375 Node := Children.First;
376 while Node /= null loop
377 Result := Result + 1;
378 Node := Node.Next;
379 end loop;
381 return Result;
382 end Child_Count;
384 -----------------
385 -- Child_Depth --
386 -----------------
388 function Child_Depth (Parent, Child : Cursor) return Count_Type is
389 Result : Count_Type;
390 N : Tree_Node_Access;
392 begin
393 if Parent = No_Element then
394 raise Constraint_Error with "Parent cursor has no element";
395 end if;
397 if Child = No_Element then
398 raise Constraint_Error with "Child cursor has no element";
399 end if;
401 if Parent.Container /= Child.Container then
402 raise Program_Error with "Parent and Child in different containers";
403 end if;
405 Result := 0;
406 N := Child.Node;
407 while N /= Parent.Node loop
408 Result := Result + 1;
409 N := N.Parent;
411 if N = null then
412 raise Program_Error with "Parent is not ancestor of Child";
413 end if;
414 end loop;
416 return Result;
417 end Child_Depth;
419 -----------
420 -- Clear --
421 -----------
423 procedure Clear (Container : in out Tree) is
424 Container_Count, Children_Count : Count_Type;
426 begin
427 if Container.Busy > 0 then
428 raise Program_Error
429 with "attempt to tamper with cursors (tree is busy)";
430 end if;
432 -- We first set the container count to 0, in order to preserve
433 -- invariants in case the deallocation fails. (This works because
434 -- Deallocate_Children immediately removes the children from their
435 -- parent, and then does the actual deallocation.)
437 Container_Count := Container.Count;
438 Container.Count := 0;
440 -- Deallocate_Children returns the number of nodes that it deallocates,
441 -- but it does this by incrementing the count value that is passed in,
442 -- so we must first initialize the count return value before calling it.
444 Children_Count := 0;
446 -- See comment above. Deallocate_Children immediately removes the
447 -- children list from their parent node (here, the root of the tree),
448 -- and only after that does it attempt the actual deallocation. So even
449 -- if the deallocation fails, the representation invariants for the tree
450 -- are preserved.
452 Deallocate_Children (Root_Node (Container), Children_Count);
453 pragma Assert (Children_Count = Container_Count);
454 end Clear;
456 ------------------------
457 -- Constant_Reference --
458 ------------------------
460 function Constant_Reference
461 (Container : aliased Tree;
462 Position : Cursor) return Constant_Reference_Type
464 begin
465 if Position.Container = null then
466 raise Constraint_Error with
467 "Position cursor has no element";
468 end if;
470 if Position.Container /= Container'Unrestricted_Access then
471 raise Program_Error with
472 "Position cursor designates wrong container";
473 end if;
475 if Position.Node = Root_Node (Container) then
476 raise Program_Error with "Position cursor designates root";
477 end if;
479 -- Implement Vet for multiway tree???
480 -- pragma Assert (Vet (Position),
481 -- "Position cursor in Constant_Reference is bad");
483 declare
484 C : Tree renames Position.Container.all;
485 B : Natural renames C.Busy;
486 L : Natural renames C.Lock;
487 begin
488 return R : constant Constant_Reference_Type :=
489 (Element => Position.Node.Element'Access,
490 Control => (Controlled with Container'Unrestricted_Access))
492 B := B + 1;
493 L := L + 1;
494 end return;
495 end;
496 end Constant_Reference;
498 --------------
499 -- Contains --
500 --------------
502 function Contains
503 (Container : Tree;
504 Item : Element_Type) return Boolean
506 begin
507 return Find (Container, Item) /= No_Element;
508 end Contains;
510 ----------
511 -- Copy --
512 ----------
514 function Copy (Source : Tree) return Tree is
515 begin
516 return Target : Tree do
517 Copy_Children
518 (Source => Source.Root.Children,
519 Parent => Root_Node (Target),
520 Count => Target.Count);
522 pragma Assert (Target.Count = Source.Count);
523 end return;
524 end Copy;
526 -------------------
527 -- Copy_Children --
528 -------------------
530 procedure Copy_Children
531 (Source : Children_Type;
532 Parent : Tree_Node_Access;
533 Count : in out Count_Type)
535 pragma Assert (Parent /= null);
536 pragma Assert (Parent.Children.First = null);
537 pragma Assert (Parent.Children.Last = null);
539 CC : Children_Type;
540 C : Tree_Node_Access;
542 begin
543 -- We special-case the first allocation, in order to establish the
544 -- representation invariants for type Children_Type.
546 C := Source.First;
548 if C = null then
549 return;
550 end if;
552 Copy_Subtree
553 (Source => C,
554 Parent => Parent,
555 Target => CC.First,
556 Count => Count);
558 CC.Last := CC.First;
560 -- The representation invariants for the Children_Type list have been
561 -- established, so we can now copy the remaining children of Source.
563 C := C.Next;
564 while C /= null loop
565 Copy_Subtree
566 (Source => C,
567 Parent => Parent,
568 Target => CC.Last.Next,
569 Count => Count);
571 CC.Last.Next.Prev := CC.Last;
572 CC.Last := CC.Last.Next;
574 C := C.Next;
575 end loop;
577 -- Add the newly-allocated children to their parent list only after the
578 -- allocation has succeeded, so as to preserve invariants of the parent.
580 Parent.Children := CC;
581 end Copy_Children;
583 ------------------
584 -- Copy_Subtree --
585 ------------------
587 procedure Copy_Subtree
588 (Target : in out Tree;
589 Parent : Cursor;
590 Before : Cursor;
591 Source : Cursor)
593 Target_Subtree : Tree_Node_Access;
594 Target_Count : Count_Type;
596 begin
597 if Parent = No_Element then
598 raise Constraint_Error with "Parent cursor has no element";
599 end if;
601 if Parent.Container /= Target'Unrestricted_Access then
602 raise Program_Error with "Parent cursor not in container";
603 end if;
605 if Before /= No_Element then
606 if Before.Container /= Target'Unrestricted_Access then
607 raise Program_Error with "Before cursor not in container";
608 end if;
610 if Before.Node.Parent /= Parent.Node then
611 raise Constraint_Error with "Before cursor not child of Parent";
612 end if;
613 end if;
615 if Source = No_Element then
616 return;
617 end if;
619 if Is_Root (Source) then
620 raise Constraint_Error with "Source cursor designates root";
621 end if;
623 -- Copy_Subtree returns a count of the number of nodes that it
624 -- allocates, but it works by incrementing the value that is passed
625 -- in. We must therefore initialize the count value before calling
626 -- Copy_Subtree.
628 Target_Count := 0;
630 Copy_Subtree
631 (Source => Source.Node,
632 Parent => Parent.Node,
633 Target => Target_Subtree,
634 Count => Target_Count);
636 pragma Assert (Target_Subtree /= null);
637 pragma Assert (Target_Subtree.Parent = Parent.Node);
638 pragma Assert (Target_Count >= 1);
640 Insert_Subtree_Node
641 (Subtree => Target_Subtree,
642 Parent => Parent.Node,
643 Before => Before.Node);
645 -- In order for operation Node_Count to complete in O(1) time, we cache
646 -- the count value. Here we increment the total count by the number of
647 -- nodes we just inserted.
649 Target.Count := Target.Count + Target_Count;
650 end Copy_Subtree;
652 procedure Copy_Subtree
653 (Source : Tree_Node_Access;
654 Parent : Tree_Node_Access;
655 Target : out Tree_Node_Access;
656 Count : in out Count_Type)
658 begin
659 Target := new Tree_Node_Type'(Element => Source.Element,
660 Parent => Parent,
661 others => <>);
663 Count := Count + 1;
665 Copy_Children
666 (Source => Source.Children,
667 Parent => Target,
668 Count => Count);
669 end Copy_Subtree;
671 -------------------------
672 -- Deallocate_Children --
673 -------------------------
675 procedure Deallocate_Children
676 (Subtree : Tree_Node_Access;
677 Count : in out Count_Type)
679 pragma Assert (Subtree /= null);
681 CC : Children_Type := Subtree.Children;
682 C : Tree_Node_Access;
684 begin
685 -- We immediately remove the children from their parent, in order to
686 -- preserve invariants in case the deallocation fails.
688 Subtree.Children := Children_Type'(others => null);
690 while CC.First /= null loop
691 C := CC.First;
692 CC.First := C.Next;
694 Deallocate_Subtree (C, Count);
695 end loop;
696 end Deallocate_Children;
698 ------------------------
699 -- Deallocate_Subtree --
700 ------------------------
702 procedure Deallocate_Subtree
703 (Subtree : in out Tree_Node_Access;
704 Count : in out Count_Type)
706 begin
707 Deallocate_Children (Subtree, Count);
708 Deallocate_Node (Subtree);
709 Count := Count + 1;
710 end Deallocate_Subtree;
712 ---------------------
713 -- Delete_Children --
714 ---------------------
716 procedure Delete_Children
717 (Container : in out Tree;
718 Parent : Cursor)
720 Count : Count_Type;
722 begin
723 if Parent = No_Element then
724 raise Constraint_Error with "Parent cursor has no element";
725 end if;
727 if Parent.Container /= Container'Unrestricted_Access then
728 raise Program_Error with "Parent cursor not in container";
729 end if;
731 if Container.Busy > 0 then
732 raise Program_Error
733 with "attempt to tamper with cursors (tree is busy)";
734 end if;
736 -- Deallocate_Children returns a count of the number of nodes that it
737 -- deallocates, but it works by incrementing the value that is passed
738 -- in. We must therefore initialize the count value before calling
739 -- Deallocate_Children.
741 Count := 0;
743 Deallocate_Children (Parent.Node, Count);
744 pragma Assert (Count <= Container.Count);
746 Container.Count := Container.Count - Count;
747 end Delete_Children;
749 -----------------
750 -- Delete_Leaf --
751 -----------------
753 procedure Delete_Leaf
754 (Container : in out Tree;
755 Position : in out Cursor)
757 X : Tree_Node_Access;
759 begin
760 if Position = No_Element then
761 raise Constraint_Error with "Position cursor has no element";
762 end if;
764 if Position.Container /= Container'Unrestricted_Access then
765 raise Program_Error with "Position cursor not in container";
766 end if;
768 if Is_Root (Position) then
769 raise Program_Error with "Position cursor designates root";
770 end if;
772 if not Is_Leaf (Position) then
773 raise Constraint_Error with "Position cursor does not designate leaf";
774 end if;
776 if Container.Busy > 0 then
777 raise Program_Error
778 with "attempt to tamper with cursors (tree is busy)";
779 end if;
781 X := Position.Node;
782 Position := No_Element;
784 -- Restore represention invariants before attempting the actual
785 -- deallocation.
787 Remove_Subtree (X);
788 Container.Count := Container.Count - 1;
790 -- It is now safe to attempt the deallocation. This leaf node has been
791 -- disassociated from the tree, so even if the deallocation fails,
792 -- representation invariants will remain satisfied.
794 Deallocate_Node (X);
795 end Delete_Leaf;
797 --------------------
798 -- Delete_Subtree --
799 --------------------
801 procedure Delete_Subtree
802 (Container : in out Tree;
803 Position : in out Cursor)
805 X : Tree_Node_Access;
806 Count : Count_Type;
808 begin
809 if Position = No_Element then
810 raise Constraint_Error with "Position cursor has no element";
811 end if;
813 if Position.Container /= Container'Unrestricted_Access then
814 raise Program_Error with "Position cursor not in container";
815 end if;
817 if Is_Root (Position) then
818 raise Program_Error with "Position cursor designates root";
819 end if;
821 if Container.Busy > 0 then
822 raise Program_Error
823 with "attempt to tamper with cursors (tree is busy)";
824 end if;
826 X := Position.Node;
827 Position := No_Element;
829 -- Here is one case where a deallocation failure can result in the
830 -- violation of a representation invariant. We disassociate the subtree
831 -- from the tree now, but we only decrement the total node count after
832 -- we attempt the deallocation. However, if the deallocation fails, the
833 -- total node count will not get decremented.
835 -- One way around this dilemma is to count the nodes in the subtree
836 -- before attempt to delete the subtree, but that is an O(n) operation,
837 -- so it does not seem worth it.
839 -- Perhaps this is much ado about nothing, since the only way
840 -- deallocation can fail is if Controlled Finalization fails: this
841 -- propagates Program_Error so all bets are off anyway. ???
843 Remove_Subtree (X);
845 -- Deallocate_Subtree returns a count of the number of nodes that it
846 -- deallocates, but it works by incrementing the value that is passed
847 -- in. We must therefore initialize the count value before calling
848 -- Deallocate_Subtree.
850 Count := 0;
852 Deallocate_Subtree (X, Count);
853 pragma Assert (Count <= Container.Count);
855 -- See comments above. We would prefer to do this sooner, but there's no
856 -- way to satisfy that goal without a potentially severe execution
857 -- penalty.
859 Container.Count := Container.Count - Count;
860 end Delete_Subtree;
862 -----------
863 -- Depth --
864 -----------
866 function Depth (Position : Cursor) return Count_Type is
867 Result : Count_Type;
868 N : Tree_Node_Access;
870 begin
871 Result := 0;
872 N := Position.Node;
873 while N /= null loop
874 N := N.Parent;
875 Result := Result + 1;
876 end loop;
878 return Result;
879 end Depth;
881 -------------
882 -- Element --
883 -------------
885 function Element (Position : Cursor) return Element_Type is
886 begin
887 if Position.Container = null then
888 raise Constraint_Error with "Position cursor has no element";
889 end if;
891 if Position.Node = Root_Node (Position.Container.all) then
892 raise Program_Error with "Position cursor designates root";
893 end if;
895 return Position.Node.Element;
896 end Element;
898 --------------------
899 -- Equal_Children --
900 --------------------
902 function Equal_Children
903 (Left_Subtree : Tree_Node_Access;
904 Right_Subtree : Tree_Node_Access) return Boolean
906 Left_Children : Children_Type renames Left_Subtree.Children;
907 Right_Children : Children_Type renames Right_Subtree.Children;
909 L, R : Tree_Node_Access;
911 begin
912 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
913 return False;
914 end if;
916 L := Left_Children.First;
917 R := Right_Children.First;
918 while L /= null loop
919 if not Equal_Subtree (L, R) then
920 return False;
921 end if;
923 L := L.Next;
924 R := R.Next;
925 end loop;
927 return True;
928 end Equal_Children;
930 -------------------
931 -- Equal_Subtree --
932 -------------------
934 function Equal_Subtree
935 (Left_Position : Cursor;
936 Right_Position : Cursor) return Boolean
938 begin
939 if Left_Position = No_Element then
940 raise Constraint_Error with "Left cursor has no element";
941 end if;
943 if Right_Position = No_Element then
944 raise Constraint_Error with "Right cursor has no element";
945 end if;
947 if Left_Position = Right_Position then
948 return True;
949 end if;
951 if Is_Root (Left_Position) then
952 if not Is_Root (Right_Position) then
953 return False;
954 end if;
956 return Equal_Children (Left_Position.Node, Right_Position.Node);
957 end if;
959 if Is_Root (Right_Position) then
960 return False;
961 end if;
963 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
964 end Equal_Subtree;
966 function Equal_Subtree
967 (Left_Subtree : Tree_Node_Access;
968 Right_Subtree : Tree_Node_Access) return Boolean
970 begin
971 if Left_Subtree.Element /= Right_Subtree.Element then
972 return False;
973 end if;
975 return Equal_Children (Left_Subtree, Right_Subtree);
976 end Equal_Subtree;
978 --------------
979 -- Finalize --
980 --------------
982 procedure Finalize (Object : in out Root_Iterator) is
983 B : Natural renames Object.Container.Busy;
984 begin
985 B := B - 1;
986 end Finalize;
988 procedure Finalize (Control : in out Reference_Control_Type) is
989 begin
990 if Control.Container /= null then
991 declare
992 C : Tree renames Control.Container.all;
993 B : Natural renames C.Busy;
994 L : Natural renames C.Lock;
995 begin
996 B := B - 1;
997 L := L - 1;
998 end;
1000 Control.Container := null;
1001 end if;
1002 end Finalize;
1004 ----------
1005 -- Find --
1006 ----------
1008 function Find
1009 (Container : Tree;
1010 Item : Element_Type) return Cursor
1012 N : constant Tree_Node_Access :=
1013 Find_In_Children (Root_Node (Container), Item);
1014 begin
1015 if N = null then
1016 return No_Element;
1017 else
1018 return Cursor'(Container'Unrestricted_Access, N);
1019 end if;
1020 end Find;
1022 -----------
1023 -- First --
1024 -----------
1026 overriding function First (Object : Subtree_Iterator) return Cursor is
1027 begin
1028 if Object.Subtree = Root_Node (Object.Container.all) then
1029 return First_Child (Root (Object.Container.all));
1030 else
1031 return Cursor'(Object.Container, Object.Subtree);
1032 end if;
1033 end First;
1035 overriding function First (Object : Child_Iterator) return Cursor is
1036 begin
1037 return First_Child (Cursor'(Object.Container, Object.Subtree));
1038 end First;
1040 -----------------
1041 -- First_Child --
1042 -----------------
1044 function First_Child (Parent : Cursor) return Cursor is
1045 Node : Tree_Node_Access;
1047 begin
1048 if Parent = No_Element then
1049 raise Constraint_Error with "Parent cursor has no element";
1050 end if;
1052 Node := Parent.Node.Children.First;
1054 if Node = null then
1055 return No_Element;
1056 end if;
1058 return Cursor'(Parent.Container, Node);
1059 end First_Child;
1061 -------------------------
1062 -- First_Child_Element --
1063 -------------------------
1065 function First_Child_Element (Parent : Cursor) return Element_Type is
1066 begin
1067 return Element (First_Child (Parent));
1068 end First_Child_Element;
1070 ----------------------
1071 -- Find_In_Children --
1072 ----------------------
1074 function Find_In_Children
1075 (Subtree : Tree_Node_Access;
1076 Item : Element_Type) return Tree_Node_Access
1078 N, Result : Tree_Node_Access;
1080 begin
1081 N := Subtree.Children.First;
1082 while N /= null loop
1083 Result := Find_In_Subtree (N, Item);
1085 if Result /= null then
1086 return Result;
1087 end if;
1089 N := N.Next;
1090 end loop;
1092 return null;
1093 end Find_In_Children;
1095 ---------------------
1096 -- Find_In_Subtree --
1097 ---------------------
1099 function Find_In_Subtree
1100 (Position : Cursor;
1101 Item : Element_Type) return Cursor
1103 Result : Tree_Node_Access;
1105 begin
1106 if Position = No_Element then
1107 raise Constraint_Error with "Position cursor has no element";
1108 end if;
1110 -- Commented out pending official ruling by ARG. ???
1112 -- if Position.Container /= Container'Unrestricted_Access then
1113 -- raise Program_Error with "Position cursor not in container";
1114 -- end if;
1116 Result :=
1117 (if Is_Root (Position)
1118 then Find_In_Children (Position.Node, Item)
1119 else Find_In_Subtree (Position.Node, Item));
1121 if Result = null then
1122 return No_Element;
1123 end if;
1125 return Cursor'(Position.Container, Result);
1126 end Find_In_Subtree;
1128 function Find_In_Subtree
1129 (Subtree : Tree_Node_Access;
1130 Item : Element_Type) return Tree_Node_Access
1132 begin
1133 if Subtree.Element = Item then
1134 return Subtree;
1135 end if;
1137 return Find_In_Children (Subtree, Item);
1138 end Find_In_Subtree;
1140 -----------------
1141 -- Has_Element --
1142 -----------------
1144 function Has_Element (Position : Cursor) return Boolean is
1145 begin
1146 return (if Position = No_Element then False
1147 else Position.Node.Parent /= null);
1148 end Has_Element;
1150 ------------------
1151 -- Insert_Child --
1152 ------------------
1154 procedure Insert_Child
1155 (Container : in out Tree;
1156 Parent : Cursor;
1157 Before : Cursor;
1158 New_Item : Element_Type;
1159 Count : Count_Type := 1)
1161 Position : Cursor;
1162 pragma Unreferenced (Position);
1164 begin
1165 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1166 end Insert_Child;
1168 procedure Insert_Child
1169 (Container : in out Tree;
1170 Parent : Cursor;
1171 Before : Cursor;
1172 New_Item : Element_Type;
1173 Position : out Cursor;
1174 Count : Count_Type := 1)
1176 First : Tree_Node_Access;
1177 Last : Tree_Node_Access;
1179 begin
1180 if Parent = No_Element then
1181 raise Constraint_Error with "Parent cursor has no element";
1182 end if;
1184 if Parent.Container /= Container'Unrestricted_Access then
1185 raise Program_Error with "Parent cursor not in container";
1186 end if;
1188 if Before /= No_Element then
1189 if Before.Container /= Container'Unrestricted_Access then
1190 raise Program_Error with "Before cursor not in container";
1191 end if;
1193 if Before.Node.Parent /= Parent.Node then
1194 raise Constraint_Error with "Parent cursor not parent of Before";
1195 end if;
1196 end if;
1198 if Count = 0 then
1199 Position := No_Element; -- Need ruling from ARG ???
1200 return;
1201 end if;
1203 if Container.Busy > 0 then
1204 raise Program_Error
1205 with "attempt to tamper with cursors (tree is busy)";
1206 end if;
1208 First := new Tree_Node_Type'(Parent => Parent.Node,
1209 Element => New_Item,
1210 others => <>);
1212 Last := First;
1213 for J in Count_Type'(2) .. Count loop
1215 -- Reclaim other nodes if Storage_Error. ???
1217 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1218 Prev => Last,
1219 Element => New_Item,
1220 others => <>);
1222 Last := Last.Next;
1223 end loop;
1225 Insert_Subtree_List
1226 (First => First,
1227 Last => Last,
1228 Parent => Parent.Node,
1229 Before => Before.Node);
1231 -- In order for operation Node_Count to complete in O(1) time, we cache
1232 -- the count value. Here we increment the total count by the number of
1233 -- nodes we just inserted.
1235 Container.Count := Container.Count + Count;
1237 Position := Cursor'(Parent.Container, First);
1238 end Insert_Child;
1240 procedure Insert_Child
1241 (Container : in out Tree;
1242 Parent : Cursor;
1243 Before : Cursor;
1244 Position : out Cursor;
1245 Count : Count_Type := 1)
1247 First : Tree_Node_Access;
1248 Last : Tree_Node_Access;
1250 begin
1251 if Parent = No_Element then
1252 raise Constraint_Error with "Parent cursor has no element";
1253 end if;
1255 if Parent.Container /= Container'Unrestricted_Access then
1256 raise Program_Error with "Parent cursor not in container";
1257 end if;
1259 if Before /= No_Element then
1260 if Before.Container /= Container'Unrestricted_Access then
1261 raise Program_Error with "Before cursor not in container";
1262 end if;
1264 if Before.Node.Parent /= Parent.Node then
1265 raise Constraint_Error with "Parent cursor not parent of Before";
1266 end if;
1267 end if;
1269 if Count = 0 then
1270 Position := No_Element; -- Need ruling from ARG ???
1271 return;
1272 end if;
1274 if Container.Busy > 0 then
1275 raise Program_Error
1276 with "attempt to tamper with cursors (tree is busy)";
1277 end if;
1279 First := new Tree_Node_Type'(Parent => Parent.Node,
1280 Element => <>,
1281 others => <>);
1283 Last := First;
1284 for J in Count_Type'(2) .. Count loop
1286 -- Reclaim other nodes if Storage_Error. ???
1288 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1289 Prev => Last,
1290 Element => <>,
1291 others => <>);
1293 Last := Last.Next;
1294 end loop;
1296 Insert_Subtree_List
1297 (First => First,
1298 Last => Last,
1299 Parent => Parent.Node,
1300 Before => Before.Node);
1302 -- In order for operation Node_Count to complete in O(1) time, we cache
1303 -- the count value. Here we increment the total count by the number of
1304 -- nodes we just inserted.
1306 Container.Count := Container.Count + Count;
1308 Position := Cursor'(Parent.Container, First);
1309 end Insert_Child;
1311 -------------------------
1312 -- Insert_Subtree_List --
1313 -------------------------
1315 procedure Insert_Subtree_List
1316 (First : Tree_Node_Access;
1317 Last : Tree_Node_Access;
1318 Parent : Tree_Node_Access;
1319 Before : Tree_Node_Access)
1321 pragma Assert (Parent /= null);
1322 C : Children_Type renames Parent.Children;
1324 begin
1325 -- This is a simple utility operation to insert a list of nodes (from
1326 -- First..Last) as children of Parent. The Before node specifies where
1327 -- the new children should be inserted relative to the existing
1328 -- children.
1330 if First = null then
1331 pragma Assert (Last = null);
1332 return;
1333 end if;
1335 pragma Assert (Last /= null);
1336 pragma Assert (Before = null or else Before.Parent = Parent);
1338 if C.First = null then
1339 C.First := First;
1340 C.First.Prev := null;
1341 C.Last := Last;
1342 C.Last.Next := null;
1344 elsif Before = null then -- means "insert after existing nodes"
1345 C.Last.Next := First;
1346 First.Prev := C.Last;
1347 C.Last := Last;
1348 C.Last.Next := null;
1350 elsif Before = C.First then
1351 Last.Next := C.First;
1352 C.First.Prev := Last;
1353 C.First := First;
1354 C.First.Prev := null;
1356 else
1357 Before.Prev.Next := First;
1358 First.Prev := Before.Prev;
1359 Last.Next := Before;
1360 Before.Prev := Last;
1361 end if;
1362 end Insert_Subtree_List;
1364 -------------------------
1365 -- Insert_Subtree_Node --
1366 -------------------------
1368 procedure Insert_Subtree_Node
1369 (Subtree : Tree_Node_Access;
1370 Parent : Tree_Node_Access;
1371 Before : Tree_Node_Access)
1373 begin
1374 -- This is a simple wrapper operation to insert a single child into the
1375 -- Parent's children list.
1377 Insert_Subtree_List
1378 (First => Subtree,
1379 Last => Subtree,
1380 Parent => Parent,
1381 Before => Before);
1382 end Insert_Subtree_Node;
1384 --------------
1385 -- Is_Empty --
1386 --------------
1388 function Is_Empty (Container : Tree) return Boolean is
1389 begin
1390 return Container.Root.Children.First = null;
1391 end Is_Empty;
1393 -------------
1394 -- Is_Leaf --
1395 -------------
1397 function Is_Leaf (Position : Cursor) return Boolean is
1398 begin
1399 return (if Position = No_Element then False
1400 else Position.Node.Children.First = null);
1401 end Is_Leaf;
1403 ------------------
1404 -- Is_Reachable --
1405 ------------------
1407 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1408 pragma Assert (From /= null);
1409 pragma Assert (To /= null);
1411 N : Tree_Node_Access;
1413 begin
1414 N := From;
1415 while N /= null loop
1416 if N = To then
1417 return True;
1418 end if;
1420 N := N.Parent;
1421 end loop;
1423 return False;
1424 end Is_Reachable;
1426 -------------
1427 -- Is_Root --
1428 -------------
1430 function Is_Root (Position : Cursor) return Boolean is
1431 begin
1432 return (if Position.Container = null then False
1433 else Position = Root (Position.Container.all));
1434 end Is_Root;
1436 -------------
1437 -- Iterate --
1438 -------------
1440 procedure Iterate
1441 (Container : Tree;
1442 Process : not null access procedure (Position : Cursor))
1444 B : Natural renames Container'Unrestricted_Access.all.Busy;
1446 begin
1447 B := B + 1;
1449 Iterate_Children
1450 (Container => Container'Unrestricted_Access,
1451 Subtree => Root_Node (Container),
1452 Process => Process);
1454 B := B - 1;
1456 exception
1457 when others =>
1458 B := B - 1;
1459 raise;
1460 end Iterate;
1462 function Iterate (Container : Tree)
1463 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1465 begin
1466 return Iterate_Subtree (Root (Container));
1467 end Iterate;
1469 ----------------------
1470 -- Iterate_Children --
1471 ----------------------
1473 procedure Iterate_Children
1474 (Parent : Cursor;
1475 Process : not null access procedure (Position : Cursor))
1477 begin
1478 if Parent = No_Element then
1479 raise Constraint_Error with "Parent cursor has no element";
1480 end if;
1482 declare
1483 B : Natural renames Parent.Container.Busy;
1484 C : Tree_Node_Access;
1486 begin
1487 B := B + 1;
1489 C := Parent.Node.Children.First;
1490 while C /= null loop
1491 Process (Position => Cursor'(Parent.Container, Node => C));
1492 C := C.Next;
1493 end loop;
1495 B := B - 1;
1497 exception
1498 when others =>
1499 B := B - 1;
1500 raise;
1501 end;
1502 end Iterate_Children;
1504 procedure Iterate_Children
1505 (Container : Tree_Access;
1506 Subtree : Tree_Node_Access;
1507 Process : not null access procedure (Position : Cursor))
1509 Node : Tree_Node_Access;
1511 begin
1512 -- This is a helper function to recursively iterate over all the nodes
1513 -- in a subtree, in depth-first fashion. This particular helper just
1514 -- visits the children of this subtree, not the root of the subtree node
1515 -- itself. This is useful when starting from the ultimate root of the
1516 -- entire tree (see Iterate), as that root does not have an element.
1518 Node := Subtree.Children.First;
1519 while Node /= null loop
1520 Iterate_Subtree (Container, Node, Process);
1521 Node := Node.Next;
1522 end loop;
1523 end Iterate_Children;
1525 function Iterate_Children
1526 (Container : Tree;
1527 Parent : Cursor)
1528 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1530 C : constant Tree_Access := Container'Unrestricted_Access;
1531 B : Natural renames C.Busy;
1533 begin
1534 if Parent = No_Element then
1535 raise Constraint_Error with "Parent cursor has no element";
1536 end if;
1538 if Parent.Container /= C then
1539 raise Program_Error with "Parent cursor not in container";
1540 end if;
1542 return It : constant Child_Iterator :=
1543 (Limited_Controlled with
1544 Container => C,
1545 Subtree => Parent.Node)
1547 B := B + 1;
1548 end return;
1549 end Iterate_Children;
1551 ---------------------
1552 -- Iterate_Subtree --
1553 ---------------------
1555 function Iterate_Subtree
1556 (Position : Cursor)
1557 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1559 begin
1560 if Position = No_Element then
1561 raise Constraint_Error with "Position cursor has no element";
1562 end if;
1564 -- Implement Vet for multiway trees???
1565 -- pragma Assert (Vet (Position), "bad subtree cursor");
1567 declare
1568 B : Natural renames Position.Container.Busy;
1569 begin
1570 return It : constant Subtree_Iterator :=
1571 (Limited_Controlled with
1572 Container => Position.Container,
1573 Subtree => Position.Node)
1575 B := B + 1;
1576 end return;
1577 end;
1578 end Iterate_Subtree;
1580 procedure Iterate_Subtree
1581 (Position : Cursor;
1582 Process : not null access procedure (Position : Cursor))
1584 begin
1585 if Position = No_Element then
1586 raise Constraint_Error with "Position cursor has no element";
1587 end if;
1589 declare
1590 B : Natural renames Position.Container.Busy;
1592 begin
1593 B := B + 1;
1595 if Is_Root (Position) then
1596 Iterate_Children (Position.Container, Position.Node, Process);
1597 else
1598 Iterate_Subtree (Position.Container, Position.Node, Process);
1599 end if;
1601 B := B - 1;
1603 exception
1604 when others =>
1605 B := B - 1;
1606 raise;
1607 end;
1608 end Iterate_Subtree;
1610 procedure Iterate_Subtree
1611 (Container : Tree_Access;
1612 Subtree : Tree_Node_Access;
1613 Process : not null access procedure (Position : Cursor))
1615 begin
1616 -- This is a helper function to recursively iterate over all the nodes
1617 -- in a subtree, in depth-first fashion. It first visits the root of the
1618 -- subtree, then visits its children.
1620 Process (Cursor'(Container, Subtree));
1621 Iterate_Children (Container, Subtree, Process);
1622 end Iterate_Subtree;
1624 ----------
1625 -- Last --
1626 ----------
1628 overriding function Last (Object : Child_Iterator) return Cursor is
1629 begin
1630 return Last_Child (Cursor'(Object.Container, Object.Subtree));
1631 end Last;
1633 ----------------
1634 -- Last_Child --
1635 ----------------
1637 function Last_Child (Parent : Cursor) return Cursor is
1638 Node : Tree_Node_Access;
1640 begin
1641 if Parent = No_Element then
1642 raise Constraint_Error with "Parent cursor has no element";
1643 end if;
1645 Node := Parent.Node.Children.Last;
1647 if Node = null then
1648 return No_Element;
1649 end if;
1651 return (Parent.Container, Node);
1652 end Last_Child;
1654 ------------------------
1655 -- Last_Child_Element --
1656 ------------------------
1658 function Last_Child_Element (Parent : Cursor) return Element_Type is
1659 begin
1660 return Element (Last_Child (Parent));
1661 end Last_Child_Element;
1663 ----------
1664 -- Move --
1665 ----------
1667 procedure Move (Target : in out Tree; Source : in out Tree) is
1668 Node : Tree_Node_Access;
1670 begin
1671 if Target'Address = Source'Address then
1672 return;
1673 end if;
1675 if Source.Busy > 0 then
1676 raise Program_Error
1677 with "attempt to tamper with cursors of Source (tree is busy)";
1678 end if;
1680 Target.Clear; -- checks busy bit
1682 Target.Root.Children := Source.Root.Children;
1683 Source.Root.Children := Children_Type'(others => null);
1685 Node := Target.Root.Children.First;
1686 while Node /= null loop
1687 Node.Parent := Root_Node (Target);
1688 Node := Node.Next;
1689 end loop;
1691 Target.Count := Source.Count;
1692 Source.Count := 0;
1693 end Move;
1695 ----------
1696 -- Next --
1697 ----------
1699 function Next
1700 (Object : Subtree_Iterator;
1701 Position : Cursor) return Cursor
1703 Node : Tree_Node_Access;
1705 begin
1706 if Position.Container = null then
1707 return No_Element;
1708 end if;
1710 if Position.Container /= Object.Container then
1711 raise Program_Error with
1712 "Position cursor of Next designates wrong tree";
1713 end if;
1715 Node := Position.Node;
1717 if Node.Children.First /= null then
1718 return Cursor'(Object.Container, Node.Children.First);
1719 end if;
1721 while Node /= Object.Subtree loop
1722 if Node.Next /= null then
1723 return Cursor'(Object.Container, Node.Next);
1724 end if;
1726 Node := Node.Parent;
1727 end loop;
1729 return No_Element;
1730 end Next;
1732 function Next
1733 (Object : Child_Iterator;
1734 Position : Cursor) return Cursor
1736 begin
1737 if Position.Container = null then
1738 return No_Element;
1739 end if;
1741 if Position.Container /= Object.Container then
1742 raise Program_Error with
1743 "Position cursor of Next designates wrong tree";
1744 end if;
1746 return Next_Sibling (Position);
1747 end Next;
1749 ------------------
1750 -- Next_Sibling --
1751 ------------------
1753 function Next_Sibling (Position : Cursor) return Cursor is
1754 begin
1755 if Position = No_Element then
1756 return No_Element;
1757 end if;
1759 if Position.Node.Next = null then
1760 return No_Element;
1761 end if;
1763 return Cursor'(Position.Container, Position.Node.Next);
1764 end Next_Sibling;
1766 procedure Next_Sibling (Position : in out Cursor) is
1767 begin
1768 Position := Next_Sibling (Position);
1769 end Next_Sibling;
1771 ----------------
1772 -- Node_Count --
1773 ----------------
1775 function Node_Count (Container : Tree) return Count_Type is
1776 begin
1777 -- Container.Count is the number of nodes we have actually allocated. We
1778 -- cache the value specifically so this Node_Count operation can execute
1779 -- in O(1) time, which makes it behave similarly to how the Length
1780 -- selector function behaves for other containers.
1782 -- The cached node count value only describes the nodes we have
1783 -- allocated; the root node itself is not included in that count. The
1784 -- Node_Count operation returns a value that includes the root node
1785 -- (because the RM says so), so we must add 1 to our cached value.
1787 return 1 + Container.Count;
1788 end Node_Count;
1790 ------------
1791 -- Parent --
1792 ------------
1794 function Parent (Position : Cursor) return Cursor is
1795 begin
1796 if Position = No_Element then
1797 return No_Element;
1798 end if;
1800 if Position.Node.Parent = null then
1801 return No_Element;
1802 end if;
1804 return Cursor'(Position.Container, Position.Node.Parent);
1805 end Parent;
1807 -------------------
1808 -- Prepent_Child --
1809 -------------------
1811 procedure Prepend_Child
1812 (Container : in out Tree;
1813 Parent : Cursor;
1814 New_Item : Element_Type;
1815 Count : Count_Type := 1)
1817 First, Last : Tree_Node_Access;
1819 begin
1820 if Parent = No_Element then
1821 raise Constraint_Error with "Parent cursor has no element";
1822 end if;
1824 if Parent.Container /= Container'Unrestricted_Access then
1825 raise Program_Error with "Parent cursor not in container";
1826 end if;
1828 if Count = 0 then
1829 return;
1830 end if;
1832 if Container.Busy > 0 then
1833 raise Program_Error
1834 with "attempt to tamper with cursors (tree is busy)";
1835 end if;
1837 First := new Tree_Node_Type'(Parent => Parent.Node,
1838 Element => New_Item,
1839 others => <>);
1841 Last := First;
1843 for J in Count_Type'(2) .. Count loop
1845 -- Reclaim other nodes if Storage_Error???
1847 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1848 Prev => Last,
1849 Element => New_Item,
1850 others => <>);
1852 Last := Last.Next;
1853 end loop;
1855 Insert_Subtree_List
1856 (First => First,
1857 Last => Last,
1858 Parent => Parent.Node,
1859 Before => Parent.Node.Children.First);
1861 -- In order for operation Node_Count to complete in O(1) time, we cache
1862 -- the count value. Here we increment the total count by the number of
1863 -- nodes we just inserted.
1865 Container.Count := Container.Count + Count;
1866 end Prepend_Child;
1868 --------------
1869 -- Previous --
1870 --------------
1872 overriding function Previous
1873 (Object : Child_Iterator;
1874 Position : Cursor) return Cursor
1876 begin
1877 if Position.Container = null then
1878 return No_Element;
1879 end if;
1881 if Position.Container /= Object.Container then
1882 raise Program_Error with
1883 "Position cursor of Previous designates wrong tree";
1884 end if;
1886 return Previous_Sibling (Position);
1887 end Previous;
1889 ----------------------
1890 -- Previous_Sibling --
1891 ----------------------
1893 function Previous_Sibling (Position : Cursor) return Cursor is
1894 begin
1895 return
1896 (if Position = No_Element then No_Element
1897 elsif Position.Node.Prev = null then No_Element
1898 else Cursor'(Position.Container, Position.Node.Prev));
1899 end Previous_Sibling;
1901 procedure Previous_Sibling (Position : in out Cursor) is
1902 begin
1903 Position := Previous_Sibling (Position);
1904 end Previous_Sibling;
1906 -------------------
1907 -- Query_Element --
1908 -------------------
1910 procedure Query_Element
1911 (Position : Cursor;
1912 Process : not null access procedure (Element : Element_Type))
1914 begin
1915 if Position = No_Element then
1916 raise Constraint_Error with "Position cursor has no element";
1917 end if;
1919 if Is_Root (Position) then
1920 raise Program_Error with "Position cursor designates root";
1921 end if;
1923 declare
1924 T : Tree renames Position.Container.all'Unrestricted_Access.all;
1925 B : Natural renames T.Busy;
1926 L : Natural renames T.Lock;
1928 begin
1929 B := B + 1;
1930 L := L + 1;
1932 Process (Position.Node.Element);
1934 L := L - 1;
1935 B := B - 1;
1937 exception
1938 when others =>
1939 L := L - 1;
1940 B := B - 1;
1942 raise;
1943 end;
1944 end Query_Element;
1946 ----------
1947 -- Read --
1948 ----------
1950 procedure Read
1951 (Stream : not null access Root_Stream_Type'Class;
1952 Container : out Tree)
1954 procedure Read_Children (Subtree : Tree_Node_Access);
1956 function Read_Subtree
1957 (Parent : Tree_Node_Access) return Tree_Node_Access;
1959 Total_Count : Count_Type'Base;
1960 -- Value read from the stream that says how many elements follow
1962 Read_Count : Count_Type'Base;
1963 -- Actual number of elements read from the stream
1965 -------------------
1966 -- Read_Children --
1967 -------------------
1969 procedure Read_Children (Subtree : Tree_Node_Access) is
1970 pragma Assert (Subtree /= null);
1971 pragma Assert (Subtree.Children.First = null);
1972 pragma Assert (Subtree.Children.Last = null);
1974 Count : Count_Type'Base;
1975 -- Number of child subtrees
1977 C : Children_Type;
1979 begin
1980 Count_Type'Read (Stream, Count);
1982 if Count < 0 then
1983 raise Program_Error with "attempt to read from corrupt stream";
1984 end if;
1986 if Count = 0 then
1987 return;
1988 end if;
1990 C.First := Read_Subtree (Parent => Subtree);
1991 C.Last := C.First;
1993 for J in Count_Type'(2) .. Count loop
1994 C.Last.Next := Read_Subtree (Parent => Subtree);
1995 C.Last.Next.Prev := C.Last;
1996 C.Last := C.Last.Next;
1997 end loop;
1999 -- Now that the allocation and reads have completed successfully, it
2000 -- is safe to link the children to their parent.
2002 Subtree.Children := C;
2003 end Read_Children;
2005 ------------------
2006 -- Read_Subtree --
2007 ------------------
2009 function Read_Subtree
2010 (Parent : Tree_Node_Access) return Tree_Node_Access
2012 Subtree : constant Tree_Node_Access :=
2013 new Tree_Node_Type'
2014 (Parent => Parent,
2015 Element => Element_Type'Input (Stream),
2016 others => <>);
2018 begin
2019 Read_Count := Read_Count + 1;
2021 Read_Children (Subtree);
2023 return Subtree;
2024 end Read_Subtree;
2026 -- Start of processing for Read
2028 begin
2029 Container.Clear; -- checks busy bit
2031 Count_Type'Read (Stream, Total_Count);
2033 if Total_Count < 0 then
2034 raise Program_Error with "attempt to read from corrupt stream";
2035 end if;
2037 if Total_Count = 0 then
2038 return;
2039 end if;
2041 Read_Count := 0;
2043 Read_Children (Root_Node (Container));
2045 if Read_Count /= Total_Count then
2046 raise Program_Error with "attempt to read from corrupt stream";
2047 end if;
2049 Container.Count := Total_Count;
2050 end Read;
2052 procedure Read
2053 (Stream : not null access Root_Stream_Type'Class;
2054 Position : out Cursor)
2056 begin
2057 raise Program_Error with "attempt to read tree cursor from stream";
2058 end Read;
2060 procedure Read
2061 (Stream : not null access Root_Stream_Type'Class;
2062 Item : out Reference_Type)
2064 begin
2065 raise Program_Error with "attempt to stream reference";
2066 end Read;
2068 procedure Read
2069 (Stream : not null access Root_Stream_Type'Class;
2070 Item : out Constant_Reference_Type)
2072 begin
2073 raise Program_Error with "attempt to stream reference";
2074 end Read;
2076 ---------------
2077 -- Reference --
2078 ---------------
2080 function Reference
2081 (Container : aliased in out Tree;
2082 Position : Cursor) return Reference_Type
2084 begin
2085 if Position.Container = null then
2086 raise Constraint_Error with
2087 "Position cursor has no element";
2088 end if;
2090 if Position.Container /= Container'Unrestricted_Access then
2091 raise Program_Error with
2092 "Position cursor designates wrong container";
2093 end if;
2095 if Position.Node = Root_Node (Container) then
2096 raise Program_Error with "Position cursor designates root";
2097 end if;
2099 -- Implement Vet for multiway tree???
2100 -- pragma Assert (Vet (Position),
2101 -- "Position cursor in Constant_Reference is bad");
2103 declare
2104 C : Tree renames Position.Container.all;
2105 B : Natural renames C.Busy;
2106 L : Natural renames C.Lock;
2107 begin
2108 return R : constant Reference_Type :=
2109 (Element => Position.Node.Element'Access,
2110 Control => (Controlled with Position.Container))
2112 B := B + 1;
2113 L := L + 1;
2114 end return;
2115 end;
2116 end Reference;
2118 --------------------
2119 -- Remove_Subtree --
2120 --------------------
2122 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2123 C : Children_Type renames Subtree.Parent.Children;
2125 begin
2126 -- This is a utility operation to remove a subtree node from its
2127 -- parent's list of children.
2129 if C.First = Subtree then
2130 pragma Assert (Subtree.Prev = null);
2132 if C.Last = Subtree then
2133 pragma Assert (Subtree.Next = null);
2134 C.First := null;
2135 C.Last := null;
2137 else
2138 C.First := Subtree.Next;
2139 C.First.Prev := null;
2140 end if;
2142 elsif C.Last = Subtree then
2143 pragma Assert (Subtree.Next = null);
2144 C.Last := Subtree.Prev;
2145 C.Last.Next := null;
2147 else
2148 Subtree.Prev.Next := Subtree.Next;
2149 Subtree.Next.Prev := Subtree.Prev;
2150 end if;
2151 end Remove_Subtree;
2153 ----------------------
2154 -- Replace_Element --
2155 ----------------------
2157 procedure Replace_Element
2158 (Container : in out Tree;
2159 Position : Cursor;
2160 New_Item : Element_Type)
2162 begin
2163 if Position = No_Element then
2164 raise Constraint_Error with "Position cursor has no element";
2165 end if;
2167 if Position.Container /= Container'Unrestricted_Access then
2168 raise Program_Error with "Position cursor not in container";
2169 end if;
2171 if Is_Root (Position) then
2172 raise Program_Error with "Position cursor designates root";
2173 end if;
2175 if Container.Lock > 0 then
2176 raise Program_Error
2177 with "attempt to tamper with elements (tree is locked)";
2178 end if;
2180 Position.Node.Element := New_Item;
2181 end Replace_Element;
2183 ------------------------------
2184 -- Reverse_Iterate_Children --
2185 ------------------------------
2187 procedure Reverse_Iterate_Children
2188 (Parent : Cursor;
2189 Process : not null access procedure (Position : Cursor))
2191 begin
2192 if Parent = No_Element then
2193 raise Constraint_Error with "Parent cursor has no element";
2194 end if;
2196 declare
2197 B : Natural renames Parent.Container.Busy;
2198 C : Tree_Node_Access;
2200 begin
2201 B := B + 1;
2203 C := Parent.Node.Children.Last;
2204 while C /= null loop
2205 Process (Position => Cursor'(Parent.Container, Node => C));
2206 C := C.Prev;
2207 end loop;
2209 B := B - 1;
2211 exception
2212 when others =>
2213 B := B - 1;
2214 raise;
2215 end;
2216 end Reverse_Iterate_Children;
2218 ----------
2219 -- Root --
2220 ----------
2222 function Root (Container : Tree) return Cursor is
2223 begin
2224 return (Container'Unrestricted_Access, Root_Node (Container));
2225 end Root;
2227 ---------------
2228 -- Root_Node --
2229 ---------------
2231 function Root_Node (Container : Tree) return Tree_Node_Access is
2232 type Root_Node_Access is access all Root_Node_Type;
2233 for Root_Node_Access'Storage_Size use 0;
2234 pragma Convention (C, Root_Node_Access);
2236 function To_Tree_Node_Access is
2237 new Ada.Unchecked_Conversion (Root_Node_Access, Tree_Node_Access);
2239 -- Start of processing for Root_Node
2241 begin
2242 -- This is a utility function for converting from an access type that
2243 -- designates the distinguished root node to an access type designating
2244 -- a non-root node. The representation of a root node does not have an
2245 -- element, but is otherwise identical to a non-root node, so the
2246 -- conversion itself is safe.
2248 return To_Tree_Node_Access (Container.Root'Unrestricted_Access);
2249 end Root_Node;
2251 ---------------------
2252 -- Splice_Children --
2253 ---------------------
2255 procedure Splice_Children
2256 (Target : in out Tree;
2257 Target_Parent : Cursor;
2258 Before : Cursor;
2259 Source : in out Tree;
2260 Source_Parent : Cursor)
2262 Count : Count_Type;
2264 begin
2265 if Target_Parent = No_Element then
2266 raise Constraint_Error with "Target_Parent cursor has no element";
2267 end if;
2269 if Target_Parent.Container /= Target'Unrestricted_Access then
2270 raise Program_Error
2271 with "Target_Parent cursor not in Target container";
2272 end if;
2274 if Before /= No_Element then
2275 if Before.Container /= Target'Unrestricted_Access then
2276 raise Program_Error
2277 with "Before cursor not in Target container";
2278 end if;
2280 if Before.Node.Parent /= Target_Parent.Node then
2281 raise Constraint_Error
2282 with "Before cursor not child of Target_Parent";
2283 end if;
2284 end if;
2286 if Source_Parent = No_Element then
2287 raise Constraint_Error with "Source_Parent cursor has no element";
2288 end if;
2290 if Source_Parent.Container /= Source'Unrestricted_Access then
2291 raise Program_Error
2292 with "Source_Parent cursor not in Source container";
2293 end if;
2295 if Target'Address = Source'Address then
2296 if Target_Parent = Source_Parent then
2297 return;
2298 end if;
2300 if Target.Busy > 0 then
2301 raise Program_Error
2302 with "attempt to tamper with cursors (Target tree is busy)";
2303 end if;
2305 if Is_Reachable (From => Target_Parent.Node,
2306 To => Source_Parent.Node)
2307 then
2308 raise Constraint_Error
2309 with "Source_Parent is ancestor of Target_Parent";
2310 end if;
2312 Splice_Children
2313 (Target_Parent => Target_Parent.Node,
2314 Before => Before.Node,
2315 Source_Parent => Source_Parent.Node);
2317 return;
2318 end if;
2320 if Target.Busy > 0 then
2321 raise Program_Error
2322 with "attempt to tamper with cursors (Target tree is busy)";
2323 end if;
2325 if Source.Busy > 0 then
2326 raise Program_Error
2327 with "attempt to tamper with cursors (Source tree is busy)";
2328 end if;
2330 -- We cache the count of the nodes we have allocated, so that operation
2331 -- Node_Count can execute in O(1) time. But that means we must count the
2332 -- nodes in the subtree we remove from Source and insert into Target, in
2333 -- order to keep the count accurate.
2335 Count := Subtree_Node_Count (Source_Parent.Node);
2336 pragma Assert (Count >= 1);
2338 Count := Count - 1; -- because Source_Parent node does not move
2340 Splice_Children
2341 (Target_Parent => Target_Parent.Node,
2342 Before => Before.Node,
2343 Source_Parent => Source_Parent.Node);
2345 Source.Count := Source.Count - Count;
2346 Target.Count := Target.Count + Count;
2347 end Splice_Children;
2349 procedure Splice_Children
2350 (Container : in out Tree;
2351 Target_Parent : Cursor;
2352 Before : Cursor;
2353 Source_Parent : Cursor)
2355 begin
2356 if Target_Parent = No_Element then
2357 raise Constraint_Error with "Target_Parent cursor has no element";
2358 end if;
2360 if Target_Parent.Container /= Container'Unrestricted_Access then
2361 raise Program_Error
2362 with "Target_Parent cursor not in container";
2363 end if;
2365 if Before /= No_Element then
2366 if Before.Container /= Container'Unrestricted_Access then
2367 raise Program_Error
2368 with "Before cursor not in container";
2369 end if;
2371 if Before.Node.Parent /= Target_Parent.Node then
2372 raise Constraint_Error
2373 with "Before cursor not child of Target_Parent";
2374 end if;
2375 end if;
2377 if Source_Parent = No_Element then
2378 raise Constraint_Error with "Source_Parent cursor has no element";
2379 end if;
2381 if Source_Parent.Container /= Container'Unrestricted_Access then
2382 raise Program_Error
2383 with "Source_Parent cursor not in container";
2384 end if;
2386 if Target_Parent = Source_Parent then
2387 return;
2388 end if;
2390 if Container.Busy > 0 then
2391 raise Program_Error
2392 with "attempt to tamper with cursors (tree is busy)";
2393 end if;
2395 if Is_Reachable (From => Target_Parent.Node,
2396 To => Source_Parent.Node)
2397 then
2398 raise Constraint_Error
2399 with "Source_Parent is ancestor of Target_Parent";
2400 end if;
2402 Splice_Children
2403 (Target_Parent => Target_Parent.Node,
2404 Before => Before.Node,
2405 Source_Parent => Source_Parent.Node);
2406 end Splice_Children;
2408 procedure Splice_Children
2409 (Target_Parent : Tree_Node_Access;
2410 Before : Tree_Node_Access;
2411 Source_Parent : Tree_Node_Access)
2413 CC : constant Children_Type := Source_Parent.Children;
2414 C : Tree_Node_Access;
2416 begin
2417 -- This is a utility operation to remove the children from
2418 -- Source parent and insert them into Target parent.
2420 Source_Parent.Children := Children_Type'(others => null);
2422 -- Fix up the Parent pointers of each child to designate
2423 -- its new Target parent.
2425 C := CC.First;
2426 while C /= null loop
2427 C.Parent := Target_Parent;
2428 C := C.Next;
2429 end loop;
2431 Insert_Subtree_List
2432 (First => CC.First,
2433 Last => CC.Last,
2434 Parent => Target_Parent,
2435 Before => Before);
2436 end Splice_Children;
2438 --------------------
2439 -- Splice_Subtree --
2440 --------------------
2442 procedure Splice_Subtree
2443 (Target : in out Tree;
2444 Parent : Cursor;
2445 Before : Cursor;
2446 Source : in out Tree;
2447 Position : in out Cursor)
2449 Subtree_Count : Count_Type;
2451 begin
2452 if Parent = No_Element then
2453 raise Constraint_Error with "Parent cursor has no element";
2454 end if;
2456 if Parent.Container /= Target'Unrestricted_Access then
2457 raise Program_Error with "Parent cursor not in Target container";
2458 end if;
2460 if Before /= No_Element then
2461 if Before.Container /= Target'Unrestricted_Access then
2462 raise Program_Error with "Before cursor not in Target container";
2463 end if;
2465 if Before.Node.Parent /= Parent.Node then
2466 raise Constraint_Error with "Before cursor not child of Parent";
2467 end if;
2468 end if;
2470 if Position = No_Element then
2471 raise Constraint_Error with "Position cursor has no element";
2472 end if;
2474 if Position.Container /= Source'Unrestricted_Access then
2475 raise Program_Error with "Position cursor not in Source container";
2476 end if;
2478 if Is_Root (Position) then
2479 raise Program_Error with "Position cursor designates root";
2480 end if;
2482 if Target'Address = Source'Address then
2483 if Position.Node.Parent = Parent.Node then
2484 if Position.Node = Before.Node then
2485 return;
2486 end if;
2488 if Position.Node.Next = Before.Node then
2489 return;
2490 end if;
2491 end if;
2493 if Target.Busy > 0 then
2494 raise Program_Error
2495 with "attempt to tamper with cursors (Target tree is busy)";
2496 end if;
2498 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2499 raise Constraint_Error with "Position is ancestor of Parent";
2500 end if;
2502 Remove_Subtree (Position.Node);
2504 Position.Node.Parent := Parent.Node;
2505 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2507 return;
2508 end if;
2510 if Target.Busy > 0 then
2511 raise Program_Error
2512 with "attempt to tamper with cursors (Target tree is busy)";
2513 end if;
2515 if Source.Busy > 0 then
2516 raise Program_Error
2517 with "attempt to tamper with cursors (Source tree is busy)";
2518 end if;
2520 -- This is an unfortunate feature of this API: we must count the nodes
2521 -- in the subtree that we remove from the source tree, which is an O(n)
2522 -- operation. It would have been better if the Tree container did not
2523 -- have a Node_Count selector; a user that wants the number of nodes in
2524 -- the tree could simply call Subtree_Node_Count, with the understanding
2525 -- that such an operation is O(n).
2527 -- Of course, we could choose to implement the Node_Count selector as an
2528 -- O(n) operation, which would turn this splice operation into an O(1)
2529 -- operation. ???
2531 Subtree_Count := Subtree_Node_Count (Position.Node);
2532 pragma Assert (Subtree_Count <= Source.Count);
2534 Remove_Subtree (Position.Node);
2535 Source.Count := Source.Count - Subtree_Count;
2537 Position.Node.Parent := Parent.Node;
2538 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2540 Target.Count := Target.Count + Subtree_Count;
2542 Position.Container := Target'Unrestricted_Access;
2543 end Splice_Subtree;
2545 procedure Splice_Subtree
2546 (Container : in out Tree;
2547 Parent : Cursor;
2548 Before : Cursor;
2549 Position : Cursor)
2551 begin
2552 if Parent = No_Element then
2553 raise Constraint_Error with "Parent cursor has no element";
2554 end if;
2556 if Parent.Container /= Container'Unrestricted_Access then
2557 raise Program_Error with "Parent cursor not in container";
2558 end if;
2560 if Before /= No_Element then
2561 if Before.Container /= Container'Unrestricted_Access then
2562 raise Program_Error with "Before cursor not in container";
2563 end if;
2565 if Before.Node.Parent /= Parent.Node then
2566 raise Constraint_Error with "Before cursor not child of Parent";
2567 end if;
2568 end if;
2570 if Position = No_Element then
2571 raise Constraint_Error with "Position cursor has no element";
2572 end if;
2574 if Position.Container /= Container'Unrestricted_Access then
2575 raise Program_Error with "Position cursor not in container";
2576 end if;
2578 if Is_Root (Position) then
2580 -- Should this be PE instead? Need ARG confirmation. ???
2582 raise Constraint_Error with "Position cursor designates root";
2583 end if;
2585 if Position.Node.Parent = Parent.Node then
2586 if Position.Node = Before.Node then
2587 return;
2588 end if;
2590 if Position.Node.Next = Before.Node then
2591 return;
2592 end if;
2593 end if;
2595 if Container.Busy > 0 then
2596 raise Program_Error
2597 with "attempt to tamper with cursors (tree is busy)";
2598 end if;
2600 if Is_Reachable (From => Parent.Node, To => Position.Node) then
2601 raise Constraint_Error with "Position is ancestor of Parent";
2602 end if;
2604 Remove_Subtree (Position.Node);
2606 Position.Node.Parent := Parent.Node;
2607 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2608 end Splice_Subtree;
2610 ------------------------
2611 -- Subtree_Node_Count --
2612 ------------------------
2614 function Subtree_Node_Count (Position : Cursor) return Count_Type is
2615 begin
2616 if Position = No_Element then
2617 return 0;
2618 end if;
2620 return Subtree_Node_Count (Position.Node);
2621 end Subtree_Node_Count;
2623 function Subtree_Node_Count
2624 (Subtree : Tree_Node_Access) return Count_Type
2626 Result : Count_Type;
2627 Node : Tree_Node_Access;
2629 begin
2630 Result := 1;
2631 Node := Subtree.Children.First;
2632 while Node /= null loop
2633 Result := Result + Subtree_Node_Count (Node);
2634 Node := Node.Next;
2635 end loop;
2637 return Result;
2638 end Subtree_Node_Count;
2640 ----------
2641 -- Swap --
2642 ----------
2644 procedure Swap
2645 (Container : in out Tree;
2646 I, J : Cursor)
2648 begin
2649 if I = No_Element then
2650 raise Constraint_Error with "I cursor has no element";
2651 end if;
2653 if I.Container /= Container'Unrestricted_Access then
2654 raise Program_Error with "I cursor not in container";
2655 end if;
2657 if Is_Root (I) then
2658 raise Program_Error with "I cursor designates root";
2659 end if;
2661 if I = J then -- make this test sooner???
2662 return;
2663 end if;
2665 if J = No_Element then
2666 raise Constraint_Error with "J cursor has no element";
2667 end if;
2669 if J.Container /= Container'Unrestricted_Access then
2670 raise Program_Error with "J cursor not in container";
2671 end if;
2673 if Is_Root (J) then
2674 raise Program_Error with "J cursor designates root";
2675 end if;
2677 if Container.Lock > 0 then
2678 raise Program_Error
2679 with "attempt to tamper with elements (tree is locked)";
2680 end if;
2682 declare
2683 EI : constant Element_Type := I.Node.Element;
2685 begin
2686 I.Node.Element := J.Node.Element;
2687 J.Node.Element := EI;
2688 end;
2689 end Swap;
2691 --------------------
2692 -- Update_Element --
2693 --------------------
2695 procedure Update_Element
2696 (Container : in out Tree;
2697 Position : Cursor;
2698 Process : not null access procedure (Element : in out Element_Type))
2700 begin
2701 if Position = No_Element then
2702 raise Constraint_Error with "Position cursor has no element";
2703 end if;
2705 if Position.Container /= Container'Unrestricted_Access then
2706 raise Program_Error with "Position cursor not in container";
2707 end if;
2709 if Is_Root (Position) then
2710 raise Program_Error with "Position cursor designates root";
2711 end if;
2713 declare
2714 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2715 B : Natural renames T.Busy;
2716 L : Natural renames T.Lock;
2718 begin
2719 B := B + 1;
2720 L := L + 1;
2722 Process (Position.Node.Element);
2724 L := L - 1;
2725 B := B - 1;
2727 exception
2728 when others =>
2729 L := L - 1;
2730 B := B - 1;
2732 raise;
2733 end;
2734 end Update_Element;
2736 -----------
2737 -- Write --
2738 -----------
2740 procedure Write
2741 (Stream : not null access Root_Stream_Type'Class;
2742 Container : Tree)
2744 procedure Write_Children (Subtree : Tree_Node_Access);
2745 procedure Write_Subtree (Subtree : Tree_Node_Access);
2747 --------------------
2748 -- Write_Children --
2749 --------------------
2751 procedure Write_Children (Subtree : Tree_Node_Access) is
2752 CC : Children_Type renames Subtree.Children;
2753 C : Tree_Node_Access;
2755 begin
2756 Count_Type'Write (Stream, Child_Count (CC));
2758 C := CC.First;
2759 while C /= null loop
2760 Write_Subtree (C);
2761 C := C.Next;
2762 end loop;
2763 end Write_Children;
2765 -------------------
2766 -- Write_Subtree --
2767 -------------------
2769 procedure Write_Subtree (Subtree : Tree_Node_Access) is
2770 begin
2771 Element_Type'Output (Stream, Subtree.Element);
2772 Write_Children (Subtree);
2773 end Write_Subtree;
2775 -- Start of processing for Write
2777 begin
2778 Count_Type'Write (Stream, Container.Count);
2780 if Container.Count = 0 then
2781 return;
2782 end if;
2784 Write_Children (Root_Node (Container));
2785 end Write;
2787 procedure Write
2788 (Stream : not null access Root_Stream_Type'Class;
2789 Position : Cursor)
2791 begin
2792 raise Program_Error with "attempt to write tree cursor to stream";
2793 end Write;
2795 procedure Write
2796 (Stream : not null access Root_Stream_Type'Class;
2797 Item : Reference_Type)
2799 begin
2800 raise Program_Error with "attempt to stream reference";
2801 end Write;
2803 procedure Write
2804 (Stream : not null access Root_Stream_Type'Class;
2805 Item : Constant_Reference_Type)
2807 begin
2808 raise Program_Error with "attempt to stream reference";
2809 end Write;
2811 end Ada.Containers.Multiway_Trees;