PR rtl-optimization/79386
[official-gcc.git] / gcc / ada / a-cimutr.adb
blob756b512c99096c1083c10a15081bd4c297ecc914
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- ADA.CONTAINERS.INDEFINITE_MULTIWAY_TREES --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2015, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Unchecked_Deallocation;
32 with System; use type System.Address;
34 package body Ada.Containers.Indefinite_Multiway_Trees is
36 pragma Warnings (Off, "variable ""Busy*"" is not referenced");
37 pragma Warnings (Off, "variable ""Lock*"" is not referenced");
38 -- See comment in Ada.Containers.Helpers
40 --------------------
41 -- Root_Iterator --
42 --------------------
44 type Root_Iterator is abstract new Limited_Controlled and
45 Tree_Iterator_Interfaces.Forward_Iterator with
46 record
47 Container : Tree_Access;
48 Subtree : Tree_Node_Access;
49 end record;
51 overriding procedure Finalize (Object : in out Root_Iterator);
53 -----------------------
54 -- Subtree_Iterator --
55 -----------------------
57 type Subtree_Iterator is new Root_Iterator with null record;
59 overriding function First (Object : Subtree_Iterator) return Cursor;
61 overriding function Next
62 (Object : Subtree_Iterator;
63 Position : Cursor) return Cursor;
65 ---------------------
66 -- Child_Iterator --
67 ---------------------
69 type Child_Iterator is new Root_Iterator and
70 Tree_Iterator_Interfaces.Reversible_Iterator with null record;
72 overriding function First (Object : Child_Iterator) return Cursor;
74 overriding function Next
75 (Object : Child_Iterator;
76 Position : Cursor) return Cursor;
78 overriding function Last (Object : Child_Iterator) return Cursor;
80 overriding function Previous
81 (Object : Child_Iterator;
82 Position : Cursor) return Cursor;
84 -----------------------
85 -- Local Subprograms --
86 -----------------------
88 function Root_Node (Container : Tree) return Tree_Node_Access;
90 procedure Free_Element is
91 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
93 procedure Deallocate_Node (X : in out 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 return Equal_Children (Root_Node (Left), Root_Node (Right));
170 end "=";
172 ------------
173 -- Adjust --
174 ------------
176 procedure Adjust (Container : in out Tree) is
177 Source : constant Children_Type := Container.Root.Children;
178 Source_Count : constant Count_Type := Container.Count;
179 Target_Count : Count_Type;
181 begin
182 -- We first restore the target container to its default-initialized
183 -- state, before we attempt any allocation, to ensure that invariants
184 -- are preserved in the event that the allocation fails.
186 Container.Root.Children := Children_Type'(others => null);
187 Zero_Counts (Container.TC);
188 Container.Count := 0;
190 -- Copy_Children returns a count of the number of nodes that it
191 -- allocates, but it works by incrementing the value that is passed in.
192 -- We must therefore initialize the count value before calling
193 -- Copy_Children.
195 Target_Count := 0;
197 -- Now we attempt the allocation of subtrees. The invariants are
198 -- satisfied even if the allocation fails.
200 Copy_Children (Source, Root_Node (Container), Target_Count);
201 pragma Assert (Target_Count = Source_Count);
203 Container.Count := Source_Count;
204 end Adjust;
206 -------------------
207 -- Ancestor_Find --
208 -------------------
210 function Ancestor_Find
211 (Position : Cursor;
212 Item : Element_Type) return Cursor
214 R, N : Tree_Node_Access;
216 begin
217 if Checks and then Position = No_Element then
218 raise Constraint_Error with "Position cursor has no element";
219 end if;
221 -- Commented-out pending ARG ruling. ???
223 -- if Checks and then
224 -- Position.Container /= Container'Unrestricted_Access
225 -- then
226 -- raise Program_Error with "Position cursor not in container";
227 -- end if;
229 -- AI-0136 says to raise PE if Position equals the root node. This does
230 -- not seem correct, as this value is just the limiting condition of the
231 -- search. For now we omit this check pending a ruling from the ARG.???
233 -- if Checks and then Is_Root (Position) then
234 -- raise Program_Error with "Position cursor designates root";
235 -- end if;
237 R := Root_Node (Position.Container.all);
238 N := Position.Node;
239 while N /= R loop
240 if N.Element.all = Item then
241 return Cursor'(Position.Container, N);
242 end if;
244 N := N.Parent;
245 end loop;
247 return No_Element;
248 end Ancestor_Find;
250 ------------------
251 -- Append_Child --
252 ------------------
254 procedure Append_Child
255 (Container : in out Tree;
256 Parent : Cursor;
257 New_Item : Element_Type;
258 Count : Count_Type := 1)
260 First, Last : Tree_Node_Access;
261 Element : Element_Access;
263 begin
264 if Checks and then Parent = No_Element then
265 raise Constraint_Error with "Parent cursor has no element";
266 end if;
268 if Checks and then Parent.Container /= Container'Unrestricted_Access then
269 raise Program_Error with "Parent cursor not in container";
270 end if;
272 if Count = 0 then
273 return;
274 end if;
276 TC_Check (Container.TC);
278 declare
279 -- The element allocator may need an accessibility check in the case
280 -- the actual type is class-wide or has access discriminants (see
281 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
282 -- allocator in the loop below, because the one in this block would
283 -- have failed already.
285 pragma Unsuppress (Accessibility_Check);
287 begin
288 Element := new Element_Type'(New_Item);
289 end;
291 First := new Tree_Node_Type'(Parent => Parent.Node,
292 Element => Element,
293 others => <>);
295 Last := First;
297 for J in Count_Type'(2) .. Count loop
299 -- Reclaim other nodes if Storage_Error. ???
301 Element := new Element_Type'(New_Item);
302 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
303 Prev => Last,
304 Element => Element,
305 others => <>);
307 Last := Last.Next;
308 end loop;
310 Insert_Subtree_List
311 (First => First,
312 Last => Last,
313 Parent => Parent.Node,
314 Before => null); -- null means "insert at end of list"
316 -- In order for operation Node_Count to complete in O(1) time, we cache
317 -- the count value. Here we increment the total count by the number of
318 -- nodes we just inserted.
320 Container.Count := Container.Count + Count;
321 end Append_Child;
323 ------------
324 -- Assign --
325 ------------
327 procedure Assign (Target : in out Tree; Source : Tree) is
328 Source_Count : constant Count_Type := Source.Count;
329 Target_Count : Count_Type;
331 begin
332 if Target'Address = Source'Address then
333 return;
334 end if;
336 Target.Clear; -- checks busy bit
338 -- Copy_Children returns the number of nodes that it allocates, but it
339 -- does this by incrementing the count value passed in, so we must
340 -- initialize the count before calling Copy_Children.
342 Target_Count := 0;
344 -- Note that Copy_Children inserts the newly-allocated children into
345 -- their parent list only after the allocation of all the children has
346 -- succeeded. This preserves invariants even if the allocation fails.
348 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
349 pragma Assert (Target_Count = Source_Count);
351 Target.Count := Source_Count;
352 end Assign;
354 -----------------
355 -- Child_Count --
356 -----------------
358 function Child_Count (Parent : Cursor) return Count_Type is
359 begin
360 if Parent = No_Element then
361 return 0;
362 else
363 return Child_Count (Parent.Node.Children);
364 end if;
365 end Child_Count;
367 function Child_Count (Children : Children_Type) return Count_Type is
368 Result : Count_Type;
369 Node : Tree_Node_Access;
371 begin
372 Result := 0;
373 Node := Children.First;
374 while Node /= null loop
375 Result := Result + 1;
376 Node := Node.Next;
377 end loop;
379 return Result;
380 end Child_Count;
382 -----------------
383 -- Child_Depth --
384 -----------------
386 function Child_Depth (Parent, Child : Cursor) return Count_Type is
387 Result : Count_Type;
388 N : Tree_Node_Access;
390 begin
391 if Checks and then Parent = No_Element then
392 raise Constraint_Error with "Parent cursor has no element";
393 end if;
395 if Checks and then Child = No_Element then
396 raise Constraint_Error with "Child cursor has no element";
397 end if;
399 if Checks and then Parent.Container /= Child.Container then
400 raise Program_Error with "Parent and Child in different containers";
401 end if;
403 Result := 0;
404 N := Child.Node;
405 while N /= Parent.Node loop
406 Result := Result + 1;
407 N := N.Parent;
409 if Checks and then N = null then
410 raise Program_Error with "Parent is not ancestor of Child";
411 end if;
412 end loop;
414 return Result;
415 end Child_Depth;
417 -----------
418 -- Clear --
419 -----------
421 procedure Clear (Container : in out Tree) is
422 Container_Count : Count_Type;
423 Children_Count : Count_Type;
425 begin
426 TC_Check (Container.TC);
428 -- We first set the container count to 0, in order to preserve
429 -- invariants in case the deallocation fails. (This works because
430 -- Deallocate_Children immediately removes the children from their
431 -- parent, and then does the actual deallocation.)
433 Container_Count := Container.Count;
434 Container.Count := 0;
436 -- Deallocate_Children returns the number of nodes that it deallocates,
437 -- but it does this by incrementing the count value that is passed in,
438 -- so we must first initialize the count return value before calling it.
440 Children_Count := 0;
442 -- See comment above. Deallocate_Children immediately removes the
443 -- children list from their parent node (here, the root of the tree),
444 -- and only after that does it attempt the actual deallocation. So even
445 -- if the deallocation fails, the representation invariants
447 Deallocate_Children (Root_Node (Container), Children_Count);
448 pragma Assert (Children_Count = Container_Count);
449 end Clear;
451 ------------------------
452 -- Constant_Reference --
453 ------------------------
455 function Constant_Reference
456 (Container : aliased Tree;
457 Position : Cursor) return Constant_Reference_Type
459 begin
460 if Checks and then Position.Container = null then
461 raise Constraint_Error with
462 "Position cursor has no element";
463 end if;
465 if Checks and then Position.Container /= Container'Unrestricted_Access
466 then
467 raise Program_Error with
468 "Position cursor designates wrong container";
469 end if;
471 if Checks and then Position.Node = Root_Node (Container) then
472 raise Program_Error with "Position cursor designates root";
473 end if;
475 if Checks and then Position.Node.Element = null then
476 raise Program_Error with "Node has no element";
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 TC : constant Tamper_Counts_Access :=
485 Container.TC'Unrestricted_Access;
486 begin
487 return R : constant Constant_Reference_Type :=
488 (Element => Position.Node.Element.all'Access,
489 Control => (Controlled with TC))
491 Lock (TC.all);
492 end return;
493 end;
494 end Constant_Reference;
496 --------------
497 -- Contains --
498 --------------
500 function Contains
501 (Container : Tree;
502 Item : Element_Type) return Boolean
504 begin
505 return Find (Container, Item) /= No_Element;
506 end Contains;
508 ----------
509 -- Copy --
510 ----------
512 function Copy (Source : Tree) return Tree is
513 begin
514 return Target : Tree do
515 Copy_Children
516 (Source => Source.Root.Children,
517 Parent => Root_Node (Target),
518 Count => Target.Count);
520 pragma Assert (Target.Count = Source.Count);
521 end return;
522 end Copy;
524 -------------------
525 -- Copy_Children --
526 -------------------
528 procedure Copy_Children
529 (Source : Children_Type;
530 Parent : Tree_Node_Access;
531 Count : in out Count_Type)
533 pragma Assert (Parent /= null);
534 pragma Assert (Parent.Children.First = null);
535 pragma Assert (Parent.Children.Last = null);
537 CC : Children_Type;
538 C : Tree_Node_Access;
540 begin
541 -- We special-case the first allocation, in order to establish the
542 -- representation invariants for type Children_Type.
544 C := Source.First;
546 if C = null then
547 return;
548 end if;
550 Copy_Subtree
551 (Source => C,
552 Parent => Parent,
553 Target => CC.First,
554 Count => Count);
556 CC.Last := CC.First;
558 -- The representation invariants for the Children_Type list have been
559 -- established, so we can now copy the remaining children of Source.
561 C := C.Next;
562 while C /= null loop
563 Copy_Subtree
564 (Source => C,
565 Parent => Parent,
566 Target => CC.Last.Next,
567 Count => Count);
569 CC.Last.Next.Prev := CC.Last;
570 CC.Last := CC.Last.Next;
572 C := C.Next;
573 end loop;
575 -- We add the newly-allocated children to their parent list only after
576 -- the allocation has succeeded, in order to preserve invariants of the
577 -- parent.
579 Parent.Children := CC;
580 end Copy_Children;
582 ------------------
583 -- Copy_Subtree --
584 ------------------
586 procedure Copy_Subtree
587 (Target : in out Tree;
588 Parent : Cursor;
589 Before : Cursor;
590 Source : Cursor)
592 Target_Subtree : Tree_Node_Access;
593 Target_Count : Count_Type;
595 begin
596 if Checks and then Parent = No_Element then
597 raise Constraint_Error with "Parent cursor has no element";
598 end if;
600 if Checks and then Parent.Container /= Target'Unrestricted_Access then
601 raise Program_Error with "Parent cursor not in container";
602 end if;
604 if Before /= No_Element then
605 if Checks and then Before.Container /= Target'Unrestricted_Access then
606 raise Program_Error with "Before cursor not in container";
607 end if;
609 if Checks and then Before.Node.Parent /= Parent.Node then
610 raise Constraint_Error with "Before cursor not child of Parent";
611 end if;
612 end if;
614 if Source = No_Element then
615 return;
616 end if;
618 if Checks and then Is_Root (Source) then
619 raise Constraint_Error with "Source cursor designates root";
620 end if;
622 -- Copy_Subtree returns a count of the number of nodes that it
623 -- allocates, but it works by incrementing the value that is passed in.
624 -- We must therefore initialize the count value before calling
625 -- Copy_Subtree.
627 Target_Count := 0;
629 Copy_Subtree
630 (Source => Source.Node,
631 Parent => Parent.Node,
632 Target => Target_Subtree,
633 Count => Target_Count);
635 pragma Assert (Target_Subtree /= null);
636 pragma Assert (Target_Subtree.Parent = Parent.Node);
637 pragma Assert (Target_Count >= 1);
639 Insert_Subtree_Node
640 (Subtree => Target_Subtree,
641 Parent => Parent.Node,
642 Before => Before.Node);
644 -- In order for operation Node_Count to complete in O(1) time, we cache
645 -- the count value. Here we increment the total count by the number of
646 -- nodes we just inserted.
648 Target.Count := Target.Count + Target_Count;
649 end Copy_Subtree;
651 procedure Copy_Subtree
652 (Source : Tree_Node_Access;
653 Parent : Tree_Node_Access;
654 Target : out Tree_Node_Access;
655 Count : in out Count_Type)
657 E : constant Element_Access := new Element_Type'(Source.Element.all);
659 begin
660 Target := new Tree_Node_Type'(Element => E,
661 Parent => Parent,
662 others => <>);
664 Count := Count + 1;
666 Copy_Children
667 (Source => Source.Children,
668 Parent => Target,
669 Count => Count);
670 end Copy_Subtree;
672 -------------------------
673 -- Deallocate_Children --
674 -------------------------
676 procedure Deallocate_Children
677 (Subtree : Tree_Node_Access;
678 Count : in out Count_Type)
680 pragma Assert (Subtree /= null);
682 CC : Children_Type := Subtree.Children;
683 C : Tree_Node_Access;
685 begin
686 -- We immediately remove the children from their parent, in order to
687 -- preserve invariants in case the deallocation fails.
689 Subtree.Children := Children_Type'(others => null);
691 while CC.First /= null loop
692 C := CC.First;
693 CC.First := C.Next;
695 Deallocate_Subtree (C, Count);
696 end loop;
697 end Deallocate_Children;
699 ---------------------
700 -- Deallocate_Node --
701 ---------------------
703 procedure Deallocate_Node (X : in out Tree_Node_Access) is
704 procedure Free_Node is
705 new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access);
707 -- Start of processing for Deallocate_Node
709 begin
710 if X /= null then
711 Free_Element (X.Element);
712 Free_Node (X);
713 end if;
714 end Deallocate_Node;
716 ------------------------
717 -- Deallocate_Subtree --
718 ------------------------
720 procedure Deallocate_Subtree
721 (Subtree : in out Tree_Node_Access;
722 Count : in out Count_Type)
724 begin
725 Deallocate_Children (Subtree, Count);
726 Deallocate_Node (Subtree);
727 Count := Count + 1;
728 end Deallocate_Subtree;
730 ---------------------
731 -- Delete_Children --
732 ---------------------
734 procedure Delete_Children
735 (Container : in out Tree;
736 Parent : Cursor)
738 Count : Count_Type;
740 begin
741 if Checks and then Parent = No_Element then
742 raise Constraint_Error with "Parent cursor has no element";
743 end if;
745 if Checks and then Parent.Container /= Container'Unrestricted_Access then
746 raise Program_Error with "Parent cursor not in container";
747 end if;
749 TC_Check (Container.TC);
751 -- Deallocate_Children returns a count of the number of nodes
752 -- that it deallocates, but it works by incrementing the
753 -- value that is passed in. We must therefore initialize
754 -- the count value before calling Deallocate_Children.
756 Count := 0;
758 Deallocate_Children (Parent.Node, Count);
759 pragma Assert (Count <= Container.Count);
761 Container.Count := Container.Count - Count;
762 end Delete_Children;
764 -----------------
765 -- Delete_Leaf --
766 -----------------
768 procedure Delete_Leaf
769 (Container : in out Tree;
770 Position : in out Cursor)
772 X : Tree_Node_Access;
774 begin
775 if Checks and then Position = No_Element then
776 raise Constraint_Error with "Position cursor has no element";
777 end if;
779 if Checks and then Position.Container /= Container'Unrestricted_Access
780 then
781 raise Program_Error with "Position cursor not in container";
782 end if;
784 if Checks and then Is_Root (Position) then
785 raise Program_Error with "Position cursor designates root";
786 end if;
788 if Checks and then not Is_Leaf (Position) then
789 raise Constraint_Error with "Position cursor does not designate leaf";
790 end if;
792 TC_Check (Container.TC);
794 X := Position.Node;
795 Position := No_Element;
797 -- Restore represention invariants before attempting the actual
798 -- deallocation.
800 Remove_Subtree (X);
801 Container.Count := Container.Count - 1;
803 -- It is now safe to attempt the deallocation. This leaf node has been
804 -- disassociated from the tree, so even if the deallocation fails,
805 -- representation invariants will remain satisfied.
807 Deallocate_Node (X);
808 end Delete_Leaf;
810 --------------------
811 -- Delete_Subtree --
812 --------------------
814 procedure Delete_Subtree
815 (Container : in out Tree;
816 Position : in out Cursor)
818 X : Tree_Node_Access;
819 Count : Count_Type;
821 begin
822 if Checks and then Position = No_Element then
823 raise Constraint_Error with "Position cursor has no element";
824 end if;
826 if Checks and then Position.Container /= Container'Unrestricted_Access
827 then
828 raise Program_Error with "Position cursor not in container";
829 end if;
831 if Checks and then Is_Root (Position) then
832 raise Program_Error with "Position cursor designates root";
833 end if;
835 TC_Check (Container.TC);
837 X := Position.Node;
838 Position := No_Element;
840 -- Here is one case where a deallocation failure can result in the
841 -- violation of a representation invariant. We disassociate the subtree
842 -- from the tree now, but we only decrement the total node count after
843 -- we attempt the deallocation. However, if the deallocation fails, the
844 -- total node count will not get decremented.
846 -- One way around this dilemma is to count the nodes in the subtree
847 -- before attempt to delete the subtree, but that is an O(n) operation,
848 -- so it does not seem worth it.
850 -- Perhaps this is much ado about nothing, since the only way
851 -- deallocation can fail is if Controlled Finalization fails: this
852 -- propagates Program_Error so all bets are off anyway. ???
854 Remove_Subtree (X);
856 -- Deallocate_Subtree returns a count of the number of nodes that it
857 -- deallocates, but it works by incrementing the value that is passed
858 -- in. We must therefore initialize the count value before calling
859 -- Deallocate_Subtree.
861 Count := 0;
863 Deallocate_Subtree (X, Count);
864 pragma Assert (Count <= Container.Count);
866 -- See comments above. We would prefer to do this sooner, but there's no
867 -- way to satisfy that goal without an potentially severe execution
868 -- penalty.
870 Container.Count := Container.Count - Count;
871 end Delete_Subtree;
873 -----------
874 -- Depth --
875 -----------
877 function Depth (Position : Cursor) return Count_Type is
878 Result : Count_Type;
879 N : Tree_Node_Access;
881 begin
882 Result := 0;
883 N := Position.Node;
884 while N /= null loop
885 N := N.Parent;
886 Result := Result + 1;
887 end loop;
889 return Result;
890 end Depth;
892 -------------
893 -- Element --
894 -------------
896 function Element (Position : Cursor) return Element_Type is
897 begin
898 if Checks and then Position.Container = null then
899 raise Constraint_Error with "Position cursor has no element";
900 end if;
902 if Checks and then Position.Node = Root_Node (Position.Container.all)
903 then
904 raise Program_Error with "Position cursor designates root";
905 end if;
907 return Position.Node.Element.all;
908 end Element;
910 --------------------
911 -- Equal_Children --
912 --------------------
914 function Equal_Children
915 (Left_Subtree : Tree_Node_Access;
916 Right_Subtree : Tree_Node_Access) return Boolean
918 Left_Children : Children_Type renames Left_Subtree.Children;
919 Right_Children : Children_Type renames Right_Subtree.Children;
921 L, R : Tree_Node_Access;
923 begin
924 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
925 return False;
926 end if;
928 L := Left_Children.First;
929 R := Right_Children.First;
930 while L /= null loop
931 if not Equal_Subtree (L, R) then
932 return False;
933 end if;
935 L := L.Next;
936 R := R.Next;
937 end loop;
939 return True;
940 end Equal_Children;
942 -------------------
943 -- Equal_Subtree --
944 -------------------
946 function Equal_Subtree
947 (Left_Position : Cursor;
948 Right_Position : Cursor) return Boolean
950 begin
951 if Checks and then Left_Position = No_Element then
952 raise Constraint_Error with "Left cursor has no element";
953 end if;
955 if Checks and then Right_Position = No_Element then
956 raise Constraint_Error with "Right cursor has no element";
957 end if;
959 if Left_Position = Right_Position then
960 return True;
961 end if;
963 if Is_Root (Left_Position) then
964 if not Is_Root (Right_Position) then
965 return False;
966 end if;
968 return Equal_Children (Left_Position.Node, Right_Position.Node);
969 end if;
971 if Is_Root (Right_Position) then
972 return False;
973 end if;
975 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
976 end Equal_Subtree;
978 function Equal_Subtree
979 (Left_Subtree : Tree_Node_Access;
980 Right_Subtree : Tree_Node_Access) return Boolean
982 begin
983 if Left_Subtree.Element.all /= Right_Subtree.Element.all then
984 return False;
985 end if;
987 return Equal_Children (Left_Subtree, Right_Subtree);
988 end Equal_Subtree;
990 --------------
991 -- Finalize --
992 --------------
994 procedure Finalize (Object : in out Root_Iterator) is
995 begin
996 Unbusy (Object.Container.TC);
997 end Finalize;
999 ----------
1000 -- Find --
1001 ----------
1003 function Find
1004 (Container : Tree;
1005 Item : Element_Type) return Cursor
1007 N : constant Tree_Node_Access :=
1008 Find_In_Children (Root_Node (Container), Item);
1010 begin
1011 if N = null then
1012 return No_Element;
1013 end if;
1015 return Cursor'(Container'Unrestricted_Access, N);
1016 end Find;
1018 -----------
1019 -- First --
1020 -----------
1022 overriding function First (Object : Subtree_Iterator) return Cursor is
1023 begin
1024 if Object.Subtree = Root_Node (Object.Container.all) then
1025 return First_Child (Root (Object.Container.all));
1026 else
1027 return Cursor'(Object.Container, Object.Subtree);
1028 end if;
1029 end First;
1031 overriding function First (Object : Child_Iterator) return Cursor is
1032 begin
1033 return First_Child (Cursor'(Object.Container, Object.Subtree));
1034 end First;
1036 -----------------
1037 -- First_Child --
1038 -----------------
1040 function First_Child (Parent : Cursor) return Cursor is
1041 Node : Tree_Node_Access;
1043 begin
1044 if Checks and then Parent = No_Element then
1045 raise Constraint_Error with "Parent cursor has no element";
1046 end if;
1048 Node := Parent.Node.Children.First;
1050 if Node = null then
1051 return No_Element;
1052 end if;
1054 return Cursor'(Parent.Container, Node);
1055 end First_Child;
1057 -------------------------
1058 -- First_Child_Element --
1059 -------------------------
1061 function First_Child_Element (Parent : Cursor) return Element_Type is
1062 begin
1063 return Element (First_Child (Parent));
1064 end First_Child_Element;
1066 ----------------------
1067 -- Find_In_Children --
1068 ----------------------
1070 function Find_In_Children
1071 (Subtree : Tree_Node_Access;
1072 Item : Element_Type) return Tree_Node_Access
1074 N, Result : Tree_Node_Access;
1076 begin
1077 N := Subtree.Children.First;
1078 while N /= null loop
1079 Result := Find_In_Subtree (N, Item);
1081 if Result /= null then
1082 return Result;
1083 end if;
1085 N := N.Next;
1086 end loop;
1088 return null;
1089 end Find_In_Children;
1091 ---------------------
1092 -- Find_In_Subtree --
1093 ---------------------
1095 function Find_In_Subtree
1096 (Position : Cursor;
1097 Item : Element_Type) return Cursor
1099 Result : Tree_Node_Access;
1101 begin
1102 if Checks and then Position = No_Element then
1103 raise Constraint_Error with "Position cursor has no element";
1104 end if;
1106 -- Commented-out pending ruling from ARG. ???
1108 -- if Checks and then
1109 -- Position.Container /= Container'Unrestricted_Access
1110 -- then
1111 -- raise Program_Error with "Position cursor not in container";
1112 -- end if;
1114 if Is_Root (Position) then
1115 Result := Find_In_Children (Position.Node, Item);
1117 else
1118 Result := Find_In_Subtree (Position.Node, Item);
1119 end if;
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.all = Item then
1134 return Subtree;
1135 end if;
1137 return Find_In_Children (Subtree, Item);
1138 end Find_In_Subtree;
1140 ------------------------
1141 -- Get_Element_Access --
1142 ------------------------
1144 function Get_Element_Access
1145 (Position : Cursor) return not null Element_Access is
1146 begin
1147 return Position.Node.Element;
1148 end Get_Element_Access;
1150 -----------------
1151 -- Has_Element --
1152 -----------------
1154 function Has_Element (Position : Cursor) return Boolean is
1155 begin
1156 if Position = No_Element then
1157 return False;
1158 end if;
1160 return Position.Node.Parent /= null;
1161 end Has_Element;
1163 ------------------
1164 -- Insert_Child --
1165 ------------------
1167 procedure Insert_Child
1168 (Container : in out Tree;
1169 Parent : Cursor;
1170 Before : Cursor;
1171 New_Item : Element_Type;
1172 Count : Count_Type := 1)
1174 Position : Cursor;
1175 pragma Unreferenced (Position);
1177 begin
1178 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1179 end Insert_Child;
1181 procedure Insert_Child
1182 (Container : in out Tree;
1183 Parent : Cursor;
1184 Before : Cursor;
1185 New_Item : Element_Type;
1186 Position : out Cursor;
1187 Count : Count_Type := 1)
1189 First : Tree_Node_Access;
1190 Last : Tree_Node_Access;
1191 Element : Element_Access;
1193 begin
1194 if Checks and then Parent = No_Element then
1195 raise Constraint_Error with "Parent cursor has no element";
1196 end if;
1198 if Checks and then Parent.Container /= Container'Unrestricted_Access then
1199 raise Program_Error with "Parent cursor not in container";
1200 end if;
1202 if Before /= No_Element then
1203 if Checks and then Before.Container /= Container'Unrestricted_Access
1204 then
1205 raise Program_Error with "Before cursor not in container";
1206 end if;
1208 if Checks and then Before.Node.Parent /= Parent.Node then
1209 raise Constraint_Error with "Parent cursor not parent of Before";
1210 end if;
1211 end if;
1213 if Count = 0 then
1214 Position := No_Element; -- Need ruling from ARG ???
1215 return;
1216 end if;
1218 TC_Check (Container.TC);
1220 declare
1221 -- The element allocator may need an accessibility check in the case
1222 -- the actual type is class-wide or has access discriminants (see
1223 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
1224 -- allocator in the loop below, because the one in this block would
1225 -- have failed already.
1227 pragma Unsuppress (Accessibility_Check);
1229 begin
1230 Element := new Element_Type'(New_Item);
1231 end;
1233 First := new Tree_Node_Type'(Parent => Parent.Node,
1234 Element => Element,
1235 others => <>);
1237 Last := First;
1238 for J in Count_Type'(2) .. Count loop
1240 -- Reclaim other nodes if Storage_Error. ???
1242 Element := new Element_Type'(New_Item);
1243 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1244 Prev => Last,
1245 Element => Element,
1246 others => <>);
1248 Last := Last.Next;
1249 end loop;
1251 Insert_Subtree_List
1252 (First => First,
1253 Last => Last,
1254 Parent => Parent.Node,
1255 Before => Before.Node);
1257 -- In order for operation Node_Count to complete in O(1) time, we cache
1258 -- the count value. Here we increment the total count by the number of
1259 -- nodes we just inserted.
1261 Container.Count := Container.Count + Count;
1263 Position := Cursor'(Parent.Container, First);
1264 end Insert_Child;
1266 -------------------------
1267 -- Insert_Subtree_List --
1268 -------------------------
1270 procedure Insert_Subtree_List
1271 (First : Tree_Node_Access;
1272 Last : Tree_Node_Access;
1273 Parent : Tree_Node_Access;
1274 Before : Tree_Node_Access)
1276 pragma Assert (Parent /= null);
1277 C : Children_Type renames Parent.Children;
1279 begin
1280 -- This is a simple utility operation to insert a list of nodes (from
1281 -- First..Last) as children of Parent. The Before node specifies where
1282 -- the new children should be inserted relative to the existing
1283 -- children.
1285 if First = null then
1286 pragma Assert (Last = null);
1287 return;
1288 end if;
1290 pragma Assert (Last /= null);
1291 pragma Assert (Before = null or else Before.Parent = Parent);
1293 if C.First = null then
1294 C.First := First;
1295 C.First.Prev := null;
1296 C.Last := Last;
1297 C.Last.Next := null;
1299 elsif Before = null then -- means "insert after existing nodes"
1300 C.Last.Next := First;
1301 First.Prev := C.Last;
1302 C.Last := Last;
1303 C.Last.Next := null;
1305 elsif Before = C.First then
1306 Last.Next := C.First;
1307 C.First.Prev := Last;
1308 C.First := First;
1309 C.First.Prev := null;
1311 else
1312 Before.Prev.Next := First;
1313 First.Prev := Before.Prev;
1314 Last.Next := Before;
1315 Before.Prev := Last;
1316 end if;
1317 end Insert_Subtree_List;
1319 -------------------------
1320 -- Insert_Subtree_Node --
1321 -------------------------
1323 procedure Insert_Subtree_Node
1324 (Subtree : Tree_Node_Access;
1325 Parent : Tree_Node_Access;
1326 Before : Tree_Node_Access)
1328 begin
1329 -- This is a simple wrapper operation to insert a single child into the
1330 -- Parent's children list.
1332 Insert_Subtree_List
1333 (First => Subtree,
1334 Last => Subtree,
1335 Parent => Parent,
1336 Before => Before);
1337 end Insert_Subtree_Node;
1339 --------------
1340 -- Is_Empty --
1341 --------------
1343 function Is_Empty (Container : Tree) return Boolean is
1344 begin
1345 return Container.Root.Children.First = null;
1346 end Is_Empty;
1348 -------------
1349 -- Is_Leaf --
1350 -------------
1352 function Is_Leaf (Position : Cursor) return Boolean is
1353 begin
1354 if Position = No_Element then
1355 return False;
1356 end if;
1358 return Position.Node.Children.First = null;
1359 end Is_Leaf;
1361 ------------------
1362 -- Is_Reachable --
1363 ------------------
1365 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1366 pragma Assert (From /= null);
1367 pragma Assert (To /= null);
1369 N : Tree_Node_Access;
1371 begin
1372 N := From;
1373 while N /= null loop
1374 if N = To then
1375 return True;
1376 end if;
1378 N := N.Parent;
1379 end loop;
1381 return False;
1382 end Is_Reachable;
1384 -------------
1385 -- Is_Root --
1386 -------------
1388 function Is_Root (Position : Cursor) return Boolean is
1389 begin
1390 if Position.Container = null then
1391 return False;
1392 end if;
1394 return Position = Root (Position.Container.all);
1395 end Is_Root;
1397 -------------
1398 -- Iterate --
1399 -------------
1401 procedure Iterate
1402 (Container : Tree;
1403 Process : not null access procedure (Position : Cursor))
1405 Busy : With_Busy (Container.TC'Unrestricted_Access);
1406 begin
1407 Iterate_Children
1408 (Container => Container'Unrestricted_Access,
1409 Subtree => Root_Node (Container),
1410 Process => Process);
1411 end Iterate;
1413 function Iterate (Container : Tree)
1414 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1416 begin
1417 return Iterate_Subtree (Root (Container));
1418 end Iterate;
1420 ----------------------
1421 -- Iterate_Children --
1422 ----------------------
1424 procedure Iterate_Children
1425 (Parent : Cursor;
1426 Process : not null access procedure (Position : Cursor))
1428 C : Tree_Node_Access;
1429 Busy : With_Busy (Parent.Container.TC'Unrestricted_Access);
1430 begin
1431 if Checks and then Parent = No_Element then
1432 raise Constraint_Error with "Parent cursor has no element";
1433 end if;
1435 C := Parent.Node.Children.First;
1436 while C /= null loop
1437 Process (Position => Cursor'(Parent.Container, Node => C));
1438 C := C.Next;
1439 end loop;
1440 end Iterate_Children;
1442 procedure Iterate_Children
1443 (Container : Tree_Access;
1444 Subtree : Tree_Node_Access;
1445 Process : not null access procedure (Position : Cursor))
1447 Node : Tree_Node_Access;
1449 begin
1450 -- This is a helper function to recursively iterate over all the nodes
1451 -- in a subtree, in depth-first fashion. This particular helper just
1452 -- visits the children of this subtree, not the root of the subtree node
1453 -- itself. This is useful when starting from the ultimate root of the
1454 -- entire tree (see Iterate), as that root does not have an element.
1456 Node := Subtree.Children.First;
1457 while Node /= null loop
1458 Iterate_Subtree (Container, Node, Process);
1459 Node := Node.Next;
1460 end loop;
1461 end Iterate_Children;
1463 function Iterate_Children
1464 (Container : Tree;
1465 Parent : Cursor)
1466 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1468 C : constant Tree_Access := Container'Unrestricted_Access;
1469 begin
1470 if Checks and then Parent = No_Element then
1471 raise Constraint_Error with "Parent cursor has no element";
1472 end if;
1474 if Checks and then Parent.Container /= C then
1475 raise Program_Error with "Parent cursor not in container";
1476 end if;
1478 return It : constant Child_Iterator :=
1479 Child_Iterator'(Limited_Controlled with
1480 Container => C,
1481 Subtree => Parent.Node)
1483 Busy (C.TC);
1484 end return;
1485 end Iterate_Children;
1487 ---------------------
1488 -- Iterate_Subtree --
1489 ---------------------
1491 function Iterate_Subtree
1492 (Position : Cursor)
1493 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1495 C : constant Tree_Access := Position.Container;
1496 begin
1497 if Checks and then Position = No_Element then
1498 raise Constraint_Error with "Position cursor has no element";
1499 end if;
1501 -- Implement Vet for multiway trees???
1502 -- pragma Assert (Vet (Position), "bad subtree cursor");
1504 return It : constant Subtree_Iterator :=
1505 (Limited_Controlled with
1506 Container => Position.Container,
1507 Subtree => Position.Node)
1509 Busy (C.TC);
1510 end return;
1511 end Iterate_Subtree;
1513 procedure Iterate_Subtree
1514 (Position : Cursor;
1515 Process : not null access procedure (Position : Cursor))
1517 Busy : With_Busy (Position.Container.TC'Unrestricted_Access);
1518 begin
1519 if Checks and then Position = No_Element then
1520 raise Constraint_Error with "Position cursor has no element";
1521 end if;
1523 if Is_Root (Position) then
1524 Iterate_Children (Position.Container, Position.Node, Process);
1525 else
1526 Iterate_Subtree (Position.Container, Position.Node, Process);
1527 end if;
1528 end Iterate_Subtree;
1530 procedure Iterate_Subtree
1531 (Container : Tree_Access;
1532 Subtree : Tree_Node_Access;
1533 Process : not null access procedure (Position : Cursor))
1535 begin
1536 -- This is a helper function to recursively iterate over all the nodes
1537 -- in a subtree, in depth-first fashion. It first visits the root of the
1538 -- subtree, then visits its children.
1540 Process (Cursor'(Container, Subtree));
1541 Iterate_Children (Container, Subtree, Process);
1542 end Iterate_Subtree;
1544 ----------
1545 -- Last --
1546 ----------
1548 overriding function Last (Object : Child_Iterator) return Cursor is
1549 begin
1550 return Last_Child (Cursor'(Object.Container, Object.Subtree));
1551 end Last;
1553 ----------------
1554 -- Last_Child --
1555 ----------------
1557 function Last_Child (Parent : Cursor) return Cursor is
1558 Node : Tree_Node_Access;
1560 begin
1561 if Checks and then Parent = No_Element then
1562 raise Constraint_Error with "Parent cursor has no element";
1563 end if;
1565 Node := Parent.Node.Children.Last;
1567 if Node = null then
1568 return No_Element;
1569 end if;
1571 return (Parent.Container, Node);
1572 end Last_Child;
1574 ------------------------
1575 -- Last_Child_Element --
1576 ------------------------
1578 function Last_Child_Element (Parent : Cursor) return Element_Type is
1579 begin
1580 return Element (Last_Child (Parent));
1581 end Last_Child_Element;
1583 ----------
1584 -- Move --
1585 ----------
1587 procedure Move (Target : in out Tree; Source : in out Tree) is
1588 Node : Tree_Node_Access;
1590 begin
1591 if Target'Address = Source'Address then
1592 return;
1593 end if;
1595 TC_Check (Source.TC);
1597 Target.Clear; -- checks busy bit
1599 Target.Root.Children := Source.Root.Children;
1600 Source.Root.Children := Children_Type'(others => null);
1602 Node := Target.Root.Children.First;
1603 while Node /= null loop
1604 Node.Parent := Root_Node (Target);
1605 Node := Node.Next;
1606 end loop;
1608 Target.Count := Source.Count;
1609 Source.Count := 0;
1610 end Move;
1612 ----------
1613 -- Next --
1614 ----------
1616 function Next
1617 (Object : Subtree_Iterator;
1618 Position : Cursor) return Cursor
1620 Node : Tree_Node_Access;
1622 begin
1623 if Position.Container = null then
1624 return No_Element;
1625 end if;
1627 if Checks and then Position.Container /= Object.Container then
1628 raise Program_Error with
1629 "Position cursor of Next designates wrong tree";
1630 end if;
1632 Node := Position.Node;
1634 if Node.Children.First /= null then
1635 return Cursor'(Object.Container, Node.Children.First);
1636 end if;
1638 while Node /= Object.Subtree loop
1639 if Node.Next /= null then
1640 return Cursor'(Object.Container, Node.Next);
1641 end if;
1643 Node := Node.Parent;
1644 end loop;
1646 return No_Element;
1647 end Next;
1649 function Next
1650 (Object : Child_Iterator;
1651 Position : Cursor) return Cursor
1653 begin
1654 if Position.Container = null then
1655 return No_Element;
1656 end if;
1658 if Checks and then Position.Container /= Object.Container then
1659 raise Program_Error with
1660 "Position cursor of Next designates wrong tree";
1661 end if;
1663 return Next_Sibling (Position);
1664 end Next;
1666 ------------------
1667 -- Next_Sibling --
1668 ------------------
1670 function Next_Sibling (Position : Cursor) return Cursor is
1671 begin
1672 if Position = No_Element then
1673 return No_Element;
1674 end if;
1676 if Position.Node.Next = null then
1677 return No_Element;
1678 end if;
1680 return Cursor'(Position.Container, Position.Node.Next);
1681 end Next_Sibling;
1683 procedure Next_Sibling (Position : in out Cursor) is
1684 begin
1685 Position := Next_Sibling (Position);
1686 end Next_Sibling;
1688 ----------------
1689 -- Node_Count --
1690 ----------------
1692 function Node_Count (Container : Tree) return Count_Type is
1693 begin
1694 -- Container.Count is the number of nodes we have actually allocated. We
1695 -- cache the value specifically so this Node_Count operation can execute
1696 -- in O(1) time, which makes it behave similarly to how the Length
1697 -- selector function behaves for other containers.
1699 -- The cached node count value only describes the nodes we have
1700 -- allocated; the root node itself is not included in that count. The
1701 -- Node_Count operation returns a value that includes the root node
1702 -- (because the RM says so), so we must add 1 to our cached value.
1704 return 1 + Container.Count;
1705 end Node_Count;
1707 ------------
1708 -- Parent --
1709 ------------
1711 function Parent (Position : Cursor) return Cursor is
1712 begin
1713 if Position = No_Element then
1714 return No_Element;
1715 end if;
1717 if Position.Node.Parent = null then
1718 return No_Element;
1719 end if;
1721 return Cursor'(Position.Container, Position.Node.Parent);
1722 end Parent;
1724 -------------------
1725 -- Prepent_Child --
1726 -------------------
1728 procedure Prepend_Child
1729 (Container : in out Tree;
1730 Parent : Cursor;
1731 New_Item : Element_Type;
1732 Count : Count_Type := 1)
1734 First, Last : Tree_Node_Access;
1735 Element : Element_Access;
1737 begin
1738 if Checks and then Parent = No_Element then
1739 raise Constraint_Error with "Parent cursor has no element";
1740 end if;
1742 if Checks and then Parent.Container /= Container'Unrestricted_Access then
1743 raise Program_Error with "Parent cursor not in container";
1744 end if;
1746 if Count = 0 then
1747 return;
1748 end if;
1750 TC_Check (Container.TC);
1752 declare
1753 -- The element allocator may need an accessibility check in the case
1754 -- the actual type is class-wide or has access discriminants (see
1755 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
1756 -- allocator in the loop below, because the one in this block would
1757 -- have failed already.
1759 pragma Unsuppress (Accessibility_Check);
1761 begin
1762 Element := new Element_Type'(New_Item);
1763 end;
1765 First := new Tree_Node_Type'(Parent => Parent.Node,
1766 Element => Element,
1767 others => <>);
1769 Last := First;
1771 for J in Count_Type'(2) .. Count loop
1773 -- Reclaim other nodes if Storage_Error. ???
1775 Element := new Element_Type'(New_Item);
1776 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1777 Prev => Last,
1778 Element => Element,
1779 others => <>);
1781 Last := Last.Next;
1782 end loop;
1784 Insert_Subtree_List
1785 (First => First,
1786 Last => Last,
1787 Parent => Parent.Node,
1788 Before => Parent.Node.Children.First);
1790 -- In order for operation Node_Count to complete in O(1) time, we cache
1791 -- the count value. Here we increment the total count by the number of
1792 -- nodes we just inserted.
1794 Container.Count := Container.Count + Count;
1795 end Prepend_Child;
1797 --------------
1798 -- Previous --
1799 --------------
1801 overriding function Previous
1802 (Object : Child_Iterator;
1803 Position : Cursor) return Cursor
1805 begin
1806 if Position.Container = null then
1807 return No_Element;
1808 end if;
1810 if Checks and then Position.Container /= Object.Container then
1811 raise Program_Error with
1812 "Position cursor of Previous designates wrong tree";
1813 end if;
1815 return Previous_Sibling (Position);
1816 end Previous;
1818 ----------------------
1819 -- Previous_Sibling --
1820 ----------------------
1822 function Previous_Sibling (Position : Cursor) return Cursor is
1823 begin
1824 if Position = No_Element then
1825 return No_Element;
1826 end if;
1828 if Position.Node.Prev = null then
1829 return No_Element;
1830 end if;
1832 return Cursor'(Position.Container, Position.Node.Prev);
1833 end Previous_Sibling;
1835 procedure Previous_Sibling (Position : in out Cursor) is
1836 begin
1837 Position := Previous_Sibling (Position);
1838 end Previous_Sibling;
1840 ----------------------
1841 -- Pseudo_Reference --
1842 ----------------------
1844 function Pseudo_Reference
1845 (Container : aliased Tree'Class) return Reference_Control_Type
1847 TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
1848 begin
1849 return R : constant Reference_Control_Type := (Controlled with TC) do
1850 Lock (TC.all);
1851 end return;
1852 end Pseudo_Reference;
1854 -------------------
1855 -- Query_Element --
1856 -------------------
1858 procedure Query_Element
1859 (Position : Cursor;
1860 Process : not null access procedure (Element : Element_Type))
1862 T : Tree renames Position.Container.all'Unrestricted_Access.all;
1863 Lock : With_Lock (T.TC'Unrestricted_Access);
1864 begin
1865 if Checks and then Position = No_Element then
1866 raise Constraint_Error with "Position cursor has no element";
1867 end if;
1869 if Checks and then Is_Root (Position) then
1870 raise Program_Error with "Position cursor designates root";
1871 end if;
1873 Process (Position.Node.Element.all);
1874 end Query_Element;
1876 ----------
1877 -- Read --
1878 ----------
1880 procedure Read
1881 (Stream : not null access Root_Stream_Type'Class;
1882 Container : out Tree)
1884 procedure Read_Children (Subtree : Tree_Node_Access);
1886 function Read_Subtree
1887 (Parent : Tree_Node_Access) return Tree_Node_Access;
1889 Total_Count : Count_Type'Base;
1890 -- Value read from the stream that says how many elements follow
1892 Read_Count : Count_Type'Base;
1893 -- Actual number of elements read from the stream
1895 -------------------
1896 -- Read_Children --
1897 -------------------
1899 procedure Read_Children (Subtree : Tree_Node_Access) is
1900 pragma Assert (Subtree /= null);
1901 pragma Assert (Subtree.Children.First = null);
1902 pragma Assert (Subtree.Children.Last = null);
1904 Count : Count_Type'Base;
1905 -- Number of child subtrees
1907 C : Children_Type;
1909 begin
1910 Count_Type'Read (Stream, Count);
1912 if Checks and then Count < 0 then
1913 raise Program_Error with "attempt to read from corrupt stream";
1914 end if;
1916 if Count = 0 then
1917 return;
1918 end if;
1920 C.First := Read_Subtree (Parent => Subtree);
1921 C.Last := C.First;
1923 for J in Count_Type'(2) .. Count loop
1924 C.Last.Next := Read_Subtree (Parent => Subtree);
1925 C.Last.Next.Prev := C.Last;
1926 C.Last := C.Last.Next;
1927 end loop;
1929 -- Now that the allocation and reads have completed successfully, it
1930 -- is safe to link the children to their parent.
1932 Subtree.Children := C;
1933 end Read_Children;
1935 ------------------
1936 -- Read_Subtree --
1937 ------------------
1939 function Read_Subtree
1940 (Parent : Tree_Node_Access) return Tree_Node_Access
1942 Element : constant Element_Access :=
1943 new Element_Type'(Element_Type'Input (Stream));
1945 Subtree : constant Tree_Node_Access :=
1946 new Tree_Node_Type'
1947 (Parent => Parent, Element => Element, others => <>);
1949 begin
1950 Read_Count := Read_Count + 1;
1952 Read_Children (Subtree);
1954 return Subtree;
1955 end Read_Subtree;
1957 -- Start of processing for Read
1959 begin
1960 Container.Clear; -- checks busy bit
1962 Count_Type'Read (Stream, Total_Count);
1964 if Checks and then Total_Count < 0 then
1965 raise Program_Error with "attempt to read from corrupt stream";
1966 end if;
1968 if Total_Count = 0 then
1969 return;
1970 end if;
1972 Read_Count := 0;
1974 Read_Children (Root_Node (Container));
1976 if Checks and then Read_Count /= Total_Count then
1977 raise Program_Error with "attempt to read from corrupt stream";
1978 end if;
1980 Container.Count := Total_Count;
1981 end Read;
1983 procedure Read
1984 (Stream : not null access Root_Stream_Type'Class;
1985 Position : out Cursor)
1987 begin
1988 raise Program_Error with "attempt to read tree cursor from stream";
1989 end Read;
1991 procedure Read
1992 (Stream : not null access Root_Stream_Type'Class;
1993 Item : out Reference_Type)
1995 begin
1996 raise Program_Error with "attempt to stream reference";
1997 end Read;
1999 procedure Read
2000 (Stream : not null access Root_Stream_Type'Class;
2001 Item : out Constant_Reference_Type)
2003 begin
2004 raise Program_Error with "attempt to stream reference";
2005 end Read;
2007 ---------------
2008 -- Reference --
2009 ---------------
2011 function Reference
2012 (Container : aliased in out Tree;
2013 Position : Cursor) return Reference_Type
2015 begin
2016 if Checks and then Position.Container = null then
2017 raise Constraint_Error with
2018 "Position cursor has no element";
2019 end if;
2021 if Checks and then Position.Container /= Container'Unrestricted_Access
2022 then
2023 raise Program_Error with
2024 "Position cursor designates wrong container";
2025 end if;
2027 if Checks and then Position.Node = Root_Node (Container) then
2028 raise Program_Error with "Position cursor designates root";
2029 end if;
2031 if Checks and then Position.Node.Element = null then
2032 raise Program_Error with "Node has no element";
2033 end if;
2035 -- Implement Vet for multiway tree???
2036 -- pragma Assert (Vet (Position),
2037 -- "Position cursor in Constant_Reference is bad");
2039 declare
2040 TC : constant Tamper_Counts_Access :=
2041 Container.TC'Unrestricted_Access;
2042 begin
2043 return R : constant Reference_Type :=
2044 (Element => Position.Node.Element.all'Access,
2045 Control => (Controlled with TC))
2047 Lock (TC.all);
2048 end return;
2049 end;
2050 end Reference;
2052 --------------------
2053 -- Remove_Subtree --
2054 --------------------
2056 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2057 C : Children_Type renames Subtree.Parent.Children;
2059 begin
2060 -- This is a utility operation to remove a subtree node from its
2061 -- parent's list of children.
2063 if C.First = Subtree then
2064 pragma Assert (Subtree.Prev = null);
2066 if C.Last = Subtree then
2067 pragma Assert (Subtree.Next = null);
2068 C.First := null;
2069 C.Last := null;
2071 else
2072 C.First := Subtree.Next;
2073 C.First.Prev := null;
2074 end if;
2076 elsif C.Last = Subtree then
2077 pragma Assert (Subtree.Next = null);
2078 C.Last := Subtree.Prev;
2079 C.Last.Next := null;
2081 else
2082 Subtree.Prev.Next := Subtree.Next;
2083 Subtree.Next.Prev := Subtree.Prev;
2084 end if;
2085 end Remove_Subtree;
2087 ----------------------
2088 -- Replace_Element --
2089 ----------------------
2091 procedure Replace_Element
2092 (Container : in out Tree;
2093 Position : Cursor;
2094 New_Item : Element_Type)
2096 E, X : Element_Access;
2098 begin
2099 if Checks and then Position = No_Element then
2100 raise Constraint_Error with "Position cursor has no element";
2101 end if;
2103 if Checks and then Position.Container /= Container'Unrestricted_Access
2104 then
2105 raise Program_Error with "Position cursor not in container";
2106 end if;
2108 if Checks and then Is_Root (Position) then
2109 raise Program_Error with "Position cursor designates root";
2110 end if;
2112 TE_Check (Container.TC);
2114 declare
2115 -- The element allocator may need an accessibility check in the case
2116 -- the actual type is class-wide or has access discriminants (see
2117 -- RM 4.8(10.1) and AI12-0035).
2119 pragma Unsuppress (Accessibility_Check);
2121 begin
2122 E := new Element_Type'(New_Item);
2123 end;
2125 X := Position.Node.Element;
2126 Position.Node.Element := E;
2128 Free_Element (X);
2129 end Replace_Element;
2131 ------------------------------
2132 -- Reverse_Iterate_Children --
2133 ------------------------------
2135 procedure Reverse_Iterate_Children
2136 (Parent : Cursor;
2137 Process : not null access procedure (Position : Cursor))
2139 C : Tree_Node_Access;
2140 Busy : With_Busy (Parent.Container.TC'Unrestricted_Access);
2141 begin
2142 if Checks and then Parent = No_Element then
2143 raise Constraint_Error with "Parent cursor has no element";
2144 end if;
2146 C := Parent.Node.Children.Last;
2147 while C /= null loop
2148 Process (Position => Cursor'(Parent.Container, Node => C));
2149 C := C.Prev;
2150 end loop;
2151 end Reverse_Iterate_Children;
2153 ----------
2154 -- Root --
2155 ----------
2157 function Root (Container : Tree) return Cursor is
2158 begin
2159 return (Container'Unrestricted_Access, Root_Node (Container));
2160 end Root;
2162 ---------------
2163 -- Root_Node --
2164 ---------------
2166 function Root_Node (Container : Tree) return Tree_Node_Access is
2167 begin
2168 return Container.Root'Unrestricted_Access;
2169 end Root_Node;
2171 ---------------------
2172 -- Splice_Children --
2173 ---------------------
2175 procedure Splice_Children
2176 (Target : in out Tree;
2177 Target_Parent : Cursor;
2178 Before : Cursor;
2179 Source : in out Tree;
2180 Source_Parent : Cursor)
2182 Count : Count_Type;
2184 begin
2185 if Checks and then Target_Parent = No_Element then
2186 raise Constraint_Error with "Target_Parent cursor has no element";
2187 end if;
2189 if Checks and then Target_Parent.Container /= Target'Unrestricted_Access
2190 then
2191 raise Program_Error
2192 with "Target_Parent cursor not in Target container";
2193 end if;
2195 if Before /= No_Element then
2196 if Checks and then Before.Container /= Target'Unrestricted_Access then
2197 raise Program_Error
2198 with "Before cursor not in Target container";
2199 end if;
2201 if Checks and then Before.Node.Parent /= Target_Parent.Node then
2202 raise Constraint_Error
2203 with "Before cursor not child of Target_Parent";
2204 end if;
2205 end if;
2207 if Checks and then Source_Parent = No_Element then
2208 raise Constraint_Error with "Source_Parent cursor has no element";
2209 end if;
2211 if Checks and then Source_Parent.Container /= Source'Unrestricted_Access
2212 then
2213 raise Program_Error
2214 with "Source_Parent cursor not in Source container";
2215 end if;
2217 if Target'Address = Source'Address then
2218 if Target_Parent = Source_Parent then
2219 return;
2220 end if;
2222 TC_Check (Target.TC);
2224 if Checks and then Is_Reachable (From => Target_Parent.Node,
2225 To => Source_Parent.Node)
2226 then
2227 raise Constraint_Error
2228 with "Source_Parent is ancestor of Target_Parent";
2229 end if;
2231 Splice_Children
2232 (Target_Parent => Target_Parent.Node,
2233 Before => Before.Node,
2234 Source_Parent => Source_Parent.Node);
2236 return;
2237 end if;
2239 TC_Check (Target.TC);
2240 TC_Check (Source.TC);
2242 -- We cache the count of the nodes we have allocated, so that operation
2243 -- Node_Count can execute in O(1) time. But that means we must count the
2244 -- nodes in the subtree we remove from Source and insert into Target, in
2245 -- order to keep the count accurate.
2247 Count := Subtree_Node_Count (Source_Parent.Node);
2248 pragma Assert (Count >= 1);
2250 Count := Count - 1; -- because Source_Parent node does not move
2252 Splice_Children
2253 (Target_Parent => Target_Parent.Node,
2254 Before => Before.Node,
2255 Source_Parent => Source_Parent.Node);
2257 Source.Count := Source.Count - Count;
2258 Target.Count := Target.Count + Count;
2259 end Splice_Children;
2261 procedure Splice_Children
2262 (Container : in out Tree;
2263 Target_Parent : Cursor;
2264 Before : Cursor;
2265 Source_Parent : Cursor)
2267 begin
2268 if Checks and then Target_Parent = No_Element then
2269 raise Constraint_Error with "Target_Parent cursor has no element";
2270 end if;
2272 if Checks and then
2273 Target_Parent.Container /= Container'Unrestricted_Access
2274 then
2275 raise Program_Error
2276 with "Target_Parent cursor not in container";
2277 end if;
2279 if Before /= No_Element then
2280 if Checks and then Before.Container /= Container'Unrestricted_Access
2281 then
2282 raise Program_Error
2283 with "Before cursor not in container";
2284 end if;
2286 if Checks and then Before.Node.Parent /= Target_Parent.Node then
2287 raise Constraint_Error
2288 with "Before cursor not child of Target_Parent";
2289 end if;
2290 end if;
2292 if Checks and then Source_Parent = No_Element then
2293 raise Constraint_Error with "Source_Parent cursor has no element";
2294 end if;
2296 if Checks and then
2297 Source_Parent.Container /= Container'Unrestricted_Access
2298 then
2299 raise Program_Error
2300 with "Source_Parent cursor not in container";
2301 end if;
2303 if Target_Parent = Source_Parent then
2304 return;
2305 end if;
2307 TC_Check (Container.TC);
2309 if Checks and then Is_Reachable (From => Target_Parent.Node,
2310 To => Source_Parent.Node)
2311 then
2312 raise Constraint_Error
2313 with "Source_Parent is ancestor of Target_Parent";
2314 end if;
2316 Splice_Children
2317 (Target_Parent => Target_Parent.Node,
2318 Before => Before.Node,
2319 Source_Parent => Source_Parent.Node);
2320 end Splice_Children;
2322 procedure Splice_Children
2323 (Target_Parent : Tree_Node_Access;
2324 Before : Tree_Node_Access;
2325 Source_Parent : Tree_Node_Access)
2327 CC : constant Children_Type := Source_Parent.Children;
2328 C : Tree_Node_Access;
2330 begin
2331 -- This is a utility operation to remove the children from Source parent
2332 -- and insert them into Target parent.
2334 Source_Parent.Children := Children_Type'(others => null);
2336 -- Fix up the Parent pointers of each child to designate its new Target
2337 -- parent.
2339 C := CC.First;
2340 while C /= null loop
2341 C.Parent := Target_Parent;
2342 C := C.Next;
2343 end loop;
2345 Insert_Subtree_List
2346 (First => CC.First,
2347 Last => CC.Last,
2348 Parent => Target_Parent,
2349 Before => Before);
2350 end Splice_Children;
2352 --------------------
2353 -- Splice_Subtree --
2354 --------------------
2356 procedure Splice_Subtree
2357 (Target : in out Tree;
2358 Parent : Cursor;
2359 Before : Cursor;
2360 Source : in out Tree;
2361 Position : in out Cursor)
2363 Subtree_Count : Count_Type;
2365 begin
2366 if Checks and then Parent = No_Element then
2367 raise Constraint_Error with "Parent cursor has no element";
2368 end if;
2370 if Checks and then Parent.Container /= Target'Unrestricted_Access then
2371 raise Program_Error with "Parent cursor not in Target container";
2372 end if;
2374 if Before /= No_Element then
2375 if Checks and then Before.Container /= Target'Unrestricted_Access then
2376 raise Program_Error with "Before cursor not in Target container";
2377 end if;
2379 if Checks and then Before.Node.Parent /= Parent.Node then
2380 raise Constraint_Error with "Before cursor not child of Parent";
2381 end if;
2382 end if;
2384 if Checks and then Position = No_Element then
2385 raise Constraint_Error with "Position cursor has no element";
2386 end if;
2388 if Checks and then Position.Container /= Source'Unrestricted_Access then
2389 raise Program_Error with "Position cursor not in Source container";
2390 end if;
2392 if Checks and then Is_Root (Position) then
2393 raise Program_Error with "Position cursor designates root";
2394 end if;
2396 if Target'Address = Source'Address then
2397 if Position.Node.Parent = Parent.Node then
2398 if Position.Node = Before.Node then
2399 return;
2400 end if;
2402 if Position.Node.Next = Before.Node then
2403 return;
2404 end if;
2405 end if;
2407 TC_Check (Target.TC);
2409 if Checks and then
2410 Is_Reachable (From => Parent.Node, To => Position.Node)
2411 then
2412 raise Constraint_Error with "Position is ancestor of Parent";
2413 end if;
2415 Remove_Subtree (Position.Node);
2417 Position.Node.Parent := Parent.Node;
2418 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2420 return;
2421 end if;
2423 TC_Check (Target.TC);
2424 TC_Check (Source.TC);
2426 -- This is an unfortunate feature of this API: we must count the nodes
2427 -- in the subtree that we remove from the source tree, which is an O(n)
2428 -- operation. It would have been better if the Tree container did not
2429 -- have a Node_Count selector; a user that wants the number of nodes in
2430 -- the tree could simply call Subtree_Node_Count, with the understanding
2431 -- that such an operation is O(n).
2433 -- Of course, we could choose to implement the Node_Count selector as an
2434 -- O(n) operation, which would turn this splice operation into an O(1)
2435 -- operation. ???
2437 Subtree_Count := Subtree_Node_Count (Position.Node);
2438 pragma Assert (Subtree_Count <= Source.Count);
2440 Remove_Subtree (Position.Node);
2441 Source.Count := Source.Count - Subtree_Count;
2443 Position.Node.Parent := Parent.Node;
2444 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2446 Target.Count := Target.Count + Subtree_Count;
2448 Position.Container := Target'Unrestricted_Access;
2449 end Splice_Subtree;
2451 procedure Splice_Subtree
2452 (Container : in out Tree;
2453 Parent : Cursor;
2454 Before : Cursor;
2455 Position : Cursor)
2457 begin
2458 if Checks and then Parent = No_Element then
2459 raise Constraint_Error with "Parent cursor has no element";
2460 end if;
2462 if Checks and then Parent.Container /= Container'Unrestricted_Access then
2463 raise Program_Error with "Parent cursor not in container";
2464 end if;
2466 if Before /= No_Element then
2467 if Checks and then Before.Container /= Container'Unrestricted_Access
2468 then
2469 raise Program_Error with "Before cursor not in container";
2470 end if;
2472 if Checks and then Before.Node.Parent /= Parent.Node then
2473 raise Constraint_Error with "Before cursor not child of Parent";
2474 end if;
2475 end if;
2477 if Checks and then Position = No_Element then
2478 raise Constraint_Error with "Position cursor has no element";
2479 end if;
2481 if Checks and then Position.Container /= Container'Unrestricted_Access
2482 then
2483 raise Program_Error with "Position cursor not in container";
2484 end if;
2486 if Checks and then Is_Root (Position) then
2488 -- Should this be PE instead? Need ARG confirmation. ???
2490 raise Constraint_Error with "Position cursor designates root";
2491 end if;
2493 if Position.Node.Parent = Parent.Node then
2494 if Position.Node = Before.Node then
2495 return;
2496 end if;
2498 if Position.Node.Next = Before.Node then
2499 return;
2500 end if;
2501 end if;
2503 TC_Check (Container.TC);
2505 if Checks and then
2506 Is_Reachable (From => Parent.Node, To => Position.Node)
2507 then
2508 raise Constraint_Error with "Position is ancestor of Parent";
2509 end if;
2511 Remove_Subtree (Position.Node);
2513 Position.Node.Parent := Parent.Node;
2514 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2515 end Splice_Subtree;
2517 ------------------------
2518 -- Subtree_Node_Count --
2519 ------------------------
2521 function Subtree_Node_Count (Position : Cursor) return Count_Type is
2522 begin
2523 if Position = No_Element then
2524 return 0;
2525 end if;
2527 return Subtree_Node_Count (Position.Node);
2528 end Subtree_Node_Count;
2530 function Subtree_Node_Count
2531 (Subtree : Tree_Node_Access) return Count_Type
2533 Result : Count_Type;
2534 Node : Tree_Node_Access;
2536 begin
2537 Result := 1;
2538 Node := Subtree.Children.First;
2539 while Node /= null loop
2540 Result := Result + Subtree_Node_Count (Node);
2541 Node := Node.Next;
2542 end loop;
2544 return Result;
2545 end Subtree_Node_Count;
2547 ----------
2548 -- Swap --
2549 ----------
2551 procedure Swap
2552 (Container : in out Tree;
2553 I, J : Cursor)
2555 begin
2556 if Checks and then I = No_Element then
2557 raise Constraint_Error with "I cursor has no element";
2558 end if;
2560 if Checks and then I.Container /= Container'Unrestricted_Access then
2561 raise Program_Error with "I cursor not in container";
2562 end if;
2564 if Checks and then Is_Root (I) then
2565 raise Program_Error with "I cursor designates root";
2566 end if;
2568 if I = J then -- make this test sooner???
2569 return;
2570 end if;
2572 if Checks and then J = No_Element then
2573 raise Constraint_Error with "J cursor has no element";
2574 end if;
2576 if Checks and then J.Container /= Container'Unrestricted_Access then
2577 raise Program_Error with "J cursor not in container";
2578 end if;
2580 if Checks and then Is_Root (J) then
2581 raise Program_Error with "J cursor designates root";
2582 end if;
2584 TE_Check (Container.TC);
2586 declare
2587 EI : constant Element_Access := I.Node.Element;
2589 begin
2590 I.Node.Element := J.Node.Element;
2591 J.Node.Element := EI;
2592 end;
2593 end Swap;
2595 --------------------
2596 -- Update_Element --
2597 --------------------
2599 procedure Update_Element
2600 (Container : in out Tree;
2601 Position : Cursor;
2602 Process : not null access procedure (Element : in out Element_Type))
2604 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2605 Lock : With_Lock (T.TC'Unrestricted_Access);
2606 begin
2607 if Checks and then Position = No_Element then
2608 raise Constraint_Error with "Position cursor has no element";
2609 end if;
2611 if Checks and then Position.Container /= Container'Unrestricted_Access
2612 then
2613 raise Program_Error with "Position cursor not in container";
2614 end if;
2616 if Checks and then Is_Root (Position) then
2617 raise Program_Error with "Position cursor designates root";
2618 end if;
2620 Process (Position.Node.Element.all);
2621 end Update_Element;
2623 -----------
2624 -- Write --
2625 -----------
2627 procedure Write
2628 (Stream : not null access Root_Stream_Type'Class;
2629 Container : Tree)
2631 procedure Write_Children (Subtree : Tree_Node_Access);
2632 procedure Write_Subtree (Subtree : Tree_Node_Access);
2634 --------------------
2635 -- Write_Children --
2636 --------------------
2638 procedure Write_Children (Subtree : Tree_Node_Access) is
2639 CC : Children_Type renames Subtree.Children;
2640 C : Tree_Node_Access;
2642 begin
2643 Count_Type'Write (Stream, Child_Count (CC));
2645 C := CC.First;
2646 while C /= null loop
2647 Write_Subtree (C);
2648 C := C.Next;
2649 end loop;
2650 end Write_Children;
2652 -------------------
2653 -- Write_Subtree --
2654 -------------------
2656 procedure Write_Subtree (Subtree : Tree_Node_Access) is
2657 begin
2658 Element_Type'Output (Stream, Subtree.Element.all);
2659 Write_Children (Subtree);
2660 end Write_Subtree;
2662 -- Start of processing for Write
2664 begin
2665 Count_Type'Write (Stream, Container.Count);
2667 if Container.Count = 0 then
2668 return;
2669 end if;
2671 Write_Children (Root_Node (Container));
2672 end Write;
2674 procedure Write
2675 (Stream : not null access Root_Stream_Type'Class;
2676 Position : Cursor)
2678 begin
2679 raise Program_Error with "attempt to write tree cursor to stream";
2680 end Write;
2682 procedure Write
2683 (Stream : not null access Root_Stream_Type'Class;
2684 Item : Reference_Type)
2686 begin
2687 raise Program_Error with "attempt to stream reference";
2688 end Write;
2690 procedure Write
2691 (Stream : not null access Root_Stream_Type'Class;
2692 Item : Constant_Reference_Type)
2694 begin
2695 raise Program_Error with "attempt to stream reference";
2696 end Write;
2698 end Ada.Containers.Indefinite_Multiway_Trees;