i386: Adjust rtx cost for imulq and imulw [PR115749]
[official-gcc.git] / gcc / ada / libgnat / a-comutr.adb
blobda3692959da93237780b84106fc0d6f161c7a581
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-2024, 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;
34 with System.Put_Images;
36 package body Ada.Containers.Multiway_Trees with
37 SPARK_Mode => Off
40 pragma Warnings (Off, "variable ""Busy*"" is not referenced");
41 pragma Warnings (Off, "variable ""Lock*"" is not referenced");
42 -- See comment in Ada.Containers.Helpers
44 --------------------
45 -- Root_Iterator --
46 --------------------
48 type Root_Iterator is abstract new Limited_Controlled and
49 Tree_Iterator_Interfaces.Forward_Iterator with
50 record
51 Container : Tree_Access;
52 Subtree : Tree_Node_Access;
53 end record
54 with Disable_Controlled => not T_Check;
56 overriding procedure Finalize (Object : in out Root_Iterator);
58 -----------------------
59 -- Subtree_Iterator --
60 -----------------------
62 -- ??? these headers are a bit odd, but for sure they do not substitute
63 -- for documenting things, what *is* a Subtree_Iterator?
65 type Subtree_Iterator is new Root_Iterator with null record;
67 overriding function First (Object : Subtree_Iterator) return Cursor;
69 overriding function Next
70 (Object : Subtree_Iterator;
71 Position : Cursor) return Cursor;
73 ---------------------
74 -- Child_Iterator --
75 ---------------------
77 type Child_Iterator is new Root_Iterator and
78 Tree_Iterator_Interfaces.Reversible_Iterator with null record
79 with Disable_Controlled => not T_Check;
81 overriding function First (Object : Child_Iterator) return Cursor;
83 overriding function Next
84 (Object : Child_Iterator;
85 Position : Cursor) return Cursor;
87 overriding function Last (Object : Child_Iterator) return Cursor;
89 overriding function Previous
90 (Object : Child_Iterator;
91 Position : Cursor) return Cursor;
93 -----------------------
94 -- Local Subprograms --
95 -----------------------
97 function Root_Node (Container : Tree) return Tree_Node_Access;
99 procedure Deallocate_Node is
100 new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access);
102 procedure Deallocate_Children
103 (Subtree : Tree_Node_Access;
104 Count : in out Count_Type);
106 procedure Deallocate_Subtree
107 (Subtree : in out Tree_Node_Access;
108 Count : in out Count_Type);
110 function Equal_Children
111 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
113 function Equal_Subtree
114 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
116 procedure Iterate_Children
117 (Container : Tree_Access;
118 Subtree : Tree_Node_Access;
119 Process : not null access procedure (Position : Cursor));
121 procedure Iterate_Subtree
122 (Container : Tree_Access;
123 Subtree : Tree_Node_Access;
124 Process : not null access procedure (Position : Cursor));
126 procedure Copy_Children
127 (Source : Children_Type;
128 Parent : Tree_Node_Access;
129 Count : in out Count_Type);
131 procedure Copy_Subtree
132 (Source : Tree_Node_Access;
133 Parent : Tree_Node_Access;
134 Target : out Tree_Node_Access;
135 Count : in out Count_Type);
137 function Find_In_Children
138 (Subtree : Tree_Node_Access;
139 Item : Element_Type) return Tree_Node_Access;
141 function Find_In_Subtree
142 (Subtree : Tree_Node_Access;
143 Item : Element_Type) return Tree_Node_Access;
145 function Child_Count (Children : Children_Type) return Count_Type;
147 function Subtree_Node_Count
148 (Subtree : Tree_Node_Access) return Count_Type;
150 function Is_Reachable (From, To : Tree_Node_Access) return Boolean;
152 procedure Remove_Subtree (Subtree : Tree_Node_Access);
154 procedure Insert_Subtree_Node
155 (Subtree : Tree_Node_Access;
156 Parent : Tree_Node_Access;
157 Before : Tree_Node_Access);
159 procedure Insert_Subtree_List
160 (First : Tree_Node_Access;
161 Last : Tree_Node_Access;
162 Parent : Tree_Node_Access;
163 Before : Tree_Node_Access);
165 procedure Splice_Children
166 (Target_Parent : Tree_Node_Access;
167 Before : Tree_Node_Access;
168 Source_Parent : Tree_Node_Access);
170 ---------
171 -- "=" --
172 ---------
174 function "=" (Left, Right : Tree) return Boolean is
175 begin
176 return Equal_Children (Root_Node (Left), Root_Node (Right));
177 end "=";
179 ------------
180 -- Adjust --
181 ------------
183 procedure Adjust (Container : in out Tree) is
184 Source : constant Children_Type := Container.Root.Children;
185 Source_Count : constant Count_Type := Container.Count;
186 Target_Count : Count_Type;
188 begin
189 -- We first restore the target container to its default-initialized
190 -- state, before we attempt any allocation, to ensure that invariants
191 -- are preserved in the event that the allocation fails.
193 Container.Root.Children := Children_Type'(others => null);
194 Zero_Counts (Container.TC);
195 Container.Count := 0;
197 -- Copy_Children returns a count of the number of nodes that it
198 -- allocates, but it works by incrementing the value that is passed
199 -- in. We must therefore initialize the count value before calling
200 -- Copy_Children.
202 Target_Count := 0;
204 -- Now we attempt the allocation of subtrees. The invariants are
205 -- satisfied even if the allocation fails.
207 Copy_Children (Source, Root_Node (Container), Target_Count);
208 pragma Assert (Target_Count = Source_Count);
210 Container.Count := Source_Count;
211 end Adjust;
213 -------------------
214 -- Ancestor_Find --
215 -------------------
217 function Ancestor_Find
218 (Position : Cursor;
219 Item : Element_Type) return Cursor
221 R, N : Tree_Node_Access;
223 begin
224 if Checks and then Position = No_Element then
225 raise Constraint_Error with "Position cursor has no element";
226 end if;
228 -- Commented-out pending official ruling from ARG. ???
230 -- if Position.Container /= Container'Unrestricted_Access then
231 -- raise Program_Error with "Position cursor not in container";
232 -- end if;
234 -- AI-0136 says to raise PE if Position equals the root node. This does
235 -- not seem correct, as this value is just the limiting condition of the
236 -- search. For now we omit this check, pending a ruling from the ARG.???
238 -- if Checks and then Is_Root (Position) then
239 -- raise Program_Error with "Position cursor designates root";
240 -- end if;
242 R := Root_Node (Position.Container.all);
243 N := Position.Node;
244 while N /= R loop
245 if N.Element = Item then
246 return Cursor'(Position.Container, N);
247 end if;
249 N := N.Parent;
250 end loop;
252 return No_Element;
253 end Ancestor_Find;
255 ------------------
256 -- Append_Child --
257 ------------------
259 procedure Append_Child
260 (Container : in out Tree;
261 Parent : Cursor;
262 New_Item : Element_Type;
263 Count : Count_Type := 1)
265 First : Tree_Node_Access;
266 Last : Tree_Node_Access;
268 begin
269 TC_Check (Container.TC);
271 if Checks and then Parent = No_Element then
272 raise Constraint_Error with "Parent cursor has no element";
273 end if;
275 if Checks and then Parent.Container /= Container'Unrestricted_Access then
276 raise Program_Error with "Parent cursor not in container";
277 end if;
279 if Count = 0 then
280 return;
281 end if;
283 First := new Tree_Node_Type'(Parent => Parent.Node,
284 Element => New_Item,
285 others => <>);
287 Last := First;
288 for J in Count_Type'(2) .. Count loop
290 -- Reclaim other nodes if Storage_Error. ???
292 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
293 Prev => Last,
294 Element => New_Item,
295 others => <>);
297 Last := Last.Next;
298 end loop;
300 Insert_Subtree_List
301 (First => First,
302 Last => Last,
303 Parent => Parent.Node,
304 Before => null); -- null means "insert at end of list"
306 -- In order for operation Node_Count to complete in O(1) time, we cache
307 -- the count value. Here we increment the total count by the number of
308 -- nodes we just inserted.
310 Container.Count := Container.Count + Count;
311 end Append_Child;
313 ------------
314 -- Assign --
315 ------------
317 procedure Assign (Target : in out Tree; Source : Tree) is
318 Source_Count : constant Count_Type := Source.Count;
319 Target_Count : Count_Type;
321 begin
322 if Target'Address = Source'Address then
323 return;
324 end if;
326 Target.Clear; -- checks busy bit
328 -- Copy_Children returns the number of nodes that it allocates, but it
329 -- does this by incrementing the count value passed in, so we must
330 -- initialize the count before calling Copy_Children.
332 Target_Count := 0;
334 -- Note that Copy_Children inserts the newly-allocated children into
335 -- their parent list only after the allocation of all the children has
336 -- succeeded. This preserves invariants even if the allocation fails.
338 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
339 pragma Assert (Target_Count = Source_Count);
341 Target.Count := Source_Count;
342 end Assign;
344 -----------------
345 -- Child_Count --
346 -----------------
348 function Child_Count (Parent : Cursor) return Count_Type is
349 begin
350 return (if Parent = No_Element
351 then 0 else Child_Count (Parent.Node.Children));
352 end Child_Count;
354 function Child_Count (Children : Children_Type) return Count_Type is
355 Result : Count_Type;
356 Node : Tree_Node_Access;
358 begin
359 Result := 0;
360 Node := Children.First;
361 while Node /= null loop
362 Result := Result + 1;
363 Node := Node.Next;
364 end loop;
366 return Result;
367 end Child_Count;
369 -----------------
370 -- Child_Depth --
371 -----------------
373 function Child_Depth (Parent, Child : Cursor) return Count_Type is
374 Result : Count_Type;
375 N : Tree_Node_Access;
377 begin
378 if Checks and then Parent = No_Element then
379 raise Constraint_Error with "Parent cursor has no element";
380 end if;
382 if Checks and then Child = No_Element then
383 raise Constraint_Error with "Child cursor has no element";
384 end if;
386 if Checks and then Parent.Container /= Child.Container then
387 raise Program_Error with "Parent and Child in different containers";
388 end if;
390 Result := 0;
391 N := Child.Node;
392 while N /= Parent.Node loop
393 Result := Result + 1;
394 N := N.Parent;
396 if Checks and then N = null then
397 raise Program_Error with "Parent is not ancestor of Child";
398 end if;
399 end loop;
401 return Result;
402 end Child_Depth;
404 -----------
405 -- Clear --
406 -----------
408 procedure Clear (Container : in out Tree) is
409 Container_Count, Children_Count : Count_Type;
411 begin
412 TC_Check (Container.TC);
414 -- We first set the container count to 0, in order to preserve
415 -- invariants in case the deallocation fails. (This works because
416 -- Deallocate_Children immediately removes the children from their
417 -- parent, and then does the actual deallocation.)
419 Container_Count := Container.Count;
420 Container.Count := 0;
422 -- Deallocate_Children returns the number of nodes that it deallocates,
423 -- but it does this by incrementing the count value that is passed in,
424 -- so we must first initialize the count return value before calling it.
426 Children_Count := 0;
428 -- See comment above. Deallocate_Children immediately removes the
429 -- children list from their parent node (here, the root of the tree),
430 -- and only after that does it attempt the actual deallocation. So even
431 -- if the deallocation fails, the representation invariants for the tree
432 -- are preserved.
434 Deallocate_Children (Root_Node (Container), Children_Count);
435 pragma Assert (Children_Count = Container_Count);
436 end Clear;
438 ------------------------
439 -- Constant_Reference --
440 ------------------------
442 function Constant_Reference
443 (Container : aliased Tree;
444 Position : Cursor) return Constant_Reference_Type
446 begin
447 if Checks and then Position.Container = null then
448 raise Constraint_Error with
449 "Position cursor has no element";
450 end if;
452 if Checks and then Position.Container /= Container'Unrestricted_Access
453 then
454 raise Program_Error with
455 "Position cursor designates wrong container";
456 end if;
458 if Checks and then Position.Node = Root_Node (Container) then
459 raise Program_Error with "Position cursor designates root";
460 end if;
462 -- Implement Vet for multiway tree???
463 -- pragma Assert (Vet (Position),
464 -- "Position cursor in Constant_Reference is bad");
466 declare
467 C : Tree renames Position.Container.all;
468 TC : constant Tamper_Counts_Access :=
469 C.TC'Unrestricted_Access;
470 begin
471 return R : constant Constant_Reference_Type :=
472 (Element => Position.Node.Element'Access,
473 Control => (Controlled with TC))
475 Busy (TC.all);
476 end return;
477 end;
478 end Constant_Reference;
480 --------------
481 -- Contains --
482 --------------
484 function Contains
485 (Container : Tree;
486 Item : Element_Type) return Boolean
488 begin
489 return Find (Container, Item) /= No_Element;
490 end Contains;
492 ----------
493 -- Copy --
494 ----------
496 function Copy (Source : Tree) return Tree is
497 begin
498 return Target : Tree do
499 Copy_Children
500 (Source => Source.Root.Children,
501 Parent => Root_Node (Target),
502 Count => Target.Count);
504 pragma Assert (Target.Count = Source.Count);
505 end return;
506 end Copy;
508 -------------------
509 -- Copy_Children --
510 -------------------
512 procedure Copy_Children
513 (Source : Children_Type;
514 Parent : Tree_Node_Access;
515 Count : in out Count_Type)
517 pragma Assert (Parent /= null);
518 pragma Assert (Parent.Children.First = null);
519 pragma Assert (Parent.Children.Last = null);
521 CC : Children_Type;
522 C : Tree_Node_Access;
524 begin
525 -- We special-case the first allocation, in order to establish the
526 -- representation invariants for type Children_Type.
528 C := Source.First;
530 if C = null then
531 return;
532 end if;
534 Copy_Subtree
535 (Source => C,
536 Parent => Parent,
537 Target => CC.First,
538 Count => Count);
540 CC.Last := CC.First;
542 -- The representation invariants for the Children_Type list have been
543 -- established, so we can now copy the remaining children of Source.
545 C := C.Next;
546 while C /= null loop
547 Copy_Subtree
548 (Source => C,
549 Parent => Parent,
550 Target => CC.Last.Next,
551 Count => Count);
553 CC.Last.Next.Prev := CC.Last;
554 CC.Last := CC.Last.Next;
556 C := C.Next;
557 end loop;
559 -- Add the newly-allocated children to their parent list only after the
560 -- allocation has succeeded, so as to preserve invariants of the parent.
562 Parent.Children := CC;
563 end Copy_Children;
565 ------------------
566 -- Copy_Subtree --
567 ------------------
569 procedure Copy_Subtree
570 (Target : in out Tree;
571 Parent : Cursor;
572 Before : Cursor;
573 Source : Cursor)
575 Target_Subtree : Tree_Node_Access;
576 Target_Count : Count_Type;
578 begin
579 if Checks and then Parent = No_Element then
580 raise Constraint_Error with "Parent cursor has no element";
581 end if;
583 if Checks and then Parent.Container /= Target'Unrestricted_Access then
584 raise Program_Error with "Parent cursor not in container";
585 end if;
587 if Before /= No_Element then
588 if Checks and then Before.Container /= Target'Unrestricted_Access then
589 raise Program_Error with "Before cursor not in container";
590 end if;
592 if Checks and then Before.Node.Parent /= Parent.Node then
593 raise Constraint_Error with "Before cursor not child of Parent";
594 end if;
595 end if;
597 if Source = No_Element then
598 return;
599 end if;
601 if Checks and then Is_Root (Source) then
602 raise Constraint_Error with "Source cursor designates root";
603 end if;
605 -- Copy_Subtree returns a count of the number of nodes that it
606 -- allocates, but it works by incrementing the value that is passed
607 -- in. We must therefore initialize the count value before calling
608 -- Copy_Subtree.
610 Target_Count := 0;
612 Copy_Subtree
613 (Source => Source.Node,
614 Parent => Parent.Node,
615 Target => Target_Subtree,
616 Count => Target_Count);
618 pragma Assert (Target_Subtree /= null);
619 pragma Assert (Target_Subtree.Parent = Parent.Node);
620 pragma Assert (Target_Count >= 1);
622 Insert_Subtree_Node
623 (Subtree => Target_Subtree,
624 Parent => Parent.Node,
625 Before => Before.Node);
627 -- In order for operation Node_Count to complete in O(1) time, we cache
628 -- the count value. Here we increment the total count by the number of
629 -- nodes we just inserted.
631 Target.Count := Target.Count + Target_Count;
632 end Copy_Subtree;
634 procedure Copy_Subtree
635 (Source : Tree_Node_Access;
636 Parent : Tree_Node_Access;
637 Target : out Tree_Node_Access;
638 Count : in out Count_Type)
640 begin
641 Target := new Tree_Node_Type'(Element => Source.Element,
642 Parent => Parent,
643 others => <>);
645 Count := Count + 1;
647 Copy_Children
648 (Source => Source.Children,
649 Parent => Target,
650 Count => Count);
651 end Copy_Subtree;
653 -------------------------
654 -- Deallocate_Children --
655 -------------------------
657 procedure Deallocate_Children
658 (Subtree : Tree_Node_Access;
659 Count : in out Count_Type)
661 pragma Assert (Subtree /= null);
663 CC : Children_Type := Subtree.Children;
664 C : Tree_Node_Access;
666 begin
667 -- We immediately remove the children from their parent, in order to
668 -- preserve invariants in case the deallocation fails.
670 Subtree.Children := Children_Type'(others => null);
672 while CC.First /= null loop
673 C := CC.First;
674 CC.First := C.Next;
676 Deallocate_Subtree (C, Count);
677 end loop;
678 end Deallocate_Children;
680 ------------------------
681 -- Deallocate_Subtree --
682 ------------------------
684 procedure Deallocate_Subtree
685 (Subtree : in out Tree_Node_Access;
686 Count : in out Count_Type)
688 begin
689 Deallocate_Children (Subtree, Count);
690 Deallocate_Node (Subtree);
691 Count := Count + 1;
692 end Deallocate_Subtree;
694 ---------------------
695 -- Delete_Children --
696 ---------------------
698 procedure Delete_Children
699 (Container : in out Tree;
700 Parent : Cursor)
702 Count : Count_Type;
704 begin
705 TC_Check (Container.TC);
707 if Checks and then Parent = No_Element then
708 raise Constraint_Error with "Parent cursor has no element";
709 end if;
711 if Checks and then Parent.Container /= Container'Unrestricted_Access then
712 raise Program_Error with "Parent cursor not in container";
713 end if;
715 -- Deallocate_Children returns a count of the number of nodes that it
716 -- deallocates, but it works by incrementing the value that is passed
717 -- in. We must therefore initialize the count value before calling
718 -- Deallocate_Children.
720 Count := 0;
722 Deallocate_Children (Parent.Node, Count);
723 pragma Assert (Count <= Container.Count);
725 Container.Count := Container.Count - Count;
726 end Delete_Children;
728 -----------------
729 -- Delete_Leaf --
730 -----------------
732 procedure Delete_Leaf
733 (Container : in out Tree;
734 Position : in out Cursor)
736 X : Tree_Node_Access;
738 begin
739 TC_Check (Container.TC);
741 if Checks and then Position = No_Element then
742 raise Constraint_Error with "Position cursor has no element";
743 end if;
745 if Checks and then Position.Container /= Container'Unrestricted_Access
746 then
747 raise Program_Error with "Position cursor not in container";
748 end if;
750 if Checks and then Is_Root (Position) then
751 raise Program_Error with "Position cursor designates root";
752 end if;
754 if Checks and then not Is_Leaf (Position) then
755 raise Constraint_Error with "Position cursor does not designate leaf";
756 end if;
758 X := Position.Node;
759 Position := No_Element;
761 -- Restore represention invariants before attempting the actual
762 -- deallocation.
764 Remove_Subtree (X);
765 Container.Count := Container.Count - 1;
767 -- It is now safe to attempt the deallocation. This leaf node has been
768 -- disassociated from the tree, so even if the deallocation fails,
769 -- representation invariants will remain satisfied.
771 Deallocate_Node (X);
772 end Delete_Leaf;
774 --------------------
775 -- Delete_Subtree --
776 --------------------
778 procedure Delete_Subtree
779 (Container : in out Tree;
780 Position : in out Cursor)
782 X : Tree_Node_Access;
783 Count : Count_Type;
785 begin
786 TC_Check (Container.TC);
788 if Checks and then Position = No_Element then
789 raise Constraint_Error with "Position cursor has no element";
790 end if;
792 if Checks and then Position.Container /= Container'Unrestricted_Access
793 then
794 raise Program_Error with "Position cursor not in container";
795 end if;
797 if Checks and then Is_Root (Position) then
798 raise Program_Error with "Position cursor designates root";
799 end if;
801 X := Position.Node;
802 Position := No_Element;
804 -- Here is one case where a deallocation failure can result in the
805 -- violation of a representation invariant. We disassociate the subtree
806 -- from the tree now, but we only decrement the total node count after
807 -- we attempt the deallocation. However, if the deallocation fails, the
808 -- total node count will not get decremented.
810 -- One way around this dilemma is to count the nodes in the subtree
811 -- before attempt to delete the subtree, but that is an O(n) operation,
812 -- so it does not seem worth it.
814 -- Perhaps this is much ado about nothing, since the only way
815 -- deallocation can fail is if Controlled Finalization fails: this
816 -- propagates Program_Error so all bets are off anyway. ???
818 Remove_Subtree (X);
820 -- Deallocate_Subtree returns a count of the number of nodes that it
821 -- deallocates, but it works by incrementing the value that is passed
822 -- in. We must therefore initialize the count value before calling
823 -- Deallocate_Subtree.
825 Count := 0;
827 Deallocate_Subtree (X, Count);
828 pragma Assert (Count <= Container.Count);
830 -- See comments above. We would prefer to do this sooner, but there's no
831 -- way to satisfy that goal without a potentially severe execution
832 -- penalty.
834 Container.Count := Container.Count - Count;
835 end Delete_Subtree;
837 -----------
838 -- Depth --
839 -----------
841 function Depth (Position : Cursor) return Count_Type is
842 Result : Count_Type;
843 N : Tree_Node_Access;
845 begin
846 Result := 0;
847 N := Position.Node;
848 while N /= null loop
849 N := N.Parent;
850 Result := Result + 1;
851 end loop;
853 return Result;
854 end Depth;
856 -------------
857 -- Element --
858 -------------
860 function Element (Position : Cursor) return Element_Type is
861 begin
862 if Checks and then Position.Container = null then
863 raise Constraint_Error with "Position cursor has no element";
864 end if;
866 if Checks and then Position.Node = Root_Node (Position.Container.all)
867 then
868 raise Program_Error with "Position cursor designates root";
869 end if;
871 return Position.Node.Element;
872 end Element;
874 --------------------
875 -- Equal_Children --
876 --------------------
878 function Equal_Children
879 (Left_Subtree : Tree_Node_Access;
880 Right_Subtree : Tree_Node_Access) return Boolean
882 Left_Children : Children_Type renames Left_Subtree.Children;
883 Right_Children : Children_Type renames Right_Subtree.Children;
885 L, R : Tree_Node_Access;
887 begin
888 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
889 return False;
890 end if;
892 L := Left_Children.First;
893 R := Right_Children.First;
894 while L /= null loop
895 if not Equal_Subtree (L, R) then
896 return False;
897 end if;
899 L := L.Next;
900 R := R.Next;
901 end loop;
903 return True;
904 end Equal_Children;
906 -------------------
907 -- Equal_Subtree --
908 -------------------
910 function Equal_Subtree
911 (Left_Position : Cursor;
912 Right_Position : Cursor) return Boolean
914 begin
915 if Checks and then Left_Position = No_Element then
916 raise Constraint_Error with "Left cursor has no element";
917 end if;
919 if Checks and then Right_Position = No_Element then
920 raise Constraint_Error with "Right cursor has no element";
921 end if;
923 if Left_Position = Right_Position then
924 return True;
925 end if;
927 if Is_Root (Left_Position) then
928 if not Is_Root (Right_Position) then
929 return False;
930 end if;
932 return Equal_Children (Left_Position.Node, Right_Position.Node);
933 end if;
935 if Is_Root (Right_Position) then
936 return False;
937 end if;
939 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
940 end Equal_Subtree;
942 function Equal_Subtree
943 (Left_Subtree : Tree_Node_Access;
944 Right_Subtree : Tree_Node_Access) return Boolean
946 begin
947 if Left_Subtree.Element /= Right_Subtree.Element then
948 return False;
949 end if;
951 return Equal_Children (Left_Subtree, Right_Subtree);
952 end Equal_Subtree;
954 --------------
955 -- Finalize --
956 --------------
958 procedure Finalize (Object : in out Root_Iterator) is
959 begin
960 Unbusy (Object.Container.TC);
961 end Finalize;
963 ----------
964 -- Find --
965 ----------
967 function Find
968 (Container : Tree;
969 Item : Element_Type) return Cursor
971 N : constant Tree_Node_Access :=
972 Find_In_Children (Root_Node (Container), Item);
973 begin
974 if N = null then
975 return No_Element;
976 else
977 return Cursor'(Container'Unrestricted_Access, N);
978 end if;
979 end Find;
981 -----------
982 -- First --
983 -----------
985 overriding function First (Object : Subtree_Iterator) return Cursor is
986 begin
987 if Object.Subtree = Root_Node (Object.Container.all) then
988 return First_Child (Root (Object.Container.all));
989 else
990 return Cursor'(Object.Container, Object.Subtree);
991 end if;
992 end First;
994 overriding function First (Object : Child_Iterator) return Cursor is
995 begin
996 return First_Child (Cursor'(Object.Container, Object.Subtree));
997 end First;
999 -----------------
1000 -- First_Child --
1001 -----------------
1003 function First_Child (Parent : Cursor) return Cursor is
1004 Node : Tree_Node_Access;
1006 begin
1007 if Checks and then Parent = No_Element then
1008 raise Constraint_Error with "Parent cursor has no element";
1009 end if;
1011 Node := Parent.Node.Children.First;
1013 if Node = null then
1014 return No_Element;
1015 end if;
1017 return Cursor'(Parent.Container, Node);
1018 end First_Child;
1020 -------------------------
1021 -- First_Child_Element --
1022 -------------------------
1024 function First_Child_Element (Parent : Cursor) return Element_Type is
1025 begin
1026 return Element (First_Child (Parent));
1027 end First_Child_Element;
1029 ----------------------
1030 -- Find_In_Children --
1031 ----------------------
1033 function Find_In_Children
1034 (Subtree : Tree_Node_Access;
1035 Item : Element_Type) return Tree_Node_Access
1037 N, Result : Tree_Node_Access;
1039 begin
1040 N := Subtree.Children.First;
1041 while N /= null loop
1042 Result := Find_In_Subtree (N, Item);
1044 if Result /= null then
1045 return Result;
1046 end if;
1048 N := N.Next;
1049 end loop;
1051 return null;
1052 end Find_In_Children;
1054 ---------------------
1055 -- Find_In_Subtree --
1056 ---------------------
1058 function Find_In_Subtree
1059 (Position : Cursor;
1060 Item : Element_Type) return Cursor
1062 Result : Tree_Node_Access;
1064 begin
1065 if Checks and then Position = No_Element then
1066 raise Constraint_Error with "Position cursor has no element";
1067 end if;
1069 -- Commented out pending official ruling by ARG. ???
1071 -- if Checks and then
1072 -- Position.Container /= Container'Unrestricted_Access
1073 -- then
1074 -- raise Program_Error with "Position cursor not in container";
1075 -- end if;
1077 Result :=
1078 (if Is_Root (Position)
1079 then Find_In_Children (Position.Node, Item)
1080 else Find_In_Subtree (Position.Node, Item));
1082 if Result = null then
1083 return No_Element;
1084 end if;
1086 return Cursor'(Position.Container, Result);
1087 end Find_In_Subtree;
1089 function Find_In_Subtree
1090 (Subtree : Tree_Node_Access;
1091 Item : Element_Type) return Tree_Node_Access
1093 begin
1094 if Subtree.Element = Item then
1095 return Subtree;
1096 end if;
1098 return Find_In_Children (Subtree, Item);
1099 end Find_In_Subtree;
1101 ------------------------
1102 -- Get_Element_Access --
1103 ------------------------
1105 function Get_Element_Access
1106 (Position : Cursor) return not null Element_Access is
1107 begin
1108 return Position.Node.Element'Access;
1109 end Get_Element_Access;
1111 -----------------
1112 -- Has_Element --
1113 -----------------
1115 function Has_Element (Position : Cursor) return Boolean is
1116 begin
1117 return (if Position = No_Element then False
1118 else Position.Node.Parent /= null);
1119 end Has_Element;
1121 ------------------
1122 -- Insert_Child --
1123 ------------------
1125 procedure Insert_Child
1126 (Container : in out Tree;
1127 Parent : Cursor;
1128 Before : Cursor;
1129 New_Item : Element_Type;
1130 Count : Count_Type := 1)
1132 Position : Cursor;
1134 begin
1135 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1136 end Insert_Child;
1138 procedure Insert_Child
1139 (Container : in out Tree;
1140 Parent : Cursor;
1141 Before : Cursor;
1142 New_Item : Element_Type;
1143 Position : out Cursor;
1144 Count : Count_Type := 1)
1146 First : Tree_Node_Access;
1147 Last : Tree_Node_Access;
1149 begin
1150 TC_Check (Container.TC);
1152 if Checks and then Parent = No_Element then
1153 raise Constraint_Error with "Parent cursor has no element";
1154 end if;
1156 if Checks and then Parent.Container /= Container'Unrestricted_Access then
1157 raise Program_Error with "Parent cursor not in container";
1158 end if;
1160 if Before /= No_Element then
1161 if Checks and then Before.Container /= Container'Unrestricted_Access
1162 then
1163 raise Program_Error with "Before cursor not in container";
1164 end if;
1166 if Checks and then Before.Node.Parent /= Parent.Node then
1167 raise Constraint_Error with "Parent cursor not parent of Before";
1168 end if;
1169 end if;
1171 if Count = 0 then
1172 Position := No_Element; -- Need ruling from ARG ???
1173 return;
1174 end if;
1176 First := new Tree_Node_Type'(Parent => Parent.Node,
1177 Element => New_Item,
1178 others => <>);
1180 Last := First;
1181 for J in Count_Type'(2) .. Count loop
1183 -- Reclaim other nodes if Storage_Error. ???
1185 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1186 Prev => Last,
1187 Element => New_Item,
1188 others => <>);
1190 Last := Last.Next;
1191 end loop;
1193 Insert_Subtree_List
1194 (First => First,
1195 Last => Last,
1196 Parent => Parent.Node,
1197 Before => Before.Node);
1199 -- In order for operation Node_Count to complete in O(1) time, we cache
1200 -- the count value. Here we increment the total count by the number of
1201 -- nodes we just inserted.
1203 Container.Count := Container.Count + Count;
1205 Position := Cursor'(Parent.Container, First);
1206 end Insert_Child;
1208 procedure Insert_Child
1209 (Container : in out Tree;
1210 Parent : Cursor;
1211 Before : Cursor;
1212 Position : out Cursor;
1213 Count : Count_Type := 1)
1215 First : Tree_Node_Access;
1216 Last : Tree_Node_Access;
1218 begin
1219 TC_Check (Container.TC);
1221 if Checks and then Parent = No_Element then
1222 raise Constraint_Error with "Parent cursor has no element";
1223 end if;
1225 if Checks and then Parent.Container /= Container'Unrestricted_Access then
1226 raise Program_Error with "Parent cursor not in container";
1227 end if;
1229 if Before /= No_Element then
1230 if Checks and then Before.Container /= Container'Unrestricted_Access
1231 then
1232 raise Program_Error with "Before cursor not in container";
1233 end if;
1235 if Checks and then Before.Node.Parent /= Parent.Node then
1236 raise Constraint_Error with "Parent cursor not parent of Before";
1237 end if;
1238 end if;
1240 if Count = 0 then
1241 Position := No_Element; -- Need ruling from ARG ???
1242 return;
1243 end if;
1245 First := new Tree_Node_Type'(Parent => Parent.Node,
1246 Element => <>,
1247 others => <>);
1249 Last := First;
1250 for J in Count_Type'(2) .. Count loop
1252 -- Reclaim other nodes if Storage_Error. ???
1254 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1255 Prev => Last,
1256 Element => <>,
1257 others => <>);
1259 Last := Last.Next;
1260 end loop;
1262 Insert_Subtree_List
1263 (First => First,
1264 Last => Last,
1265 Parent => Parent.Node,
1266 Before => Before.Node);
1268 -- In order for operation Node_Count to complete in O(1) time, we cache
1269 -- the count value. Here we increment the total count by the number of
1270 -- nodes we just inserted.
1272 Container.Count := Container.Count + Count;
1274 Position := Cursor'(Parent.Container, First);
1275 end Insert_Child;
1277 -------------------------
1278 -- Insert_Subtree_List --
1279 -------------------------
1281 procedure Insert_Subtree_List
1282 (First : Tree_Node_Access;
1283 Last : Tree_Node_Access;
1284 Parent : Tree_Node_Access;
1285 Before : Tree_Node_Access)
1287 pragma Assert (Parent /= null);
1288 C : Children_Type renames Parent.Children;
1290 begin
1291 -- This is a simple utility operation to insert a list of nodes (from
1292 -- First..Last) as children of Parent. The Before node specifies where
1293 -- the new children should be inserted relative to the existing
1294 -- children.
1296 if First = null then
1297 pragma Assert (Last = null);
1298 return;
1299 end if;
1301 pragma Assert (Last /= null);
1302 pragma Assert (Before = null or else Before.Parent = Parent);
1304 if C.First = null then
1305 C.First := First;
1306 C.First.Prev := null;
1307 C.Last := Last;
1308 C.Last.Next := null;
1310 elsif Before = null then -- means "insert after existing nodes"
1311 C.Last.Next := First;
1312 First.Prev := C.Last;
1313 C.Last := Last;
1314 C.Last.Next := null;
1316 elsif Before = C.First then
1317 Last.Next := C.First;
1318 C.First.Prev := Last;
1319 C.First := First;
1320 C.First.Prev := null;
1322 else
1323 Before.Prev.Next := First;
1324 First.Prev := Before.Prev;
1325 Last.Next := Before;
1326 Before.Prev := Last;
1327 end if;
1328 end Insert_Subtree_List;
1330 -------------------------
1331 -- Insert_Subtree_Node --
1332 -------------------------
1334 procedure Insert_Subtree_Node
1335 (Subtree : Tree_Node_Access;
1336 Parent : Tree_Node_Access;
1337 Before : Tree_Node_Access)
1339 begin
1340 -- This is a simple wrapper operation to insert a single child into the
1341 -- Parent's children list.
1343 Insert_Subtree_List
1344 (First => Subtree,
1345 Last => Subtree,
1346 Parent => Parent,
1347 Before => Before);
1348 end Insert_Subtree_Node;
1350 --------------
1351 -- Is_Empty --
1352 --------------
1354 function Is_Empty (Container : Tree) return Boolean is
1355 begin
1356 return Container.Root.Children.First = null;
1357 end Is_Empty;
1359 -------------
1360 -- Is_Leaf --
1361 -------------
1363 function Is_Leaf (Position : Cursor) return Boolean is
1364 begin
1365 return (if Position = No_Element then False
1366 else Position.Node.Children.First = null);
1367 end Is_Leaf;
1369 ------------------
1370 -- Is_Reachable --
1371 ------------------
1373 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1374 pragma Assert (From /= null);
1375 pragma Assert (To /= null);
1377 N : Tree_Node_Access;
1379 begin
1380 N := From;
1381 while N /= null loop
1382 if N = To then
1383 return True;
1384 end if;
1386 N := N.Parent;
1387 end loop;
1389 return False;
1390 end Is_Reachable;
1392 -------------
1393 -- Is_Root --
1394 -------------
1396 function Is_Root (Position : Cursor) return Boolean is
1397 begin
1398 return (if Position.Container = null then False
1399 else Position = Root (Position.Container.all));
1400 end Is_Root;
1402 -------------
1403 -- Iterate --
1404 -------------
1406 procedure Iterate
1407 (Container : Tree;
1408 Process : not null access procedure (Position : Cursor))
1410 Busy : With_Busy (Container.TC'Unrestricted_Access);
1411 begin
1412 Iterate_Children
1413 (Container => Container'Unrestricted_Access,
1414 Subtree => Root_Node (Container),
1415 Process => Process);
1416 end Iterate;
1418 function Iterate (Container : Tree)
1419 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1421 begin
1422 return Iterate_Subtree (Root (Container));
1423 end Iterate;
1425 ----------------------
1426 -- Iterate_Children --
1427 ----------------------
1429 procedure Iterate_Children
1430 (Parent : Cursor;
1431 Process : not null access procedure (Position : Cursor))
1433 C : Tree_Node_Access;
1434 Busy : With_Busy (Parent.Container.TC'Unrestricted_Access);
1435 begin
1436 if Checks and then Parent = No_Element then
1437 raise Constraint_Error with "Parent cursor has no element";
1438 end if;
1440 C := Parent.Node.Children.First;
1441 while C /= null loop
1442 Process (Position => Cursor'(Parent.Container, Node => C));
1443 C := C.Next;
1444 end loop;
1445 end Iterate_Children;
1447 procedure Iterate_Children
1448 (Container : Tree_Access;
1449 Subtree : Tree_Node_Access;
1450 Process : not null access procedure (Position : Cursor))
1452 Node : Tree_Node_Access;
1454 begin
1455 -- This is a helper function to recursively iterate over all the nodes
1456 -- in a subtree, in depth-first fashion. This particular helper just
1457 -- visits the children of this subtree, not the root of the subtree node
1458 -- itself. This is useful when starting from the ultimate root of the
1459 -- entire tree (see Iterate), as that root does not have an element.
1461 Node := Subtree.Children.First;
1462 while Node /= null loop
1463 Iterate_Subtree (Container, Node, Process);
1464 Node := Node.Next;
1465 end loop;
1466 end Iterate_Children;
1468 function Iterate_Children
1469 (Container : Tree;
1470 Parent : Cursor)
1471 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1473 C : constant Tree_Access := Container'Unrestricted_Access;
1474 begin
1475 if Checks and then Parent = No_Element then
1476 raise Constraint_Error with "Parent cursor has no element";
1477 end if;
1479 if Checks and then Parent.Container /= C then
1480 raise Program_Error with "Parent cursor not in container";
1481 end if;
1483 return It : constant Child_Iterator :=
1484 (Limited_Controlled with
1485 Container => C,
1486 Subtree => Parent.Node)
1488 Busy (C.TC);
1489 end return;
1490 end Iterate_Children;
1492 ---------------------
1493 -- Iterate_Subtree --
1494 ---------------------
1496 function Iterate_Subtree
1497 (Position : Cursor)
1498 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1500 C : constant Tree_Access := Position.Container;
1501 begin
1502 if Checks and then Position = No_Element then
1503 raise Constraint_Error with "Position cursor has no element";
1504 end if;
1506 -- Implement Vet for multiway trees???
1507 -- pragma Assert (Vet (Position), "bad subtree cursor");
1509 return It : constant Subtree_Iterator :=
1510 (Limited_Controlled with
1511 Container => C,
1512 Subtree => Position.Node)
1514 Busy (C.TC);
1515 end return;
1516 end Iterate_Subtree;
1518 procedure Iterate_Subtree
1519 (Position : Cursor;
1520 Process : not null access procedure (Position : Cursor))
1522 Busy : With_Busy (Position.Container.TC'Unrestricted_Access);
1523 begin
1524 if Checks and then Position = No_Element then
1525 raise Constraint_Error with "Position cursor has no element";
1526 end if;
1528 if Is_Root (Position) then
1529 Iterate_Children (Position.Container, Position.Node, Process);
1530 else
1531 Iterate_Subtree (Position.Container, Position.Node, Process);
1532 end if;
1533 end Iterate_Subtree;
1535 procedure Iterate_Subtree
1536 (Container : Tree_Access;
1537 Subtree : Tree_Node_Access;
1538 Process : not null access procedure (Position : Cursor))
1540 begin
1541 -- This is a helper function to recursively iterate over all the nodes
1542 -- in a subtree, in depth-first fashion. It first visits the root of the
1543 -- subtree, then visits its children.
1545 Process (Cursor'(Container, Subtree));
1546 Iterate_Children (Container, Subtree, Process);
1547 end Iterate_Subtree;
1549 ----------
1550 -- Last --
1551 ----------
1553 overriding function Last (Object : Child_Iterator) return Cursor is
1554 begin
1555 return Last_Child (Cursor'(Object.Container, Object.Subtree));
1556 end Last;
1558 ----------------
1559 -- Last_Child --
1560 ----------------
1562 function Last_Child (Parent : Cursor) return Cursor is
1563 Node : Tree_Node_Access;
1565 begin
1566 if Checks and then Parent = No_Element then
1567 raise Constraint_Error with "Parent cursor has no element";
1568 end if;
1570 Node := Parent.Node.Children.Last;
1572 if Node = null then
1573 return No_Element;
1574 end if;
1576 return (Parent.Container, Node);
1577 end Last_Child;
1579 ------------------------
1580 -- Last_Child_Element --
1581 ------------------------
1583 function Last_Child_Element (Parent : Cursor) return Element_Type is
1584 begin
1585 return Element (Last_Child (Parent));
1586 end Last_Child_Element;
1588 ----------
1589 -- Move --
1590 ----------
1592 procedure Move (Target : in out Tree; Source : in out Tree) is
1593 Node : Tree_Node_Access;
1595 begin
1596 if Target'Address = Source'Address then
1597 return;
1598 end if;
1600 TC_Check (Source.TC);
1602 Target.Clear; -- checks busy bit
1604 Target.Root.Children := Source.Root.Children;
1605 Source.Root.Children := Children_Type'(others => null);
1607 Node := Target.Root.Children.First;
1608 while Node /= null loop
1609 Node.Parent := Root_Node (Target);
1610 Node := Node.Next;
1611 end loop;
1613 Target.Count := Source.Count;
1614 Source.Count := 0;
1615 end Move;
1617 ----------
1618 -- Next --
1619 ----------
1621 function Next
1622 (Object : Subtree_Iterator;
1623 Position : Cursor) return Cursor
1625 Node : Tree_Node_Access;
1627 begin
1628 if Position.Container = null then
1629 return No_Element;
1630 end if;
1632 if Checks and then Position.Container /= Object.Container then
1633 raise Program_Error with
1634 "Position cursor of Next designates wrong tree";
1635 end if;
1637 Node := Position.Node;
1639 if Node.Children.First /= null then
1640 return Cursor'(Object.Container, Node.Children.First);
1641 end if;
1643 while Node /= Object.Subtree loop
1644 if Node.Next /= null then
1645 return Cursor'(Object.Container, Node.Next);
1646 end if;
1648 Node := Node.Parent;
1649 end loop;
1651 return No_Element;
1652 end Next;
1654 function Next
1655 (Object : Child_Iterator;
1656 Position : Cursor) return Cursor
1658 begin
1659 if Position.Container = null then
1660 return No_Element;
1661 end if;
1663 if Checks and then Position.Container /= Object.Container then
1664 raise Program_Error with
1665 "Position cursor of Next designates wrong tree";
1666 end if;
1668 return Next_Sibling (Position);
1669 end Next;
1671 ------------------
1672 -- Next_Sibling --
1673 ------------------
1675 function Next_Sibling (Position : Cursor) return Cursor is
1676 begin
1677 if Position = No_Element then
1678 return No_Element;
1679 end if;
1681 if Position.Node.Next = null then
1682 return No_Element;
1683 end if;
1685 return Cursor'(Position.Container, Position.Node.Next);
1686 end Next_Sibling;
1688 procedure Next_Sibling (Position : in out Cursor) is
1689 begin
1690 Position := Next_Sibling (Position);
1691 end Next_Sibling;
1693 ----------------
1694 -- Node_Count --
1695 ----------------
1697 function Node_Count (Container : Tree) return Count_Type is
1698 begin
1699 -- Container.Count is the number of nodes we have actually allocated. We
1700 -- cache the value specifically so this Node_Count operation can execute
1701 -- in O(1) time, which makes it behave similarly to how the Length
1702 -- selector function behaves for other containers.
1704 -- The cached node count value only describes the nodes we have
1705 -- allocated; the root node itself is not included in that count. The
1706 -- Node_Count operation returns a value that includes the root node
1707 -- (because the RM says so), so we must add 1 to our cached value.
1709 return 1 + Container.Count;
1710 end Node_Count;
1712 ------------
1713 -- Parent --
1714 ------------
1716 function Parent (Position : Cursor) return Cursor is
1717 begin
1718 if Position = No_Element then
1719 return No_Element;
1720 end if;
1722 if Position.Node.Parent = null then
1723 return No_Element;
1724 end if;
1726 return Cursor'(Position.Container, Position.Node.Parent);
1727 end Parent;
1729 -------------------
1730 -- Prepend_Child --
1731 -------------------
1733 procedure Prepend_Child
1734 (Container : in out Tree;
1735 Parent : Cursor;
1736 New_Item : Element_Type;
1737 Count : Count_Type := 1)
1739 First, Last : Tree_Node_Access;
1741 begin
1742 TC_Check (Container.TC);
1744 if Checks and then Parent = No_Element then
1745 raise Constraint_Error with "Parent cursor has no element";
1746 end if;
1748 if Checks and then Parent.Container /= Container'Unrestricted_Access then
1749 raise Program_Error with "Parent cursor not in container";
1750 end if;
1752 if Count = 0 then
1753 return;
1754 end if;
1756 First := new Tree_Node_Type'(Parent => Parent.Node,
1757 Element => New_Item,
1758 others => <>);
1760 Last := First;
1762 for J in Count_Type'(2) .. Count loop
1764 -- Reclaim other nodes if Storage_Error???
1766 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1767 Prev => Last,
1768 Element => New_Item,
1769 others => <>);
1771 Last := Last.Next;
1772 end loop;
1774 Insert_Subtree_List
1775 (First => First,
1776 Last => Last,
1777 Parent => Parent.Node,
1778 Before => Parent.Node.Children.First);
1780 -- In order for operation Node_Count to complete in O(1) time, we cache
1781 -- the count value. Here we increment the total count by the number of
1782 -- nodes we just inserted.
1784 Container.Count := Container.Count + Count;
1785 end Prepend_Child;
1787 --------------
1788 -- Previous --
1789 --------------
1791 overriding function Previous
1792 (Object : Child_Iterator;
1793 Position : Cursor) return Cursor
1795 begin
1796 if Position.Container = null then
1797 return No_Element;
1798 end if;
1800 if Checks and then Position.Container /= Object.Container then
1801 raise Program_Error with
1802 "Position cursor of Previous designates wrong tree";
1803 end if;
1805 return Previous_Sibling (Position);
1806 end Previous;
1808 ----------------------
1809 -- Previous_Sibling --
1810 ----------------------
1812 function Previous_Sibling (Position : Cursor) return Cursor is
1813 begin
1814 return
1815 (if Position = No_Element then No_Element
1816 elsif Position.Node.Prev = null then No_Element
1817 else Cursor'(Position.Container, Position.Node.Prev));
1818 end Previous_Sibling;
1820 procedure Previous_Sibling (Position : in out Cursor) is
1821 begin
1822 Position := Previous_Sibling (Position);
1823 end Previous_Sibling;
1825 ----------------------
1826 -- Pseudo_Reference --
1827 ----------------------
1829 function Pseudo_Reference
1830 (Container : aliased Tree'Class) return Reference_Control_Type
1832 TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
1833 begin
1834 return R : constant Reference_Control_Type := (Controlled with TC) do
1835 Busy (TC.all);
1836 end return;
1837 end Pseudo_Reference;
1839 -------------------
1840 -- Query_Element --
1841 -------------------
1843 procedure Query_Element
1844 (Position : Cursor;
1845 Process : not null access procedure (Element : Element_Type))
1847 T : Tree renames Position.Container.all'Unrestricted_Access.all;
1848 Lock : With_Lock (T.TC'Unrestricted_Access);
1849 begin
1850 if Checks and then Position = No_Element then
1851 raise Constraint_Error with "Position cursor has no element";
1852 end if;
1854 if Checks and then Is_Root (Position) then
1855 raise Program_Error with "Position cursor designates root";
1856 end if;
1858 Process (Position.Node.Element);
1859 end Query_Element;
1861 ---------------
1862 -- Put_Image --
1863 ---------------
1865 procedure Put_Image
1866 (S : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class; V : Tree)
1868 use System.Put_Images;
1870 procedure Rec (Position : Cursor);
1871 -- Recursive routine operating on cursors
1873 procedure Rec (Position : Cursor) is
1874 First_Time : Boolean := True;
1875 begin
1876 Array_Before (S);
1878 for X in Iterate_Children (V, Position) loop
1879 if First_Time then
1880 First_Time := False;
1881 else
1882 Array_Between (S);
1883 end if;
1885 Element_Type'Put_Image (S, Element (X));
1886 if Child_Count (X) > 0 then
1887 Simple_Array_Between (S);
1888 Rec (X);
1889 end if;
1890 end loop;
1892 Array_After (S);
1893 end Rec;
1895 begin
1896 if First_Child (Root (V)) = No_Element then
1897 Array_Before (S);
1898 Array_After (S);
1899 else
1900 Rec (First_Child (Root (V)));
1901 end if;
1902 end Put_Image;
1904 ----------
1905 -- Read --
1906 ----------
1908 procedure Read
1909 (Stream : not null access Root_Stream_Type'Class;
1910 Container : out Tree)
1912 procedure Read_Children (Subtree : Tree_Node_Access);
1914 function Read_Subtree
1915 (Parent : Tree_Node_Access) return Tree_Node_Access;
1917 Total_Count : Count_Type'Base;
1918 -- Value read from the stream that says how many elements follow
1920 Read_Count : Count_Type'Base;
1921 -- Actual number of elements read from the stream
1923 -------------------
1924 -- Read_Children --
1925 -------------------
1927 procedure Read_Children (Subtree : Tree_Node_Access) is
1928 pragma Assert (Subtree /= null);
1929 pragma Assert (Subtree.Children.First = null);
1930 pragma Assert (Subtree.Children.Last = null);
1932 Count : Count_Type'Base;
1933 -- Number of child subtrees
1935 C : Children_Type;
1937 begin
1938 Count_Type'Read (Stream, Count);
1940 if Checks and then Count < 0 then
1941 raise Program_Error with "attempt to read from corrupt stream";
1942 end if;
1944 if Count = 0 then
1945 return;
1946 end if;
1948 C.First := Read_Subtree (Parent => Subtree);
1949 C.Last := C.First;
1951 for J in Count_Type'(2) .. Count loop
1952 C.Last.Next := Read_Subtree (Parent => Subtree);
1953 C.Last.Next.Prev := C.Last;
1954 C.Last := C.Last.Next;
1955 end loop;
1957 -- Now that the allocation and reads have completed successfully, it
1958 -- is safe to link the children to their parent.
1960 Subtree.Children := C;
1961 end Read_Children;
1963 ------------------
1964 -- Read_Subtree --
1965 ------------------
1967 function Read_Subtree
1968 (Parent : Tree_Node_Access) return Tree_Node_Access
1970 Subtree : constant Tree_Node_Access :=
1971 new Tree_Node_Type'
1972 (Parent => Parent,
1973 Element => Element_Type'Input (Stream),
1974 others => <>);
1976 begin
1977 Read_Count := Read_Count + 1;
1979 Read_Children (Subtree);
1981 return Subtree;
1982 end Read_Subtree;
1984 -- Start of processing for Read
1986 begin
1987 Container.Clear; -- checks busy bit
1989 Count_Type'Read (Stream, Total_Count);
1991 if Checks and then Total_Count < 0 then
1992 raise Program_Error with "attempt to read from corrupt stream";
1993 end if;
1995 if Total_Count = 0 then
1996 return;
1997 end if;
1999 Read_Count := 0;
2001 Read_Children (Root_Node (Container));
2003 if Checks and then Read_Count /= Total_Count then
2004 raise Program_Error with "attempt to read from corrupt stream";
2005 end if;
2007 Container.Count := Total_Count;
2008 end Read;
2010 procedure Read
2011 (Stream : not null access Root_Stream_Type'Class;
2012 Position : out Cursor)
2014 begin
2015 raise Program_Error with "attempt to read tree cursor from stream";
2016 end Read;
2018 procedure Read
2019 (Stream : not null access Root_Stream_Type'Class;
2020 Item : out Reference_Type)
2022 begin
2023 raise Program_Error with "attempt to stream reference";
2024 end Read;
2026 procedure Read
2027 (Stream : not null access Root_Stream_Type'Class;
2028 Item : out Constant_Reference_Type)
2030 begin
2031 raise Program_Error with "attempt to stream reference";
2032 end Read;
2034 ---------------
2035 -- Reference --
2036 ---------------
2038 function Reference
2039 (Container : aliased in out Tree;
2040 Position : Cursor) return Reference_Type
2042 begin
2043 if Checks and then Position.Container = null then
2044 raise Constraint_Error with
2045 "Position cursor has no element";
2046 end if;
2048 if Checks and then Position.Container /= Container'Unrestricted_Access
2049 then
2050 raise Program_Error with
2051 "Position cursor designates wrong container";
2052 end if;
2054 if Checks and then Position.Node = Root_Node (Container) then
2055 raise Program_Error with "Position cursor designates root";
2056 end if;
2058 -- Implement Vet for multiway tree???
2059 -- pragma Assert (Vet (Position),
2060 -- "Position cursor in Constant_Reference is bad");
2062 declare
2063 C : Tree renames Position.Container.all;
2064 TC : constant Tamper_Counts_Access :=
2065 C.TC'Unrestricted_Access;
2066 begin
2067 return R : constant Reference_Type :=
2068 (Element => Position.Node.Element'Access,
2069 Control => (Controlled with TC))
2071 Busy (TC.all);
2072 end return;
2073 end;
2074 end Reference;
2076 --------------------
2077 -- Remove_Subtree --
2078 --------------------
2080 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2081 C : Children_Type renames Subtree.Parent.Children;
2083 begin
2084 -- This is a utility operation to remove a subtree node from its
2085 -- parent's list of children.
2087 if C.First = Subtree then
2088 pragma Assert (Subtree.Prev = null);
2090 if C.Last = Subtree then
2091 pragma Assert (Subtree.Next = null);
2092 C.First := null;
2093 C.Last := null;
2095 else
2096 C.First := Subtree.Next;
2097 C.First.Prev := null;
2098 end if;
2100 elsif C.Last = Subtree then
2101 pragma Assert (Subtree.Next = null);
2102 C.Last := Subtree.Prev;
2103 C.Last.Next := null;
2105 else
2106 Subtree.Prev.Next := Subtree.Next;
2107 Subtree.Next.Prev := Subtree.Prev;
2108 end if;
2109 end Remove_Subtree;
2111 ----------------------
2112 -- Replace_Element --
2113 ----------------------
2115 procedure Replace_Element
2116 (Container : in out Tree;
2117 Position : Cursor;
2118 New_Item : Element_Type)
2120 begin
2121 TE_Check (Container.TC);
2123 if Checks and then Position = No_Element then
2124 raise Constraint_Error with "Position cursor has no element";
2125 end if;
2127 if Checks and then Position.Container /= Container'Unrestricted_Access
2128 then
2129 raise Program_Error with "Position cursor not in container";
2130 end if;
2132 if Checks and then Is_Root (Position) then
2133 raise Program_Error with "Position cursor designates root";
2134 end if;
2136 Position.Node.Element := New_Item;
2137 end Replace_Element;
2139 ------------------------------
2140 -- Reverse_Iterate_Children --
2141 ------------------------------
2143 procedure Reverse_Iterate_Children
2144 (Parent : Cursor;
2145 Process : not null access procedure (Position : Cursor))
2147 C : Tree_Node_Access;
2148 Busy : With_Busy (Parent.Container.TC'Unrestricted_Access);
2149 begin
2150 if Checks and then Parent = No_Element then
2151 raise Constraint_Error with "Parent cursor has no element";
2152 end if;
2154 C := Parent.Node.Children.Last;
2155 while C /= null loop
2156 Process (Position => Cursor'(Parent.Container, Node => C));
2157 C := C.Prev;
2158 end loop;
2159 end Reverse_Iterate_Children;
2161 ----------
2162 -- Root --
2163 ----------
2165 function Root (Container : Tree) return Cursor is
2166 begin
2167 return (Container'Unrestricted_Access, Root_Node (Container));
2168 end Root;
2170 ---------------
2171 -- Root_Node --
2172 ---------------
2174 function Root_Node (Container : Tree) return Tree_Node_Access is
2175 type Root_Node_Access is access all Root_Node_Type;
2176 for Root_Node_Access'Storage_Size use 0;
2177 pragma Convention (C, Root_Node_Access);
2179 function To_Tree_Node_Access is
2180 new Ada.Unchecked_Conversion (Root_Node_Access, Tree_Node_Access);
2182 -- Start of processing for Root_Node
2184 begin
2185 -- This is a utility function for converting from an access type that
2186 -- designates the distinguished root node to an access type designating
2187 -- a non-root node. The representation of a root node does not have an
2188 -- element, but is otherwise identical to a non-root node, so the
2189 -- conversion itself is safe.
2191 return To_Tree_Node_Access (Container.Root'Unrestricted_Access);
2192 end Root_Node;
2194 ---------------------
2195 -- Splice_Children --
2196 ---------------------
2198 procedure Splice_Children
2199 (Target : in out Tree;
2200 Target_Parent : Cursor;
2201 Before : Cursor;
2202 Source : in out Tree;
2203 Source_Parent : Cursor)
2205 Count : Count_Type;
2207 begin
2208 TC_Check (Target.TC);
2209 TC_Check (Source.TC);
2211 if Checks and then Target_Parent = No_Element then
2212 raise Constraint_Error with "Target_Parent cursor has no element";
2213 end if;
2215 if Checks and then Target_Parent.Container /= Target'Unrestricted_Access
2216 then
2217 raise Program_Error
2218 with "Target_Parent cursor not in Target container";
2219 end if;
2221 if Before /= No_Element then
2222 if Checks and then Before.Container /= Target'Unrestricted_Access then
2223 raise Program_Error
2224 with "Before cursor not in Target container";
2225 end if;
2227 if Checks and then Before.Node.Parent /= Target_Parent.Node then
2228 raise Constraint_Error
2229 with "Before cursor not child of Target_Parent";
2230 end if;
2231 end if;
2233 if Checks and then Source_Parent = No_Element then
2234 raise Constraint_Error with "Source_Parent cursor has no element";
2235 end if;
2237 if Checks and then Source_Parent.Container /= Source'Unrestricted_Access
2238 then
2239 raise Program_Error
2240 with "Source_Parent cursor not in Source container";
2241 end if;
2243 if Target'Address = Source'Address then
2244 if Target_Parent = Source_Parent then
2245 return;
2246 end if;
2248 if Checks and then Is_Reachable (From => Target_Parent.Node,
2249 To => Source_Parent.Node)
2250 then
2251 raise Constraint_Error
2252 with "Source_Parent is ancestor of Target_Parent";
2253 end if;
2255 Splice_Children
2256 (Target_Parent => Target_Parent.Node,
2257 Before => Before.Node,
2258 Source_Parent => Source_Parent.Node);
2260 return;
2261 end if;
2263 -- We cache the count of the nodes we have allocated, so that operation
2264 -- Node_Count can execute in O(1) time. But that means we must count the
2265 -- nodes in the subtree we remove from Source and insert into Target, in
2266 -- order to keep the count accurate.
2268 Count := Subtree_Node_Count (Source_Parent.Node);
2269 pragma Assert (Count >= 1);
2271 Count := Count - 1; -- because Source_Parent node does not move
2273 Splice_Children
2274 (Target_Parent => Target_Parent.Node,
2275 Before => Before.Node,
2276 Source_Parent => Source_Parent.Node);
2278 Source.Count := Source.Count - Count;
2279 Target.Count := Target.Count + Count;
2280 end Splice_Children;
2282 procedure Splice_Children
2283 (Container : in out Tree;
2284 Target_Parent : Cursor;
2285 Before : Cursor;
2286 Source_Parent : Cursor)
2288 begin
2289 TC_Check (Container.TC);
2291 if Checks and then Target_Parent = No_Element then
2292 raise Constraint_Error with "Target_Parent cursor has no element";
2293 end if;
2295 if Checks and then
2296 Target_Parent.Container /= Container'Unrestricted_Access
2297 then
2298 raise Program_Error
2299 with "Target_Parent cursor not in container";
2300 end if;
2302 if Before /= No_Element then
2303 if Checks and then Before.Container /= Container'Unrestricted_Access
2304 then
2305 raise Program_Error
2306 with "Before cursor not in container";
2307 end if;
2309 if Checks and then Before.Node.Parent /= Target_Parent.Node then
2310 raise Constraint_Error
2311 with "Before cursor not child of Target_Parent";
2312 end if;
2313 end if;
2315 if Checks and then Source_Parent = No_Element then
2316 raise Constraint_Error with "Source_Parent cursor has no element";
2317 end if;
2319 if Checks and then
2320 Source_Parent.Container /= Container'Unrestricted_Access
2321 then
2322 raise Program_Error
2323 with "Source_Parent cursor not in container";
2324 end if;
2326 if Target_Parent = Source_Parent then
2327 return;
2328 end if;
2330 if Checks and then Is_Reachable (From => Target_Parent.Node,
2331 To => Source_Parent.Node)
2332 then
2333 raise Constraint_Error
2334 with "Source_Parent is ancestor of Target_Parent";
2335 end if;
2337 Splice_Children
2338 (Target_Parent => Target_Parent.Node,
2339 Before => Before.Node,
2340 Source_Parent => Source_Parent.Node);
2341 end Splice_Children;
2343 procedure Splice_Children
2344 (Target_Parent : Tree_Node_Access;
2345 Before : Tree_Node_Access;
2346 Source_Parent : Tree_Node_Access)
2348 CC : constant Children_Type := Source_Parent.Children;
2349 C : Tree_Node_Access;
2351 begin
2352 -- This is a utility operation to remove the children from
2353 -- Source parent and insert them into Target parent.
2355 Source_Parent.Children := Children_Type'(others => null);
2357 -- Fix up the Parent pointers of each child to designate
2358 -- its new Target parent.
2360 C := CC.First;
2361 while C /= null loop
2362 C.Parent := Target_Parent;
2363 C := C.Next;
2364 end loop;
2366 Insert_Subtree_List
2367 (First => CC.First,
2368 Last => CC.Last,
2369 Parent => Target_Parent,
2370 Before => Before);
2371 end Splice_Children;
2373 --------------------
2374 -- Splice_Subtree --
2375 --------------------
2377 procedure Splice_Subtree
2378 (Target : in out Tree;
2379 Parent : Cursor;
2380 Before : Cursor;
2381 Source : in out Tree;
2382 Position : in out Cursor)
2384 Subtree_Count : Count_Type;
2386 begin
2387 TC_Check (Target.TC);
2388 TC_Check (Source.TC);
2390 if Checks and then Parent = No_Element then
2391 raise Constraint_Error with "Parent cursor has no element";
2392 end if;
2394 if Checks and then Parent.Container /= Target'Unrestricted_Access then
2395 raise Program_Error with "Parent cursor not in Target container";
2396 end if;
2398 if Before /= No_Element then
2399 if Checks and then Before.Container /= Target'Unrestricted_Access then
2400 raise Program_Error with "Before cursor not in Target container";
2401 end if;
2403 if Checks and then Before.Node.Parent /= Parent.Node then
2404 raise Constraint_Error with "Before cursor not child of Parent";
2405 end if;
2406 end if;
2408 if Checks and then Position = No_Element then
2409 raise Constraint_Error with "Position cursor has no element";
2410 end if;
2412 if Checks and then Position.Container /= Source'Unrestricted_Access then
2413 raise Program_Error with "Position cursor not in Source container";
2414 end if;
2416 if Checks and then Is_Root (Position) then
2417 raise Program_Error with "Position cursor designates root";
2418 end if;
2420 if Target'Address = Source'Address then
2421 if Position.Node.Parent = Parent.Node then
2422 if Position.Node = Before.Node then
2423 return;
2424 end if;
2426 if Position.Node.Next = Before.Node then
2427 return;
2428 end if;
2429 end if;
2431 if Checks and then
2432 Is_Reachable (From => Parent.Node, To => Position.Node)
2433 then
2434 raise Constraint_Error with "Position is ancestor of Parent";
2435 end if;
2437 Remove_Subtree (Position.Node);
2439 Position.Node.Parent := Parent.Node;
2440 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2442 return;
2443 end if;
2445 -- This is an unfortunate feature of this API: we must count the nodes
2446 -- in the subtree that we remove from the source tree, which is an O(n)
2447 -- operation. It would have been better if the Tree container did not
2448 -- have a Node_Count selector; a user that wants the number of nodes in
2449 -- the tree could simply call Subtree_Node_Count, with the understanding
2450 -- that such an operation is O(n).
2452 -- Of course, we could choose to implement the Node_Count selector as an
2453 -- O(n) operation, which would turn this splice operation into an O(1)
2454 -- operation. ???
2456 Subtree_Count := Subtree_Node_Count (Position.Node);
2457 pragma Assert (Subtree_Count <= Source.Count);
2459 Remove_Subtree (Position.Node);
2460 Source.Count := Source.Count - Subtree_Count;
2462 Position.Node.Parent := Parent.Node;
2463 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2465 Target.Count := Target.Count + Subtree_Count;
2467 Position.Container := Target'Unrestricted_Access;
2468 end Splice_Subtree;
2470 procedure Splice_Subtree
2471 (Container : in out Tree;
2472 Parent : Cursor;
2473 Before : Cursor;
2474 Position : Cursor)
2476 begin
2477 TC_Check (Container.TC);
2479 if Checks and then Parent = No_Element then
2480 raise Constraint_Error with "Parent cursor has no element";
2481 end if;
2483 if Checks and then Parent.Container /= Container'Unrestricted_Access then
2484 raise Program_Error with "Parent cursor not in container";
2485 end if;
2487 if Before /= No_Element then
2488 if Checks and then Before.Container /= Container'Unrestricted_Access
2489 then
2490 raise Program_Error with "Before cursor not in container";
2491 end if;
2493 if Checks and then Before.Node.Parent /= Parent.Node then
2494 raise Constraint_Error with "Before cursor not child of Parent";
2495 end if;
2496 end if;
2498 if Checks and then Position = No_Element then
2499 raise Constraint_Error with "Position cursor has no element";
2500 end if;
2502 if Checks and then Position.Container /= Container'Unrestricted_Access
2503 then
2504 raise Program_Error with "Position cursor not in container";
2505 end if;
2507 if Checks and then Is_Root (Position) then
2509 -- Should this be PE instead? Need ARG confirmation. ???
2511 raise Constraint_Error with "Position cursor designates root";
2512 end if;
2514 if Position.Node.Parent = Parent.Node then
2515 if Position.Node = Before.Node then
2516 return;
2517 end if;
2519 if Position.Node.Next = Before.Node then
2520 return;
2521 end if;
2522 end if;
2524 if Checks and then
2525 Is_Reachable (From => Parent.Node, To => Position.Node)
2526 then
2527 raise Constraint_Error with "Position is ancestor of Parent";
2528 end if;
2530 Remove_Subtree (Position.Node);
2532 Position.Node.Parent := Parent.Node;
2533 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2534 end Splice_Subtree;
2536 ------------------------
2537 -- Subtree_Node_Count --
2538 ------------------------
2540 function Subtree_Node_Count (Position : Cursor) return Count_Type is
2541 begin
2542 if Position = No_Element then
2543 return 0;
2544 end if;
2546 return Subtree_Node_Count (Position.Node);
2547 end Subtree_Node_Count;
2549 function Subtree_Node_Count
2550 (Subtree : Tree_Node_Access) return Count_Type
2552 Result : Count_Type;
2553 Node : Tree_Node_Access;
2555 begin
2556 Result := 1;
2557 Node := Subtree.Children.First;
2558 while Node /= null loop
2559 Result := Result + Subtree_Node_Count (Node);
2560 Node := Node.Next;
2561 end loop;
2563 return Result;
2564 end Subtree_Node_Count;
2566 ----------
2567 -- Swap --
2568 ----------
2570 procedure Swap
2571 (Container : in out Tree;
2572 I, J : Cursor)
2574 begin
2575 TE_Check (Container.TC);
2577 if Checks and then I = No_Element then
2578 raise Constraint_Error with "I cursor has no element";
2579 end if;
2581 if Checks and then I.Container /= Container'Unrestricted_Access then
2582 raise Program_Error with "I cursor not in container";
2583 end if;
2585 if Checks and then Is_Root (I) then
2586 raise Program_Error with "I cursor designates root";
2587 end if;
2589 if I = J then -- make this test sooner???
2590 return;
2591 end if;
2593 if Checks and then J = No_Element then
2594 raise Constraint_Error with "J cursor has no element";
2595 end if;
2597 if Checks and then J.Container /= Container'Unrestricted_Access then
2598 raise Program_Error with "J cursor not in container";
2599 end if;
2601 if Checks and then Is_Root (J) then
2602 raise Program_Error with "J cursor designates root";
2603 end if;
2605 declare
2606 EI : constant Element_Type := I.Node.Element;
2608 begin
2609 I.Node.Element := J.Node.Element;
2610 J.Node.Element := EI;
2611 end;
2612 end Swap;
2614 --------------------
2615 -- Update_Element --
2616 --------------------
2618 procedure Update_Element
2619 (Container : in out Tree;
2620 Position : Cursor;
2621 Process : not null access procedure (Element : in out Element_Type))
2623 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2624 Lock : With_Lock (T.TC'Unrestricted_Access);
2625 begin
2626 if Checks and then Position = No_Element then
2627 raise Constraint_Error with "Position cursor has no element";
2628 end if;
2630 if Checks and then Position.Container /= Container'Unrestricted_Access
2631 then
2632 raise Program_Error with "Position cursor not in container";
2633 end if;
2635 if Checks and then Is_Root (Position) then
2636 raise Program_Error with "Position cursor designates root";
2637 end if;
2639 Process (Position.Node.Element);
2640 end Update_Element;
2642 -----------
2643 -- Write --
2644 -----------
2646 procedure Write
2647 (Stream : not null access Root_Stream_Type'Class;
2648 Container : Tree)
2650 procedure Write_Children (Subtree : Tree_Node_Access);
2651 procedure Write_Subtree (Subtree : Tree_Node_Access);
2653 --------------------
2654 -- Write_Children --
2655 --------------------
2657 procedure Write_Children (Subtree : Tree_Node_Access) is
2658 CC : Children_Type renames Subtree.Children;
2659 C : Tree_Node_Access;
2661 begin
2662 Count_Type'Write (Stream, Child_Count (CC));
2664 C := CC.First;
2665 while C /= null loop
2666 Write_Subtree (C);
2667 C := C.Next;
2668 end loop;
2669 end Write_Children;
2671 -------------------
2672 -- Write_Subtree --
2673 -------------------
2675 procedure Write_Subtree (Subtree : Tree_Node_Access) is
2676 begin
2677 Element_Type'Output (Stream, Subtree.Element);
2678 Write_Children (Subtree);
2679 end Write_Subtree;
2681 -- Start of processing for Write
2683 begin
2684 Count_Type'Write (Stream, Container.Count);
2686 if Container.Count = 0 then
2687 return;
2688 end if;
2690 Write_Children (Root_Node (Container));
2691 end Write;
2693 procedure Write
2694 (Stream : not null access Root_Stream_Type'Class;
2695 Position : Cursor)
2697 begin
2698 raise Program_Error with "attempt to write tree cursor to stream";
2699 end Write;
2701 procedure Write
2702 (Stream : not null access Root_Stream_Type'Class;
2703 Item : Reference_Type)
2705 begin
2706 raise Program_Error with "attempt to stream reference";
2707 end Write;
2709 procedure Write
2710 (Stream : not null access Root_Stream_Type'Class;
2711 Item : Constant_Reference_Type)
2713 begin
2714 raise Program_Error with "attempt to stream reference";
2715 end Write;
2717 end Ada.Containers.Multiway_Trees;